From 8c044d0852dc9d0d8799b4f8376cc11057410486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Mon, 15 Jul 2019 14:27:35 +0200 Subject: [PATCH 1/2] keyboard: Schedule widget redraw instead of gdk_window_invalidate_rect The later would invaliate the drawn area again and again in a ::draw() handler. This caused infinite redraws when e.g. a key was locked. To reproduce break e.g. on `eek_gtk_keyboard_real_draw()` and see how it is invoked again and again. --- eek/eek-gtk-keyboard.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 436e754e..913a0567 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -558,9 +558,6 @@ render_pressed_key (GtkWidget *widget, gdk_window_end_draw_frame (window, context); cairo_region_destroy (region); - - /* force immediate drawing of the backbuffer to the screen */ - gdk_window_invalidate_rect (window, &dirty_rect, FALSE); } static void @@ -590,9 +587,6 @@ render_locked_key (GtkWidget *widget, gdk_window_end_draw_frame (window, context); cairo_region_destroy (region); - - /* force immediate drawing of the backbuffer to the screen */ - gdk_window_invalidate_rect (window, &dirty_rect, FALSE); } static void @@ -622,9 +616,6 @@ render_released_key (GtkWidget *widget, gdk_window_end_draw_frame (window, context); cairo_region_destroy (region); - - /* force immediate drawing of the backbuffer to the screen */ - gdk_window_invalidate_rect (window, &dirty_rect, FALSE); } static void @@ -638,6 +629,7 @@ on_key_pressed (EekKey *key, return; render_pressed_key (GTK_WIDGET(self), key); + gtk_widget_queue_draw (GTK_WIDGET(self)); #if HAVE_LIBCANBERRA ca_gtk_play_for_widget (widget, 0, @@ -659,6 +651,7 @@ on_key_released (EekKey *key, return; render_released_key (GTK_WIDGET(self), key); + gtk_widget_queue_draw (GTK_WIDGET(self)); #if HAVE_LIBCANBERRA ca_gtk_play_for_widget (widget, 0, @@ -682,6 +675,7 @@ on_key_locked (EekKeyboard *keyboard, return; render_locked_key (widget, key); + gtk_widget_queue_draw (widget); } static void @@ -697,6 +691,7 @@ on_key_unlocked (EekKeyboard *keyboard, return; render_released_key (widget, key); + gtk_widget_queue_draw (GTK_WIDGET(widget)); } static void From 94c9442de1de1ecba1eb58080f292269af5f9af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Mon, 15 Jul 2019 17:40:37 +0200 Subject: [PATCH 2/2] keyboard: Drop now unused clip_bounds_to_dirty_rectangle() --- eek/eek-gtk-keyboard.c | 57 ------------------------------------------ 1 file changed, 57 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 913a0567..7df9a6b9 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -484,45 +484,6 @@ magnify_bounds (GtkWidget *self, large_bounds->y = CLAMP(y, 0, allocation.height - large_bounds->height); } -/* - * Alleviate the asymmetry between drawing a pressed key and a released key, - * and consistently draw to the exact same area. - * - * By saving the dirty rectangle we can limit drawing of the backbuffer to - * the screen as well, eg gdk_window_invalidate_rect() instead of - * gtk_widget_queue_draw() which redraws the entire widget. - * - * b1 is mandatory, b2 is optional - */ -static GdkRectangle -clip_bounds_to_dirty_rectangle (cairo_t *cr, EekBounds *b1, EekBounds *b2) -{ - if (b2) - cairo_rectangle (cr, b2->x, b2->y, b2->width, b2->height); - - cairo_rectangle (cr, b1->x, b1->y, b1->width, b1->height); - cairo_clip (cr); - - /* - * save the clipped region to a bounding box so we can limit - * the drawing of the backbuffer to the screen to the same area - */ - cairo_rectangle_t bbox; - - cairo_clip_extents (cr, &bbox.x, &bbox.y, &bbox.width, &bbox.height); - - /* convert double to int, making sure r strictly covers bbox to avoid - * artefacts. floor() is unnecessary, ceil() is not */ - GdkRectangle r = { - floor (bbox.x), - floor (bbox.y), - ceil (bbox.width), - ceil (bbox.height) - }; - - return r; -} - static void render_pressed_key (GtkWidget *widget, EekKey *key) @@ -539,12 +500,6 @@ render_pressed_key (GtkWidget *widget, eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); magnify_bounds (widget, &bounds, &large_bounds, 1.5); - /* - * clip to limit drawing to backbuffer and save clip region to dirty_rect - * to limit redrawing of the backbuffer to the same area - */ - GdkRectangle dirty_rect = clip_bounds_to_dirty_rectangle (cr, &bounds, &large_bounds); - cairo_save (cr); cairo_translate (cr, bounds.x, bounds.y); eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); @@ -575,12 +530,6 @@ render_locked_key (GtkWidget *widget, eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); - /* - * clip to limit drawing to backbuffer and save clip region to dirty_rect - * to limit redrawing of the backbuffer to the same area - */ - GdkRectangle dirty_rect = clip_bounds_to_dirty_rectangle (cr, &bounds, NULL); - cairo_translate (cr, bounds.x, bounds.y); eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); @@ -605,12 +554,6 @@ render_released_key (GtkWidget *widget, eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); magnify_bounds (widget, &bounds, &large_bounds, 1.5); - /* - * clip to limit drawing to backbuffer and save clip region to dirty_rect - * to limit redrawing of the backbuffer to the same area - */ - GdkRectangle dirty_rect = clip_bounds_to_dirty_rectangle(cr, &bounds, &large_bounds); - eek_renderer_render_keyboard (priv->renderer, cr); gdk_window_end_draw_frame (window, context);