mirror of https://github.com/GNOME/gimp.git
Issue #11957: ignore events on all display shell when one is being created.
This fixes a never-ending flickering blocking the GUI, until a manual focus event (such as moving a window in front) breaks the infinite loop of handling focus events.
This commit is contained in:
parent
b728ecb9f2
commit
c5db158f58
|
@ -306,3 +306,39 @@ gimp_displays_unset_busy (Gimp *gimp)
|
|||
gimp_display_shell_unset_override_cursor (shell);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_displays_accept_focus_events:
|
||||
* @gimp:
|
||||
*
|
||||
* When this returns %FALSE, we should ignore focus events. In
|
||||
* particular, I had weird cases in multi-window mode, before a new
|
||||
* image window was actually displayed on screen, there seemed to be
|
||||
* infinite loops of focus events switching the active display between
|
||||
* the current active one and the one being created, with flickering
|
||||
* window title and the new display never actually displayed until we
|
||||
* broke the loop by manually getting out of focus (see #11957).
|
||||
* This is why when any of the display is not fully drawn yet (which
|
||||
* usually means it is being created), we temporarily ignore focus
|
||||
* events on all displays.
|
||||
*/
|
||||
gboolean
|
||||
gimp_displays_accept_focus_events (Gimp *gimp)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
|
||||
|
||||
for (list = gimp_get_display_iter (gimp);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
GimpDisplay *display = list->data;
|
||||
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
||||
|
||||
if (! gimp_display_shell_is_drawn (shell))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ gint gimp_displays_get_num_visible (Gimp *gimp);
|
|||
|
||||
void gimp_displays_set_busy (Gimp *gimp);
|
||||
void gimp_displays_unset_busy (Gimp *gimp);
|
||||
gboolean gimp_displays_accept_focus_events (Gimp *gimp);
|
||||
|
||||
|
||||
#endif /* __GIMP_DISPLAY_FOREACH_H__ */
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
|
||||
#include "gimpcanvas.h"
|
||||
#include "gimpdisplay.h"
|
||||
#include "gimpdisplay-foreach.h"
|
||||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-autoscroll.h"
|
||||
#include "gimpdisplayshell-cursor.h"
|
||||
|
@ -173,6 +174,15 @@ gimp_display_shell_events (GtkWidget *widget,
|
|||
|
||||
gimp = gimp_display_get_gimp (shell->display);
|
||||
|
||||
/* When a display is being created, we may have some weird cases where
|
||||
* we get never-ending focus events fighting for which image window
|
||||
* should have focus, in an infinite loop. See #11957.
|
||||
* Just ignore focus events in these cases, and in particular, don't
|
||||
* set the display from such focus events.
|
||||
*/
|
||||
if (! gimp_displays_accept_focus_events (gimp))
|
||||
return TRUE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
|
|
|
@ -187,6 +187,9 @@ static void gimp_display_shell_transform_overlay (GimpDisplayShell *shell,
|
|||
GtkWidget *child,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
static gboolean gimp_display_shell_draw (GimpDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
gpointer *data);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GimpDisplayShell, gimp_display_shell,
|
||||
|
@ -373,6 +376,7 @@ gimp_display_shell_init (GimpDisplayShell *shell)
|
|||
shell->equidistance_side_vertical = GIMP_ARRANGE_HFILL;
|
||||
shell->near_layer_vertical1 = NULL;
|
||||
shell->near_layer_vertical2 = NULL;
|
||||
shell->drawn = FALSE;
|
||||
|
||||
env = g_getenv ("GIMP_DISPLAY_RENDER_BUF_SIZE");
|
||||
|
||||
|
@ -429,6 +433,10 @@ gimp_display_shell_init (GimpDisplayShell *shell)
|
|||
G_CALLBACK (gimp_display_shell_events),
|
||||
shell);
|
||||
|
||||
g_signal_connect (shell, "draw",
|
||||
G_CALLBACK (gimp_display_shell_draw),
|
||||
NULL);
|
||||
|
||||
gimp_help_connect (GTK_WIDGET (shell), NULL, gimp_standard_help_func,
|
||||
GIMP_HELP_IMAGE_WINDOW, NULL, NULL);
|
||||
}
|
||||
|
@ -1333,6 +1341,19 @@ gimp_display_shell_transform_overlay (GimpDisplayShell *shell,
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_display_shell_draw (GimpDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
gpointer *data)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (shell),
|
||||
G_CALLBACK (gimp_display_shell_draw),
|
||||
data);
|
||||
|
||||
shell->drawn = TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -2269,3 +2290,22 @@ gimp_display_shell_set_mask (GimpDisplayShell *shell,
|
|||
gimp_display_shell_expose_full (shell);
|
||||
gimp_display_shell_render_invalidate_full (shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_display_shell_is_drawn:
|
||||
* @shell:
|
||||
*
|
||||
* This should be run when you need to verify that the shell or its
|
||||
* display were actually drawn. gtk_widget_is_visible(),
|
||||
* gtk_widget_get_mapped() or gtk_widget_get_realized() are not enough
|
||||
* because they may all return TRUE before the window is actually on
|
||||
* screen.
|
||||
*
|
||||
* Returns: whether @shell was actually drawn on screen, i.e. the "draw"
|
||||
* signal has run.
|
||||
*/
|
||||
gboolean
|
||||
gimp_display_shell_is_drawn (GimpDisplayShell *shell)
|
||||
{
|
||||
return shell->drawn;
|
||||
}
|
||||
|
|
|
@ -253,6 +253,8 @@ struct _GimpDisplayShell
|
|||
GimpAlignmentType equidistance_side_vertical;
|
||||
GimpLayer *near_layer_vertical1;
|
||||
GimpLayer *near_layer_vertical2;
|
||||
|
||||
gboolean drawn;
|
||||
};
|
||||
|
||||
struct _GimpDisplayShellClass
|
||||
|
@ -359,5 +361,7 @@ void gimp_display_shell_set_mask (GimpDisplayShell *shell,
|
|||
GeglColor *color,
|
||||
gboolean inverted);
|
||||
|
||||
gboolean gimp_display_shell_is_drawn (GimpDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __GIMP_DISPLAY_SHELL_H__ */
|
||||
|
|
Loading…
Reference in New Issue