Skip to content
This repository has been archived by the owner on Feb 10, 2024. It is now read-only.

Undo tab close #1668

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 48 additions & 3 deletions src/fe-gtk/fkeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void key_action_tab_clean (void);
*/

/* Remember that the *number* of actions is this *plus* 1 --AGL */
#define KEY_MAX_ACTIONS 14
#define KEY_MAX_ACTIONS 17

struct key_binding
{
Expand Down Expand Up @@ -132,6 +132,15 @@ static int key_action_move_tab_family_right (GtkWidget * wid, GdkEventKey * evt,
static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_close_tab (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_undo_tab_close (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_clear_text (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);

static GSList *keybind_list = NULL;

Expand Down Expand Up @@ -167,6 +176,12 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
N_("This command moves the current tab family to the right")},
{key_action_put_history, "Push input line into history",
N_("Push input line into history but doesn't send to server")},
{key_action_close_tab, "Close tab",
N_("Close tab")},
{key_action_undo_tab_close, "Undo tab close",
N_("Undo tab close")},
{key_action_clear_text, "Clear text",
N_("Clear text")},
};

#define default_kb_cfg \
Expand Down Expand Up @@ -208,7 +223,10 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
"ACCEL=<Alt>Right\nMove front tab right\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Up\nMove tab family left\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Down\nMove tab family right\nD1!\nD2!\n\n"\
"ACCEL=F9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n"
"ACCEL=F9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n"\
"ACCEL=<Primary>w\nClose tab\nD1:!\nD2!\n\n"\
"ACCEL=<Primary><Shift>t\nUndo tab close\nD1:!\nD2!\n\n"\
"ACCEL=<Primary>l\nClear text\nD1:!\nD2!\n\n"\

void
key_init ()
Expand Down Expand Up @@ -305,6 +323,7 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
struct key_binding *kb;
int n;
GSList *list;
guint upper, lower;

/* where did this event come from? */
list = sess_list;
Expand Down Expand Up @@ -333,9 +352,12 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
list = keybind_list;
while (list)
{
upper = lower = 0;
gdk_keyval_convert_case(evt->keyval, &upper, &lower);
kb = (struct key_binding*)list->data;

if (kb->keyval == evt->keyval && kb->mod == key_modifier_get_valid (evt->state))
if ((kb->keyval == evt->keyval || kb->keyval == upper || kb->keyval == lower) &&
kb->mod == key_modifier_get_valid (evt->state))
{
if (kb->action < 0 || kb->action > KEY_MAX_ACTIONS)
return 0;
Expand Down Expand Up @@ -1767,6 +1789,29 @@ key_action_put_history (GtkWidget * wid, GdkEventKey * ent, char *d1,
return 2; /* -''- */
}

static int
key_action_close_tab (GtkWidget * wid, GdkEventKey * ent, char *d1,
char *d2, struct session *sess)
{
mg_close_sess (sess);
return 2;
}

static int
key_action_undo_tab_close (GtkWidget * wid, GdkEventKey * ent, char *d1,
char *d2, struct session *sess)
{
mg_undo_tab_close (sess);
return 2;
}

static int
key_action_clear_text (GtkWidget * wid, GdkEventKey * ent, char *d1,
char *d2, struct session *sess)
{
fe_text_clear (sess, 0);
return 2;
}

/* -------- */

Expand Down
41 changes: 41 additions & 0 deletions src/fe-gtk/maingui.c
Original file line number Diff line number Diff line change
Expand Up @@ -1051,13 +1051,39 @@ mg_tab_close_cb (GtkWidget *dialog, gint arg1, session *sess)
}
}

typedef struct closed_channel {
server *server;
char channel[CHANLEN];
char key[64];
} closed_channel;

static GQueue closed_channels = G_QUEUE_INIT;

void
mg_tab_close (session *sess)
{
GtkWidget *dialog;
GSList *list;
int i;

if (hexchat_is_quitting)
{
closed_channel *chan;
while (!g_queue_is_empty(&closed_channels))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the point of freeing memory when the process is exiting.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in any case, g_queue_free_full exists for this purpose.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About g_queue_free_full, isn't it intended to be used only for dynamically allocated queue objects? I thought it was the same as g_queue_free, so I avoided using it. I need to investigate a bit further.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have just checked glib source code and g_queue_free_full will indeed call g_queue_free, so it should not be used in this case.

{
chan = g_queue_pop_head(&closed_channels);
g_free(chan);
}
}
else if (is_channel (sess->server, sess->channel))
{
closed_channel *chan = g_new0(closed_channel, 1);
chan->server = sess->server;
g_strlcpy(chan->channel, sess->channel, CHANLEN);
g_strlcpy(chan->key, sess->channelkey, 64);
g_queue_push_head(&closed_channels, chan);
}

if (chan_remove (sess->res->tab, FALSE))
{
sess->res->tab = NULL;
Expand Down Expand Up @@ -1089,6 +1115,21 @@ mg_tab_close (session *sess)
}
}

void
mg_undo_tab_close (session *sess)
{
closed_channel *chan;

if (g_queue_is_empty(&closed_channels))
return;

chan = g_queue_pop_head(&closed_channels);
if (is_server (chan->server))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little suboptimal to silently ignore the undo command if this is false. The user will have no idea why nothing happened, and if they press it again expecting it didn't go through the first time, it might reopen a completely different tab.

chan->server->p_join (chan->server, chan->channel, chan->key);

g_free(chan);
}

static void
mg_menu_destroy (GtkWidget *menu, gpointer userdata)
{
Expand Down
1 change: 1 addition & 0 deletions src/fe-gtk/maingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void mg_set_access_icon (session_gui *gui, GdkPixbuf *pix, gboolean away);
void mg_apply_setup (void);
void mg_close_sess (session *);
void mg_tab_close (session *sess);
void mg_undo_tab_close (session *sess);
void mg_detach (session *sess, int mode);
void mg_progressbar_create (session_gui *gui);
void mg_progressbar_destroy (session_gui *gui);
Expand Down