From 697a698add88b59b744a42a2c54e2408dcd4ffbd Mon Sep 17 00:00:00 2001 From: gryf Date: Sat, 28 Oct 2023 16:57:44 +0200 Subject: [PATCH] Added urxvt overlay based dialog for closing window --- README.rst | 24 +++++++++++++++--------- tabbedalt | 52 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/README.rst b/README.rst index 1e726e2..057e6d8 100644 --- a/README.rst +++ b/README.rst @@ -255,14 +255,24 @@ Confirm closing window When working with tabs, sometimes user accidentally could close the window, and loose all the applications run on the tabs. There might be multiple tabs open, or just one with running process on it (i.e. some editor), where closing window -by accident could result in data loss. To prevent this, there are couple of -resources to be set. First one, disabled by default is:: +by accident could result in data loss. To prevent this, there are two +additional resources that can be set. First one, disabled by default is:: URxvt.tabbedalt.confirm-quit: false -When set to ``true`` it will execute a message program defined in -``confirm-program`` resource. It might be whatever X program, which can accept -text as an argument, and can provide dialog which: +When set to ``true`` it will either execute a message program or will display +an urxvt overlay with the dialog directly on current tab. Note that overlay +dialog will expect the user to either press: + +- ``y`` or ``enter`` key to close the window +- ``n`` or ``escape`` key to deny closing it + +Second one is to provide X dialog program:: + + URxvt.tabbedalt.confirm-program: + +It might be whatever X program, which can accept text as an argument, and can +provide dialog which: - have two buttons (i.e. yes/no, ok/cancel) where first will exit dialog with 0 exit code and the latter will exit with whatever other number, @@ -282,10 +292,6 @@ or `kdialog`_:: or… any other dialog programs which fulfill the above criteria. -Note, that ``confirm-program`` resource have no default value and you'll need -to configure it alongside with the ``confirm-quit``, otherwise ``confirm-quit`` -will have no effect. - Creating specific commands/shells --------------------------------- diff --git a/tabbedalt b/tabbedalt index 84968f6..413cade 100644 --- a/tabbedalt +++ b/tabbedalt @@ -152,6 +152,9 @@ # 2023-10-24 21:14:56 # - Added confirmation when closing window when there is more than one tab or # there is a process still running. +# +# 2023-10-28 16:30:32 +# - Added overlay based dialog to confirm closing urxvt window use Scalar::Util; @@ -588,6 +591,23 @@ sub init { } +sub dialog_key_press { + # react only on certain keys: + # n and ESC - this case will delete the overlay + # y and Enter - in this case, all tabs will be destroyed + my ($tab, $event, $keysym, $str) = @_; + + if ($keysym == 0xff0d || $keysym == 0xff8d || $keysym == 0x79) { # enter/y + $tab->disable('key_press'); + $_->destroy for @{ $tab->{main}->{tabs} }; + } elsif ($keysym == 0xff1b || $keysym == 0x6e) { # escape/n + delete $tab->{overlay}; + $tab->disable('key_press'); + $tab->{main}->refresh; + } + return 1; +} + _on start => sub { my ($self) = @_; @@ -626,7 +646,7 @@ _on configure_notify => sub { _on wm_delete_window => sub { my ($self) = @_; - if ($self->{confirm_quit} and $self->{confirm_program}) { + if ($self->{confirm_quit}) { my $tab_count = @{ $self->{tabs} }; my $subp_count = 0; my @subprocesses = split(/\n/, `ps --ppid $$ -o pid=,cmd=`); @@ -647,27 +667,36 @@ _on wm_delete_window => sub { if ($tab_count > 1 or $subp_count > 0) { my $msg = ""; + my $qst = "Are you sure you want to close urxvt?"; $msg = "There are $tab_count tabs opened" if ($tab_count > 1); if ($subp_count > 0) { if (! $msg) { $msg = "There is $subp_count active processes running."; - $msg = "$msg Are you sure you want to close urxvt?"; } else { $msg = "$msg and there is $subp_count active processes running."; - $msg = "$msg Are you sure you want to close urxvt?"; } - }else{ - $msg = "$msg. Are you sure you want to close urxvt?"; } - `$self->{confirm_program} '$msg'`; + if ($self->{confirm_program}) { + `$self->{confirm_program} '$msg $qst'`; - if ($? == 0) { - $self->{is_being_destroyed} = 1; - # stop the timers, as we changed focus - $self->{timer}->stop(); - $_->destroy for @{ $self->{tabs} }; + if ($? == 0) { + $self->{is_being_destroyed} = 1; + # stop the timers, as we changed focus + $self->{timer}->stop(); + $_->destroy for @{ $self->{tabs} }; + } + } else { + my $marginc = int(($self->ncol - length $msg)/2); + my $marginr = int(($self->nrow - 4)/2); + my $tab = $self->{cur}; + + $tab->{overlay} = $tab->overlay_simple($marginc, $marginr, + "$msg\n$qst (y/n)"); + # action for removing all tabs will be decided in following + # method. + $tab->enable(key_press => \&dialog_key_press); } } else { $_->destroy for @{ $self->{tabs} }; @@ -881,7 +910,6 @@ sub start_rename_tab { 1 } - sub _rename_tab_key_press { my ($tab, $event, $keysym, $str) = @_;