diff options
Diffstat (limited to 'src/compositor/meta-window-actor-x11.c')
-rw-r--r-- | src/compositor/meta-window-actor-x11.c | 1693 |
1 files changed, 0 insertions, 1693 deletions
diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c deleted file mode 100644 index e18b1b28b..000000000 --- a/src/compositor/meta-window-actor-x11.c +++ /dev/null @@ -1,1693 +0,0 @@ -/* - * Copyright (C) 2018 Endless, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Written by: - * Georges Basile Stavracas Neto <gbsneto@gnome.org> - */ - -#include "config.h" - -#include "compositor/meta-window-actor-x11.h" - -#include "backends/meta-logical-monitor.h" -#include "clutter/clutter-frame-clock.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/meta-surface-actor.h" -#include "compositor/meta-surface-actor-x11.h" -#include "compositor/region-utils.h" -#include "core/frame.h" -#include "core/window-private.h" -#include "meta/compositor.h" -#include "meta/meta-enum-types.h" -#include "meta/meta-shadow-factory.h" -#include "meta/meta-window-actor.h" -#include "meta/meta-x11-errors.h" -#include "meta/window.h" -#include "x11/window-x11.h" -#include "x11/meta-x11-display-private.h" -#include "x11/window-x11.h" - -enum -{ - PROP_SHADOW_MODE = 1, - PROP_SHADOW_CLASS -}; - -struct _MetaWindowActorX11 -{ - MetaWindowActor parent; - - /* List of FrameData for recent frames */ - GList *frames; - - guint send_frame_messages_timer; - int64_t frame_drawn_time; - gboolean pending_schedule_update_now; - ClutterFrameClock *frame_clock; - - gulong repaint_scheduled_id; - gulong size_changed_id; - - /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN - * client message for one or more messages in ->frames */ - gboolean needs_frame_drawn; - gboolean repaint_scheduled; - - /* - * MetaShadowFactory only caches shadows that are actually in use; - * to avoid unnecessary recomputation we do two things: 1) we store - * both a focused and unfocused shadow for the window. If the window - * doesn't have different focused and unfocused shadow parameters, - * these will be the same. 2) when the shadow potentially changes we - * don't immediately unreference the old shadow, we just flag it as - * dirty and recompute it when we next need it (recompute_focused_shadow, - * recompute_unfocused_shadow.) Because of our extraction of - * size-invariant window shape, we'll often find that the new shadow - * is the same as the old shadow. - */ - MetaShadow *focused_shadow; - MetaShadow *unfocused_shadow; - - /* A region that matches the shape of the window, including frame bounds */ - cairo_region_t *shape_region; - /* The region we should clip to when painting the shadow */ - cairo_region_t *shadow_clip; - /* The frame region */ - cairo_region_t *frame_bounds; - - /* Extracted size-invariant shape used for shadows */ - MetaWindowShape *shadow_shape; - char *shadow_class; - - MetaShadowFactory *shadow_factory; - gulong shadow_factory_changed_handler_id; - - MetaShadowMode shadow_mode; - - gboolean needs_reshape; - gboolean recompute_focused_shadow; - gboolean recompute_unfocused_shadow; - gboolean is_frozen; -}; - -static MetaCullableInterface *cullable_parent_iface; - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaWindowActorX11, meta_window_actor_x11, META_TYPE_WINDOW_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)) - -/* Each time the application updates the sync request counter to a new even value - * value, we queue a frame into the windows list of frames. Once we're painting - * an update "in response" to the window, we fill in frame_counter with the - * Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the - * frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback. - * - * As an exception, if a window is completely obscured, we try to throttle drawning - * to a slower frame rate. In this case, frame_counter stays -1 until - * send_frame_message_timeout() runs, at which point we send both the - * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages. - */ -typedef struct -{ - uint64_t sync_request_serial; - int64_t frame_counter; - int64_t frame_drawn_time; -} FrameData; - -static void -frame_data_free (FrameData *frame) -{ - g_free (frame); -} - -static void -surface_repaint_scheduled (MetaSurfaceActor *actor, - gpointer user_data) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data); - - actor_x11->repaint_scheduled = TRUE; -} - -static void -remove_frame_messages_timer (MetaWindowActorX11 *actor_x11) -{ - g_assert (actor_x11->send_frame_messages_timer != 0); - - g_clear_handle_id (&actor_x11->send_frame_messages_timer, g_source_remove); -} - -static void -do_send_frame_drawn (MetaWindowActorX11 *actor_x11, - FrameData *frame) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaDisplay *display = meta_window_get_display (window); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - int64_t now_us; - - XClientMessageEvent ev = { 0, }; - - now_us = g_get_monotonic_time (); - frame->frame_drawn_time = - meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, - now_us); - actor_x11->frame_drawn_time = frame->frame_drawn_time; - - ev.type = ClientMessage; - ev.window = meta_window_get_xwindow (window); - ev.message_type = display->x11_display->atom__NET_WM_FRAME_DRAWN; - ev.format = 32; - ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[1] = frame->sync_request_serial >> 32; - ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[3] = frame->frame_drawn_time >> 32; - - meta_x11_error_trap_push (display->x11_display); - XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); - XFlush (xdisplay); - meta_x11_error_trap_pop (display->x11_display); -} - -static void -do_send_frame_timings (MetaWindowActorX11 *actor_x11, - FrameData *frame, - int refresh_interval, - int64_t presentation_time) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaDisplay *display = meta_window_get_display (window); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - XClientMessageEvent ev = { 0, }; - - ev.type = ClientMessage; - ev.window = meta_window_get_xwindow (window); - ev.message_type = display->x11_display->atom__NET_WM_FRAME_TIMINGS; - ev.format = 32; - ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[1] = frame->sync_request_serial >> 32; - - if (presentation_time != 0) - { - MetaCompositor *compositor = display->compositor; - int64_t presentation_time_server; - - presentation_time_server = - meta_compositor_monotonic_to_high_res_xserver_time (compositor, - presentation_time); - int64_t presentation_time_offset = presentation_time_server - frame->frame_drawn_time; - if (presentation_time_offset == 0) - presentation_time_offset = 1; - - if ((int32_t)presentation_time_offset == presentation_time_offset) - ev.data.l[2] = presentation_time_offset; - } - - ev.data.l[3] = refresh_interval; - ev.data.l[4] = 1000 * META_SYNC_DELAY; - - meta_x11_error_trap_push (display->x11_display); - XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); - XFlush (xdisplay); - meta_x11_error_trap_pop (display->x11_display); -} - -static void -send_frame_timings (MetaWindowActorX11 *actor_x11, - FrameData *frame, - ClutterFrameInfo *frame_info, - int64_t presentation_time) -{ - float refresh_rate; - int refresh_interval; - - refresh_rate = frame_info->refresh_rate; - /* 0.0 is a flag for not known, but sanity-check against other odd numbers */ - if (refresh_rate >= 1.0) - refresh_interval = (int) (0.5 + 1000000 / refresh_rate); - else - refresh_interval = 0; - - do_send_frame_timings (actor_x11, frame, refresh_interval, presentation_time); -} - -static gboolean -send_frame_messages_timeout (gpointer data) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (data); - GList *l; - - for (l = actor_x11->frames; l;) - { - GList *l_next = l->next; - FrameData *frame = l->data; - - if (frame->frame_counter == -1) - { - do_send_frame_drawn (actor_x11, frame); - do_send_frame_timings (actor_x11, frame, 0, 0); - - actor_x11->frames = g_list_delete_link (actor_x11->frames, l); - frame_data_free (frame); - } - - l = l_next; - } - - actor_x11->needs_frame_drawn = FALSE; - actor_x11->send_frame_messages_timer = 0; - - return G_SOURCE_REMOVE; -} - -static void -queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaDisplay *display = meta_window_get_display (window); - MetaLogicalMonitor *logical_monitor; - int64_t now_us; - int64_t current_time; - float refresh_rate; - int interval, offset; - - if (actor_x11->send_frame_messages_timer != 0) - return; - - logical_monitor = meta_window_get_main_logical_monitor (window); - if (logical_monitor) - { - GList *monitors = meta_logical_monitor_get_monitors (logical_monitor); - MetaMonitor *monitor; - MetaMonitorMode *mode; - - monitor = g_list_first (monitors)->data; - mode = meta_monitor_get_current_mode (monitor); - - refresh_rate = meta_monitor_mode_get_refresh_rate (mode); - } - else - { - refresh_rate = 60.0f; - } - - now_us = g_get_monotonic_time (); - current_time = - meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, - now_us); - interval = (int) (1000000 / refresh_rate) * 6; - offset = MAX (0, actor_x11->frame_drawn_time + interval - current_time) / 1000; - - /* The clutter master clock source has already been added with META_PRIORITY_REDRAW, - * so the timer will run *after* the clutter frame handling, if a frame is ready - * to be drawn when the timer expires. - */ - actor_x11->send_frame_messages_timer = - g_timeout_add_full (META_PRIORITY_REDRAW, offset, - send_frame_messages_timeout, - actor_x11, NULL); - g_source_set_name_by_id (actor_x11->send_frame_messages_timer, - "[mutter] send_frame_messages_timeout"); -} - -static void -assign_frame_counter_to_frames (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaCompositor *compositor = window->display->compositor; - ClutterStage *stage = meta_compositor_get_stage (compositor); - GList *l; - - /* If the window is obscured, then we're expecting to deal with sending - * frame messages in a timeout, rather than in this paint cycle. - */ - if (actor_x11->send_frame_messages_timer != 0) - return; - - for (l = actor_x11->frames; l; l = l->next) - { - FrameData *frame = l->data; - - if (frame->frame_counter == -1) - frame->frame_counter = clutter_stage_get_frame_counter (stage); - } -} - -static void -meta_window_actor_x11_frame_complete (MetaWindowActor *actor, - ClutterFrameInfo *frame_info, - int64_t presentation_time) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - GList *l; - - if (meta_window_actor_is_destroyed (actor)) - return; - - for (l = actor_x11->frames; l;) - { - GList *l_next = l->next; - FrameData *frame = l->data; - int64_t frame_counter = frame_info->frame_counter; - - if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter) - { - MetaWindow *window = - meta_window_actor_get_meta_window (actor); - - if (G_UNLIKELY (frame->frame_drawn_time == 0)) - g_warning ("%s: Frame has assigned frame counter but no frame drawn time", - window->desc); - if (G_UNLIKELY (frame->frame_counter < frame_counter)) - g_debug ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, - window->desc, frame->frame_counter); - - actor_x11->frames = g_list_delete_link (actor_x11->frames, l); - send_frame_timings (actor_x11, frame, frame_info, presentation_time); - frame_data_free (frame); - } - - l = l_next; - } -} - -static void -surface_size_changed (MetaSurfaceActor *actor, - gpointer user_data) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data); - - meta_window_actor_x11_update_shape (actor_x11); -} - -static void -meta_window_actor_x11_assign_surface_actor (MetaWindowActor *actor, - MetaSurfaceActor *surface_actor) -{ - MetaWindowActorClass *parent_class = - META_WINDOW_ACTOR_CLASS (meta_window_actor_x11_parent_class); - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaSurfaceActor *prev_surface_actor; - - prev_surface_actor = meta_window_actor_get_surface (actor); - if (prev_surface_actor) - { - g_warn_if_fail (meta_is_wayland_compositor ()); - - g_clear_signal_handler (&actor_x11->size_changed_id, prev_surface_actor); - clutter_actor_remove_child (CLUTTER_ACTOR (actor), - CLUTTER_ACTOR (prev_surface_actor)); - } - - parent_class->assign_surface_actor (actor, surface_actor); - - clutter_actor_add_child (CLUTTER_ACTOR (actor), - CLUTTER_ACTOR (surface_actor)); - - meta_window_actor_x11_update_shape (actor_x11); - - actor_x11->size_changed_id = - g_signal_connect (surface_actor, "size-changed", - G_CALLBACK (surface_size_changed), - actor_x11); - actor_x11->repaint_scheduled_id = - g_signal_connect (surface_actor, "repaint-scheduled", - G_CALLBACK (surface_repaint_scheduled), - actor_x11); -} - -static void -meta_window_actor_x11_queue_frame_drawn (MetaWindowActor *actor, - gboolean skip_sync_delay) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window = - meta_window_actor_get_meta_window (actor); - FrameData *frame; - - if (meta_window_actor_is_destroyed (actor)) - return; - - frame = g_new0 (FrameData, 1); - frame->frame_counter = -1; - frame->sync_request_serial = window->sync_request_serial; - - actor_x11->frames = g_list_prepend (actor_x11->frames, frame); - - actor_x11->needs_frame_drawn = TRUE; - - if (skip_sync_delay) - { - if (actor_x11->frame_clock) - clutter_frame_clock_schedule_update_now (actor_x11->frame_clock); - else - actor_x11->pending_schedule_update_now = TRUE; - } - - if (!actor_x11->repaint_scheduled) - { - MetaSurfaceActor *surface; - gboolean is_obscured; - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - - if (surface) - is_obscured = meta_surface_actor_is_obscured (surface); - else - is_obscured = FALSE; - - /* A frame was marked by the client without actually doing any - * damage or any unobscured, or while we had the window frozen - * (e.g. during an interactive resize.) We need to make sure that the - * before_paint/after_paint functions get called, enabling us to - * send a _NET_WM_FRAME_DRAWN. We need to do full damage to ensure that - * the window is actually repainted, otherwise any subregion we would pass - * might end up being either outside of any stage view, or be occluded by - * something else, which could potentially result in no frame being drawn - * after all. If the window is completely obscured, or completely off - * screen we fire off the send_frame_messages timeout. - */ - if (is_obscured || - !clutter_actor_peek_stage_views (CLUTTER_ACTOR (actor))) - { - queue_send_frame_messages_timeout (actor_x11); - } - else if (surface) - { - clutter_actor_queue_redraw (CLUTTER_ACTOR (surface)); - actor_x11->repaint_scheduled = TRUE; - } - } -} - -static gboolean -has_shadow (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - - if (actor_x11->shadow_mode == META_SHADOW_MODE_FORCED_OFF) - return FALSE; - if (actor_x11->shadow_mode == META_SHADOW_MODE_FORCED_ON) - return TRUE; - - /* Leaving out shadows for maximized and fullscreen windows is an efficiency - * win and also prevents the unsightly effect of the shadow of maximized - * window appearing on an adjacent window */ - if ((meta_window_get_maximized (window) == META_MAXIMIZE_BOTH) || - meta_window_is_fullscreen (window)) - return FALSE; - - /* - * If we have two snap-tiled windows, we don't want the shadow to obstruct - * the other window. - */ - if (meta_window_get_tile_match (window)) - return FALSE; - - /* - * Always put a shadow around windows with a frame - This should override - * the restriction about not putting a shadow around ARGB windows. - */ - if (meta_window_get_frame (window)) - return TRUE; - - /* - * Do not add shadows to non-opaque (ARGB32) windows, as we can't easily - * generate shadows for them. - */ - if (!meta_window_actor_is_opaque (META_WINDOW_ACTOR (actor_x11))) - return FALSE; - - /* - * If a window specifies that it has custom frame extents, that likely - * means that it is drawing a shadow itself. Don't draw our own. - */ - if (window->has_custom_frame_extents) - return FALSE; - - /* - * Generate shadows for all other windows. - */ - return TRUE; -} - -gboolean -meta_window_actor_x11_should_unredirect (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaSurfaceActor *surface; - MetaSurfaceActorX11 *surface_x11; - - if (meta_window_actor_is_destroyed (META_WINDOW_ACTOR (actor_x11))) - return FALSE; - - if (!meta_window_x11_can_unredirect (window_x11)) - return FALSE; - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - if (!surface) - return FALSE; - - if (!META_IS_SURFACE_ACTOR_X11 (surface)) - return FALSE; - - surface_x11 = META_SURFACE_ACTOR_X11 (surface); - return meta_surface_actor_x11_should_unredirect (surface_x11); -} - -void -meta_window_actor_x11_set_unredirected (MetaWindowActorX11 *actor_x11, - gboolean unredirected) -{ - MetaSurfaceActor *surface; - MetaSurfaceActorX11 *surface_x11; - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - g_assert (surface); - - g_return_if_fail (META_IS_SURFACE_ACTOR_X11 (surface)); - - surface_x11 = META_SURFACE_ACTOR_X11 (surface); - meta_surface_actor_x11_set_unredirected (surface_x11, unredirected); -} - -static const char * -get_shadow_class (MetaWindowActorX11 *actor_x11) -{ - if (actor_x11->shadow_class) - { - return actor_x11->shadow_class; - } - else - { - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaWindowType window_type; - - window_type = meta_window_get_window_type (window); - switch (window_type) - { - case META_WINDOW_DROPDOWN_MENU: - case META_WINDOW_COMBO: - return "dropdown-menu"; - case META_WINDOW_POPUP_MENU: - return "popup-menu"; - default: - { - MetaFrameType frame_type; - - frame_type = meta_window_get_frame_type (window); - return meta_frame_type_to_string (frame_type); - } - } - } -} - -static void -get_shadow_params (MetaWindowActorX11 *actor_x11, - gboolean appears_focused, - MetaShadowParams *params) -{ - const char *shadow_class = get_shadow_class (actor_x11); - - meta_shadow_factory_get_params (actor_x11->shadow_factory, - shadow_class, appears_focused, - params); -} - -static void -get_shape_bounds (MetaWindowActorX11 *actor_x11, - cairo_rectangle_int_t *bounds) -{ - cairo_region_get_extents (actor_x11->shape_region, bounds); -} - -static void -get_shadow_bounds (MetaWindowActorX11 *actor_x11, - gboolean appears_focused, - cairo_rectangle_int_t *bounds) -{ - MetaShadow *shadow; - cairo_rectangle_int_t shape_bounds; - MetaShadowParams params; - - shadow = appears_focused ? actor_x11->focused_shadow - : actor_x11->unfocused_shadow; - - get_shape_bounds (actor_x11, &shape_bounds); - get_shadow_params (actor_x11, appears_focused, ¶ms); - - meta_shadow_get_bounds (shadow, - params.x_offset + shape_bounds.x, - params.y_offset + shape_bounds.y, - shape_bounds.width, - shape_bounds.height, - bounds); -} - -/* If we have an ARGB32 window that we decorate with a frame, it's - * probably something like a translucent terminal - something where - * the alpha channel represents transparency rather than a shape. We - * don't want to show the shadow through the translucent areas since - * the shadow is wrong for translucent windows (it should be - * translucent itself and colored), and not only that, will /look/ - * horribly wrong - a misplaced big black blob. As a hack, what we - * want to do is just draw the shadow as normal outside the frame, and - * inside the frame draw no shadow. This is also not even close to - * the right result, but looks OK. We also apply this approach to - * windows set to be partially translucent with _NET_WM_WINDOW_OPACITY. - */ -static gboolean -clip_shadow_under_window (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - - if (window->frame) - return TRUE; - - return meta_window_actor_is_opaque (META_WINDOW_ACTOR (actor_x11)); -} - -/** - * set_clip_region_beneath: - * @actor_x11: a #MetaWindowActorX11 - * @clip_region: the region of the screen that isn't completely - * obscured beneath the main window texture. - * - * Provides a hint as to what areas need to be drawn *beneath* - * the main window texture. This is the relevant clip region - * when drawing the shadow, properly accounting for areas of the - * shadow hid by the window itself. This will be set before painting - * then unset afterwards. - */ -static void -set_clip_region_beneath (MetaWindowActorX11 *actor_x11, - cairo_region_t *beneath_region) -{ - MetaWindow *window; - gboolean appears_focused; - - window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - appears_focused = meta_window_appears_focused (window); - if (appears_focused ? actor_x11->focused_shadow : actor_x11->unfocused_shadow) - { - g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy); - - if (beneath_region) - { - actor_x11->shadow_clip = cairo_region_copy (beneath_region); - - if (clip_shadow_under_window (actor_x11)) - { - if (actor_x11->frame_bounds) - cairo_region_subtract (actor_x11->shadow_clip, actor_x11->frame_bounds); - } - } - else - { - actor_x11->shadow_clip = NULL; - } - } -} - -static void -check_needs_shadow (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaShadow *old_shadow = NULL; - MetaShadow **shadow_location; - gboolean recompute_shadow; - gboolean should_have_shadow; - gboolean appears_focused; - - /* Calling has_shadow() here at every pre-paint is cheap - * and avoids the need to explicitly handle window type changes, which - * we would do if tried to keep track of when we might be adding or removing - * a shadow more explicitly. We only keep track of changes to the *shape* of - * the shadow with actor_x11->recompute_shadow. - */ - - should_have_shadow = has_shadow (actor_x11); - appears_focused = meta_window_appears_focused (window); - - if (appears_focused) - { - recompute_shadow = actor_x11->recompute_focused_shadow; - actor_x11->recompute_focused_shadow = FALSE; - shadow_location = &actor_x11->focused_shadow; - } - else - { - recompute_shadow = actor_x11->recompute_unfocused_shadow; - actor_x11->recompute_unfocused_shadow = FALSE; - shadow_location = &actor_x11->unfocused_shadow; - } - - if (!should_have_shadow || recompute_shadow) - { - if (*shadow_location != NULL) - { - old_shadow = *shadow_location; - *shadow_location = NULL; - } - } - - if (!*shadow_location && should_have_shadow) - { - MetaShadowFactory *factory = actor_x11->shadow_factory; - const char *shadow_class = get_shadow_class (actor_x11); - cairo_rectangle_int_t shape_bounds; - - if (!actor_x11->shadow_shape) - { - actor_x11->shadow_shape = - meta_window_shape_new (actor_x11->shape_region); - } - - get_shape_bounds (actor_x11, &shape_bounds); - *shadow_location = - meta_shadow_factory_get_shadow (factory, - actor_x11->shadow_shape, - shape_bounds.width, shape_bounds.height, - shadow_class, appears_focused); - } - - if (old_shadow) - meta_shadow_unref (old_shadow); -} - -void -meta_window_actor_x11_process_damage (MetaWindowActorX11 *actor_x11, - XDamageNotifyEvent *event) -{ - MetaSurfaceActor *surface; - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - if (surface) - meta_surface_actor_process_damage (surface, - event->area.x, - event->area.y, - event->area.width, - event->area.height); - - meta_window_actor_notify_damaged (META_WINDOW_ACTOR (actor_x11)); -} - -static cairo_region_t * -scan_visible_region (guchar *mask_data, - int stride, - cairo_region_t *scan_area) -{ - int i, n_rects = cairo_region_num_rectangles (scan_area); - MetaRegionBuilder builder; - - meta_region_builder_init (&builder); - - for (i = 0; i < n_rects; i++) - { - int x, y; - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (scan_area, i, &rect); - - for (y = rect.y; y < (rect.y + rect.height); y++) - { - for (x = rect.x; x < (rect.x + rect.width); x++) - { - int x2 = x; - while (mask_data[y * stride + x2] == 255 && x2 < (rect.x + rect.width)) - x2++; - - if (x2 > x) - { - meta_region_builder_add_rectangle (&builder, x, y, x2 - x, 1); - x = x2; - } - } - } - } - - return meta_region_builder_finish (&builder); -} - -static void -get_client_area_rect_from_texture (MetaWindowActorX11 *actor_x11, - MetaShapedTexture *shaped_texture, - cairo_rectangle_int_t *client_area) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - cairo_rectangle_int_t surface_rect = { 0 }; - - surface_rect.width = meta_shaped_texture_get_width (shaped_texture); - surface_rect.height = meta_shaped_texture_get_height (shaped_texture); - meta_window_x11_surface_rect_to_client_rect (window, - &surface_rect, - client_area); -} - -static void -get_client_area_rect (MetaWindowActorX11 *actor_x11, - cairo_rectangle_int_t *client_area) -{ - MetaSurfaceActor *surface = - meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaShapedTexture *stex = meta_surface_actor_get_texture (surface); - - if (!meta_window_x11_always_update_shape (window) || !stex) - { - meta_window_get_client_area_rect (window, client_area); - return; - } - - get_client_area_rect_from_texture (actor_x11, stex, client_area); -} - -static void -build_and_scan_frame_mask (MetaWindowActorX11 *actor_x11, - cairo_region_t *shape_region) -{ - ClutterBackend *backend = clutter_get_default_backend (); - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - CoglContext *ctx = clutter_backend_get_cogl_context (backend); - MetaSurfaceActor *surface = - meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - uint8_t *mask_data; - unsigned int tex_width, tex_height; - MetaShapedTexture *stex; - CoglTexture2D *mask_texture; - int stride; - cairo_t *cr; - cairo_surface_t *image; - GError *error = NULL; - - stex = meta_surface_actor_get_texture (surface); - g_return_if_fail (stex); - - meta_shaped_texture_set_mask_texture (stex, NULL); - - tex_width = meta_shaped_texture_get_width (stex); - tex_height = meta_shaped_texture_get_height (stex); - - stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); - - /* Create data for an empty image */ - mask_data = g_malloc0 (stride * tex_height); - - image = cairo_image_surface_create_for_data (mask_data, - CAIRO_FORMAT_A8, - tex_width, - tex_height, - stride); - cr = cairo_create (image); - - gdk_cairo_region (cr, shape_region); - cairo_fill (cr); - - if (window->frame) - { - cairo_region_t *frame_paint_region, *scanned_region; - cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height }; - cairo_rectangle_int_t client_area; - cairo_rectangle_int_t frame_rect; - - /* If we update the shape regardless of the frozen state of the actor, - * as with Xwayland to avoid the black shadow effect, we ought to base - * the frame size on the buffer size rather than the reported window's - * frame size, as the buffer may not have been committed yet at this - * point. - */ - if (meta_window_x11_always_update_shape (window)) - { - meta_window_x11_surface_rect_to_frame_rect (window, &rect, &frame_rect); - get_client_area_rect_from_texture (actor_x11, stex, &client_area); - } - else - { - meta_window_get_frame_rect (window, &frame_rect); - meta_window_get_client_area_rect (window, &client_area); - } - - /* Make sure we don't paint the frame over the client window. */ - frame_paint_region = cairo_region_create_rectangle (&rect); - cairo_region_subtract_rectangle (frame_paint_region, &client_area); - - gdk_cairo_region (cr, frame_paint_region); - cairo_clip (cr); - - meta_frame_get_mask (window->frame, &frame_rect, cr); - - cairo_surface_flush (image); - scanned_region = scan_visible_region (mask_data, stride, frame_paint_region); - cairo_region_union (shape_region, scanned_region); - cairo_region_destroy (scanned_region); - cairo_region_destroy (frame_paint_region); - } - - cairo_destroy (cr); - cairo_surface_destroy (image); - - mask_texture = cogl_texture_2d_new_from_data (ctx, tex_width, tex_height, - COGL_PIXEL_FORMAT_A_8, - stride, mask_data, &error); - - if (error) - { - g_warning ("Failed to allocate mask texture: %s", error->message); - g_error_free (error); - } - - if (mask_texture) - { - meta_shaped_texture_set_mask_texture (stex, COGL_TEXTURE (mask_texture)); - cogl_object_unref (mask_texture); - } - else - { - meta_shaped_texture_set_mask_texture (stex, NULL); - } - - g_free (mask_data); -} - -static void -invalidate_shadow (MetaWindowActorX11 *actor_x11) -{ - actor_x11->recompute_focused_shadow = TRUE; - actor_x11->recompute_unfocused_shadow = TRUE; - - if (meta_window_actor_is_frozen (META_WINDOW_ACTOR (actor_x11))) - return; - - clutter_actor_queue_redraw (CLUTTER_ACTOR (actor_x11)); - clutter_actor_invalidate_paint_volume (CLUTTER_ACTOR (actor_x11)); -} - -static void -update_shape_region (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - cairo_region_t *region = NULL; - cairo_rectangle_int_t client_area; - - get_client_area_rect (actor_x11, &client_area); - - if (window->frame && window->shape_region) - { - region = cairo_region_copy (window->shape_region); - cairo_region_translate (region, client_area.x, client_area.y); - } - else if (window->shape_region != NULL) - { - region = cairo_region_reference (window->shape_region); - } - else - { - /* If we don't have a shape on the server, that means that - * we have an implicit shape of one rectangle covering the - * entire window. */ - region = cairo_region_create_rectangle (&client_area); - } - - if (window->shape_region || window->frame) - build_and_scan_frame_mask (actor_x11, region); - - g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy); - actor_x11->shape_region = region; - - g_clear_pointer (&actor_x11->shadow_shape, meta_window_shape_unref); - - invalidate_shadow (actor_x11); -} - -static void -update_input_region (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaSurfaceActor *surface = - meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - cairo_region_t *region; - - if (window->shape_region && window->input_region) - { - region = cairo_region_copy (window->shape_region); - cairo_region_intersect (region, window->input_region); - } - else if (window->shape_region) - { - region = cairo_region_reference (window->shape_region); - } - else if (window->input_region) - { - region = cairo_region_reference (window->input_region); - } - else - { - region = NULL; - } - - meta_surface_actor_set_input_region (surface, region); - cairo_region_destroy (region); -} - -static gboolean -is_actor_maybe_transparent (MetaWindowActorX11 *actor_x11) -{ - MetaSurfaceActor *surface; - MetaShapedTexture *stex; - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - if (!surface) - return TRUE; - - if (META_IS_SURFACE_ACTOR_X11 (surface) && - meta_surface_actor_x11_is_unredirected (META_SURFACE_ACTOR_X11 (surface))) - return FALSE; - - stex = meta_surface_actor_get_texture (surface); - if (!meta_shaped_texture_has_alpha (stex)) - return FALSE; - - return TRUE; -} - -static void -update_opaque_region (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - gboolean is_maybe_transparent; - cairo_region_t *opaque_region; - MetaSurfaceActor *surface; - - is_maybe_transparent = is_actor_maybe_transparent (actor_x11); - if (is_maybe_transparent && window->opaque_region) - { - cairo_rectangle_int_t client_area; - - get_client_area_rect (actor_x11, &client_area); - - /* The opaque region is defined to be a part of the - * window which ARGB32 will always paint with opaque - * pixels. For these regions, we want to avoid painting - * windows and shadows beneath them. - * - * If the client gives bad coordinates where it does not - * fully paint, the behavior is defined by the specification - * to be undefined, and considered a client bug. In mutter's - * case, graphical glitches will occur. - */ - opaque_region = cairo_region_copy (window->opaque_region); - cairo_region_translate (opaque_region, client_area.x, client_area.y); - cairo_region_intersect (opaque_region, actor_x11->shape_region); - } - else if (is_maybe_transparent) - { - opaque_region = NULL; - } - else - { - opaque_region = cairo_region_reference (actor_x11->shape_region); - } - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - meta_surface_actor_set_opaque_region (surface, opaque_region); - cairo_region_destroy (opaque_region); -} - -static void -update_frame_bounds (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - - g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy); - actor_x11->frame_bounds = - cairo_region_copy (meta_window_get_frame_bounds (window)); -} - -static void -update_regions (MetaWindowActorX11 *actor_x11) -{ - if (!actor_x11->needs_reshape) - return; - - update_shape_region (actor_x11); - update_input_region (actor_x11); - update_opaque_region (actor_x11); - - actor_x11->needs_reshape = FALSE; -} - -static void -check_needs_reshape (MetaWindowActorX11 *actor_x11) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - - if (meta_window_x11_always_update_shape (window)) - return; - - update_regions (actor_x11); -} - -void -meta_window_actor_x11_update_shape (MetaWindowActorX11 *actor_x11) -{ - MetaSurfaceActor *surface = - meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - - actor_x11->needs_reshape = TRUE; - - if (meta_window_actor_is_frozen (META_WINDOW_ACTOR (actor_x11))) - return; - - clutter_actor_queue_redraw (CLUTTER_ACTOR (surface)); -} - -static void -handle_updates (MetaWindowActorX11 *actor_x11) -{ - MetaSurfaceActor *surface = - meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - MetaWindow *window; - - if (META_IS_SURFACE_ACTOR_X11 (surface) && - meta_surface_actor_x11_is_unredirected (META_SURFACE_ACTOR_X11 (surface))) - return; - - window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - if (meta_window_actor_is_frozen (META_WINDOW_ACTOR (actor_x11))) - { - /* The window is frozen due to a pending animation: we'll wait until - * the animation finishes to repair the window. - * - * However, with Xwayland, we still might need to update the shape - * region as the wl_buffer will be set to plain black on resize, - * which causes the shadows to look bad. - */ - if (surface && meta_window_x11_always_update_shape (window)) - check_needs_reshape (actor_x11); - - return; - } - - if (META_IS_SURFACE_ACTOR_X11 (surface)) - { - MetaSurfaceActorX11 *surface_x11 = META_SURFACE_ACTOR_X11 (surface); - - meta_surface_actor_x11_handle_updates (surface_x11); - } - - if (META_IS_SURFACE_ACTOR_X11 (surface) && - !meta_surface_actor_x11_is_visible (META_SURFACE_ACTOR_X11 (surface))) - return; - - update_frame_bounds (actor_x11); - check_needs_reshape (actor_x11); - check_needs_shadow (actor_x11); -} - -static void -handle_stage_views_changed (MetaWindowActorX11 *actor_x11) -{ - ClutterActor *actor = CLUTTER_ACTOR (actor_x11); - - actor_x11->frame_clock = clutter_actor_pick_frame_clock (actor, NULL); - if (actor_x11->frame_clock && actor_x11->pending_schedule_update_now) - { - clutter_frame_clock_schedule_update_now (actor_x11->frame_clock); - actor_x11->pending_schedule_update_now = FALSE; - } -} - -static void -meta_window_actor_x11_before_paint (MetaWindowActor *actor, - ClutterStageView *stage_view) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - - handle_updates (actor_x11); - - assign_frame_counter_to_frames (actor_x11); -} - -static void -meta_window_actor_x11_paint (ClutterActor *actor, - ClutterPaintContext *paint_context) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window; - gboolean appears_focused; - MetaShadow *shadow; - - /* This window got damage when obscured; we set up a timer - * to send frame completion events, but since we're drawing - * the window now (for some other reason) cancel the timer - * and send the completion events normally */ - if (actor_x11->send_frame_messages_timer != 0) - { - remove_frame_messages_timer (actor_x11); - assign_frame_counter_to_frames (actor_x11); - } - - window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - appears_focused = meta_window_appears_focused (window); - shadow = appears_focused ? actor_x11->focused_shadow - : actor_x11->unfocused_shadow; - - if (shadow) - { - MetaShadowParams params; - cairo_rectangle_int_t shape_bounds; - cairo_region_t *clip = actor_x11->shadow_clip; - CoglFramebuffer *framebuffer; - - get_shape_bounds (actor_x11, &shape_bounds); - get_shadow_params (actor_x11, appears_focused, ¶ms); - - /* The frame bounds are already subtracted from actor_x11->shadow_clip - * if that exists. - */ - if (!clip && clip_shadow_under_window (actor_x11)) - { - cairo_rectangle_int_t bounds; - - get_shadow_bounds (actor_x11, appears_focused, &bounds); - clip = cairo_region_create_rectangle (&bounds); - - if (actor_x11->frame_bounds) - cairo_region_subtract (clip, actor_x11->frame_bounds); - } - - framebuffer = clutter_paint_context_get_framebuffer (paint_context); - meta_shadow_paint (shadow, - framebuffer, - params.x_offset + shape_bounds.x, - params.y_offset + shape_bounds.y, - shape_bounds.width, - shape_bounds.height, - (clutter_actor_get_paint_opacity (actor) * - params.opacity * window->opacity) / (255 * 255), - clip, - clip_shadow_under_window (actor_x11)); - - if (clip && clip != actor_x11->shadow_clip) - cairo_region_destroy (clip); - } - - CLUTTER_ACTOR_CLASS (meta_window_actor_x11_parent_class)->paint (actor, - paint_context); -} - -static void -meta_window_actor_x11_after_paint (MetaWindowActor *actor, - ClutterStageView *stage_view) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window; - - actor_x11->repaint_scheduled = FALSE; - - if (meta_window_actor_is_destroyed (actor)) - return; - - /* If the window had damage, but wasn't actually redrawn because - * it is obscured, we should wait until timer expiration before - * sending _NET_WM_FRAME_* messages. - */ - if (actor_x11->send_frame_messages_timer == 0 && - actor_x11->needs_frame_drawn) - { - GList *l; - - for (l = actor_x11->frames; l; l = l->next) - { - FrameData *frame = l->data; - - if (frame->frame_drawn_time == 0) - do_send_frame_drawn (actor_x11, frame); - } - - actor_x11->needs_frame_drawn = FALSE; - } - - /* This is for Xwayland, and a no-op on plain Xorg */ - window = meta_window_actor_get_meta_window (actor); - if (meta_window_x11_should_thaw_after_paint (window)) - { - meta_window_x11_thaw_commits (window); - meta_window_x11_set_thaw_after_paint (window, FALSE); - } -} - -static gboolean -meta_window_actor_x11_get_paint_volume (ClutterActor *actor, - ClutterPaintVolume *volume) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window; - gboolean appears_focused; - MetaSurfaceActor *surface; - - /* The paint volume is computed before paint functions are called - * so our bounds might not be updated yet. Force an update. */ - handle_updates (actor_x11); - - window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - appears_focused = meta_window_appears_focused (window); - if (appears_focused ? actor_x11->focused_shadow : actor_x11->unfocused_shadow) - { - cairo_rectangle_int_t shadow_bounds; - ClutterActorBox shadow_box; - - /* We could compute an full clip region as we do for the window - * texture, but the shadow is relatively cheap to draw, and - * a little more complex to clip, so we just catch the case where - * the shadow is completely obscured and doesn't need to be drawn - * at all. - */ - - get_shadow_bounds (actor_x11, appears_focused, &shadow_bounds); - shadow_box.x1 = shadow_bounds.x; - shadow_box.x2 = shadow_bounds.x + shadow_bounds.width; - shadow_box.y1 = shadow_bounds.y; - shadow_box.y2 = shadow_bounds.y + shadow_bounds.height; - - clutter_paint_volume_union_box (volume, &shadow_box); - } - - surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - if (surface) - { - ClutterActor *surface_actor = CLUTTER_ACTOR (surface); - const ClutterPaintVolume *child_volume; - - child_volume = clutter_actor_get_transformed_paint_volume (surface_actor, - actor); - if (!child_volume) - return FALSE; - - clutter_paint_volume_union (volume, child_volume); - } - - return TRUE; -} - -static void -meta_window_actor_x11_queue_destroy (MetaWindowActor *actor) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - - if (actor_x11->send_frame_messages_timer != 0) - remove_frame_messages_timer (actor_x11); -} - -static void -meta_window_actor_x11_set_frozen (MetaWindowActor *actor, - gboolean frozen) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window = meta_window_actor_get_meta_window (actor); - - if (actor_x11->is_frozen == frozen) - return; - - actor_x11->is_frozen = frozen; - - if (frozen) - meta_window_x11_freeze_commits (window); - else - meta_window_x11_thaw_commits (window); -} - -static void -meta_window_actor_x11_update_regions (MetaWindowActor *actor) -{ - update_regions (META_WINDOW_ACTOR_X11 (actor)); -} - -static gboolean -meta_window_actor_x11_can_freeze_commits (MetaWindowActor *actor) -{ - ClutterActor *clutter_actor = CLUTTER_ACTOR (actor); - - return clutter_actor_is_mapped (clutter_actor); -} - -static void -meta_window_actor_x11_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - - switch (prop_id) - { - case PROP_SHADOW_MODE: - { - MetaShadowMode newv = g_value_get_enum (value); - - if (newv == actor_x11->shadow_mode) - return; - - actor_x11->shadow_mode = newv; - - invalidate_shadow (actor_x11); - } - break; - case PROP_SHADOW_CLASS: - { - const char *newv = g_value_get_string (value); - - if (g_strcmp0 (newv, actor_x11->shadow_class) == 0) - return; - - g_free (actor_x11->shadow_class); - actor_x11->shadow_class = g_strdup (newv); - - invalidate_shadow (actor_x11); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_window_actor_x11_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - - switch (prop_id) - { - case PROP_SHADOW_MODE: - g_value_set_enum (value, actor_x11->shadow_mode); - break; - case PROP_SHADOW_CLASS: - g_value_set_string (value, actor_x11->shadow_class); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_window_actor_x11_constructed (GObject *object) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - MetaWindowActor *actor = META_WINDOW_ACTOR (actor_x11); - MetaWindow *window = meta_window_actor_get_meta_window (actor); - - /* - * Start off with an empty shape region to maintain the invariant that it's - * always set. - */ - actor_x11->shape_region = cairo_region_create (); - - G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->constructed (object); - - /* If a window doesn't start off with updates frozen, we should - * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. - */ - if (window->extended_sync_request_counter && - !meta_window_updates_are_frozen (window)) - meta_window_actor_queue_frame_drawn (actor, FALSE); -} - -static void -meta_window_actor_x11_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - MetaWindowActorX11 *self = META_WINDOW_ACTOR_X11 (cullable); - - cullable_parent_iface->cull_out (cullable, unobscured_region, clip_region); - - set_clip_region_beneath (self, clip_region); -} - -static void -meta_window_actor_x11_reset_culling (MetaCullable *cullable) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (cullable); - - g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy); - - cullable_parent_iface->reset_culling (cullable); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - cullable_parent_iface = g_type_interface_peek_parent (iface); - - iface->cull_out = meta_window_actor_x11_cull_out; - iface->reset_culling = meta_window_actor_x11_reset_culling; -} - -static void -meta_window_actor_x11_dispose (GObject *object) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - MetaSurfaceActor *surface_actor; - - g_clear_signal_handler (&actor_x11->shadow_factory_changed_handler_id, - actor_x11->shadow_factory); - - if (actor_x11->send_frame_messages_timer != 0) - remove_frame_messages_timer (actor_x11); - - surface_actor = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); - if (surface_actor) - { - g_clear_signal_handler (&actor_x11->repaint_scheduled_id, surface_actor); - g_clear_signal_handler (&actor_x11->size_changed_id, surface_actor); - } - - g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy); - g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy); - g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy); - - g_clear_pointer (&actor_x11->shadow_class, g_free); - g_clear_pointer (&actor_x11->focused_shadow, meta_shadow_unref); - g_clear_pointer (&actor_x11->unfocused_shadow, meta_shadow_unref); - g_clear_pointer (&actor_x11->shadow_shape, meta_window_shape_unref); - - G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->dispose (object); -} - -static void -meta_window_actor_x11_finalize (GObject *object) -{ - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - - g_list_free_full (actor_x11->frames, (GDestroyNotify) frame_data_free); - - G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->finalize (object); -} - -static void -meta_window_actor_x11_class_init (MetaWindowActorX11Class *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass); - GParamSpec *pspec; - - window_actor_class->frame_complete = meta_window_actor_x11_frame_complete; - window_actor_class->assign_surface_actor = meta_window_actor_x11_assign_surface_actor; - window_actor_class->queue_frame_drawn = meta_window_actor_x11_queue_frame_drawn; - window_actor_class->before_paint = meta_window_actor_x11_before_paint; - window_actor_class->after_paint = meta_window_actor_x11_after_paint; - window_actor_class->queue_destroy = meta_window_actor_x11_queue_destroy; - window_actor_class->set_frozen = meta_window_actor_x11_set_frozen; - window_actor_class->update_regions = meta_window_actor_x11_update_regions; - window_actor_class->can_freeze_commits = meta_window_actor_x11_can_freeze_commits; - - actor_class->paint = meta_window_actor_x11_paint; - actor_class->get_paint_volume = meta_window_actor_x11_get_paint_volume; - - object_class->constructed = meta_window_actor_x11_constructed; - object_class->set_property = meta_window_actor_x11_set_property; - object_class->get_property = meta_window_actor_x11_get_property; - object_class->dispose = meta_window_actor_x11_dispose; - object_class->finalize = meta_window_actor_x11_finalize; - - pspec = g_param_spec_enum ("shadow-mode", - "Shadow mode", - "Decides when to paint shadows", - META_TYPE_SHADOW_MODE, - META_SHADOW_MODE_AUTO, - G_PARAM_READWRITE); - - g_object_class_install_property (object_class, - PROP_SHADOW_MODE, - pspec); - - pspec = g_param_spec_string ("shadow-class", - "Name of the shadow class for this window.", - "NULL means to use the default shadow class for this window type", - NULL, - G_PARAM_READWRITE); - - g_object_class_install_property (object_class, - PROP_SHADOW_CLASS, - pspec); -} - -static void -meta_window_actor_x11_init (MetaWindowActorX11 *self) -{ - /* We do this now since we might be going right back into the frozen state. */ - g_signal_connect (self, "thawed", G_CALLBACK (handle_updates), NULL); - - g_signal_connect (self, "stage-views-changed", - G_CALLBACK (handle_stage_views_changed), NULL); - - self->shadow_factory = meta_shadow_factory_get_default (); - self->shadow_factory_changed_handler_id = - g_signal_connect_swapped (self->shadow_factory, - "changed", - G_CALLBACK (invalidate_shadow), - self); -} |