diff --git a/src/core/window-private.h b/src/core/window-private.h index 8305897a4..258445d98 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -60,10 +60,9 @@ typedef enum { META_QUEUE_CALC_SHOWING = 1 << 0, META_QUEUE_MOVE_RESIZE = 1 << 1, - META_QUEUE_UPDATE_ICON = 1 << 2, } MetaQueueType; -#define NUMBER_OF_QUEUES 3 +#define NUMBER_OF_QUEUES 2 typedef enum { @@ -185,9 +184,6 @@ struct _MetaWindow char *desc; /* used in debug spew */ char *title; - cairo_surface_t *icon; - cairo_surface_t *mini_icon; - MetaWindowType type; /* NOTE these five are not in UTF-8, we just treat them as random @@ -608,9 +604,10 @@ struct _MetaWindowClass void (*get_default_skip_hints) (MetaWindow *window, gboolean *skip_taskbar_out, gboolean *skip_pager_out); - gboolean (*update_icon) (MetaWindow *window, - cairo_surface_t **icon, - cairo_surface_t **mini_icon); + + cairo_surface_t * (*get_icon) (MetaWindow *window); + cairo_surface_t * (*get_mini_icon) (MetaWindow *window); + pid_t (*get_client_pid) (MetaWindow *window); void (*update_main_monitor) (MetaWindow *window, MetaWindowUpdateMonitorFlags flags); @@ -867,6 +864,10 @@ MetaLogicalMonitor * meta_window_get_main_logical_monitor (MetaWindow *window); void meta_window_update_monitor (MetaWindow *window, MetaWindowUpdateMonitorFlags flags); +cairo_surface_t * meta_window_get_icon (MetaWindow *window); + +cairo_surface_t * meta_window_get_mini_icon (MetaWindow *window); + void meta_window_set_urgent (MetaWindow *window, gboolean urgent); diff --git a/src/core/window.c b/src/core/window.c index 9a82a9e68..262ec1958 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -26,7 +26,7 @@ * @short_description: A display-agnostic abstraction for a window. * * #MetaWindow is the core abstraction in Mutter of a window. It has the - * properties you'd expect, such as a title, an icon, whether it's fullscreen, + * properties you'd expect, such as a title, whether it's fullscreen, * has decorations, etc. * * Since a lot of different kinds of windows exist, each window also a @@ -161,9 +161,6 @@ static void unminimize_window_and_all_transient_parents (MetaWindow *window); static void meta_window_propagate_focus_appearance (MetaWindow *window, gboolean focused); -static void meta_window_update_icon_now (MetaWindow *window, - gboolean force); - static void set_workspace_state (MetaWindow *window, gboolean on_all_workspaces, MetaWorkspace *workspace); @@ -181,7 +178,6 @@ static void update_edge_constraints (MetaWindow *window); */ static gboolean idle_calc_showing (gpointer data); static gboolean idle_move_resize (gpointer data); -static gboolean idle_update_icon (gpointer data); G_DEFINE_ABSTRACT_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); @@ -293,16 +289,6 @@ meta_window_real_get_default_skip_hints (MetaWindow *window, *skip_pager_out = FALSE; } -static gboolean -meta_window_real_update_icon (MetaWindow *window, - cairo_surface_t **icon, - cairo_surface_t **mini_icon) -{ - *icon = NULL; - *mini_icon = NULL; - return FALSE; -} - static pid_t meta_window_real_get_client_pid (MetaWindow *window) { @@ -314,12 +300,6 @@ meta_window_finalize (GObject *object) { MetaWindow *window = META_WINDOW (object); - if (window->icon) - cairo_surface_destroy (window->icon); - - if (window->mini_icon) - cairo_surface_destroy (window->mini_icon); - if (window->frame_bounds) cairo_region_destroy (window->frame_bounds); @@ -373,10 +353,10 @@ meta_window_get_property(GObject *object, g_value_set_string (value, win->title); break; case PROP_ICON: - g_value_set_pointer (value, win->icon); + g_value_set_pointer (value, meta_window_get_icon (win)); break; case PROP_MINI_ICON: - g_value_set_pointer (value, win->mini_icon); + g_value_set_pointer (value, meta_window_get_mini_icon (win)); break; case PROP_DECORATED: g_value_set_boolean (value, win->decorated); @@ -479,7 +459,6 @@ meta_window_class_init (MetaWindowClass *klass) klass->current_workspace_changed = meta_window_real_current_workspace_changed; klass->update_struts = meta_window_real_update_struts; klass->get_default_skip_hints = meta_window_real_get_default_skip_hints; - klass->update_icon = meta_window_real_update_icon; klass->get_client_pid = meta_window_real_get_client_pid; obj_props[PROP_TITLE] = @@ -1068,8 +1047,6 @@ _meta_window_shared_new (MetaDisplay *display, window->xvisual = attrs->visual; window->title = NULL; - window->icon = NULL; - window->mini_icon = NULL; window->frame = NULL; window->has_focus = FALSE; @@ -1218,9 +1195,6 @@ _meta_window_shared_new (MetaDisplay *display, meta_window_manage (window); - if (!window->override_redirect) - meta_window_update_icon_now (window, TRUE); - if (window->initially_iconic) { /* WM_HINTS said minimized */ @@ -1578,9 +1552,9 @@ meta_window_unmanage (MetaWindow *window, if (window->maximized_horizontally || window->maximized_vertically) unmaximize_window_before_freeing (window); - meta_window_unqueue (window, META_QUEUE_CALC_SHOWING | - META_QUEUE_MOVE_RESIZE | - META_QUEUE_UPDATE_ICON); + meta_window_unqueue (window, + (META_QUEUE_CALC_SHOWING | + META_QUEUE_MOVE_RESIZE)); set_workspace_state (window, FALSE, NULL); @@ -1805,8 +1779,8 @@ meta_window_calc_showing (MetaWindow *window) implement_showing (window, meta_window_should_be_showing (window)); } -static guint queue_later[NUMBER_OF_QUEUES] = {0, 0, 0}; -static GSList *queue_pending[NUMBER_OF_QUEUES] = {NULL, NULL, NULL}; +static guint queue_later[NUMBER_OF_QUEUES] = {}; +static GSList *queue_pending[NUMBER_OF_QUEUES] = {}; static int stackcmp (gconstpointer a, gconstpointer b) @@ -1989,7 +1963,7 @@ idle_calc_showing (gpointer data) #ifdef WITH_VERBOSE_MODE static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] = - {"calc_showing", "move_resize", "update_icon"}; + {"calc_showing", "move_resize", }; #endif static void @@ -2053,16 +2027,14 @@ meta_window_queue (MetaWindow *window, { const MetaLaterType window_queue_later_when[NUMBER_OF_QUEUES] = { - META_LATER_CALC_SHOWING, /* CALC_SHOWING */ - META_LATER_RESIZE, /* MOVE_RESIZE */ - META_LATER_BEFORE_REDRAW /* UPDATE_ICON */ + META_LATER_CALC_SHOWING, + META_LATER_RESIZE, }; const GSourceFunc window_queue_later_handler[NUMBER_OF_QUEUES] = { idle_calc_showing, idle_move_resize, - idle_update_icon, }; if (window->unmanaging) @@ -5533,85 +5505,26 @@ meta_window_set_icon_geometry (MetaWindow *window, } } -static void -redraw_icon (MetaWindow *window) +cairo_surface_t * +meta_window_get_icon (MetaWindow *window) { - /* We could probably be smart and just redraw the icon here, - * instead of the whole frame. - */ - if (window->frame) - meta_frame_queue_draw (window->frame); + MetaWindowClass *klass = META_WINDOW_GET_CLASS (window); + + if (klass->get_icon) + return klass->get_icon (window); + else + return NULL; } -static void -meta_window_update_icon_now (MetaWindow *window, - gboolean force) +cairo_surface_t * +meta_window_get_mini_icon (MetaWindow *window) { - gboolean changed; - cairo_surface_t *icon = NULL; - cairo_surface_t *mini_icon; + MetaWindowClass *klass = META_WINDOW_GET_CLASS (window); - g_return_if_fail (!window->override_redirect); - - changed = META_WINDOW_GET_CLASS (window)->update_icon (window, &icon, &mini_icon); - - if (changed || force) - { - if (window->icon) - cairo_surface_destroy (window->icon); - window->icon = icon; - - if (window->mini_icon) - cairo_surface_destroy (window->mini_icon); - window->mini_icon = mini_icon; - - g_object_freeze_notify (G_OBJECT (window)); - g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_ICON]); - g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MINI_ICON]); - g_object_thaw_notify (G_OBJECT (window)); - - redraw_icon (window); - } -} - -static gboolean -idle_update_icon (gpointer data) -{ - GSList *tmp; - GSList *copy; - guint queue_index = GPOINTER_TO_INT (data); - - meta_topic (META_DEBUG_GEOMETRY, "Clearing the update_icon queue"); - - /* Work with a copy, for reentrancy. The allowed reentrancy isn't - * complete; destroying a window while we're in here would result in - * badness. But it's OK to queue/unqueue update_icons. - */ - copy = g_slist_copy (queue_pending[queue_index]); - g_slist_free (queue_pending[queue_index]); - queue_pending[queue_index] = NULL; - queue_later[queue_index] = 0; - - destroying_windows_disallowed += 1; - - tmp = copy; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - meta_window_update_icon_now (window, FALSE); - window->is_in_queues &= ~META_QUEUE_UPDATE_ICON; - - tmp = tmp->next; - } - - g_slist_free (copy); - - destroying_windows_disallowed -= 1; - - return FALSE; + if (klass->get_mini_icon) + return klass->get_mini_icon (window); + else + return NULL; } GList* diff --git a/src/ui/frames.c b/src/ui/frames.c index b1329b272..cf90d477b 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -1595,7 +1595,7 @@ meta_ui_frame_paint (MetaUIFrame *frame, if (button_type > -1) button_states[button_type] = frame->button_state; - mini_icon = frame->meta_window->mini_icon; + mini_icon = meta_window_get_mini_icon (frame->meta_window); flags = meta_frame_get_flags (frame->meta_window->frame); type = meta_window_get_frame_type (frame->meta_window); diff --git a/src/x11/window-props.c b/src/x11/window-props.c index 1d8cf63a6..aa4fab99c 100644 --- a/src/x11/window-props.c +++ b/src/x11/window-props.c @@ -296,7 +296,7 @@ reload_icon (MetaWindow *window, meta_icon_cache_property_changed (&priv->icon_cache, window->display->x11_display, atom); - meta_window_queue(window, META_QUEUE_UPDATE_ICON); + meta_window_x11_queue_update_icon (window_x11); } static void @@ -1694,7 +1694,8 @@ reload_wm_hints (MetaWindow *window, window->display->x11_display, XA_WM_HINTS); - meta_window_queue (window, META_QUEUE_UPDATE_ICON | META_QUEUE_MOVE_RESIZE); + meta_window_x11_queue_update_icon (window_x11); + meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } static gboolean diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h index e12f83be0..7e5a72d03 100644 --- a/src/x11/window-x11-private.h +++ b/src/x11/window-x11-private.h @@ -72,6 +72,10 @@ struct _MetaWindowX11Private Pixmap wm_hints_pixmap; Pixmap wm_hints_mask; + cairo_surface_t *icon; + cairo_surface_t *mini_icon; + guint update_icon_handle_id; + /* Freeze/thaw on resize (for Xwayland) */ gboolean thaw_after_paint; @@ -84,6 +88,8 @@ MetaWindowX11Private * meta_window_x11_get_private (MetaWindowX11 *window_x11); void meta_window_x11_set_bypass_compositor_hint (MetaWindowX11 *window_x11, MetaBypassCompositorHint requested_value); +void meta_window_x11_queue_update_icon (MetaWindowX11 *window_x11); + G_END_DECLS #endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index 7f8e79aa5..4e8efcd75 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -42,7 +42,9 @@ #include "core/window-private.h" #include "core/workspace-private.h" #include "meta/common.h" +#include "meta/compositor.h" #include "meta/meta-cursor-tracker.h" +#include "meta/meta-later.h" #include "meta/meta-x11-errors.h" #include "meta/prefs.h" #include "x11/meta-x11-display-private.h" @@ -1773,23 +1775,88 @@ meta_window_x11_get_default_skip_hints (MetaWindow *window, *skip_pager_out = priv->wm_state_skip_pager; } +static void +meta_window_x11_update_icon (MetaWindowX11 *window_x11, + gboolean force) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaWindow *window = META_WINDOW (window_x11); + cairo_surface_t *icon = NULL; + cairo_surface_t *mini_icon = NULL; + gboolean changed; + + changed = meta_read_icons (window->display->x11_display, + window->xwindow, + &priv->icon_cache, + priv->wm_hints_pixmap, + priv->wm_hints_mask, + &icon, + META_ICON_WIDTH, META_ICON_HEIGHT, + &mini_icon, + META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT); + + if (changed || force) + { + g_clear_pointer (&priv->icon, cairo_surface_destroy); + g_clear_pointer (&priv->mini_icon, cairo_surface_destroy); + priv->icon = icon; + priv->mini_icon = mini_icon; + + g_object_freeze_notify (G_OBJECT (window)); + g_object_notify (G_OBJECT (window), "icon"); + g_object_notify (G_OBJECT (window), "mini-icon"); + g_object_thaw_notify (G_OBJECT (window)); + + if (window->frame) + meta_frame_queue_draw (window->frame); + } +} + static gboolean -meta_window_x11_update_icon (MetaWindow *window, - cairo_surface_t **icon, - cairo_surface_t **mini_icon) +update_icon_before_redraw (gpointer user_data) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (user_data); + + meta_window_x11_update_icon (window_x11, FALSE); + + return G_SOURCE_REMOVE; +} + +void +meta_window_x11_queue_update_icon (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = + meta_window_x11_get_instance_private (window_x11); + MetaWindow *window = META_WINDOW (window_x11); + MetaDisplay *display = meta_window_get_display (window); + MetaCompositor *compositor = meta_display_get_compositor (display); + + priv->update_icon_handle_id = + meta_laters_add (meta_compositor_get_laters (compositor), + META_LATER_BEFORE_REDRAW, + update_icon_before_redraw, + window, + NULL); +} + +static cairo_surface_t * +meta_window_x11_get_icon (MetaWindow *window) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaWindowX11Private *priv = + meta_window_x11_get_instance_private (window_x11); - return meta_read_icons (window->display->x11_display, - window->xwindow, - &priv->icon_cache, - priv->wm_hints_pixmap, - priv->wm_hints_mask, - icon, - META_ICON_WIDTH, META_ICON_HEIGHT, - mini_icon, - META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT); + return priv->icon; +} + +static cairo_surface_t * +meta_window_x11_get_mini_icon (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = + meta_window_x11_get_instance_private (window_x11); + + return priv->mini_icon; } static void @@ -2069,11 +2136,36 @@ meta_window_x11_is_focus_async (MetaWindow *window) return !window->input && priv->wm_take_focus; } +static void +meta_window_x11_dispose (GObject *object) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (object); + MetaWindowX11Private *priv = + meta_window_x11_get_instance_private (window_x11); + MetaWindow *window = META_WINDOW (window_x11); + MetaDisplay *display = meta_window_get_display (window); + MetaCompositor *compositor = meta_display_get_compositor (display); + + if (priv->update_icon_handle_id) + { + meta_laters_remove (meta_compositor_get_laters (compositor), + priv->update_icon_handle_id); + } + + g_clear_pointer (&priv->icon, cairo_surface_destroy); + g_clear_pointer (&priv->mini_icon, cairo_surface_destroy); + + G_OBJECT_CLASS (meta_window_x11_parent_class)->dispose (object); +} + static void meta_window_x11_class_init (MetaWindowX11Class *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaWindowClass *window_class = META_WINDOW_CLASS (klass); + object_class->dispose = meta_window_x11_dispose; + window_class->manage = meta_window_x11_manage; window_class->unmanage = meta_window_x11_unmanage; window_class->ping = meta_window_x11_ping; @@ -2086,7 +2178,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass) window_class->move_resize_internal = meta_window_x11_move_resize_internal; window_class->update_struts = meta_window_x11_update_struts; window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints; - window_class->update_icon = meta_window_x11_update_icon; + window_class->get_icon = meta_window_x11_get_icon; + window_class->get_mini_icon = meta_window_x11_get_mini_icon; window_class->update_main_monitor = meta_window_x11_update_main_monitor; window_class->main_monitor_changed = meta_window_x11_main_monitor_changed; window_class->get_client_pid = meta_window_x11_get_client_pid; @@ -3692,6 +3785,9 @@ meta_window_x11_new (MetaDisplay *display, priv->border_width = attrs.border_width; + if (!window->override_redirect) + meta_window_x11_update_icon (window_x11, TRUE); + meta_window_grab_keys (window); if (window->type != META_WINDOW_DOCK && !window->override_redirect) {