From 98f7f2620c96ea0a2b235c6ddd559db85ec96daf Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 19 Dec 2013 04:59:42 +0100 Subject: [PATCH] Implemented a way to unregister desktop messages --- include/Desktop/message.h | 3 ++ src/message.c | 99 +++++++++++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/include/Desktop/message.h b/include/Desktop/message.h index f64a967..0c95c3f 100644 --- a/include/Desktop/message.h +++ b/include/Desktop/message.h @@ -30,6 +30,9 @@ typedef int (*DesktopMessageCallback)(void * data, uint32_t value1, /* functions */ int desktop_message_register(GtkWidget * window, char const * destination, DesktopMessageCallback callback, void * data); +void desktop_message_unregister(GtkWidget * window, + DesktopMessageCallback callback, void * data); + int desktop_message_send(char const * destination, uint32_t value1, uint32_t value2, uint32_t value3); diff --git a/src/message.c b/src/message.c index 07b793b..49b6320 100644 --- a/src/message.c +++ b/src/message.c @@ -17,6 +17,10 @@ +#include +#ifdef DEBUG +# include +#endif #include #include #include @@ -28,16 +32,22 @@ /* Message */ +#if !GTK_CHECK_VERSION(3, 0, 0) /* private */ /* types */ -#if !GTK_CHECK_VERSION(3, 0, 0) typedef struct _MessageCallback { + GtkWidget * window; GtkWidget * widget; - Window window; + Window xwindow; DesktopMessageCallback callback; void * data; } MessageCallback; + + +/* variables */ +static MessageCallback ** _callbacks = NULL; +static size_t _callbacks_cnt = 0; #endif @@ -56,26 +66,34 @@ int desktop_message_register(GtkWidget * window, char const * destination, DesktopMessageCallback callback, void * data) { #if !GTK_CHECK_VERSION(3, 0, 0) + MessageCallback ** p; MessageCallback * mc; - GdkWindow * w; + GdkWindow * gwindow; + GdkAtom atom; - /* XXX memory leak */ +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p, \"%s\", %p, %p)\n", __func__, window, + destination, callback, data); +# endif + if((p = realloc(_callbacks, sizeof(*p) * (_callbacks_cnt + 1))) == NULL) + return -1; + _callbacks = p; if((mc = object_new(sizeof(*mc))) == NULL) return -1; - if(window == NULL) + _callbacks[_callbacks_cnt++] = mc; + if((mc->window = window) == NULL) { - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - mc->widget = window; - gtk_widget_realize(window); + mc->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_realize(mc->widget); } else - mc->widget = NULL; - w = gtk_widget_get_window(window); - mc->window = GDK_WINDOW_XWINDOW(w); + mc->widget = window; + gwindow = gtk_widget_get_window(mc->widget); + mc->xwindow = GDK_WINDOW_XWINDOW(gwindow); mc->callback = callback; mc->data = data; - gdk_add_client_message_filter(gdk_atom_intern(destination, FALSE), - _desktop_message_on_callback, mc); + atom = gdk_atom_intern(destination, FALSE); + gdk_add_client_message_filter(atom, _desktop_message_on_callback, mc); #endif return 0; } @@ -86,14 +104,16 @@ int desktop_message_send(char const * destination, uint32_t value1, uint32_t value2, uint32_t value3) { #if !GTK_CHECK_VERSION(3, 0, 0) + GdkAtom atom; GdkEvent event; GdkEventClient * client = &event.client; + atom = gdk_atom_intern(destination, FALSE); memset(&event, 0, sizeof(event)); client->type = GDK_CLIENT_EVENT; client->window = NULL; client->send_event = TRUE; - client->message_type = gdk_atom_intern(destination, FALSE); + client->message_type = atom; client->data_format = 32; client->data.l[0] = value1; client->data.l[1] = value2; @@ -104,6 +124,43 @@ int desktop_message_send(char const * destination, uint32_t value1, } +/* desktop_message_unregister */ +void desktop_message_unregister(GtkWidget * window, + DesktopMessageCallback callback, void * data) +{ +#if !GTK_CHECK_VERSION(3, 0, 0) + size_t i; + MessageCallback ** p; + MessageCallback * mc; + GdkWindow * w; + +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%p, %p)\n", __func__, callback, data); +# endif + for(i = 0; i < _callbacks_cnt; i++) + { + mc = _callbacks[i]; + if(mc->window == window + && mc->callback == callback + && mc->data == data) + break; + } + if(i == _callbacks_cnt) + return; + w = gtk_widget_get_window(mc->widget); + gdk_window_remove_filter(w, _desktop_message_on_callback, mc); + if(mc->window == NULL) + gtk_widget_destroy(mc->widget); + object_delete(mc); + p = &_callbacks[i]; + memmove(p, p + 1, sizeof(*p) * (_callbacks_cnt - i - 1)); + if((p = realloc(_callbacks, sizeof(*p) * (--_callbacks_cnt))) != NULL + || _callbacks_cnt == 0) + _callbacks = p; +#endif +} + + /* private */ /* callbacks */ #if !GTK_CHECK_VERSION(3, 0, 0) @@ -122,19 +179,21 @@ static GdkFilterReturn _desktop_message_on_callback(GdkXEvent * xevent, return GDK_FILTER_CONTINUE; xcme = &xev->xclient; # ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%lu %lu) %lu\n", __func__, xcme->serial, - xcme->window, mc->window); + fprintf(stderr, "DEBUG: %s(%lu %lu %p) %lu\n", __func__, xcme->serial, + xcme->window, mc, mc->xwindow); # endif - if(mc->window != xcme->window) + if(mc->xwindow != xcme->window) return GDK_FILTER_CONTINUE; +# ifdef DEBUG + fprintf(stderr, "DEBUG: %s() %p(%p)\n", __func__, mc->callback, + mc->data); +# endif value1 = xcme->data.l[0]; value2 = xcme->data.l[1]; value3 = xcme->data.l[2]; if(mc->callback(mc->data, value1, value2, value3) == 0) return GDK_FILTER_CONTINUE; - if(mc->widget != NULL) - gtk_widget_destroy(mc->widget); - object_delete(mc); + desktop_message_unregister(mc->window, mc->callback, mc->data); return GDK_FILTER_REMOVE; } #endif