Fix operator for unmaintained translations conditions
[clawsker.git] / clawsker
index 0681ef2cb48370ed4fa23c247cdd778322c9f581..136a15625ed8d78195b96beb5e533a08fb3a5093 100755 (executable)
--- a/clawsker
+++ b/clawsker
 # See COPYING file for license details.
 # See AUTHORS file for a complete list of contributors.
 #
-
-binmode STDOUT, ":encoding(utf8)";
-
+package Clawsker;
 use 5.010_000;
 use strict;
 use utf8;
 use version 0.77;
 use Glib qw(TRUE FALSE);
 use Gtk3;
+use File::Which;
+use File::Spec::Functions;
 use POSIX qw(setlocale);
 use Locale::gettext;
 use Encode;
 use Digest::MD5 qw(md5_hex);
-use Getopt::Long;
+use Getopt::Long qw(GetOptionsFromArray);
 
 my $NAME = 'clawsker';
 my $PREFIX = '@PREFIX@';
@@ -36,14 +36,14 @@ my $READONLY = FALSE;
 my $CLAWSV = undef;
 my $main_window = undef;
 
-my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
-$locale = "C" unless defined($locale);
-setlocale (LC_ALL, $locale);
-bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
-textdomain ($NAME);
-
-my $SHOWHINTS = FALSE;
-$SHOWHINTS = TRUE if ($Gtk3::VERSION >= 1.040 and Gtk3->CHECK_VERSION (2, 12, 0));
+sub initialise {
+    binmode STDOUT, ":encoding(utf8)";
+    my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
+    $locale = "C" unless defined($locale);
+    setlocale (LC_ALL, $locale);
+    bindtextdomain ($NAME, catdir ($PREFIX, 'share', 'locale'));
+    textdomain ($NAME);
+}
 
 sub _ {
     my $str = shift;
@@ -59,44 +59,7 @@ sub _ {
 
 # default messages
 %xl::s = (
-    win_title => _('Claws Mail Hidden Preferences'),
-    about => _('About...'),
     about_title => _('Clawsker :: A Claws Mail Tweaker'),
-    about_license => _('License:'),
-    about_version => _('Version:'),
-
-    exit_title => _('Clawsker warning'),
-    exit_fact => _('There are unapplied modifications.'),
-    exit_question => _('Do you really want to quit?'),
-
-    tab_colours => _('Colours'),
-    tab_behaviour => _('Behaviour'),
-    tab_gui => _('GUI'),
-    tab_other => _('Other'),
-    tab_winpos => _('Windows'),
-    tab_accounts => _('Accounts'),
-    tab_plugins => _('Plugins'),
-    tab_hotkeys => _('Hotkeys'),
-    tab_info => _('Info'),
-
-    ab_frame => _('Addressbook'),
-    mem_frame => _('Memory'),
-    msgview_frame => _('Message View'),
-    log_frame => _('Log window'),
-    dnd_frame => _('Drag \'n\' drop'),
-    ssl_frame => _('Secure Sockets Layer'),
-    msgs_frame => _('Messages'),
-    swc_frame => _('Completion'),
-    stripes_frame => _('Coloured stripes'),
-    sbar_frame => _('Scroll bars'),
-    mlist_frame => _('Message List'),
-    mview_frame => _('Message View'),
-    compo_frame => _('Compose window'),
-    netm_frame => _('NetworkManager'),
-    diff_frame => _('Viewing patches'),
-    mpass_frame => _('Master passphrase'),
-    compose_frame => _('Compose window'),
-    qs_frame => _('Quick search'),
 
     l_oth_use_dlg => _('Use detached address book edit dialogue'),
     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.'),
@@ -250,6 +213,8 @@ sub _ {
     h_acc_gtls_set => _('Enables using user provided GnuTLS priority string.'),
     l_acc_gtls_pri => _('GnuTLS priority'),
     h_acc_gtls_pri => _('Value to use as GnuTLS priority string if custom priority check is enabled. Otherwise this value is ignored.'),
+    l_acc_tls_sni => _('Use TLS SNI extension'),
+    h_acc_tls_sni => _('Enables sending your hostname, if available, so the server can select the appropriate certificate for your domain. Useful for servers which host multiple domains on the same IP address.'),
 
     l_plu_gpg_alimit => _('Autocompletion limit'),
     h_plu_gpg_alimit => _('Limits the number of addresses obtained from keyring through autocompletion. Use 0 to get all matches.'),
@@ -278,7 +243,7 @@ my %ACHPVALUE = ();
 my %PLHPVALUE = ();
 # default config dir and file name
 my $ALTCONFIGDIR = FALSE;
-my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
+my $CONFIGDIR = catdir ($ENV{HOME}, '.claws-mail');
 my $CONFIGRC = 'clawsrc';
 my $ACCOUNTRC = 'accountrc';
 # supported and available plugins lists
@@ -293,23 +258,28 @@ my @APPICONS = ();
 # modification flag
 my $MODIFIED = 0;
 
-# index constants for preference arrays
-use constant NAME  => 0; # the name on the rc file
-use constant LABEL => 1; # the label on the GUI
-use constant DESC  => 2; # the description for the hint/help
-use constant TYPE  => 3; # data type: bool, int, float, string, color
-use constant CMVER => 4; # lowest[,highest] Claws Mail version(s) the feature exists
-use constant CMDEF => 5; # default value for the preference in Claws Mail
-use constant PLUGIN => 6; # plugin section (only in plugin preferences)
-
-# constants for GUI spacing
-use constant HBOX_PAD => 5;
-use constant FRAME_SPC => 2;
-use constant PAGE_SPC => 5;
-
-# for data references indexing
-use constant VALUE => 0;
-use constant IVALUE => 1;
+use constant {
+    # index constants for preference arrays
+    NAME  => 0, # the name on the rc file
+    LABEL => 1, # the label on the GUI
+    DESC  => 2, # the description for the hint/help
+    TYPE  => 3, # data type: bool, int, float, string, color
+    CMVER => 4, # lowest[,highest] Claws Mail version(s) the feature exists
+    CMDEF => 5, # default value for the preference in Claws Mail
+    PLUGIN => 6, # plugin section (only in plugin preferences)
+    # constants for GUI spacing
+    HBOX_PAD => 5,
+    GRID_SPC => 9,
+    # for data references indexing
+    VALUE => 0,
+    IVALUE => 1,
+    # hotkey list store columns
+    C_LABEL => 0,
+    C_HOTKEY => 1,
+    C_GROUP => 2,
+    C_ACCEL => 3,
+    C_ODDITY => 4,
+};
 
 # version functions
 
@@ -322,24 +292,16 @@ sub version_greater_or_equal {
 }
 
 sub get_claws_version {
-    $_ = qx/which claws-mail/;
-    chomp;
-    return "" unless ($_); # not installed
-    my $res = "";
-    $_ = qx/$_ -v/;
-    chomp;
-    my @fver = split (/ /);
-    die "Invalid version string" unless ($fver[2] eq "version");
-    my @ver = split (/\./, $fver[3]);
-    $res .= "$ver[0].";
-    $res .= "$ver[1].";
-    if ($ver[2] =~ /(\d+)git(\d+)/) {
-        $res .= "$1.$2";
-    }
-    else {
-        $res .= "$ver[2].0";
-    }
-    return $res;
+    my $cm_path = which ('claws-mail') or return ""; # not found
+    open my $ph, "-|", $cm_path, "-v"  or return ""; # no pipe
+    chomp (my $v = <$ph>);
+    close $ph;
+    # Claws Mail version 3.17.2git17
+    $v =~ m/\bversion\s+(\d[\w.]+)/ or die "Invalid version string: '$v'";
+    my $cmv = $1;
+    my @ver = split m/(?:\.|git)/, $cmv;
+    @ver < 4 and push @ver, 0;
+    return join ".", @ver;
 }
 
 # data handlers and auxiliar functions
@@ -367,13 +329,6 @@ sub handle_int_value {
         if defined $$dataref->[IVALUE];
 }
 
-sub handle_string_value {
-    my ($widget, $event, $dataref) = @_;
-    $$dataref->[VALUE] = $widget->get_text ();
-    $MODIFIED += $$dataref->[VALUE] ne $$dataref->[IVALUE]? 1: -1
-        if defined $$dataref->[IVALUE];
-}
-
 sub handle_nchar_value {
     my ($widget, $event, $dataref, $minlen, $maxlen) = @_;
     $_ = substr ($widget->get_text (), 0, $maxlen);
@@ -421,23 +376,23 @@ sub handle_selection_value {
 }
 
 sub get_rc_filename {
-    return $CONFIGDIR . $CONFIGRC;
+    return catfile ($CONFIGDIR, $CONFIGRC);
 }
 
 sub get_ac_rc_filename {
-    return $CONFIGDIR . $ACCOUNTRC;
+    return catfile ($CONFIGDIR, $ACCOUNTRC);
 }
 
 sub get_menurc_filename {
-    return $CONFIGDIR . "menurc";
+    return catfile ($CONFIGDIR, "menurc");
 }
 
 sub set_rc_filename {
     my ($fullname) = @_;
-    my @parts = split ('/', $fullname);
+    my @parts = splitpath ($fullname);
     $CONFIGRC = $parts[$#parts];
     $parts[$#parts] = '';
-    $CONFIGDIR = join ('/', @parts);
+    $CONFIGDIR = catpath (@parts);
 }
 
 sub log_message {
@@ -450,12 +405,37 @@ sub log_message {
     }
 }
 
+sub message_dialog {
+    my ($parent, $title, $markup, $type, $buttons) = @_;
+    my $flags = [qw/modal destroy-with-parent/];
+    my $dialog = Gtk3::Dialog->new_with_buttons (
+        $title, $parent, $flags, @$buttons
+    );
+    my $label = Gtk3::Label->new;
+    $label->set_markup ($markup);
+    my $icon = undef;
+    if ($type eq 'error') {
+      $icon = Gtk3::Image->new_from_icon_name('dialog-error', 'GTK_ICON_SIZE_DIALOG');
+    } elsif ($type eq 'warning') {
+      $icon = Gtk3::Image->new_from_icon_name('dialog-warning', 'GTK_ICON_SIZE_DIALOG');
+    } elsif ($type eq 'question') {
+      $icon = Gtk3::Image->new_from_icon_name('dialog-question', 'GTK_ICON_SIZE_DIALOG');
+    }
+    my $hbox = Gtk3::Box->new ('horizontal', 5);
+    $hbox->pack_start ($icon, FALSE, FALSE, 5) if defined $icon;
+    $hbox->pack_start ($label, FALSE, FALSE, 5);
+    my $dialogbox = $dialog->get_content_area;
+    $dialogbox->add ($hbox);
+    $dialogbox->show_all;
+    return $dialog;
+}
+
 sub error_dialog {
     my ($emsg) = @_;
     my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
-    my $errordlg = Gtk3::MessageDialog->new ($main_window, 'modal', 'error', 'cancel');
-    $errordlg->set_markup ($markup);
-    $errordlg->set_title (_('Clawsker error'));
+    my $errordlg = message_dialog (
+        $main_window, _('Clawsker error'), $markup, 'error', [ 'gtk-cancel', 0 ]
+    );
     $errordlg->run;
     $errordlg->destroy;
 }
@@ -469,13 +449,12 @@ sub claws_is_running {
 
 sub check_claws_not_running {
     return TRUE if $READONLY;
-    my $tmpdir = (defined $ENV{TMPDIR})? $ENV{TMPDIR}: '/tmp';
-    $tmpdir = '/tmp' if ($tmpdir eq '');
-    my $lockdir = "$tmpdir/claws-mail-$<";
+    my $tmpdir = File::Spec->tmpdir ();
+    my $lockdir = catfile ($tmpdir, "claws-mail-$<");
     -d $lockdir and do {
         $_ = $CONFIGDIR;
         s/\/$//;
-        my $socket = "$lockdir/" . md5_hex ($_);
+        my $socket = catfile ($lockdir, md5_hex ($_));
         -S $socket and return claws_is_running ();
     };
     return TRUE;
@@ -493,11 +472,9 @@ sub check_rc_file {
 }
 
 sub set_widget_hint {
-    if ($SHOWHINTS) {
-        my ($wdgt, $hint) = @_;
-        $wdgt->set_tooltip_text ($hint);
-        $wdgt->set_has_tooltip (TRUE);
-    }
+    my ($wdgt, $hint) = @_;
+    $wdgt->set_tooltip_text ($hint);
+    $wdgt->set_has_tooltip (TRUE);
 }
 
 sub set_widget_sens {
@@ -580,7 +557,7 @@ sub new_text_box_for_nchar($$$) {
     my $label = $$hash{$key}[LABEL];
     my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen,width
     my $glabel = Gtk3::Label->new ($label);
-    my $gentry = Gtk3::Entry->new ();
+    my $gentry = Gtk3::Entry->new;
     $gentry->set_max_length($type[2]) if defined ($type[2]);
     my $width = $type[3];
     $width //= $type[2];
@@ -650,48 +627,60 @@ sub new_selection_box_for($$$) {
 
 # more graphic helpers
 
-sub new_hbox_pack {
-    my $hbox = Gtk3::HBox->new (FALSE);
-    $hbox->set_border_width (PAGE_SPC);
-    foreach (@_) {
-        $hbox->pack_start ($_, FALSE, FALSE, 0);
-    }
-    return $hbox;
-}
-
-sub new_hbox_pack_compact {
-    my $hbox = Gtk3::HBox->new (FALSE);
-    $hbox->set_border_width (0);
-    foreach (@_) {
-        $hbox->pack_start ($_, FALSE, FALSE, 0);
-    }
-    return $hbox;
-}
-
-sub new_vbox_pack {
-    my $vbox = Gtk3::VBox->new (FALSE, 5);
-    $vbox->set_border_width (PAGE_SPC);
-    foreach (@_) {
-        $vbox->pack_start ($_, FALSE, FALSE, 0);
-    }
-    return $vbox;
-}
-
-sub new_vbox_pack_compact {
-    my $vbox = Gtk3::VBox->new (FALSE, 0);
-    $vbox->set_border_width (0);
-    foreach (@_) {
-        $vbox->pack_start ($_, FALSE, FALSE, 0);
+sub new_grid {
+    my ($border_w, $row_s, $col_s) = @_;
+    $border_w //= GRID_SPC;
+    $row_s //= GRID_SPC;
+    $col_s //= GRID_SPC;
+    my $grid = Gtk3::Grid->new;
+    $grid->set_border_width ($border_w);
+    $grid->set_row_spacing ($row_s);
+    $grid->set_column_spacing ($col_s);
+    return $grid;
+}
+
+sub new_label {
+    my $text = shift;
+    $text //= '';
+    my $label = Gtk3::Label->new ($text);
+    $label->set_alignment (0, 0.5);
+    return $label;
+}
+
+sub new_title {
+    my $text = shift;
+    $text //= '';
+    my $label = Gtk3::Label->new ('<b>' . $text . '</b>');
+    $label->set_use_markup (TRUE);
+    $label->set_alignment (0, 0.5);
+    return $label;
+}
+
+sub new_grid_pack {
+    my ($width, $height, $widget) = @_;
+    my $grid = new_grid ();
+    $grid->set_column_homogeneous (TRUE);
+    for (my $i = 0; $i < $width; ++$i) {
+        for (my $j = 0; $j < $height; ++$j) {
+            my $wid = $widget->[$j]->[$i];
+            next unless defined $wid;
+            my $ww = (($i + 1 < $width) and (defined $widget->[$j]->[$i + 1]))
+                ? 1
+                : $width - $i;
+            if (ref $wid) {
+                $grid->attach ($wid, $i, $j, $ww, 1);
+            } else { # not a widget
+                if ('--' eq $wid) { # a separator
+                    $grid->attach (Gtk3::Separator->new ('horizontal'),
+                        $i, $j, $ww, 1);
+                } else { # or a title
+                    $grid->attach (new_title ($wid),
+                        $i, $j, $ww, 1);
+                }
+            }
+        }
     }
-    return $vbox;
-}
-
-sub new_subpage_frame {
-    my ($box, $title, $notpacked) = @_;
-    my $frame = Gtk3::Frame->new ($title);
-    $frame->add ($box);
-    return new_vbox_pack ($frame) unless defined ($notpacked);
-    return $frame;
+    return $grid;
 }
 
 # preference maps and corresponding page creation subs
@@ -740,25 +729,20 @@ sub new_subpage_frame {
 );
 
 sub new_other_page() {
-    return new_vbox_pack (
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_check_button_for(\%pr::oth, 'use_dlg', \%HPVALUE)),
-                   $xl::s{ab_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_text_box_for_int(\%pr::oth, 'max_use', \%HPVALUE),
-                       new_text_box_for_int(\%pr::oth, 'min_time', \%HPVALUE)),
-                   $xl::s{mem_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_check_button_for(\%pr::oth, 'use_netm', \%HPVALUE)),
-                   $xl::s{netm_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_text_box_for_int(\%pr::oth, 'mp_rounds', \%HPVALUE)),
-                   $xl::s{mpass_frame}, 'not-packed')
-           );
+    return new_grid_pack (1, 12, [
+        [ _('Addressbook') ],
+        [ new_check_button_for(\%pr::oth, 'use_dlg', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Memory') ],
+        [ new_text_box_for_int(\%pr::oth, 'max_use', \%HPVALUE) ],
+        [ new_text_box_for_int(\%pr::oth, 'min_time', \%HPVALUE) ],
+        [ '--' ],
+        [ _('NetworkManager') ],
+        [ new_check_button_for(\%pr::oth, 'use_netm', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Master passphrase') ],
+        [ new_text_box_for_int(\%pr::oth, 'mp_rounds', \%HPVALUE) ]
+    ]);
 }
 
 %pr::gui = ( # gui bells and whistles
@@ -917,55 +901,38 @@ sub new_other_page() {
 );
 
 sub new_gui_page() {
-    my $gf = Gtk3::VBox->new (FALSE, 5);
-    $gf->set_border_width (PAGE_SPC);
-
-    my $cb_dot_lines = new_check_button_for (\%pr::gui, 'dot_lines', \%HPVALUE);
-    my $cb_toolbar_d = new_check_button_for (\%pr::gui, 'toolbar_d', \%HPVALUE);
-    my $tb_zero_char = new_text_box_for_nchar (\%pr::gui, 'zero_char', \%HPVALUE);
-
-    $gf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_check_button_for (\%pr::gui, 'strip_all', \%HPVALUE),
-                             new_check_button_for (\%pr::gui, 'strip_sum', \%HPVALUE),
-                             new_text_box_for_int (\%pr::gui, 'strip_off', \%HPVALUE)),
-                         $xl::s{stripes_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $gf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_check_button_for (\%pr::gui, 'b_unread', \%HPVALUE),
-                             new_check_button_for (\%pr::gui, 'swp_from', \%HPVALUE),
-                             new_check_button_for (\%pr::gui, 'two_linev', \%HPVALUE),
-                             new_check_button_for (\%pr::gui, 'next_del', \%HPVALUE),
-                             new_selection_box_for (\%pr::gui, 'from_show', \%HPVALUE)),
-                         $xl::s{mlist_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $gf->pack_start (new_subpage_frame (
-                         new_hbox_pack (
-                             new_check_button_for (\%pr::gui, 'cursor_v', \%HPVALUE),
-                             new_check_button_for (\%pr::gui, 'mview_date', \%HPVALUE)),
-                         $xl::s{mview_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $gf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_hbox_pack_compact (
-                                 new_check_button_for (\%pr::gui, 'no_markup', \%HPVALUE),
-                                 new_check_button_for (\%pr::gui, 'margin_co', \%HPVALUE),
-                                 new_check_button_for (\%pr::gui, 'type_any', \%HPVALUE)),
-                             new_text_box_for_int (\%pr::gui, 'warn_send_multi', \%HPVALUE)),
-                         $xl::s{compo_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
-    $gf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_check_button_for (\%pr::gui, 'h_scroll', \%HPVALUE),
-                             new_selection_box_for (\%pr::gui, 'v_scroll', \%HPVALUE)),
-                         $xl::s{sbar_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $gf->pack_start ($tb_zero_char, FALSE, FALSE, 0);
-
-    return $gf;
+    return new_grid_pack (2, 24, [
+        [ _('Coloured stripes') ],
+        [ new_check_button_for (\%pr::gui, 'strip_all', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'strip_sum', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::gui, 'strip_off', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Message List') ],
+        [ new_check_button_for (\%pr::gui, 'b_unread', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'swp_from', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::gui, 'two_linev', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'next_del', \%HPVALUE) ],
+        [ new_selection_box_for (\%pr::gui, 'from_show', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Message View') ],
+        [ new_check_button_for (\%pr::gui, 'cursor_v', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'mview_date', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Compose window') ],
+        [ new_check_button_for (\%pr::gui, 'no_markup', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'margin_co', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::gui, 'type_any', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::gui, 'warn_send_multi', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Scroll bars') ],
+        [ new_check_button_for (\%pr::gui, 'h_scroll', \%HPVALUE),
+            new_selection_box_for (\%pr::gui, 'v_scroll', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Other') ],
+        [ new_check_button_for (\%pr::gui, 'dot_lines', \%HPVALUE),
+            new_check_button_for (\%pr::gui, 'toolbar_d', \%HPVALUE) ],
+        [ new_text_box_for_nchar (\%pr::gui, 'zero_char', \%HPVALUE) ]
+    ]);
 }
 
 %pr::beh = ( # tweak some behaviour
@@ -1100,45 +1067,33 @@ sub new_gui_page() {
 );
 
 sub new_behaviour_page() {
-    my $bf = Gtk3::VBox->new (FALSE, 5);
-    $bf->set_border_width (PAGE_SPC);
-
-    my $tb_up_step = new_text_box_for_int (\%pr::beh, 'up_step', \%HPVALUE);
-    my $tb_thread_a = new_text_box_for_int (\%pr::beh, 'thread_a', \%HPVALUE);
-
-    $bf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_text_box_for_int (\%pr::beh, 'hover_t', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'warn_dnd', \%HPVALUE)),
-                         $xl::s{dnd_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $bf->pack_start (new_subpage_frame (
-                         new_hbox_pack (
-                             new_check_button_for (\%pr::beh, 'skip_ssl', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'unsafe_ssl', \%HPVALUE)),
-                         $xl::s{ssl_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
-    $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
-    $bf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_check_button_for (\%pr::beh, 'flowed', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'parts_rw', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'use_utf8', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'dangerous', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'out_ascii', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'pp_unsel', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'inline_at', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'rewrite_ff', \%HPVALUE)),
-                         $xl::s{msgs_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    $bf->pack_start (new_subpage_frame (
-                         new_vbox_pack (
-                             new_check_button_for (\%pr::beh, 'addr_swc', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'fold_swc', \%HPVALUE)),
-                         $xl::s{swc_frame}, 'not-packed'),
-                     FALSE, FALSE, FRAME_SPC);
-    return $bf;
+    return new_grid_pack (2, 20, [
+        [ _('Drag \'n\' drop') ],
+        [ new_text_box_for_int (\%pr::beh, 'hover_t', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::beh, 'warn_dnd', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Secure Sockets Layer') ],
+        [ new_check_button_for (\%pr::beh, 'skip_ssl', \%HPVALUE),
+            new_check_button_for (\%pr::beh, 'unsafe_ssl', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Messages') ],
+        [ new_check_button_for (\%pr::beh, 'flowed', \%HPVALUE),
+            new_check_button_for (\%pr::beh, 'out_ascii', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::beh, 'parts_rw', \%HPVALUE),
+            new_check_button_for (\%pr::beh, 'pp_unsel', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::beh, 'use_utf8', \%HPVALUE),
+            new_check_button_for (\%pr::beh, 'inline_at', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::beh, 'dangerous', \%HPVALUE),
+            new_check_button_for (\%pr::beh, 'rewrite_ff', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Completion') ],
+        [ new_check_button_for (\%pr::beh, 'addr_swc', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::beh, 'fold_swc', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Other') ],
+        [ new_text_box_for_int (\%pr::beh, 'up_step', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::beh, 'thread_a', \%HPVALUE) ]
+    ]);
 }
 
 %pr::col = ( # a variety of colours
@@ -1281,45 +1236,34 @@ sub new_behaviour_page() {
 );
 
 sub new_colours_page() {
-    return new_vbox_pack (
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_color_button_for (\%pr::col, 'emphasis', \%HPVALUE),
-                       new_hbox_pack_compact (
-                           new_color_button_for (\%pr::col, 'tags_text', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'tags_bg', \%HPVALUE))),
-                   $xl::s{msgview_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_vbox_pack_compact (
-                           new_color_button_for (\%pr::col, 'log_err', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'log_warn', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'log_msg', \%HPVALUE)),
-                       new_vbox_pack_compact (
-                           new_color_button_for (\%pr::col, 'log_in', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'log_out', \%HPVALUE))),
-                   $xl::s{log_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_vbox_pack (
-                       new_color_button_for (\%pr::col, 'diff_add', \%HPVALUE),
-                       new_color_button_for (\%pr::col, 'diff_del', \%HPVALUE),
-                       new_color_button_for (\%pr::col, 'diff_hunk', \%HPVALUE)),
-                   $xl::s{diff_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_color_button_for (\%pr::col, 'default_header_text', \%HPVALUE),
-                       new_color_button_for (\%pr::col, 'default_header_bg', \%HPVALUE)),
-                   $xl::s{compose_frame}, 'not-packed'),
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_vbox_pack_compact (
-                           new_color_button_for (\%pr::col, 'qs_active_text', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'qs_error_text', \%HPVALUE)),
-                       new_vbox_pack_compact (
-                           new_color_button_for (\%pr::col, 'qs_active_bg', \%HPVALUE),
-                           new_color_button_for (\%pr::col, 'qs_error_bg', \%HPVALUE))),
-                   $xl::s{qs_frame}, 'not-packed')
-           );
+    return new_grid_pack (3, 18, [
+        [ _('Message View') ],
+        [ new_color_button_for (\%pr::col, 'emphasis', \%HPVALUE) ],
+        [ new_color_button_for (\%pr::col, 'tags_text', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'tags_bg', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Log window') ],
+        [ new_color_button_for (\%pr::col, 'log_err', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'log_in', \%HPVALUE) ],
+        [ new_color_button_for (\%pr::col, 'log_warn', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'log_out', \%HPVALUE) ],
+        [ new_color_button_for (\%pr::col, 'log_msg', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Viewing patches') ],
+        [ new_color_button_for (\%pr::col, 'diff_add', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'diff_del', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'diff_hunk', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Compose window') ],
+        [ new_color_button_for (\%pr::col, 'default_header_text', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'default_header_bg', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Quick search') ],
+        [ new_color_button_for (\%pr::col, 'qs_active_text', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'qs_active_bg', \%HPVALUE) ],
+        [ new_color_button_for (\%pr::col, 'qs_error_text', \%HPVALUE) ,
+            new_color_button_for (\%pr::col, 'qs_error_bg', \%HPVALUE) ]
+    ]);
 }
 
 %pr::win = ( # tweak window positions and/or sizes
@@ -1755,6 +1699,22 @@ sub new_colours_page() {
         '0.0.0',
         '-1',
     ],
+    sslman_w => [
+        'sslmanwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '486',
+    ],
+    sslman_h => [
+        'sslmanwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+    ],
     plug_w => [
         'pluginswin_width',
         $xl::s{l_win_w},
@@ -1806,221 +1766,175 @@ sub new_colours_page() {
 );
 
 sub new_winpos_subpage_main() {
-    return new_subpage_frame (
-               new_vbox_pack_compact (
-                   new_vbox_pack (
-                       new_text_box_for_int (\%pr::win, 'main_x', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'main_y', \%HPVALUE)),
-                   new_hbox_pack (
-                       new_text_box_for_int (\%pr::win, 'main_w', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'main_h', \%HPVALUE)),
-                   new_vbox_pack (
-                       new_check_button_for (\%pr::win, 'main_fs', \%HPVALUE),
-                       new_check_button_for (\%pr::win, 'main_mx', \%HPVALUE))),
-               _('Main window')
-           );
+    return new_grid_pack (3, 7, [
+        [ _('Main window'), undef ],
+        [ new_text_box_for_int (\%pr::win, 'main_x', \%HPVALUE), undef ],
+        [ new_text_box_for_int (\%pr::win, 'main_y', \%HPVALUE), undef ],
+        [ new_text_box_for_int (\%pr::win, 'main_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'main_h', \%HPVALUE) ],
+        [ new_check_button_for (\%pr::win, 'main_fs', \%HPVALUE), undef ],
+        [ new_check_button_for (\%pr::win, 'main_mx', \%HPVALUE), undef ]
+    ]);
 }
 
 sub new_winpos_subpage_msgs() {
-    return new_subpage_frame (
-               new_vbox_pack_compact (
-                   new_vbox_pack (
-                       new_text_box_for_int (\%pr::win, 'msgs_x', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'msgs_y', \%HPVALUE)),
-                   new_hbox_pack (
-                       new_text_box_for_int (\%pr::win, 'msgs_w', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'msgs_h', \%HPVALUE))),
-               _('Message window')
-           );
+    return new_grid_pack (3, 4, [
+        [ _('Message window') ],
+        [ new_text_box_for_int (\%pr::win, 'msgs_x', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::win, 'msgs_y', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::win, 'msgs_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'msgs_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_sendrecv() {
-    return new_vbox_pack (
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_text_box_for_int (\%pr::win, 'send_w', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'send_h', \%HPVALUE)),
-                   _('Send window'), 'not-packed'),
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_text_box_for_int (\%pr::win, 'recv_w', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'recv_h', \%HPVALUE)),
-                   _('Receive window'), 'not-packed')
-           );
+    return new_grid_pack (3, 5, [
+        [ _('Send window') ],
+        [ new_text_box_for_int (\%pr::win, 'send_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'send_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Receive window') ],
+        [ new_text_box_for_int (\%pr::win, 'recv_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'recv_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_fold() {
-    return new_vbox_pack (
-               new_subpage_frame (
-                   new_vbox_pack_compact (
-                       new_vbox_pack (
-                            new_text_box_for_int (\%pr::win, 'fold_x', \%HPVALUE),
-                            new_text_box_for_int (\%pr::win, 'fold_y', \%HPVALUE)),
-                       new_hbox_pack (
-                           new_text_box_for_int (\%pr::win, 'fold_w', \%HPVALUE),
-                           new_text_box_for_int (\%pr::win, 'fold_h', \%HPVALUE))),
-                   _('Folder window'), 'not-packed'),
-               new_subpage_frame (
-                   new_hbox_pack (
-                       new_text_box_for_int (\%pr::win, 'fsel_w', \%HPVALUE),
-                       new_text_box_for_int (\%pr::win, 'fsel_h', \%HPVALUE)),
-                   _('Folder selection window'), 'not-packed')
-           );
+    return new_grid_pack (3, 7, [
+        [ _('Folder window') ],
+        [ new_text_box_for_int (\%pr::win, 'fold_x', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::win, 'fold_y', \%HPVALUE) ],
+        [ new_text_box_for_int (\%pr::win, 'fold_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'fold_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Folder selection window') ],
+        [ new_text_box_for_int (\%pr::win, 'fsel_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'fsel_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_addrbook() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'addr_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'addr_h', \%HPVALUE)),
-                     _('Addressbook main window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'adep_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'adep_h', \%HPVALUE)),
-                     _('Edit person window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'adeg_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'adeg_h', \%HPVALUE)),
-                     _('Edit group window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'adda_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'adda_h', \%HPVALUE)),
-                     _('Add address window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'addf_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'addf_h', \%HPVALUE)),
-                     _('Folder select window'), 'not-packed')
-           );
+    return new_grid_pack (3, 14, [
+        [ _('Addressbook main window') ],
+        [ new_text_box_for_int (\%pr::win, 'addr_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'addr_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Edit person window') ],
+        [ new_text_box_for_int (\%pr::win, 'adep_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'adep_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Edit group window') ],
+        [ new_text_box_for_int (\%pr::win, 'adeg_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'adeg_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Add address window') ],
+        [ new_text_box_for_int (\%pr::win, 'adda_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'adda_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Folder select window') ],
+        [ new_text_box_for_int (\%pr::win, 'addf_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'addf_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_accounts() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'acco_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'acco_h', \%HPVALUE)),
-                     _('Accounts window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'acce_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'acce_h', \%HPVALUE)),
-                     _('Edit account window'), 'not-packed')
-           );
+    return new_grid_pack (3, 5, [
+        [ _('Accounts window') ],
+        [ new_text_box_for_int (\%pr::win, 'acco_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'acco_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Edit account window') ],
+        [ new_text_box_for_int (\%pr::win, 'acce_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'acce_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_filtering() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'filt_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'filt_h', \%HPVALUE)),
-                     _('Filtering window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'fila_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'fila_h', \%HPVALUE)),
-                     _('Filtering actions window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'fild_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'fild_h', \%HPVALUE)),
-                     _('Filtering debug window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'matc_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'matc_h', \%HPVALUE)),
-                     _('Matcher window'), 'not-packed')
-           );
+    return new_grid_pack (3, 11, [
+        [ _('Filtering window') ],
+        [ new_text_box_for_int (\%pr::win, 'filt_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'filt_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Filtering actions window') ],
+        [ new_text_box_for_int (\%pr::win, 'fila_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'fila_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Filtering debug window') ],
+        [ new_text_box_for_int (\%pr::win, 'fild_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'fild_h', \%HPVALUE) ],
+        [ '--' ],
+        [ ('Matcher window') ],
+        [ new_text_box_for_int (\%pr::win, 'matc_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'matc_h', \%HPVALUE) ]
+
+    ]);
 }
 
 sub new_winpos_subpage_useractions() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'acti_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'acti_h', \%HPVALUE)),
-                     _('User Actions prefs window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'acio_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'acio_h', \%HPVALUE)),
-                     _('User Actions I/O window'), 'not-packed')
-           );
+    return new_grid_pack (3, 5, [
+        [ _('User Actions prefs window') ],
+        [ new_text_box_for_int (\%pr::win, 'acti_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'acti_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('User Actions I/O window') ],
+        [ new_text_box_for_int (\%pr::win, 'acio_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'acio_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_prefs() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'pref_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'pref_h', \%HPVALUE)),
-                     _('Preferences window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'temp_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'temp_h', \%HPVALUE)),
-                     _('Templates window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'tags_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'tags_h', \%HPVALUE)),
-                     _('Tags window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'plug_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'plug_h', \%HPVALUE)),
-                     _('Plugins window'), 'not-packed')
-           );
+    return new_grid_pack (3, 11, [
+        [ _('Preferences window') ],
+        [ new_text_box_for_int (\%pr::win, 'pref_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'pref_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Templates window') ],
+        [ new_text_box_for_int (\%pr::win, 'temp_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'temp_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Tags window') ],
+        [ new_text_box_for_int (\%pr::win, 'tags_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'tags_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Plugins window') ],
+        [ new_text_box_for_int (\%pr::win, 'plug_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'plug_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_subpage_misc() {
-    return new_vbox_pack (
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'logw_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'logw_h', \%HPVALUE)),
-                     _('Log window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'prin_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'prin_h', \%HPVALUE)),
-                     _('Print preview window'), 'not-packed'),
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::win, 'sour_w', \%HPVALUE),
-                          new_text_box_for_int (\%pr::win, 'sour_h', \%HPVALUE)),
-                     _('View source window'), 'not-packed')
-           );
+    return new_grid_pack (4, 11, [
+        [ _('Log window') ],
+        [ new_text_box_for_int (\%pr::win, 'logw_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'logw_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('SSL manager') ],
+        [ new_text_box_for_int (\%pr::win, 'sslman_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'sslman_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('Print preview window') ],
+        [ new_text_box_for_int (\%pr::win, 'prin_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'prin_h', \%HPVALUE) ],
+        [ '--' ],
+        [ _('View source window') ],
+        [ new_text_box_for_int (\%pr::win, 'sour_w', \%HPVALUE),
+            new_text_box_for_int (\%pr::win, 'sour_h', \%HPVALUE) ]
+    ]);
 }
 
 sub new_winpos_page() {
     my $winbook = Gtk3::Notebook->new;
     $winbook->set_tab_pos ('right');
-    $winbook->append_page (new_winpos_subpage_main,
-        Gtk3::Label->new (_('Main')));
-    $winbook->append_page (new_winpos_subpage_msgs,
-        Gtk3::Label->new (_('Message')));
-    $winbook->append_page (new_winpos_subpage_sendrecv,
-        Gtk3::Label->new (_('Send/Receive')));
-    $winbook->append_page (new_winpos_subpage_fold,
-        Gtk3::Label->new (_('Folder')));
-    $winbook->append_page (new_winpos_subpage_addrbook,
-        Gtk3::Label->new (_('Addressbook')));
-    $winbook->append_page (new_winpos_subpage_accounts,
-        Gtk3::Label->new (_('Accounts')));
-    $winbook->append_page (new_winpos_subpage_filtering,
-        Gtk3::Label->new (_('Filtering')));
-    $winbook->append_page (new_winpos_subpage_useractions,
-        Gtk3::Label->new (_('User Actions')));
-    $winbook->append_page (new_winpos_subpage_prefs,
-        Gtk3::Label->new (_('Preferences')));
-    $winbook->append_page (new_winpos_subpage_misc,
-        Gtk3::Label->new (_('Other')));
+    $winbook->append_page (&new_winpos_subpage_main, new_label (_('Main')));
+    $winbook->append_page (&new_winpos_subpage_msgs, new_label (_('Message')));
+    $winbook->append_page (&new_winpos_subpage_sendrecv, new_label (_('Send/Receive')));
+    $winbook->append_page (&new_winpos_subpage_fold, new_label (_('Folder')));
+    $winbook->append_page (&new_winpos_subpage_addrbook, new_label (_('Addressbook')));
+    $winbook->append_page (&new_winpos_subpage_accounts, new_label (_('Accounts')));
+    $winbook->append_page (&new_winpos_subpage_filtering, new_label (_('Filtering')));
+    $winbook->append_page (&new_winpos_subpage_useractions, new_label (_('User Actions')));
+    $winbook->append_page (&new_winpos_subpage_prefs, new_label (_('Preferences')));
+    $winbook->append_page (&new_winpos_subpage_misc, new_label (_('Other')));
     return $winbook;
 }
 
@@ -2041,17 +1955,25 @@ sub new_winpos_page() {
         '3.9.0.181',
         '0',
     ],
+    tls_sni => [
+        'use_tls_sni',
+        $xl::s{l_acc_tls_sni},
+        $xl::s{h_acc_tls_sni},
+        'bool',
+        '3.17.2.16',
+        '0',
+    ],
 );
 
 sub new_account_subpage($) {
     my ($akey) = @_;
-    return new_vbox_pack (
-                new_subpage_frame (
-                    new_vbox_pack (
-                        new_check_button_for (\%pr::acc, 'tls_set', $ACHPVALUE{$akey}),
-                        new_text_box_for_nchar (\%pr::acc, 'tls_pri', $ACHPVALUE{$akey})),
-                    _('GnuTLS priority'), 'not-packed')
-           );
+    return new_grid_pack (1, 5, [
+        [ _('GnuTLS priority') ],
+        [ new_check_button_for (\%pr::acc, 'tls_set', $ACHPVALUE{$akey}) ],
+        [ new_text_box_for_nchar (\%pr::acc, 'tls_pri', $ACHPVALUE{$akey}) ],
+        [ _('Server Name Indication') ],
+        [ new_check_button_for (\%pr::acc, 'tls_sni', $ACHPVALUE{$akey}) ],
+    ]);
 }
 
 sub new_accounts_page() {
@@ -2064,12 +1986,9 @@ sub new_accounts_page() {
         my $name = $ACPREFS{$_}{'account_name'};
         my $isdef = ($ACPREFS{$_}{'is_default'} eq '1');
         my $page = new_account_subpage ($_);
-        $accbook->append_page ($page,
-            Gtk3::Label->new ($isdef? '<b>' . $name . '</b>': $name));
-        if ($isdef) {
-            my $label = $accbook->get_tab_label ($page);
-            $label->set_use_markup (TRUE);
-        }
+        my $label = new_label ($isdef? '<u>' . $name . '</u>': $name);
+        $label->set_use_markup (TRUE);
+        $accbook->append_page ($page, $label);
     }
     $accbook->set_scrollable (TRUE);
     return $accbook;
@@ -2147,70 +2066,53 @@ sub new_accounts_page() {
 );
 
 sub new_plugins_page() {
-    my %frame = ();
-    $frame{'AttRemover'} =
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::plu, 'arm_winw', $PLHPVALUE{'AttRemover'}),
-                          new_text_box_for_int (\%pr::plu, 'arm_winh', $PLHPVALUE{'AttRemover'})),
-                     _('Attachment remover'), 'not-packed');
-    $frame{'GPG'} =
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::plu, 'gpg_alimit', $PLHPVALUE{'GPG'})),
-                     _('GPG'), 'not-packed');
-    $frame{'ManageSieve'} =
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_int (\%pr::plu, 'msv_winw', $PLHPVALUE{'ManageSieve'}),
-                          new_text_box_for_int (\%pr::plu, 'msv_winh', $PLHPVALUE{'ManageSieve'})),
-                     _('Sieve manager'), 'not-packed');
-    $frame{'Libravatar'} =
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_text_box_for_nchar (\%pr::plu, 'lav_burl', $PLHPVALUE{'Libravatar'})),
-                     _('Libravatar'), 'not-packed');
-    $frame{'PerlPlugin'} =
-                new_subpage_frame (
-                     new_hbox_pack (
-                          new_selection_box_for (\%pr::plu, 'prl_flvb', $PLHPVALUE{'PerlPlugin'})),
-                     _('Perl'), 'not-packed');
-    foreach (@PLUGINS) {
-        $frame{$_}->set_sensitive (defined $PLHPVALUE{$_});
+    my %widget = (
+        'AttRemover' => [
+            new_text_box_for_int (\%pr::plu, 'arm_winw', $PLHPVALUE{'AttRemover'}),
+            new_text_box_for_int (\%pr::plu, 'arm_winh', $PLHPVALUE{'AttRemover'})
+        ],
+        'GPG' => [
+            new_text_box_for_int (\%pr::plu, 'gpg_alimit', $PLHPVALUE{'GPG'})
+        ],
+        'ManageSieve' => [
+            new_text_box_for_int (\%pr::plu, 'msv_winw', $PLHPVALUE{'ManageSieve'}),
+            new_text_box_for_int (\%pr::plu, 'msv_winh', $PLHPVALUE{'ManageSieve'})
+        ],
+        'Libravatar' => [
+            new_text_box_for_nchar (\%pr::plu, 'lav_burl', $PLHPVALUE{'Libravatar'})
+        ],
+        'PerlPlugin' => [
+            new_selection_box_for (\%pr::plu, 'prl_flvb', $PLHPVALUE{'PerlPlugin'})
+        ]
+    );
+    foreach my $pk (@PLUGINS) {
+        foreach my $wg (@{$widget{$pk}}) {
+            $wg->set_sensitive (defined $PLHPVALUE{$pk});
+        }
     }
-    return new_vbox_pack (
-                $frame{'AttRemover'},
-                $frame{'GPG'},
-                $frame{'ManageSieve'},
-                $frame{'Libravatar'},
-                $frame{'PerlPlugin'});
+    return new_grid_pack (3, 14, [
+        [ _('Attachment remover') ], $widget{'AttRemover'}, [ '--' ],
+        [ _('GPG') ], $widget{'GPG'}, [ '--' ],
+        [ _('Sieve manager') ], $widget{'ManageSieve'}, [ '--' ],
+        [ _('Libravatar') ], $widget{'Libravatar'}, [ '--' ],
+        [ _('Perl') ], $widget{'PerlPlugin'}
+    ]);
 }
 
-use constant {
-    C_LABEL => 0,
-    C_HOTKEY => 1,
-    C_GROUP => 2,
-    C_ACCEL => 3,
-    C_BCOLOR => 4,
-    # cell backgrounds
-    BG_LIGHTER => '#ffffff',
-    BG_DARKER => '#eeeeee'
-};
-
 sub new_hotkeys_list_label {
-    my $renderer = Gtk3::CellRendererText->new ();
+    my $renderer = Gtk3::CellRendererText->new;
     $renderer->set_property('alignment' => 'left');
     $renderer->set_property('editable' => FALSE);
     return $renderer;
 }
 
 sub new_hotkeys_list_hotkey {
-    my $renderer = Gtk3::CellRendererAccel->new ();
+    my $renderer = Gtk3::CellRendererAccel->new;
     $renderer->set_property ('accel-mode' => 'gtk');
     $renderer->set_property ('editable' => TRUE);
     $renderer->signal_connect ('accel-edited' => sub {
         my ($w, $path, $key, $mods, $keycode) = @_;
-        my $accel = Gtk3::Accelerator->name ($key, $mods);
+        my $accel = Gtk3::accelerator_name ($key, $mods);
         my ($model, $iter) = $SELHOTKEY->get_selected ();
         $model->set($iter, C_HOTKEY, "\"$accel\"");
         my $gkey = $model->get_value ($iter, C_GROUP);
@@ -2232,19 +2134,27 @@ sub new_hotkeys_list_hotkey {
     return $renderer;
 }
 
+sub row_background_color {
+    my ($column, $isodd) = @_;
+    my $treeview = $column->get_tree_view;
+    my $stylectx = $treeview->get_style_context;
+    return $isodd
+        ? $stylectx->get_background_color ('normal')
+        : $stylectx->get_background_color ('insensitive');
+}
+
 sub new_hotkeys_list {
     my ($gkey, $group) = @_;
     my $store = Gtk3::ListStore->new(
-        qw/Glib::String Glib::String Glib::String Glib::String Glib::String/);
-    my $even = FALSE;
+        qw/Glib::String Glib::String Glib::String Glib::String Glib::Boolean/);
+    my $even = TRUE;
     foreach my $akey (sort keys %$group) {
         my $iter = $store->append ();
         my $hotkey = $group->{$akey}->{'key'};
         my $label = $akey;
         $label =~ s/[<>]//g; # <rrsyl> and <IMAPFolder> !?
-        my $bgcol = $even ? BG_DARKER: BG_LIGHTER;
         $store->set ($iter, C_LABEL, $label, C_HOTKEY, $hotkey,
-            C_GROUP, $gkey, C_ACCEL, $akey, C_BCOLOR, $bgcol);
+            C_GROUP, $gkey, C_ACCEL, $akey, C_ODDITY, $even);
         $even = not $even;
     }
     my $treeview = Gtk3::TreeView->new_with_model ($store);
@@ -2257,8 +2167,9 @@ sub new_hotkeys_list {
                 'markup' => '<span size="smaller">'
                             . $model->get_value ($iter, C_LABEL)
                             . '</span>');
-            $renderer->set_property (
-                'background' => $model->get_value ($iter, C_BCOLOR));
+            my $bgcol = row_background_color (
+                $col, $model->get_value ($iter, C_ODDITY));
+            $renderer->set_property ('cell-background-rgba' => $bgcol);
         }
     );
     # hotkeys column
@@ -2271,8 +2182,9 @@ sub new_hotkeys_list {
             my ($acckey, $accmod) = Gtk3::accelerator_parse ($hkey);
             $renderer->set_property ('accel-key' => $acckey);
             $renderer->set_property ('accel-mods' => $accmod);
-            $renderer->set_property (
-                'background' => $model->get_value ($iter, C_BCOLOR));
+            my $bgcol = row_background_color (
+                $col, $model->get_value ($iter, C_ODDITY));
+            $renderer->set_property ('cell-background-rgba' => $bgcol);
         }
     );
     # callback for saving current selection
@@ -2282,69 +2194,40 @@ sub new_hotkeys_list {
 }
 
 sub new_hotkeys_page() {
-    my $swin = Gtk3::ScrolledWindow->new ();
-    my $vbox = Gtk3::VBox->new (FALSE, 5);
+    my $hkbook = Gtk3::Notebook->new;
+    $hkbook->set_tab_pos ('right');
     foreach my $gkey (sort keys %$HOTKEYS) {
         my $group = $HOTKEYS->{$gkey};
-        # group title
-        my $glabel = Gtk3::Label->new ('<b>' . $gkey . '</b>');
-        $glabel->set_use_markup (TRUE);
-        $glabel->set_alignment (0, 0.5);
-        $glabel->set_padding (5, 1);
-        $vbox->pack_start ($glabel, FALSE, FALSE, 0);
-        # group key list
         my $keylist = new_hotkeys_list ($gkey, $group);
-        $vbox->pack_start ($keylist, FALSE, FALSE, 0);
+        # prepare scrolled window
+        my $swin = Gtk3::ScrolledWindow->new;
+        $swin->set_border_width (5);
+        $swin->set_shadow_type ('none');
+        $swin->set_policy ('automatic', 'automatic');
+        # add list of keys
+        $swin->add ($keylist);
+        $hkbook->append_page ($swin, new_label ($gkey));
     }
-    $swin->set_border_width (5);
-    $swin->set_shadow_type ('none');
-    $swin->set_policy ('automatic', 'always');
-    $swin->add_with_viewport ($vbox);
-    return $swin;
+    return $hkbook;
 }
 
 sub new_info_page() {
-    my $t0 = Gtk3::Table->new (7, 2, FALSE);
     my $v = get_toolkit_versions ();
-    my %labels = (
-        'glib' => 'Perl-GLib',
-        'glib-r' => _('GLib runtime'),
-        'glib-b' => _('GLib built'),
-        'gtk2' => 'Perl-GTK2',
-        'gtk2-r' => _('GTK2 runtime'),
-        'gtk2-b' => _('GTK2 built'),
-    );
-    my $row = 0;
-    foreach (sort keys %$v) {
-        if (defined $v->{$_}) {
-            my $label = Gtk3::Label->new ($labels{$_});
-            my $value = Gtk3::Label->new ('<b>' . $v->{$_} . '</b>');
-            $label->set_alignment (0, 0.5);
-            $value->set_alignment (0, 0.5);
-            $value->set_use_markup (TRUE);
-            $t0->attach ($label, 0, 1, $row, $row + 1, 'fill', 'shrink', 8, 6);
-            $t0->attach ($value, 1, 2, $row, $row + 1, 'fill', 'shrink', 8, 6);
-            ++$row;
-        }
-    }
-    my $t1 = Gtk3::Table->new (2, 2, FALSE);
-    my @lbl = map { $_->set_alignment (0, 0.5); $_ } (
-        Gtk3::Label->new (_('Binary')),
-        Gtk3::Label->new (_('Configuration'))
-    );
     my $cfgv = $CONFIGDATA->{'Common'}{'config_version'};
     $cfgv //= '';
-    my @val = map { $_->set_alignment (0, 0.5); $_->set_use_markup (TRUE); $_ } (
-        Gtk3::Label->new ('<b>' . $CLAWSV . '</b>'),
-        Gtk3::Label->new ('<b>' . $cfgv . '</b>')
-    );
-    for (my $i = 0; $i <= $#lbl; ++$i) {
-        $t1->attach ($lbl[$i], 0, 1, $i, $i + 1, 'fill', 'shrink', 8, 6);
-        $t1->attach ($val[$i], 1, 2, $i, $i + 1, 'fill', 'shrink', 8, 6);
-    }
-    return new_vbox_pack (
-                new_subpage_frame ($t0, _('Library versions'), 'not-packed'),
-                new_subpage_frame ($t1, _('Claws Mail versions'), 'not-packed'));
+    return new_grid_pack (4, 11, [
+        [ _('Library versions') ],
+        [ new_label ('Perl-GLib'), new_title ($v->{'glib'}) ],
+        [ new_label (_('GLib runtime')), new_title ($v->{'glib-r'}) ],
+        [ new_label (_('GLib built')), new_title ($v->{'glib-b'}) ],
+        [ new_label ('Perl-GTK3'), new_title ($v->{'gtk'}) ],
+        [ new_label (_('GTK3 runtime')), new_title ($v->{'gtk-r'}) ],
+        [ new_label (_('GTK3 built')), new_title ($v->{'gtk-b'}) ],
+        [ '--' ],
+        [ _('Claws Mail versions') ],
+        [ new_label (_('Binary')), new_title ($CLAWSV) ],
+        [ new_label (_('Configuration')), new_title ($cfgv) ]
+    ]);
 }
 
 # version info
@@ -2357,41 +2240,41 @@ sub get_toolkit_versions {
         $versions{'glib-r'} = join('.',
             &Glib::major_version, &Glib::minor_version, &Glib::micro_version);
     }
-    $versions{'gtk2'} = $Gtk3::VERSION;
-    if ($Gtk3::VERSION >= 1.040) {
-        $versions{'gtk2-b'} = join('.', Gtk3->GET_VERSION_INFO);
-        $versions{'gtk2-r'} = join('.',
-            &Gtk3::major_version, &Gtk3::minor_version, &Gtk3::micro_version);
+    $versions{'gtk'} = $Gtk3::VERSION;
+    if ($Gtk3::VERSION >= 0.034) {
+        $versions{'gtk-b'} = &Gtk3::GET_VERSION_INFO
+    } else {
+        $versions{'gtk-b'} = _('Not available')
     }
+    $versions{'gtk-r'} = join('.',
+        &Gtk3::get_major_version, &Gtk3::get_minor_version, &Gtk3::get_micro_version);
     return \%versions;
 }
 
 sub print_version() {
-    print $xl::s{about_title} . "\n";
-    print $xl::s{about_version} . " $VERSION\n";
+    say $xl::s{about_title};
+    say _('Version:') . " $VERSION";
     my $v = get_toolkit_versions ();
     if ($v->{'glib-b'}) {
-        print _("Perl-GLib version {glibv}, built for {glibb}, running with {glibr}.",
+        say _("Perl-GLib version {glibv}, built for {glibb}, running with {glibr}.",
                 glibv => $v->{'glib'},
                 glibb => $v->{'glib-b'},
                 glibr => $v->{'glib-r'});
     } else {
-        print _("Perl-GLib version {glibv}.", glibv => $v->{'glib'});
+        say _("Perl-GLib version {glibv}.", glibv => $v->{'glib'});
     }
-    print "\n";
-    if ($v->{'gtk2-b'}) {
-        print _("Perl-GTK2 version {gtkv}, built for {gtkb}, running with {gtkr}.",
-                gtkv => $v->{'gtk2'},
-                gtkb => $v->{'gtk2-b'},
-                gtkr => $v->{'gtk2-r'});
+    if ($v->{'gtk-b'}) {
+        say _("Perl-GTK3 version {gtkv}, built for {gtkb}, running with {gtkr}.",
+                gtkv => $v->{'gtk'},
+                gtkb => $v->{'gtk-b'},
+                gtkr => $v->{'gtk-r'});
     } else {
-        print _("Perl-GTK2 version {gtkv}.", gtkv => $v->{'gtk2'});
+        say _("Perl-GTK3 version {gtkv}.", gtkv => $v->{'gtk'});
     }
-    print "\n";
     my $clawsver = ($CLAWSV eq "") ?
                 _("Claws Mail was not found!") :
                 _("Claws Mail returned version {cmv}.", cmv => $CLAWSV);
-    print $clawsver . "\n";
+    say $clawsver;
 }
 
 # the command line help
@@ -2415,10 +2298,12 @@ sub print_help() {
 }
 
 sub parse_command_line {
+    my $argv = shift;
     my $cont = TRUE;
     $CLAWSV = get_claws_version ();
     eval {
-        GetOptions('h|help' => sub { print_help (); $cont = FALSE },
+        GetOptionsFromArray($argv,
+            'h|help' => sub { print_help (); $cont = FALSE },
             'v|version' => sub { print_version (); $cont = FALSE },
             'b|verbose' => sub { $VERBOSE = TRUE },
             'r|read-only' => sub { $READONLY = TRUE },
@@ -2450,7 +2335,6 @@ sub opt_alternate_config_dir {
     die _("Error: '{dir}' is not a directory or does not exist\n", dir => $value)
         unless -d $value;
     $CONFIGDIR = $value;
-    $CONFIGDIR .= "/" unless ($CONFIGDIR =~ /.*\/$/);
     $ALTCONFIGDIR = TRUE;
 }
 
@@ -2666,7 +2550,6 @@ sub save_rc_preferences {
     my $rc = get_rc_filename ();
     log_message ("Saving preferences to $rc\n");
     return FALSE unless check_rc_file ($rc);
-    return FALSE unless check_claws_not_running ();
     return FALSE unless backup_resource ($rc);
     foreach (keys %PREFS) {
         if (defined $HPVALUE{$_}) {
@@ -2688,7 +2571,6 @@ sub save_ac_preferences {
     my $rc = get_ac_rc_filename ();
     log_message ("Saving account preferences to $rc\n");
     return FALSE unless check_rc_file ($rc);
-    return FALSE unless check_claws_not_running ();
     return FALSE unless backup_resource ($rc);
     foreach my $asect (keys %$ACCOUNTDATA) {
         if ($asect =~ /^Account: (\d+)$/) {
@@ -2707,13 +2589,13 @@ sub save_hk_preferences {
     my $rc = get_menurc_filename ();
     log_message ("Saving hotkey preferences to $rc\n");
     return FALSE unless check_rc_file ($rc);
-    return FALSE unless check_claws_not_running ();
     return FALSE unless backup_resource ($rc);
     save_menurc ($rc, $HOTKEYS);
     return TRUE;
 }
 
 sub save_preferences {
+    return FALSE unless check_claws_not_running ();
     my $result = save_rc_preferences ()
         and save_ac_preferences ()
         and save_hk_preferences ();
@@ -2724,25 +2606,16 @@ sub save_preferences {
 # create notebook
 sub new_notebook {
     my $nb = Gtk3::Notebook->new;
-    #
-    $nb->append_page (new_behaviour_page (),
-        Gtk3::Label->new ($xl::s{tab_behaviour}));
-    $nb->append_page (new_colours_page (),
-        Gtk3::Label->new ($xl::s{tab_colours}));
-    $nb->append_page (new_gui_page (),
-        Gtk3::Label->new ($xl::s{tab_gui}));
-    $nb->append_page (new_other_page (),
-        Gtk3::Label->new ($xl::s{tab_other}));
-    $nb->append_page (new_winpos_page (),
-        Gtk3::Label->new ($xl::s{tab_winpos}));
-    $nb->append_page (new_accounts_page (),
-        Gtk3::Label->new ($xl::s{tab_accounts}));
-    $nb->append_page (new_plugins_page (),
-        Gtk3::Label->new ($xl::s{tab_plugins}));
-    $nb->append_page (new_hotkeys_page (),
-        Gtk3::Label->new ($xl::s{tab_hotkeys}));
-    $nb->append_page (new_info_page (),
-        Gtk3::Label->new ($xl::s{tab_info}));
+
+    $nb->append_page (&new_behaviour_page, Gtk3::Label->new (_('Behaviour')));
+    $nb->append_page (&new_colours_page, Gtk3::Label->new (_('Colours')));
+    $nb->append_page (&new_gui_page, Gtk3::Label->new (_('GUI')));
+    $nb->append_page (&new_other_page, Gtk3::Label->new (_('Other')));
+    $nb->append_page (&new_winpos_page, Gtk3::Label->new (_('Windows')));
+    $nb->append_page (&new_accounts_page, Gtk3::Label->new (_('Accounts')));
+    $nb->append_page (&new_plugins_page, Gtk3::Label->new (_('Plugins')));
+    $nb->append_page (&new_hotkeys_page, Gtk3::Label->new (_('Hotkeys')));
+    $nb->append_page (&new_info_page, Gtk3::Label->new (_('Info')));
 
     return $nb;
 }
@@ -2750,60 +2623,69 @@ sub new_notebook {
 # create an about dialog
 sub new_about_dialog {
     my ($parent) = @_;
-    my $title = $xl::s{about_title};
-    my $lic = $xl::s{about_license};
-    my $vers = $xl::s{about_version} . " $VERSION";
-    my $license =
-"This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
-    my $year = "2007-2018";
-    my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
-    my $url = "http://www.claws-mail.org/clawsker.php";
-
-    my $dialog = Gtk3::MessageDialog->new ($parent,
-        [qw/modal destroy-with-parent/], 'info', 'close');
-    $dialog->set_markup (
-        "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
-        . "<span size=\"large\">$vers</span>\n\n"
-        . "<span color=\"blue\" size=\"large\">$url</span>\n\n"
-        . "<span>Copyright $year by $holder</span>\n\n"
-        . "<span size=\"large\">$lic</span>\n\n"
-        . "<span size=\"small\">$license</span>");
-    $dialog->set_title ($xl::s{about});
-    if (Gtk3->CHECK_VERSION (2, 10, 0)) {
-        my @icons = get_app_icons ();
-        my $image = Gtk3::Image->new_from_pixbuf ($icons[-1]);
-        $image->show ();
-        $image->set_alignment (0, 0);
-        $dialog->set_image ($image);
-    }
-    #
+    my $year = '2007-2018';
+    my $holder = 'Ricardo Mones <ricardo@mones.org>';
+    my $url = 'http://www.claws-mail.org/clawsker.php';
+    my $icons = &get_app_icons;
+
+    my $dialog = Gtk3::AboutDialog->new;
+    $dialog->set_transient_for ($parent);
+    $dialog->set_program_name ('Clawsker');
+    $dialog->set_version ($VERSION);
+    $dialog->set_copyright ("Copyright © $year $holder");
+    $dialog->set_license_type ('gpl-3-0');
+    $dialog->set_website ($url);
+    $dialog->set_website_label (_("Visit Clawsker's web page"));
+    # committers, by number of commits
+    $dialog->set_authors ([
+        $holder,
+        'Tristan Chabredier (wwp) <subscript@free.fr>',
+        'Andreas Rönnquist <andreas@ronnquist.net>',
+        'Christian Hesse <mail@eworm.de>',
+    ]);
+    $dialog->set_artists ([
+        'Jesper Schultz <jesper@schultz-net.dk>',
+        $holder,
+    ]);
+    $dialog->set_documenters ([
+        $holder,
+        'Paul Mangan <paul@claws-mail.org>',
+    ]);
+    # active translators, in alphabetical order
+    $dialog->set_translator_credits (join ("\n",
+        'Andreas Rönnquist <andreas@ronnquist.net>',
+        'Axel Köllhofer <AxelKoellhofer@web.de>',
+        'David Medina <opensusecatala@gmail.com>',
+        'Erik P. Olsen <erik@epo.dk>',
+        'Frederico Goncalves Guimaraes <frederico@teia.bio.br>',
+        'Marcel Pol <marcel@timelord.nl>',
+        'Mark Chang <mark.cyj@gmail.com>',
+        'M. Sulchan Darmawan <bleketux@gmail.com>',
+        'Numan Demirdöğen <if.gnu.linux@gmail.com>',
+        'Pedro Albuquerque <pmra@gmx.com>',
+        'Petter Adsen <petter@synth.no>',
+        $holder,
+        'Tristan Chabredier (wwp) <subscript@free.fr>',
+    ));
+    $dialog->set_title ($xl::s{about_title});
+    $dialog->set_logo ($icons->[-1]);
+
     return $dialog;
 }
 
 sub exit_handler {
   my ($parent) = @_;
   if ($MODIFIED != 0 and not $READONLY) {
-    my $fact = $xl::s{exit_fact};
-    my $question = $xl::s{exit_question};
-    my $dialog = Gtk3::MessageDialog->new ($parent,
-        [qw/modal destroy-with-parent/], 'warning', 'yes-no');
-    $dialog->set_markup ("<span>$fact</span>\n\n"
-        . "<span weight=\"bold\">$question</span>");
-    $dialog->set_title ($xl::s{exit_title});
+    my $markup = "<span>" . _('There are unapplied modifications.')
+        . "</span>\n\n<span weight=\"bold\">"
+        . _('Do you really want to quit?') . "</span>\n";
+    my $dialog = message_dialog (
+        $parent, _('Clawsker warning'), $markup, 'question',
+        [ 'gtk-no', 1, 'gtk-yes', 0 ]
+    );
     my $resp = $dialog->run;
     $dialog->hide;
-    return TRUE if ($resp eq 'no');
+    return TRUE if $resp;
   }
   Gtk3->main_quit;
 }
@@ -2836,13 +2718,13 @@ sub get_app_icons {
     return \@APPICONS if (@APPICONS);
     my @names;
     if (-d $DATADIR) { # installed
-        my $dir = $DATADIR . '/icons/hicolor';
+        my $dir = catdir ($DATADIR, 'icons', 'hicolor');
         @names = map {
-            join ('/', ($dir, $_ . 'x' . $_, 'apps', $NAME . '.png'))
+            catfile ($dir, $_ . 'x' . $_, 'apps', $NAME . '.png')
         } (48, 64, 128);
     } else { # unpacked tarball or git clone
         @names = map {
-            join ('/', ('./icons', $NAME . '-' . $_ . '.png'));
+            catfile ('.', 'icons', $NAME . '-' . $_ . '.png');
         } (48, 64, 128);
     }
     foreach (@names) {
@@ -2860,24 +2742,29 @@ sub escape_key_handler {
     }
 }
 
-# initialise
-exit unless parse_command_line ();
-Gtk3->init;
-$main_window = Gtk3::Window->new ('toplevel');
-exit unless load_preferences ();
-exit unless init_hidden_preferences ();
-# create main GUI
-my $box = Gtk3::VBox->new (FALSE, 5);
-$box->set_border_width(3);
-my $about = new_about_dialog ($main_window);
-$box->pack_start (new_notebook (), TRUE, TRUE, 0);
-$box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
-$main_window->signal_connect (delete_event => sub { exit_handler($main_window) });
-$main_window->signal_connect (key_press_event => \&escape_key_handler);
-$main_window->set_title ($xl::s{win_title});
-$main_window->set_icon_list (get_app_icons ());
-$main_window->add ($box);
-$main_window->show_all;
-$MODIFIED = 0;
-Gtk3->main;
-
+sub main {
+    my $args = shift;
+    initialise;
+    exit unless parse_command_line ($args);
+    Gtk3->init;
+    $main_window = Gtk3::Window->new ('toplevel');
+    exit unless load_preferences ();
+    exit unless init_hidden_preferences ();
+    # create main GUI
+    my $box = Gtk3::VBox->new (FALSE, 5);
+    $box->set_border_width(3);
+    my $about = new_about_dialog ($main_window);
+    $box->pack_start (new_notebook (), TRUE, TRUE, 0);
+    $box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
+    $main_window->signal_connect (delete_event => sub { exit_handler($main_window) });
+    $main_window->signal_connect (key_press_event => \&escape_key_handler);
+    $main_window->set_title (_('Claws Mail Hidden Preferences'));
+    $main_window->set_icon_list (get_app_icons ());
+    $main_window->add ($box);
+    $main_window->show_all;
+    $MODIFIED = 0;
+    Gtk3->main;
+    return 0;
+}
+
+exit Clawsker::main(\@ARGV) unless caller;