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?p=chaz%2Fopenbox;a=commitdiff_plain;h=d714bb5708bb8b99d71803404af7af01029c5553 prompt to kill windows when they are not responding --- diff --git a/openbox/client.c b/openbox/client.c index 7add1222..98ad7de2 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -105,6 +105,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) @@ -302,7 +303,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(ob_display, window, SetModeInsert); @@ -704,7 +706,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(ob_display, self->window, SetModeDelete); @@ -715,6 +718,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); g_hash_table_remove(window_map, &self->window); @@ -1992,7 +1999,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")); @@ -2024,7 +2031,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")); @@ -3338,9 +3345,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; } } @@ -3359,24 +3371,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(ob_display, self->window); - else if (self->not_responding) - client_kill(self); - else + else { /* request the client to close with WM_DELETE_WINDOW */ PROP_MSG_TO(self->window, self->window, wm_protocols, prop_atoms.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) { - ob_debug("killing window 0x%x with pid %lu, with SIGTERM\n", + 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); @@ -3387,8 +3439,10 @@ void client_kill(ObClient *self) kill(self->pid, SIGKILL); /* kill -9 */ } } - else + else { + /* running on a remote host */ XKillClient(ob_display, self->window); + } } void client_hilite(ObClient *self, gboolean hilite) diff --git a/openbox/client.h b/openbox/client.h index ac6b3153..4e19bdf8 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 ddf78e4f..ea249712 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -89,7 +89,7 @@ static void event_process(const XEvent *e, gpointer data); static void event_handle_root(XEvent *e); static gboolean event_handle_menu_keyboard(XEvent *e); static gboolean event_handle_menu(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); @@ -707,8 +707,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 */ @@ -1677,18 +1677,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_keyboard(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 277294d0..cb14187c 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -232,6 +232,8 @@ gint main(gint argc, gchar **argv) keys[OB_KEY_RIGHT] = modkeys_sym_to_code(XK_Right); keys[OB_KEY_UP] = modkeys_sym_to_code(XK_Up); keys[OB_KEY_DOWN] = modkeys_sym_to_code(XK_Down); + keys[OB_KEY_TAB] = modkeys_sym_to_code(XK_Tab); + keys[OB_KEY_SPACE] = modkeys_sym_to_code(XK_space); { ObParseInst *i; diff --git a/openbox/prompt.c b/openbox/prompt.c index ba5228a1..080dc9a8 100644 --- a/openbox/prompt.c +++ b/openbox/prompt.c @@ -348,8 +348,8 @@ void prompt_show(ObPrompt *self, ObClient *parent) hints.min_height = hints.max_height = self->height; XSetWMNormalHints(ob_display, self->super.window, &hints); - XSetTransientForHint(ob_display, (parent ? parent->window : 0), - self->super.window); + XSetTransientForHint(ob_display, self->super.window, + (parent ? parent->window : 0)); /* set up the dialog and render it */ prompt_layout(self); @@ -366,12 +366,12 @@ 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; g_print("key 0x%x 0x%x\n", e->xkey.keycode, ob_keycode(OB_KEY_TAB)); @@ -380,23 +380,31 @@ void prompt_key_event(ObPrompt *self, XEvent *e) /* 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]; @@ -404,9 +412,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; @@ -415,6 +424,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)) @@ -422,7 +432,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; @@ -452,6 +462,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 c470f101..c24f0448 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