aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-07-26 01:02:12 +0200
committerJavier <dev.git@javispedro.com>2015-07-26 01:02:12 +0200
commitbaef440d424640a6fc99edd8a12a6abcea80c5fc (patch)
tree7fb717c04564618d3c9c7b0db1c46ddde138bf5a
parentf690cd97506f45e02bb6383fde2a7c8f06820408 (diff)
downloadtopmenu-gtk-baef440d424640a6fc99edd8a12a6abcea80c5fc.tar.gz
topmenu-gtk-baef440d424640a6fc99edd8a12a6abcea80c5fc.zip
initial gtk2 "transparent" background attempt
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac5
-rw-r--r--global.h9
-rw-r--r--libtopmenu-client/Makefile.am8
-rw-r--r--libtopmenu-client/topmenu-appmenubar.h2
-rw-r--r--libtopmenu-client/topmenu-client.c48
-rw-r--r--libtopmenu-client/topmenu-client.h1
-rw-r--r--libtopmenu-client/topmenu-monitor.c3
-rw-r--r--libtopmenu-client/topmenu-monitor.h4
-rw-r--r--libtopmenu-common/Makefile.am17
-rw-r--r--libtopmenu-common/topmenu-background.c365
-rw-r--r--libtopmenu-common/topmenu-background.h74
-rw-r--r--libtopmenu-server/Makefile.am8
-rw-r--r--libtopmenu-server/topmenu-server.c20
-rw-r--r--libtopmenu-server/topmenu-widget.c92
-rw-r--r--libtopmenu-server/topmenu-widget.h7
-rw-r--r--mate-applet/Makefile.am2
-rw-r--r--mate-applet/topmenu-mate-panel-applet.c41
-rw-r--r--mate-applet/topmenu-mate-panel-applet.h4
-rw-r--r--module/data.c6
-rw-r--r--module/main.c15
-rw-r--r--xfce-applet/topmenu-xfce-panel-applet.h2
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
diff --git a/global.h b/global.h
index 3229497..9b4bd69 100644
--- a/global.h
+++ b/global.h
@@ -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) &gtk_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);