diff options
Diffstat (limited to 'libtopmenu-server')
-rw-r--r-- | libtopmenu-server/Makefile.am | 8 | ||||
-rw-r--r-- | libtopmenu-server/topmenu-server.c | 20 | ||||
-rw-r--r-- | libtopmenu-server/topmenu-widget.c | 92 | ||||
-rw-r--r-- | libtopmenu-server/topmenu-widget.h | 7 |
4 files changed, 98 insertions, 29 deletions
diff --git a/libtopmenu-server/Makefile.am b/libtopmenu-server/Makefile.am index b910248..7830b11 100644 --- a/libtopmenu-server/Makefile.am +++ b/libtopmenu-server/Makefile.am @@ -2,15 +2,15 @@ if GTK3 lib_LTLIBRARIES = libtopmenu-server-gtk3.la libtopmenu_server_gtk3_la_SOURCES = topmenu-server.c topmenu-server.h topmenu-widget.c topmenu-widget.h -libtopmenu_server_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK3_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-server\" -libtopmenu_server_gtk3_la_LIBADD = $(GTK_LIBS) $(WNCK3_LIBS) +libtopmenu_server_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK3_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-server\" +libtopmenu_server_gtk3_la_LIBADD = $(GTK_LIBS) $(WNCK3_LIBS) ../libtopmenu-common/libtopmenu-common-gtk3.la else lib_LTLIBRARIES = libtopmenu-server-gtk2.la libtopmenu_server_gtk2_la_SOURCES = topmenu-server.c topmenu-server.h topmenu-widget.c topmenu-widget.h -libtopmenu_server_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK1_CFLAGS) $(MATEWNCK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-server\" -libtopmenu_server_gtk2_la_LIBADD = $(GTK_LIBS) $(WNCK1_LIBS) $(MATEWNCK_LIBS) +libtopmenu_server_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK1_CFLAGS) $(MATEWNCK_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-server\" +libtopmenu_server_gtk2_la_LIBADD = $(GTK_LIBS) $(WNCK1_LIBS) $(MATEWNCK_LIBS) ../libtopmenu-common/libtopmenu-common-gtk2.la endif diff --git a/libtopmenu-server/topmenu-server.c b/libtopmenu-server/topmenu-server.c index 1e94398..7e5f3f7 100644 --- a/libtopmenu-server/topmenu-server.c +++ b/libtopmenu-server/topmenu-server.c @@ -17,21 +17,29 @@ * along with TopMenu. If not, see <http://www.gnu.org/licenses/>. */ +#include <math.h> +#include <string.h> +#include <X11/Xatom.h> #include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <cairo-xlib.h> #include "topmenu-server.h" #include "../global.h" static GdkAtom selection_atom = GDK_NONE; +static GdkAtom background_atom = GDK_NONE; static GtkClipboard *selection_clipboard = NULL; static GList *server_widgets = NULL; +static G_DEFINE_QUARK(topmenu-server-stub, server_stub) + static void handle_selection_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data); static void init_selection_monitor() { - if (!selection_clipboard || selection_atom == GDK_NONE) { + if (!selection_clipboard || selection_atom == GDK_NONE || background_atom == GDK_NONE) { selection_atom = gdk_atom_intern_static_string(ATOM_TOPMENU_SERVER_SELECTION); selection_clipboard = gtk_clipboard_get(selection_atom); // Used to monitor the current owner of the server selection @@ -45,7 +53,7 @@ static GdkWindow *get_front_server_stub() { if (server_widgets) { GtkWidget *widget = server_widgets->data; - gpointer data = g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB); + gpointer data = g_object_get_qdata(G_OBJECT(widget), server_stub_quark()); g_return_val_if_fail(data, NULL); return GDK_WINDOW(data); } else { @@ -78,14 +86,14 @@ void topmenu_server_register_server_widget(GtkWidget *widget) init_selection_monitor(); - g_return_if_fail(g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB) == NULL); + g_return_if_fail(g_object_get_qdata(G_OBJECT(widget), server_stub_quark()) == NULL); GdkWindowAttr stub_attr = { 0 }; stub_attr.wclass = GDK_INPUT_ONLY; stub_attr.override_redirect = TRUE; GdkWindow *stub = gdk_window_new(window, &stub_attr, GDK_WA_NOREDIR); - g_object_set_data_full(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB, stub, + g_object_set_qdata_full(G_OBJECT(widget), server_stub_quark(), stub, (GDestroyNotify) &gdk_window_destroy); server_widgets = g_list_prepend(server_widgets, widget); @@ -94,9 +102,9 @@ void topmenu_server_register_server_widget(GtkWidget *widget) void topmenu_server_unregister_server_widget(GtkWidget *widget) { - g_return_if_fail(g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB) != NULL); + g_return_if_fail(g_object_get_qdata(G_OBJECT(widget), server_stub_quark()) != NULL); server_widgets = g_list_remove_all(server_widgets, widget); - gpointer data = g_object_steal_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB); + gpointer data = g_object_steal_qdata(G_OBJECT(widget), server_stub_quark()); GdkWindow *stub = GDK_WINDOW(data); gdk_window_destroy(stub); } diff --git a/libtopmenu-server/topmenu-widget.c b/libtopmenu-server/topmenu-widget.c index 9d80ff2..5d13a6a 100644 --- a/libtopmenu-server/topmenu-widget.c +++ b/libtopmenu-server/topmenu-widget.c @@ -42,10 +42,17 @@ #include <libmatewnck/libmatewnck.h> #endif +enum _TopMenuWidgetAtoms +{ + ATOM_WINDOW, + ATOM_BACKGROUND_CHANGE, + ATOM_TRANSIENT_FOR, + N_ATOMS +}; + struct _TopMenuWidgetPrivate { - Atom atom_window; - Atom atom_transient_for; + Atom atoms[N_ATOMS]; GQueue followed_windows; #ifdef HAVE_WNCK WnckScreen *wnck_screen; @@ -176,7 +183,8 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W for (i = g_list_last(windows); i; i = g_list_previous(i)) { if (i->data != w && wnck_window_get_application(i->data) == app) { Window candidate = wnck_window_get_xid(i->data); - Window menu_window = read_window_property(dpy, candidate, self->priv->atom_window); + Window menu_window = read_window_property(dpy, candidate, + self->priv->atoms[ATOM_WINDOW]); if (menu_window) { return candidate; } @@ -198,7 +206,8 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W for (i = g_list_last(windows); i; i = g_list_previous(i)) { if (i->data != w && matewnck_window_get_application(i->data) == app) { Window candidate = matewnck_window_get_xid(i->data); - Window menu_window = read_window_property(dpy, candidate, self->priv->atom_window); + Window menu_window = read_window_property(dpy, candidate, + self->priv->atoms[ATOM_WINDOW]); if (menu_window) { return candidate; } @@ -208,6 +217,37 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W return None; } +static Window topmenu_widget_get_current_topmenu_window(TopMenuWidget *self) +{ + g_return_val_if_fail(self->socket, None); + GdkWindow *cur = gtk_socket_get_plug_window(self->socket); + if (cur) { + return GDK_WINDOW_XID(cur); + } else { + return None; + } +} + +static void topmenu_widget_send_background(TopMenuWidget *self, Window window) +{ + Display *dpy = topmenu_widget_get_display(self); + g_return_if_fail(dpy); + + XEvent e; + XClientMessageEvent *msg = &e.xclient; + msg->type = ClientMessage; + msg->display = dpy; + msg->window = window; + msg->message_type = self->priv->atoms[ATOM_BACKGROUND_CHANGE]; + topmenu_background_fill_client_message(self->background, msg); + + g_debug("sending current background to window 0x%lx", window); + + if (XSendEvent(dpy, window, False, 0, &e) == 0) { + g_warning("sending background message failed"); + } +} + static void topmenu_widget_embed_topmenu_window(TopMenuWidget *self, Window window) { g_return_if_fail(self->socket); @@ -244,6 +284,7 @@ static void topmenu_widget_embed_topmenu_window(TopMenuWidget *self, Window wind if (window) { g_debug("Embedding window 0x%lx", window); + topmenu_widget_send_background(self, window); gtk_socket_add_id(self->socket, window); } } @@ -254,7 +295,8 @@ static gboolean topmenu_widget_try_window(TopMenuWidget *self, Window window) g_return_val_if_fail(dpy, FALSE); g_return_val_if_fail(window, FALSE); - Window menu_window = read_window_property(dpy, window, self->priv->atom_window); + Window menu_window = read_window_property(dpy, window, + self->priv->atoms[ATOM_WINDOW]); if (menu_window) { topmenu_widget_embed_topmenu_window(self, menu_window); return TRUE; @@ -335,11 +377,16 @@ static void topmenu_widget_set_followed_window(TopMenuWidget *self, Window windo if (window) { // Initialize atoms now - if (self->priv->atom_window == None) { - self->priv->atom_window = XInternAtom(dpy, ATOM_TOPMENU_WINDOW, False); - } - if (self->priv->atom_transient_for) { - self->priv->atom_transient_for = XInternAtom(dpy, "WM_TRANSIENT_FOR", False); + if (self->priv->atoms[0] == None) { + static const char *atom_names[] = { + ATOM_TOPMENU_WINDOW, + ATOM_TOPMENU_BACKGROUND_CHANGE, + "WM_TRANSIENT_FOR", + NULL + }; + if (!XInternAtoms(dpy, (char**) atom_names, N_ATOMS, False, self->priv->atoms)) { + g_warning("Could not intern all atoms"); + } } // Start by checking the active window @@ -360,9 +407,7 @@ static void topmenu_widget_set_followed_window(TopMenuWidget *self, Window windo static void handle_socket_realize(GtkSocket *socket, TopMenuWidget *self) { - // Workaround a "bug workaround" where GtkSocket will not select ButtonPress - // events - g_warn_if_fail(gtk_widget_get_realized(GTK_WIDGET(socket))); + // GtkSocket does not select ButtonPress events gtk_widget_add_events(GTK_WIDGET(socket), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); } @@ -374,6 +419,16 @@ static gboolean handle_socket_plug_removed(GtkSocket *socket, TopMenuWidget *sel return TRUE; // Do not destroy the socket } +static void handle_background_changed(TopMenuBackground *background, TopMenuWidget *self) +{ + g_debug("background has changed"); + topmenu_background_apply(background, GTK_WIDGET(self->socket)); + Window cur = topmenu_widget_get_current_topmenu_window(self); + if (cur != None) { + topmenu_widget_send_background(self, cur); + } +} + #ifdef HAVE_WNCK static void handle_active_wnck_window_changed(WnckScreen *screen, WnckWindow *prev_window, TopMenuWidget *self) { @@ -410,8 +465,8 @@ static GdkFilterReturn handle_gdk_event(GdkXEvent *xevent, GdkEvent *event, gpoi XEvent *e = (XEvent*) xevent; if (e->type == PropertyNotify && - (e->xproperty.atom == self->priv->atom_transient_for || - e->xproperty.atom == self->priv->atom_window)) { + (e->xproperty.atom == self->priv->atoms[ATOM_TRANSIENT_FOR] || + e->xproperty.atom == self->priv->atoms[ATOM_WINDOW])) { // One of the properties we are interested in changed. // See if it's one of the windows we're following. if (g_queue_find(&self->priv->followed_windows, @@ -480,7 +535,7 @@ static void topmenu_widget_size_request(GtkWidget *widget, GtkRequisition *requi if (self->socket) { gtk_widget_size_request(GTK_WIDGET(self->socket), requisition); } -} +} #endif static void topmenu_widget_dispose(GObject *obj) @@ -534,8 +589,9 @@ static void topmenu_widget_init(TopMenuWidget *self) G_CALLBACK(handle_socket_realize), self); g_signal_connect(self->socket, "plug-removed", G_CALLBACK(handle_socket_plug_removed), self); - self->priv->atom_window = None; - self->priv->atom_transient_for = None; + self->background = topmenu_background_new(); + g_signal_connect(self->background, "changed", + G_CALLBACK(handle_background_changed), self); g_queue_init(&self->priv->followed_windows); #ifdef HAVE_WNCK self->priv->wnck_screen = wnck_screen_get_default(); diff --git a/libtopmenu-server/topmenu-widget.h b/libtopmenu-server/topmenu-widget.h index 7d9ee05..73663ad 100644 --- a/libtopmenu-server/topmenu-widget.h +++ b/libtopmenu-server/topmenu-widget.h @@ -26,6 +26,10 @@ #include <gtk/gtkx.h> #endif +#include <gdk/gdkx.h> + +#include <topmenu-background.h> + G_BEGIN_DECLS #define TOPMENU_TYPE_WIDGET topmenu_widget_get_type() @@ -46,6 +50,7 @@ struct _TopMenuWidget TopMenuWidgetPrivate *priv; GtkSocket *socket; + TopMenuBackground *background; }; struct _TopMenuWidgetClass @@ -53,7 +58,7 @@ struct _TopMenuWidgetClass GtkBinClass parent_class; }; -GType topmenu_widget_get_type(void); +GType topmenu_widget_get_type(void) G_GNUC_CONST; GtkWidget *topmenu_widget_new(void); |