diff options
author | Javier <dev.git@javispedro.com> | 2015-07-26 01:02:12 +0200 |
---|---|---|
committer | Javier <dev.git@javispedro.com> | 2015-07-26 01:02:12 +0200 |
commit | baef440d424640a6fc99edd8a12a6abcea80c5fc (patch) | |
tree | 7fb717c04564618d3c9c7b0db1c46ddde138bf5a | |
parent | f690cd97506f45e02bb6383fde2a7c8f06820408 (diff) | |
download | topmenu-gtk-baef440d424640a6fc99edd8a12a6abcea80c5fc.tar.gz topmenu-gtk-baef440d424640a6fc99edd8a12a6abcea80c5fc.zip |
initial gtk2 "transparent" background attempt
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | global.h | 9 | ||||
-rw-r--r-- | libtopmenu-client/Makefile.am | 8 | ||||
-rw-r--r-- | libtopmenu-client/topmenu-appmenubar.h | 2 | ||||
-rw-r--r-- | libtopmenu-client/topmenu-client.c | 48 | ||||
-rw-r--r-- | libtopmenu-client/topmenu-client.h | 1 | ||||
-rw-r--r-- | libtopmenu-client/topmenu-monitor.c | 3 | ||||
-rw-r--r-- | libtopmenu-client/topmenu-monitor.h | 4 | ||||
-rw-r--r-- | libtopmenu-common/Makefile.am | 17 | ||||
-rw-r--r-- | libtopmenu-common/topmenu-background.c | 365 | ||||
-rw-r--r-- | libtopmenu-common/topmenu-background.h | 74 | ||||
-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 | ||||
-rw-r--r-- | mate-applet/Makefile.am | 2 | ||||
-rw-r--r-- | mate-applet/topmenu-mate-panel-applet.c | 41 | ||||
-rw-r--r-- | mate-applet/topmenu-mate-panel-applet.h | 4 | ||||
-rw-r--r-- | module/data.c | 6 | ||||
-rw-r--r-- | module/main.c | 15 | ||||
-rw-r--r-- | xfce-applet/topmenu-xfce-panel-applet.h | 2 |
22 files changed, 670 insertions, 65 deletions
diff --git a/Makefile.am b/Makefile.am index 11946ff..e1855b5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = libtopmenu-server libtopmenu-client module test mate-applet xfce-applet icons +SUBDIRS = libtopmenu-common libtopmenu-server libtopmenu-client module test mate-applet xfce-applet icons noinst_HEADERS = global.h diff --git a/configure.ac b/configure.ac index 8c67f7a..03385f6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT(libtopmenu-gtk, 1.0, javier@javispedro.com) +AC_INIT(TopMenu Gtk, 1.0, dev.bugs@javispedro.com, topmenu-gtk, [https://git.javispedro.com/cgit/topmenu-gtk.git/about/]) AC_CONFIG_SRCDIR([libtopmenu-server/topmenu-server.h]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) @@ -47,7 +47,7 @@ AM_PROG_CC_C_O AC_PROG_LIBTOOL # Checks for libraries. -PKG_CHECK_MODULES([GTK], [gtk+-x11-$with_gtk.0]) +PKG_CHECK_MODULES([GTK], [gtk+-x11-$with_gtk.0 x11]) AS_IF([test "x$with_gtk" = x3], [AS_IF([test "x$with_wnck" = xwnck3 -o "x$with_wnck" = xcheck], @@ -110,6 +110,7 @@ AM_CONDITIONAL([WANT_XFCE_APPLET], [test x$enable_xfce_applet = xyes]) # Output files AC_CONFIG_FILES([ Makefile + libtopmenu-common/Makefile libtopmenu-client/Makefile libtopmenu-server/Makefile module/Makefile @@ -11,12 +11,7 @@ /** The X11 selection that is used to indicate the current server widget. */ #define ATOM_TOPMENU_SERVER_SELECTION "_TOPMENU_SERVER" -/* Gobject data keys */ -/** For a GtkWindow, stores its associated TopMenu GtkPlug */ -#define OBJECT_DATA_KEY_PLUG "topmenu-plug" - -/** For a server widget, stores the associated stub window. - This is the window that might own ATOM_TOPMENU_SERVER_SELECTION. */ -#define OBJECT_DATA_KEY_SERVER_STUB "topmenu-server-stub" +/** Event sent from server widget to current client, to indicate a change of background */ +#define ATOM_TOPMENU_BACKGROUND_CHANGE "_TOPMENU_BACKGROUND_CHANGE" #endif diff --git a/libtopmenu-client/Makefile.am b/libtopmenu-client/Makefile.am index f4f8b6f..2f2fc31 100644 --- a/libtopmenu-client/Makefile.am +++ b/libtopmenu-client/Makefile.am @@ -4,8 +4,8 @@ lib_LTLIBRARIES = libtopmenu-client-gtk3.la libtopmenu_client_gtk3_la_SOURCES = topmenu-client.c topmenu-client.h \ topmenu-monitor.c topmenu-monitor.h \ topmenu-appmenubar.c topmenu-appmenubar.h -libtopmenu_client_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-client\" -libtopmenu_client_gtk3_la_LIBADD = $(GTK_LIBS) +libtopmenu_client_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-client\" +libtopmenu_client_gtk3_la_LIBADD = $(GTK_LIBS) ../libtopmenu-common/libtopmenu-common-gtk3.la else @@ -13,8 +13,8 @@ lib_LTLIBRARIES = libtopmenu-client-gtk2.la libtopmenu_client_gtk2_la_SOURCES = topmenu-client.c topmenu-client.h \ topmenu-monitor.c topmenu-monitor.h \ topmenu-appmenubar.c topmenu-appmenubar.h -libtopmenu_client_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-client\" -libtopmenu_client_gtk2_la_LIBADD = $(GTK_LIBS) +libtopmenu_client_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-client\" +libtopmenu_client_gtk2_la_LIBADD = $(GTK_LIBS) ../libtopmenu-common/libtopmenu-common-gtk2.la endif diff --git a/libtopmenu-client/topmenu-appmenubar.h b/libtopmenu-client/topmenu-appmenubar.h index 012d82f..575ac6e 100644 --- a/libtopmenu-client/topmenu-appmenubar.h +++ b/libtopmenu-client/topmenu-appmenubar.h @@ -45,7 +45,7 @@ struct _TopMenuAppMenuBarClass GtkMenuBarClass parent_class; }; -GType topmenu_app_menu_bar_get_type(void); +GType topmenu_app_menu_bar_get_type(void) G_GNUC_CONST; TopMenuAppMenuBar *topmenu_app_menu_bar_new(void); diff --git a/libtopmenu-client/topmenu-client.c b/libtopmenu-client/topmenu-client.c index e62104e..ae9eac3 100644 --- a/libtopmenu-client/topmenu-client.c +++ b/libtopmenu-client/topmenu-client.c @@ -28,6 +28,10 @@ #include "topmenu-client.h" +static G_DEFINE_QUARK(topmenu-plug, plug) +static G_DEFINE_QUARK(topmenu-background, background) +static Atom atom_change_background = None; + static gboolean handle_plug_delete(GtkPlug *plug, GdkEvent *event, GdkWindow *window) { return TRUE; // Prevent deletion of plug window @@ -85,14 +89,39 @@ static gboolean handle_widget_button_event(GtkWidget *widget, GdkEvent *event, G return FALSE; } +static GdkFilterReturn handle_plug_window_event(GdkXEvent *xevent, GdkEvent *event, gpointer data) +{ + GdkWindow *window = GDK_WINDOW(data); + if (((XEvent*)xevent)->type == ClientMessage) { + XClientMessageEvent *msg = (XClientMessageEvent*) xevent; + if (msg->message_type == atom_change_background) { + g_debug("received change background message"); + TopMenuBackground *bg = g_object_get_qdata(G_OBJECT(window), background_quark()); + g_return_val_if_fail(bg, GDK_FILTER_REMOVE); + + topmenu_background_set_from_client_message(bg, msg); + + return GDK_FILTER_REMOVE; + } + } + + return GDK_FILTER_CONTINUE; +} + void topmenu_client_connect_window_widget(GdkWindow *window, GtkWidget *widget) { Display *display = GDK_WINDOW_XDISPLAY(window); - if (g_object_get_data(G_OBJECT(window), OBJECT_DATA_KEY_PLUG)) { + // Disconnect any pre-existing widget + if (g_object_get_qdata(G_OBJECT(window), plug_quark())) { topmenu_client_disconnect_window(window); } + // Initialize atoms now + if (atom_change_background == None) { + atom_change_background = XInternAtom(display, ATOM_TOPMENU_BACKGROUND_CHANGE, False); + } + Window xwin = GDK_WINDOW_XID(window); GtkPlug *plug = GTK_PLUG(gtk_plug_new(0)); gtk_container_add(GTK_CONTAINER(plug), widget); @@ -102,6 +131,9 @@ void topmenu_client_connect_window_widget(GdkWindow *window, GtkWidget *widget) G_CALLBACK(handle_widget_button_event), plug, 0); g_signal_connect_object(widget, "button-release-event", G_CALLBACK(handle_widget_button_event), plug, 0); + gtk_widget_realize(GTK_WIDGET(plug)); + gdk_window_add_filter(gtk_widget_get_window(GTK_WIDGET(plug)), + handle_plug_window_event, window); gtk_widget_show(GTK_WIDGET(plug)); Window plug_xwin = gtk_plug_get_id(plug); @@ -112,17 +144,27 @@ void topmenu_client_connect_window_widget(GdkWindow *window, GtkWidget *widget) XA_WINDOW, 32, PropModeReplace, (unsigned char*)&plug_xwin, 1); - g_object_set_data_full(G_OBJECT(window), OBJECT_DATA_KEY_PLUG, plug, + g_object_set_qdata_full(G_OBJECT(window), plug_quark(), plug, (GDestroyNotify) >k_widget_destroy); + + // Connect the background + TopMenuBackground *bg = topmenu_background_new(); + topmenu_background_connect(bg, widget); + + // Destroy the background when the window is destroyed + g_object_set_qdata_full(G_OBJECT(window), background_quark(), + bg, g_object_unref); } void topmenu_client_disconnect_window(GdkWindow *window) { Display *display = GDK_WINDOW_XDISPLAY(window); - gpointer window_data = g_object_steal_data(G_OBJECT(window), OBJECT_DATA_KEY_PLUG); + gpointer window_data = g_object_steal_qdata(G_OBJECT(window), plug_quark()); g_return_if_fail(window_data); + g_object_set_qdata(G_OBJECT(window), background_quark(), NULL); + Window xwin = GDK_WINDOW_XID(window); GtkPlug *plug = GTK_PLUG(window_data); diff --git a/libtopmenu-client/topmenu-client.h b/libtopmenu-client/topmenu-client.h index d9af99c..0fad7d0 100644 --- a/libtopmenu-client/topmenu-client.h +++ b/libtopmenu-client/topmenu-client.h @@ -21,6 +21,7 @@ #define _TOPMENU_CLIENT_H_ #include <gtk/gtk.h> +#include <topmenu-background.h> G_BEGIN_DECLS diff --git a/libtopmenu-client/topmenu-monitor.c b/libtopmenu-client/topmenu-monitor.c index c67e3cd..b03502e 100644 --- a/libtopmenu-client/topmenu-monitor.c +++ b/libtopmenu-client/topmenu-monitor.c @@ -53,10 +53,10 @@ static void handle_clipboard_owner_change(GtkClipboard *clipboard, GdkEvent *eve static GdkFilterReturn handle_cur_server_event(GdkXEvent *xevent, GdkEvent *event, gpointer data) { + TopMenuMonitor *self = TOPMENU_MONITOR(data); XEvent *e = (XEvent*)xevent; if (e->type == DestroyNotify) { g_debug("Current server has been destroyed"); - TopMenuMonitor *self = TOPMENU_MONITOR(data); if (self->priv->cur_server && GDK_WINDOW_XID(self->priv->cur_server) == e->xdestroywindow.window) { topmenu_monitor_update(self); @@ -155,7 +155,6 @@ static void topmenu_monitor_class_init(TopMenuMonitorClass *klass) static void topmenu_monitor_init(TopMenuMonitor *self) { self->priv = TOPMENU_MONITOR_GET_PRIVATE(self); - self->available = FALSE; self->priv->atom_selection = gdk_atom_intern_static_string(ATOM_TOPMENU_SERVER_SELECTION); self->priv->selection = gtk_clipboard_get(self->priv->atom_selection); diff --git a/libtopmenu-client/topmenu-monitor.h b/libtopmenu-client/topmenu-monitor.h index 1128d6d..12ff511 100644 --- a/libtopmenu-client/topmenu-monitor.h +++ b/libtopmenu-client/topmenu-monitor.h @@ -47,11 +47,11 @@ struct _TopMenuMonitorClass GObjectClass parent_class; }; -GType topmenu_monitor_get_type(void); +GType topmenu_monitor_get_type(void) G_GNUC_CONST; TopMenuMonitor * topmenu_monitor_get_instance(void); -gboolean topmenu_monitor_is_topmenu_available(TopMenuMonitor * self); +gboolean topmenu_monitor_is_topmenu_available(TopMenuMonitor *self); G_END_DECLS diff --git a/libtopmenu-common/Makefile.am b/libtopmenu-common/Makefile.am new file mode 100644 index 0000000..7316058 --- /dev/null +++ b/libtopmenu-common/Makefile.am @@ -0,0 +1,17 @@ +if GTK3 + +lib_LTLIBRARIES = libtopmenu-common-gtk3.la +libtopmenu_common_gtk3_la_SOURCES = topmenu-background.c topmenu-background.h +libtopmenu_common_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-common\" +libtopmenu_common_gtk3_la_LIBADD = $(GTK_LIBS) + +else + +lib_LTLIBRARIES = libtopmenu-common-gtk2.la +libtopmenu_common_gtk2_la_SOURCES = topmenu-background.c topmenu-background.h +libtopmenu_common_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-common\" +libtopmenu_common_gtk2_la_LIBADD = $(GTK_LIBS) + +endif + +include_HEADERS = topmenu-background.h diff --git a/libtopmenu-common/topmenu-background.c b/libtopmenu-common/topmenu-background.c new file mode 100644 index 0000000..99d36e9 --- /dev/null +++ b/libtopmenu-common/topmenu-background.c @@ -0,0 +1,365 @@ +/* + * Copyright 2014-2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of TopMenu. + * + * TopMenu is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TopMenu 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with TopMenu. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <math.h> +#include <cairo-xlib.h> +#include "topmenu-background.h" + +struct _TopMenuBackgroundPrivate +{ + double red, green, blue, alpha; + Pixmap pixmap; + gint width, height, depth; + gboolean has_color; +}; + +enum { + SIGNAL_CHANGED, + N_SIGNALS +}; + +G_DEFINE_TYPE(TopMenuBackground, topmenu_background, G_TYPE_OBJECT) + +#define TOPMENU_BACKGROUND_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), TOPMENU_TYPE_BACKGROUND, TopMenuBackgroundPrivate)) + +static guint signals[N_SIGNALS]; + +static inline GdkDisplay * topmenu_background_get_display(TopMenuBackground *self) +{ + return gdk_display_get_default(); +} + +static gboolean topmenu_background_reset(TopMenuBackground *self) +{ + gboolean had_contents = self->priv->has_color || self->priv->pixmap; + self->priv->has_color = FALSE; + if (self->priv->pixmap) { + GdkDisplay *display = topmenu_background_get_display(self); + XFreePixmap(GDK_DISPLAY_XDISPLAY(display), self->priv->pixmap); + self->priv->pixmap = None; + } + return had_contents; +} + +static void topmenu_background_finalize(GObject *obj) +{ + TopMenuBackground *self = TOPMENU_BACKGROUND(obj); + topmenu_background_clear(self); + G_OBJECT_CLASS(topmenu_background_parent_class)->finalize(obj); +} + +static void topmenu_background_class_init(TopMenuBackgroundClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + obj_class->finalize = topmenu_background_finalize; + + signals[SIGNAL_CHANGED] = g_signal_newv("changed", + G_TYPE_FROM_CLASS(obj_class), + G_SIGNAL_NO_RECURSE, + NULL, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0, NULL); + + g_type_class_add_private(klass, sizeof(TopMenuBackgroundPrivate)); +} + +static void topmenu_background_init(TopMenuBackground *self) +{ + self->priv = TOPMENU_BACKGROUND_GET_PRIVATE(self); +} + +TopMenuBackground *topmenu_background_new(void) +{ + return TOPMENU_BACKGROUND(g_object_new(TOPMENU_TYPE_BACKGROUND, NULL)); +} + +void topmenu_background_set_from_color(TopMenuBackground *self, double red, double green, double blue, double alpha) +{ + if (self->priv->has_color + && self->priv->red == red && self->priv->green == green + && self->priv->blue == blue && self->priv->alpha == alpha) { + return; // Nothing to do + } + + topmenu_background_reset(self); + + self->priv->has_color = TRUE; + self->priv->red = red; + self->priv->green = green; + self->priv->blue = blue; + self->priv->alpha = alpha; + g_signal_emit(self, signals[SIGNAL_CHANGED], 0); +} + +void topmenu_background_set_from_drawable(TopMenuBackground *self, Drawable drawable) +{ + gboolean had_contents = topmenu_background_reset(self); + + g_return_if_fail(drawable); + + GdkDisplay *display = topmenu_background_get_display(self); + GdkScreen *screen = gdk_display_get_default_screen(display); + Display *xdpy = GDK_DISPLAY_XDISPLAY(display); + int err; + + gdk_error_trap_push(); + + Window root; + int x, y; + unsigned int width, height, border_width, depth; + if (!XGetGeometry(xdpy, drawable, &root, + &x, &y, &width, &height, &border_width, &depth)) { + g_debug("could not get geometry of drawable: 0x%lx", drawable); + goto err_out; + } + + self->priv->width = width; + self->priv->height = height; + self->priv->depth = depth; + + cairo_surface_t *orig_surface = cairo_xlib_surface_create(xdpy, drawable, + GDK_VISUAL_XVISUAL(gdk_screen_get_system_visual(screen)), + width, height); + if (!orig_surface) { + g_debug("could not create orig surface"); + goto err_out; + } + + self->priv->pixmap = XCreatePixmap(xdpy, drawable, width, height, depth); + cairo_surface_t *new_surface = cairo_xlib_surface_create(xdpy, self->priv->pixmap, + GDK_VISUAL_XVISUAL(gdk_screen_get_system_visual(screen)), + width, height); + if (!new_surface) { + g_debug("could not create new surface"); + goto err_out; + } + + cairo_t *cr = cairo_create(new_surface); + cairo_set_source_surface(cr, orig_surface, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + + cairo_surface_destroy(new_surface); + cairo_surface_destroy(orig_surface); + +err_out: + err = gdk_error_trap_pop(); + if (err) g_debug("X error: %d", err); + + if (had_contents || self->priv->pixmap) { + g_signal_emit(self, signals[SIGNAL_CHANGED], 0); + } +} + +void topmenu_background_set_from_cairo_pattern(TopMenuBackground *self, cairo_pattern_t *pattern) +{ + if (!pattern) { + topmenu_background_clear(self); + return; + } + + gboolean had_contents = topmenu_background_reset(self); + + cairo_surface_t *surface; + double red, green, blue, alpha; + if (cairo_pattern_get_rgba(pattern, &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS) { + topmenu_background_set_from_color(self, red, green, blue, alpha); + } else if (cairo_pattern_get_surface(pattern, &surface) == CAIRO_STATUS_SUCCESS) { + cairo_surface_type_t type = cairo_surface_get_type(surface); + if (type == CAIRO_SURFACE_TYPE_XLIB) { + Drawable drawable = cairo_xlib_surface_get_drawable(surface); + topmenu_background_set_from_drawable(self, drawable); + return; + } else { + g_warning("no idea how to handle this cairo pattern type"); + } + } else { + g_warning("no idea how to handle this cairo surface type"); + } + + if (had_contents) { + g_signal_emit(self, signals[SIGNAL_CHANGED], 0); + } +} + +void topmenu_background_clear(TopMenuBackground *self) +{ + if (topmenu_background_reset(self)) { + g_signal_emit(self, signals[SIGNAL_CHANGED], 0); + } +} + +gboolean topmenu_background_get_color(TopMenuBackground *self, double *red, double *green, double *blue, double *alpha) +{ + if (self->priv->has_color) { + if (red) *red = self->priv->red; + if (green) *green = self->priv->green; + if (blue) *blue = self->priv->blue; + if (alpha) *alpha = self->priv->alpha; + return TRUE; + } else { + return FALSE; + } +} + +gboolean topmenu_background_get_pixmap(TopMenuBackground *self, Pixmap *pixmap) +{ + if (self->priv->pixmap) { + if (pixmap) *pixmap = self->priv->pixmap; + return TRUE; + } else { + return FALSE; + } +} + +cairo_pattern_t * topmenu_background_get_cairo_pattern(TopMenuBackground *self) +{ + if (self->priv->has_color) { + return cairo_pattern_create_rgba(self->priv->red, self->priv->green, + self->priv->blue, self->priv->alpha); + } else if (self->priv->pixmap) { + GdkDisplay *display = topmenu_background_get_display(self); + GdkScreen *screen = gdk_display_get_default_screen(display); + Display *xdpy = GDK_DISPLAY_XDISPLAY(display); + + cairo_surface_t * surface = cairo_xlib_surface_create(xdpy, self->priv->pixmap, + GDK_VISUAL_XVISUAL(gdk_screen_get_system_visual(screen)), + self->priv->width, self->priv->height); + + cairo_pattern_t * pattern = cairo_pattern_create_for_surface(surface); + cairo_surface_destroy(surface); + + return pattern; + } else { + return NULL; + } +} + +void topmenu_background_fill_client_message(TopMenuBackground *self, XClientMessageEvent *event) +{ + event->format = 32; + event->data.l[0] = self->priv->has_color ? 1 : 0; + if (self->priv->has_color) { + // Encode color as a 32-bit RGBA value + guint32 rgba = (lround(self->priv->red * 255.0) & 0xFF) << 24 + | (lround(self->priv->green * 255.0) & 0xFF) << 16 + | (lround(self->priv->blue * 255.0) & 0xFF) << 8 + | (lround(self->priv->alpha * 255.0) & 0xFF) << 0; + event->data.l[1] = rgba; + } else { + event->data.l[1] = 0; + } + event->data.l[2] = self->priv->pixmap; + event->data.l[3] = 0; + event->data.l[4] = 0; +} + +void topmenu_background_set_from_client_message(TopMenuBackground *self, XClientMessageEvent *event) +{ + g_return_if_fail(event->format == 32); + g_warn_if_fail(event->data.l[3] == 0); + if (event->data.l[0] & 1) { + const guint32 rgba = event->data.l[1]; + double red = ((rgba >> 24) & 0xFF) / 255.0, + green = ((rgba >> 16) & 0xFF) / 255.0, + blue = ((rgba >> 8) & 0xFF) / 255.0, + alpha = ((rgba >> 0) & 0xFF) / 255.0; + g_debug("received color %.2f,%.2f,%.2f,%.2f", red, green, blue, alpha); + topmenu_background_set_from_color(self, red, green, blue, alpha); + } else if (event->data.l[2] != None) { + g_debug("received pixmap 0x%lx", event->data.l[2]); + topmenu_background_set_from_drawable(self, event->data.l[2]); + } else { + g_debug("received nothing"); + topmenu_background_clear(self); + } +} + +#if GTK_MAJOR_VERSION == 2 +static GdkPixmap * get_pixmap(GdkDisplay *display, Pixmap pixmap) +{ + gdk_error_trap_push(); + GdkPixmap *gp = gdk_pixmap_lookup_for_display(display, pixmap); + if (!gp) { + gp = gdk_pixmap_foreign_new_for_display(display, pixmap); + } + gdk_error_trap_pop(); + return gp; +} +#endif + +void topmenu_background_apply(TopMenuBackground *self, GtkWidget *widget) +{ +#if GTK_MAJOR_VERSION == 3 + g_debug("background set not yet supported on Gtk+ 3"); +#elif GTK_MAJOR_VERSION == 2 + // Clear current background + GtkRcStyle *rc_style; + gtk_widget_set_style(widget, NULL); + rc_style = gtk_rc_style_new(); + gtk_widget_modify_style(widget, rc_style); + g_object_unref(rc_style); + + double red, green, blue, alpha; + Pixmap pixmap; + if (topmenu_background_get_color(self, &red, &green, &blue, &alpha)) { + if (alpha >= 1.0) { + // Opaque + GdkColor color = { 0, red * 65535U, green * 65535U, blue * 65535U }; + gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color); + } else { + // TODO Alpha color + g_warning("Alpha colors not yet supported (alpha=%f)", alpha); + } + } else if (topmenu_background_get_pixmap(self, &pixmap)) { + GdkDisplay *display = gtk_widget_get_display(widget); + GdkPixmap *gpixmap = get_pixmap(display, pixmap); + + if (gpixmap) { + if (!gdk_drawable_get_colormap(gpixmap)) { + gdk_drawable_set_colormap(GDK_DRAWABLE (gpixmap), + gtk_widget_get_colormap(widget)); + } + + GtkStyle *style = gtk_style_copy(gtk_widget_get_style(widget)); + g_clear_object(&style->bg_pixmap[GTK_STATE_NORMAL]); + style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref_sink(gpixmap); + gtk_widget_set_style(widget, style); + g_object_unref(style); + } + } + + gtk_widget_queue_draw(widget); +#endif +} + +void topmenu_background_connect(TopMenuBackground *self, GtkWidget *widget) +{ + g_signal_connect(self, "changed", + G_CALLBACK(topmenu_background_apply), widget); +} + +void topmenu_background_disconnect(TopMenuBackground *self, GtkWidget *widget) +{ + g_signal_handlers_disconnect_by_func(self, + G_CALLBACK(topmenu_background_apply), widget); +} diff --git a/libtopmenu-common/topmenu-background.h b/libtopmenu-common/topmenu-background.h new file mode 100644 index 0000000..aca72f8 --- /dev/null +++ b/libtopmenu-common/topmenu-background.h @@ -0,0 +1,74 @@ +/* + * Copyright 2014-2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of TopMenu. + * + * TopMenu is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TopMenu 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with TopMenu. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _TOPMENU_BACKGROUND_H_ +#define _TOPMENU_BACKGROUND_H_ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> + +G_BEGIN_DECLS + +#define TOPMENU_TYPE_BACKGROUND topmenu_background_get_type() +#define TOPMENU_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOPMENU_TYPE_BACKGROUND, TopMenuBackground)) +#define TOPMENU_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOPMENU_TYPE_BACKGROUND)) +#define TOPMENU_BACKGROUND_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), TOPMENU_TYPE_BACKGROUND, TopMenuBackgroundClass)) +#define TOPMENU_IS_BACKGROUND_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), TOPMENU_TYPE_BACKGROUND)) +#define TOPMENU_BACKGROUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOPMENU_TYPE_BACKGROUND, TopMenuBackgroundClass)) + +typedef struct _TopMenuBackground TopMenuBackground; +typedef struct _TopMenuBackgroundClass TopMenuBackgroundClass; +typedef struct _TopMenuBackgroundPrivate TopMenuBackgroundPrivate; + +struct _TopMenuBackground +{ + GObject parent_instance; + TopMenuBackgroundPrivate *priv; +}; + +struct _TopMenuBackgroundClass +{ + GObjectClass parent_class; +}; + +GType topmenu_background_get_type(void) G_GNUC_CONST; + +TopMenuBackground * topmenu_background_new(void); + +void topmenu_background_set_from_color(TopMenuBackground *self, double red, double green, double blue, double alpha); +void topmenu_background_set_from_drawable(TopMenuBackground *self, Drawable drawable); +void topmenu_background_set_from_cairo_pattern(TopMenuBackground *self, cairo_pattern_t *pattern); +void topmenu_background_clear(TopMenuBackground *self); + +gboolean topmenu_background_get_color(TopMenuBackground *self, double *red, double *green, double *blue, double *alpha); +gboolean topmenu_background_get_pixmap(TopMenuBackground *self, Pixmap *pixmap); + +cairo_pattern_t * topmenu_background_get_cairo_pattern(TopMenuBackground *self); + +void topmenu_background_fill_client_message(TopMenuBackground *self, XClientMessageEvent *event); +void topmenu_background_set_from_client_message(TopMenuBackground *self, XClientMessageEvent *event); + +void topmenu_background_apply(TopMenuBackground *self, GtkWidget *widget); + +void topmenu_background_connect(TopMenuBackground *self, GtkWidget *widget); +void topmenu_background_disconnect(TopMenuBackground *self, GtkWidget *widget); + +G_END_DECLS + +#endif 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); diff --git a/mate-applet/Makefile.am b/mate-applet/Makefile.am index 6877eff..b4945e1 100644 --- a/mate-applet/Makefile.am +++ b/mate-applet/Makefile.am @@ -3,7 +3,7 @@ if WANT_MATE_APPLET libexec_PROGRAMS = topmenu-mate-panel-applet topmenu_mate_panel_applet_SOURCES = main.c topmenu-mate-panel-applet.c topmenu-mate-panel-applet.h -topmenu_mate_panel_applet_CPPFLAGS = $(GTK_CFLAGS) $(MATEPANELAPPLET_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-mate-panel-applet\" +topmenu_mate_panel_applet_CPPFLAGS = $(GTK_CFLAGS) $(MATEPANELAPPLET_CFLAGS) -I../libtopmenu-server -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-mate-panel-applet\" topmenu_mate_panel_applet_LDADD = $(GTK_LIBS) $(MATEPANELAPPLET_LIBS) ../libtopmenu-server/libtopmenu-server-gtk$(GTK_VERSION).la appletdir = $(datadir)/mate-panel/applets diff --git a/mate-applet/topmenu-mate-panel-applet.c b/mate-applet/topmenu-mate-panel-applet.c index eb133bb..32841b7 100644 --- a/mate-applet/topmenu-mate-panel-applet.c +++ b/mate-applet/topmenu-mate-panel-applet.c @@ -21,12 +21,13 @@ #include <glib/gi18n.h> #include <gdk/gdkx.h> +#include <cairo-xlib.h> G_DEFINE_TYPE(TopMenuMatePanelApplet, topmenu_mate_panel_applet, PANEL_TYPE_APPLET) static void display_preferences_dialog(GtkAction *action, TopMenuMatePanelApplet *self) { - // TODO + // No preferences yet } static void display_about_dialog(GtkAction *action, TopMenuMatePanelApplet *self) @@ -51,6 +52,41 @@ static const GtkActionEntry menu_verbs[] = { G_CALLBACK (display_about_dialog) } }; +#if GTK_MAJOR_VERSION == 3 +static void topmenu_mate_panel_applet_change_background(MatePanelApplet* applet, MatePanelAppletBackgroundType type, GdkRGBA* color, cairo_pattern_t* pattern) +{ + TopMenuMatePanelApplet *self = TOPMENU_MATE_PANEL_APPLET(applet); + + if (type == PANEL_PIXMAP_BACKGROUND) { + topmenu_background_set_from_cairo_pattern(self->menu_widget->background, pattern); + } else if (type == PANEL_COLOR_BACKGROUND) { + topmenu_background_set_from_color(self->menu_widget->background, + color->red, color->green, color->blue, + color->alpha); + } else { + topmenu_background_clear(self->menu_widget->background); + } +} +#elif GTK_MAJOR_VERSION == 2 +static void topmenu_mate_panel_applet_change_background(MatePanelApplet* applet, MatePanelAppletBackgroundType type, GdkColor* color, GdkPixmap* pixmap) +{ + TopMenuMatePanelApplet *self = TOPMENU_MATE_PANEL_APPLET(applet); + + if (type == PANEL_PIXMAP_BACKGROUND) { + topmenu_background_set_from_drawable(self->menu_widget->background, + GDK_PIXMAP_XID(pixmap)); + } else if (type == PANEL_COLOR_BACKGROUND) { + topmenu_background_set_from_color(self->menu_widget->background, + color->red / 65535.0, + color->green / 65535.0, + color->blue / 65535.0, + 1.0); + } else { + topmenu_background_clear(self->menu_widget->background); + } +} +#endif + static void topmenu_mate_panel_applet_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { TopMenuMatePanelApplet *self = TOPMENU_MATE_PANEL_APPLET(widget); @@ -70,6 +106,9 @@ static void topmenu_mate_panel_applet_size_request(GtkWidget *widget, GtkRequisi static void topmenu_mate_panel_applet_class_init(TopMenuMatePanelAppletClass *klass) { + MatePanelAppletClass *applet_class = MATE_PANEL_APPLET_CLASS(klass); + applet_class->change_background = topmenu_mate_panel_applet_change_background; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); widget_class->size_allocate = topmenu_mate_panel_applet_size_allocate; widget_class->size_request = topmenu_mate_panel_applet_size_request; diff --git a/mate-applet/topmenu-mate-panel-applet.h b/mate-applet/topmenu-mate-panel-applet.h index de28b10..05fcb48 100644 --- a/mate-applet/topmenu-mate-panel-applet.h +++ b/mate-applet/topmenu-mate-panel-applet.h @@ -21,7 +21,7 @@ #define _TOPMENU_MATE_PANEL_APPLET_H_ #include <mate-panel-applet.h> -#include "../libtopmenu-server/topmenu-widget.h" +#include <topmenu-widget.h> G_BEGIN_DECLS @@ -47,7 +47,7 @@ struct _TopMenuMatePanelAppletClass MatePanelAppletClass parent_class; }; -GType topmenu_mate_panel_applet_get_type(void); +GType topmenu_mate_panel_applet_get_type(void) G_GNUC_CONST; MatePanelApplet *topmenu_mate_panel_applet_new(void); diff --git a/module/data.c b/module/data.c index 824bd8f..00902bb 100644 --- a/module/data.c +++ b/module/data.c @@ -30,9 +30,9 @@ #include "data.h" #include "appmenu.h" -G_DEFINE_QUARK(topmenu-window-data, window_data) -G_DEFINE_QUARK(topmenu-menu-shell-data, menu_shell_data) -G_DEFINE_QUARK(topmenu-menu-item-data, menu_item_data) +static G_DEFINE_QUARK(topmenu-window-data, window_data) +static G_DEFINE_QUARK(topmenu-menu-shell-data, menu_shell_data) +static G_DEFINE_QUARK(topmenu-menu-item-data, menu_item_data) gboolean topmenu_is_blacklisted (void) diff --git a/module/main.c b/module/main.c index e978582..5ab7e28 100644 --- a/module/main.c +++ b/module/main.c @@ -23,6 +23,7 @@ #include <gdk/gdkx.h> #include "../global.h" +#include "../libtopmenu-common/topmenu-background.h" #include "../libtopmenu-client/topmenu-client.h" #include "../libtopmenu-client/topmenu-monitor.h" @@ -168,7 +169,9 @@ topmenu_connect_window (GtkWindow *window) window_data->monitor_connection_id = g_signal_connect(monitor, "notify::available", G_CALLBACK (handle_should_hide_menubar_updated), window); - topmenu_client_connect_window_widget (gtk_widget_get_window (GTK_WIDGET (window)), + GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + topmenu_client_connect_window_widget (gdk_window, GTK_WIDGET (window_data->appmenubar)); } @@ -184,12 +187,12 @@ topmenu_disconnect_window (GtkWindow *window) if (window_data == NULL) return; // Already disconnected or ignored - if (window_data->monitor_connection_id == 0) - return; // Already disconnected - TopMenuMonitor *monitor = topmenu_monitor_get_instance(); - g_signal_handler_disconnect(monitor, window_data->monitor_connection_id); - window_data->monitor_connection_id = 0; + if (window_data->monitor_connection_id) + { + g_signal_handler_disconnect (monitor, window_data->monitor_connection_id); + window_data->monitor_connection_id = 0; + } if (window_data->appmenu.menu) topmenu_appmenu_destroy(&window_data->appmenu); diff --git a/xfce-applet/topmenu-xfce-panel-applet.h b/xfce-applet/topmenu-xfce-panel-applet.h index c948fda..958fe3b 100644 --- a/xfce-applet/topmenu-xfce-panel-applet.h +++ b/xfce-applet/topmenu-xfce-panel-applet.h @@ -47,7 +47,7 @@ struct _TopMenuXfcePanelAppletClass XfcePanelPluginClass parent_class; }; -GType topmenu_xfce_panel_applet_get_type(void); +GType topmenu_xfce_panel_applet_get_type(void) G_GNUC_CONST; XfcePanelPlugin *topmenu_xfce_panel_applet_new(void); |