Add info page with detected versions
[clawsker.git] / clawsker
1 #!/usr/bin/perl -w
2 #
3 # Clawsker :: A Claws Mail Tweaker
4 # Copyright 2007-2016 Ricardo Mones <ricardo@mones.org>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # See COPYING file for license details.
12 # See AUTHORS file for a complete list of contributors.
13 #
14
15 binmode STDOUT, ":encoding(utf8)";
16
17 use 5.010_000;
18 use strict;
19 use utf8;
20 use Glib qw(TRUE FALSE);
21 use Gtk2;
22 use POSIX qw(setlocale);
23 use Locale::gettext;
24 use Encode;
25 use Digest::MD5 qw(md5_hex);
26 use Getopt::Long;
27
28 my $NAME = 'clawsker';
29 my $PREFIX = '@PREFIX@';
30 my $LIBDIR = '@LIBDIR@';
31 my $DATADIR = '@DATADIR@';
32 my $VERSION = '@VERSION@';
33 my $VERBOSE = FALSE;
34 my $READONLY = FALSE;
35 my $CLAWSV = undef;
36 my $main_window = undef;
37
38 my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
39 $locale = "C" unless defined($locale);
40 setlocale (LC_ALL, $locale);
41 bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
42 textdomain ($NAME);
43
44 my $SHOWHINTS = FALSE;
45 $SHOWHINTS = TRUE if ($Gtk2::VERSION >= 1.040 and Gtk2->CHECK_VERSION (2, 12, 0));
46
47 sub _ {
48     my $str = shift;
49     my %par = @_;
50     my $xla = gettext ($str);
51     if (scalar(keys(%par)) > 0) {
52         foreach my $key (keys %par) {
53             $xla =~ s/\{$key\}/$par{$key}/g;
54         }
55     }
56     return decode_utf8($xla);
57 }
58
59 # default messages
60 %xl::s = (
61     win_title => _('Claws Mail Hidden Preferences'),
62     about => _('About...'),
63     about_title => _('Clawsker :: A Claws Mail Tweaker'),
64     about_license => _('License:'),
65     about_version => _('Version:'),
66
67     tab_colours => _('Colours'),
68     tab_behaviour => _('Behaviour'),
69     tab_gui => _('GUI'),
70     tab_other => _('Other'),
71     tab_winpos => _('Windows'),
72     tab_accounts => _('Accounts'),
73     tab_plugins => _('Plugins'),
74     tab_info => _('Info'),
75
76     ab_frame => _('Addressbook'),
77     mem_frame => _('Memory'),
78     msgview_frame => _('Message View'),
79     log_frame => _('Log window'),
80     dnd_frame => _('Drag \'n\' drop'),
81     ssl_frame => _('Secure Sockets Layer'),
82     msgs_frame => _('Messages'),
83     swc_frame => _('Completion'),
84     stripes_frame => _('Coloured stripes'),
85     sbar_frame => _('Scroll bars'),
86     mlist_frame => _('Message List'),
87     mview_frame => _('Message View'),
88     compo_frame => _('Compose window'),
89     netm_frame => _('NetworkManager'),
90     diff_frame => _('Viewing patches'),
91     mpass_frame => _('Master passphrase'),
92
93     l_oth_use_dlg => _('Use detached address book edit dialogue'),
94     h_oth_use_dlg => _('If true use a separate dialogue to edit a person\'s details. Otherwise will use a form embedded in the address book\'s main window.'),
95     l_oth_max_use => _('Maximum memory for message cache (kB)'),
96     h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kilobytes.'),
97     l_oth_min_time => _('Minimun time for cache elements (minutes)'),
98     h_oth_min_time => _('The minimum time in minutes to keep a cache in memory. Caches more recent than this time will not be freed, even if the memory usage is too high.'),
99     l_oth_use_netm => _('Use NetworkManager'),
100     h_oth_use_netm => _('Use NetworkManager to switch offline automatically.'),
101     l_oth_mp_rounds => _('Rounds for PBKDF2 function'),
102     h_oth_mp_rounds => _('Specify the number of iterations the key derivation function will be applied on master passphrase computation. Does not modify currently stored passphrase, only master passphrases computed after changing this value are affected.'),
103
104     l_gui_b_unread => _('Show unread messages with bold font'),
105     h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
106     l_gui_no_markup => _('Don\'t use markup'),
107     h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
108     l_gui_dot_lines => _('Use dotted lines in tree view components'),
109     h_gui_dot_lines => _('Use the old dotted line look in the main window tree views (Folder, Message and other lists) instead of the modern lineless look.'),
110     l_gui_h_scroll => _('Enable horizontal scrollbar'),
111     h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
112     l_gui_swp_from => _('Display To column instead From column in Sent folder'),
113     h_gui_swp_from => _('Display the recipient\'s email address in a To column of the Sent folder instead of the originator\'s one in a From column.'),
114     l_gui_v_scroll => _('Folder List scrollbar behaviour'),
115     h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
116     l_gui_v_scroll_show => _('Show always'),
117     l_gui_v_scroll_auto => _('Automatic'),
118     l_gui_v_scroll_hide => _('Hide always'),
119     l_gui_from_show => _('From column displays'),
120     h_gui_from_show => _('Selects the data displayed in the From column of the Message List: name, address or both.'),
121     l_gui_from_show_name => _('Name only'),
122     l_gui_from_show_addr => _('Address only'),
123     l_gui_from_show_both => _('Both name and address'),
124     l_gui_strip_off => _('Coloured lines contrast'),
125     h_gui_strip_off => _('Specify the value to use when creating alternately coloured lines in tree view components. The smaller the value, the less visible the difference in the alternating colours of the lines.'),
126     l_gui_cursor_v => _('Show cursor'),
127     h_gui_cursor_v => _('Display the cursor in the Message View.'),
128     l_gui_toolbar_d => _('Detachable toolbars'),
129     h_gui_toolbar_d => _('Show handles in the toolbars.'),
130     l_gui_strip_all => _('Use stripes in all tree view components'),
131     h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
132     l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
133     h_gui_strip_sum => _('Enable alternately coloured lines in Message List and Folder List.'),
134     l_gui_two_line_v => _('2 lines per Message List item in 3-column layout'),
135     h_gui_two_line_v => _('Spread Message List information over two lines when using the three column mode.'),
136     l_gui_margin_co => _('Show margin'),
137     h_gui_margin_co => _('Shows a small margin in the Compose View.'),
138     l_gui_mview_date => _('Don\'t display localized date'),
139     h_gui_mview_date => _('Toggles localization of date format in Message View.'),
140     l_gui_zero_char => _('Zero replacement character'),
141     h_gui_zero_char => _('Replaces \'0\' with the given character in Folder List.'),
142     l_gui_type_any => _('Editable headers'),
143     h_gui_type_any => _('Allows to manually type any value in Compose Window header entries or just select from the available choices in the associated dropdown list.'),
144     l_gui_next_del => _('Select next message on delete'),
145     h_gui_next_del => _('When deleting a message, toggles between selecting the next one (newer message) or the previous one (older message).'),
146
147     l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
148     h_beh_hover_t => _('Time in milliseconds that will cause a folder tree to expand when the mouse cursor is held over it during drag and drop.'),
149     l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
150     h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
151     l_beh_flowed => _('Respect format=flowed in messages'),
152     h_beh_flowed => _('Respect format=flowed on text/plain message parts. This will cause some mails to have long lines, but will fix some URLs that would otherwise be wrapped.'),
153     l_beh_parts_rw => _('Allow writable temporary files'),
154     h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
155     l_beh_skip_ssl => _('Don\'t check SSL certificates'),
156     h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
157     l_beh_up_step => _('Progress bar update step (items)'),
158     h_beh_up_step => _('Update stepping in progress bars.'),
159     l_beh_thread_a => _('Maximum age when threading by subject (days)'),
160     h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
161     l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
162     h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
163     l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
164     h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
165     l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
166     h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
167     l_beh_out_ascii => _('Outgoing messages fallback to ASCII'),
168     h_beh_out_ascii => _('If content allows, ASCII will be used to encode outgoing messages, otherwise the user-defined encoding is enforced always.'),
169     l_beh_pp_unsel => _('Primary paste unselects selection'),
170     h_beh_pp_unsel => _('Controls how pasting using middle-click changes the selected text and insertion point.'),
171     l_beh_inline_at => _('Show inline attachments'),
172     h_beh_inline_at => _('Allows hiding inline attachments already shown in mail structure view.'),
173     l_beh_addr_swc => _('Address search in compose window matches any'),
174     h_beh_addr_swc => _('On Tab-key completion, address text will match any part of the string or only from the start.'),
175     l_beh_fold_swc => _('Folder search in folder selector matches any'),
176     h_beh_fold_swc => _('On folder name completion text will match any part of the string or only from the start.'),
177
178     l_col_emphasis => _('X-Mailer header'),
179     h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
180     l_col_log_err => _('Error messages'),
181     h_col_log_err => _('Colour for error messages in log window.'),
182     l_col_log_in => _('Server messages'),
183     h_col_log_in => _('Colour for messages received from servers in log window.'),
184     l_col_log_msg => _('Standard messages'),
185     h_col_log_msg => _('Colour for messages in log window.'),
186     l_col_log_out => _('Client messages'),
187     h_col_log_out => _('Colour for messages sent to servers in log window.'),
188     l_col_log_warn => _('Warnings'),
189     h_col_log_warn => _('Colour for warning messages in log window.'),
190
191     l_col_diff_add => _('Added lines'),
192     h_col_diff_add => _('Colour for added lines in patches.'),
193     l_col_diff_del => _('Deleted lines'),
194     h_col_diff_del => _('Colour for deleted lines in patches.'),
195     l_col_diff_hunk => _('Hunk lines'),
196     h_col_diff_hunk => _('Color for hunk headers in patches.'),
197
198     l_win_x => _('X position'),
199     h_win_x => _('X coordinate for window\'s top-left corner.'),
200     l_win_y => _('Y position'),
201     h_win_y => _('Y coordinate for window\'s top-left corner.'),
202     l_win_w => _('Width'),
203     h_win_w => _('Window\'s width in pixels.'),
204     l_win_h => _('Height'),
205     h_win_h => _('Window\'s height in pixels.'),
206
207     l_win_main_mx => _('Maximized'),
208     h_win_main_mx => _('Changes window maximized status.'),
209     l_win_main_fs => _('Full-screen'),
210     h_win_main_fs => _('Changes full screen status.'),
211
212     l_acc_gtls_set => _('Use custom GnuTLS priority'),
213     h_acc_gtls_set => _('Enables using user provided GnuTLS priority string.'),
214     l_acc_gtls_pri => _('GnuTLS priority'),
215     h_acc_gtls_pri => _('Value to use as GnuTLS priority string if custom priority check is enabled. Otherwise this value is ignored.'),
216
217     l_plu_gpg_alimit => _('Autocompletion limit'),
218     h_plu_gpg_alimit => _('Limits the number of addresses obtained from from keyring through autocompletion. Use 0 to get all matches.'),
219     l_plu_lav_burl => _('Base URL'),
220     h_plu_lav_burl => _('This is the URL where avatar requests are sent. You can use the one of your own libravatar server, if available.'),
221     l_plu_prl_flvb => _('Log level'),
222     h_plu_prl_flvb => _('Verbosity level of log, acumulative.'),
223     l_plu_prl_none => _('None'),
224     l_plu_prl_manual => _('Manual'),
225     l_plu_prl_action => _('Actions'),
226     l_plu_prl_match => _('Matches'),
227
228     e_error => _('Error: '),
229     e_noclawsrc => _('resource file for Claws Mail was not found.'),
230     e_running => _('seems Claws Mail is currently running, close it first.'),
231 );
232
233 # data and metadata of resource files
234 my $CONFIGDATA;
235 my $CONFIGMETA;
236 my $ACCOUNTDATA;
237 my $ACCOUNTMETA;
238 # all preferences read by load_preferences
239 my %PREFS = ();
240 my %ACPREFS = ();
241 my %PLPREFS = ();
242 # values of all preferences handled by clawsker
243 my %HPVALUE = ();
244 my %ACHPVALUE = ();
245 my %PLHPVALUE = ();
246 # default config dir and file name
247 my $ALTCONFIGDIR = FALSE;
248 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
249 my $CONFIGRC = 'clawsrc';
250 my $ACCOUNTRC = 'accountrc';
251 # supported and available plugins lists
252 my @PLUGINS = qw(AttRemover GPG ManageSieve Libravatar PerlPlugin);
253 my @AVPLUGINS = ();
254
255 # index constants for preference arrays
256 use constant NAME  => 0; # the name on the rc file
257 use constant LABEL => 1; # the label on the GUI
258 use constant DESC  => 2; # the description for the hint/help
259 use constant TYPE  => 3; # data type: bool, int, float, string, color
260 use constant CMVER => 4; # lowest[,highest] Claws Mail version(s) the feature exists
261 use constant CMDEF => 5; # default value for the preference in Claws Mail
262 use constant PLUGIN => 6; # plugin section (only in plugin preferences)
263
264 # constants for GUI spacing
265 use constant HBOX_SPC => 5;
266 use constant FRAME_SPC => 2;
267 use constant PAGE_SPC => 5;
268
269 # version functions
270
271 sub version_greater_or_equal {
272     my ($version, $refvers) = @_;
273     my @version = split (/\./, $version);
274     my @refvers = split (/\./, $refvers);
275     while ($#version < $#refvers) {
276         push (@version, '0');
277     }
278     my $idx = 0;
279     while (($idx <= $#refvers)
280             and (int ($version[$idx]) == int ($refvers[$idx]))) {
281         ++$idx;
282     }
283     return TRUE if (($idx > $#refvers)
284         or (int ($version[$idx]) >= int ($refvers[$idx])));
285     return FALSE;
286 }
287
288 sub get_claws_version {
289     $_ = qx/which claws-mail/;
290     chomp;
291     return "" unless ($_); # not installed
292     my $res = "";
293     $_ = qx/$_ -v/;
294     chomp;
295     my @fver = split (/ /);
296     die "Invalid version string" unless ($fver[2] eq "version");
297     my @ver = split (/\./, $fver[3]);
298     $res .= "$ver[0].";
299     $res .= "$ver[1].";
300     if ($ver[2] =~ /(\d+)git(\d+)/) {
301         $res .= "$1.$2";
302     }
303     else {
304         $res .= "$ver[2].0";
305     }
306     return $res;
307 }
308
309 # data handlers and auxiliar functions
310
311 sub handle_bool_value {
312     my ($widget, $event, $dataref) = @_;
313     $$dataref = ($widget->get_active ())? '1': '0';
314 }
315
316 sub handle_int_value {
317     my ($widget, $event, $dataref) = @_;
318     $_ = $widget->get_text ();
319     s/^\s+//;
320     s/\s+$//;
321     if (/^[0-9]+$/) {
322         $$dataref = $_;
323         $widget->set_text ($_);
324     }
325     else {
326         $widget->set_text ($$dataref);
327     }
328 }
329
330 sub handle_string_value {
331     my ($widget, $event, $dataref) = @_;
332     $$dataref = $widget->get_text ();
333 }
334
335 sub handle_nchar_value {
336     my ($widget, $event, $dataref, $minlen, $maxlen) = @_;
337     $_ = substr ($widget->get_text (), 0, $maxlen);
338     $widget->set_text ($_);
339     $$dataref = $_;
340 }
341
342 sub gdk_color_from_str {
343     my ($str) = @_;
344     my ($rr, $gg, $bb) = (0, 0 ,0);
345     $_ = uc ($str);
346     if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
347         $rr = hex($1) * 256;
348         $gg = hex($2) * 256;
349         $bb = hex($3) * 256;
350     }
351     my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
352     return $color;
353 }
354
355 sub str_from_gdk_color {
356     my ($color) = @_;
357     my $rr = $color->red / 256;
358     my $gg = $color->green / 256;
359     my $bb = $color->blue / 256;
360     my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
361     return $str;
362 }
363
364 sub handle_color_value {
365     my ($widget, $event, $dataref) = @_;
366     my $newcol = $widget->get_color;
367     $$dataref = str_from_gdk_color ($newcol);
368 }
369
370 sub handle_selection_value {
371     my ($widget, $event, $dataref) = @_;
372     $$dataref = $widget->get_active;
373 }
374
375 sub get_rc_filename {
376     return $CONFIGDIR . $CONFIGRC;
377 }
378
379 sub get_ac_rc_filename {
380     return $CONFIGDIR . $ACCOUNTRC;
381 }
382
383 sub set_rc_filename {
384     my ($fullname) = @_;
385     my @parts = split ('/', $fullname);
386     $CONFIGRC = $parts[$#parts];
387     $parts[$#parts] = '';
388     $CONFIGDIR = join ('/', @parts);
389 }
390
391 sub log_message {
392     my ($mesg, $fatal) = @_;
393     if (defined($fatal) && $fatal eq 'die') {
394         die "$NAME: $mesg\n";
395     }
396     if ($VERBOSE) {
397         print "$NAME: $mesg\n";
398     }
399 }
400
401 sub error_dialog {
402     my ($emsg) = @_;
403     my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
404     my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
405     $errordlg->set_title (_('Clawsker error'));
406     $errordlg->run;
407     $errordlg->destroy;
408 }
409
410 sub claws_is_running {
411     my $emsg = "$xl::s{e_error}$xl::s{e_running}";
412     log_message ($emsg);
413     error_dialog ($emsg);
414     return FALSE;
415 }
416
417 sub check_claws_not_running {
418     return TRUE if $READONLY;
419     my $tmpdir = (defined $ENV{TMPDIR})? $ENV{TMPDIR}: '/tmp';
420     $tmpdir = '/tmp' if ($tmpdir eq '');
421     my $lockdir = "$tmpdir/claws-mail-$<";
422     -d $lockdir and do {
423         $_ = $CONFIGDIR;
424         s/\/$//;
425         my $socket = "$lockdir/" . md5_hex ($_);
426         -S $socket and return claws_is_running ();
427     };
428     return TRUE;
429 }
430
431 sub check_rc_file {
432     my ($rcfile) = @_;
433     (defined($rcfile) && -f $rcfile) or do {
434         my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
435         log_message ($emsg);
436         error_dialog ($emsg);
437         return FALSE;
438     };
439     return TRUE;
440 }
441
442 sub set_widget_hint {
443     if ($SHOWHINTS) {
444         my ($wdgt, $hint) = @_;
445         $wdgt->set_tooltip_text ($hint);
446         $wdgt->set_has_tooltip (TRUE);
447     }
448 }
449
450 sub set_widget_sens {
451     my ($wdgt, $versions) = @_;
452     my @ver = split(/,/, $versions);
453     if ($#ver == 1) {
454       $wdgt->set_sensitive (
455         version_greater_or_equal ($CLAWSV, $ver[0])
456         and version_greater_or_equal ($ver[1], $CLAWSV)
457       );
458     } else {
459         $wdgt->set_sensitive (version_greater_or_equal ($CLAWSV, $ver[0]));
460     }
461 }
462
463 # graphic element creation
464
465 sub new_check_button_for($$$) {
466     my ($hash, $key, $vhash) = @_;
467     my $name = $$hash{$key}[NAME];
468     my $label = $$hash{$key}[LABEL];
469     #
470     my $hbox = Gtk2::HBox->new (FALSE, 5);
471     my $cb = Gtk2::CheckButton->new ($label);
472     my $value = $$vhash{$name};
473     $value //= $$hash{$key}[CMDEF];
474     $cb->set_active ($value eq '1');
475     $cb->signal_connect (clicked => sub {
476             my ($w, $e) = @_;
477             handle_bool_value ($w, $e, \$$vhash{$name});
478         });
479     set_widget_hint ($cb, $$hash{$key}[DESC]);
480     set_widget_sens ($cb, $$hash{$key}[CMVER]);
481     $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
482     #
483     return $hbox;
484 }
485
486 sub new_text_box_for_int($$$) {
487     my ($hash, $key, $vhash) = @_;
488     my $name = $$hash{$key}[NAME];
489     my $label = $$hash{$key}[LABEL];
490     my @type = split (/,/, $$hash{$key}[TYPE]);
491     push (@type, 0), push (@type, 10000) unless ($#type > 0);
492     #
493     my $hbox = Gtk2::HBox->new (FALSE, 5);
494     my $glabel = Gtk2::Label->new ($label);
495     my $pagei = int (($type[2] - $type[1]) / 10);
496     my $gentry = Gtk2::SpinButton->new_with_range ($type[1], $type[2], $pagei);
497     my $value = $$vhash{$name};
498     $value //= $$hash{$key}[CMDEF];
499     $gentry->set_numeric (TRUE);
500     $gentry->set_value ($value);
501     $gentry->signal_connect('value-changed' => sub {
502             my ($w, $e) = @_;
503             handle_int_value ($w, $e, \$$vhash{$name});
504         });
505     set_widget_hint ($gentry, $$hash{$key}[DESC]);
506     set_widget_sens ($gentry, $$hash{$key}[CMVER]);
507     $glabel->set_sensitive ($gentry->sensitive);
508     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
509     $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
510     #
511     return $hbox;
512 }
513
514 sub new_text_box_for_nchar($$$) {
515     my ($hash, $key, $vhash) = @_;
516     my $name = $$hash{$key}[NAME];
517     my $label = $$hash{$key}[LABEL];
518     my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen,width
519     my $hbox = Gtk2::HBox->new (FALSE, 5);
520     my $glabel = Gtk2::Label->new ($label);
521     my $gentry = Gtk2::Entry->new ();
522     $gentry->set_max_length($type[2]) if defined ($type[2]);
523     my $width = $type[3];
524     $width //= $type[2];
525     $gentry->set_width_chars(int ($width) + 2) if defined ($width);
526     my $value = $$vhash{$name};
527     $value //= $$hash{$key}[CMDEF];
528     $gentry->set_text ($value);
529     $gentry->signal_connect('key-release-event' => sub {
530             my ($w, $e) = @_;
531             handle_nchar_value ($w, $e, \$$vhash{$name}, $type[1], $type[2]);
532         });
533     set_widget_hint ($gentry, $$hash{$key}[DESC]);
534     set_widget_sens ($gentry, $$hash{$key}[CMVER]);
535     $glabel->set_sensitive ($gentry->sensitive);
536     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
537     $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
538     #
539     return $hbox;
540 }
541
542 sub new_color_button_for($$$) {
543     my ($hash, $key, $vhash) = @_;
544     my $name = $$hash{$key}[NAME];
545     my $label = $$hash{$key}[LABEL];
546     #
547     my $value = $$vhash{$name};
548     $value //= $$hash{$key}[CMDEF];
549     my $col = gdk_color_from_str ($value);
550     my $hbox = Gtk2::HBox->new (FALSE, 5);
551     my $glabel = Gtk2::Label->new ($label);
552     my $button = Gtk2::ColorButton->new_with_color ($col);
553     $button->set_title ($label);
554     $button->set_relief ('none');
555     $button->signal_connect ('color-set' => sub {
556             my ($w, $e) = @_;
557             handle_color_value ($w, $e, \$$vhash{$name});
558         });
559     set_widget_hint ($button, $$hash{$key}[DESC]);
560     set_widget_sens ($button, $$hash{$key}[CMVER]);
561     $glabel->set_sensitive ($button->sensitive);
562     $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
563     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
564     #
565     return $hbox;
566 }
567
568 sub new_selection_box_for($$$) {
569     my ($hash, $key, $vhash) = @_;
570     my $name = $$hash{$key}[NAME];
571     my $label = $$hash{$key}[LABEL];
572     #
573     my $hbox = Gtk2::HBox->new (FALSE, 5);
574     my $glabel = Gtk2::Label->new ($label);
575     my $combo = Gtk2::ComboBox->new_text;
576     my @options = split (';', $$hash{$key}[TYPE]);
577     foreach my $opt (@options) {
578         my ($index, $textkey) = split ('=', $opt);
579         $combo->insert_text ($index, $xl::s{$textkey});
580     }
581     $combo->signal_connect ('changed' => sub {
582             my ($w, $e) = @_;
583             handle_selection_value ($w, $e, \$$vhash{$name});
584         });
585     my $value = $$vhash{$name};
586     $value //= $$hash{$key}[CMDEF];
587     $combo->set_active ($value);
588     set_widget_hint ($combo, $$hash{$key}[DESC]);
589     set_widget_sens ($combo, $$hash{$key}[CMVER]);
590     $glabel->set_sensitive ($combo->sensitive);
591     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
592     $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
593     #
594     return $hbox;
595 }
596
597 # more graphic helpers
598
599 sub new_hbox_pack {
600     my $hbox = Gtk2::HBox->new (FALSE, 5);
601     $hbox->set_border_width (PAGE_SPC);
602     foreach my $item (@_) {
603         $hbox->pack_start ($item, FALSE, FALSE, 0);
604     }
605     return $hbox;
606 }
607
608 sub new_vbox_pack {
609     my $vbox = Gtk2::VBox->new (FALSE, 5);
610     $vbox->set_border_width (PAGE_SPC);
611     foreach my $item (@_) {
612         $vbox->pack_start ($item, FALSE, FALSE, 0);
613     }
614     return $vbox;
615 }
616
617 sub new_vbox_pack_compact {
618     my $vbox = Gtk2::VBox->new (FALSE, 0);
619     $vbox->set_border_width (0);
620     foreach my $item (@_) {
621         $vbox->pack_start ($item, FALSE, FALSE, 0);
622     }
623     return $vbox;
624 }
625
626 sub new_subpage_frame {
627     my ($box, $title, $notpacked) = @_;
628     my $frame = Gtk2::Frame->new ($title);
629     $frame->add ($box);
630     return new_vbox_pack ($frame) unless defined ($notpacked);
631     return $frame;
632 }
633
634 # preference maps and corresponding page creation subs
635
636 %pr::oth = ( # other preferences
637     use_dlg => [
638         'addressbook_use_editaddress_dialog',
639         $xl::s{l_oth_use_dlg},
640         $xl::s{h_oth_use_dlg},
641         'bool',
642         '2.7.0',
643         '0',
644     ],
645     max_use => [
646         'cache_max_mem_usage',
647         $xl::s{l_oth_max_use},
648         $xl::s{h_oth_max_use},
649         'int,0,262144', # 0 Kb - 256 Mb
650         '0.0.0',
651         '4096',
652     ],
653     min_time => [
654         'cache_min_keep_time',
655         $xl::s{l_oth_min_time},
656         $xl::s{h_oth_min_time},
657         'int,0,120', # 0 minutes - 2 hours
658         '0.0.0',
659         '15',
660     ],
661     use_netm => [
662         'use_networkmanager',
663         $xl::s{l_oth_use_netm},
664         $xl::s{h_oth_use_netm},
665         'bool',
666         '3.3.1',
667         '1',
668     ],
669     mp_rounds => [
670         'master_passphrase_pbkdf2_rounds',
671         $xl::s{l_oth_mp_rounds},
672         $xl::s{h_oth_mp_rounds},
673         'int,50000,1000000',
674         '3.13.2.110',
675         '50000',
676     ],
677 );
678
679 sub new_other_page() {
680     return new_vbox_pack (
681                new_subpage_frame (
682                    new_vbox_pack (
683                        new_check_button_for(\%pr::oth, 'use_dlg', \%HPVALUE)),
684                    $xl::s{ab_frame}, 'not-packed'),
685                new_subpage_frame (
686                    new_vbox_pack (
687                        new_text_box_for_int(\%pr::oth, 'max_use', \%HPVALUE),
688                        new_text_box_for_int(\%pr::oth, 'min_time', \%HPVALUE)),
689                    $xl::s{mem_frame}, 'not-packed'),
690                new_subpage_frame (
691                    new_vbox_pack (
692                        new_check_button_for(\%pr::oth, 'use_netm', \%HPVALUE)),
693                    $xl::s{netm_frame}, 'not-packed'),
694                new_subpage_frame (
695                    new_vbox_pack (
696                        new_text_box_for_int(\%pr::oth, 'mp_rounds', \%HPVALUE)),
697                    $xl::s{mpass_frame}, 'not-packed')
698            );
699 }
700
701 %pr::gui = ( # gui bells and whistles
702     b_unread => [
703         'bold_unread',
704         $xl::s{l_gui_b_unread},
705         $xl::s{h_gui_b_unread},
706         'bool',
707         '0.0.0',
708         '1',
709     ],
710     no_markup => [
711         'compose_no_markup',
712         $xl::s{l_gui_no_markup},
713         $xl::s{h_gui_no_markup},
714         'bool',
715         '0.0.0',
716         '0',
717     ],
718     dot_lines => [
719         'enable_dotted_lines',
720         $xl::s{l_gui_dot_lines},
721         $xl::s{h_gui_dot_lines},
722         'bool',
723         '0.0.0,3.7.10.44',
724         '0',
725     ],
726     h_scroll => [
727         'enable_hscrollbar',
728         $xl::s{l_gui_h_scroll},
729         $xl::s{h_gui_h_scroll},
730         'bool',
731         '0.0.0',
732         '1',
733     ],
734     swp_from => [
735         'enable_swap_from',
736         $xl::s{l_gui_swp_from},
737         $xl::s{h_gui_swp_from},
738         'bool',
739         '0.0.0',
740         '0',
741     ],
742     v_scroll => [
743         'folderview_vscrollbar_policy',
744         $xl::s{l_gui_v_scroll},
745         $xl::s{h_gui_v_scroll},
746         '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
747         '0.0.0',
748         '0',
749     ],
750     from_show => [
751         'summary_from_show',
752         $xl::s{l_gui_from_show},
753         $xl::s{h_gui_from_show},
754         '0=l_gui_from_show_name;1=l_gui_from_show_addr;2=l_gui_from_show_both',
755         '3.7.10',
756         '0',
757     ],
758     strip_off => [
759         'stripes_color_offset',
760         $xl::s{l_gui_strip_off},
761         $xl::s{h_gui_strip_off},
762         'int,0,40000', # no idea what this number means
763         '0.0.0',
764         '4000',
765     ],
766     cursor_v => [
767         'textview_cursor_visible',
768         $xl::s{l_gui_cursor_v},
769         $xl::s{h_gui_cursor_v},
770         'bool',
771         '0.0.0',
772         '0',
773     ],
774     toolbar_d => [
775         'toolbar_detachable',
776         $xl::s{l_gui_toolbar_d},
777         $xl::s{h_gui_toolbar_d},
778         'bool',
779         '0.0.0',
780         '0',
781     ],
782     strip_all => [
783         'use_stripes_everywhere',
784         $xl::s{l_gui_strip_all},
785         $xl::s{h_gui_strip_all},
786         'bool',
787         '0.0.0',
788         '1',
789     ],
790     strip_sum => [
791         'use_stripes_in_summaries',
792         $xl::s{l_gui_strip_sum},
793         $xl::s{h_gui_strip_sum},
794         'bool',
795         '0.0.0',
796         '1',
797     ],
798     two_linev => [
799         'two_line_vertical',
800         $xl::s{l_gui_two_line_v},
801         $xl::s{h_gui_two_line_v},
802         'bool',
803         '3.4.0.7',
804         '0',
805     ],
806     margin_co => [
807         'show_compose_margin',
808         $xl::s{l_gui_margin_co},
809         $xl::s{h_gui_margin_co},
810         'bool',
811         '3.7.6.7',
812         '0',
813     ],
814     mview_date => [
815         'msgview_date_format',
816         $xl::s{l_gui_mview_date},
817         $xl::s{h_gui_mview_date},
818         'bool',
819         '3.7.8.42',
820         '0',
821     ],
822     zero_char => [
823         'zero_replacement_char',
824         $xl::s{l_gui_zero_char},
825         $xl::s{h_gui_zero_char},
826         'char,1,1',
827         '2.8.1.77',
828         '0',
829     ],
830     type_any => [
831         'type_any_header',
832         $xl::s{l_gui_type_any},
833         $xl::s{h_gui_type_any},
834         'bool',
835         '3.12.0.44',
836         '0',
837     ],
838     next_del => [
839         'next_on_delete',
840         $xl::s{l_gui_next_del},
841         $xl::s{h_gui_next_del},
842         'bool',
843         '3.13.0.5',
844         '0',
845     ],
846 );
847
848 sub new_gui_page() {
849     my $gf = Gtk2::VBox->new (FALSE, 5);
850     $gf->set_border_width (PAGE_SPC);
851
852     my $cb_dot_lines = new_check_button_for (\%pr::gui, 'dot_lines', \%HPVALUE);
853     my $cb_toolbar_d = new_check_button_for (\%pr::gui, 'toolbar_d', \%HPVALUE);
854     my $tb_zero_char = new_text_box_for_nchar (\%pr::gui, 'zero_char', \%HPVALUE);
855
856     $gf->pack_start (new_subpage_frame (
857                          new_vbox_pack (
858                              new_check_button_for (\%pr::gui, 'strip_all', \%HPVALUE),
859                              new_check_button_for (\%pr::gui, 'strip_sum', \%HPVALUE),
860                              new_text_box_for_int (\%pr::gui, 'strip_off', \%HPVALUE)),
861                          $xl::s{stripes_frame}, 'not-packed'),
862                      FALSE, FALSE, FRAME_SPC);
863     $gf->pack_start (new_subpage_frame (
864                          new_vbox_pack (
865                              new_check_button_for (\%pr::gui, 'b_unread', \%HPVALUE),
866                              new_check_button_for (\%pr::gui, 'swp_from', \%HPVALUE),
867                              new_check_button_for (\%pr::gui, 'two_linev', \%HPVALUE),
868                              new_check_button_for (\%pr::gui, 'next_del', \%HPVALUE),
869                              new_selection_box_for (\%pr::gui, 'from_show', \%HPVALUE)),
870                          $xl::s{mlist_frame}, 'not-packed'),
871                      FALSE, FALSE, FRAME_SPC);
872     $gf->pack_start (new_subpage_frame (
873                          new_hbox_pack (
874                              new_check_button_for (\%pr::gui, 'cursor_v', \%HPVALUE),
875                              new_check_button_for (\%pr::gui, 'mview_date', \%HPVALUE)),
876                          $xl::s{mview_frame}, 'not-packed'),
877                      FALSE, FALSE, FRAME_SPC);
878     $gf->pack_start (new_subpage_frame (
879                          new_hbox_pack (
880                              new_check_button_for (\%pr::gui, 'no_markup', \%HPVALUE),
881                              new_check_button_for (\%pr::gui, 'margin_co', \%HPVALUE),
882                              new_check_button_for (\%pr::gui, 'type_any', \%HPVALUE)),
883                          $xl::s{compo_frame}, 'not-packed'),
884                      FALSE, FALSE, FRAME_SPC);
885     $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
886     $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
887     $gf->pack_start (new_subpage_frame (
888                          new_vbox_pack (
889                              new_check_button_for (\%pr::gui, 'h_scroll', \%HPVALUE),
890                              new_selection_box_for (\%pr::gui, 'v_scroll', \%HPVALUE)),
891                          $xl::s{sbar_frame}, 'not-packed'),
892                      FALSE, FALSE, FRAME_SPC);
893     $gf->pack_start ($tb_zero_char, FALSE, FALSE, 0);
894
895     return $gf;
896 }
897
898 %pr::beh = ( # tweak some behaviour
899     hover_t => [
900         'hover_timeout',
901         $xl::s{l_beh_hover_t},
902         $xl::s{h_beh_hover_t},
903         'int,100,3000', # 0.1 seconds - 3 seconds
904         '0.0.0',
905         '500',
906     ],
907     dangerous => [
908         'live_dangerously',
909         $xl::s{l_beh_dangerous},
910         $xl::s{h_beh_dangerous},
911         'bool',
912         '0.0.0',
913         '0',
914     ],
915     flowed => [
916         'respect_flowed_format',
917         $xl::s{l_beh_flowed},
918         $xl::s{h_beh_flowed},
919         'bool',
920         '0.0.0',
921         '0',
922     ],
923     parts_rw => [
924         'save_parts_readwrite',
925         $xl::s{l_beh_parts_rw},
926         $xl::s{h_beh_parts_rw},
927         'bool',
928         '0.0.0',
929         '0',
930     ],
931     skip_ssl => [
932         'skip_ssl_cert_check',
933         $xl::s{l_beh_skip_ssl},
934         $xl::s{h_beh_skip_ssl},
935         'bool',
936         '0.0.0',
937         '0',
938     ],
939     up_step => [
940         'statusbar_update_step',
941         $xl::s{l_beh_up_step},
942         $xl::s{h_beh_up_step},
943         'int,1,200', # 1 item - 200 items
944         '0.0.0',
945         '10',
946     ],
947     thread_a => [
948         'thread_by_subject_max_age',
949         $xl::s{l_beh_thread_a},
950         $xl::s{h_beh_thread_a},
951         'int,1,30', # 1 day - 30 days
952         '0.0.0',
953         '10',
954     ],
955     unsafe_ssl => [
956         'unsafe_ssl_certs',
957         $xl::s{l_beh_unsafe_ssl},
958         $xl::s{h_beh_unsafe_ssl},
959         'bool',
960         '0.0.0',
961         '0',
962     ],
963     use_utf8 => [
964         'utf8_instead_of_locale_for_broken_mail',
965         $xl::s{l_beh_use_utf8},
966         $xl::s{h_beh_use_utf8},
967         'bool',
968         '0.0.0',
969         '0',
970     ],
971     warn_dnd => [
972         'warn_dnd',
973         $xl::s{l_beh_warn_dnd},
974         $xl::s{h_beh_warn_dnd},
975         'bool',
976         '0.0.0',
977         '1',
978     ],
979     out_ascii => [
980         'outgoing_fallback_to_ascii',
981         $xl::s{l_beh_out_ascii},
982         $xl::s{h_beh_out_ascii},
983         'bool',
984         '3.4.0.37',
985         '1',
986     ],
987     pp_unsel => [
988         'primary_paste_unselects',
989         $xl::s{l_beh_pp_unsel},
990         $xl::s{h_beh_pp_unsel},
991         'bool',
992         '3.6.1.35',
993         '0',
994     ],
995     inline_at => [
996         'show_inline_attachments',
997         $xl::s{l_beh_inline_at},
998         $xl::s{h_beh_inline_at},
999         'bool',
1000         '3.7.8.48',
1001         '1',
1002     ],
1003     addr_swc => [
1004         'address_search_wildcard',
1005         $xl::s{l_beh_addr_swc},
1006         $xl::s{h_beh_addr_swc},
1007         'bool',
1008         '3.9.3.18',
1009         '0',
1010     ],
1011     fold_swc => [
1012         'folder_search_wildcard',
1013         $xl::s{l_beh_fold_swc},
1014         $xl::s{h_beh_fold_swc},
1015         'bool',
1016         '3.9.3.18',
1017         '0',
1018     ],
1019 );
1020
1021 sub new_behaviour_page() {
1022     my $bf = Gtk2::VBox->new (FALSE, 5);
1023     $bf->set_border_width (PAGE_SPC);
1024
1025     my $tb_up_step = new_text_box_for_int (\%pr::beh, 'up_step', \%HPVALUE);
1026     my $tb_thread_a = new_text_box_for_int (\%pr::beh, 'thread_a', \%HPVALUE);
1027
1028     $bf->pack_start (new_subpage_frame (
1029                          new_vbox_pack (
1030                              new_text_box_for_int (\%pr::beh, 'hover_t', \%HPVALUE),
1031                              new_check_button_for (\%pr::beh, 'warn_dnd', \%HPVALUE)),
1032                          $xl::s{dnd_frame}, 'not-packed'),
1033                      FALSE, FALSE, FRAME_SPC);
1034     $bf->pack_start (new_subpage_frame (
1035                          new_hbox_pack (
1036                              new_check_button_for (\%pr::beh, 'skip_ssl', \%HPVALUE),
1037                              new_check_button_for (\%pr::beh, 'unsafe_ssl', \%HPVALUE)),
1038                          $xl::s{ssl_frame}, 'not-packed'),
1039                      FALSE, FALSE, FRAME_SPC);
1040     $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
1041     $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
1042     $bf->pack_start (new_subpage_frame (
1043                          new_vbox_pack (
1044                              new_check_button_for (\%pr::beh, 'flowed', \%HPVALUE),
1045                              new_check_button_for (\%pr::beh, 'parts_rw', \%HPVALUE),
1046                              new_check_button_for (\%pr::beh, 'use_utf8', \%HPVALUE),
1047                              new_check_button_for (\%pr::beh, 'dangerous', \%HPVALUE),
1048                              new_check_button_for (\%pr::beh, 'out_ascii', \%HPVALUE),
1049                              new_check_button_for (\%pr::beh, 'pp_unsel', \%HPVALUE),
1050                              new_check_button_for (\%pr::beh, 'inline_at', \%HPVALUE)),
1051                          $xl::s{msgs_frame}, 'not-packed'),
1052                      FALSE, FALSE, FRAME_SPC);
1053     $bf->pack_start (new_subpage_frame (
1054                          new_vbox_pack (
1055                              new_check_button_for (\%pr::beh, 'addr_swc', \%HPVALUE),
1056                              new_check_button_for (\%pr::beh, 'fold_swc', \%HPVALUE)),
1057                          $xl::s{swc_frame}, 'not-packed'),
1058                      FALSE, FALSE, FRAME_SPC);
1059     return $bf;
1060 }
1061
1062 %pr::col = ( # a variety of colours
1063     emphasis => [
1064         'emphasis_color',
1065         $xl::s{l_col_emphasis},
1066         $xl::s{h_col_emphasis},
1067         'color',
1068         '0.0.0',
1069         '#0000cf',
1070     ],
1071     log_err => [
1072         'log_error_color',
1073         $xl::s{l_col_log_err},
1074         $xl::s{h_col_log_err},
1075         'color',
1076         '0.0.0',
1077         '#af0000',
1078     ],
1079     log_in => [
1080         'log_in_color',
1081         $xl::s{l_col_log_in},
1082         $xl::s{h_col_log_in},
1083         'color',
1084         '0.0.0',
1085         '#000000',
1086     ],
1087     log_msg => [
1088         'log_msg_color',
1089         $xl::s{l_col_log_msg},
1090         $xl::s{h_col_log_msg},
1091         'color',
1092         '0.0.0',
1093         '#00af00',
1094     ],
1095     log_out => [
1096         'log_out_color',
1097         $xl::s{l_col_log_out},
1098         $xl::s{h_col_log_out},
1099         'color',
1100         '0.0.0',
1101         '#0000ef',
1102     ],
1103     log_warn => [
1104         'log_warn_color',
1105         $xl::s{l_col_log_warn},
1106         $xl::s{h_col_log_warn},
1107         'color',
1108         '0.0.0',
1109         '#af0000',
1110     ],
1111     diff_add => [
1112         'diff_added_color',
1113         $xl::s{l_col_diff_add},
1114         $xl::s{h_col_diff_add},
1115         'color',
1116         '3.8.0.54',
1117         '#008b8b',
1118     ],
1119     diff_del => [
1120         'diff_deleted_color',
1121         $xl::s{l_col_diff_del},
1122         $xl::s{h_col_diff_del},
1123         'color',
1124         '3.8.0.54',
1125         '#6a5acd',
1126     ],
1127     diff_hunk => [
1128         'diff_hunk_color',
1129         $xl::s{l_col_diff_hunk},
1130         $xl::s{h_col_diff_hunk},
1131         'color',
1132         '3.8.0.54',
1133         '#a52a2a',
1134     ],
1135 );
1136
1137 sub new_colours_page() {
1138     return new_vbox_pack (
1139                new_subpage_frame (
1140                    new_vbox_pack (
1141                        new_color_button_for (\%pr::col, 'emphasis', \%HPVALUE)),
1142                    $xl::s{msgview_frame}, 'not-packed'),
1143                new_subpage_frame (
1144                    new_vbox_pack (
1145                        new_color_button_for (\%pr::col, 'log_err', \%HPVALUE),
1146                        new_color_button_for (\%pr::col, 'log_in', \%HPVALUE),
1147                        new_color_button_for (\%pr::col, 'log_msg', \%HPVALUE),
1148                        new_color_button_for (\%pr::col, 'log_out', \%HPVALUE),
1149                        new_color_button_for (\%pr::col, 'log_warn', \%HPVALUE)),
1150                    $xl::s{log_frame}, 'not-packed'),
1151                new_subpage_frame (
1152                    new_vbox_pack (
1153                        new_color_button_for (\%pr::col, 'diff_add', \%HPVALUE),
1154                        new_color_button_for (\%pr::col, 'diff_del', \%HPVALUE),
1155                        new_color_button_for (\%pr::col, 'diff_hunk', \%HPVALUE)),
1156                    $xl::s{diff_frame}, 'not-packed')
1157            );
1158 }
1159
1160 %pr::win = ( # tweak window positions and/or sizes
1161     main_x => [
1162         'mainwin_x',
1163         $xl::s{l_win_x},
1164         $xl::s{h_win_x},
1165         'int,0,3000', # 0 pixels - 3000 pixels
1166         '0.0.0',
1167         '16',
1168     ],
1169     main_y => [
1170         'mainwin_y',
1171         $xl::s{l_win_y},
1172         $xl::s{h_win_y},
1173         'int,0,3000', # 0 pixels - 3000 pixels
1174         '0.0.0',
1175         '16',
1176     ],
1177     main_w => [
1178         'mainwin_width',
1179         $xl::s{l_win_w},
1180         $xl::s{h_win_w},
1181         'int,0,3000', # 0 pixels - 3000 pixels
1182         '0.0.0',
1183         '779',
1184     ],
1185     main_h => [
1186         'mainwin_height',
1187         $xl::s{l_win_h},
1188         $xl::s{h_win_h},
1189         'int,0,3000', # 0 pixels - 3000 pixels
1190         '0.0.0',
1191         '568',
1192     ],
1193     main_mx => [
1194         'mainwin_maximised',
1195         $xl::s{l_win_main_mx},
1196         $xl::s{h_win_main_mx},
1197         'bool',
1198         '0.0.0',
1199         '0',
1200     ],
1201     main_fs => [
1202         'mainwin_fullscreen',
1203         $xl::s{l_win_main_fs},
1204         $xl::s{h_win_main_fs},
1205         'bool',
1206         '0.0.0',
1207         '0',
1208     ],
1209     msgs_x => [
1210         'main_messagewin_x',
1211         $xl::s{l_win_x},
1212         $xl::s{h_win_x},
1213         'int,0,3000', # 0 pixels - 3000 pixels
1214         '0.0.0',
1215         '256',
1216     ],
1217     msgs_y => [
1218         'main_messagewin_y',
1219         $xl::s{l_win_y},
1220         $xl::s{h_win_y},
1221         'int,0,3000', # 0 pixels - 3000 pixels
1222         '0.0.0',
1223         '210',
1224     ],
1225     msgs_w => [
1226         'messagewin_width',
1227         $xl::s{l_win_w},
1228         $xl::s{h_win_w},
1229         'int,0,3000', # 0 pixels - 3000 pixels
1230         '0.0.0',
1231         '600',
1232     ],
1233     msgs_h => [
1234         'messagewin_height',
1235         $xl::s{l_win_h},
1236         $xl::s{h_win_h},
1237         'int,0,3000', # 0 pixels - 3000 pixels
1238         '0.0.0',
1239         '540',
1240     ],
1241     send_w => [
1242         'sendwin_width',
1243         $xl::s{l_win_w},
1244         $xl::s{h_win_w},
1245         'int,0,3000', # 0 pixels - 3000 pixels
1246         '0.0.0',
1247         '460',
1248     ],
1249     send_h => [
1250         'sendwin_height',
1251         $xl::s{l_win_h},
1252         $xl::s{h_win_h},
1253         'int,0,3000', # 0 pixels - 3000 pixels
1254         '0.0.0',
1255         '-1',
1256     ],
1257     recv_w => [
1258         'receivewin_width',
1259         $xl::s{l_win_w},
1260         $xl::s{h_win_w},
1261         'int,0,3000', # 0 pixels - 3000 pixels
1262         '0.0.0',
1263         '460',
1264     ],
1265     recv_h => [
1266         'receivewin_height',
1267         $xl::s{l_win_h},
1268         $xl::s{h_win_h},
1269         'int,0,3000', # 0 pixels - 3000 pixels
1270         '0.0.0',
1271         '-1',
1272     ],
1273     fold_x => [
1274         'folderwin_x',
1275         $xl::s{l_win_x},
1276         $xl::s{h_win_x},
1277         'int,0,3000', # 0 pixels - 3000 pixels
1278         '0.0.0',
1279         '16',
1280     ],
1281     fold_y => [
1282         'folderwin_y',
1283         $xl::s{l_win_y},
1284         $xl::s{h_win_y},
1285         'int,0,3000', # 0 pixels - 3000 pixels
1286         '0.0.0',
1287         '16',
1288     ],
1289     fold_w => [
1290         'folderitemwin_width',
1291         $xl::s{l_win_w},
1292         $xl::s{h_win_w},
1293         'int,0,3000', # 0 pixels - 3000 pixels
1294         '0.0.0',
1295         '500',
1296     ],
1297     fold_h => [
1298         'folderitemwin_height',
1299         $xl::s{l_win_h},
1300         $xl::s{h_win_h},
1301         'int,0,3000', # 0 pixels - 3000 pixels
1302         '0.0.0',
1303         '-1',
1304     ],
1305     fsel_w => [
1306         'folderselwin_width',
1307         $xl::s{l_win_w},
1308         $xl::s{h_win_w},
1309         'int,0,3000', # 0 pixels - 3000 pixels
1310         '0.0.0',
1311         '300',
1312     ],
1313     fsel_h => [
1314         'folderselwin_height',
1315         $xl::s{l_win_h},
1316         $xl::s{h_win_h},
1317         'int,0,3000', # 0 pixels - 3000 pixels
1318         '0.0.0',
1319         '-1',
1320     ],
1321     sour_w => [
1322         'sourcewin_width',
1323         $xl::s{l_win_w},
1324         $xl::s{h_win_w},
1325         'int,0,3000', # 0 pixels - 3000 pixels
1326         '0.0.0',
1327         '600',
1328     ],
1329     sour_h => [
1330         'sourcewin_height',
1331         $xl::s{l_win_h},
1332         $xl::s{h_win_h},
1333         'int,0,3000', # 0 pixels - 3000 pixels
1334         '0.0.0',
1335         '500',
1336     ],
1337     addr_w => [
1338         'addressbookwin_width',
1339         $xl::s{l_win_w},
1340         $xl::s{h_win_w},
1341         'int,0,3000', # 0 pixels - 3000 pixels
1342         '0.0.0',
1343         '520',
1344     ],
1345     addr_h => [
1346         'addressbookwin_height',
1347         $xl::s{l_win_h},
1348         $xl::s{h_win_h},
1349         'int,0,3000', # 0 pixels - 3000 pixels
1350         '0.0.0',
1351         '-1',
1352     ],
1353     adep_w => [
1354         'addressbookeditpersonwin_width',
1355         $xl::s{l_win_w},
1356         $xl::s{h_win_w},
1357         'int,0,3000', # 0 pixels - 3000 pixels
1358         '0.0.0',
1359         '640',
1360     ],
1361     adep_h => [
1362         'addressbookeditpersonwin_height',
1363         $xl::s{l_win_h},
1364         $xl::s{h_win_h},
1365         'int,0,3000', # 0 pixels - 3000 pixels
1366         '0.0.0',
1367         '320',
1368     ],
1369     adeg_w => [
1370         'addressbookeditgroupwin_width',
1371         $xl::s{l_win_w},
1372         $xl::s{h_win_w},
1373         'int,0,3000', # 0 pixels - 3000 pixels
1374         '0.0.0',
1375         '580',
1376     ],
1377     adeg_h => [
1378         'addressbookeditgroupwin_height',
1379         $xl::s{l_win_h},
1380         $xl::s{h_win_h},
1381         'int,0,3000', # 0 pixels - 3000 pixels
1382         '0.0.0',
1383         '340',
1384     ],
1385     adda_w => [
1386         'addressaddwin_width',
1387         $xl::s{l_win_w},
1388         $xl::s{h_win_w},
1389         'int,0,3000', # 0 pixels - 3000 pixels
1390         '0.0.0',
1391         '300',
1392     ],
1393     adda_h => [
1394         'addressaddwin_height',
1395         $xl::s{l_win_h},
1396         $xl::s{h_win_h},
1397         'int,0,3000', # 0 pixels - 3000 pixels
1398         '0.0.0',
1399         '-1',
1400     ],
1401     addf_w => [
1402         'addressbook_folderselwin_width',
1403         $xl::s{l_win_w},
1404         $xl::s{h_win_w},
1405         'int,0,3000', # 0 pixels - 3000 pixels
1406         '0.0.0',
1407         '300',
1408     ],
1409     addf_h => [
1410         'addressbook_folderselwin_height',
1411         $xl::s{l_win_h},
1412         $xl::s{h_win_h},
1413         'int,0,3000', # 0 pixels - 3000 pixels
1414         '0.0.0',
1415         '-1',
1416     ],
1417     acce_w => [
1418         'editaccountwin_width',
1419         $xl::s{l_win_w},
1420         $xl::s{h_win_w},
1421         'int,0,3000', # 0 pixels - 3000 pixels
1422         '0.0.0',
1423         '500',
1424     ],
1425     acce_h => [
1426         'editaccountwin_height',
1427         $xl::s{l_win_h},
1428         $xl::s{h_win_h},
1429         'int,0,3000', # 0 pixels - 3000 pixels
1430         '0.0.0',
1431         '-1',
1432     ],
1433     acco_w => [
1434         'accountswin_width',
1435         $xl::s{l_win_w},
1436         $xl::s{h_win_w},
1437         'int,0,3000', # 0 pixels - 3000 pixels
1438         '0.0.0',
1439         '500',
1440     ],
1441     acco_h => [
1442         'accountswin_height',
1443         $xl::s{l_win_h},
1444         $xl::s{h_win_h},
1445         'int,0,3000', # 0 pixels - 3000 pixels
1446         '0.0.0',
1447         '-1',
1448     ],
1449     filt_w => [
1450         'filteringwin_width',
1451         $xl::s{l_win_w},
1452         $xl::s{h_win_w},
1453         'int,0,3000', # 0 pixels - 3000 pixels
1454         '0.0.0',
1455         '500',
1456     ],
1457     filt_h => [
1458         'filteringwin_height',
1459         $xl::s{l_win_h},
1460         $xl::s{h_win_h},
1461         'int,0,3000', # 0 pixels - 3000 pixels
1462         '0.0.0',
1463         '-1',
1464     ],
1465     fila_w => [
1466         'filteringactionwin_width',
1467         $xl::s{l_win_w},
1468         $xl::s{h_win_w},
1469         'int,0,3000', # 0 pixels - 3000 pixels
1470         '0.0.0',
1471         '490',
1472     ],
1473     fila_h => [
1474         'filteringactionwin_height',
1475         $xl::s{l_win_h},
1476         $xl::s{h_win_h},
1477         'int,0,3000', # 0 pixels - 3000 pixels
1478         '0.0.0',
1479         '-1',
1480     ],
1481     fild_w => [
1482         'filtering_debugwin_width',
1483         $xl::s{l_win_w},
1484         $xl::s{h_win_w},
1485         'int,0,3000', # 0 pixels - 3000 pixels
1486         '0.0.0',
1487         '600',
1488     ],
1489     fild_h => [
1490         'filtering_debugwin_height',
1491         $xl::s{l_win_h},
1492         $xl::s{h_win_h},
1493         'int,0,3000', # 0 pixels - 3000 pixels
1494         '0.0.0',
1495         '-1',
1496     ],
1497     matc_w => [
1498         'matcherwin_width',
1499         $xl::s{l_win_w},
1500         $xl::s{h_win_w},
1501         'int,0,3000', # 0 pixels - 3000 pixels
1502         '0.0.0',
1503         '520',
1504     ],
1505     matc_h => [
1506         'matcherwin_height',
1507         $xl::s{l_win_h},
1508         $xl::s{h_win_h},
1509         'int,0,3000', # 0 pixels - 3000 pixels
1510         '0.0.0',
1511         '-1',
1512     ],
1513     pref_w => [
1514         'prefswin_width',
1515         $xl::s{l_win_w},
1516         $xl::s{h_win_w},
1517         'int,0,3000', # 0 pixels - 3000 pixels
1518         '0.0.0',
1519         '600',
1520     ],
1521     pref_h => [
1522         'prefswin_height',
1523         $xl::s{l_win_h},
1524         $xl::s{h_win_h},
1525         'int,0,3000', # 0 pixels - 3000 pixels
1526         '0.0.0',
1527         '-1',
1528     ],
1529     temp_w => [
1530         'templateswin_width',
1531         $xl::s{l_win_w},
1532         $xl::s{h_win_w},
1533         'int,0,3000', # 0 pixels - 3000 pixels
1534         '0.0.0',
1535         '480',
1536     ],
1537     temp_h => [
1538         'templateswin_height',
1539         $xl::s{l_win_h},
1540         $xl::s{h_win_h},
1541         'int,0,3000', # 0 pixels - 3000 pixels
1542         '0.0.0',
1543         '-1',
1544     ],
1545     acti_w => [
1546         'actionswin_width',
1547         $xl::s{l_win_w},
1548         $xl::s{h_win_w},
1549         'int,0,3000', # 0 pixels - 3000 pixels
1550         '0.0.0',
1551         '486',
1552     ],
1553     acti_h => [
1554         'actionswin_height',
1555         $xl::s{l_win_h},
1556         $xl::s{h_win_h},
1557         'int,0,3000', # 0 pixels - 3000 pixels
1558         '0.0.0',
1559         '-1',
1560     ],
1561     tags_w => [
1562         'tagswin_width',
1563         $xl::s{l_win_w},
1564         $xl::s{h_win_w},
1565         'int,0,3000', # 0 pixels - 3000 pixels
1566         '0.0.0',
1567         '486',
1568     ],
1569     tags_h => [
1570         'tagswin_height',
1571         $xl::s{l_win_h},
1572         $xl::s{h_win_h},
1573         'int,0,3000', # 0 pixels - 3000 pixels
1574         '0.0.0',
1575         '-1',
1576     ],
1577     plug_w => [
1578         'pluginswin_width',
1579         $xl::s{l_win_w},
1580         $xl::s{h_win_w},
1581         'int,0,3000', # 0 pixels - 3000 pixels
1582         '0.0.0',
1583         '-1',
1584     ],
1585     plug_h => [
1586         'pluginswin_height',
1587         $xl::s{l_win_h},
1588         $xl::s{h_win_h},
1589         'int,0,3000', # 0 pixels - 3000 pixels
1590         '0.0.0',
1591         '-1',
1592     ],
1593     logw_w => [
1594         'logwin_width',
1595         $xl::s{l_win_w},
1596         $xl::s{h_win_w},
1597         'int,0,3000', # 0 pixels - 3000 pixels
1598         '0.0.0',
1599         '520',
1600     ],
1601     logw_h => [
1602         'logwin_height',
1603         $xl::s{l_win_h},
1604         $xl::s{h_win_h},
1605         'int,0,3000', # 0 pixels - 3000 pixels
1606         '0.0.0',
1607         '-1',
1608     ],
1609     prin_w => [
1610         'print_previewwin_width',
1611         $xl::s{l_win_w},
1612         $xl::s{h_win_w},
1613         'int,0,3000', # 0 pixels - 3000 pixels
1614         '0.0.0',
1615         '600',
1616     ],
1617     prin_h => [
1618         'print_previewwin_height',
1619         $xl::s{l_win_h},
1620         $xl::s{h_win_h},
1621         'int,0,3000', # 0 pixels - 3000 pixels
1622         '0.0.0',
1623         '-1',
1624     ],
1625 );
1626
1627 sub new_winpos_subpage_main() {
1628     return new_subpage_frame (
1629                new_vbox_pack_compact (
1630                    new_vbox_pack (
1631                        new_text_box_for_int (\%pr::win, 'main_x', \%HPVALUE),
1632                        new_text_box_for_int (\%pr::win, 'main_y', \%HPVALUE)),
1633                    new_hbox_pack (
1634                        new_text_box_for_int (\%pr::win, 'main_w', \%HPVALUE),
1635                        new_text_box_for_int (\%pr::win, 'main_h', \%HPVALUE)),
1636                    new_vbox_pack (
1637                        new_check_button_for (\%pr::win, 'main_fs', \%HPVALUE),
1638                        new_check_button_for (\%pr::win, 'main_mx', \%HPVALUE))),
1639                _('Main window')
1640            );
1641 }
1642
1643 sub new_winpos_subpage_msgs() {
1644     return new_subpage_frame (
1645                new_vbox_pack_compact (
1646                    new_vbox_pack (
1647                        new_text_box_for_int (\%pr::win, 'msgs_x', \%HPVALUE),
1648                        new_text_box_for_int (\%pr::win, 'msgs_y', \%HPVALUE)),
1649                    new_hbox_pack (
1650                        new_text_box_for_int (\%pr::win, 'msgs_w', \%HPVALUE),
1651                        new_text_box_for_int (\%pr::win, 'msgs_h', \%HPVALUE))),
1652                _('Message window')
1653            );
1654 }
1655
1656 sub new_winpos_subpage_sendrecv() {
1657     return new_vbox_pack (
1658                new_subpage_frame (
1659                    new_hbox_pack (
1660                        new_text_box_for_int (\%pr::win, 'send_w', \%HPVALUE),
1661                        new_text_box_for_int (\%pr::win, 'send_h', \%HPVALUE)),
1662                    _('Send window'), 'not-packed'),
1663                new_subpage_frame (
1664                    new_hbox_pack (
1665                        new_text_box_for_int (\%pr::win, 'recv_w', \%HPVALUE),
1666                        new_text_box_for_int (\%pr::win, 'recv_h', \%HPVALUE)),
1667                    _('Receive window'), 'not-packed')
1668            );
1669 }
1670
1671 sub new_winpos_subpage_fold() {
1672     return new_vbox_pack (
1673                new_subpage_frame (
1674                    new_vbox_pack_compact (
1675                        new_vbox_pack (
1676                             new_text_box_for_int (\%pr::win, 'fold_x', \%HPVALUE),
1677                             new_text_box_for_int (\%pr::win, 'fold_y', \%HPVALUE)),
1678                        new_hbox_pack (
1679                            new_text_box_for_int (\%pr::win, 'fold_w', \%HPVALUE),
1680                            new_text_box_for_int (\%pr::win, 'fold_h', \%HPVALUE))),
1681                    _('Folder window'), 'not-packed'),
1682                new_subpage_frame (
1683                    new_hbox_pack (
1684                        new_text_box_for_int (\%pr::win, 'fsel_w', \%HPVALUE),
1685                        new_text_box_for_int (\%pr::win, 'fsel_h', \%HPVALUE)),
1686                    _('Folder selection window'), 'not-packed')
1687            );
1688 }
1689
1690 sub new_winpos_subpage_addrbook() {
1691     return new_vbox_pack (
1692                 new_subpage_frame (
1693                      new_hbox_pack (
1694                           new_text_box_for_int (\%pr::win, 'addr_w', \%HPVALUE),
1695                           new_text_box_for_int (\%pr::win, 'addr_h', \%HPVALUE)),
1696                      _('Addressbook main window'), 'not-packed'),
1697                 new_subpage_frame (
1698                      new_hbox_pack (
1699                           new_text_box_for_int (\%pr::win, 'adep_w', \%HPVALUE),
1700                           new_text_box_for_int (\%pr::win, 'adep_h', \%HPVALUE)),
1701                      _('Edit person window'), 'not-packed'),
1702                 new_subpage_frame (
1703                      new_hbox_pack (
1704                           new_text_box_for_int (\%pr::win, 'adeg_w', \%HPVALUE),
1705                           new_text_box_for_int (\%pr::win, 'adeg_h', \%HPVALUE)),
1706                      _('Edit group window'), 'not-packed'),
1707                 new_subpage_frame (
1708                      new_hbox_pack (
1709                           new_text_box_for_int (\%pr::win, 'adda_w', \%HPVALUE),
1710                           new_text_box_for_int (\%pr::win, 'adda_h', \%HPVALUE)),
1711                      _('Add address window'), 'not-packed'),
1712                 new_subpage_frame (
1713                      new_hbox_pack (
1714                           new_text_box_for_int (\%pr::win, 'addf_w', \%HPVALUE),
1715                           new_text_box_for_int (\%pr::win, 'addf_h', \%HPVALUE)),
1716                      _('Folder select window'), 'not-packed')
1717            );
1718 }
1719
1720 sub new_winpos_subpage_accounts() {
1721     return new_vbox_pack (
1722                 new_subpage_frame (
1723                      new_hbox_pack (
1724                           new_text_box_for_int (\%pr::win, 'acco_w', \%HPVALUE),
1725                           new_text_box_for_int (\%pr::win, 'acco_h', \%HPVALUE)),
1726                      _('Accounts window'), 'not-packed'),
1727                 new_subpage_frame (
1728                      new_hbox_pack (
1729                           new_text_box_for_int (\%pr::win, 'acce_w', \%HPVALUE),
1730                           new_text_box_for_int (\%pr::win, 'acce_h', \%HPVALUE)),
1731                      _('Edit account window'), 'not-packed')
1732            );
1733 }
1734
1735 sub new_winpos_subpage_filtering() {
1736     return new_vbox_pack (
1737                 new_subpage_frame (
1738                      new_hbox_pack (
1739                           new_text_box_for_int (\%pr::win, 'filt_w', \%HPVALUE),
1740                           new_text_box_for_int (\%pr::win, 'filt_h', \%HPVALUE)),
1741                      _('Filtering window'), 'not-packed'),
1742                 new_subpage_frame (
1743                      new_hbox_pack (
1744                           new_text_box_for_int (\%pr::win, 'fila_w', \%HPVALUE),
1745                           new_text_box_for_int (\%pr::win, 'fila_h', \%HPVALUE)),
1746                      _('Filtering actions window'), 'not-packed'),
1747                 new_subpage_frame (
1748                      new_hbox_pack (
1749                           new_text_box_for_int (\%pr::win, 'fild_w', \%HPVALUE),
1750                           new_text_box_for_int (\%pr::win, 'fild_h', \%HPVALUE)),
1751                      _('Filtering debug window'), 'not-packed'),
1752                 new_subpage_frame (
1753                      new_hbox_pack (
1754                           new_text_box_for_int (\%pr::win, 'matc_w', \%HPVALUE),
1755                           new_text_box_for_int (\%pr::win, 'matc_h', \%HPVALUE)),
1756                      _('Matcher window'), 'not-packed')
1757            );
1758 }
1759
1760 sub new_winpos_subpage_prefs() {
1761     return new_vbox_pack (
1762                 new_subpage_frame (
1763                      new_hbox_pack (
1764                           new_text_box_for_int (\%pr::win, 'pref_w', \%HPVALUE),
1765                           new_text_box_for_int (\%pr::win, 'pref_h', \%HPVALUE)),
1766                      _('Preferences window'), 'not-packed'),
1767                 new_subpage_frame (
1768                      new_hbox_pack (
1769                           new_text_box_for_int (\%pr::win, 'temp_w', \%HPVALUE),
1770                           new_text_box_for_int (\%pr::win, 'temp_h', \%HPVALUE)),
1771                      _('Templates window'), 'not-packed'),
1772                 new_subpage_frame (
1773                      new_hbox_pack (
1774                           new_text_box_for_int (\%pr::win, 'acti_w', \%HPVALUE),
1775                           new_text_box_for_int (\%pr::win, 'acti_h', \%HPVALUE)),
1776                      _('Actions window'), 'not-packed'),
1777                 new_subpage_frame (
1778                      new_hbox_pack (
1779                           new_text_box_for_int (\%pr::win, 'tags_w', \%HPVALUE),
1780                           new_text_box_for_int (\%pr::win, 'tags_h', \%HPVALUE)),
1781                      _('Tags window'), 'not-packed'),
1782                 new_subpage_frame (
1783                      new_hbox_pack (
1784                           new_text_box_for_int (\%pr::win, 'plug_w', \%HPVALUE),
1785                           new_text_box_for_int (\%pr::win, 'plug_h', \%HPVALUE)),
1786                      _('Plugins window'), 'not-packed')
1787            );
1788 }
1789
1790 sub new_winpos_subpage_misc() {
1791     return new_vbox_pack (
1792                 new_subpage_frame (
1793                      new_hbox_pack (
1794                           new_text_box_for_int (\%pr::win, 'logw_w', \%HPVALUE),
1795                           new_text_box_for_int (\%pr::win, 'logw_h', \%HPVALUE)),
1796                      _('Log window'), 'not-packed'),
1797                 new_subpage_frame (
1798                      new_hbox_pack (
1799                           new_text_box_for_int (\%pr::win, 'prin_w', \%HPVALUE),
1800                           new_text_box_for_int (\%pr::win, 'prin_h', \%HPVALUE)),
1801                      _('Print preview window'), 'not-packed'),
1802                 new_subpage_frame (
1803                      new_hbox_pack (
1804                           new_text_box_for_int (\%pr::win, 'sour_w', \%HPVALUE),
1805                           new_text_box_for_int (\%pr::win, 'sour_h', \%HPVALUE)),
1806                      _('View source window'), 'not-packed')
1807            );
1808 }
1809
1810 sub new_winpos_page() {
1811     my $winbook = Gtk2::Notebook->new;
1812     $winbook->set_tab_pos ('right');
1813     $winbook->append_page (new_winpos_subpage_main, _('Main'));
1814     $winbook->append_page (new_winpos_subpage_msgs, _('Message'));
1815     $winbook->append_page (new_winpos_subpage_sendrecv, _('Send/Receive'));
1816     $winbook->append_page (new_winpos_subpage_fold, _('Folder'));
1817     $winbook->append_page (new_winpos_subpage_addrbook, _('Addressbook'));
1818     $winbook->append_page (new_winpos_subpage_accounts, _('Accounts'));
1819     $winbook->append_page (new_winpos_subpage_filtering, _('Filtering'));
1820     $winbook->append_page (new_winpos_subpage_prefs, _('Preferences'));
1821     $winbook->append_page (new_winpos_subpage_misc, _('Other'));
1822     return $winbook;
1823 }
1824
1825 %pr::acc = ( # per account hidden preferences
1826     tls_set => [
1827         'gnutls_set_priority',
1828         $xl::s{l_acc_gtls_set},
1829         $xl::s{h_acc_gtls_set},
1830         'bool',
1831         '3.9.0.181',
1832         '0',
1833     ],
1834     tls_pri => [
1835         'gnutls_priority',
1836         $xl::s{l_acc_gtls_pri},
1837         $xl::s{h_acc_gtls_pri},
1838         'char,0,256,32',
1839         '3.9.0.181',
1840         '0',
1841     ],
1842 );
1843
1844 sub new_account_subpage($) {
1845     my ($akey) = @_;
1846     return new_vbox_pack (
1847                 new_subpage_frame (
1848                     new_vbox_pack (
1849                         new_check_button_for (\%pr::acc, 'tls_set', $ACHPVALUE{$akey}),
1850                         new_text_box_for_nchar (\%pr::acc, 'tls_pri', $ACHPVALUE{$akey})),
1851                     _('GnuTLS priority'), 'not-packed')
1852            );
1853 }
1854
1855 sub new_accounts_page() {
1856     my $accbook = Gtk2::Notebook->new;
1857     $accbook->set_tab_pos ('right');
1858     my @akeys = sort {
1859         $ACPREFS{$a}{'account_name'} cmp $ACPREFS{$b}{'account_name'}
1860     } keys %ACPREFS;
1861     foreach (@akeys) {
1862         my $name = $ACPREFS{$_}{'account_name'};
1863         my $isdef = ($ACPREFS{$_}{'is_default'} eq '1');
1864         my $page = new_account_subpage ($_);
1865         $accbook->append_page ($page, $isdef? '<b>' . $name . '</b>': $name);
1866         if ($isdef) {
1867             my $label = $accbook->get_tab_label ($page);
1868             $label->set_use_markup (TRUE);
1869         }
1870     }
1871     return $accbook;
1872 }
1873
1874 %pr::plu = ( # plugins hidden preferences
1875     # att_remover
1876     arm_winw => [
1877         'win_width',
1878         $xl::s{l_win_w},
1879         $xl::s{h_win_w},
1880         'int,0,3000', # 0 pixels - 3000 pixels
1881         '3.9.0.74',
1882         '-1',
1883         'AttRemover',
1884     ],
1885     arm_winh => [
1886         'win_height',
1887         $xl::s{l_win_h},
1888         $xl::s{h_win_h},
1889         'int,0,3000', # 0 pixels - 3000 pixels
1890         '3.9.0.74',
1891         '-1',
1892         'AttRemover',
1893     ],
1894     # GPG
1895     gpg_alimit => [
1896         'autocompletion_limit',
1897         $xl::s{l_plu_gpg_alimit},
1898         $xl::s{h_plu_gpg_alimit},
1899         'int,0,100',
1900         '3.12.0.75',
1901         '0',
1902         'GPG',
1903     ],
1904     # managesieve
1905     msv_winw => [
1906         'manager_win_width',
1907         $xl::s{l_win_w},
1908         $xl::s{h_win_w},
1909         'int,0,3000', # 0 pixels - 3000 pixels
1910         '3.11.1.210',
1911         '-1',
1912         'ManageSieve',
1913     ],
1914     msv_winh => [
1915         'manager_win_height',
1916         $xl::s{l_win_h},
1917         $xl::s{h_win_h},
1918         'int,0,3000', # 0 pixels - 3000 pixels
1919         '3.11.1.210',
1920         '-1',
1921         'ManageSieve',
1922     ],
1923     # libravatar
1924     lav_burl => [
1925         'base_url',
1926         $xl::s{l_plu_lav_burl},
1927         $xl::s{h_plu_lav_burl},
1928         'char,0,1024,32',
1929         '3.9.3.32',
1930         'http://cdn.libravatar.org/avatar',
1931         'Libravatar',
1932     ],
1933     # perl
1934     prl_flvb => [
1935         'filter_log_verbosity',
1936         $xl::s{l_plu_prl_flvb},
1937         $xl::s{h_plu_prl_flvb},
1938         '0=l_plu_prl_none;1=l_plu_prl_manual;2=l_plu_prl_action;3=l_plu_prl_match',
1939         '3.9.0.75',
1940         '2',
1941         'PerlPlugin',
1942     ],
1943 );
1944
1945 sub new_plugins_page() {
1946     my %frame = ();
1947     $frame{'AttRemover'} =
1948                 new_subpage_frame (
1949                      new_hbox_pack (
1950                           new_text_box_for_int (\%pr::plu, 'arm_winw', $PLHPVALUE{'AttRemover'}),
1951                           new_text_box_for_int (\%pr::plu, 'arm_winh', $PLHPVALUE{'AttRemover'})),
1952                      _('Attachment remover'), 'not-packed');
1953     $frame{'GPG'} =
1954                 new_subpage_frame (
1955                      new_hbox_pack (
1956                           new_text_box_for_int (\%pr::plu, 'gpg_alimit', $PLHPVALUE{'GPG'})),
1957                      _('GPG'), 'not-packed');
1958     $frame{'ManageSieve'} =
1959                 new_subpage_frame (
1960                      new_hbox_pack (
1961                           new_text_box_for_int (\%pr::plu, 'msv_winw', $PLHPVALUE{'ManageSieve'}),
1962                           new_text_box_for_int (\%pr::plu, 'msv_winh', $PLHPVALUE{'ManageSieve'})),
1963                      _('Sieve manager'), 'not-packed');
1964     $frame{'Libravatar'} =
1965                 new_subpage_frame (
1966                      new_hbox_pack (
1967                           new_text_box_for_nchar (\%pr::plu, 'lav_burl', $PLHPVALUE{'Libravatar'})),
1968                      _('Libravatar'), 'not-packed');
1969     $frame{'PerlPlugin'} =
1970                 new_subpage_frame (
1971                      new_hbox_pack (
1972                           new_selection_box_for (\%pr::plu, 'prl_flvb', $PLHPVALUE{'PerlPlugin'})),
1973                      _('Perl'), 'not-packed');
1974     foreach (@PLUGINS) {
1975         $frame{$_}->set_sensitive (defined $PLHPVALUE{$_});
1976     }
1977     return new_vbox_pack (
1978                 $frame{'AttRemover'},
1979                 $frame{'GPG'},
1980                 $frame{'ManageSieve'},
1981                 $frame{'Libravatar'},
1982                 $frame{'PerlPlugin'});
1983 }
1984
1985 sub new_info_page() {
1986     my $t0 = Gtk2::Table->new (7, 2, FALSE);
1987     my $v = get_toolkit_versions ();
1988     my %labels = (
1989         'glib' => 'Perl-GLib',
1990         'glib-r' => _('GLib runtime'),
1991         'glib-b' => _('GLib built'),
1992         'gtk2' => 'Perl-GTK2',
1993         'gtk2-r' => _('GTK2 runtime'),
1994         'gtk2-b' => _('GTK2 built'),
1995     );
1996     my $row = 0;
1997     foreach (sort keys %$v) {
1998         if (defined $v->{$_}) {
1999             my $label = Gtk2::Label->new ($labels{$_});
2000             my $value = Gtk2::Label->new ('<b>' . $v->{$_} . '</b>');
2001             $label->set_alignment (0, 0.5);
2002             $value->set_alignment (0, 0.5);
2003             $value->set_use_markup (TRUE);
2004             $t0->attach ($label, 0, 1, $row, $row + 1, 'fill', 'shrink', 8, 6);
2005             $t0->attach ($value, 1, 2, $row, $row + 1, 'fill', 'shrink', 8, 6);
2006             ++$row;
2007         }
2008     }
2009     my $t1 = Gtk2::Table->new (2, 2, FALSE);
2010     my @lbl = map { $_->set_alignment (0, 0.5); $_ } (
2011         Gtk2::Label->new (_('Binary')),
2012         Gtk2::Label->new (_('Configuration'))
2013     );
2014     my $cfgv = $CONFIGDATA->{'Common'}{'config_version'};
2015     $cfgv //= '';
2016     my @val = map { $_->set_alignment (0, 0.5); $_->set_use_markup (TRUE); $_ } (
2017         Gtk2::Label->new ('<b>' . $CLAWSV . '</b>'),
2018         Gtk2::Label->new ('<b>' . $cfgv . '</b>')
2019     );
2020     for (my $i = 0; $i <= $#lbl; ++$i) {
2021         $t1->attach ($lbl[$i], 0, 1, $i, $i + 1, 'fill', 'shrink', 8, 6);
2022         $t1->attach ($val[$i], 1, 2, $i, $i + 1, 'fill', 'shrink', 8, 6);
2023     }
2024     return new_vbox_pack (
2025                 new_subpage_frame ($t0, _('Library versions'), 'not-packed'),
2026                 new_subpage_frame ($t1, _('Claws Mail versions'), 'not-packed'));
2027 }
2028
2029 # version info
2030 sub get_toolkit_versions {
2031     my %versions = ();
2032     $versions{'glib'} = $Glib::VERSION;
2033     # version info stuff appeared in 1.040
2034     if ($Glib::VERSION >= 1.040) {
2035         $versions{'glib-b'} = join('.', Glib->GET_VERSION_INFO);
2036         $versions{'glib-r'} = join('.',
2037             &Glib::major_version, &Glib::minor_version, &Glib::micro_version);
2038     }
2039     $versions{'gtk2'} = $Gtk2::VERSION;
2040     if ($Gtk2::VERSION >= 1.040) {
2041         $versions{'gtk2-b'} = join('.', Gtk2->GET_VERSION_INFO);
2042         $versions{'gtk2-r'} = join('.',
2043             &Gtk2::major_version, &Gtk2::minor_version, &Gtk2::micro_version);
2044     }
2045     return \%versions;
2046 }
2047
2048 sub print_version() {
2049     print $xl::s{about_title} . "\n";
2050     print $xl::s{about_version} . " $VERSION\n";
2051     my $v = get_toolkit_versions ();
2052     print "Perl-GLib " . $v->{'glib'};
2053     print _(", built for ") . $v->{'glib-b'}
2054         . _(", running with ") . $v->{'glib-r'} if $v->{'glib-b'};
2055     print "\n";
2056     print "Perl-GTK2 " . $v->{'gtk2'};
2057     print _(", built for ") . $v->{'gtk2-b'}
2058         . _(", running with ") . $v->{'gtk2-r'} if $v->{'gtk2-b'};
2059     print "\n";
2060     my $clawsver = ($CLAWSV eq "") ?
2061                 _("was not found!") :
2062                 (_("returned version ") . $CLAWSV);
2063     print "Claws Mail " . $clawsver . "\n";
2064 }
2065
2066 # the command line help
2067 sub print_help() {
2068     my $line = '-' x length ($xl::s{about_title}) . "\n";
2069     print $line;
2070     print $xl::s{about_title} . "\n";
2071     print $line;
2072     print _("Syntax:\n");
2073     print _("  clawsker [options]\n");
2074     print _("Options:\n");
2075     print _("  -a|--alternate-config-dir <dir>  Uses <dir> as Claws Mail config dir.\n");
2076     print _("  -b|--verbose                     More messages on standard output.\n");
2077     print _("  -c|--clawsrc <file>              Uses <file> as full resource name.\n");
2078     print _("  -h|--help                        Prints this help screen.\n");
2079     print _("  -r|--read-only                   Disables writing changes to disk.\n");
2080     print _("  -v|--version                     Prints version infos.\n");
2081 }
2082
2083 sub parse_command_line {
2084     my $cont = TRUE;
2085     $CLAWSV = get_claws_version ();
2086     eval {
2087         GetOptions('h|help' => sub { print_help (); $cont = FALSE },
2088             'v|version' => sub { print_version (); $cont = FALSE },
2089             'b|verbose' => sub { $VERBOSE = TRUE },
2090             'r|read-only' => sub { $READONLY = TRUE },
2091             'u|use-claws-version=s' => \&opt_use_claws_version,
2092             'a|alternate-config-dir=s' => \&opt_alternate_config_dir,
2093             'c|clawsrc=s' => \&opt_clawsrc)
2094         or die _("try -h or --help for syntax.\n");
2095     };
2096     if ($@) {
2097         my $msg = _("Error in options: {msg}\n", msg => $@);
2098         if (defined $ENV{'DISPLAY'} and $ENV{'DISPLAY'} ne '') {
2099             eval { Gtk2->init };
2100             error_dialog ($msg) unless $@;
2101         }
2102         die $msg;
2103     }
2104     return $cont;
2105 }
2106
2107 sub opt_use_claws_version {
2108     my ($name, $value) = @_;
2109     die _("Error: {opt} requires a dotted numeric value argument\n", opt => $name)
2110         unless ($value =~ /^[\d\.]+$/);
2111     $CLAWSV = $value;
2112 }
2113
2114 sub opt_alternate_config_dir {
2115     my ($name, $value) = @_;
2116     die _("Error: '{dir}' is not a directory or does not exist\n", dir => $value)
2117         unless -d $value;
2118     $CONFIGDIR = $value;
2119     $CONFIGDIR .= "/" unless ($CONFIGDIR =~ /.*\/$/);
2120     $ALTCONFIGDIR = TRUE;
2121 }
2122
2123 sub opt_clawsrc {
2124     my ($name, $value) = @_;
2125     die _("Error: '{value}' is not a file or does not exist\n", value => $value)
2126         unless -f $value;
2127     set_rc_filename ($value);
2128 }
2129
2130 # update the hidden preferences status from loaded values
2131 sub init_hidden_preferences {
2132     foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth, \%pr::win) {
2133         foreach my $key (keys %$hash) {
2134             $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
2135         }
2136     }
2137     return TRUE;
2138 }
2139
2140 sub init_ac_hidden_preferences {
2141     foreach my $akey (keys %ACPREFS) {
2142         foreach my $key (keys %pr::acc) {
2143             my $pname = $pr::acc{$key}[NAME];
2144             $ACHPVALUE{$akey}{$pname} = $ACPREFS{$akey}{$pname};
2145         }
2146     }
2147     return TRUE;
2148 }
2149
2150 sub init_plu_hidden_preferences {
2151     foreach my $key (keys %pr::plu) {
2152         my $plugin = $pr::plu{$key}[PLUGIN];
2153         my $pname = $pr::plu{$key}[NAME];
2154         if (defined $PLPREFS{$plugin}) {
2155             $PLHPVALUE{$plugin}{$pname} = $PLPREFS{$plugin}{$pname};
2156         }
2157     }
2158     return TRUE;
2159 }
2160
2161 # generic load/save resource files
2162 sub load_resource {
2163     my $rc = shift;
2164     my %data = ();
2165     my %meta = ();
2166     my $line = 0;
2167     open (RCF, '<:encoding(utf8)', $rc)
2168         or die _("Error: opening '{file}' for reading", file => $rc) . ": $!";
2169     my $section = '_'; # default unnamed section
2170     while (<RCF>) {
2171         chomp;
2172         ++$line;
2173         next if (/^\s*$/);
2174         if (/^\[([^\]]+)\]$/) { # new section
2175             $section = $1;
2176             die _("Error: duplicate section '{sect}' in resource file '{file}'\n",
2177                 sect => $section, file => $rc) if ($data{$section});
2178             $data{$section} = {};
2179             $meta{$section}{'#'} = $line;
2180         }
2181         elsif (/^([0-9a-z_]+)=(.*)$/) { # key=value
2182             $data{$section}{$1} = $2;
2183             $meta{$section}{$1} = $line;
2184         }
2185         elsif (/^(.*)$/) { # lone value
2186             push (@{$data{$section}{'_'}}, $1);
2187         }
2188     }
2189     close (RCF);
2190     return (\%data, \%meta);
2191 }
2192
2193 sub save_resource {
2194     my ($rc, $data, $meta) = @_;
2195     open (RCF, '>:utf8', $rc)
2196         or die _("Error: opening '{file}' for writing", file => $rc) . ": $!";
2197     my @sections = keys %$data;
2198     if (defined $meta) {
2199         @sections = sort {
2200             $meta->{$a}{'#'} <=> $meta->{$b}{'#'}
2201         } @sections
2202     }
2203     foreach my $section (@sections) {
2204         say RCF "[$section]";
2205         if (ref ($data->{$section}{'_'}) eq 'ARRAY') {
2206             foreach my $val (@{$data->{$section}{'_'}}) {
2207                 say RCF $val;
2208             }
2209         } else {
2210             my @keys = keys %{$data->{$section}};
2211             if (defined $meta) {
2212                 @keys = sort {
2213                     $meta->{$section}{$a} <=> $meta->{$section}{$b}
2214                 } @keys
2215             }
2216             foreach my $key (@keys) {
2217                 my $val = $data->{$section}{$key};
2218                 say RCF "$key=$val";
2219             }
2220         }
2221         say RCF "";
2222     }
2223     close (RCF);
2224 }
2225
2226 # load current status from disc
2227 sub load_preferences {
2228     my $rc = get_rc_filename ();
2229     log_message ("Loading preferences from $rc\n");
2230     return FALSE unless check_rc_file ($rc);
2231     return FALSE unless check_claws_not_running ();
2232     ($CONFIGDATA, $CONFIGMETA) = load_resource ($rc);
2233     foreach (keys %{$CONFIGDATA->{'Common'}}) {
2234         $PREFS{$_} = $CONFIGDATA->{'Common'}{$_};
2235     }
2236     foreach my $plugin (@PLUGINS) {
2237         if (defined $CONFIGDATA->{$plugin}) {
2238             push (@AVPLUGINS, $plugin);
2239             foreach (keys %{$CONFIGDATA->{$plugin}}) {
2240                 $PLPREFS{$plugin}{$_} = $CONFIGDATA->{$plugin}{$_};
2241             }
2242         }
2243     }
2244     return TRUE;
2245 }
2246
2247 sub load_ac_preferences {
2248     my $rc = get_ac_rc_filename ();
2249     log_message ("Loading account preferences from $rc\n");
2250     return FALSE unless check_rc_file ($rc);
2251     return FALSE unless check_claws_not_running ();
2252     ($ACCOUNTDATA, $ACCOUNTMETA) = load_resource ($rc);
2253     foreach my $asect (keys %$ACCOUNTDATA) {
2254         if ($asect =~ /^Account: (\d+)$/) {
2255             foreach (keys %{$ACCOUNTDATA->{$asect}}) {
2256                 $ACPREFS{$1}{$_} = $ACCOUNTDATA->{$asect}{$_};
2257             }
2258         }
2259     }
2260     return TRUE;
2261 }
2262
2263 # save current preferences to disc
2264 sub save_preferences {
2265     my $rc = get_rc_filename ();
2266     log_message ("Saving preferences to $rc\n");
2267     return FALSE unless check_rc_file ($rc);
2268     return FALSE unless check_claws_not_running ();
2269     my $rcbak = "$rc.backup";
2270     rename ($rc, $rcbak);
2271     foreach (keys %PREFS) {
2272         if (defined $HPVALUE{$_}) {
2273             $CONFIGDATA->{'Common'}{$_} = $HPVALUE{$_};
2274         }
2275     }
2276     foreach my $plugin (@AVPLUGINS) {
2277         foreach (keys %{$CONFIGDATA->{$plugin}}) {
2278             if (defined $PLHPVALUE{$plugin}{$_}) {
2279                 $CONFIGDATA->{$plugin}{$_} = $PLHPVALUE{$plugin}{$_};
2280             }
2281         }
2282     }
2283     save_resource ($rc, $CONFIGDATA, $CONFIGMETA);
2284     return TRUE;
2285 }
2286
2287 sub save_ac_preferences {
2288     my $rc = get_ac_rc_filename ();
2289     log_message ("Saving account preferences to $rc\n");
2290     return FALSE unless check_rc_file ($rc);
2291     return FALSE unless check_claws_not_running ();
2292     my $rcbak = "$rc.backup";
2293     rename ($rc, $rcbak);
2294     foreach my $asect (keys %$ACCOUNTDATA) {
2295         if ($asect =~ /^Account: (\d+)$/) {
2296             foreach (keys %{$ACCOUNTDATA->{$asect}}) {
2297                 if (defined $ACHPVALUE{$1}{$_}) {
2298                     $ACCOUNTDATA->{$asect}{$_} = $ACHPVALUE{$1}{$_};
2299                 }
2300             }
2301         }
2302     }
2303     save_resource ($rc, $ACCOUNTDATA, $ACCOUNTMETA);
2304     return TRUE;
2305 }
2306
2307 # create notebook
2308 sub new_notebook {
2309     my $nb = Gtk2::Notebook->new;
2310     #
2311     $nb->append_page (new_behaviour_page (), $xl::s{tab_behaviour});
2312     $nb->append_page (new_colours_page (), $xl::s{tab_colours});
2313     $nb->append_page (new_gui_page (), $xl::s{tab_gui});
2314     $nb->append_page (new_other_page (), $xl::s{tab_other});
2315     $nb->append_page (new_winpos_page (), $xl::s{tab_winpos});
2316     $nb->append_page (new_accounts_page (), $xl::s{tab_accounts});
2317     $nb->append_page (new_plugins_page (), $xl::s{tab_plugins});
2318     $nb->append_page (new_info_page (), $xl::s{tab_info});
2319
2320     return $nb;
2321 }
2322
2323 # create an about dialog
2324 sub new_about_dialog {
2325     my ($parent) = @_;
2326     my $title = $xl::s{about_title};
2327     my $lic = $xl::s{about_license};
2328     my $vers = $xl::s{about_version} . " $VERSION";
2329     my $license =
2330 "This program is free software: you can redistribute it and/or modify
2331 it under the terms of the GNU General Public License as published by
2332 the Free Software Foundation, either version 3 of the License, or
2333 (at your option) any later version.
2334
2335 This program is distributed in the hope that it will be useful,
2336 but WITHOUT ANY WARRANTY; without even the implied warranty of
2337 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2338 GNU General Public License for more details.
2339
2340 You should have received a copy of the GNU General Public License
2341 along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
2342     my $year = "2007-2016";
2343     my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
2344     my $url = "http://www.claws-mail.org/clawsker.php";
2345
2346     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
2347                     [qw/modal destroy-with-parent/],
2348                     'info', 'close',
2349                     "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
2350                     . "<span size=\"large\">$vers</span>\n\n"
2351                     . "<span color=\"blue\" size=\"large\">$url</span>\n\n"
2352                     . "<span>Copyright $year by $holder</span>\n\n"
2353                     . "<span size=\"large\">$lic</span>\n\n"
2354                     . "<span size=\"small\">$license</span>");
2355     $dialog->set_title ($xl::s{about});
2356     #
2357     return $dialog;
2358 }
2359
2360 # create buttons box
2361 sub new_button_box {
2362     my ($parent, $adlg) = @_;
2363     my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
2364     my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
2365     my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
2366     # disable button until is really implemented
2367     # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
2368     my $hbox = Gtk2::HBox->new (FALSE, 5);
2369     # signal handlers
2370     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
2371     $b_apply->set_sensitive (not $READONLY);
2372     $b_apply->signal_connect (clicked => sub {
2373         save_preferences ($parent);
2374         save_ac_preferences ($parent);
2375     });
2376     # $b_undo->signal_connect (clicked => sub { undo_current_changes });
2377     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
2378     # package them
2379     $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
2380     $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
2381     # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
2382     $hbox->pack_start ($b_about, FALSE, FALSE, 0);
2383     #
2384     return $hbox;
2385 }
2386
2387 sub get_app_icons {
2388     my $dir = $DATADIR . '/icons/hicolor';
2389     my @names = map {
2390       join ('/', ($dir, , $_ . 'x' . $_, 'apps', $NAME . '.png'))
2391     } (64, 128);
2392     my @icons = ();
2393     foreach (@names) {
2394         my $icon = undef;
2395         $icon = Gtk2::Gdk::Pixbuf->new_from_file($_) if (-f $_);
2396         push @icons, $icon if ($icon);
2397     }
2398     return @icons;
2399 }
2400
2401 # initialise
2402 exit unless parse_command_line ();
2403 Gtk2->init;
2404 $main_window = Gtk2::Window->new ('toplevel');
2405 exit unless load_preferences ();
2406 exit unless load_ac_preferences ();
2407 exit unless init_hidden_preferences ();
2408 exit unless init_ac_hidden_preferences ();
2409 exit unless init_plu_hidden_preferences ();
2410 # create main GUI
2411 my $box = Gtk2::VBox->new (FALSE, 5);
2412 $box->set_border_width(3);
2413 my $about = new_about_dialog ();
2414 $box->pack_start (new_notebook (), FALSE, FALSE, 0);
2415 $box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
2416 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
2417 $main_window->set_title ($xl::s{win_title});
2418 $main_window->set_icon_list (get_app_icons ());
2419 $main_window->add ($box);
2420 $main_window->show_all;
2421 Gtk2->main;
2422