From 468c2f72f6282704b444b608b8bd7b03aa6990a0 Mon Sep 17 00:00:00 2001 From: gryf Date: Wed, 25 Oct 2023 21:45:02 +0200 Subject: [PATCH] Added ability to confogure window close confirmation. --- README.rst | 57 ++++++++++++++++++++++++++++++++++++++++++------- tabbedalt | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 275860b..1e726e2 100644 --- a/README.rst +++ b/README.rst @@ -8,9 +8,9 @@ terminal emulator Features -------- -* Possibility to add named tabs, through the X resources, which represents its - *class*. Without any configuration only default shell *class* is available - under default (``Shift+Down``) shortcut. +* Possibility to add named tabs, through the X resources, which run specified + command or another shell (zsh/fish/ash/csh/ksh…). Without any configuration + only default shell is available under default (``Shift+Down``) shortcut. .. image:: /screens/tabbed.png :alt: Named tabs @@ -31,6 +31,8 @@ Features option. See below for examples. * Autohide tab when there is only one tab at the moment. * Ability to assign hotkey to jump to last tab. +* Configurable confirm dialog for closing urxvt window, when there is more than + one tab opened or there is an process still running. Installation ------------ @@ -247,6 +249,42 @@ still a way for selecting 10th tab, i.e.:: In the example above, there are mapping for jump to tabs 1 - 12 using function keys, and `Control+0` to jump whatever last tab is. +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:: + + 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: + +- 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, +- destroying the dialog also emit exit code higher than 0. + +So, for example standard `xmessage`_ can be used:: + + URxvt.tabbedalt.confirm-program: xmessage -buttons ok:0,cancel:1 + +or `zenity`_:: + + URxvt.tabbedalt.confirm-program: zenity --question --title 'Close window' --text + +or `kdialog`_:: + + URxvt.tabbedalt.confirm-program: kdialog --title 'Close window' --yesno + +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 --------------------------------- @@ -260,14 +298,14 @@ Let's assume, that one want to add three kind of custom shells: A way to do this is to associate keystroke for it in ``.Xdefaults`` using urxvts ``keysym`` option, and the actions described above:: - URxvt.keysym.Control-Shift-N: tabbedalt.new_tab:shell - URxvt.keysym.Control-Shift-R: tabbedalt.new_tab:root:su - - URxvt.keysym.Control-Shift-M: tabbedalt.new_tab:mc:mc + URxvt.keysym.Control-Shift-N: tabbedalt:new_tab:shell + URxvt.keysym.Control-Shift-R: tabbedalt:new_tab:root:su - + URxvt.keysym.Control-Shift-M: tabbedalt:new_tab:mc:mc Resource values are colon separated values, which are in order: -* **plugin name**, which in case of this very plugin would be always - ``tabbedalt``. +* **plugin name:command**, which in this case of creating new tab will be + ``tabbedalt:new_tab``. * **title of the tab**, it could be anything but the colon. * **optional command**. If omitted, default shell will be launched. @@ -282,3 +320,6 @@ feature was taken from `stepb`_ tabbedx repository. .. _activity indicator: http://mina86.com/2009/05/16/tabbed-urxvt-extension/ .. _stepb: http://github.com/stepb/urxvt-tabbedex .. _tabbedex: https://github.com/mina86/urxvt-tabbedex +.. _xmessage: https://gitlab.freedesktop.org/xorg/app/xmessage +.. _zenity: https://wiki.gnome.org/Projects/Zenity +.. _kdialog: https://develop.kde.org/docs/administration/kdialog diff --git a/tabbedalt b/tabbedalt index ffdceb8..84968f6 100644 --- a/tabbedalt +++ b/tabbedalt @@ -148,6 +148,10 @@ # # 2022-09-18 14:26:00 # - Add workaround for font flickering +# +# 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. use Scalar::Util; @@ -467,12 +471,18 @@ sub _key_event { _on focus_in => sub { my ($self, $event) = @_; + if (defined($self->{is_being_destroyed})) { + return + } $self->{cur}->focus_in; () }; _on focus_out => sub { my ($self, $event) = @_; + if (defined($self->{is_being_destroyed})) { + return + } $self->{cur}->focus_out; () }; @@ -551,6 +561,8 @@ sub init { $self->{autohide} = $self->x_resource_boolean('autohide'); $self->{zero_jump_last} = $self->x_resource_boolean('zero-jump-last'); $self->{stop_flickering} = $self->x_resource_boolean('stop-flickering'); + $self->{confirm_quit} = $self->x_resource_boolean('confirm-quit'); + $self->{confirm_program} = $self->x_resource('confirm-program'); my $timeouts = $self->x_resource ("tabbar-timeouts"); $timeouts = '16:.:8:::4:+' unless defined $timeouts; @@ -614,7 +626,55 @@ _on configure_notify => sub { _on wm_delete_window => sub { my ($self) = @_; - $_->destroy for @{ $self->{tabs} }; + if ($self->{confirm_quit} and $self->{confirm_program}) { + my $tab_count = @{ $self->{tabs} }; + my $subp_count = 0; + my @subprocesses = split(/\n/, `ps --ppid $$ -o pid=,cmd=`); + my %process_to_skip = ( "bash"=>1, "zsh"=>1, "ps"=>1, "fish"=>1, "sh"=>1 ); + + foreach my $line (@subprocesses) { + chomp $line; + my @split_line = split(/ /, $line); + my $pid = @split_line[0]; + my $proc_name = @split_line[1]; + chomp $proc_name; + if (!exists $process_to_skip{$proc_name}) { + $subp_count = $subp_count + 1; + } else { + $subp_count = $subp_count + `ps --ppid $pid -o pid= | wc -l`; + } + } + + if ($tab_count > 1 or $subp_count > 0) { + my $msg = ""; + $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 ($? == 0) { + $self->{is_being_destroyed} = 1; + # stop the timers, as we changed focus + $self->{timer}->stop(); + $_->destroy for @{ $self->{tabs} }; + } + } else { + $_->destroy for @{ $self->{tabs} }; + } + } else { + $_->destroy for @{ $self->{tabs} }; + } 1 };