From: Dana Jansens Date: Thu, 7 Feb 2008 05:49:08 +0000 (-0500) Subject: prompt to kill windows when they are not responding X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;ds=sidebyside;h=95ee6b103f116e34062bf5e1ad1cb8b0f23e7231;hp=0e9cfd7c77d8608a4be29f43413575d9553bf21c;p=chaz%2Fopenbox prompt to kill windows when they are not responding --- diff --git a/openbox/client.c b/openbox/client.c index aad92029..d088fca6 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -104,6 +104,7 @@ static GSList *client_search_all_top_parents_internal(ObClient *self, ObStackingLayer layer); static void client_call_notifies(ObClient *self, GSList *list); static void client_ping_event(ObClient *self, gboolean dead); +static void client_prompt_kill(ObClient *self); void client_startup(gboolean reconfig) @@ -221,7 +222,8 @@ void client_manage(Window window, ObPrompt *prompt) client_setup_decor_and_functions(self, FALSE); /* specify that if we exit, the window should not be destroyed and - should be reparented back to root automatically */ + should be reparented back to root automatically, unless we are managing + an internal ObPrompt window */ if (!self->prompt) XChangeSaveSet(obt_display, window, SetModeInsert); @@ -621,7 +623,8 @@ void client_unmanage(ObClient *self) mouse_grab_for_client(self, FALSE); - /* remove the window from our save set */ + /* remove the window from our save set, unless we are managing an internal + ObPrompt window */ if (!self->prompt) XChangeSaveSet(obt_display, self->window, SetModeDelete); @@ -632,6 +635,10 @@ void client_unmanage(ObClient *self) focus_client = NULL; } + /* if we're prompting to kill the client, close that */ + prompt_unref(self->kill_prompt); + self->kill_prompt = NULL; + client_list = g_list_remove(client_list, self); stacking_remove(self); window_remove(self->window); @@ -1910,7 +1917,7 @@ void client_update_title(ObClient *self) if (self->not_responding) { data = visible; - if (self->close_tried_term) + if (self->kill_level > 0) visible = g_strdup_printf("%s - [%s]", data, _("Killing...")); else visible = g_strdup_printf("%s - [%s]", data, _("Not Responding")); @@ -1942,7 +1949,7 @@ void client_update_title(ObClient *self) if (self->not_responding) { data = visible; - if (self->close_tried_term) + if (self->kill_level > 0) visible = g_strdup_printf("%s - [%s]", data, _("Killing...")); else visible = g_strdup_printf("%s - [%s]", data, _("Not Responding")); @@ -3246,9 +3253,14 @@ static void client_ping_event(ObClient *self, gboolean dead) client_update_title(self); if (!dead) { - /* try kill it nicely the first time again, if it started responding - at some point */ - self->close_tried_term = FALSE; + /* it came back to life ! */ + + if (self->kill_prompt) { + prompt_unref(self->kill_prompt); + self->kill_prompt = NULL; + } + + self->kill_level = 0; } } @@ -3267,24 +3279,64 @@ void client_close(ObClient *self) /* don't use client_kill(), we should only kill based on PID in response to a lack of PING replies */ XKillClient(obt_display, self->window); - else if (self->not_responding) - client_kill(self); - else + else { /* request the client to close with WM_DELETE_WINDOW */ OBT_PROP_MSG_TO(self->window, self->window, WM_PROTOCOLS, OBT_PROP_ATOM(WM_DELETE_WINDOW), event_curtime, 0, 0, 0, NoEventMask); + + if (self->not_responding) + client_prompt_kill(self); + } +} + +#define OB_KILL_RESULT_NO 0 +#define OB_KILL_RESULT_YES 1 + +static void client_kill_requested(ObPrompt *p, gint result, gpointer data) +{ + ObClient *self = data; + + if (result == OB_KILL_RESULT_YES) + client_kill(self); + + prompt_unref(self->kill_prompt); + self->kill_prompt = NULL; +} + +static void client_prompt_kill(ObClient *self) +{ + ObPromptAnswer answers[] = { + { _("No"), OB_KILL_RESULT_NO }, + { _("Yes"), OB_KILL_RESULT_YES } + }; + gchar *m; + + /* check if we're already prompting */ + if (self->kill_prompt) return; + + m = g_strdup_printf + (_("The window \"%s\" does not seem to be responding. Do you want to force it to exit?"), self->title); + + self->kill_prompt = prompt_new(m, answers, + sizeof(answers)/sizeof(answers[0]), + OB_KILL_RESULT_NO, /* default = no */ + OB_KILL_RESULT_NO, /* cancel = no */ + client_kill_requested, self); + prompt_show(self->kill_prompt, self); + + g_free(m); } void client_kill(ObClient *self) { if (!self->client_machine && self->pid) { /* running on the local host */ - if (!self->close_tried_term) { + if (self->kill_level == 0) { ob_debug("killing window 0x%x with pid %lu, with SIGTERM", self->window, self->pid); kill(self->pid, SIGTERM); - self->close_tried_term = TRUE; + ++self->kill_level; /* show that we're trying to kill it */ client_update_title(self); @@ -3295,8 +3347,10 @@ void client_kill(ObClient *self) kill(self->pid, SIGKILL); /* kill -9 */ } } - else + else { + /* running on a remote host */ XKillClient(obt_display, self->window); + } } void client_hilite(ObClient *self, gboolean hilite) diff --git a/openbox/client.h b/openbox/client.h index 2012cbd7..2f1840cf 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -236,8 +236,11 @@ struct _ObClient /*! Indicates if the client is trying to close but has stopped responding to pings */ gboolean not_responding; + /*! A prompt shown when you are trying to close a client that is not + responding. It asks if you want to kill the client */ + struct _ObPrompt *kill_prompt; /*! We tried to close the window with a SIGTERM */ - gboolean close_tried_term; + gint kill_level; #ifdef SYNC /*! The client wants to sync during resizes */ diff --git a/openbox/event.c b/openbox/event.c index 3476f627..4fbb97c6 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -86,7 +86,7 @@ static void event_process(const XEvent *e, gpointer data); static void event_handle_root(XEvent *e); static gboolean event_handle_menu_input(XEvent *e); static void event_handle_menu(ObMenuFrame *frame, XEvent *e); -static void event_handle_prompt(ObPrompt *p, XEvent *e); +static gboolean event_handle_prompt(ObPrompt *p, XEvent *e); static void event_handle_dock(ObDock *s, XEvent *e); static void event_handle_dockapp(ObDockApp *app, XEvent *e); static void event_handle_client(ObClient *c, XEvent *e); @@ -712,8 +712,8 @@ static void event_process(const XEvent *ec, gpointer data) } #endif - if (prompt) - event_handle_prompt(prompt, e); + if (prompt && event_handle_prompt(prompt, e)) + ; else if (e->type == ButtonPress || e->type == ButtonRelease) { /* If the button press was on some non-root window, or was physically on the root window, then process it */ @@ -1682,18 +1682,19 @@ static ObMenuFrame* find_active_or_last_menu(void) return ret; } -static void event_handle_prompt(ObPrompt *p, XEvent *e) +static gboolean event_handle_prompt(ObPrompt *p, XEvent *e) { switch (e->type) { case ButtonPress: case ButtonRelease: case MotionNotify: - prompt_mouse_event(p, e); + return prompt_mouse_event(p, e); break; case KeyPress: - prompt_key_event(p, e); + return prompt_key_event(p, e); break; } + return FALSE; } static gboolean event_handle_menu_input(XEvent *ev) diff --git a/openbox/misc.h b/openbox/misc.h index 01c2da1d..c73c9265 100644 --- a/openbox/misc.h +++ b/openbox/misc.h @@ -52,6 +52,7 @@ typedef enum OB_KEY_UP, OB_KEY_DOWN, OB_KEY_TAB, + OB_KEY_SPACE, OB_NUM_KEYS } ObKey; diff --git a/openbox/openbox.c b/openbox/openbox.c index bef42ab1..a6a81cef 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -210,6 +210,8 @@ gint main(gint argc, gchar **argv) keys[OB_KEY_RIGHT] = obt_keyboard_keysym_to_keycode(XK_Right); keys[OB_KEY_UP] = obt_keyboard_keysym_to_keycode(XK_Up); keys[OB_KEY_DOWN] = obt_keyboard_keysym_to_keycode(XK_Down); + keys[OB_KEY_TAB] = obt_keyboard_keysym_to_keycode(XK_Tab); + keys[OB_KEY_SPACE] = obt_keyboard_keysym_to_keycode(XK_space); { ObtParseInst *i; diff --git a/openbox/prompt.c b/openbox/prompt.c index 54ea469d..b1969e06 100644 --- a/openbox/prompt.c +++ b/openbox/prompt.c @@ -346,8 +346,8 @@ void prompt_show(ObPrompt *self, ObClient *parent) hints.min_height = hints.max_height = self->height; XSetWMNormalHints(obt_display, self->super.window, &hints); - XSetTransientForHint(obt_display, (parent ? parent->window : 0), - self->super.window); + XSetTransientForHint(obt_display, self->super.window, + (parent ? parent->window : 0)); /* set up the dialog and render it */ prompt_layout(self); @@ -364,35 +364,43 @@ void prompt_hide(ObPrompt *self) self->mapped = FALSE; } -void prompt_key_event(ObPrompt *self, XEvent *e) +gboolean prompt_key_event(ObPrompt *self, XEvent *e) { gboolean shift; guint shift_mask; - if (e->type != KeyPress) return; + if (e->type != KeyPress) return FALSE; shift_mask = obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT); shift = !!(e->xkey.state & shift_mask); /* only accept shift */ if (e->xkey.state != 0 && e->xkey.state != shift_mask) - return; + return FALSE; if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) prompt_cancel(self); - else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) { + else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) || + e->xkey.keycode == ob_keycode(OB_KEY_SPACE)) + { if (self->func) self->func(self, self->focus->result, self->data); prompt_hide(self); } - else if (e->xkey.keycode == ob_keycode(OB_KEY_TAB)) { + else if (e->xkey.keycode == ob_keycode(OB_KEY_TAB) || + e->xkey.keycode == ob_keycode(OB_KEY_LEFT) || + e->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) + { gint i; + gboolean left; ObPromptElement *oldfocus; + left = e->xkey.keycode == ob_keycode(OB_KEY_LEFT) || + (e->xkey.keycode == ob_keycode(OB_KEY_TAB) && shift); oldfocus = self->focus; for (i = 0; i < self->n_buttons; ++i) if (self->focus == &self->button[i]) break; - i += (shift ? -1 : 1); + i += (left ? -1 : 1); if (i < 0) i = self->n_buttons - 1; else if (i >= self->n_buttons) i = 0; self->focus = &self->button[i]; @@ -400,9 +408,10 @@ void prompt_key_event(ObPrompt *self, XEvent *e) if (oldfocus != self->focus) render_button(self, oldfocus); render_button(self, self->focus); } + return TRUE; } -void prompt_mouse_event(ObPrompt *self, XEvent *e) +gboolean prompt_mouse_event(ObPrompt *self, XEvent *e) { gint i; ObPromptElement *but; @@ -411,6 +420,7 @@ void prompt_mouse_event(ObPrompt *self, XEvent *e) e->type != MotionNotify) return; /* find the button */ + but = NULL; for (i = 0; i < self->n_buttons; ++i) if (self->button[i].window == (e->type == MotionNotify ? e->xmotion.window : e->xbutton.window)) @@ -418,7 +428,7 @@ void prompt_mouse_event(ObPrompt *self, XEvent *e) but = &self->button[i]; break; } - g_assert(but != NULL); + if (!but) return FALSE; if (e->type == ButtonPress) { ObPromptElement *oldfocus; @@ -448,6 +458,7 @@ void prompt_mouse_event(ObPrompt *self, XEvent *e) render_button(self, but); } } + return TRUE; } void prompt_cancel(ObPrompt *self) diff --git a/openbox/prompt.h b/openbox/prompt.h index 1d5851f5..1bcd66cc 100644 --- a/openbox/prompt.h +++ b/openbox/prompt.h @@ -103,8 +103,8 @@ void prompt_unref(ObPrompt *self); void prompt_show(ObPrompt *self, struct _ObClient *parent); void prompt_hide(ObPrompt *self); -void prompt_key_event(ObPrompt *self, XEvent *e); -void prompt_mouse_event(ObPrompt *self, XEvent *e); +gboolean prompt_key_event(ObPrompt *self, XEvent *e); +gboolean prompt_mouse_event(ObPrompt *self, XEvent *e); void prompt_cancel(ObPrompt *self); #endif