summaryrefslogtreecommitdiff
path: root/openbox/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbox/client.c')
-rw-r--r--openbox/client.c113
1 files changed, 95 insertions, 18 deletions
diff --git a/openbox/client.c b/openbox/client.c
index 6534e1b3..a54feb8b 100644
--- a/openbox/client.c
+++ b/openbox/client.c
@@ -29,6 +29,7 @@
#include "session.h"
#include "event.h"
#include "grab.h"
+#include "prompt.h"
#include "focus.h"
#include "stacking.h"
#include "openbox.h"
@@ -103,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)
@@ -174,7 +176,7 @@ void client_set_list(void)
stacking_set_list();
}
-void client_manage(Window window)
+void client_manage(Window window, ObPrompt *prompt)
{
ObClient *self;
XSetWindowAttributes attrib_set;
@@ -188,8 +190,10 @@ void client_manage(Window window)
map_time = event_get_server_time();
- /* choose the events we want to receive on the CLIENT window */
- attrib_set.event_mask = CLIENT_EVENTMASK;
+ /* choose the events we want to receive on the CLIENT window
+ (ObPrompt windows can request events too) */
+ attrib_set.event_mask = CLIENT_EVENTMASK |
+ (prompt ? prompt->event_mask : 0);
attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
XChangeWindowAttributes(obt_display, window,
CWEventMask|CWDontPropagate, &attrib_set);
@@ -199,6 +203,7 @@ void client_manage(Window window)
self = g_new0(ObClient, 1);
self->obwin.type = OB_WINDOW_CLASS_CLIENT;
self->window = window;
+ self->prompt = prompt;
/* non-zero defaults */
self->wmstate = WithdrawnState; /* make sure it gets updated first time */
@@ -217,8 +222,10 @@ void client_manage(Window window)
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 */
- XChangeSaveSet(obt_display, window, SetModeInsert);
+ should be reparented back to root automatically, unless we are managing
+ an internal ObPrompt window */
+ if (!self->prompt)
+ XChangeSaveSet(obt_display, window, SetModeInsert);
/* create the decoration frame for the client window */
self->frame = frame_new(self);
@@ -616,8 +623,10 @@ void client_unmanage(ObClient *self)
mouse_grab_for_client(self, FALSE);
- /* remove the window from our save set */
- XChangeSaveSet(obt_display, self->window, SetModeDelete);
+ /* remove the window from our save set, unless we are managing an internal
+ ObPrompt window */
+ if (!self->prompt)
+ XChangeSaveSet(obt_display, self->window, SetModeDelete);
/* update the focus lists */
focus_order_remove(self);
@@ -626,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);
@@ -724,6 +737,7 @@ void client_unmanage(ObClient *self)
g_free(self->wm_command);
g_free(self->title);
g_free(self->icon_title);
+ g_free(self->original_title);
g_free(self->name);
g_free(self->class);
g_free(self->role);
@@ -1879,6 +1893,7 @@ void client_update_title(ObClient *self)
gchar *visible = NULL;
g_free(self->title);
+ g_free(self->original_title);
/* try netwm */
if (!OBT_PROP_GETS(self->window, NET_WM_NAME, utf8, &data)) {
@@ -1895,6 +1910,7 @@ void client_update_title(ObClient *self)
data = g_strdup("Unnamed Window");
}
}
+ self->original_title = g_strdup(data);
if (self->client_machine) {
visible = g_strdup_printf("%s (%s)", data, self->client_machine);
@@ -1904,7 +1920,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"));
@@ -1936,7 +1952,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"));
@@ -3240,9 +3256,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;
}
}
@@ -3250,30 +3271,84 @@ void client_close(ObClient *self)
{
if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return;
+ if (self->prompt) {
+ prompt_cancel(self->prompt);
+ return;
+ }
+
/* in the case that the client provides no means to requesting that it
close, we just kill it */
if (!self->delete_window)
/* 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)
+{
+ /* check if we're already prompting */
+ if (!self->kill_prompt) {
+ ObPromptAnswer answers[] = {
+ { _("No"), OB_KILL_RESULT_NO },
+ { _("Yes"), OB_KILL_RESULT_YES }
+ };
+ gchar *m;
+ const gchar *sig;
+
+ if (self->kill_level == 0)
+ sig = "terminate";
+ else
+ sig = "kill";
+
+ m = g_strdup_printf
+ (_("The window \"%s\" does not seem to be responding. Do you want to force it to exit by sending the %s signal?"), self->original_title, sig);
+
+ 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);
+ g_free(m);
+ }
+
+ prompt_show(self->kill_prompt, self);
}
void client_kill(ObClient *self)
{
+ /* don't kill our own windows */
+ if (self->prompt) return;
+
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);
@@ -3284,8 +3359,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)