]> Dogcows Code - chaz/openbox/commitdiff
can tell when a window that was "closed" has stopped responding now
authorDana Jansens <danakj@orodu.net>
Wed, 16 Jan 2008 02:40:15 +0000 (21:40 -0500)
committerDana Jansens <danakj@orodu.net>
Wed, 16 Jan 2008 02:43:23 +0000 (21:43 -0500)
Makefile.am
openbox/client.c
openbox/event.c
openbox/mainloop.c
openbox/ping.c [new file with mode: 0644]
openbox/ping.h [new file with mode: 0644]
openbox/prop.c
openbox/prop.h

index 34ee07e44ec2ad77446df83e792231e6be1f4bf5..6b474a654a3bd69e29d97dc924779c2a9ab54b51 100644 (file)
@@ -243,6 +243,8 @@ openbox_openbox_SOURCES = \
        openbox/mwm.h \
        openbox/openbox.c \
        openbox/openbox.h \
+       openbox/ping.c \
+       openbox/ping.h \
        openbox/place.c \
        openbox/place.h \
        openbox/popup.c \
index 7019f690086e16f881a3a2efd0a3c24aaed31a47..0f592ebe72df9595c79d22840252039f124cf171 100644 (file)
@@ -3166,10 +3166,16 @@ void client_shade(ObClient *self, gboolean shade)
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
 }
 
-void client_close(ObClient *self)
+static void client_ping_event(ObClient *self, gboolean dead)
 {
-    XEvent ce;
+    if (dead)
+        ob_debug("client 0x%x window 0x%x is not responding !!\n");
+    else
+        ob_debug("client 0x%x window 0x%x started responding again..\n");
+}
 
+void client_close(ObClient *self)
+{
     if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return;
 
     /* in the case that the client provides no means to requesting that it
@@ -3185,17 +3191,11 @@ void client_close(ObClient *self)
       explicitly killed.
     */
 
-    ce.xclient.type = ClientMessage;
-    ce.xclient.message_type =  prop_atoms.wm_protocols;
-    ce.xclient.display = ob_display;
-    ce.xclient.window = self->window;
-    ce.xclient.format = 32;
-    ce.xclient.data.l[0] = prop_atoms.wm_delete_window;
-    ce.xclient.data.l[1] = event_curtime;
-    ce.xclient.data.l[2] = 0l;
-    ce.xclient.data.l[3] = 0l;
-    ce.xclient.data.l[4] = 0l;
-    XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
+    PROP_MSG_TO(self->window, self->window, wm_protocols,
+                prop_atoms.wm_delete_window, event_curtime, 0, 0, 0,
+                NoEventMask);
+
+    ping_start(self, client_ping_event);
 }
 
 void client_kill(ObClient *self)
index 44e0f5328ed269cb46133264e8007e680b4a3704..5d85eaeb3dfdecbf771533c9dbb3a4f199c4f323 100644 (file)
@@ -767,6 +767,9 @@ static void event_handle_root(XEvent *e)
                 ob_restart();
             else if (e->xclient.data.l[0] == 3)
                 ob_exit(0);
+        } else if (msgtype == prop_atoms.wm_protocols) {
+            if (e->xclient.data.l[0] == prop_atoms.net_wm_ping)
+                ping_got_pong(e->xclient.data.l[1]);
         }
         break;
     case PropertyNotify:
index 7c6a956648c480401104ddf3a6dd90175fb1de0b..c1ede830a69eabcd379e2a6576a734cf35ef678b 100644 (file)
@@ -560,7 +560,9 @@ void ob_main_loop_timeout_remove_data(ObMainLoop *loop, GSourceFunc handler,
 
     for (it = loop->timers; it; it = g_slist_next(it)) {
         ObMainLoopTimer *t = it->data;
-        if (t->func == handler && t->equal(t->data, data)) {
+        if (t->func == handler &&
+            (t->equal ? t->equal(t->data, data) : (t->data == data)))
+        {
             t->del_me = TRUE;
             if (cancel_dest)
                 t->destroy = NULL;
diff --git a/openbox/ping.c b/openbox/ping.c
new file mode 100644 (file)
index 0000000..d8c10c8
--- /dev/null
@@ -0,0 +1,151 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   client.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2008   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "ping.h"
+#include "client.h"
+#include "prop.h"
+#include "event.h"
+#include "mainloop.h"
+#include "openbox.h"
+
+typedef struct _ObPingTarget
+{
+    ObClient *client;
+    ObPingEventHandler h;
+    Time sent;
+    gint waiting;
+} ObPingTarget;
+
+static GSList *ping_targets = NULL;
+static gboolean active = FALSE;
+
+#define PING_TIMEOUT (G_USEC_PER_SEC * 1)
+/*! Warn the user after this many PING_TIMEOUT intervals */
+#define PING_TIMEOUT_WARN 3
+
+static void ping_send(ObPingTarget *t);
+static void ping_end(ObClient *client, gpointer data);
+static gboolean ping_timeout(gpointer data);
+
+void ping_start(struct _ObClient *client, ObPingEventHandler h)
+{
+    GSList *it;
+    ObPingTarget *t;
+
+    /* make sure we're not already pinging it */
+    for (it = ping_targets; it != NULL; it = g_slist_next(it)) {
+        t = it->data;
+        if (t->client == client) return;
+    }
+
+    t = g_new(ObPingTarget, 1);
+    t->client = client;
+    t->h = h;
+    t->waiting = 1; /* first wait for a reply */
+
+    ping_send(t);
+    ping_targets = g_slist_prepend(ping_targets, t);
+    ob_main_loop_timeout_add(ob_main_loop, PING_TIMEOUT, ping_timeout,
+                             t, NULL, NULL);
+
+    if (!active) {
+        active = TRUE;
+        /* listen for the client to disappear */
+        client_add_destroy_notify(ping_end, NULL);
+    }
+}
+
+void ping_stop(struct _ObClient *c)
+{
+    ping_end(c, NULL);
+}
+
+void ping_got_pong(Time timestamp)
+{
+    GSList *it;
+    ObPingTarget *t;
+
+    /* make sure we're not already pinging it */
+    for (it = ping_targets; it != NULL; it = g_slist_next(it)) {
+        t = it->data;
+        if (t->sent == timestamp) {
+            ob_debug("Got PONG with timestamp %lu\n", timestamp);
+            if (t->waiting > PING_TIMEOUT_WARN) {
+                /* we had notified that they weren't responding, so now we
+                   need to notify that they are again */
+                t->h(t->client, FALSE);
+            }
+            t->waiting = 0; /* not waiting for a reply anymore */
+            break;
+        }
+    }
+
+    if (it == NULL)
+        ob_debug("Got PONG with timestamp %lu but not waiting for one\n",
+                 timestamp);
+}
+
+static void ping_send(ObPingTarget *t)
+{
+    t->sent = event_get_server_time();
+    ob_debug("PINGing client 0x%x at %lu\n", t->client->window, t->sent);
+    PROP_MSG_TO(t->client->window, t->client->window, wm_protocols,
+                prop_atoms.net_wm_ping, t->sent, t->client->window, 0, 0,
+                NoEventMask);
+}
+
+static gboolean ping_timeout(gpointer data)
+{
+    ObPingTarget *t = data;
+
+    if (t->waiting == 0) { /* got a reply already */
+        /* send another ping to make sure it's still alive */
+        ping_send(t);
+    }
+
+    if (t->waiting == PING_TIMEOUT_WARN)
+        t->h(t->client, TRUE); /* notify that the client isn't responding */
+
+    ++t->waiting;
+
+    return TRUE; /* repeat */
+}
+
+static void ping_end(ObClient *client, gpointer data)
+{
+    GSList *it;
+    ObPingTarget *t;
+
+    for (it = ping_targets; it != NULL; it = g_slist_next(it)) {
+        t = it->data;
+        if (t->client == client) {
+            ping_targets = g_slist_remove_link(ping_targets, it);
+            ob_main_loop_timeout_remove_data(ob_main_loop, ping_timeout, t,
+                                             FALSE);
+            g_free(t);
+            break;
+        }
+    }
+
+    /* stop listening if we're not waiting for any more pings */
+    if (!ping_targets) {
+        active = TRUE;
+        client_remove_destroy_notify(ping_end);
+    }    
+}
diff --git a/openbox/ping.h b/openbox/ping.h
new file mode 100644 (file)
index 0000000..0b6dfea
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   client.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2008   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __ping_h
+#define __ping_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+struct _ObClient;
+
+/*!
+  Notifies when the client application isn't responding to pings, or when it
+  starts responding again.
+  @param dead TRUE if the app isn't responding, FALSE if it starts responding
+              again
+*/
+typedef void (*ObPingEventHandler) (struct _ObClient *c, gboolean dead);
+
+void ping_start(struct _ObClient *c, ObPingEventHandler h);
+void ping_stop(struct _ObClient *c);
+
+void ping_got_pong(Time timestamp);
+
+#endif
index 1e343e1695507f06e556f0017436ce9a20302b40..b43dcd13fd5f177f61921e696edbfada314d7d86 100644 (file)
@@ -446,6 +446,14 @@ void prop_erase(Window win, Atom prop)
 
 void prop_message(Window about, Atom messagetype, glong data0, glong data1,
                   glong data2, glong data3, glong mask)
+{
+    prop_message_to(RootWindow(ob_display, ob_screen), about, messagetype,
+                    data0, data1, data2, data3, 0, mask);
+}
+
+void prop_message_to(Window to, Window about, Atom messagetype,
+                     glong data0, glong data1, glong data2,
+                     glong data3, glong data4, glong mask)
 {
     XEvent ce;
     ce.xclient.type = ClientMessage;
@@ -457,7 +465,6 @@ void prop_message(Window about, Atom messagetype, glong data0, glong data1,
     ce.xclient.data.l[1] = data1;
     ce.xclient.data.l[2] = data2;
     ce.xclient.data.l[3] = data3;
-    ce.xclient.data.l[4] = 0;
-    XSendEvent(ob_display, RootWindow(ob_display, ob_screen), FALSE,
-               mask, &ce);
+    ce.xclient.data.l[4] = data4;
+    XSendEvent(ob_display, to, FALSE, mask, &ce);
 }
index fd12f98a94d7c138a05f37a6abd95470ed9ddcee..13c338efcfd86115351ae4c9e6cff7deeebe3eed 100644 (file)
@@ -218,6 +218,9 @@ void prop_erase(Window win, Atom prop);
 
 void prop_message(Window about, Atom messagetype, glong data0, glong data1,
                   glong data2, glong data3, glong mask);
+void prop_message_to(Window to, Window about, Atom messagetype,
+                     glong data0, glong data1, glong data2,
+                     glong data3, glong data4, glong mask);
 
 #define PROP_GET32(win, prop, type, ret) \
     (prop_get32(win, prop_atoms.prop, prop_atoms.type, ret))
@@ -244,4 +247,9 @@ void prop_message(Window about, Atom messagetype, glong data0, glong data1,
   (prop_message(about, prop_atoms.msgtype, data0, data1, data2, data3, \
                 SubstructureNotifyMask | SubstructureRedirectMask))
 
+#define PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, data4, \
+                    mask) \
+    (prop_message_to(to, about, prop_atoms.msgtype,                        \
+                     data0, data1, data2, data3, data4, mask))
+
 #endif
This page took 0.036817 seconds and 4 git commands to generate.