From 2da9d48c9bcd1800f8a499b5e46c6ce04678acd5 Mon Sep 17 00:00:00 2001 From: Javier Date: Sun, 26 Jul 2015 03:11:35 +0200 Subject: add gtk+3 support for transparent backgrounds --- README.md | 1 - libtopmenu-client/topmenu-client.c | 1 - libtopmenu-common/topmenu-background.c | 72 ++++++++++++++++++++++++++++------ libtopmenu-common/topmenu-background.h | 1 + 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 22ced6f..f22c606 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ please send questions or problem reports to dev.bugs at javispedro com. Alternat * Multi-monitor support. Currently only one applet instance is supported. Ideally, IF there are multiple panel applets, they should synchronize to only embed menubars from the same display. * Allow Qt programs to render the menubars using Qt itself instead of using Gtk+. -* Transparent panels without XComposite (relative X11 background pixmaps, maybe?) * Add some toggables for some commonely requested options: hide/show the application menu, "menu button" instead of menu bar. # Design diff --git a/libtopmenu-client/topmenu-client.c b/libtopmenu-client/topmenu-client.c index ae9eac3..266ba54 100644 --- a/libtopmenu-client/topmenu-client.c +++ b/libtopmenu-client/topmenu-client.c @@ -95,7 +95,6 @@ static GdkFilterReturn handle_plug_window_event(GdkXEvent *xevent, GdkEvent *eve 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); diff --git a/libtopmenu-common/topmenu-background.c b/libtopmenu-common/topmenu-background.c index 99d36e9..04ea20d 100644 --- a/libtopmenu-common/topmenu-background.c +++ b/libtopmenu-common/topmenu-background.c @@ -40,6 +40,11 @@ G_DEFINE_TYPE(TopMenuBackground, topmenu_background, G_TYPE_OBJECT) static guint signals[N_SIGNALS]; +#if GTK_MAJOR_VERSION == 3 +#define TOPMENU_BACKGROUND_CSS_STYLE_CLASS "topmenu-background" +static GtkCssProvider *topmenu_provider; +#endif + static inline GdkDisplay * topmenu_background_get_display(TopMenuBackground *self) { return gdk_display_get_default(); @@ -94,12 +99,6 @@ TopMenuBackground *topmenu_background_new(void) 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; @@ -150,6 +149,7 @@ void topmenu_background_set_from_drawable(TopMenuBackground *self, Drawable draw width, height); if (!new_surface) { g_debug("could not create new surface"); + XFreePixmap(xdpy, self->priv->pixmap); goto err_out; } @@ -283,13 +283,10 @@ void topmenu_background_set_from_client_message(TopMenuBackground *self, XClient 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); } } @@ -310,7 +307,41 @@ static GdkPixmap * get_pixmap(GdkDisplay *display, Pixmap pixmap) void topmenu_background_apply(TopMenuBackground *self, GtkWidget *widget) { #if GTK_MAJOR_VERSION == 3 - g_debug("background set not yet supported on Gtk+ 3"); + if (!topmenu_provider) { + topmenu_provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(topmenu_provider, + "." TOPMENU_BACKGROUND_CSS_STYLE_CLASS " {\n" + " background-color: rgba (0, 0, 0, 0);\n" + " background-image: none;\n" + "}", -1, NULL); + } + + GtkStyleContext *context = gtk_widget_get_style_context(widget); + + GdkWindow *widget_window = gtk_widget_get_window(widget); + double red, green, blue, alpha; + Pixmap pixmap; + if (topmenu_background_get_color(self, &red, &green, &blue, &alpha)) { + gtk_style_context_add_class(context, TOPMENU_BACKGROUND_CSS_STYLE_CLASS); + if (widget_window) { + GdkRGBA color = {red, green, blue, alpha}; + gdk_window_set_background_rgba(widget_window, &color); + g_debug("do color"); + + } + } else if (topmenu_background_get_pixmap(self, &pixmap)) { + gtk_style_context_add_class(context, TOPMENU_BACKGROUND_CSS_STYLE_CLASS); + if (widget_window) { + cairo_pattern_t * pattern = topmenu_background_get_cairo_pattern(self); + gdk_window_set_background_pattern(widget_window, pattern); + cairo_pattern_destroy(pattern); + } + } else { + gtk_style_context_remove_class(context, TOPMENU_BACKGROUND_CSS_STYLE_CLASS); + } + + gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(topmenu_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); #elif GTK_MAJOR_VERSION == 2 // Clear current background GtkRcStyle *rc_style; @@ -347,15 +378,34 @@ void topmenu_background_apply(TopMenuBackground *self, GtkWidget *widget) g_object_unref(style); } } - +#endif gtk_widget_queue_draw(widget); +} + +void topmenu_background_unapply(TopMenuBackground *self, GtkWidget *widget) +{ +#if GTK_MAJOR_VERSION == 3 + GtkStyleContext *context = gtk_widget_get_style_context(widget); + gtk_style_context_remove_class(context, TOPMENU_BACKGROUND_CSS_STYLE_CLASS); + gtk_style_context_remove_provider(context, GTK_STYLE_PROVIDER(topmenu_provider)); +#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); #endif + gtk_widget_queue_draw(widget); } void topmenu_background_connect(TopMenuBackground *self, GtkWidget *widget) { g_signal_connect(self, "changed", G_CALLBACK(topmenu_background_apply), widget); + if (gtk_widget_get_realized(widget)) { + topmenu_background_apply(self, widget); + } } void topmenu_background_disconnect(TopMenuBackground *self, GtkWidget *widget) diff --git a/libtopmenu-common/topmenu-background.h b/libtopmenu-common/topmenu-background.h index aca72f8..76c9f6d 100644 --- a/libtopmenu-common/topmenu-background.h +++ b/libtopmenu-common/topmenu-background.h @@ -65,6 +65,7 @@ void topmenu_background_fill_client_message(TopMenuBackground *self, XClientMess void topmenu_background_set_from_client_message(TopMenuBackground *self, XClientMessageEvent *event); void topmenu_background_apply(TopMenuBackground *self, GtkWidget *widget); +void topmenu_background_unapply(TopMenuBackground *self, GtkWidget *widget); void topmenu_background_connect(TopMenuBackground *self, GtkWidget *widget); void topmenu_background_disconnect(TopMenuBackground *self, GtkWidget *widget); -- cgit v1.2.3