From 0afdda11f38f8ae6a3595b18b6ce9dcdd30a9909 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 9 Sep 2017 17:09:50 +0300 Subject: [PATCH 1/5] Drop dependency on gtk3 As per discussion in #334 drop dependency on gtk3 and instead depend only on gdk-pixbuf2 for icon loading. The only gtk3 function used was gdk_cairo_set_source_pixbuf in order to convert the loaded pixbufs into cairo surfaces for us to render. In order to drop the dependency this step was bypassed by using pixbufs export to png capability and importing it into cairo via a pngstream. --- config.mk | 2 +- src/x11/x.c | 33 ++++++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/config.mk b/config.mk index 7b26a48..68b29f2 100644 --- a/config.mk +++ b/config.mk @@ -17,7 +17,7 @@ LDFLAGS_DEBUG := pkg_config_packs := dbus-1 \ gio-2.0 \ - gdk-3.0 \ + gdk-pixbuf-2.0 \ "glib-2.0 >= 2.36" \ pangocairo \ x11 \ diff --git a/src/x11/x.c b/src/x11/x.c index dcfef35..0cef023 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -288,21 +287,29 @@ static dimension_t calculate_dimensions(GSList *layouts) return dim; } -static cairo_surface_t *gdk_pixbuf_to_cairo_surface(const GdkPixbuf *pixbuf) +struct buffer { + char *buf; + gsize bufsize; +}; + +static cairo_status_t read_from_buf(void *closure, unsigned char *data, unsigned int size) +{ + struct buffer *buf = (struct buffer *)closure; + unsigned int cpy = MIN(size, buf->bufsize); + memcpy(data, buf->buf, cpy); + buf->buf += cpy; + buf->bufsize -= cpy; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) { cairo_surface_t *icon_surface = NULL; - cairo_t *cr; - cairo_format_t format; - double width, height; + struct buffer buffer; + + gdk_pixbuf_save_to_buffer(pixbuf, &buffer.buf, &buffer.bufsize, "png", NULL, NULL); + icon_surface = cairo_image_surface_create_from_png_stream(read_from_buf, &buffer); - format = gdk_pixbuf_get_has_alpha(pixbuf) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; - width = gdk_pixbuf_get_width(pixbuf); - height = gdk_pixbuf_get_height(pixbuf); - icon_surface = cairo_image_surface_create(format, width, height); - cr = cairo_create(icon_surface); - gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); - cairo_paint(cr); - cairo_destroy(cr); return icon_surface; } From a6dea0cc35eb3fd544ff99f34c63d562ed9204b1 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Mon, 18 Sep 2017 16:58:02 +0200 Subject: [PATCH 2/5] Use GByteArray for bytebuffer in pixbuf conversion --- src/x11/x.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/x11/x.c b/src/x11/x.c index 0cef023..552110e 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -287,28 +287,31 @@ static dimension_t calculate_dimensions(GSList *layouts) return dim; } -struct buffer { - char *buf; - gsize bufsize; -}; - static cairo_status_t read_from_buf(void *closure, unsigned char *data, unsigned int size) { - struct buffer *buf = (struct buffer *)closure; - unsigned int cpy = MIN(size, buf->bufsize); - memcpy(data, buf->buf, cpy); - buf->buf += cpy; - buf->bufsize -= cpy; + GByteArray *buf = (GByteArray *)closure; + + unsigned int cpy = MIN(size, buf->len); + memcpy(data, buf->data, cpy); + g_byte_array_remove_range(buf, 0, cpy); + return CAIRO_STATUS_SUCCESS; } + static cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) { cairo_surface_t *icon_surface = NULL; - struct buffer buffer; + GByteArray *buffer; + char *bufstr; + gsize buflen; - gdk_pixbuf_save_to_buffer(pixbuf, &buffer.buf, &buffer.bufsize, "png", NULL, NULL); - icon_surface = cairo_image_surface_create_from_png_stream(read_from_buf, &buffer); + gdk_pixbuf_save_to_buffer(pixbuf, &bufstr, &buflen, "png", NULL, NULL); + + buffer = g_byte_array_new_take((guint8*)bufstr, buflen); + icon_surface = cairo_image_surface_create_from_png_stream(read_from_buf, buffer); + + g_byte_array_free(buffer, TRUE); return icon_surface; } From d7ec8bf165b68a4e48b916c23c4262e01d07f128 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Mon, 18 Sep 2017 19:14:44 +0200 Subject: [PATCH 3/5] Explain counterintuitive gdk pixbuf conversion --- src/x11/x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/x11/x.c b/src/x11/x.c index 552110e..881b1af 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -301,6 +301,13 @@ static cairo_status_t read_from_buf(void *closure, unsigned char *data, unsigned static cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) { + /* + * Export the gdk pixbuf into buffer as a png and import the png buffer + * via cairo again as a cairo_surface_t. + * It looks counterintuitive, as there is gdk_cairo_set_source_pixbuf, + * which does the job faster. But this would require gtk3 as a dependency + * for a single function call. See discussion in #334 and #376. + */ cairo_surface_t *icon_surface = NULL; GByteArray *buffer; char *bufstr; From a5d722799e2a1b477642f442015763aab1f413d6 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 22 Dec 2017 22:07:32 +0100 Subject: [PATCH 4/5] Insert actual screen number into screen info struct The screen info struct contained always a 0 in its screen number field. So it always had been scr1 == scr2. --- src/x11/screen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/x11/screen.c b/src/x11/screen.c index bce8c54..07a22a6 100644 --- a/src/x11/screen.c +++ b/src/x11/screen.c @@ -122,6 +122,7 @@ void randr_update() alloc_screen_ar(n); for (int i = 0; i < n; i++) { + screens[i].scr = i; screens[i].dim.x = m[i].x; screens[i].dim.y = m[i].y; screens[i].dim.w = m[i].width; @@ -157,6 +158,7 @@ void xinerama_update() alloc_screen_ar(n); for (int i = 0; i < n; i++) { + screens[i].scr = i; screens[i].dim.x = info[i].x_org; screens[i].dim.y = info[i].y_org; screens[i].dim.h = info[i].height; From 8f5afaafb681c2b37828fd241c5317742cf8aba2 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 22 Dec 2017 22:23:17 +0100 Subject: [PATCH 5/5] Do not redraw window on PropertyChange When receiving a PropertyChange XEvent, it's mostly because the focus of another window changed to another window. This isn't actually neccessary for dunst. We need the event only, to know, when the screens have switched. As redrawing the screen became more expensive with the drop of GTK3, we have to ignore this event and only really redraw the window, when the focus has moved to another screen. --- src/x11/x.c | 11 ++++++++++- src/x11/x.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/x11/x.c b/src/x11/x.c index 881b1af..0f38487 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -730,6 +730,7 @@ static void x_win_move(int width, int height) int x, y; screen_info *scr = get_active_screen(); + xctx.cur_screen = scr->scr; /* calculate window position */ if (xctx.geometry.mask & XNegative) { x = (scr->dim.x + (scr->dim.w - width)) + xctx.geometry.x; @@ -908,9 +909,17 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer break; case FocusIn: case FocusOut: - case PropertyNotify: wake_up(); break; + case PropertyNotify: + /* Ignore PropertyNotify, when we're still on the + * same screen. PropertyNotify is only neccessary + * to detect a focus change to another screen + */ + if( settings.f_mode != FOLLOW_NONE + && get_active_screen()->scr != xctx.cur_screen) + wake_up(); + break; default: screen_check_event(ev); break; diff --git a/src/x11/x.h b/src/x11/x.h index 3b08ca4..8ee757a 100644 --- a/src/x11/x.h +++ b/src/x11/x.h @@ -25,6 +25,7 @@ typedef struct _keyboard_shortcut { typedef struct _xctx { Atom utf8; Display *dpy; + int cur_screen; Window win; bool visible; dimension_t geometry;