diff options
Diffstat (limited to 'src/compositor')
61 files changed, 0 insertions, 19833 deletions
diff --git a/src/compositor/README b/src/compositor/README deleted file mode 100644 index 93edf8dc9..000000000 --- a/src/compositor/README +++ /dev/null @@ -1,70 +0,0 @@ -Intro -===== - -In general, the compositor splits the window from the contents of -the window from the shape of the window. In other words, a window -has contents, and the contents of the window have a shape. This is -represented by the actor hierarchy: - - +--------------------------------------+ - | MetaWindowActor | - | +----------------------------------+ | - | | MetaSurfaceActor | | - | | +------------------------------+ | | - | | | MetaShapedTexture | | | - | | | | | | - | | | | | | - | | | | | | - | | | | | | - | | +------------------------------+ | | - | +----------------------------------+ | - +--------------------------------------+ - -Surfaces may also contain subsurfaces. The MetaWindowActor and -MetaSurfaceActor subclasses that will be created depend on the client -type, and the display server type. - -## Subsurfaces - -Additionally, there is also the case of subsurfaces: surfaces that -are child of other surfaces. That is also represented in the actor -hierarchy by having one or many MetaSurfaceActors (the subsurfaces) -added as children of a parent MetaSurfaceActor. There are no limits -to how many subsurfaces a surface may have. With subsurfaces, the -actor hierarchy looks like this: - - MetaWindowActor - ↳ MetaSurfaceActor (surface) - ↳ MetaShapedTexture - ↳ MetaSurfaceActor (subsurface) - ↳ MetaShapedTexture - ↳ MetaSurfaceActor (sub-subsurface) - ↳ MetaShapedTexture - ↳ MetaSurfaceActor (subsurface) - ↳ MetaShapedTexture - -In this example, the main surface has 2 subsurfaces. One of these -subsurfaces contains a subsurface as well. - -All MetaWindowActors contain at least one MetaSurfaceActor, and all -MetaSurfaceActors contain a MetaShapedTexture. - -## Client and compositor - -MetaWindowActor and its subclasses represent the client window's -type. A X11 client will have a MetaWindowActorX11 representing it, -and a Wayland client will have a MetaWindowActorWayland. - -On the compositor side, the surface where the contents of the window -are drawn into are represented by MetaSurfaceActor subclasses. On a -Wayland session, windows are backed by a MetaSurfaceActorWayland -surface, whereas on X11 sessions, by MetaSurfaceActorX11. - -XWayland windows are X11 client windows (MetaWindowActorX11) backed -by Wayland surfaces (MetaWindowActorWayland). - - -Env Vars -======== - -MUTTER_DISABLE_MIPMAPS - set to disable use of mipmaped windows.
\ No newline at end of file diff --git a/src/compositor/clutter-utils.c b/src/compositor/clutter-utils.c deleted file mode 100644 index 86d788562..000000000 --- a/src/compositor/clutter-utils.c +++ /dev/null @@ -1,188 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for use with Cogl - * - * Copyright 2010 Red Hat, Inc. - * Copyright 2010 Intel Corporation - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "compositor/clutter-utils.h" - -#include <math.h> - -/* This file uses pixel-aligned region computation to determine what - * can be clipped out. This only really works if everything is aligned - * to the pixel grid - not scaled or rotated and at integer offsets. - * - * (This could be relaxed - if we turned off filtering for unscaled - * windows then windows would be, by definition aligned to the pixel - * grid. And for rectangular windows without a shape, the outline that - * we draw for an unrotated window is always a rectangle because we - * don't use antialasing for the window boundary - with or without - * filtering, with or without a scale. But figuring out exactly - * what pixels will be drawn by the graphics system in these cases - * gets tricky, so we just go for the easiest part - no scale, - * and at integer offsets.) - * - * The way we check for pixel-aligned is by looking at the - * transformation into screen space of the allocation box of an actor - * and and checking if the corners are "close enough" to integral - * pixel values. - */ - -/* The definition of "close enough" to integral pixel values is - * equality when we convert to 24.8 fixed-point. - */ -static inline int -round_to_fixed (float x) -{ - return roundf (x * 256); -} - -/* Help macros to scale from OpenGL <-1,1> coordinates system to - * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c - */ -#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) -#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) - -/* This helper function checks if (according to our fixed point precision) - * the vertices @verts form a box of width @widthf and height @heightf - * located at integral coordinates. These coordinates are returned - * in @x_origin and @y_origin. - */ -gboolean -meta_actor_vertices_are_untransformed (graphene_point3d_t *verts, - float widthf, - float heightf, - int *x_origin, - int *y_origin) -{ - int width, height; - int v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y; - int x, y; - - width = round_to_fixed (widthf); - height = round_to_fixed (heightf); - - v0x = round_to_fixed (verts[0].x); v0y = round_to_fixed (verts[0].y); - v1x = round_to_fixed (verts[1].x); v1y = round_to_fixed (verts[1].y); - v2x = round_to_fixed (verts[2].x); v2y = round_to_fixed (verts[2].y); - v3x = round_to_fixed (verts[3].x); v3y = round_to_fixed (verts[3].y); - - /* Using shifting for converting fixed => int, gets things right for - * negative values. / 256. wouldn't do the same - */ - x = v0x >> 8; - y = v0y >> 8; - - /* At integral coordinates? */ - if (x * 256 != v0x || y * 256 != v0y) - return FALSE; - - /* Not scaled? */ - if (v1x - v0x != width || v2y - v0y != height) - return FALSE; - - /* Not rotated/skewed? */ - if (v0x != v2x || v0y != v1y || - v3x != v1x || v3y != v2y) - return FALSE; - - if (x_origin) - *x_origin = x; - if (y_origin) - *y_origin = y; - - return TRUE; -} - -/** - * meta_actor_painting_untransformed: - * @paint_width: the width of the painted area - * @paint_height: the height of the painted area - * @sample_width: the width of the sampled area of the texture - * @sample_height: the height of the sampled area of the texture - * @x_origin: if the transform is only an integer translation - * then the X coordinate of the location of the origin under the transformation - * from drawing space to screen pixel space is returned here. - * @y_origin: if the transform is only an integer translation - * then the X coordinate of the location of the origin under the transformation - * from drawing space to screen pixel space is returned here. - * - * Determines if the current painting transform is an integer translation. - * This can differ from the result of meta_actor_is_untransformed() when - * painting an actor if we're inside a inside a clone paint. @paint_width - * and @paint_height are used to determine the vertices of the rectangle - * we check to see if the painted area is "close enough" to the integer - * transform. - */ -gboolean -meta_actor_painting_untransformed (CoglFramebuffer *fb, - int paint_width, - int paint_height, - int sample_width, - int sample_height, - int *x_origin, - int *y_origin) -{ - graphene_matrix_t modelview, projection, modelview_projection; - graphene_point3d_t vertices[4]; - float viewport[4]; - int i; - - cogl_framebuffer_get_modelview_matrix (fb, &modelview); - cogl_framebuffer_get_projection_matrix (fb, &projection); - - graphene_matrix_multiply (&modelview, - &projection, - &modelview_projection); - - vertices[0].x = 0; - vertices[0].y = 0; - vertices[0].z = 0; - vertices[1].x = paint_width; - vertices[1].y = 0; - vertices[1].z = 0; - vertices[2].x = 0; - vertices[2].y = paint_height; - vertices[2].z = 0; - vertices[3].x = paint_width; - vertices[3].y = paint_height; - vertices[3].z = 0; - - cogl_framebuffer_get_viewport4fv (fb, viewport); - - for (i = 0; i < 4; i++) - { - float w = 1; - cogl_graphene_matrix_project_point (&modelview_projection, - &vertices[i].x, - &vertices[i].y, - &vertices[i].z, - &w); - vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, - viewport[2], viewport[0]); - vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, - viewport[3], viewport[1]); - } - - return meta_actor_vertices_are_untransformed (vertices, - sample_width, sample_height, - x_origin, y_origin); -} - diff --git a/src/compositor/clutter-utils.h b/src/compositor/clutter-utils.h deleted file mode 100644 index 8ed0e2a4d..000000000 --- a/src/compositor/clutter-utils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for use with Clutter - * - * Copyright 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __META_CLUTTER_UTILS_H__ -#define __META_CLUTTER_UTILS_H__ - -#include "clutter/clutter.h" - -gboolean meta_actor_vertices_are_untransformed (graphene_point3d_t *verts, - float widthf, - float heightf, - int *x_origin, - int *y_origin); - -gboolean meta_actor_painting_untransformed (CoglFramebuffer *fb, - int paint_width, - int paint_height, - int sample_widthf, - int sample_heightf, - int *x_origin, - int *y_origin); - -#endif /* __META_CLUTTER_UTILS_H__ */ diff --git a/src/compositor/cogl-utils.c b/src/compositor/cogl-utils.c deleted file mode 100644 index 0a39755a5..000000000 --- a/src/compositor/cogl-utils.c +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for use with Cogl - * - * Copyright 2010 Red Hat, Inc. - * Copyright 2010 Intel Corporation - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "clutter/clutter.h" -#include "compositor/cogl-utils.h" - -/* Based on gnome-shell/src/st/st-private.c:_st_create_texture_material.c */ - -/** - * meta_create_texture_pipeline: - * @src_texture: (nullable): texture to use initially for the layer - * - * Creates a pipeline with a single layer. Using a common template - * makes it easier for Cogl to share a shader for different uses in - * Mutter. - * - * Return value: (transfer full): a newly created #CoglPipeline - */ -CoglPipeline * -meta_create_texture_pipeline (CoglTexture *src_texture) -{ - static CoglPipeline *texture_pipeline_template = NULL; - CoglPipeline *pipeline; - - /* The only state used in the pipeline that would affect the shader - generation is the texture type on the layer. Therefore we create - a template pipeline which sets this state and all texture - pipelines are created as a copy of this. That way Cogl can find - the shader state for the pipeline more quickly by looking at the - pipeline ancestry instead of resorting to the shader cache. */ - if (G_UNLIKELY (texture_pipeline_template == NULL)) - { - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - - texture_pipeline_template = cogl_pipeline_new (ctx); - cogl_pipeline_set_layer_null_texture (texture_pipeline_template, 0); - } - - pipeline = cogl_pipeline_copy (texture_pipeline_template); - - if (src_texture != NULL) - cogl_pipeline_set_layer_texture (pipeline, 0, src_texture); - - return pipeline; -} - -/** - * meta_create_texture: - * @width: width of the texture to create - * @height: height of the texture to create - * @components; components to store in the texture (color or alpha) - * @flags: flags that affect the allocation behavior - * - * Creates a texture of the given size with the specified components - * for use as a frame buffer object. - * - * If %META_TEXTURE_ALLOW_SLICING is present in @flags, and the texture - * is larger than the texture size limits of the system, then the texture - * will be created as a sliced texture. This also will cause problems - * with using the texture with GLSL, and is more likely to be an issue - * since all GL implementations have texture size limits, and they can - * be as small as 2048x2048 on reasonably current systems. - */ -CoglTexture * -meta_create_texture (int width, - int height, - CoglTextureComponents components, - MetaTextureFlags flags) -{ - ClutterBackend *backend = clutter_get_default_backend (); - CoglContext *ctx = clutter_backend_get_cogl_context (backend); - CoglTexture *texture; - - texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height)); - cogl_texture_set_components (texture, components); - - if ((flags & META_TEXTURE_ALLOW_SLICING) != 0) - { - /* To find out if we need to slice the texture, we have to go ahead and force storage - * to be allocated - */ - GError *catch_error = NULL; - if (!cogl_texture_allocate (texture, &catch_error)) - { - g_error_free (catch_error); - cogl_object_unref (texture); - texture = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE)); - cogl_texture_set_components (texture, components); - } - } - - return texture; -} diff --git a/src/compositor/cogl-utils.h b/src/compositor/cogl-utils.h deleted file mode 100644 index ae7e85176..000000000 --- a/src/compositor/cogl-utils.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for use with Cogl - * - * Copyright 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __META_COGL_UTILS_H__ -#define __META_COGL_UTILS_H__ - -#include "cogl/cogl.h" - -CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture); - -typedef enum -{ - META_TEXTURE_FLAGS_NONE = 0, - META_TEXTURE_ALLOW_SLICING = 1 << 1 -} MetaTextureFlags; - -CoglTexture *meta_create_texture (int width, - int height, - CoglTextureComponents components, - MetaTextureFlags flags); - -#endif /* __META_COGL_UTILS_H__ */ diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h deleted file mode 100644 index 580618e48..000000000 --- a/src/compositor/compositor-private.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_COMPOSITOR_PRIVATE_H -#define META_COMPOSITOR_PRIVATE_H - -#include <X11/extensions/Xfixes.h> - -#include "clutter/clutter-mutter.h" -#include "clutter/clutter.h" -#include "compositor/meta-plugin-manager.h" -#include "compositor/meta-window-actor-private.h" -#include "meta/compositor.h" -#include "meta/display.h" - -/* Wait 2ms after vblank before starting to draw next frame */ -#define META_SYNC_DELAY 2 - -typedef struct _MetaLaters MetaLaters; - -struct _MetaCompositorClass -{ - GObjectClass parent_class; - - gboolean (* manage) (MetaCompositor *compositor, - GError **error); - void (* unmanage) (MetaCompositor *compositor); - void (* before_paint) (MetaCompositor *compositor, - ClutterStageView *stage_view); - void (* after_paint) (MetaCompositor *compositor, - ClutterStageView *stage_view); - void (* remove_window) (MetaCompositor *compositor, - MetaWindow *window); - int64_t (* monotonic_to_high_res_xserver_time) (MetaCompositor *compositor, - int64_t time_us); - void (* grab_begin) (MetaCompositor *compositor); - void (* grab_end) (MetaCompositor *compositor); -}; - -gboolean meta_compositor_do_manage (MetaCompositor *compositor, - GError **error); - -void meta_compositor_remove_window_actor (MetaCompositor *compositor, - MetaWindowActor *window_actor); - -void meta_switch_workspace_completed (MetaCompositor *compositor); - -gboolean meta_begin_modal_for_plugin (MetaCompositor *compositor, - MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp); -void meta_end_modal_for_plugin (MetaCompositor *compositor, - MetaPlugin *plugin, - guint32 timestamp); - -MetaPluginManager * meta_compositor_get_plugin_manager (MetaCompositor *compositor); - -int64_t meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor, - int64_t monotonic_time_us); - -void meta_compositor_flash_window (MetaCompositor *compositor, - MetaWindow *window); - -MetaCloseDialog * meta_compositor_create_close_dialog (MetaCompositor *compositor, - MetaWindow *window); - -MetaInhibitShortcutsDialog * meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor, - MetaWindow *window); - -void meta_compositor_locate_pointer (MetaCompositor *compositor); - -void meta_compositor_redirect_x11_windows (MetaCompositor *compositor); - -gboolean meta_compositor_is_unredirect_inhibited (MetaCompositor *compositor); - -MetaDisplay * meta_compositor_get_display (MetaCompositor *compositor); - -MetaWindowActor * meta_compositor_get_top_window_actor (MetaCompositor *compositor); - -ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor); - -gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor); - -MetaLaters * meta_compositor_get_laters (MetaCompositor *compositor); - -/* - * This function takes a 64 bit time stamp from the monotonic clock, and clamps - * it to the scope of the X server clock, without losing the granularity. - */ -static inline int64_t -meta_translate_to_high_res_xserver_time (int64_t time_us) -{ - int64_t us; - int64_t ms; - - us = time_us % 1000; - ms = time_us / 1000; - - return ms2us (ms & 0xffffffff) + us; -} - -#endif /* META_COMPOSITOR_PRIVATE_H */ diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c deleted file mode 100644 index 9cdd39c15..000000000 --- a/src/compositor/compositor.c +++ /dev/null @@ -1,1581 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/** - * SECTION:compositor - * @Title: MetaCompositor - * @Short_Description: Compositor API - * - * At a high-level, a window is not-visible or visible. When a - * window is added (with meta_compositor_add_window()) it is not visible. - * meta_compositor_show_window() indicates a transition from not-visible to - * visible. Some of the reasons for this: - * - * - Window newly created - * - Window is unminimized - * - Window is moved to the current desktop - * - Window was made sticky - * - * meta_compositor_hide_window() indicates that the window has transitioned from - * visible to not-visible. Some reasons include: - * - * - Window was destroyed - * - Window is minimized - * - Window is moved to a different desktop - * - Window no longer sticky. - * - * Note that combinations are possible - a window might have first - * been minimized and then moved to a different desktop. The 'effect' parameter - * to meta_compositor_show_window() and meta_compositor_hide_window() is a hint - * as to the appropriate effect to show the user and should not - * be considered to be indicative of a state change. - * - * When the active workspace is changed, meta_compositor_switch_workspace() is - * called first, then meta_compositor_show_window() and - * meta_compositor_hide_window() are called individually for each window - * affected, with an effect of META_COMP_EFFECT_NONE. - * If hiding windows will affect the switch workspace animation, the - * compositor needs to delay hiding the windows until the switch - * workspace animation completes. - * - * # Containers # - * - * There's two containers in the stage that are used to place window actors, here - * are listed in the order in which they are painted: - * - * - window group, accessible with meta_get_window_group_for_display() - * - top window group, accessible with meta_get_top_window_group_for_display() - * - * Mutter will place actors representing windows in the window group, except for - * override-redirect windows (ie. popups and menus) which will be placed in the - * top window group. - */ - -#include "config.h" - -#include "compositor/compositor-private.h" - -#include <X11/extensions/Xcomposite.h> - -#include "backends/x11/meta-backend-x11.h" -#include "backends/x11/meta-event-x11.h" -#include "backends/x11/meta-stage-x11.h" -#include "clutter/clutter-mutter.h" -#include "cogl/cogl.h" -#include "compositor/meta-later-private.h" -#include "compositor/meta-window-actor-x11.h" -#include "compositor/meta-window-actor-private.h" -#include "compositor/meta-window-group-private.h" -#include "core/frame.h" -#include "core/util-private.h" -#include "core/window-private.h" -#include "meta/compositor-mutter.h" -#include "meta/main.h" -#include "meta/meta-backend.h" -#include "meta/meta-background-actor.h" -#include "meta/meta-background-group.h" -#include "meta/meta-context.h" -#include "meta/meta-shadow-factory.h" -#include "meta/meta-x11-errors.h" -#include "meta/prefs.h" -#include "meta/window.h" -#include "x11/meta-x11-display-private.h" - -#ifdef HAVE_WAYLAND -#include "compositor/meta-window-actor-wayland.h" -#include "wayland/meta-wayland-private.h" -#endif - -enum -{ - PROP_0, - - PROP_DISPLAY, - PROP_BACKEND, - - N_PROPS -}; - -static GParamSpec *obj_props[N_PROPS] = { NULL, }; - -typedef struct _MetaCompositorPrivate -{ - GObject parent; - - MetaDisplay *display; - MetaBackend *backend; - - gulong stage_presented_id; - gulong before_paint_handler_id; - gulong after_paint_handler_id; - - int64_t server_time_query_time; - int64_t server_time_offset; - - gboolean server_time_is_monotonic_time; - - ClutterActor *window_group; - ClutterActor *top_window_group; - ClutterActor *feedback_group; - - GList *windows; - - CoglContext *context; - - MetaWindowActor *top_window_actor; - gulong top_window_actor_destroy_id; - - int disable_unredirect_count; - - int switch_workspace_in_progress; - - MetaPluginManager *plugin_mgr; - - MetaLaters *laters; -} MetaCompositorPrivate; - -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, - G_TYPE_OBJECT) - -static void -on_presented (ClutterStage *stage, - ClutterStageView *stage_view, - ClutterFrameInfo *frame_info, - MetaCompositor *compositor); - -static void -on_top_window_actor_destroyed (MetaWindowActor *window_actor, - MetaCompositor *compositor); - -static gboolean -is_modal (MetaDisplay *display) -{ - return display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB; -} - -static void sync_actor_stacking (MetaCompositor *compositor); - -static void -meta_finish_workspace_switch (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - GList *l; - - /* Finish hiding and showing actors for the new workspace */ - for (l = priv->windows; l; l = l->next) - meta_window_actor_sync_visibility (l->data); - - /* Fix up stacking order. */ - sync_actor_stacking (compositor); -} - -void -meta_switch_workspace_completed (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - /* FIXME -- must redo stacking order */ - priv->switch_workspace_in_progress--; - if (priv->switch_workspace_in_progress < 0) - { - g_warning ("Error in workspace_switch accounting!"); - priv->switch_workspace_in_progress = 0; - } - - if (!priv->switch_workspace_in_progress) - meta_finish_workspace_switch (compositor); -} - -void -meta_compositor_destroy (MetaCompositor *compositor) -{ - g_object_run_dispose (G_OBJECT (compositor)); - g_object_unref (compositor); -} - -/* compat helper */ -static MetaCompositor * -get_compositor_for_display (MetaDisplay *display) -{ - return display->compositor; -} - -/** - * meta_get_stage_for_display: - * @display: a #MetaDisplay - * - * Returns: (transfer none): The #ClutterStage for the display - */ -ClutterActor * -meta_get_stage_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - g_return_val_if_fail (display, NULL); - - compositor = get_compositor_for_display (display); - g_return_val_if_fail (compositor, NULL); - priv = meta_compositor_get_instance_private (compositor); - - return meta_backend_get_stage (priv->backend); -} - -/** - * meta_get_window_group_for_display: - * @display: a #MetaDisplay - * - * Returns: (transfer none): The window group corresponding to @display - */ -ClutterActor * -meta_get_window_group_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - g_return_val_if_fail (display, NULL); - - compositor = get_compositor_for_display (display); - g_return_val_if_fail (compositor, NULL); - priv = meta_compositor_get_instance_private (compositor); - - return priv->window_group; -} - -/** - * meta_get_top_window_group_for_display: - * @display: a #MetaDisplay - * - * Returns: (transfer none): The top window group corresponding to @display - */ -ClutterActor * -meta_get_top_window_group_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - g_return_val_if_fail (display, NULL); - - compositor = get_compositor_for_display (display); - g_return_val_if_fail (compositor, NULL); - priv = meta_compositor_get_instance_private (compositor); - - return priv->top_window_group; -} - -/** - * meta_get_feedback_group_for_display: - * @display: a #MetaDisplay - * - * Returns: (transfer none): The feedback group corresponding to @display - */ -ClutterActor * -meta_get_feedback_group_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - g_return_val_if_fail (display, NULL); - - compositor = get_compositor_for_display (display); - g_return_val_if_fail (compositor, NULL); - priv = meta_compositor_get_instance_private (compositor); - - return priv->feedback_group; -} - -/** - * meta_get_window_actors: - * @display: a #MetaDisplay - * - * Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @display - */ -GList * -meta_get_window_actors (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - g_return_val_if_fail (display, NULL); - - compositor = get_compositor_for_display (display); - g_return_val_if_fail (compositor, NULL); - priv = meta_compositor_get_instance_private (compositor); - - return priv->windows; -} - -void -meta_focus_stage_window (MetaDisplay *display, - guint32 timestamp) -{ - ClutterStage *stage; - Window window; - - stage = CLUTTER_STAGE (meta_get_stage_for_display (display)); - if (!stage) - return; - - window = meta_x11_get_stage_window (stage); - - if (window == None) - return; - - meta_x11_display_set_input_focus_xwindow (display->x11_display, - window, - timestamp); -} - -gboolean -meta_stage_is_focused (MetaDisplay *display) -{ - ClutterStage *stage; - Window window; - - if (meta_is_wayland_compositor ()) - return TRUE; - - stage = CLUTTER_STAGE (meta_get_stage_for_display (display)); - if (!stage) - return FALSE; - - window = meta_x11_get_stage_window (stage); - - if (window == None) - return FALSE; - - return (display->x11_display->focus_xwindow == window); -} - -static gboolean -grab_devices (MetaModalOptions options, - guint32 timestamp) -{ - MetaBackend *backend = META_BACKEND (meta_get_backend ()); - gboolean pointer_grabbed = FALSE; - gboolean keyboard_grabbed = FALSE; - - if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) - { - if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp)) - goto fail; - - pointer_grabbed = TRUE; - } - - if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0) - { - if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp)) - goto fail; - - keyboard_grabbed = TRUE; - } - - return TRUE; - - fail: - if (pointer_grabbed) - meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp); - if (keyboard_grabbed) - meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); - - return FALSE; -} - -static void -meta_compositor_grab_begin (MetaCompositor *compositor) -{ - META_COMPOSITOR_GET_CLASS (compositor)->grab_begin (compositor); -} - -static void -meta_compositor_grab_end (MetaCompositor *compositor) -{ - META_COMPOSITOR_GET_CLASS (compositor)->grab_end (compositor); -} - -gboolean -meta_begin_modal_for_plugin (MetaCompositor *compositor, - MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp) -{ - /* To some extent this duplicates code in meta_display_begin_grab_op(), but there - * are significant differences in how we handle grabs that make it difficult to - * merge the two. - */ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaDisplay *display = priv->display; - -#ifdef HAVE_WAYLAND - if (display->grab_op == META_GRAB_OP_WAYLAND_POPUP) - { - MetaWaylandSeat *seat = meta_wayland_compositor_get_default ()->seat; - meta_wayland_pointer_end_popup_grab (seat->pointer); - } -#endif - - if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE) - return FALSE; - - if (display->x11_display) - { - /* XXX: why is this needed? */ - XIUngrabDevice (display->x11_display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - timestamp); - XSync (display->x11_display->xdisplay, False); - } - - if (!grab_devices (options, timestamp)) - return FALSE; - - display->grab_op = META_GRAB_OP_COMPOSITOR; - display->event_route = META_EVENT_ROUTE_COMPOSITOR_GRAB; - display->grab_window = NULL; - display->grab_have_pointer = TRUE; - display->grab_have_keyboard = TRUE; - - g_signal_emit_by_name (display, "grab-op-begin", - display->grab_window, display->grab_op); - - meta_compositor_grab_begin (compositor); - - return TRUE; -} - -void -meta_end_modal_for_plugin (MetaCompositor *compositor, - MetaPlugin *plugin, - guint32 timestamp) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaDisplay *display = priv->display; - MetaBackend *backend = meta_get_backend (); - MetaWindow *grab_window = display->grab_window; - MetaGrabOp grab_op = display->grab_op; - - g_return_if_fail (is_modal (display)); - - display->grab_op = META_GRAB_OP_NONE; - display->event_route = META_EVENT_ROUTE_NORMAL; - display->grab_window = NULL; - display->grab_have_pointer = FALSE; - display->grab_have_keyboard = FALSE; - - meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp); - meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); - - meta_compositor_grab_end (compositor); - - g_signal_emit_by_name (display, "grab-op-end", - grab_window, grab_op); -} - -static void -redirect_windows (MetaX11Display *x11_display) -{ - MetaBackend *backend = meta_get_backend (); - MetaContext *context = meta_backend_get_context (backend); - Display *xdisplay = meta_x11_display_get_xdisplay (x11_display); - Window xroot = meta_x11_display_get_xroot (x11_display); - int screen_number = meta_x11_display_get_screen_number (x11_display); - guint n_retries; - guint max_retries; - - if (meta_context_is_replacing (context)) - max_retries = 5; - else - max_retries = 1; - - n_retries = 0; - - /* Some compositors (like old versions of Mutter) might not properly unredirect - * subwindows before destroying the WM selection window; so we wait a while - * for such a compositor to exit before giving up. - */ - while (TRUE) - { - meta_x11_error_trap_push (x11_display); - XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual); - XSync (xdisplay, FALSE); - - if (!meta_x11_error_trap_pop_with_return (x11_display)) - break; - - if (n_retries == max_retries) - { - /* This probably means that a non-WM compositor like xcompmgr is running; - * we have no way to get it to exit */ - meta_fatal (_("Another compositing manager is already running on screen %i on display “%s”."), - screen_number, x11_display->name); - } - - n_retries++; - g_usleep (G_USEC_PER_SEC); - } -} - -void -meta_compositor_redirect_x11_windows (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaDisplay *display = priv->display; - - if (display->x11_display) - redirect_windows (display->x11_display); -} - -gboolean -meta_compositor_do_manage (MetaCompositor *compositor, - GError **error) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaDisplay *display = priv->display; - MetaBackend *backend = priv->backend; - ClutterActor *stage = meta_backend_get_stage (backend); - - priv->stage_presented_id = - g_signal_connect (stage, "presented", - G_CALLBACK (on_presented), - compositor); - - priv->window_group = meta_window_group_new (display); - priv->top_window_group = meta_window_group_new (display); - priv->feedback_group = meta_window_group_new (display); - - clutter_actor_add_child (stage, priv->window_group); - clutter_actor_add_child (stage, priv->top_window_group); - clutter_actor_add_child (stage, priv->feedback_group); - - if (!META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor, error)) - return FALSE; - - priv->plugin_mgr = meta_plugin_manager_new (compositor); - - return TRUE; -} - -void -meta_compositor_manage (MetaCompositor *compositor) -{ - GError *error = NULL; - - if (!meta_compositor_do_manage (compositor, &error)) - g_error ("Compositor failed to manage display: %s", error->message); -} - -void -meta_compositor_unmanage (MetaCompositor *compositor) -{ - META_COMPOSITOR_GET_CLASS (compositor)->unmanage (compositor); -} - -void -meta_compositor_add_window (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *window_actor; - ClutterActor *window_group; - GType window_actor_type = G_TYPE_INVALID; - - switch (window->client_type) - { - case META_WINDOW_CLIENT_TYPE_X11: - window_actor_type = META_TYPE_WINDOW_ACTOR_X11; - break; - -#ifdef HAVE_WAYLAND - case META_WINDOW_CLIENT_TYPE_WAYLAND: - window_actor_type = META_TYPE_WINDOW_ACTOR_WAYLAND; - break; -#endif - - default: - g_return_if_reached (); - } - - window_actor = g_object_new (window_actor_type, - "meta-window", window, - "show-on-set-parent", FALSE, - NULL); - - if (window->layer == META_LAYER_OVERRIDE_REDIRECT) - window_group = priv->top_window_group; - else - window_group = priv->window_group; - - clutter_actor_add_child (window_group, CLUTTER_ACTOR (window_actor)); - - /* Initial position in the stack is arbitrary; stacking will be synced - * before we first paint. - */ - priv->windows = g_list_append (priv->windows, window_actor); - sync_actor_stacking (compositor); -} - -static void -meta_compositor_real_remove_window (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_queue_destroy (window_actor); -} - -void -meta_compositor_remove_window (MetaCompositor *compositor, - MetaWindow *window) -{ - META_COMPOSITOR_GET_CLASS (compositor)->remove_window (compositor, window); -} - -void -meta_compositor_remove_window_actor (MetaCompositor *compositor, - MetaWindowActor *window_actor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - priv->windows = g_list_remove (priv->windows, window_actor); -} - -void -meta_compositor_sync_updates_frozen (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_sync_updates_frozen (window_actor); -} - -void -meta_compositor_queue_frame_drawn (MetaCompositor *compositor, - MetaWindow *window, - gboolean no_delay_frame) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); -} - -void -meta_compositor_window_shape_changed (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaWindowActor *window_actor; - - window_actor = meta_window_actor_from_window (window); - if (!window_actor) - return; - - meta_window_actor_x11_update_shape (META_WINDOW_ACTOR_X11 (window_actor)); -} - -void -meta_compositor_window_opacity_changed (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaWindowActor *window_actor; - - window_actor = meta_window_actor_from_window (window); - if (!window_actor) - return; - - meta_window_actor_update_opacity (window_actor); -} - -gboolean -meta_compositor_filter_keybinding (MetaCompositor *compositor, - MetaKeyBinding *binding) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return meta_plugin_manager_filter_keybinding (priv->plugin_mgr, binding); -} - -void -meta_compositor_show_window (MetaCompositor *compositor, - MetaWindow *window, - MetaCompEffect effect) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_show (window_actor, effect); -} - -void -meta_compositor_hide_window (MetaCompositor *compositor, - MetaWindow *window, - MetaCompEffect effect) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_hide (window_actor, effect); - meta_stack_tracker_queue_sync_stack (priv->display->stack_tracker); -} - -void -meta_compositor_size_change_window (MetaCompositor *compositor, - MetaWindow *window, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect); -} - -void -meta_compositor_switch_workspace (MetaCompositor *compositor, - MetaWorkspace *from, - MetaWorkspace *to, - MetaMotionDirection direction) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - gint to_indx, from_indx; - - to_indx = meta_workspace_index (to); - from_indx = meta_workspace_index (from); - - priv->switch_workspace_in_progress++; - - if (!meta_plugin_manager_switch_workspace (priv->plugin_mgr, - from_indx, - to_indx, - direction)) - { - priv->switch_workspace_in_progress--; - - /* We have to explicitly call this to fix up stacking order of the - * actors; this is because the abs stacking position of actors does not - * necessarily change during the window hiding/unhiding, only their - * relative position toward the destkop window. - */ - meta_finish_workspace_switch (compositor); - } -} - -static void -sync_actor_stacking (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - GList *children; - GList *expected_window_node; - GList *tmp; - GList *old; - GList *backgrounds; - gboolean has_windows; - gboolean reordered; - - /* NB: The first entries in the lists are stacked the lowest */ - - /* Restacking will trigger full screen redraws, so it's worth a - * little effort to make sure we actually need to restack before - * we go ahead and do it */ - - children = clutter_actor_get_children (priv->window_group); - has_windows = FALSE; - reordered = FALSE; - - /* We allow for actors in the window group other than the actors we - * know about, but it's up to a plugin to try and keep them stacked correctly - * (we really need extra API to make that reliable.) - */ - - /* First we collect a list of all backgrounds, and check if they're at the - * bottom. Then we check if the window actors are in the correct sequence */ - backgrounds = NULL; - expected_window_node = priv->windows; - for (old = children; old != NULL; old = old->next) - { - ClutterActor *actor = old->data; - - if (META_IS_BACKGROUND_GROUP (actor) || - META_IS_BACKGROUND_ACTOR (actor)) - { - backgrounds = g_list_prepend (backgrounds, actor); - - if (has_windows) - reordered = TRUE; - } - else if (META_IS_WINDOW_ACTOR (actor) && !reordered) - { - has_windows = TRUE; - - if (expected_window_node != NULL && actor == expected_window_node->data) - expected_window_node = expected_window_node->next; - else - reordered = TRUE; - } - } - - g_list_free (children); - - if (!reordered) - { - g_list_free (backgrounds); - return; - } - - /* reorder the actors by lowering them in turn to the bottom of the stack. - * windows first, then background. - * - * We reorder the actors even if they're not parented to the window group, - * to allow stacking to work with intermediate actors (eg during effects) - */ - for (tmp = g_list_last (priv->windows); tmp != NULL; tmp = tmp->prev) - { - ClutterActor *actor = tmp->data, *parent; - - parent = clutter_actor_get_parent (actor); - clutter_actor_set_child_below_sibling (parent, actor, NULL); - } - - /* we prepended the backgrounds above so the last actor in the list - * should get lowered to the bottom last. - */ - for (tmp = backgrounds; tmp != NULL; tmp = tmp->next) - { - ClutterActor *actor = tmp->data, *parent; - - parent = clutter_actor_get_parent (actor); - clutter_actor_set_child_below_sibling (parent, actor, NULL); - } - g_list_free (backgrounds); -} - -/* - * Find the top most window that is visible on the screen. The intention of - * this is to avoid offscreen windows that isn't actually part of the visible - * desktop (such as the UI frames override redirect window). - */ -static MetaWindowActor * -get_top_visible_window_actor (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - GList *l; - - for (l = g_list_last (priv->windows); l; l = l->prev) - { - MetaWindowActor *window_actor = l->data; - MetaWindow *window = meta_window_actor_get_meta_window (window_actor); - MetaRectangle buffer_rect; - MetaRectangle display_rect = { 0 }; - - if (!window->visible_to_compositor) - continue; - - meta_window_get_buffer_rect (window, &buffer_rect); - meta_display_get_size (priv->display, - &display_rect.width, &display_rect.height); - - if (meta_rectangle_overlap (&display_rect, &buffer_rect)) - return window_actor; - } - - return NULL; -} - -static void -on_top_window_actor_destroyed (MetaWindowActor *window_actor, - MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - priv->top_window_actor = NULL; - priv->top_window_actor_destroy_id = 0; - priv->windows = g_list_remove (priv->windows, window_actor); - - meta_stack_tracker_queue_sync_stack (priv->display->stack_tracker); -} - -void -meta_compositor_sync_stack (MetaCompositor *compositor, - GList *stack) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *top_window_actor; - GList *old_stack; - - /* This is painful because hidden windows that we are in the process - * of animating out of existence. They'll be at the bottom of the - * stack of X windows, but we want to leave them in their old position - * until the animation effect finishes. - */ - - /* Sources: first window is the highest */ - stack = g_list_copy (stack); /* The new stack of MetaWindow */ - old_stack = g_list_reverse (priv->windows); /* The old stack of MetaWindowActor */ - priv->windows = NULL; - - while (TRUE) - { - MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor; - MetaWindow *old_window = NULL, *stack_window = NULL, *window; - - /* Find the remaining top actor in our existing stack (ignoring - * windows that have been hidden and are no longer animating) */ - while (old_stack) - { - old_actor = old_stack->data; - old_window = meta_window_actor_get_meta_window (old_actor); - - if ((old_window->hidden || old_window->unmanaging) && - !meta_window_actor_effect_in_progress (old_actor)) - { - old_stack = g_list_delete_link (old_stack, old_stack); - old_actor = NULL; - } - else - break; - } - - /* And the remaining top actor in the new stack */ - while (stack) - { - stack_window = stack->data; - stack_actor = meta_window_actor_from_window (stack_window); - if (!stack_actor) - { - meta_verbose ("Failed to find corresponding MetaWindowActor " - "for window %s", meta_window_get_description (stack_window)); - stack = g_list_delete_link (stack, stack); - } - else - break; - } - - if (!old_actor && !stack_actor) /* Nothing more to stack */ - break; - - /* We usually prefer the window in the new stack, but if if we - * found a hidden window in the process of being animated out - * of existence in the old stack we use that instead. We've - * filtered out non-animating hidden windows above. - */ - if (old_actor && - (!stack_actor || old_window->hidden || old_window->unmanaging)) - { - actor = old_actor; - window = old_window; - } - else - { - actor = stack_actor; - window = stack_window; - } - - /* OK, we know what actor we want next. Add it to our window - * list, and remove it from both source lists. (It will - * be at the front of at least one, hopefully it will be - * near the front of the other.) - */ - priv->windows = g_list_prepend (priv->windows, actor); - - stack = g_list_remove (stack, window); - old_stack = g_list_remove (old_stack, actor); - } - - sync_actor_stacking (compositor); - - top_window_actor = get_top_visible_window_actor (compositor); - - if (priv->top_window_actor == top_window_actor) - return; - - g_clear_signal_handler (&priv->top_window_actor_destroy_id, - priv->top_window_actor); - - priv->top_window_actor = top_window_actor; - - if (priv->top_window_actor) - priv->top_window_actor_destroy_id = - g_signal_connect (priv->top_window_actor, "destroy", - G_CALLBACK (on_top_window_actor_destroyed), - compositor); -} - -void -meta_compositor_sync_window_geometry (MetaCompositor *compositor, - MetaWindow *window, - gboolean did_placement) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - MetaWindowActorChanges changes; - - changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement); - - if (changes & META_WINDOW_ACTOR_CHANGE_SIZE) - meta_plugin_manager_event_size_changed (priv->plugin_mgr, window_actor); -} - -static void -on_presented (ClutterStage *stage, - ClutterStageView *stage_view, - ClutterFrameInfo *frame_info, - MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - int64_t presentation_time = frame_info->presentation_time; - GList *l; - - for (l = priv->windows; l; l = l->next) - { - ClutterActor *actor = l->data; - GList *actor_stage_views; - - actor_stage_views = clutter_actor_peek_stage_views (actor); - if (g_list_find (actor_stage_views, stage_view)) - { - meta_window_actor_frame_complete (META_WINDOW_ACTOR (actor), - frame_info, - presentation_time); - } - } -} - -static void -meta_compositor_real_before_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - GList *l; - - for (l = priv->windows; l; l = l->next) - meta_window_actor_before_paint (l->data, stage_view); -} - -static void -meta_compositor_before_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - COGL_TRACE_BEGIN_SCOPED (MetaCompositorPrePaint, - "Compositor (before-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->before_paint (compositor, stage_view); -} - -static void -meta_compositor_real_after_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - ClutterActor *stage_actor = meta_backend_get_stage (priv->backend); - CoglGraphicsResetStatus status; - GList *l; - - status = cogl_get_graphics_reset_status (priv->context); - switch (status) - { - case COGL_GRAPHICS_RESET_STATUS_NO_ERROR: - break; - - case COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET: - g_signal_emit_by_name (priv->display, "gl-video-memory-purged"); - g_signal_emit_by_name (stage_actor, "gl-video-memory-purged"); - clutter_actor_queue_redraw (stage_actor); - break; - - default: - /* The ARB_robustness spec says that, on error, the application - should destroy the old context and create a new one. Since we - don't have the necessary plumbing to do this we'll simply - restart the process. Obviously we can't do this when we are - a wayland compositor but in that case we shouldn't get here - since we don't enable robustness in that case. */ - g_assert (!meta_is_wayland_compositor ()); - meta_restart (NULL); - break; - } - - for (l = priv->windows; l; l = l->next) - { - ClutterActor *actor = l->data; - GList *actor_stage_views; - - actor_stage_views = clutter_actor_peek_stage_views (actor); - if (g_list_find (actor_stage_views, stage_view)) - meta_window_actor_after_paint (META_WINDOW_ACTOR (actor), stage_view); - } -} - -static void -meta_compositor_after_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - COGL_TRACE_BEGIN_SCOPED (MetaCompositorPostPaint, - "Compositor (after-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->after_paint (compositor, stage_view); -} - -static void -on_before_paint (ClutterStage *stage, - ClutterStageView *stage_view, - MetaCompositor *compositor) -{ - meta_compositor_before_paint (compositor, stage_view); -} - -static void -on_after_paint (ClutterStage *stage, - ClutterStageView *stage_view, - MetaCompositor *compositor) -{ - meta_compositor_after_paint (compositor, stage_view); -} - -static void -meta_compositor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaCompositor *compositor = META_COMPOSITOR (object); - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - switch (prop_id) - { - case PROP_DISPLAY: - priv->display = g_value_get_object (value); - break; - case PROP_BACKEND: - priv->backend = g_value_get_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -meta_compositor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaCompositor *compositor = META_COMPOSITOR (object); - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - switch (prop_id) - { - case PROP_DISPLAY: - g_value_set_object (value, priv->display); - break; - case PROP_BACKEND: - g_value_set_object (value, priv->backend); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -meta_compositor_init (MetaCompositor *compositor) -{ -} - -static void -meta_compositor_constructed (GObject *object) -{ - MetaCompositor *compositor = META_COMPOSITOR (object); - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - ClutterBackend *clutter_backend = - meta_backend_get_clutter_backend (priv->backend); - ClutterActor *stage = meta_backend_get_stage (priv->backend); - - priv->context = clutter_backend->cogl_context; - - priv->before_paint_handler_id = - g_signal_connect (stage, - "before-paint", - G_CALLBACK (on_before_paint), - compositor); - priv->after_paint_handler_id = - g_signal_connect_after (stage, - "after-paint", - G_CALLBACK (on_after_paint), - compositor); - - priv->laters = meta_laters_new (compositor); - - G_OBJECT_CLASS (meta_compositor_parent_class)->constructed (object); -} - -static void -meta_compositor_dispose (GObject *object) -{ - MetaCompositor *compositor = META_COMPOSITOR (object); - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - ClutterActor *stage = meta_backend_get_stage (priv->backend); - - g_clear_pointer (&priv->laters, meta_laters_free); - - g_clear_signal_handler (&priv->stage_presented_id, stage); - g_clear_signal_handler (&priv->before_paint_handler_id, stage); - g_clear_signal_handler (&priv->after_paint_handler_id, stage); - - g_clear_signal_handler (&priv->top_window_actor_destroy_id, - priv->top_window_actor); - - g_clear_pointer (&priv->window_group, clutter_actor_destroy); - g_clear_pointer (&priv->top_window_group, clutter_actor_destroy); - g_clear_pointer (&priv->feedback_group, clutter_actor_destroy); - g_clear_pointer (&priv->windows, g_list_free); - - G_OBJECT_CLASS (meta_compositor_parent_class)->dispose (object); -} - -static void -meta_compositor_class_init (MetaCompositorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = meta_compositor_set_property; - object_class->get_property = meta_compositor_get_property; - object_class->constructed = meta_compositor_constructed; - object_class->dispose = meta_compositor_dispose; - - klass->remove_window = meta_compositor_real_remove_window; - klass->before_paint = meta_compositor_real_before_paint; - klass->after_paint = meta_compositor_real_after_paint; - - obj_props[PROP_DISPLAY] = - g_param_spec_object ("display", - "display", - "MetaDisplay", - META_TYPE_DISPLAY, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_props[PROP_BACKEND] = - g_param_spec_object ("backend", - "backend", - "MetaBackend", - META_TYPE_BACKEND, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, N_PROPS, obj_props); -} - -/** - * meta_disable_unredirect_for_display: - * @display: a #MetaDisplay - * - * Disables unredirection, can be useful in situations where having - * unredirected windows is undesirable like when recording a video. - * - */ -void -meta_disable_unredirect_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - if (display->closing) - return; - - compositor = get_compositor_for_display (display); - priv = meta_compositor_get_instance_private (compositor); - - priv->disable_unredirect_count++; -} - -/** - * meta_enable_unredirect_for_display: - * @display: a #MetaDisplay - * - * Enables unredirection which reduces the overhead for apps like games. - * - */ -void -meta_enable_unredirect_for_display (MetaDisplay *display) -{ - MetaCompositor *compositor; - MetaCompositorPrivate *priv; - - if (display->closing) - return; - - compositor = get_compositor_for_display (display); - priv = meta_compositor_get_instance_private (compositor); - - if (priv->disable_unredirect_count == 0) - g_warning ("Called enable_unredirect_for_display while unredirection is enabled."); - if (priv->disable_unredirect_count > 0) - priv->disable_unredirect_count--; -} - -gboolean -meta_compositor_is_unredirect_inhibited (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->disable_unredirect_count > 0; -} - -#define FLASH_TIME_MS 50 - -static void -flash_out_completed (ClutterTimeline *timeline, - gboolean is_finished, - gpointer user_data) -{ - ClutterActor *flash = CLUTTER_ACTOR (user_data); - clutter_actor_destroy (flash); -} - -void -meta_compositor_flash_display (MetaCompositor *compositor, - MetaDisplay *display) -{ - ClutterActor *stage; - ClutterActor *flash; - ClutterTransition *transition; - gfloat width, height; - - stage = meta_get_stage_for_display (display); - clutter_actor_get_size (stage, &width, &height); - - flash = clutter_actor_new (); - clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black); - clutter_actor_set_size (flash, width, height); - clutter_actor_set_opacity (flash, 0); - clutter_actor_add_child (stage, flash); - - clutter_actor_save_easing_state (flash); - clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD); - clutter_actor_set_easing_duration (flash, FLASH_TIME_MS); - clutter_actor_set_opacity (flash, 192); - - transition = clutter_actor_get_transition (flash, "opacity"); - clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); - clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); - - g_signal_connect (transition, "stopped", - G_CALLBACK (flash_out_completed), flash); - - clutter_actor_restore_easing_state (flash); -} - -static void -window_flash_out_completed (ClutterTimeline *timeline, - gboolean is_finished, - gpointer user_data) -{ - ClutterActor *flash = CLUTTER_ACTOR (user_data); - clutter_actor_destroy (flash); -} - -void -meta_compositor_flash_window (MetaCompositor *compositor, - MetaWindow *window) -{ - ClutterActor *window_actor = - CLUTTER_ACTOR (meta_window_actor_from_window (window)); - ClutterActor *flash; - ClutterTransition *transition; - - flash = clutter_actor_new (); - clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black); - clutter_actor_set_size (flash, window->rect.width, window->rect.height); - clutter_actor_set_position (flash, - window->custom_frame_extents.left, - window->custom_frame_extents.top); - clutter_actor_set_opacity (flash, 0); - clutter_actor_add_child (window_actor, flash); - - clutter_actor_save_easing_state (flash); - clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD); - clutter_actor_set_easing_duration (flash, FLASH_TIME_MS); - clutter_actor_set_opacity (flash, 192); - - transition = clutter_actor_get_transition (flash, "opacity"); - clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); - clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); - - g_signal_connect (transition, "stopped", - G_CALLBACK (window_flash_out_completed), flash); - - clutter_actor_restore_easing_state (flash); -} - -/** - * meta_compositor_monotonic_to_high_res_xserver_time: - * @display: a #MetaDisplay - * @monotonic_time: time in the units of g_get_monotonic_time() - * - * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time - * as a "high resolution server time" - this is the server time interpolated - * to microsecond resolution. The advantage of this time representation - * is that if X server is running on the same computer as a client, and - * the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server - * time, the client can detect this, and all such clients will share a - * a time representation with high accuracy. If there is not a common - * time source, then the time synchronization will be less accurate. - */ -int64_t -meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor, - int64_t monotonic_time_us) -{ - MetaCompositorClass *klass = META_COMPOSITOR_GET_CLASS (compositor); - - return klass->monotonic_to_high_res_xserver_time (compositor, monotonic_time_us); -} - -void -meta_compositor_show_tile_preview (MetaCompositor *compositor, - MetaWindow *window, - MetaRectangle *tile_rect, - int tile_monitor_number) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - meta_plugin_manager_show_tile_preview (priv->plugin_mgr, - window, tile_rect, tile_monitor_number); -} - -void -meta_compositor_hide_tile_preview (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - meta_plugin_manager_hide_tile_preview (priv->plugin_mgr); -} - -void -meta_compositor_show_window_menu (MetaCompositor *compositor, - MetaWindow *window, - MetaWindowMenuType menu, - int x, - int y) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - meta_plugin_manager_show_window_menu (priv->plugin_mgr, window, menu, x, y); -} - -void -meta_compositor_show_window_menu_for_rect (MetaCompositor *compositor, - MetaWindow *window, - MetaWindowMenuType menu, - MetaRectangle *rect) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - meta_plugin_manager_show_window_menu_for_rect (priv->plugin_mgr, window, menu, rect); -} - -MetaCloseDialog * -meta_compositor_create_close_dialog (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return meta_plugin_manager_create_close_dialog (priv->plugin_mgr, - window); -} - -MetaInhibitShortcutsDialog * -meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return meta_plugin_manager_create_inhibit_shortcuts_dialog (priv->plugin_mgr, - window); -} - -void -meta_compositor_locate_pointer (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - meta_plugin_manager_locate_pointer (priv->plugin_mgr); -} - -MetaPluginManager * -meta_compositor_get_plugin_manager (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->plugin_mgr; -} - -MetaDisplay * -meta_compositor_get_display (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->display; -} - -ClutterStage * -meta_compositor_get_stage (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return CLUTTER_STAGE (meta_backend_get_stage (priv->backend)); -} - -MetaWindowActor * -meta_compositor_get_top_window_actor (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->top_window_actor; -} - -gboolean -meta_compositor_is_switching_workspace (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->switch_workspace_in_progress > 0; -} - -MetaLaters * -meta_compositor_get_laters (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->laters; -} diff --git a/src/compositor/meta-background-actor-private.h b/src/compositor/meta-background-actor-private.h deleted file mode 100644 index bdf8c4744..000000000 --- a/src/compositor/meta-background-actor-private.h +++ /dev/null @@ -1,10 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_BACKGROUND_ACTOR_PRIVATE_H -#define META_BACKGROUND_ACTOR_PRIVATE_H - -#include "meta/meta-background-actor.h" - -cairo_region_t *meta_background_actor_get_clip_region (MetaBackgroundActor *self); - -#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c deleted file mode 100644 index 105f94259..000000000 --- a/src/compositor/meta-background-actor.c +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright 2009 Sander Dijkhuis - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - * - * Portions adapted from gnome-shell/src/shell-global.c - */ - -#include "config.h" - -#include "compositor/meta-background-actor-private.h" -#include "compositor/meta-background-content-private.h" - -#include "compositor/meta-cullable.h" - -enum -{ - PROP_META_DISPLAY = 1, - PROP_MONITOR, -}; - -struct _MetaBackgroundActor -{ - ClutterActor parent; - - MetaDisplay *display; - int monitor; - - MetaBackgroundContent *content; -}; - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); - -static void -maybe_create_content (MetaBackgroundActor *self) -{ - g_autoptr (ClutterContent) content = NULL; - - if (self->content || !self->display || self->monitor == -1) - return; - - content = meta_background_content_new (self->display, self->monitor); - self->content = META_BACKGROUND_CONTENT (content); - clutter_actor_set_content (CLUTTER_ACTOR (self), content); -} - -static void -meta_background_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); - - switch (prop_id) - { - case PROP_META_DISPLAY: - self->display = g_value_get_object (value); - maybe_create_content (self); - break; - case PROP_MONITOR: - self->monitor = g_value_get_int (value); - maybe_create_content (self); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); - - switch (prop_id) - { - case PROP_META_DISPLAY: - g_value_set_object (value, self->display); - break; - case PROP_MONITOR: - g_value_set_int (value, self->monitor); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_actor_class_init (MetaBackgroundActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->set_property = meta_background_actor_set_property; - object_class->get_property = meta_background_actor_get_property; - - param_spec = g_param_spec_object ("meta-display", - "MetaDisplay", - "MetaDisplay", - META_TYPE_DISPLAY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_META_DISPLAY, - param_spec); - - param_spec = g_param_spec_int ("monitor", - "monitor", - "monitor", - 0, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_MONITOR, - param_spec); -} - -static void -meta_background_actor_init (MetaBackgroundActor *self) -{ - self->monitor = -1; - - clutter_actor_set_request_mode (CLUTTER_ACTOR (self), - CLUTTER_REQUEST_CONTENT_SIZE); -} - -/** - * meta_background_actor_new: - * @monitor: Index of the monitor for which to draw the background - * - * Creates a new actor to draw the background for the given monitor. - * - * Return value: the newly created background actor - */ -ClutterActor * -meta_background_actor_new (MetaDisplay *display, - int monitor) -{ - MetaBackgroundActor *self; - - self = g_object_new (META_TYPE_BACKGROUND_ACTOR, - "meta-display", display, - "monitor", monitor, - NULL); - - return CLUTTER_ACTOR (self); -} - -static void -meta_background_actor_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable); - - if (!self->content) - return; - - meta_background_content_cull_out (self->content, - unobscured_region, - clip_region); -} - -static void -meta_background_actor_reset_culling (MetaCullable *cullable) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable); - - if (!self->content) - return; - - meta_background_content_reset_culling (self->content); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_background_actor_cull_out; - iface->reset_culling = meta_background_actor_reset_culling; -} - -/** - * meta_background_actor_get_clip_region: - * @self: a #MetaBackgroundActor - * - * Return value (transfer none): a #cairo_region_t that represents the part of - * the background not obscured by other #MetaBackgroundActor or - * #MetaWindowActor objects. - */ -cairo_region_t * -meta_background_actor_get_clip_region (MetaBackgroundActor *self) -{ - if (!self->content) - return NULL; - - return meta_background_content_get_clip_region (self->content); -} diff --git a/src/compositor/meta-background-content-private.h b/src/compositor/meta-background-content-private.h deleted file mode 100644 index 284cddb3a..000000000 --- a/src/compositor/meta-background-content-private.h +++ /dev/null @@ -1,16 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_BACKGROUND_CONTENT_PRIVATE_H -#define META_BACKGROUND_CONTENT_PRIVATE_H - -#include "meta/meta-background-content.h" - -cairo_region_t *meta_background_content_get_clip_region (MetaBackgroundContent *self); - -void meta_background_content_cull_out (MetaBackgroundContent *self, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region); - -void meta_background_content_reset_culling (MetaBackgroundContent *self); - -#endif /* META_BACKGROUND_CONTENT_PRIVATE_H */ diff --git a/src/compositor/meta-background-content.c b/src/compositor/meta-background-content.c deleted file mode 100644 index 86f777752..000000000 --- a/src/compositor/meta-background-content.c +++ /dev/null @@ -1,1312 +0,0 @@ -/* - * Copyright 2009 Sander Dijkhuis - * Copyright 2014 Red Hat, Inc. - * Copyright 2020 Endless Foundation. - * - * 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, see <http://www.gnu.org/licenses/>. - * - * Portions adapted from gnome-shell/src/shell-global.c - */ - - -/** - * SECTION:meta-background-content - * @title: MetaBackgroundContent - * @short_description: ClutterContent for painting the root window background - * - */ - -/* - * The overall model drawing model of this content is that we have one - * texture, or two interpolated textures, possibly with alpha or - * margins that let the underlying background show through, blended - * over a solid color or a gradient. The result of that combination - * can then be affected by a "vignette" that darkens the background - * away from a central point (or as a no-GLSL fallback, simply darkens - * the background) and by overall opacity. - * - * As of GNOME 3.14, GNOME is only using a fraction of this when the - * user sets the background through the control center - what can be - * set is: - * - * A single image without a border - * An animation of images without a border that blend together, - * with the blend changing every 4-5 minutes - * A solid color with a repeated noise texture blended over it - * - * This all is pretty easy to do in a fragment shader, except when: - * - * A) We don't have GLSL - in this case, the operation of - * interpolating the two textures and blending the result over the - * background can't be expressed with Cogl's fixed-function layer - * combining (which is confined to what GL's texture environment - * combining can do) So we can only handle the above directly if - * there are no margins or alpha. - * - * B) The image textures are sliced. Texture size limits on older - * hardware (pre-965 intel hardware, r300, etc.) is often 2048, - * and it would be common to use a texture larger than this for a - * background and expect it to be scaled down. Cogl can compensate - * for this by breaking the texture up into multiple textures, but - * can't multitexture with sliced textures. So we can only handle - * the above if there's a single texture. - * - * However, even when we *can* represent everything in a single pass, - * it's not necessarily efficient. If we want to draw a 1024x768 - * background, it's pretty inefficient to bilinearly texture from - * two 2560x1440 images and mix that. So the drawing model we take - * here is that MetaBackground generates a single texture (which - * might be a 1x1 texture for a solid color, or a 1x2 texture for a - * gradient, or a repeated texture for wallpaper, or a pre-rendered - * texture the size of the screen), and we draw with that, possibly - * adding the vignette and opacity. - */ - -#include "config.h" - -#include "compositor/meta-background-content-private.h" - -#include "backends/meta-backend-private.h" -#include "clutter/clutter.h" -#include "compositor/clutter-utils.h" -#include "compositor/cogl-utils.h" -#include "compositor/meta-background-private.h" -#include "compositor/meta-cullable.h" -#include "meta/display.h" - -typedef enum -{ - CHANGED_BACKGROUND = 1 << 0, - CHANGED_EFFECTS = 1 << 2, - CHANGED_VIGNETTE_PARAMETERS = 1 << 3, - CHANGED_GRADIENT_PARAMETERS = 1 << 4, - CHANGED_ROUNDED_CLIP_PARAMETERS = 1 << 5, - CHANGED_ALL = 0xFFFF -} ChangedFlags; - -#define GRADIENT_VERTEX_SHADER_DECLARATIONS \ -"uniform vec2 scale;\n" \ -"varying vec2 position;\n" \ - -#define GRADIENT_VERTEX_SHADER_CODE \ -"position = cogl_tex_coord0_in.xy * scale;\n" \ - -#define GRADIENT_FRAGMENT_SHADER_DECLARATIONS \ -"uniform float gradient_height_perc;\n" \ -"uniform float gradient_max_darkness;\n" \ -"varying vec2 position;\n" \ - -#define GRADIENT_FRAGMENT_SHADER_CODE \ -"float min_brightness = 1.0 - gradient_max_darkness;\n" \ -"float gradient_y_pos = min(position.y, gradient_height_perc) / gradient_height_perc;\n" \ -"float pixel_brightness = (1.0 - min_brightness) * gradient_y_pos + min_brightness;\n" \ -"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \ - -#define VIGNETTE_VERTEX_SHADER_DECLARATIONS \ -"uniform vec2 scale;\n" \ -"uniform vec2 offset;\n" \ -"varying vec2 position;\n" \ - -#define VIGNETTE_VERTEX_SHADER_CODE \ -"position = cogl_tex_coord0_in.xy * scale + offset;\n" \ - -#define VIGNETTE_SQRT_2 "1.4142" - -#define VIGNETTE_FRAGMENT_SHADER_DECLARATIONS \ -"uniform float vignette_sharpness;\n" \ -"varying vec2 position;\n" \ -"float rand(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123); }\n" \ - -#define VIGNETTE_FRAGMENT_SHADER_CODE \ -"float t = " VIGNETTE_SQRT_2 " * length(position);\n" \ -"t = min(t, 1.0);\n" \ -"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \ -"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \ -"cogl_color_out.rgb += (rand(position) - 0.5) / 255.0;\n" \ - -/* The ellipsis_dist(), ellipsis_coverage() and rounded_rect_coverage() are - * copied from GSK, see gsk_ellipsis_dist(), gsk_ellipsis_coverage(), and - * gsk_rounded_rect_coverage() here: - * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.3.1/gsk/gl/resources/preamble.fs.glsl - */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS \ -"uniform vec4 bounds; // x, y: top left; w, v: bottom right \n"\ -"uniform vec4 corner_centers_1; // x, y: top left; w, v: top right \n"\ -"uniform vec4 corner_centers_2; // x, y: bottom right; w, v: bottom left \n"\ -"uniform vec2 pixel_step; \n"\ -" \n"\ -"float \n"\ -"ellipsis_dist (vec2 p, vec2 radius) \n"\ -"{ \n"\ -" if (radius == vec2(0, 0)) \n"\ -" return 0.0; \n"\ -" \n"\ -" vec2 p0 = p / radius; \n"\ -" vec2 p1 = (2.0 * p0) / radius; \n"\ -" \n"\ -" return (dot(p0, p0) - 1.0) / length (p1); \n"\ -"} \n"\ -" \n"\ -"float \n"\ -"ellipsis_coverage (vec2 point, vec2 center, vec2 radius) \n"\ -"{ \n"\ -" float d = ellipsis_dist ((point - center), radius); \n"\ -" return clamp (0.5 - d, 0.0, 1.0); \n"\ -"} \n"\ -" \n"\ -"float \n"\ -"rounded_rect_coverage (vec4 bounds, \n"\ -" vec4 corner_centers_1, \n"\ -" vec4 corner_centers_2, \n"\ -" vec2 p) \n"\ -"{ \n"\ -" if (p.x < bounds.x || p.y < bounds.y || \n"\ -" p.x >= bounds.z || p.y >= bounds.w) \n"\ -" return 0.0; \n"\ -" \n"\ -" vec2 ref_tl = corner_centers_1.xy; \n"\ -" vec2 ref_tr = corner_centers_1.zw; \n"\ -" vec2 ref_br = corner_centers_2.xy; \n"\ -" vec2 ref_bl = corner_centers_2.zw; \n"\ -" \n"\ -" if (p.x >= ref_tl.x && p.x >= ref_bl.x && \n"\ -" p.x <= ref_tr.x && p.x <= ref_br.x) \n"\ -" return 1.0; \n"\ -" \n"\ -" if (p.y >= ref_tl.y && p.y >= ref_tr.y && \n"\ -" p.y <= ref_bl.y && p.y <= ref_br.y) \n"\ -" return 1.0; \n"\ -" \n"\ -" vec2 rad_tl = corner_centers_1.xy - bounds.xy; \n"\ -" vec2 rad_tr = corner_centers_1.zw - bounds.zy; \n"\ -" vec2 rad_br = corner_centers_2.xy - bounds.zw; \n"\ -" vec2 rad_bl = corner_centers_2.zw - bounds.xw; \n"\ -" \n"\ -" float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); \n"\ -" float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); \n"\ -" float d_br = ellipsis_coverage(p, ref_br, rad_br); \n"\ -" float d_bl = ellipsis_coverage(p, ref_bl, rad_bl); \n"\ -" \n"\ -" vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl); \n"\ -" \n"\ -" bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y, \n"\ -" p.x > ref_tr.x && p.y < ref_tr.y, \n"\ -" p.x > ref_br.x && p.y > ref_br.y, \n"\ -" p.x < ref_bl.x && p.y > ref_bl.y); \n"\ -" \n"\ -" return 1.0 - dot(vec4(is_out), corner_coverages); \n"\ -"} \n" - -#define ROUNDED_CLIP_FRAGMENT_SHADER_CODE \ -"vec2 texture_coord; \n"\ -" \n"\ -"texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\ -" \n"\ -"cogl_color_out *= rounded_rect_coverage (bounds, \n"\ -" corner_centers_1, \n"\ -" corner_centers_2, \n"\ -" texture_coord); \n" - -typedef struct _MetaBackgroundLayer MetaBackgroundLayer; - -typedef enum -{ - PIPELINE_VIGNETTE = (1 << 0), - PIPELINE_BLEND = (1 << 1), - PIPELINE_GRADIENT = (1 << 2), - PIPELINE_ROUNDED_CLIP = (1 << 3), - - PIPELINE_ALL = (PIPELINE_VIGNETTE | - PIPELINE_BLEND | - PIPELINE_GRADIENT | - PIPELINE_ROUNDED_CLIP) -} PipelineFlags; - -struct _MetaBackgroundContent -{ - GObject parent; - - MetaDisplay *display; - int monitor; - - MetaBackground *background; - - gboolean gradient; - double gradient_max_darkness; - int gradient_height; - - gboolean vignette; - double vignette_brightness; - double vignette_sharpness; - - gboolean has_rounded_clip; - float rounded_clip_radius; - gboolean rounded_clip_bounds_set; - graphene_rect_t rounded_clip_bounds; - - ChangedFlags changed; - CoglPipeline *pipeline; - PipelineFlags pipeline_flags; - cairo_rectangle_int_t texture_area; - int texture_width, texture_height; - - cairo_region_t *clip_region; - cairo_region_t *unobscured_region; -}; - -static void clutter_content_iface_init (ClutterContentInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaBackgroundContent, - meta_background_content, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, - clutter_content_iface_init)); - -enum -{ - PROP_0, - PROP_META_DISPLAY, - PROP_MONITOR, - PROP_BACKGROUND, - PROP_GRADIENT, - PROP_GRADIENT_HEIGHT, - PROP_GRADIENT_MAX_DARKNESS, - PROP_VIGNETTE, - PROP_VIGNETTE_SHARPNESS, - PROP_VIGNETTE_BRIGHTNESS, - PROP_ROUNDED_CLIP_RADIUS, - N_PROPS, -}; - -static GParamSpec *properties[N_PROPS] = { NULL, }; - -static void -set_clip_region (MetaBackgroundContent *self, - cairo_region_t *clip_region) -{ - g_clear_pointer (&self->clip_region, cairo_region_destroy); - if (clip_region) - { - if (cairo_region_is_empty (clip_region)) - self->clip_region = cairo_region_reference (clip_region); - else - self->clip_region = cairo_region_copy (clip_region); - } -} - -static void -set_unobscured_region (MetaBackgroundContent *self, - cairo_region_t *unobscured_region) -{ - g_clear_pointer (&self->unobscured_region, cairo_region_destroy); - if (unobscured_region) - { - if (cairo_region_is_empty (unobscured_region)) - self->unobscured_region = cairo_region_reference (unobscured_region); - else - self->unobscured_region = cairo_region_copy (unobscured_region); - } -} - -static void -invalidate_pipeline (MetaBackgroundContent *self, - ChangedFlags changed) -{ - self->changed |= changed; -} - -static void -on_background_changed (MetaBackground *background, - MetaBackgroundContent *self) -{ - invalidate_pipeline (self, CHANGED_BACKGROUND); - clutter_content_invalidate (CLUTTER_CONTENT (self)); -} - -static CoglPipeline * -make_pipeline (PipelineFlags pipeline_flags) -{ - static CoglPipeline *templates[PIPELINE_ALL + 1]; - CoglPipeline **templatep; - - g_assert (pipeline_flags < G_N_ELEMENTS (templates)); - - templatep = &templates[pipeline_flags]; - if (*templatep == NULL) - { - /* Cogl automatically caches pipelines with no eviction policy, - * so we need to prevent identical pipelines from getting cached - * separately, by reusing the same shader snippets. - */ - *templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL)); - - if ((pipeline_flags & PIPELINE_VIGNETTE) != 0) - { - static CoglSnippet *vignette_vertex_snippet; - static CoglSnippet *vignette_fragment_snippet; - - if (!vignette_vertex_snippet) - vignette_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, - VIGNETTE_VERTEX_SHADER_DECLARATIONS, - VIGNETTE_VERTEX_SHADER_CODE); - - cogl_pipeline_add_snippet (*templatep, vignette_vertex_snippet); - - if (!vignette_fragment_snippet) - vignette_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, - VIGNETTE_FRAGMENT_SHADER_DECLARATIONS, - VIGNETTE_FRAGMENT_SHADER_CODE); - - cogl_pipeline_add_snippet (*templatep, vignette_fragment_snippet); - } - - if ((pipeline_flags & PIPELINE_GRADIENT) != 0) - { - static CoglSnippet *gradient_vertex_snippet; - static CoglSnippet *gradient_fragment_snippet; - - if (!gradient_vertex_snippet) - gradient_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, - GRADIENT_VERTEX_SHADER_DECLARATIONS, - GRADIENT_VERTEX_SHADER_CODE); - - cogl_pipeline_add_snippet (*templatep, gradient_vertex_snippet); - - if (!gradient_fragment_snippet) - gradient_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, - GRADIENT_FRAGMENT_SHADER_DECLARATIONS, - GRADIENT_FRAGMENT_SHADER_CODE); - - cogl_pipeline_add_snippet (*templatep, gradient_fragment_snippet); - } - - if ((pipeline_flags & PIPELINE_ROUNDED_CLIP) != 0) - { - static CoglSnippet *rounded_clip_fragment_snippet; - - if (!rounded_clip_fragment_snippet) - { - rounded_clip_fragment_snippet = - cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, - ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS, - ROUNDED_CLIP_FRAGMENT_SHADER_CODE); - } - - cogl_pipeline_add_snippet (*templatep, rounded_clip_fragment_snippet); - } - - - if ((pipeline_flags & PIPELINE_BLEND) == 0) - cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL); - } - - return cogl_pipeline_copy (*templatep); -} - -static void -setup_pipeline (MetaBackgroundContent *self, - ClutterActor *actor, - ClutterPaintContext *paint_context, - cairo_rectangle_int_t *actor_pixel_rect) -{ - PipelineFlags pipeline_flags = 0; - guint8 opacity; - float color_component; - CoglFramebuffer *fb; - CoglPipelineFilter min_filter, mag_filter; - - opacity = clutter_actor_get_paint_opacity (actor); - if (opacity < 255) - pipeline_flags |= PIPELINE_BLEND; - if (self->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) - pipeline_flags |= PIPELINE_VIGNETTE; - if (self->gradient && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) - pipeline_flags |= PIPELINE_GRADIENT; - if (self->has_rounded_clip && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) - pipeline_flags |= PIPELINE_ROUNDED_CLIP | PIPELINE_BLEND; - - if (pipeline_flags != self->pipeline_flags) - g_clear_pointer (&self->pipeline, cogl_object_unref); - - if (self->pipeline == NULL) - { - self->pipeline_flags = pipeline_flags; - self->pipeline = make_pipeline (pipeline_flags); - self->changed = CHANGED_ALL; - } - - if (self->changed & CHANGED_BACKGROUND) - { - CoglPipelineWrapMode wrap_mode; - CoglTexture *texture = meta_background_get_texture (self->background, - self->monitor, - &self->texture_area, - &wrap_mode); - - if (texture) - { - self->texture_width = cogl_texture_get_width (texture); - self->texture_height = cogl_texture_get_height (texture); - } - else - { - self->texture_width = 0; - self->texture_height = 0; - } - - cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); - cogl_pipeline_set_layer_wrap_mode (self->pipeline, 0, wrap_mode); - - self->changed &= ~CHANGED_BACKGROUND; - } - - if (self->changed & CHANGED_VIGNETTE_PARAMETERS) - { - cogl_pipeline_set_uniform_1f (self->pipeline, - cogl_pipeline_get_uniform_location (self->pipeline, - "vignette_sharpness"), - self->vignette_sharpness); - - self->changed &= ~CHANGED_VIGNETTE_PARAMETERS; - } - - if (self->changed & CHANGED_GRADIENT_PARAMETERS) - { - MetaRectangle monitor_geometry; - float gradient_height_perc; - - meta_display_get_monitor_geometry (self->display, - self->monitor, &monitor_geometry); - gradient_height_perc = MAX (0.0001, self->gradient_height / (float)monitor_geometry.height); - cogl_pipeline_set_uniform_1f (self->pipeline, - cogl_pipeline_get_uniform_location (self->pipeline, - "gradient_height_perc"), - gradient_height_perc); - cogl_pipeline_set_uniform_1f (self->pipeline, - cogl_pipeline_get_uniform_location (self->pipeline, - "gradient_max_darkness"), - self->gradient_max_darkness); - - self->changed &= ~CHANGED_GRADIENT_PARAMETERS; - } - - if (self->changed & CHANGED_ROUNDED_CLIP_PARAMETERS) - { - float monitor_scale; - float bounds_x1, bounds_x2, bounds_y1, bounds_y2; - float clip_radius; - - monitor_scale = meta_is_stage_views_scaled () - ? meta_display_get_monitor_scale (self->display, self->monitor) - : 1.0; - - if (self->rounded_clip_bounds_set) - { - bounds_x1 = self->rounded_clip_bounds.origin.x; - bounds_x2 = self->rounded_clip_bounds.origin.x + self->rounded_clip_bounds.size.width; - bounds_y1 = self->rounded_clip_bounds.origin.y; - bounds_y2 = self->rounded_clip_bounds.origin.y + self->rounded_clip_bounds.size.height; - - bounds_x1 *= monitor_scale; - bounds_x2 *= monitor_scale; - bounds_y1 *= monitor_scale; - bounds_y2 *= monitor_scale; - } - else - { - bounds_x1 = 0.0; - bounds_x2 = self->texture_width; - bounds_y1 = 0.0; - bounds_y2 = self->texture_height; - } - - clip_radius = self->rounded_clip_radius * monitor_scale; - - float bounds[] = { - bounds_x1, - bounds_y1, - bounds_x2, - bounds_y2, - }; - - float corner_centers_1[] = { - bounds_x1 + clip_radius, - bounds_y1 + clip_radius, - bounds_x2 - clip_radius, - bounds_y1 + clip_radius, - }; - - float corner_centers_2[] = { - bounds_x2 - clip_radius, - bounds_y2 - clip_radius, - bounds_x1 + clip_radius, - bounds_y2 - clip_radius, - }; - - int bounds_uniform_location; - int corner_centers_1_uniform_location; - int corner_centers_2_uniform_location; - - bounds_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, "bounds"); - corner_centers_1_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, "corner_centers_1"); - corner_centers_2_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, "corner_centers_2"); - - cogl_pipeline_set_uniform_float (self->pipeline, - bounds_uniform_location, - 4, 1, - bounds); - - cogl_pipeline_set_uniform_float (self->pipeline, - corner_centers_1_uniform_location, - 4, 1, - corner_centers_1); - - cogl_pipeline_set_uniform_float (self->pipeline, - corner_centers_2_uniform_location, - 4, 1, - corner_centers_2); - - self->changed &= ~CHANGED_ROUNDED_CLIP_PARAMETERS; - } - - if (self->vignette) - { - color_component = self->vignette_brightness * opacity / 255.; - - if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) - { - /* Darken everything to match the average brightness that would - * be there if we were drawing the vignette, which is - * (1 - (pi/12.) * vignette_sharpness) [exercise for the reader :] - */ - color_component *= (1 - 0.74 * self->vignette_sharpness); - } - } - else - { - color_component = opacity / 255.; - } - - cogl_pipeline_set_color4f (self->pipeline, - color_component, - color_component, - color_component, - opacity / 255.); - - fb = clutter_paint_context_get_framebuffer (paint_context); - if (meta_actor_painting_untransformed (fb, - actor_pixel_rect->width, - actor_pixel_rect->height, - self->texture_width, - self->texture_height, - NULL, NULL)) - { - min_filter = COGL_PIPELINE_FILTER_NEAREST; - mag_filter = COGL_PIPELINE_FILTER_NEAREST; - } - else - { - min_filter = COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST; - mag_filter = COGL_PIPELINE_FILTER_LINEAR; - } - - cogl_pipeline_set_layer_filters (self->pipeline, 0, min_filter, mag_filter); -} - -static void -set_glsl_parameters (MetaBackgroundContent *self, - cairo_rectangle_int_t *actor_pixel_rect) -{ - float monitor_scale; - float scale[2]; - float offset[2]; - int pixel_step_uniform_location; - - monitor_scale = meta_is_stage_views_scaled () - ? meta_display_get_monitor_scale (self->display, self->monitor) - : 1.0; - - float pixel_step[] = { - 1.f / (self->texture_area.width * monitor_scale), - 1.f / (self->texture_area.height * monitor_scale), - }; - - pixel_step_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, - "pixel_step"); - - /* Compute a scale and offset for transforming texture coordinates to the - * coordinate system from [-0.5 to 0.5] across the area of the actor - */ - scale[0] = self->texture_area.width / (float)actor_pixel_rect->width; - scale[1] = self->texture_area.height / (float)actor_pixel_rect->height; - offset[0] = self->texture_area.x / (float)actor_pixel_rect->width - 0.5; - offset[1] = self->texture_area.y / (float)actor_pixel_rect->height - 0.5; - - cogl_pipeline_set_uniform_float (self->pipeline, - cogl_pipeline_get_uniform_location (self->pipeline, - "scale"), - 2, 1, scale); - - cogl_pipeline_set_uniform_float (self->pipeline, - cogl_pipeline_get_uniform_location (self->pipeline, - "offset"), - 2, 1, offset); - - cogl_pipeline_set_uniform_float (self->pipeline, - pixel_step_uniform_location, - 2, 1, - pixel_step); -} - -static void -paint_clipped_rectangle (MetaBackgroundContent *self, - ClutterPaintNode *node, - ClutterActorBox *actor_box, - cairo_rectangle_int_t *rect) -{ - g_autoptr (ClutterPaintNode) pipeline_node = NULL; - float h_scale, v_scale; - float x1, y1, x2, y2; - float tx1, ty1, tx2, ty2; - - h_scale = self->texture_area.width / clutter_actor_box_get_width (actor_box); - v_scale = self->texture_area.height / clutter_actor_box_get_height (actor_box); - - x1 = rect->x; - y1 = rect->y; - x2 = rect->x + rect->width; - y2 = rect->y + rect->height; - - tx1 = (x1 * h_scale - self->texture_area.x) / (float)self->texture_area.width; - ty1 = (y1 * v_scale - self->texture_area.y) / (float)self->texture_area.height; - tx2 = (x2 * h_scale - self->texture_area.x) / (float)self->texture_area.width; - ty2 = (y2 * v_scale - self->texture_area.y) / (float)self->texture_area.height; - - pipeline_node = clutter_pipeline_node_new (self->pipeline); - clutter_paint_node_set_name (pipeline_node, "MetaBackgroundContent (Slice)"); - clutter_paint_node_add_texture_rectangle (pipeline_node, - &(ClutterActorBox) { - .x1 = x1, - .y1 = y1, - .x2 = x2, - .y2 = y2, - }, - tx1, ty1, - tx2, ty2); - - clutter_paint_node_add_child (node, pipeline_node); -} - -static void -meta_background_content_paint_content (ClutterContent *content, - ClutterActor *actor, - ClutterPaintNode *node, - ClutterPaintContext *paint_context) -{ - MetaBackgroundContent *self = META_BACKGROUND_CONTENT (content); - ClutterActorBox actor_box; - cairo_rectangle_int_t rect_within_actor; - cairo_rectangle_int_t rect_within_stage; - cairo_region_t *region; - int i, n_rects; - float transformed_x, transformed_y, transformed_width, transformed_height; - gboolean untransformed; - - if ((self->clip_region && cairo_region_is_empty (self->clip_region))) - return; - - clutter_actor_get_content_box (actor, &actor_box); - rect_within_actor.x = actor_box.x1; - rect_within_actor.y = actor_box.y1; - rect_within_actor.width = actor_box.x2 - actor_box.x1; - rect_within_actor.height = actor_box.y2 - actor_box.y1; - - if (clutter_actor_is_in_clone_paint (actor)) - { - untransformed = FALSE; - } - else - { - clutter_actor_get_transformed_position (actor, - &transformed_x, - &transformed_y); - rect_within_stage.x = floorf (transformed_x); - rect_within_stage.y = floorf (transformed_y); - - clutter_actor_get_transformed_size (actor, - &transformed_width, - &transformed_height); - rect_within_stage.width = ceilf (transformed_width); - rect_within_stage.height = ceilf (transformed_height); - - untransformed = - rect_within_actor.x == rect_within_stage.x && - rect_within_actor.y == rect_within_stage.y && - rect_within_actor.width == rect_within_stage.width && - rect_within_actor.height == rect_within_stage.height; - } - - if (untransformed) /* actor and stage space are the same */ - { - if (self->clip_region) - { - region = cairo_region_copy (self->clip_region); - cairo_region_intersect_rectangle (region, &rect_within_stage); - } - else - { - const cairo_region_t *redraw_clip; - - redraw_clip = clutter_paint_context_get_redraw_clip (paint_context); - if (redraw_clip) - { - region = cairo_region_copy (redraw_clip); - cairo_region_intersect_rectangle (region, &rect_within_stage); - } - else - { - region = cairo_region_create_rectangle (&rect_within_stage); - } - } - } - else /* actor and stage space are different but we need actor space */ - { - if (self->clip_region) - { - region = cairo_region_copy (self->clip_region); - cairo_region_intersect_rectangle (region, &rect_within_actor); - } - else - { - region = cairo_region_create_rectangle (&rect_within_actor); - } - } - - if (self->unobscured_region) - cairo_region_intersect (region, self->unobscured_region); - - /* region is now in actor space */ - if (cairo_region_is_empty (region)) - { - cairo_region_destroy (region); - return; - } - - setup_pipeline (self, actor, paint_context, &rect_within_actor); - set_glsl_parameters (self, &rect_within_actor); - - /* Limit to how many separate rectangles we'll draw; beyond this just - * fall back and draw the whole thing */ -#define MAX_RECTS 64 - - n_rects = cairo_region_num_rectangles (region); - if (n_rects <= MAX_RECTS) - { - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - paint_clipped_rectangle (self, node, &actor_box, &rect); - } - } - else - { - cairo_rectangle_int_t rect; - cairo_region_get_extents (region, &rect); - paint_clipped_rectangle (self, node, &actor_box, &rect); - } - - cairo_region_destroy (region); -} - -static gboolean -meta_background_content_get_preferred_size (ClutterContent *content, - float *width, - float *height) - -{ - MetaBackgroundContent *background_content = META_BACKGROUND_CONTENT (content); - MetaRectangle monitor_geometry; - - meta_display_get_monitor_geometry (background_content->display, - background_content->monitor, - &monitor_geometry); - - if (width) - *width = monitor_geometry.width; - - if (height) - *height = monitor_geometry.height; - - return TRUE; -} - -static void -clutter_content_iface_init (ClutterContentInterface *iface) -{ - iface->paint_content = meta_background_content_paint_content; - iface->get_preferred_size = meta_background_content_get_preferred_size; -} - -static void -set_monitor (MetaBackgroundContent *self, - int monitor) -{ - MetaRectangle old_monitor_geometry; - MetaRectangle new_monitor_geometry; - MetaDisplay *display = self->display; - - if(self->monitor == monitor) - return; - - meta_display_get_monitor_geometry (display, self->monitor, &old_monitor_geometry); - meta_display_get_monitor_geometry (display, monitor, &new_monitor_geometry); - if(old_monitor_geometry.height != new_monitor_geometry.height) - invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS); - - self->monitor = monitor; -} - -static void -meta_background_content_dispose (GObject *object) -{ - MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object); - - set_clip_region (self, NULL); - set_unobscured_region (self, NULL); - meta_background_content_set_background (self, NULL); - - g_clear_pointer (&self->pipeline, cogl_object_unref); - - G_OBJECT_CLASS (meta_background_content_parent_class)->dispose (object); -} - -static void -meta_background_content_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object); - - switch (prop_id) - { - case PROP_META_DISPLAY: - self->display = g_value_get_object (value); - break; - case PROP_MONITOR: - set_monitor (self, g_value_get_int (value)); - break; - case PROP_BACKGROUND: - meta_background_content_set_background (self, g_value_get_object (value)); - break; - case PROP_GRADIENT: - meta_background_content_set_gradient (self, - g_value_get_boolean (value), - self->gradient_height, - self->gradient_max_darkness); - break; - case PROP_GRADIENT_HEIGHT: - meta_background_content_set_gradient (self, - self->gradient, - g_value_get_int (value), - self->gradient_max_darkness); - break; - case PROP_GRADIENT_MAX_DARKNESS: - meta_background_content_set_gradient (self, - self->gradient, - self->gradient_height, - g_value_get_double (value)); - break; - case PROP_VIGNETTE: - meta_background_content_set_vignette (self, - g_value_get_boolean (value), - self->vignette_brightness, - self->vignette_sharpness); - break; - case PROP_VIGNETTE_SHARPNESS: - meta_background_content_set_vignette (self, - self->vignette, - self->vignette_brightness, - g_value_get_double (value)); - break; - case PROP_VIGNETTE_BRIGHTNESS: - meta_background_content_set_vignette (self, - self->vignette, - g_value_get_double (value), - self->vignette_sharpness); - break; - case PROP_ROUNDED_CLIP_RADIUS: - meta_background_content_set_rounded_clip_radius (self, - g_value_get_float (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_content_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object); - - switch (prop_id) - { - case PROP_META_DISPLAY: - g_value_set_object (value, self->display); - break; - case PROP_MONITOR: - g_value_set_int (value, self->monitor); - break; - case PROP_BACKGROUND: - g_value_set_object (value, self->background); - break; - case PROP_GRADIENT: - g_value_set_boolean (value, self->gradient); - break; - case PROP_GRADIENT_HEIGHT: - g_value_set_int (value, self->gradient_height); - break; - case PROP_GRADIENT_MAX_DARKNESS: - g_value_set_double (value, self->gradient_max_darkness); - break; - case PROP_VIGNETTE: - g_value_set_boolean (value, self->vignette); - break; - case PROP_VIGNETTE_BRIGHTNESS: - g_value_set_double (value, self->vignette_brightness); - break; - case PROP_VIGNETTE_SHARPNESS: - g_value_set_double (value, self->vignette_sharpness); - break; - case PROP_ROUNDED_CLIP_RADIUS: - g_value_set_float (value, self->rounded_clip_radius); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_content_class_init (MetaBackgroundContentClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = meta_background_content_dispose; - object_class->set_property = meta_background_content_set_property; - object_class->get_property = meta_background_content_get_property; - - properties[PROP_META_DISPLAY] = - g_param_spec_object ("meta-display", - "MetaDisplay", - "MetaDisplay", - META_TYPE_DISPLAY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - properties[PROP_MONITOR] = - g_param_spec_int ("monitor", - "monitor", - "monitor", - 0, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - properties[PROP_BACKGROUND] = - g_param_spec_object ("background", - "Background", - "MetaBackground object holding background parameters", - META_TYPE_BACKGROUND, - G_PARAM_READWRITE); - - properties[PROP_GRADIENT] = - g_param_spec_boolean ("gradient", - "Gradient", - "Whether gradient effect is enabled", - FALSE, - G_PARAM_READWRITE); - - properties[PROP_GRADIENT_HEIGHT] = - g_param_spec_int ("gradient-height", - "Gradient Height", - "Height of gradient effect", - 0, G_MAXINT, 0, - G_PARAM_READWRITE); - - properties[PROP_GRADIENT_MAX_DARKNESS] = - g_param_spec_double ("gradient-max-darkness", - "Gradient Max Darkness", - "How dark is the gradient initially", - 0.0, 1.0, 0.0, - G_PARAM_READWRITE); - - properties[PROP_VIGNETTE] = - g_param_spec_boolean ("vignette", - "Vignette", - "Whether vignette effect is enabled", - FALSE, - G_PARAM_READWRITE); - - properties[PROP_VIGNETTE_BRIGHTNESS] = - g_param_spec_double ("brightness", - "Vignette Brightness", - "Brightness of vignette effect", - 0.0, 1.0, 1.0, - G_PARAM_READWRITE); - - properties[PROP_VIGNETTE_SHARPNESS] = - g_param_spec_double ("vignette-sharpness", - "Vignette Sharpness", - "Sharpness of vignette effect", - 0.0, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE); - - properties[PROP_ROUNDED_CLIP_RADIUS] = - g_param_spec_float ("rounded-clip-radius", - "Rounded clip radius", - "Rounded clip radius", - 0.0, G_MAXFLOAT, 0.0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY); - - g_object_class_install_properties (object_class, N_PROPS, properties); -} - -static void -meta_background_content_init (MetaBackgroundContent *self) -{ - self->gradient = FALSE; - self->gradient_height = 0; - self->gradient_max_darkness = 0.0; - - self->vignette = FALSE; - self->vignette_brightness = 1.0; - self->vignette_sharpness = 0.0; - - self->has_rounded_clip = FALSE; - self->rounded_clip_radius = 0.0; -} - -/** - * meta_background_content_new: - * @monitor: Index of the monitor for which to draw the background - * - * Creates a new actor to draw the background for the given monitor. - * - * Return value: (transfer full): the newly created background actor - */ -ClutterContent * -meta_background_content_new (MetaDisplay *display, - int monitor) -{ - return g_object_new (META_TYPE_BACKGROUND_CONTENT, - "meta-display", display, - "monitor", monitor, - NULL); -} - -void -meta_background_content_set_background (MetaBackgroundContent *self, - MetaBackground *background) -{ - g_return_if_fail (META_IS_BACKGROUND_CONTENT (self)); - g_return_if_fail (background == NULL || META_IS_BACKGROUND (background)); - - if (background == self->background) - return; - - if (self->background) - { - g_signal_handlers_disconnect_by_func (self->background, - (gpointer)on_background_changed, - self); - g_clear_object (&self->background); - } - - if (background) - { - self->background = g_object_ref (background); - g_signal_connect (self->background, "changed", - G_CALLBACK (on_background_changed), self); - } - - invalidate_pipeline (self, CHANGED_BACKGROUND); - clutter_content_invalidate (CLUTTER_CONTENT (self)); -} - -void -meta_background_content_set_gradient (MetaBackgroundContent *self, - gboolean enabled, - int height, - double max_darkness) -{ - gboolean changed = FALSE; - - g_return_if_fail (META_IS_BACKGROUND_CONTENT (self)); - g_return_if_fail (height >= 0); - g_return_if_fail (max_darkness >= 0. && max_darkness <= 1.); - - enabled = enabled != FALSE && height != 0; - - if (enabled != self->gradient) - { - self->gradient = enabled; - invalidate_pipeline (self, CHANGED_EFFECTS); - changed = TRUE; - } - - if (height != self->gradient_height || max_darkness != self->gradient_max_darkness) - { - self->gradient_height = height; - self->gradient_max_darkness = max_darkness; - invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS); - changed = TRUE; - } - - if (changed) - clutter_content_invalidate (CLUTTER_CONTENT (self)); -} - -void -meta_background_content_set_vignette (MetaBackgroundContent *self, - gboolean enabled, - double brightness, - double sharpness) -{ - gboolean changed = FALSE; - - g_return_if_fail (META_IS_BACKGROUND_CONTENT (self)); - g_return_if_fail (brightness >= 0. && brightness <= 1.); - g_return_if_fail (sharpness >= 0.); - - enabled = enabled != FALSE; - - if (enabled != self->vignette) - { - self->vignette = enabled; - invalidate_pipeline (self, CHANGED_EFFECTS); - changed = TRUE; - } - - if (brightness != self->vignette_brightness || sharpness != self->vignette_sharpness) - { - self->vignette_brightness = brightness; - self->vignette_sharpness = sharpness; - invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS); - changed = TRUE; - } - - if (changed) - clutter_content_invalidate (CLUTTER_CONTENT (self)); -} - -void -meta_background_content_set_rounded_clip_radius (MetaBackgroundContent *self, - float radius) -{ - gboolean enabled; - gboolean changed = FALSE; - - g_return_if_fail (META_IS_BACKGROUND_CONTENT (self)); - g_return_if_fail (radius >= 0.0); - - enabled = radius > 0.0; - - if (enabled != self->has_rounded_clip) - { - self->has_rounded_clip = enabled; - invalidate_pipeline (self, CHANGED_EFFECTS); - changed = TRUE; - } - - if (!G_APPROX_VALUE (radius, self->rounded_clip_radius, FLT_EPSILON)) - { - self->rounded_clip_radius = radius; - invalidate_pipeline (self, CHANGED_ROUNDED_CLIP_PARAMETERS); - changed = TRUE; - } - - if (changed) - { - clutter_content_invalidate (CLUTTER_CONTENT (self)); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROUNDED_CLIP_RADIUS]); - } -} - -/** - * meta_background_content_set_rounded_clip_bounds: - * @self: The #MetaBackgroundContent - * @bounds: (allow-none): The new bounding clip rectangle, or %NULL - * - * Sets the bounding clip rectangle of the #MetaBackgroundContent that's used - * when a rounded clip set via meta_background_content_set_rounded_clip_radius() - * is in effect, set it to %NULL to use no bounding clip, rounding the edges - * of the full texture. - */ -void -meta_background_content_set_rounded_clip_bounds (MetaBackgroundContent *self, - const graphene_rect_t *bounds) -{ - g_return_if_fail (META_IS_BACKGROUND_CONTENT (self)); - - if (bounds == NULL) - { - if (!self->rounded_clip_bounds_set) - return; - - self->rounded_clip_bounds_set = FALSE; - } - else - { - if (self->rounded_clip_bounds_set && - graphene_rect_equal (&self->rounded_clip_bounds, bounds)) - return; - - self->rounded_clip_bounds_set = TRUE; - graphene_rect_init_from_rect (&self->rounded_clip_bounds, bounds); - } - - invalidate_pipeline (self, CHANGED_ROUNDED_CLIP_PARAMETERS); - clutter_content_invalidate (CLUTTER_CONTENT (self)); -} - -cairo_region_t * -meta_background_content_get_clip_region (MetaBackgroundContent *self) -{ - return self->clip_region; -} - -void -meta_background_content_cull_out (MetaBackgroundContent *self, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - set_unobscured_region (self, unobscured_region); - set_clip_region (self, clip_region); -} - -void -meta_background_content_reset_culling (MetaBackgroundContent *self) -{ - set_unobscured_region (self, NULL); - set_clip_region (self, NULL); -} diff --git a/src/compositor/meta-background-group.c b/src/compositor/meta-background-group.c deleted file mode 100644 index e30b8af4c..000000000 --- a/src/compositor/meta-background-group.c +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/** - * SECTION:meta-background-group - * @title: MetaBackgroundGroup - * @short_description: Container for background actors - * - * This class is a subclass of ClutterActor with special handling for - * MetaBackgroundActor/MetaBackgroundGroup when painting children. - * It makes sure to only draw the parts of the backgrounds not - * occluded by opaque windows. - * - * See #MetaWindowGroup for more information behind the motivation, - * and details on implementation. - */ - -#include "config.h" - -#include "compositor/meta-cullable.h" -#include "meta/meta-background-group.h" - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaBackgroundGroup, meta_background_group, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); - -static void -meta_background_group_class_init (MetaBackgroundGroupClass *klass) -{ -} - -static void -meta_background_group_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); -} - -static void -meta_background_group_reset_culling (MetaCullable *cullable) -{ - meta_cullable_reset_culling_children (cullable); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_background_group_cull_out; - iface->reset_culling = meta_background_group_reset_culling; -} - -static void -meta_background_group_init (MetaBackgroundGroup *self) -{ -} - -ClutterActor * -meta_background_group_new (void) -{ - MetaBackgroundGroup *background_group; - - background_group = g_object_new (META_TYPE_BACKGROUND_GROUP, NULL); - - return CLUTTER_ACTOR (background_group); -} diff --git a/src/compositor/meta-background-image.c b/src/compositor/meta-background-image.c deleted file mode 100644 index ed9425bb3..000000000 --- a/src/compositor/meta-background-image.c +++ /dev/null @@ -1,370 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -/** - * SECTION:meta-background-image - * @title: MetaBackgroundImage - * @short_description: objects holding images loaded from files, used for backgrounds - */ - -#include "config.h" - -#include "meta/meta-background-image.h" - -#include <gdk-pixbuf/gdk-pixbuf.h> -#include <gio/gio.h> - -#include "clutter/clutter.h" -#include "compositor/cogl-utils.h" - -enum -{ - LOADED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -/** - * MetaBackgroundImageCache: - * - * #MetaBackgroundImageCache caches loading of textures for backgrounds; there's actually - * nothing background specific about it, other than it is tuned to work well for - * large images as typically are used for backgrounds. - */ -struct _MetaBackgroundImageCache -{ - GObject parent_instance; - - GHashTable *images; -}; - -/** - * MetaBackgroundImage: - * - * #MetaBackgroundImage is an object that represents a loaded or loading background image. - */ -struct _MetaBackgroundImage -{ - GObject parent_instance; - GFile *file; - MetaBackgroundImageCache *cache; - gboolean in_cache; - gboolean loaded; - CoglTexture *texture; -}; - -G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJECT); - -static void -meta_background_image_cache_init (MetaBackgroundImageCache *cache) -{ - cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal); -} - -static void -meta_background_image_cache_finalize (GObject *object) -{ - MetaBackgroundImageCache *cache = META_BACKGROUND_IMAGE_CACHE (object); - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, cache->images); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - MetaBackgroundImage *image = value; - image->in_cache = FALSE; - } - - g_hash_table_destroy (cache->images); - - G_OBJECT_CLASS (meta_background_image_cache_parent_class)->finalize (object); -} - -static void -meta_background_image_cache_class_init (MetaBackgroundImageCacheClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_background_image_cache_finalize; -} - -/** - * meta_background_image_cache_get_default: - * - * Return value: (transfer none): the global singleton background cache - */ -MetaBackgroundImageCache * -meta_background_image_cache_get_default (void) -{ - static MetaBackgroundImageCache *cache; - - if (cache == NULL) - cache = g_object_new (META_TYPE_BACKGROUND_IMAGE_CACHE, NULL); - - return cache; -} - -static void -load_file (GTask *task, - MetaBackgroundImage *image, - gpointer task_data, - GCancellable *cancellable) -{ - GError *error = NULL; - GdkPixbuf *pixbuf; - GFileInputStream *stream; - - stream = g_file_read (image->file, NULL, &error); - if (stream == NULL) - { - g_task_return_error (task, error); - return; - } - - pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error); - g_object_unref (stream); - - if (pixbuf == NULL) - { - g_task_return_error (task, error); - return; - } - - g_task_return_pointer (task, pixbuf, (GDestroyNotify) g_object_unref); -} - -static void -file_loaded (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - MetaBackgroundImage *image = META_BACKGROUND_IMAGE (source_object); - GError *error = NULL; - GError *catch_error = NULL; - GTask *task; - CoglTexture *texture; - GdkPixbuf *pixbuf, *rotated; - int width, height, row_stride; - guchar *pixels; - gboolean has_alpha; - - task = G_TASK (result); - pixbuf = g_task_propagate_pointer (task, &error); - - if (pixbuf == NULL) - { - char *uri = g_file_get_uri (image->file); - g_warning ("Failed to load background '%s': %s", - uri, error->message); - g_clear_error (&error); - g_free (uri); - goto out; - } - - rotated = gdk_pixbuf_apply_embedded_orientation (pixbuf); - if (rotated != NULL) - { - g_object_unref (pixbuf); - pixbuf = rotated; - } - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - row_stride = gdk_pixbuf_get_rowstride (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); - has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); - - texture = meta_create_texture (width, height, - has_alpha ? COGL_TEXTURE_COMPONENTS_RGBA : COGL_TEXTURE_COMPONENTS_RGB, - META_TEXTURE_ALLOW_SLICING); - - if (!cogl_texture_set_data (texture, - has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, - row_stride, - pixels, 0, - &catch_error)) - { - g_warning ("Failed to create texture for background"); - g_error_free (catch_error); - cogl_object_unref (texture); - } - - image->texture = texture; - -out: - if (pixbuf != NULL) - g_object_unref (pixbuf); - - image->loaded = TRUE; - g_signal_emit (image, signals[LOADED], 0); -} - -/** - * meta_background_image_cache_load: - * @cache: a #MetaBackgroundImageCache - * @file: #GFile to load - * - * Loads an image to use as a background, or returns a reference to an - * image that is already in the process of loading or loaded. In either - * case, what is returned is a #MetaBackgroundImage which can be dereferenced - * to get a #CoglTexture. If meta_background_image_is_loaded() returns %TRUE, - * the background is loaded, otherwise the MetaBackgroundImage::loaded - * signal will be emitted exactly once. The 'loaded' state means that the - * loading process finished, whether it succeeded or failed. - * - * Return value: (transfer full): a #MetaBackgroundImage to dereference to get the loaded texture - */ -MetaBackgroundImage * -meta_background_image_cache_load (MetaBackgroundImageCache *cache, - GFile *file) -{ - MetaBackgroundImage *image; - GTask *task; - - g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL); - g_return_val_if_fail (file != NULL, NULL); - - image = g_hash_table_lookup (cache->images, file); - if (image != NULL) - return g_object_ref (image); - - image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL); - image->cache = cache; - image->in_cache = TRUE; - image->file = g_object_ref (file); - g_hash_table_insert (cache->images, image->file, image); - - task = g_task_new (image, NULL, file_loaded, NULL); - - g_task_run_in_thread (task, (GTaskThreadFunc) load_file); - g_object_unref (task); - - return image; -} - -/** - * meta_background_image_cache_purge: - * @cache: a #MetaBackgroundImageCache - * @file: file to remove from the cache - * - * Remove an entry from the cache; this would be used if monitoring - * showed that the file changed. - */ -void -meta_background_image_cache_purge (MetaBackgroundImageCache *cache, - GFile *file) -{ - MetaBackgroundImage *image; - - g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache)); - g_return_if_fail (file != NULL); - - image = g_hash_table_lookup (cache->images, file); - if (image == NULL) - return; - - g_hash_table_remove (cache->images, image->file); - image->in_cache = FALSE; -} - -G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT); - -static void -meta_background_image_init (MetaBackgroundImage *image) -{ -} - -static void -meta_background_image_finalize (GObject *object) -{ - MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object); - - if (image->in_cache) - g_hash_table_remove (image->cache->images, image->file); - - if (image->texture) - cogl_object_unref (image->texture); - if (image->file) - g_object_unref (image->file); - - G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object); -} - -static void -meta_background_image_class_init (MetaBackgroundImageClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_background_image_finalize; - - signals[LOADED] = - g_signal_new ("loaded", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -/** - * meta_background_image_is_loaded: - * @image: a #MetaBackgroundImage - * - * Return value: %TRUE if loading has already completed, %FALSE otherwise - */ -gboolean -meta_background_image_is_loaded (MetaBackgroundImage *image) -{ - g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE); - - return image->loaded; -} - -/** - * meta_background_image_get_success: - * @image: a #MetaBackgroundImage - * - * This function is a convenience function for checking for success, - * without having to call meta_background_image_get_texture() and - * handle the return of a Cogl type. - * - * Return value: %TRUE if loading completed successfully, otherwise %FALSE - */ -gboolean -meta_background_image_get_success (MetaBackgroundImage *image) -{ - g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE); - - return image->texture != NULL; -} - -/** - * meta_background_image_get_texture: - * @image: a #MetaBackgroundImage - * - * Return value: (transfer none): a #CoglTexture if loading succeeded; if - * loading failed or has not yet finished, %NULL. - */ -CoglTexture * -meta_background_image_get_texture (MetaBackgroundImage *image) -{ - g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), NULL); - - return image->texture; -} diff --git a/src/compositor/meta-background-private.h b/src/compositor/meta-background-private.h deleted file mode 100644 index 871487da4..000000000 --- a/src/compositor/meta-background-private.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_BACKGROUND_PRIVATE_H -#define META_BACKGROUND_PRIVATE_H - -#include "cogl/cogl.h" -#include "meta/meta-background.h" - -CoglTexture *meta_background_get_texture (MetaBackground *self, - int monitor_index, - cairo_rectangle_int_t *texture_area, - CoglPipelineWrapMode *wrap_mode); - -#endif /* META_BACKGROUND_PRIVATE_H */ diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c deleted file mode 100644 index c0d8d335d..000000000 --- a/src/compositor/meta-background.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright 2013 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "compositor/meta-background-private.h" - -#include <string.h> - -#include "backends/meta-backend-private.h" -#include "compositor/cogl-utils.h" -#include "meta/display.h" -#include "meta/meta-background-image.h" -#include "meta/meta-background.h" -#include "meta/meta-monitor-manager.h" -#include "meta/util.h" - -enum -{ - CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _MetaBackgroundMonitor MetaBackgroundMonitor; - -struct _MetaBackgroundMonitor -{ - gboolean dirty; - CoglTexture *texture; - CoglFramebuffer *fbo; -}; - -struct _MetaBackground -{ - GObject parent; - - MetaDisplay *display; - MetaBackgroundMonitor *monitors; - int n_monitors; - - GDesktopBackgroundStyle style; - GDesktopBackgroundShading shading_direction; - ClutterColor color; - ClutterColor second_color; - - GFile *file1; - MetaBackgroundImage *background_image1; - GFile *file2; - MetaBackgroundImage *background_image2; - - CoglTexture *color_texture; - CoglTexture *wallpaper_texture; - - float blend_factor; - - guint wallpaper_allocation_failed : 1; -}; - -enum -{ - PROP_META_DISPLAY = 1, - PROP_MONITOR, -}; - -G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT) - -static gboolean texture_has_alpha (CoglTexture *texture); - -static GSList *all_backgrounds = NULL; - -static void -free_fbos (MetaBackground *self) -{ - int i; - - for (i = 0; i < self->n_monitors; i++) - { - MetaBackgroundMonitor *monitor = &self->monitors[i]; - - g_clear_object (&monitor->fbo); - cogl_clear_object (&monitor->texture); - } -} - -static void -free_color_texture (MetaBackground *self) -{ - cogl_clear_object (&self->color_texture); -} - -static void -free_wallpaper_texture (MetaBackground *self) -{ - cogl_clear_object (&self->wallpaper_texture); - - self->wallpaper_allocation_failed = FALSE; -} - -static void -invalidate_monitor_backgrounds (MetaBackground *self) -{ - free_fbos (self); - g_clear_pointer (&self->monitors, g_free); - self->n_monitors = 0; - - if (self->display) - { - int i; - - self->n_monitors = meta_display_get_n_monitors (self->display); - self->monitors = g_new0 (MetaBackgroundMonitor, self->n_monitors); - - for (i = 0; i < self->n_monitors; i++) - self->monitors[i].dirty = TRUE; - } -} - -static void -on_monitors_changed (MetaBackground *self) -{ - invalidate_monitor_backgrounds (self); -} - -static void -set_display (MetaBackground *self, - MetaDisplay *display) -{ - g_set_object (&self->display, display); - - invalidate_monitor_backgrounds (self); -} - -static void -meta_background_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) - { - case PROP_META_DISPLAY: - set_display (META_BACKGROUND (object), g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaBackground *self = META_BACKGROUND (object); - - switch (prop_id) - { - case PROP_META_DISPLAY: - g_value_set_object (value, self->display); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -need_prerender (MetaBackground *self) -{ - CoglTexture *texture1 = self->background_image1 ? meta_background_image_get_texture (self->background_image1) : NULL; - CoglTexture *texture2 = self->background_image2 ? meta_background_image_get_texture (self->background_image2) : NULL; - - if (texture1 == NULL && texture2 == NULL) - return FALSE; - - if (texture2 == NULL && self->style == G_DESKTOP_BACKGROUND_STYLE_WALLPAPER) - return FALSE; - - return TRUE; -} - -static void -mark_changed (MetaBackground *self) -{ - int i; - - if (!need_prerender (self)) - free_fbos (self); - - for (i = 0; i < self->n_monitors; i++) - self->monitors[i].dirty = TRUE; - - g_signal_emit (self, signals[CHANGED], 0); -} - -static void -on_background_loaded (MetaBackgroundImage *image, - MetaBackground *self) -{ - mark_changed (self); -} - -static gboolean -file_equal0 (GFile *file1, - GFile *file2) -{ - if (file1 == file2) - return TRUE; - - if ((file1 == NULL) || (file2 == NULL)) - return FALSE; - - return g_file_equal (file1, file2); -} - -static void -set_file (MetaBackground *self, - GFile **filep, - MetaBackgroundImage **imagep, - GFile *file, - gboolean force_reload) -{ - if (force_reload || !file_equal0 (*filep, file)) - { - if (*imagep) - { - g_signal_handlers_disconnect_by_func (*imagep, - (gpointer)on_background_loaded, - self); - g_clear_object (imagep); - } - - g_set_object (filep, file); - - if (file) - { - MetaBackgroundImageCache *cache = meta_background_image_cache_get_default (); - - *imagep = meta_background_image_cache_load (cache, file); - g_signal_connect (*imagep, "loaded", - G_CALLBACK (on_background_loaded), self); - } - } -} - -static void -on_gl_video_memory_purged (MetaBackground *self) -{ - MetaBackgroundImageCache *cache = meta_background_image_cache_get_default (); - - /* The GPU memory that just got invalidated is the texture inside - * self->background_image1,2 and/or its mipmaps. However, to save memory the - * original pixbuf isn't kept in RAM so we can't do a simple re-upload. The - * only copy of the image was the one in texture memory that got invalidated. - * So we need to do a full reload from disk. - */ - if (self->file1) - { - meta_background_image_cache_purge (cache, self->file1); - set_file (self, &self->file1, &self->background_image1, self->file1, TRUE); - } - - if (self->file2) - { - meta_background_image_cache_purge (cache, self->file2); - set_file (self, &self->file2, &self->background_image2, self->file2, TRUE); - } - - mark_changed (self); -} - -static void -meta_background_dispose (GObject *object) -{ - MetaBackground *self = META_BACKGROUND (object); - - free_color_texture (self); - free_wallpaper_texture (self); - - set_file (self, &self->file1, &self->background_image1, NULL, FALSE); - set_file (self, &self->file2, &self->background_image2, NULL, FALSE); - - set_display (self, NULL); - - G_OBJECT_CLASS (meta_background_parent_class)->dispose (object); -} - -static void -meta_background_finalize (GObject *object) -{ - all_backgrounds = g_slist_remove (all_backgrounds, object); - - G_OBJECT_CLASS (meta_background_parent_class)->finalize (object); -} - -static void -meta_background_constructed (GObject *object) -{ - MetaBackground *self = META_BACKGROUND (object); - MetaMonitorManager *monitor_manager = meta_monitor_manager_get (); - - G_OBJECT_CLASS (meta_background_parent_class)->constructed (object); - - g_signal_connect_object (self->display, "gl-video-memory-purged", - G_CALLBACK (on_gl_video_memory_purged), object, G_CONNECT_SWAPPED); - - g_signal_connect_object (monitor_manager, "monitors-changed", - G_CALLBACK (on_monitors_changed), self, - G_CONNECT_SWAPPED); -} - -static void -meta_background_class_init (MetaBackgroundClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->dispose = meta_background_dispose; - object_class->finalize = meta_background_finalize; - object_class->constructed = meta_background_constructed; - object_class->set_property = meta_background_set_property; - object_class->get_property = meta_background_get_property; - - signals[CHANGED] = - g_signal_new ("changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - param_spec = g_param_spec_object ("meta-display", - "MetaDisplay", - "MetaDisplay", - META_TYPE_DISPLAY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_META_DISPLAY, - param_spec); - -} - -static void -meta_background_init (MetaBackground *self) -{ - all_backgrounds = g_slist_prepend (all_backgrounds, self); -} - -static void -set_texture_area_from_monitor_area (cairo_rectangle_int_t *monitor_area, - cairo_rectangle_int_t *texture_area) -{ - texture_area->x = 0; - texture_area->y = 0; - texture_area->width = monitor_area->width; - texture_area->height = monitor_area->height; -} - -static void -get_texture_area (MetaBackground *self, - cairo_rectangle_int_t *monitor_rect, - float monitor_scale, - CoglTexture *texture, - cairo_rectangle_int_t *texture_area) -{ - cairo_rectangle_int_t image_area; - int screen_width, screen_height; - float texture_width, texture_height; - float monitor_x_scale, monitor_y_scale; - - texture_width = cogl_texture_get_width (texture); - texture_height = cogl_texture_get_height (texture); - - switch (self->style) - { - case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: - default: - /* paint region is whole actor, and the texture - * is scaled disproportionately to fit the actor - */ - set_texture_area_from_monitor_area (monitor_rect, texture_area); - break; - case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: - meta_display_get_size (self->display, &screen_width, &screen_height); - - /* Start off by centering a tile in the middle of the - * total screen area taking care of the monitor scaling. - */ - image_area.x = (screen_width - texture_width) / 2.0; - image_area.y = (screen_height - texture_height) / 2.0; - image_area.width = texture_width; - image_area.height = texture_height; - - /* Translate into the coordinate system of the particular monitor */ - image_area.x -= monitor_rect->x; - image_area.y -= monitor_rect->y; - - *texture_area = image_area; - break; - case G_DESKTOP_BACKGROUND_STYLE_CENTERED: - /* paint region is the original image size centered in the actor, - * and the texture is scaled to the original image size */ - image_area.width = texture_width; - image_area.height = texture_height; - image_area.x = monitor_rect->width / 2 - image_area.width / 2; - image_area.y = monitor_rect->height / 2 - image_area.height / 2; - - *texture_area = image_area; - break; - case G_DESKTOP_BACKGROUND_STYLE_SCALED: - case G_DESKTOP_BACKGROUND_STYLE_ZOOM: - /* paint region is the actor size in one dimension, and centered and - * scaled by proportional amount in the other dimension. - * - * SCALED forces the centered dimension to fit on screen. - * ZOOM forces the centered dimension to grow off screen - */ - monitor_x_scale = monitor_rect->width / texture_width; - monitor_y_scale = monitor_rect->height / texture_height; - - if ((self->style == G_DESKTOP_BACKGROUND_STYLE_SCALED && - (monitor_x_scale < monitor_y_scale)) || - (self->style == G_DESKTOP_BACKGROUND_STYLE_ZOOM && - (monitor_x_scale > monitor_y_scale))) - { - /* Fill image to exactly fit actor horizontally */ - image_area.width = monitor_rect->width; - image_area.height = texture_height * monitor_x_scale; - - /* Position image centered vertically in actor */ - image_area.x = 0; - image_area.y = monitor_rect->height / 2 - image_area.height / 2; - } - else - { - /* Scale image to exactly fit actor vertically */ - image_area.width = texture_width * monitor_y_scale; - image_area.height = monitor_rect->height; - - /* Position image centered horizontally in actor */ - image_area.x = monitor_rect->width / 2 - image_area.width / 2; - image_area.y = 0; - } - - *texture_area = image_area; - break; - - case G_DESKTOP_BACKGROUND_STYLE_SPANNED: - { - /* paint region is the union of all monitors, with the origin - * of the region set to align with monitor associated with the background. - */ - meta_display_get_size (self->display, &screen_width, &screen_height); - - /* unclipped texture area is whole screen, scaled depending on monitor */ - image_area.width = screen_width * monitor_scale; - image_area.height = screen_height * monitor_scale; - - /* But make (0,0) line up with the appropriate monitor */ - image_area.x = -monitor_rect->x; - image_area.y = -monitor_rect->y; - - *texture_area = image_area; - break; - } - } -} - -static gboolean -draw_texture (MetaBackground *self, - CoglFramebuffer *framebuffer, - CoglPipeline *pipeline, - CoglTexture *texture, - cairo_rectangle_int_t *monitor_area, - float monitor_scale) -{ - cairo_rectangle_int_t texture_area; - gboolean bare_region_visible; - - get_texture_area (self, monitor_area, monitor_scale, texture, &texture_area); - - switch (self->style) - { - case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: - case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: - case G_DESKTOP_BACKGROUND_STYLE_ZOOM: - case G_DESKTOP_BACKGROUND_STYLE_SPANNED: - /* Draw the entire monitor */ - cogl_framebuffer_draw_textured_rectangle (framebuffer, - pipeline, - 0, - 0, - monitor_area->width, - monitor_area->height, - - texture_area.x / (float)texture_area.width, - - texture_area.y / (float)texture_area.height, - (monitor_area->width - texture_area.x) / (float)texture_area.width, - (monitor_area->height - texture_area.y) / (float)texture_area.height); - - bare_region_visible = texture_has_alpha (texture); - - /* Draw just the texture */ - break; - case G_DESKTOP_BACKGROUND_STYLE_CENTERED: - case G_DESKTOP_BACKGROUND_STYLE_SCALED: - cogl_framebuffer_draw_textured_rectangle (framebuffer, - pipeline, - texture_area.x, texture_area.y, - texture_area.x + texture_area.width, - texture_area.y + texture_area.height, - 0, 0, 1.0, 1.0); - bare_region_visible = texture_has_alpha (texture) || memcmp (&texture_area, monitor_area, sizeof (cairo_rectangle_int_t)) != 0; - break; - case G_DESKTOP_BACKGROUND_STYLE_NONE: - bare_region_visible = TRUE; - break; - default: - g_return_val_if_reached(FALSE); - } - - return bare_region_visible; -} - -static void -ensure_color_texture (MetaBackground *self) -{ - if (self->color_texture == NULL) - { - ClutterBackend *backend = clutter_get_default_backend (); - CoglContext *ctx = clutter_backend_get_cogl_context (backend); - GError *error = NULL; - uint8_t pixels[6]; - int width, height; - - if (self->shading_direction == G_DESKTOP_BACKGROUND_SHADING_SOLID) - { - width = 1; - height = 1; - - pixels[0] = self->color.red; - pixels[1] = self->color.green; - pixels[2] = self->color.blue; - } - else - { - switch (self->shading_direction) - { - case G_DESKTOP_BACKGROUND_SHADING_VERTICAL: - width = 1; - height = 2; - break; - case G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL: - width = 2; - height = 1; - break; - default: - g_return_if_reached (); - } - - pixels[0] = self->color.red; - pixels[1] = self->color.green; - pixels[2] = self->color.blue; - pixels[3] = self->second_color.red; - pixels[4] = self->second_color.green; - pixels[5] = self->second_color.blue; - } - - self->color_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width, height, - COGL_PIXEL_FORMAT_RGB_888, - width * 3, - pixels, - &error)); - - if (error != NULL) - { - meta_warning ("Failed to allocate color texture: %s", error->message); - g_error_free (error); - } - } -} - -typedef enum -{ - PIPELINE_REPLACE, - PIPELINE_ADD, - PIPELINE_OVER_REVERSE, -} PipelineType; - -static CoglPipeline * -create_pipeline (PipelineType type) -{ - const char * const blend_strings[3] = { - [PIPELINE_REPLACE] = "RGBA = ADD (SRC_COLOR, 0)", - [PIPELINE_ADD] = "RGBA = ADD (SRC_COLOR, DST_COLOR)", - [PIPELINE_OVER_REVERSE] = "RGBA = ADD (SRC_COLOR * (1 - DST_COLOR[A]), DST_COLOR)", - }; - static CoglPipeline *templates[3]; - - if (templates[type] == NULL) - { - templates[type] = meta_create_texture_pipeline (NULL); - cogl_pipeline_set_blend (templates[type], blend_strings[type], NULL); - } - - cogl_pipeline_set_layer_filters (templates[type], - 0, - COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR, - COGL_PIPELINE_FILTER_LINEAR); - - return cogl_pipeline_copy (templates[type]); -} - -static gboolean -texture_has_alpha (CoglTexture *texture) -{ - if (!texture) - return FALSE; - - switch (cogl_texture_get_components (texture)) - { - case COGL_TEXTURE_COMPONENTS_A: - case COGL_TEXTURE_COMPONENTS_RGBA: - return TRUE; - case COGL_TEXTURE_COMPONENTS_RG: - case COGL_TEXTURE_COMPONENTS_RGB: - case COGL_TEXTURE_COMPONENTS_DEPTH: - return FALSE; - default: - g_assert_not_reached (); - return FALSE; - } -} - -static gboolean -ensure_wallpaper_texture (MetaBackground *self, - CoglTexture *texture) -{ - if (self->wallpaper_texture == NULL && !self->wallpaper_allocation_failed) - { - int width = cogl_texture_get_width (texture); - int height = cogl_texture_get_height (texture); - CoglOffscreen *offscreen; - CoglFramebuffer *fbo; - GError *catch_error = NULL; - CoglPipeline *pipeline; - - self->wallpaper_texture = meta_create_texture (width, height, - COGL_TEXTURE_COMPONENTS_RGBA, - META_TEXTURE_FLAGS_NONE); - offscreen = cogl_offscreen_new_with_texture (self->wallpaper_texture); - fbo = COGL_FRAMEBUFFER (offscreen); - - if (!cogl_framebuffer_allocate (fbo, &catch_error)) - { - /* This probably means that the size of the wallpapered texture is larger - * than the maximum texture size; we treat it as permanent until the - * background is changed again. - */ - g_error_free (catch_error); - - cogl_clear_object (&self->wallpaper_texture); - g_object_unref (fbo); - - self->wallpaper_allocation_failed = TRUE; - return FALSE; - } - - cogl_framebuffer_orthographic (fbo, 0, 0, - width, height, -1., 1.); - - pipeline = create_pipeline (PIPELINE_REPLACE); - cogl_pipeline_set_layer_texture (pipeline, 0, texture); - cogl_framebuffer_draw_textured_rectangle (fbo, pipeline, 0, 0, width, height, - 0., 0., 1., 1.); - cogl_object_unref (pipeline); - - if (texture_has_alpha (texture)) - { - ensure_color_texture (self); - - pipeline = create_pipeline (PIPELINE_OVER_REVERSE); - cogl_pipeline_set_layer_texture (pipeline, 0, self->color_texture); - cogl_framebuffer_draw_rectangle (fbo, pipeline, 0, 0, width, height); - cogl_object_unref (pipeline); - } - - g_object_unref (fbo); - } - - return self->wallpaper_texture != NULL; -} - -static CoglPipelineWrapMode -get_wrap_mode (GDesktopBackgroundStyle style) -{ - switch (style) - { - case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: - return COGL_PIPELINE_WRAP_MODE_REPEAT; - case G_DESKTOP_BACKGROUND_STYLE_NONE: - case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: - case G_DESKTOP_BACKGROUND_STYLE_CENTERED: - case G_DESKTOP_BACKGROUND_STYLE_SCALED: - case G_DESKTOP_BACKGROUND_STYLE_ZOOM: - case G_DESKTOP_BACKGROUND_STYLE_SPANNED: - default: - return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; - } -} - -static int -get_best_mipmap_level (CoglTexture *texture, - int visible_width, - int visible_height) -{ - int mipmap_width = cogl_texture_get_width (texture); - int mipmap_height = cogl_texture_get_height (texture); - int halves = 0; - - while (mipmap_width >= visible_width && mipmap_height >= visible_height) - { - halves++; - mipmap_width /= 2; - mipmap_height /= 2; - } - - return MAX (0, halves - 1); -} - -CoglTexture * -meta_background_get_texture (MetaBackground *self, - int monitor_index, - cairo_rectangle_int_t *texture_area, - CoglPipelineWrapMode *wrap_mode) -{ - MetaBackgroundMonitor *monitor; - MetaRectangle geometry; - cairo_rectangle_int_t monitor_area; - CoglTexture *texture1, *texture2; - float monitor_scale; - - g_return_val_if_fail (META_IS_BACKGROUND (self), NULL); - g_return_val_if_fail (monitor_index >= 0 && monitor_index < self->n_monitors, NULL); - - monitor = &self->monitors[monitor_index]; - - meta_display_get_monitor_geometry (self->display, monitor_index, &geometry); - monitor_scale = meta_display_get_monitor_scale (self->display, monitor_index); - monitor_area.x = geometry.x; - monitor_area.y = geometry.y; - monitor_area.width = geometry.width; - monitor_area.height = geometry.height; - - texture1 = self->background_image1 ? meta_background_image_get_texture (self->background_image1) : NULL; - texture2 = self->background_image2 ? meta_background_image_get_texture (self->background_image2) : NULL; - - if (texture1 == NULL && texture2 == NULL) - { - ensure_color_texture (self); - if (texture_area) - set_texture_area_from_monitor_area (&monitor_area, texture_area); - if (wrap_mode) - *wrap_mode = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; - return self->color_texture; - } - - if (texture2 == NULL && self->style == G_DESKTOP_BACKGROUND_STYLE_WALLPAPER && - self->shading_direction == G_DESKTOP_BACKGROUND_SHADING_SOLID && - ensure_wallpaper_texture (self, texture1)) - { - if (texture_area) - get_texture_area (self, &monitor_area, monitor_scale, - self->wallpaper_texture, texture_area); - if (wrap_mode) - *wrap_mode = COGL_PIPELINE_WRAP_MODE_REPEAT; - return self->wallpaper_texture; - } - - if (monitor->dirty) - { - GError *catch_error = NULL; - gboolean bare_region_visible = FALSE; - int texture_width, texture_height; - - if (meta_is_stage_views_scaled ()) - { - texture_width = monitor_area.width * monitor_scale; - texture_height = monitor_area.height * monitor_scale; - } - else - { - texture_width = monitor_area.width; - texture_height = monitor_area.height; - } - - if (monitor->texture == NULL) - { - CoglOffscreen *offscreen; - - monitor->texture = meta_create_texture (texture_width, - texture_height, - COGL_TEXTURE_COMPONENTS_RGB, - META_TEXTURE_FLAGS_NONE); - offscreen = cogl_offscreen_new_with_texture (monitor->texture); - monitor->fbo = COGL_FRAMEBUFFER (offscreen); - } - - if (self->style != G_DESKTOP_BACKGROUND_STYLE_WALLPAPER) - { - monitor_area.x *= monitor_scale; - monitor_area.y *= monitor_scale; - monitor_area.width *= monitor_scale; - monitor_area.height *= monitor_scale; - } - - if (!cogl_framebuffer_allocate (monitor->fbo, &catch_error)) - { - /* Texture or framebuffer allocation failed; it's unclear why this happened; - * we'll try again the next time this is called. (MetaBackgroundActor - * caches the result, so user might be left without a background.) - */ - cogl_clear_object (&monitor->texture); - g_clear_object (&monitor->fbo); - - g_error_free (catch_error); - return NULL; - } - - cogl_framebuffer_orthographic (monitor->fbo, 0, 0, - monitor_area.width, monitor_area.height, -1., 1.); - - if (texture2 != NULL && self->blend_factor != 0.0) - { - CoglPipeline *pipeline = create_pipeline (PIPELINE_REPLACE); - int mipmap_level; - - mipmap_level = get_best_mipmap_level (texture2, - texture_width, - texture_height); - - cogl_pipeline_set_color4f (pipeline, - self->blend_factor, self->blend_factor, self->blend_factor, self->blend_factor); - cogl_pipeline_set_layer_texture (pipeline, 0, texture2); - cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (self->style)); - cogl_pipeline_set_layer_max_mipmap_level (pipeline, 0, mipmap_level); - - bare_region_visible = draw_texture (self, - monitor->fbo, pipeline, - texture2, &monitor_area, - monitor_scale); - - cogl_object_unref (pipeline); - } - else - { - cogl_framebuffer_clear4f (monitor->fbo, - COGL_BUFFER_BIT_COLOR, - 0.0, 0.0, 0.0, 0.0); - } - - if (texture1 != NULL && self->blend_factor != 1.0) - { - CoglPipeline *pipeline = create_pipeline (PIPELINE_ADD); - int mipmap_level; - - mipmap_level = get_best_mipmap_level (texture1, - texture_width, - texture_height); - - cogl_pipeline_set_color4f (pipeline, - (1 - self->blend_factor), - (1 - self->blend_factor), - (1 - self->blend_factor), - (1 - self->blend_factor)); - cogl_pipeline_set_layer_texture (pipeline, 0, texture1); - cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (self->style)); - cogl_pipeline_set_layer_max_mipmap_level (pipeline, 0, mipmap_level); - - bare_region_visible = bare_region_visible || draw_texture (self, - monitor->fbo, pipeline, - texture1, &monitor_area, - monitor_scale); - - cogl_object_unref (pipeline); - } - - if (bare_region_visible) - { - CoglPipeline *pipeline = create_pipeline (PIPELINE_OVER_REVERSE); - - ensure_color_texture (self); - cogl_pipeline_set_layer_texture (pipeline, 0, self->color_texture); - cogl_framebuffer_draw_rectangle (monitor->fbo, - pipeline, - 0, 0, - monitor_area.width, monitor_area.height); - cogl_object_unref (pipeline); - } - - monitor->dirty = FALSE; - } - - if (texture_area) - set_texture_area_from_monitor_area (&geometry, texture_area); - - if (wrap_mode) - *wrap_mode = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; - return monitor->texture; -} - -MetaBackground * -meta_background_new (MetaDisplay *display) -{ - return g_object_new (META_TYPE_BACKGROUND, - "meta-display", display, - NULL); -} - -void -meta_background_set_color (MetaBackground *self, - ClutterColor *color) -{ - ClutterColor dummy = { 0 }; - - g_return_if_fail (META_IS_BACKGROUND (self)); - g_return_if_fail (color != NULL); - - meta_background_set_gradient (self, - G_DESKTOP_BACKGROUND_SHADING_SOLID, - color, &dummy); -} - -void -meta_background_set_gradient (MetaBackground *self, - GDesktopBackgroundShading shading_direction, - ClutterColor *color, - ClutterColor *second_color) -{ - g_return_if_fail (META_IS_BACKGROUND (self)); - g_return_if_fail (color != NULL); - g_return_if_fail (second_color != NULL); - - self->shading_direction = shading_direction; - self->color = *color; - self->second_color = *second_color; - - free_color_texture (self); - free_wallpaper_texture (self); - mark_changed (self); -} - -/** - * meta_background_set_file: - * @self: a #MetaBackground - * @file: (nullable): a #GFile representing the background file - * @style: the background style to apply - * - * Set the background to @file - */ -void -meta_background_set_file (MetaBackground *self, - GFile *file, - GDesktopBackgroundStyle style) -{ - g_return_if_fail (META_IS_BACKGROUND (self)); - - meta_background_set_blend (self, file, NULL, 0.0, style); -} - -void -meta_background_set_blend (MetaBackground *self, - GFile *file1, - GFile *file2, - double blend_factor, - GDesktopBackgroundStyle style) -{ - g_return_if_fail (META_IS_BACKGROUND (self)); - g_return_if_fail (blend_factor >= 0.0 && blend_factor <= 1.0); - - set_file (self, &self->file1, &self->background_image1, file1, FALSE); - set_file (self, &self->file2, &self->background_image2, file2, FALSE); - - self->blend_factor = blend_factor; - self->style = style; - - free_wallpaper_texture (self); - mark_changed (self); -} - -void -meta_background_refresh_all (void) -{ - GSList *l; - - for (l = all_backgrounds; l; l = l->next) - mark_changed (l->data); -} diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c deleted file mode 100644 index 00f66b70d..000000000 --- a/src/compositor/meta-compositor-native.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#include "config.h" - -#include "compositor/meta-compositor-native.h" - -#include "backends/meta-logical-monitor.h" -#include "compositor/meta-surface-actor-wayland.h" - -struct _MetaCompositorNative -{ - MetaCompositorServer parent; -}; - -G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native, - META_TYPE_COMPOSITOR_SERVER) - -static MetaRendererView * -get_window_view (MetaRenderer *renderer, - MetaWindow *window) -{ - GList *l; - MetaRendererView *view_found = NULL; - - for (l = meta_renderer_get_views (renderer); l; l = l->next) - { - ClutterStageView *stage_view = l->data; - MetaRectangle view_layout; - - clutter_stage_view_get_layout (stage_view, &view_layout); - - if (meta_rectangle_equal (&window->buffer_rect, - &view_layout)) - { - if (view_found) - return NULL; - view_found = META_RENDERER_VIEW (stage_view); - } - } - - return view_found; -} - -static void -maybe_assign_primary_plane (MetaCompositor *compositor) -{ - MetaBackend *backend = meta_get_backend (); - MetaRenderer *renderer = meta_backend_get_renderer (backend); - MetaWindowActor *window_actor; - MetaWindow *window; - MetaRendererView *view; - CoglFramebuffer *framebuffer; - CoglOnscreen *onscreen; - MetaSurfaceActor *surface_actor; - MetaSurfaceActorWayland *surface_actor_wayland; - g_autoptr (CoglScanout) scanout = NULL; - - if (meta_compositor_is_unredirect_inhibited (compositor)) - return; - - window_actor = meta_compositor_get_top_window_actor (compositor); - if (!window_actor) - return; - - if (meta_window_actor_effect_in_progress (window_actor)) - return; - - if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor))) - return; - - if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1) - return; - - window = meta_window_actor_get_meta_window (window_actor); - if (!window) - return; - - view = get_window_view (renderer, window); - if (!view) - return; - - framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view)); - if (!COGL_IS_ONSCREEN (framebuffer)) - return; - - surface_actor = meta_window_actor_get_surface (window_actor); - if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor)) - return; - - surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor); - onscreen = COGL_ONSCREEN (framebuffer); - scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland, - onscreen); - if (!scanout) - return; - - clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout); -} - -static void -meta_compositor_native_before_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - MetaCompositorClass *parent_class; - - maybe_assign_primary_plane (compositor); - - parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class); - parent_class->before_paint (compositor, stage_view); -} - -MetaCompositorNative * -meta_compositor_native_new (MetaDisplay *display, - MetaBackend *backend) -{ - return g_object_new (META_TYPE_COMPOSITOR_NATIVE, - "display", display, - "backend", backend, - NULL); -} - -static void -meta_compositor_native_init (MetaCompositorNative *compositor_native) -{ -} - -static void -meta_compositor_native_class_init (MetaCompositorNativeClass *klass) -{ - MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); - - compositor_class->before_paint = meta_compositor_native_before_paint; -} diff --git a/src/compositor/meta-compositor-native.h b/src/compositor/meta-compositor-native.h deleted file mode 100644 index 2b1c65208..000000000 --- a/src/compositor/meta-compositor-native.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#ifndef META_COMPOSITOR_NATIVE_H -#define META_COMPOSITOR_NATIVE_H - -#include "compositor/meta-compositor-server.h" - -#define META_TYPE_COMPOSITOR_NATIVE (meta_compositor_native_get_type ()) -G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native, - META, COMPOSITOR_NATIVE, MetaCompositor) - -MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display, - MetaBackend *backend); - -#endif /* META_COMPOSITOR_NATIVE_H */ diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c deleted file mode 100644 index 179dc83ef..000000000 --- a/src/compositor/meta-compositor-server.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#include "config.h" - -#include "backends/meta-dnd-private.h" -#include "compositor/meta-compositor-server.h" -#include "core/display-private.h" - -G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR) - -static gboolean -meta_compositor_server_manage (MetaCompositor *compositor, - GError **error) -{ - return TRUE; -} - -static void -meta_compositor_server_unmanage (MetaCompositor *compositor) -{ -} - -static int64_t -meta_compositor_server_monotonic_to_high_res_xserver_time (MetaCompositor *compositor, - int64_t monotonic_time_us) -{ - return meta_translate_to_high_res_xserver_time (monotonic_time_us); -} - -static void -meta_compositor_server_grab_begin (MetaCompositor *compositor) -{ - MetaDisplay *display; - - display = meta_compositor_get_display (compositor); - meta_display_sync_wayland_input_focus (display); - meta_display_cancel_touch (display); - -#ifdef HAVE_WAYLAND - meta_dnd_wayland_handle_begin_modal (compositor); -#endif -} - -static void -meta_compositor_server_grab_end (MetaCompositor *compositor) -{ - MetaDisplay *display; - - display = meta_compositor_get_display (compositor); -#ifdef HAVE_WAYLAND - meta_dnd_wayland_handle_end_modal (compositor); -#endif - meta_display_sync_wayland_input_focus (display); -} - -MetaCompositorServer * -meta_compositor_server_new (MetaDisplay *display, - MetaBackend *backend) -{ - return g_object_new (META_TYPE_COMPOSITOR_SERVER, - "display", display, - "backend", backend, - NULL); -} - -static void -meta_compositor_server_init (MetaCompositorServer *compositor_server) -{ -} - -static void -meta_compositor_server_class_init (MetaCompositorServerClass *klass) -{ - MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); - - compositor_class->manage = meta_compositor_server_manage; - compositor_class->unmanage = meta_compositor_server_unmanage; - compositor_class->monotonic_to_high_res_xserver_time = - meta_compositor_server_monotonic_to_high_res_xserver_time; - compositor_class->grab_begin = meta_compositor_server_grab_begin; - compositor_class->grab_end = meta_compositor_server_grab_end; -} diff --git a/src/compositor/meta-compositor-server.h b/src/compositor/meta-compositor-server.h deleted file mode 100644 index 2bf8d5ec3..000000000 --- a/src/compositor/meta-compositor-server.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#ifndef META_COMPOSITOR_SERVER_H -#define META_COMPOSITOR_SERVER_H - -#include "compositor/compositor-private.h" - -#define META_TYPE_COMPOSITOR_SERVER (meta_compositor_server_get_type ()) -G_DECLARE_DERIVABLE_TYPE (MetaCompositorServer, meta_compositor_server, - META, COMPOSITOR_SERVER, MetaCompositor) - -struct _MetaCompositorServerClass -{ - MetaCompositorClass parent_class; -}; - -MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display, - MetaBackend *backend); - -#endif /* META_COMPOSITOR_SERVER_H */ diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c deleted file mode 100644 index a16604640..000000000 --- a/src/compositor/meta-compositor-x11.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#include "config.h" - -#include "compositor/meta-compositor-x11.h" - -#include <X11/extensions/shape.h> -#include <X11/extensions/Xcomposite.h> - -#include "backends/x11/meta-backend-x11.h" -#include "backends/x11/meta-clutter-backend-x11.h" -#include "backends/x11/meta-event-x11.h" -#include "compositor/meta-sync-ring.h" -#include "compositor/meta-window-actor-x11.h" -#include "core/display-private.h" -#include "x11/meta-x11-display-private.h" - -struct _MetaCompositorX11 -{ - MetaCompositor parent; - - Window output; - - gulong before_update_handler_id; - gulong after_update_handler_id; - - gboolean frame_has_updated_xsurfaces; - gboolean have_x11_sync_object; - - MetaWindow *unredirected_window; - - gboolean xserver_uses_monotonic_clock; - int64_t xserver_time_query_time_us; - int64_t xserver_time_offset_us; -}; - -G_DEFINE_TYPE (MetaCompositorX11, meta_compositor_x11, META_TYPE_COMPOSITOR) - -static void -process_damage (MetaCompositorX11 *compositor_x11, - XDamageNotifyEvent *damage_xevent, - MetaWindow *window) -{ - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - MetaWindowActorX11 *window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor); - - meta_window_actor_x11_process_damage (window_actor_x11, damage_xevent); - - compositor_x11->frame_has_updated_xsurfaces = TRUE; -} - -void -meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, - XEvent *xevent, - MetaWindow *window) -{ - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - MetaDisplay *display = meta_compositor_get_display (compositor); - MetaX11Display *x11_display = display->x11_display; - int damage_event_base; - - damage_event_base = meta_x11_display_get_damage_event_base (x11_display); - if (xevent->type == damage_event_base + XDamageNotify) - { - /* - * Core code doesn't handle damage events, so we need to extract the - * MetaWindow ourselves. - */ - if (!window) - { - Window xwindow; - - xwindow = ((XDamageNotifyEvent *) xevent)->drawable; - window = meta_x11_display_lookup_x_window (x11_display, xwindow); - } - - if (window) - process_damage (compositor_x11, (XDamageNotifyEvent *) xevent, window); - } - - if (compositor_x11->have_x11_sync_object) - meta_sync_ring_handle_event (xevent); - - /* - * Clutter needs to know about MapNotify events otherwise it will think the - * stage is invisible - */ - if (xevent->type == MapNotify) - meta_x11_handle_event (xevent); -} - -static void -determine_server_clock_source (MetaCompositorX11 *compositor_x11) -{ - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - MetaDisplay *display = meta_compositor_get_display (compositor); - MetaX11Display *x11_display = display->x11_display; - uint32_t server_time_ms; - int64_t server_time_us; - int64_t translated_monotonic_now_us; - - server_time_ms = meta_x11_display_get_current_time_roundtrip (x11_display); - server_time_us = ms2us (server_time_ms); - translated_monotonic_now_us = - meta_translate_to_high_res_xserver_time (g_get_monotonic_time ()); - - /* If the server time offset is within a second of the monotonic time, we - * assume that they are identical. This seems like a big margin, but we want - * to be as robust as possible even if the system is under load and our - * processing of the server response is delayed. - */ - if (ABS (server_time_us - translated_monotonic_now_us) < s2us (1)) - compositor_x11->xserver_uses_monotonic_clock = TRUE; - else - compositor_x11->xserver_uses_monotonic_clock = FALSE; -} - -static gboolean -meta_compositor_x11_manage (MetaCompositor *compositor, - GError **error) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - MetaDisplay *display = meta_compositor_get_display (compositor); - MetaX11Display *x11_display = display->x11_display; - Display *xdisplay = meta_x11_display_get_xdisplay (x11_display); - int composite_version; - MetaBackend *backend = meta_get_backend (); - Window xwindow; - - if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) || - !META_X11_DISPLAY_HAS_DAMAGE (x11_display)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Missing required extension %s", - !META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ? - "composite" : "damage"); - return FALSE; - } - - composite_version = ((x11_display->composite_major_version * 10) + - x11_display->composite_minor_version); - if (composite_version < 3) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "COMPOSITE extension 3.0 required (found %d.%d)", - x11_display->composite_major_version, - x11_display->composite_minor_version); - return FALSE; - } - - determine_server_clock_source (compositor_x11); - - meta_x11_display_set_cm_selection (display->x11_display); - - compositor_x11->output = display->x11_display->composite_overlay_window; - - xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); - - XReparentWindow (xdisplay, xwindow, compositor_x11->output, 0, 0); - - meta_x11_display_clear_stage_input_region (display->x11_display); - - /* - * Make sure there isn't any left-over output shape on the overlay window by - * setting the whole screen to be an output region. - * - * Note: there doesn't seem to be any real chance of that because the X - * server will destroy the overlay window when the last client using it - * exits. - */ - XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, - ShapeBounding, 0, 0, None); - - /* - * Map overlay window before redirecting windows offscreen so we catch their - * contents until we show the stage. - */ - XMapWindow (xdisplay, compositor_x11->output); - - compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay); - - meta_compositor_redirect_x11_windows (META_COMPOSITOR (compositor)); - - return TRUE; -} - -static void -meta_compositor_x11_unmanage (MetaCompositor *compositor) -{ - MetaDisplay *display = meta_compositor_get_display (compositor); - MetaX11Display *x11_display = display->x11_display; - Display *xdisplay = x11_display->xdisplay; - Window xroot = x11_display->xroot; - - /* - * This is the most important part of cleanup - we have to do this before - * giving up the window manager selection or the next window manager won't be - * able to redirect subwindows - */ - XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); -} - -/* - * Sets an bounding shape on the COW so that the given window - * is exposed. If window is %NULL it clears the shape again. - * - * Used so we can unredirect windows, by shaping away the part - * of the COW, letting the raw window be seen through below. - */ -static void -shape_cow_for_window (MetaCompositorX11 *compositor_x11, - MetaWindow *window) -{ - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - MetaDisplay *display = meta_compositor_get_display (compositor); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - if (!window) - { - XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, - ShapeBounding, 0, 0, None); - } - else - { - XserverRegion output_region; - XRectangle screen_rect, window_bounds; - int width, height; - MetaRectangle rect; - - meta_window_get_frame_rect (window, &rect); - - window_bounds.x = rect.x; - window_bounds.y = rect.y; - window_bounds.width = rect.width; - window_bounds.height = rect.height; - - meta_display_get_size (display, &width, &height); - screen_rect.x = 0; - screen_rect.y = 0; - screen_rect.width = width; - screen_rect.height = height; - - output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); - - XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); - XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, - ShapeBounding, 0, 0, output_region); - XFixesDestroyRegion (xdisplay, output_region); - } -} - -static void -set_unredirected_window (MetaCompositorX11 *compositor_x11, - MetaWindow *window) -{ - MetaWindow *prev_unredirected_window = compositor_x11->unredirected_window; - - if (prev_unredirected_window == window) - return; - - if (prev_unredirected_window) - { - MetaWindowActor *window_actor; - MetaWindowActorX11 *window_actor_x11; - - window_actor = meta_window_actor_from_window (prev_unredirected_window); - window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor); - meta_window_actor_x11_set_unredirected (window_actor_x11, FALSE); - } - - shape_cow_for_window (compositor_x11, window); - compositor_x11->unredirected_window = window; - - if (window) - { - MetaWindowActor *window_actor; - MetaWindowActorX11 *window_actor_x11; - - window_actor = meta_window_actor_from_window (window); - window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor); - meta_window_actor_x11_set_unredirected (window_actor_x11, TRUE); - } -} - -static void -maybe_unredirect_top_window (MetaCompositorX11 *compositor_x11) -{ - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - MetaWindow *window_to_unredirect = NULL; - MetaWindowActor *window_actor; - MetaWindowActorX11 *window_actor_x11; - - if (meta_compositor_is_unredirect_inhibited (compositor)) - goto out; - - window_actor = meta_compositor_get_top_window_actor (compositor); - if (!window_actor) - goto out; - - window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor); - if (!meta_window_actor_x11_should_unredirect (window_actor_x11)) - goto out; - - window_to_unredirect = meta_window_actor_get_meta_window (window_actor); - -out: - set_unredirected_window (compositor_x11, window_to_unredirect); -} - -static void -on_before_update (ClutterStage *stage, - ClutterStageView *stage_view, - MetaCompositor *compositor) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - - if (compositor_x11->frame_has_updated_xsurfaces) - { - MetaDisplay *display = meta_compositor_get_display (compositor); - - /* - * We need to make sure that any X drawing that happens before the - * XDamageSubtract() for each window above is visible to subsequent GL - * rendering; the standardized way to do this is GL_EXT_X11_sync_object. - * Since this isn't implemented yet in mesa, we also have a path that - * relies on the implementation of the open source drivers. - * - * Anything else, we just hope for the best. - * - * Xorg and open source driver specifics: - * - * The X server makes sure to flush drawing to the kernel before sending - * out damage events, but since we use DamageReportBoundingBox there may - * be drawing between the last damage event and the XDamageSubtract() - * that needs to be flushed as well. - * - * Xorg always makes sure that drawing is flushed to the kernel before - * writing events or responses to the client, so any round trip request - * at this point is sufficient to flush the GLX buffers. - */ - if (compositor_x11->have_x11_sync_object) - compositor_x11->have_x11_sync_object = meta_sync_ring_insert_wait (); - else - XSync (display->x11_display->xdisplay, False); - } -} - -static void -on_after_update (ClutterStage *stage, - ClutterStageView *stage_view, - MetaCompositor *compositor) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - - if (compositor_x11->frame_has_updated_xsurfaces) - { - if (compositor_x11->have_x11_sync_object) - compositor_x11->have_x11_sync_object = meta_sync_ring_after_frame (); - - compositor_x11->frame_has_updated_xsurfaces = FALSE; - } -} - -static void -meta_compositor_x11_before_paint (MetaCompositor *compositor, - ClutterStageView *stage_view) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - MetaCompositorClass *parent_class; - - maybe_unredirect_top_window (compositor_x11); - - parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); - parent_class->before_paint (compositor, stage_view); -} - -static void -meta_compositor_x11_remove_window (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - MetaCompositorClass *parent_class; - - if (compositor_x11->unredirected_window == window) - set_unredirected_window (compositor_x11, NULL); - - parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); - parent_class->remove_window (compositor, window); -} - -static int64_t -meta_compositor_x11_monotonic_to_high_res_xserver_time (MetaCompositor *compositor, - int64_t monotonic_time_us) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); - int64_t now_us; - - if (compositor_x11->xserver_uses_monotonic_clock) - return meta_translate_to_high_res_xserver_time (monotonic_time_us); - - now_us = g_get_monotonic_time (); - - if (compositor_x11->xserver_time_query_time_us == 0 || - now_us > (compositor_x11->xserver_time_query_time_us + s2us (10))) - { - MetaDisplay *display = meta_compositor_get_display (compositor); - MetaX11Display *x11_display = display->x11_display; - uint32_t xserver_time_ms; - int64_t xserver_time_us; - - compositor_x11->xserver_time_query_time_us = now_us; - - xserver_time_ms = - meta_x11_display_get_current_time_roundtrip (x11_display); - xserver_time_us = ms2us (xserver_time_ms); - compositor_x11->xserver_time_offset_us = xserver_time_us - now_us; - } - - return monotonic_time_us + compositor_x11->xserver_time_offset_us; -} - -static void -meta_compositor_x11_grab_begin (MetaCompositor *compositor) -{ - MetaBackendX11 *backend_x11 = META_BACKEND_X11 (meta_get_backend ()); - - meta_backend_x11_sync_pointer (backend_x11); -} - -static void -meta_compositor_x11_grab_end (MetaCompositor *compositor) -{ - MetaBackendX11 *backend_x11 = META_BACKEND_X11 (meta_get_backend ()); - - meta_backend_x11_sync_pointer (backend_x11); -} - -Window -meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11) -{ - return compositor_x11->output; -} - -MetaCompositorX11 * -meta_compositor_x11_new (MetaDisplay *display, - MetaBackend *backend) -{ - return g_object_new (META_TYPE_COMPOSITOR_X11, - "display", display, - "backend", backend, - NULL); -} - -static void -meta_compositor_x11_constructed (GObject *object) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (object); - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - ClutterStage *stage = meta_compositor_get_stage (compositor); - - compositor_x11->before_update_handler_id = - g_signal_connect (stage, "before-update", - G_CALLBACK (on_before_update), compositor); - compositor_x11->after_update_handler_id = - g_signal_connect (stage, "after-update", - G_CALLBACK (on_after_update), compositor); - - G_OBJECT_CLASS (meta_compositor_x11_parent_class)->constructed (object); -} - -static void -meta_compositor_x11_dispose (GObject *object) -{ - MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (object); - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - ClutterStage *stage = meta_compositor_get_stage (compositor); - - if (compositor_x11->have_x11_sync_object) - { - meta_sync_ring_destroy (); - compositor_x11->have_x11_sync_object = FALSE; - } - - g_clear_signal_handler (&compositor_x11->before_update_handler_id, stage); - g_clear_signal_handler (&compositor_x11->after_update_handler_id, stage); - - G_OBJECT_CLASS (meta_compositor_x11_parent_class)->dispose (object); -} - -static void -meta_compositor_x11_init (MetaCompositorX11 *compositor_x11) -{ -} - -static void -meta_compositor_x11_class_init (MetaCompositorX11Class *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); - - object_class->constructed = meta_compositor_x11_constructed; - object_class->dispose = meta_compositor_x11_dispose; - - compositor_class->manage = meta_compositor_x11_manage; - compositor_class->unmanage = meta_compositor_x11_unmanage; - compositor_class->before_paint = meta_compositor_x11_before_paint; - compositor_class->remove_window = meta_compositor_x11_remove_window; - compositor_class->monotonic_to_high_res_xserver_time = - meta_compositor_x11_monotonic_to_high_res_xserver_time; - compositor_class->grab_begin = meta_compositor_x11_grab_begin; - compositor_class->grab_end = meta_compositor_x11_grab_end; -} diff --git a/src/compositor/meta-compositor-x11.h b/src/compositor/meta-compositor-x11.h deleted file mode 100644 index 42554feb3..000000000 --- a/src/compositor/meta-compositor-x11.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2019 Red Hat 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. - * - */ - -#ifndef META_COMPOSITOR_X11_H -#define META_COMPOSITOR_X11_H - -#include "compositor/compositor-private.h" - -#define META_TYPE_COMPOSITOR_X11 (meta_compositor_x11_get_type ()) -G_DECLARE_FINAL_TYPE (MetaCompositorX11, meta_compositor_x11, - META, COMPOSITOR_X11, MetaCompositor) - -MetaCompositorX11 * meta_compositor_x11_new (MetaDisplay *display, - MetaBackend *backend); - -void meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, - XEvent *xevent, - MetaWindow *window); - -Window meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11); - -#endif /* META_COMPOSITOR_X11_H */ diff --git a/src/compositor/meta-cullable.c b/src/compositor/meta-cullable.c deleted file mode 100644 index 6f38c5e47..000000000 --- a/src/compositor/meta-cullable.c +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright (C) 2013 Red Hat - * - * 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, see <http://www.gnu.org/licenses/>. - * - * Written by: - * Owen Taylor <otaylor@redhat.com> - * Ray Strode <rstrode@redhat.com> - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#include "config.h" - -#include "compositor/clutter-utils.h" -#include "compositor/meta-cullable.h" - -G_DEFINE_INTERFACE (MetaCullable, meta_cullable, CLUTTER_TYPE_ACTOR); - -static gboolean -has_active_effects (ClutterActor *actor) -{ - g_autoptr (GList) effects = NULL; - GList *l; - - effects = clutter_actor_get_effects (actor); - for (l = effects; l != NULL; l = l->next) - { - if (clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (l->data))) - return TRUE; - } - - return FALSE; -} - -/** - * SECTION:meta-cullable - * @title: MetaCullable - * @short_description: CPU culling operations for efficient drawing - * - * When we are painting a stack of 5-10 large actors, the standard - * bottom-to-top method of drawing every actor results in a tremendous - * amount of overdraw. If these actors are painting textures like - * windows, it can easily max out the available memory bandwidth on a - * low-end graphics chipset. It's even worse if window textures are - * being accessed over the AGP bus. - * - * #MetaCullable is our solution. The basic technique applied here is to - * do a pre-pass before painting where we walk each actor from top to bottom - * and ask each actor to "cull itself out". We pass in a region it can copy - * to clip its drawing to, and the actor can subtract its fully opaque pixels - * so that actors underneath know not to draw there as well. - */ - -/** - * meta_cullable_cull_out_children: - * @cullable: The #MetaCullable - * @unobscured_region: The unobscured region, as passed into cull_out() - * @clip_region: The clip region, as passed into cull_out() - * - * This is a helper method for actors that want to recurse over their - * child actors, and cull them out. - * - * See #MetaCullable and meta_cullable_cull_out() for more details. - */ -void -meta_cullable_cull_out_children (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - ClutterActor *actor = CLUTTER_ACTOR (cullable); - ClutterActor *child; - ClutterActorIter iter; - - clutter_actor_iter_init (&iter, actor); - while (clutter_actor_iter_prev (&iter, &child)) - { - float x, y; - gboolean needs_culling; - - if (!META_IS_CULLABLE (child)) - continue; - - needs_culling = (unobscured_region != NULL && clip_region != NULL); - - if (needs_culling && !CLUTTER_ACTOR_IS_VISIBLE (child)) - needs_culling = FALSE; - - /* If an actor has effects applied, then that can change the area - * it paints and the opacity, so we no longer can figure out what - * portion of the actor is obscured and what portion of the screen - * it obscures, so we skip the actor. - * - * This has a secondary beneficial effect: if a ClutterOffscreenEffect - * is applied to an actor, then our clipped redraws interfere with the - * caching of the FBO - even if we only need to draw a small portion - * of the window right now, ClutterOffscreenEffect may use other portions - * of the FBO later. So, skipping actors with effects applied also - * prevents these bugs. - * - * Theoretically, we should check clutter_actor_get_offscreen_redirect() - * as well for the same reason, but omitted for simplicity in the - * hopes that no-one will do that. - */ - if (needs_culling && has_active_effects (child)) - needs_culling = FALSE; - - if (needs_culling && !meta_cullable_is_untransformed (META_CULLABLE (child))) - needs_culling = FALSE; - - if (needs_culling) - { - clutter_actor_get_position (child, &x, &y); - - /* Temporarily move to the coordinate system of the actor */ - cairo_region_translate (unobscured_region, - x, - y); - cairo_region_translate (clip_region, - x, - y); - - meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region); - - cairo_region_translate (unobscured_region, x, y); - cairo_region_translate (clip_region, x, y); - } - else - { - meta_cullable_cull_out (META_CULLABLE (child), NULL, NULL); - } - } -} - -/** - * meta_cullable_reset_culling_children: - * @cullable: The #MetaCullable - * - * This is a helper method for actors that want to recurse over their - * child actors, and cull them out. - * - * See #MetaCullable and meta_cullable_reset_culling() for more details. - */ -void -meta_cullable_reset_culling_children (MetaCullable *cullable) -{ - ClutterActor *actor = CLUTTER_ACTOR (cullable); - ClutterActor *child; - ClutterActorIter iter; - - clutter_actor_iter_init (&iter, actor); - while (clutter_actor_iter_next (&iter, &child)) - { - if (!META_IS_CULLABLE (child)) - continue; - - meta_cullable_reset_culling (META_CULLABLE (child)); - } -} - -static gboolean -meta_cullable_default_is_untransformed (MetaCullable *cullable) -{ - float width, height; - graphene_point3d_t verts[4]; - - clutter_actor_get_size (CLUTTER_ACTOR (cullable), &width, &height); - clutter_actor_get_abs_allocation_vertices (CLUTTER_ACTOR (cullable), verts); - - return meta_actor_vertices_are_untransformed (verts, width, height, - NULL, NULL); -} - -static void -meta_cullable_default_init (MetaCullableInterface *iface) -{ - iface->is_untransformed = meta_cullable_default_is_untransformed; -} - -/** - * meta_cullable_cull_out: - * @cullable: The #MetaCullable - * @unobscured_region: The unobscured region, in @cullable's space. - * @clip_region: The clip region, in @cullable's space. - * - * When #MetaWindowGroup is painted, we walk over its direct cullable - * children from top to bottom and ask themselves to "cull out". Cullables - * can use @unobscured_region and @clip_region to clip their drawing. Actors - * interested in eliminating overdraw should copy the @clip_region and only - * paint those parts, as everything else has been obscured by actors above it. - * - * Actors that may have fully opaque parts should also subtract out a region - * that is fully opaque from @unobscured_region and @clip_region. - * - * @unobscured_region and @clip_region are extremely similar. The difference - * is that @clip_region starts off with the stage's clip, if Clutter detects - * that we're doing a clipped redraw. @unobscured_region, however, starts off - * with the full stage size, so actors that may want to record what parts of - * their window are unobscured for e.g. scheduling repaints can do so. - * - * Actors that have children can also use the meta_cullable_cull_out_children() - * helper method to do a simple cull across all their children. - */ -void -meta_cullable_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - META_CULLABLE_GET_IFACE (cullable)->cull_out (cullable, unobscured_region, clip_region); -} - -/** - * meta_cullable_is_untransformed: - * @cullable: The #MetaCullable - * - * Check if a cullable is "untransformed" - which actually means transformed by - * at most a integer-translation. - */ -gboolean -meta_cullable_is_untransformed (MetaCullable *cullable) -{ - return META_CULLABLE_GET_IFACE (cullable)->is_untransformed (cullable); -} - -/** - * meta_cullable_reset_culling: - * @cullable: The #MetaCullable - * - * Actors that copied data in their cull_out() implementation can now - * reset their data, as the paint is now over. Additional paints may be - * done by #ClutterClone or similar, and they should not be affected by - * the culling operation. - */ -void -meta_cullable_reset_culling (MetaCullable *cullable) -{ - META_CULLABLE_GET_IFACE (cullable)->reset_culling (cullable); -} diff --git a/src/compositor/meta-cullable.h b/src/compositor/meta-cullable.h deleted file mode 100644 index 471681da3..000000000 --- a/src/compositor/meta-cullable.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2013 Red Hat - * - * 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, see <http://www.gnu.org/licenses/>. - * - * Written by: - * Owen Taylor <otaylor@redhat.com> - * Ray Strode <rstrode@redhat.com> - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#ifndef __META_CULLABLE_H__ -#define __META_CULLABLE_H__ - -#include "clutter/clutter.h" - -G_BEGIN_DECLS - -#define META_TYPE_CULLABLE (meta_cullable_get_type ()) -G_DECLARE_INTERFACE (MetaCullable, meta_cullable, META, CULLABLE, ClutterActor) - -struct _MetaCullableInterface -{ - GTypeInterface g_iface; - - void (* cull_out) (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region); - gboolean (* is_untransformed) (MetaCullable *cullable); - void (* reset_culling) (MetaCullable *cullable); -}; - -void meta_cullable_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region); -gboolean meta_cullable_is_untransformed (MetaCullable *cullable); -void meta_cullable_reset_culling (MetaCullable *cullable); - -/* Utility methods for implementations */ -void meta_cullable_cull_out_children (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region); -void meta_cullable_reset_culling_children (MetaCullable *cullable); - -G_END_DECLS - -#endif /* __META_CULLABLE_H__ */ - diff --git a/src/compositor/meta-dnd-actor-private.h b/src/compositor/meta-dnd-actor-private.h deleted file mode 100644 index 20be369eb..000000000 --- a/src/compositor/meta-dnd-actor-private.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * meta-dnd-actor-private.h: Actor for painting the DnD surface - * - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - * - * Author: Carlos Garnacho <carlosg@gnome.org> - */ - -#ifndef META_DND_ACTOR_PRIVATE_H -#define META_DND_ACTOR_PRIVATE_H - -#include "compositor/meta-feedback-actor-private.h" - -/** - * MetaDnDActor: - * - * This class handles the rendering of the DnD surface - */ - -#define META_TYPE_DND_ACTOR (meta_dnd_actor_get_type ()) -G_DECLARE_FINAL_TYPE (MetaDnDActor, - meta_dnd_actor, - META, DND_ACTOR, - MetaFeedbackActor) - - -ClutterActor *meta_dnd_actor_new (ClutterActor *drag_origin, - int start_x, - int start_y); - -void meta_dnd_actor_drag_finish (MetaDnDActor *self, - gboolean success); - -#endif /* META_DND_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-dnd-actor.c b/src/compositor/meta-dnd-actor.c deleted file mode 100644 index 80bffdeb7..000000000 --- a/src/compositor/meta-dnd-actor.c +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - * - * Author: Carlos Garnacho <carlosg@gnome.org> - */ - -/** - * SECTION:meta-dnd-actor - * @title: MetaDnDActor - * @short_description: Actor for painting the drag and drop surface - * - */ - -#include "config.h" - -#include "compositor/meta-dnd-actor-private.h" -#include "compositor/meta-window-actor-private.h" - -#include "clutter/clutter.h" - -#define DRAG_FAILED_DURATION 500 - -enum -{ - PROP_DRAG_ORIGIN = 1, - PROP_DRAG_START_X, - PROP_DRAG_START_Y -}; - -struct _MetaDnDActor -{ - MetaFeedbackActor parent; - - ClutterActor *drag_origin; - int drag_start_x; - int drag_start_y; -}; - -G_DEFINE_TYPE (MetaDnDActor, meta_dnd_actor, META_TYPE_FEEDBACK_ACTOR) - -static void -meta_dnd_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaDnDActor *self = META_DND_ACTOR (object); - - switch (prop_id) - { - case PROP_DRAG_ORIGIN: - self->drag_origin = g_value_get_object (value); - break; - case PROP_DRAG_START_X: - self->drag_start_x = g_value_get_int (value); - break; - case PROP_DRAG_START_Y: - self->drag_start_y = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_dnd_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaDnDActor *self = META_DND_ACTOR (object); - - switch (prop_id) - { - case PROP_DRAG_ORIGIN: - g_value_set_object (value, self->drag_origin); - break; - case PROP_DRAG_START_X: - g_value_set_int (value, self->drag_start_x); - break; - case PROP_DRAG_START_Y: - g_value_set_int (value, self->drag_start_y); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_dnd_actor_class_init (MetaDnDActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->set_property = meta_dnd_actor_set_property; - object_class->get_property = meta_dnd_actor_get_property; - - pspec = g_param_spec_object ("drag-origin", - "Drag origin", - "The origin of the DnD operation", - CLUTTER_TYPE_ACTOR, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_DRAG_ORIGIN, - pspec); - - pspec = g_param_spec_int ("drag-start-x", - "Drag start X", - "The X axis of the drag start point", - 0, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_DRAG_START_X, - pspec); - - pspec = g_param_spec_int ("drag-start-y", - "Drag start Y", - "The Y axis of the drag start point", - 0, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_DRAG_START_Y, - pspec); -} - -static void -meta_dnd_actor_init (MetaDnDActor *self) -{ -} - -/** - * meta_dnd_actor_new: - * - * Creates a new actor to draw the current drag and drop surface. - * - * Return value: the newly created background actor - */ -ClutterActor * -meta_dnd_actor_new (ClutterActor *drag_origin, - int drag_start_x, - int drag_start_y) -{ - MetaDnDActor *self; - - self = g_object_new (META_TYPE_DND_ACTOR, - "drag-origin", drag_origin, - "drag-start-x", drag_start_x, - "drag-start-y", drag_start_y, - NULL); - - return CLUTTER_ACTOR (self); -} - -static void -drag_failed_complete (ClutterTimeline *timeline, - gboolean is_finished, - gpointer user_data) -{ - ClutterActor *self = user_data; - - clutter_actor_remove_all_children (self); - clutter_actor_destroy (self); -} - -void -meta_dnd_actor_drag_finish (MetaDnDActor *self, - gboolean success) -{ - ClutterActor *actor; - - g_return_if_fail (META_IS_DND_ACTOR (self)); - - actor = CLUTTER_ACTOR (self); - - if (success) - { - clutter_actor_remove_all_children (CLUTTER_ACTOR (self)); - clutter_actor_destroy (CLUTTER_ACTOR (self)); - } - else - { - ClutterTransition *transition; - - clutter_actor_save_easing_state (actor); - clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC); - clutter_actor_set_easing_duration (actor, DRAG_FAILED_DURATION); - clutter_actor_set_opacity (actor, 0); - - if (CLUTTER_ACTOR_IS_VISIBLE (self->drag_origin)) - { - MetaWindowActor *origin_actor; - float anchor_x, anchor_y; - graphene_point_t dest; - int origin_geometry_scale; - int feedback_geometry_scale; - - clutter_actor_get_transformed_position (self->drag_origin, - &dest.x, &dest.y); - - origin_actor = meta_window_actor_from_actor (self->drag_origin); - g_return_if_fail (origin_actor); - origin_geometry_scale = - meta_window_actor_get_geometry_scale (origin_actor); - - meta_feedback_actor_get_anchor (META_FEEDBACK_ACTOR (self), - &anchor_x, &anchor_y); - feedback_geometry_scale = - meta_feedback_actor_get_geometry_scale (META_FEEDBACK_ACTOR (self)); - - dest.x += ((self->drag_start_x * origin_geometry_scale) - - (anchor_x * feedback_geometry_scale)); - dest.y += ((self->drag_start_y * origin_geometry_scale) - - (anchor_y * feedback_geometry_scale)); - clutter_actor_set_position (actor, dest.x, dest.y); - } - - transition = clutter_actor_get_transition (actor, "opacity"); - g_signal_connect (transition, "stopped", - G_CALLBACK (drag_failed_complete), self); - - clutter_actor_restore_easing_state (actor); - } -} diff --git a/src/compositor/meta-dnd.c b/src/compositor/meta-dnd.c deleted file mode 100644 index 8461690a2..000000000 --- a/src/compositor/meta-dnd.c +++ /dev/null @@ -1,336 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright (C) 2016 Hyungwon Hwang - * - * 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, see <http://www.gnu.org/licenses/>. - * - */ - -#include "config.h" - -#include <gdk/gdkx.h> - -#include "meta/meta-backend.h" -#include "compositor/compositor-private.h" -#include "core/display-private.h" -#include "backends/meta-dnd-private.h" -#include "backends/x11/meta-backend-x11.h" -#include "backends/x11/meta-clutter-backend-x11.h" -#include "backends/x11/meta-stage-x11.h" -#include "meta/meta-dnd.h" -#include "x11/meta-x11-display-private.h" - -struct _MetaDndClass -{ - GObjectClass parent_class; -}; - -#ifdef HAVE_WAYLAND -#include "wayland/meta-wayland-private.h" -#include "wayland/meta-wayland-data-device.h" -#endif - -typedef struct _MetaDndPrivate MetaDndPrivate; - -struct _MetaDndPrivate -{ -#ifdef HAVE_WAYLAND - gulong handler_id[3]; - - MetaCompositor *compositor; - MetaWaylandCompositor *wl_compositor; -#else - /* to avoid warnings (g_type_class_add_private: assertion `private_size > 0' failed) */ - gchar dummy; -#endif -}; - -struct _MetaDnd -{ - GObject parent; - - MetaDndPrivate *priv; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (MetaDnd, meta_dnd, G_TYPE_OBJECT); - -enum -{ - ENTER, - POSITION_CHANGE, - LEAVE, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -meta_dnd_class_init (MetaDndClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - signals[ENTER] = - g_signal_new ("dnd-enter", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[POSITION_CHANGE] = - g_signal_new ("dnd-position-change", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - - signals[LEAVE] = - g_signal_new ("dnd-leave", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -static void -meta_dnd_init (MetaDnd *dnd) -{ -} - -void -meta_dnd_init_xdnd (MetaX11Display *x11_display) -{ - MetaBackend *backend = meta_get_backend (); - Display *xdisplay = x11_display->xdisplay; - Window xwindow, overlay_xwindow; - long xdnd_version = 5; - - overlay_xwindow = x11_display->composite_overlay_window; - xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); - - XChangeProperty (xdisplay, xwindow, - XInternAtom (xdisplay, "XdndAware", TRUE), XA_ATOM, - 32, PropModeReplace, - (const unsigned char *) &xdnd_version, 1); - - XChangeProperty (xdisplay, overlay_xwindow, - XInternAtom (xdisplay, "XdndProxy", TRUE), XA_WINDOW, - 32, PropModeReplace, (const unsigned char *) &xwindow, 1); - - /* - * XdndProxy is additionally set on the proxy window as verification that the - * XdndProxy property on the target window isn't a left-over - */ - XChangeProperty (xdisplay, xwindow, - XInternAtom (xdisplay, "XdndProxy", TRUE), XA_WINDOW, - 32, PropModeReplace, (const unsigned char *) &xwindow, 1); -} - -static void -meta_dnd_notify_dnd_enter (MetaDnd *dnd) -{ - g_signal_emit (dnd, signals[ENTER], 0); -} - -static void -meta_dnd_notify_dnd_position_change (MetaDnd *dnd, - int x, - int y) -{ - g_signal_emit (dnd, signals[POSITION_CHANGE], 0, x, y); -} - -static void -meta_dnd_notify_dnd_leave (MetaDnd *dnd) -{ - g_signal_emit (dnd, signals[LEAVE], 0); -} - -/* - * Process Xdnd events - * - * We pass the position and leave events to the plugin via a signal - * where the actual drag & drop handling happens. - * - * http://www.freedesktop.org/wiki/Specifications/XDND - */ -gboolean -meta_dnd_handle_xdnd_event (MetaBackend *backend, - MetaCompositorX11 *compositor_x11, - Display *xdisplay, - XEvent *xev) -{ - MetaDnd *dnd = meta_backend_get_dnd (backend); - MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); - Window output_window; - ClutterStage *stage; - - if (xev->xany.type != ClientMessage) - return FALSE; - - output_window = meta_compositor_x11_get_output_xwindow (compositor_x11); - stage = meta_compositor_get_stage (compositor); - if (xev->xany.window != output_window && - xev->xany.window != meta_x11_get_stage_window (stage)) - return FALSE; - - if (xev->xclient.message_type == XInternAtom (xdisplay, "XdndPosition", TRUE)) - { - XEvent xevent; - Window src = xev->xclient.data.l[0]; - - memset (&xevent, 0, sizeof(xevent)); - xevent.xany.type = ClientMessage; - xevent.xany.display = xdisplay; - xevent.xclient.window = src; - xevent.xclient.message_type = XInternAtom (xdisplay, "XdndStatus", TRUE); - xevent.xclient.format = 32; - xevent.xclient.data.l[0] = output_window; - /* flags: bit 0: will we accept the drop? bit 1: do we want more position messages */ - xevent.xclient.data.l[1] = 2; - xevent.xclient.data.l[4] = None; - - XSendEvent (xdisplay, src, False, 0, &xevent); - - meta_dnd_notify_dnd_position_change (dnd, - (int)(xev->xclient.data.l[2] >> 16), - (int)(xev->xclient.data.l[2] & 0xFFFF)); - - return TRUE; - } - else if (xev->xclient.message_type == XInternAtom (xdisplay, "XdndLeave", TRUE)) - { - meta_dnd_notify_dnd_leave (dnd); - - return TRUE; - } - else if (xev->xclient.message_type == XInternAtom (xdisplay, "XdndEnter", TRUE)) - { - meta_dnd_notify_dnd_enter (dnd); - - return TRUE; - } - - return FALSE; -} - -#ifdef HAVE_WAYLAND -static void -meta_dnd_wayland_on_motion_event (ClutterActor *actor, - ClutterEvent *event, - MetaDnd *dnd) -{ - MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); - MetaWaylandDragGrab *current_grab; - gfloat event_x, event_y; - - g_return_if_fail (event != NULL); - - clutter_event_get_coords (event, &event_x, &event_y); - meta_dnd_notify_dnd_position_change (dnd, (int)event_x, (int)event_y); - - current_grab = meta_wayland_data_device_get_current_grab (&priv->wl_compositor->seat->data_device); - if (current_grab) - meta_wayland_drag_grab_update_feedback_actor (current_grab, event); -} - -static void -meta_dnd_wayland_end_notify (ClutterActor *actor, - ClutterEvent *event, - MetaDnd *dnd) -{ - MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); - - meta_wayland_data_device_end_drag (&priv->wl_compositor->seat->data_device); - meta_dnd_wayland_handle_end_modal (priv->compositor); -} - -static void -meta_dnd_wayland_on_button_released (ClutterActor *actor, - ClutterEvent *event, - MetaDnd *dnd) -{ - meta_dnd_wayland_end_notify (actor, event, dnd); -} - -static void -meta_dnd_wayland_on_key_pressed (ClutterActor *actor, - ClutterEvent *event, - MetaDnd *dnd) -{ - guint key = clutter_event_get_key_symbol (event); - - if (key != CLUTTER_KEY_Escape) - return; - - meta_dnd_wayland_end_notify (actor, event, dnd); -} - -void -meta_dnd_wayland_handle_begin_modal (MetaCompositor *compositor) -{ - MetaWaylandCompositor *wl_compositor = meta_wayland_compositor_get_default (); - MetaDnd *dnd = meta_backend_get_dnd (meta_get_backend ()); - MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); - - if (priv->handler_id[0] == 0 && - meta_wayland_data_device_get_current_grab (&wl_compositor->seat->data_device) != NULL) - { - ClutterStage *stage = meta_compositor_get_stage (compositor); - - priv->compositor = compositor; - priv->wl_compositor = wl_compositor; - - priv->handler_id[0] = g_signal_connect (stage, - "motion-event", - G_CALLBACK (meta_dnd_wayland_on_motion_event), - dnd); - - priv->handler_id[1] = g_signal_connect (stage, - "button-release-event", - G_CALLBACK (meta_dnd_wayland_on_button_released), - dnd); - - priv->handler_id[2] = g_signal_connect (stage, - "key-press-event", - G_CALLBACK (meta_dnd_wayland_on_key_pressed), - dnd); - - meta_dnd_notify_dnd_enter (dnd); - } -} - -void -meta_dnd_wayland_handle_end_modal (MetaCompositor *compositor) -{ - MetaDnd *dnd = meta_backend_get_dnd (meta_get_backend ()); - MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); - ClutterStage *stage = meta_compositor_get_stage (compositor); - unsigned int i; - - if (!priv->compositor) - return; - - for (i = 0; i < G_N_ELEMENTS (priv->handler_id); i++) - g_clear_signal_handler (&priv->handler_id[i], stage); - - priv->compositor = NULL; - priv->wl_compositor = NULL; - - meta_dnd_notify_dnd_leave (dnd); -} -#endif diff --git a/src/compositor/meta-feedback-actor-private.h b/src/compositor/meta-feedback-actor-private.h deleted file mode 100644 index 86cacb360..000000000 --- a/src/compositor/meta-feedback-actor-private.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * meta-feedback-actor-private.h: Actor for painting user interaction feedback - * - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - * - * Author: Carlos Garnacho <carlosg@gnome.org> - */ - -#ifndef META_FEEDBACK_ACTOR_PRIVATE_H -#define META_FEEDBACK_ACTOR_PRIVATE_H - -#include "clutter/clutter.h" - -/** - * MetaFeedbackActor: - * - * This class handles the rendering of user interaction feedback - */ - -#define META_TYPE_FEEDBACK_ACTOR (meta_feedback_actor_get_type ()) -G_DECLARE_DERIVABLE_TYPE (MetaFeedbackActor, - meta_feedback_actor, - META, FEEDBACK_ACTOR, - ClutterActor) - - -struct _MetaFeedbackActorClass -{ - /*< private >*/ - ClutterActorClass parent_class; -}; - - -ClutterActor *meta_feedback_actor_new (float anchor_x, - float anchor_y); - -void meta_feedback_actor_set_anchor (MetaFeedbackActor *actor, - float anchor_x, - float anchor_y); -void meta_feedback_actor_get_anchor (MetaFeedbackActor *actor, - float *anchor_x, - float *anchor_y); - -void meta_feedback_actor_set_position (MetaFeedbackActor *self, - float x, - float y); - -void meta_feedback_actor_update (MetaFeedbackActor *self, - const ClutterEvent *event); - -void meta_feedback_actor_set_geometry_scale (MetaFeedbackActor *self, - int geometry_scale); - -int meta_feedback_actor_get_geometry_scale (MetaFeedbackActor *self); - -#endif /* META_FEEDBACK_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-feedback-actor.c b/src/compositor/meta-feedback-actor.c deleted file mode 100644 index 4b4bed78a..000000000 --- a/src/compositor/meta-feedback-actor.c +++ /dev/null @@ -1,285 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>. - * - * Author: Carlos Garnacho <carlosg@gnome.org> - */ - -/** - * SECTION:meta-feedback-actor - * @title: MetaFeedbackActor - * @short_description: Actor for painting user interaction feedback - */ - -#include "config.h" - -#include "compositor/compositor-private.h" -#include "compositor/meta-feedback-actor-private.h" -#include "core/display-private.h" - -enum -{ - PROP_ANCHOR_X = 1, - PROP_ANCHOR_Y -}; - -typedef struct _MetaFeedbackActorPrivate MetaFeedbackActorPrivate; - -struct _MetaFeedbackActorPrivate -{ - float anchor_x; - float anchor_y; - float pos_x; - float pos_y; - - int geometry_scale; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (MetaFeedbackActor, meta_feedback_actor, CLUTTER_TYPE_ACTOR) - -static void -meta_feedback_actor_constructed (GObject *object) -{ - MetaDisplay *display; - ClutterActor *feedback_group; - - display = meta_get_display (); - feedback_group = meta_get_feedback_group_for_display (display); - clutter_actor_add_child (feedback_group, CLUTTER_ACTOR (object)); -} - -static void -meta_feedback_actor_update_position (MetaFeedbackActor *self) -{ - MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self); - - clutter_actor_set_position (CLUTTER_ACTOR (self), - priv->pos_x - - (priv->anchor_x * priv->geometry_scale), - priv->pos_y - - (priv->anchor_y * priv->geometry_scale)); -} - -static void -meta_feedback_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object); - MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_ANCHOR_X: - priv->anchor_x = g_value_get_int (value); - meta_feedback_actor_update_position (self); - break; - case PROP_ANCHOR_Y: - priv->anchor_y = g_value_get_int (value); - meta_feedback_actor_update_position (self); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_feedback_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object); - MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_ANCHOR_X: - g_value_set_float (value, priv->anchor_x); - break; - case PROP_ANCHOR_Y: - g_value_set_float (value, priv->anchor_y); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_feedback_actor_class_init (MetaFeedbackActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->constructed = meta_feedback_actor_constructed; - object_class->set_property = meta_feedback_actor_set_property; - object_class->get_property = meta_feedback_actor_get_property; - - pspec = g_param_spec_float ("anchor-x", - "Anchor X", - "The X axis of the anchor point", - 0, G_MAXFLOAT, 0, - G_PARAM_READWRITE); - - g_object_class_install_property (object_class, - PROP_ANCHOR_X, - pspec); - - pspec = g_param_spec_float ("anchor-y", - "Anchor Y", - "The Y axis of the anchor point", - 0, G_MAXFLOAT, 0, - G_PARAM_READWRITE); - - g_object_class_install_property (object_class, - PROP_ANCHOR_Y, - pspec); -} - -static void -meta_feedback_actor_init (MetaFeedbackActor *self) -{ - clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE); -} - -/** - * meta_feedback_actor_new: - * - * Creates a new actor to draw the current drag and drop surface. - * - * Return value: the newly created background actor - */ -ClutterActor * -meta_feedback_actor_new (float anchor_x, - float anchor_y) -{ - MetaFeedbackActor *self; - - self = g_object_new (META_TYPE_FEEDBACK_ACTOR, - "anchor-x", anchor_x, - "anchor-y", anchor_y, - NULL); - - return CLUTTER_ACTOR (self); -} - -void -meta_feedback_actor_set_anchor (MetaFeedbackActor *self, - float anchor_x, - float anchor_y) -{ - MetaFeedbackActorPrivate *priv; - - g_return_if_fail (META_IS_FEEDBACK_ACTOR (self)); - - priv = meta_feedback_actor_get_instance_private (self); - - if (priv->anchor_x == anchor_x && priv->anchor_y == anchor_y) - return; - - if (priv->anchor_x != anchor_x) - { - priv->anchor_x = anchor_x; - g_object_notify (G_OBJECT (self), "anchor-x"); - } - - if (priv->anchor_y != anchor_y) - { - priv->anchor_y = anchor_y; - g_object_notify (G_OBJECT (self), "anchor-y"); - } - - meta_feedback_actor_update_position (self); -} - -void -meta_feedback_actor_get_anchor (MetaFeedbackActor *self, - float *anchor_x, - float *anchor_y) -{ - MetaFeedbackActorPrivate *priv; - - g_return_if_fail (META_IS_FEEDBACK_ACTOR (self)); - - priv = meta_feedback_actor_get_instance_private (self); - - if (anchor_x) - *anchor_x = priv->anchor_x; - if (anchor_y) - *anchor_y = priv->anchor_y; -} - -void -meta_feedback_actor_set_position (MetaFeedbackActor *self, - float x, - float y) -{ - MetaFeedbackActorPrivate *priv; - - g_return_if_fail (META_IS_FEEDBACK_ACTOR (self)); - - priv = meta_feedback_actor_get_instance_private (self); - priv->pos_x = x; - priv->pos_y = y; - - meta_feedback_actor_update_position (self); -} - -void -meta_feedback_actor_update (MetaFeedbackActor *self, - const ClutterEvent *event) -{ - graphene_point_t point; - - g_return_if_fail (META_IS_FEEDBACK_ACTOR (self)); - g_return_if_fail (event != NULL); - - clutter_event_get_position (event, &point); - meta_feedback_actor_set_position (self, point.x, point.y); -} - -void -meta_feedback_actor_set_geometry_scale (MetaFeedbackActor *self, - int geometry_scale) -{ - MetaFeedbackActorPrivate *priv = - meta_feedback_actor_get_instance_private (self); - graphene_matrix_t child_transform; - - if (priv->geometry_scale == geometry_scale) - return; - - priv->geometry_scale = geometry_scale; - - graphene_matrix_init_scale (&child_transform, - geometry_scale, - geometry_scale, - 1); - clutter_actor_set_child_transform (CLUTTER_ACTOR (self), - &child_transform); -} - -int -meta_feedback_actor_get_geometry_scale (MetaFeedbackActor *self) -{ - MetaFeedbackActorPrivate *priv = - meta_feedback_actor_get_instance_private (self); - - return priv->geometry_scale; -} diff --git a/src/compositor/meta-later-private.h b/src/compositor/meta-later-private.h deleted file mode 100644 index c8d0f80a8..000000000 --- a/src/compositor/meta-later-private.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2020 Red Hat 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef META_LATER_PRIVATE_H -#define META_LATER_PRIVATE_H - -typedef struct _MetaLaters MetaLaters; -typedef struct _MetaCompositor MetaCompositor; - -MetaLaters * meta_laters_new (MetaCompositor *compositor); - -void meta_laters_free (MetaLaters *laters); - -#endif /* META_LATER_PRIVATE_H */ diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c deleted file mode 100644 index 43da6d8e6..000000000 --- a/src/compositor/meta-later.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2005 Elijah Newren - * Copyright (C) 2020 Red Hat 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "compositor/meta-later-private.h" - -#include "cogl/cogl.h" -#include "compositor/compositor-private.h" -#include "core/display-private.h" -#include "meta/meta-later.h" - -typedef struct _MetaLater -{ - unsigned int id; - unsigned int ref_count; - MetaLaterType when; - - GSourceFunc func; - gpointer user_data; - GDestroyNotify destroy_notify; - - guint source_id; - gboolean run_once; -} MetaLater; - -#define META_LATER_N_TYPES (META_LATER_IDLE + 1) - -struct _MetaLaters -{ - MetaCompositor *compositor; - - unsigned int last_later_id; - - GSList *laters[META_LATER_N_TYPES]; - - gulong before_update_handler_id; -}; - -static MetaLater * -meta_later_ref (MetaLater *later) -{ - later->ref_count++; - return later; -} - -static void -meta_later_unref (MetaLater *later) -{ - if (--later->ref_count == 0) - { - if (later->destroy_notify) - { - later->destroy_notify (later->user_data); - later->destroy_notify = NULL; - } - - g_free (later); - } -} - -static void -meta_later_destroy (MetaLater *later) -{ - g_clear_handle_id (&later->source_id, g_source_remove); - later->func = NULL; - meta_later_unref (later); -} - -#ifdef COGL_HAS_TRACING -static const char * -later_type_to_string (MetaLaterType when) -{ - switch (when) - { - case META_LATER_RESIZE: - return "Later (resize)"; - case META_LATER_CALC_SHOWING: - return "Later (calc-showing)"; - case META_LATER_CHECK_FULLSCREEN: - return "Later (check-fullscreen)"; - case META_LATER_SYNC_STACK: - return "Later (sync-stack)"; - case META_LATER_BEFORE_REDRAW: - return "Later (before-redraw)"; - case META_LATER_IDLE: - return "Later (idle)"; - } - - return "unknown"; -} -#endif - -static gboolean -meta_later_invoke (MetaLater *later) -{ - COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when)); - return later->func (later->user_data); -} - -static gboolean -remove_later_from_list (unsigned int later_id, - GSList **laters_list) -{ - GSList *l; - - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - - if (later->id == later_id) - { - *laters_list = g_slist_delete_link (*laters_list, l); - meta_later_destroy (later); - return TRUE; - } - } - - return FALSE; -} - -static void -run_repaint_laters (GSList **laters_list) -{ - g_autoptr (GSList) laters_copy = NULL; - GSList *l; - - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - - if (!later->source_id || - (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) - laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later)); - } - laters_copy = g_slist_reverse (laters_copy); - - for (l = laters_copy; l; l = l->next) - { - MetaLater *later = l->data; - - if (!later->func) - remove_later_from_list (later->id, laters_list); - else if (!meta_later_invoke (later)) - remove_later_from_list (later->id, laters_list); - - meta_later_unref (later); - } -} - -static void -on_before_update (ClutterStage *stage, - ClutterStageView *stage_view, - MetaLaters *laters) -{ - unsigned int i; - GSList *l; - gboolean needs_schedule_update = FALSE; - - for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) - run_repaint_laters (&laters->laters[i]); - - for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) - { - for (l = laters->laters[i]; l; l = l->next) - { - MetaLater *later = l->data; - - if (!later->source_id) - needs_schedule_update = TRUE; - } - } - - if (needs_schedule_update) - clutter_stage_schedule_update (stage); -} - -static gboolean -invoke_later_idle (gpointer data) -{ - MetaLater *later = data; - - if (!later->func (later->user_data)) - { - meta_later_remove (later->id); - return FALSE; - } - else - { - later->run_once = TRUE; - return TRUE; - } -} - -static unsigned int -meta_laters_add (MetaLaters *laters, - MetaLaterType when, - GSourceFunc func, - gpointer user_data, - GDestroyNotify notify) -{ - ClutterStage *stage = meta_compositor_get_stage (laters->compositor); - MetaLater *later = g_new0 (MetaLater, 1); - - later->id = ++laters->last_later_id; - later->ref_count = 1; - later->when = when; - later->func = func; - later->user_data = user_data; - later->destroy_notify = notify; - - laters->laters[when] = g_slist_prepend (laters->laters[when], later); - - switch (when) - { - case META_LATER_RESIZE: - later->source_id = g_idle_add_full (META_PRIORITY_RESIZE, - invoke_later_idle, - later, NULL); - g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle"); - clutter_stage_schedule_update (stage); - break; - case META_LATER_CALC_SHOWING: - case META_LATER_CHECK_FULLSCREEN: - case META_LATER_SYNC_STACK: - case META_LATER_BEFORE_REDRAW: - clutter_stage_schedule_update (stage); - break; - case META_LATER_IDLE: - later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - invoke_later_idle, - later, NULL); - g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle"); - break; - } - - return later->id; -} - -/** - * meta_later_add: - * @when: enumeration value determining the phase at which to run the callback - * @func: callback to run later - * @data: data to pass to the callback - * @notify: function to call to destroy @data when it is no longer in use, or %NULL - * - * Sets up a callback to be called at some later time. @when determines the - * particular later occasion at which it is called. This is much like g_idle_add(), - * except that the functions interact properly with clutter event handling. - * If a "later" function is added from a clutter event handler, and is supposed - * to be run before the stage is redrawn, it will be run before that redraw - * of the stage, not the next one. - * - * Return value: an integer ID (guaranteed to be non-zero) that can be used - * to cancel the callback and prevent it from being run. - */ -unsigned int -meta_later_add (MetaLaterType when, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) -{ - MetaDisplay *display = meta_get_display (); - MetaCompositor *compositor; - - g_return_val_if_fail (display, 0); - g_return_val_if_fail (display->compositor, 0); - - compositor = display->compositor; - return meta_laters_add (meta_compositor_get_laters (compositor), - when, func, data, notify); -} - -static void -meta_laters_remove (MetaLaters *laters, - unsigned int later_id) -{ - unsigned int i; - - for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) - { - if (remove_later_from_list (later_id, &laters->laters[i])) - return; - } -} - -/** - * meta_later_remove: - * @later_id: the integer ID returned from meta_later_add() - * - * Removes a callback added with meta_later_add() - */ -void -meta_later_remove (unsigned int later_id) -{ - MetaDisplay *display = meta_get_display (); - MetaCompositor *compositor; - - g_return_if_fail (display); - - compositor = display->compositor; - if (!compositor) - return; - - meta_laters_remove (meta_compositor_get_laters (compositor), later_id); -} - -MetaLaters * -meta_laters_new (MetaCompositor *compositor) -{ - ClutterStage *stage = meta_compositor_get_stage (compositor); - MetaLaters *laters; - - laters = g_new0 (MetaLaters, 1); - laters->compositor = compositor; - - laters->before_update_handler_id = - g_signal_connect (stage, "before-update", - G_CALLBACK (on_before_update), - laters); - - return laters; -} - -void -meta_laters_free (MetaLaters *laters) -{ - ClutterStage *stage = meta_compositor_get_stage (laters->compositor); - unsigned int i; - - for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) - g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref); - - g_clear_signal_handler (&laters->before_update_handler_id, stage); - g_free (laters); -} diff --git a/src/compositor/meta-module.c b/src/compositor/meta-module.c deleted file mode 100644 index a8ed15bae..000000000 --- a/src/compositor/meta-module.c +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "compositor/meta-module.h" - -#include <gmodule.h> - -#include "meta/meta-plugin.h" - -enum -{ - PROP_0, - PROP_PATH, -}; - -struct _MetaModulePrivate -{ - GModule *lib; - gchar *path; - GType plugin_type; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (MetaModule, meta_module, G_TYPE_TYPE_MODULE); - -static gboolean -meta_module_load (GTypeModule *gmodule) -{ - MetaModulePrivate *priv = META_MODULE (gmodule)->priv; - GType (*register_type) (GTypeModule *) = NULL; - - if (priv->lib && priv->plugin_type) - return TRUE; - - g_assert (priv->path); - - if (!priv->lib && - !(priv->lib = g_module_open (priv->path, 0))) - { - g_warning ("Could not load library [%s (%s)]", - priv->path, g_module_error ()); - return FALSE; - } - - if (g_module_symbol (priv->lib, "meta_plugin_register_type", - (gpointer *)(void *)®ister_type) && - register_type) - { - GType plugin_type; - - if (!(plugin_type = register_type (gmodule))) - { - g_warning ("Could not register type for plugin %s", - priv->path); - return FALSE; - } - else - { - priv->plugin_type = plugin_type; - } - - return TRUE; - } - else - g_warning ("Broken plugin module [%s]", priv->path); - - return FALSE; -} - -static void -meta_module_unload (GTypeModule *gmodule) -{ - MetaModulePrivate *priv = META_MODULE (gmodule)->priv; - - g_module_close (priv->lib); - - priv->lib = NULL; - priv->plugin_type = 0; -} - -static void -meta_module_dispose (GObject *object) -{ - G_OBJECT_CLASS (meta_module_parent_class)->dispose (object); -} - -static void -meta_module_finalize (GObject *object) -{ - MetaModulePrivate *priv = META_MODULE (object)->priv; - - g_free (priv->path); - priv->path = NULL; - - G_OBJECT_CLASS (meta_module_parent_class)->finalize (object); -} - -static void -meta_module_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaModulePrivate *priv = META_MODULE (object)->priv; - - switch (prop_id) - { - case PROP_PATH: - g_free (priv->path); - priv->path = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_module_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaModulePrivate *priv = META_MODULE (object)->priv; - - switch (prop_id) - { - case PROP_PATH: - g_value_set_string (value, priv->path); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_module_class_init (MetaModuleClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GTypeModuleClass *gmodule_class = G_TYPE_MODULE_CLASS (klass); - - gobject_class->finalize = meta_module_finalize; - gobject_class->dispose = meta_module_dispose; - gobject_class->set_property = meta_module_set_property; - gobject_class->get_property = meta_module_get_property; - - gmodule_class->load = meta_module_load; - gmodule_class->unload = meta_module_unload; - - g_object_class_install_property (gobject_class, - PROP_PATH, - g_param_spec_string ("path", - "Path", - "Load path", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); -} - -static void -meta_module_init (MetaModule *self) -{ - self->priv = meta_module_get_instance_private (self); -} - -GType -meta_module_get_plugin_type (MetaModule *module) -{ - MetaModulePrivate *priv = META_MODULE (module)->priv; - - return priv->plugin_type; -} - diff --git a/src/compositor/meta-module.h b/src/compositor/meta-module.h deleted file mode 100644 index dd6d5a685..000000000 --- a/src/compositor/meta-module.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef META_MODULE_H_ -#define META_MODULE_H_ - -#include <glib-object.h> - -#define META_TYPE_MODULE (meta_module_get_type ()) -#define META_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MODULE, MetaModule)) -#define META_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MODULE, MetaModuleClass)) -#define META_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_MODULE_TYPE)) -#define META_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MODULE)) -#define META_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MODULE, MetaModuleClass)) - -typedef struct _MetaModule MetaModule; -typedef struct _MetaModuleClass MetaModuleClass; -typedef struct _MetaModulePrivate MetaModulePrivate; - -struct _MetaModule -{ - GTypeModule parent; - - MetaModulePrivate *priv; -}; - -struct _MetaModuleClass -{ - GTypeModuleClass parent_class; -}; - - -GType meta_module_get_type (void); - -GType meta_module_get_plugin_type (MetaModule *module); - -#endif diff --git a/src/compositor/meta-plugin-manager.c b/src/compositor/meta-plugin-manager.c deleted file mode 100644 index ab7fce663..000000000 --- a/src/compositor/meta-plugin-manager.c +++ /dev/null @@ -1,419 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "compositor/meta-plugin-manager.h" - -#include <stdlib.h> -#include <string.h> - -#include "backends/x11/meta-clutter-backend-x11.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-module.h" -#include "core/meta-close-dialog-default-private.h" -#include "core/meta-inhibit-shortcuts-dialog-default-private.h" -#include "core/window-private.h" -#include "meta/meta-x11-errors.h" -#include "meta/prefs.h" -#include "meta/workspace.h" - -static GType plugin_type = G_TYPE_NONE; - -struct MetaPluginManager -{ - MetaCompositor *compositor; - MetaPlugin *plugin; -}; - -void -meta_plugin_manager_set_plugin_type (GType gtype) -{ - if (plugin_type != G_TYPE_NONE) - meta_fatal ("Mutter plugin already set: %s", g_type_name (plugin_type)); - - plugin_type = gtype; -} - -/* - * Loads the given plugin. - */ -void -meta_plugin_manager_load (const gchar *plugin_name) -{ - const gchar *dpath = MUTTER_PLUGIN_DIR "/"; - gchar *path; - MetaModule *module; - - if (g_path_is_absolute (plugin_name)) - path = g_strdup (plugin_name); - else - path = g_strconcat (dpath, plugin_name, ".so", NULL); - - module = g_object_new (META_TYPE_MODULE, "path", path, NULL); - if (!module || !g_type_module_use (G_TYPE_MODULE (module))) - { - /* This is fatal under the assumption that a monitoring - * process like gnome-session will take over and handle - * our untimely exit. - */ - g_printerr ("Unable to load plugin module [%s]: %s", - path, g_module_error()); - exit (1); - } - - meta_plugin_manager_set_plugin_type (meta_module_get_plugin_type (module)); - - g_type_module_unuse (G_TYPE_MODULE (module)); - g_free (path); -} - -static void -on_confirm_display_change (MetaMonitorManager *monitors, - MetaPluginManager *plugin_mgr) -{ - meta_plugin_manager_confirm_display_change (plugin_mgr); -} - -MetaPluginManager * -meta_plugin_manager_new (MetaCompositor *compositor) -{ - MetaPluginManager *plugin_mgr; - MetaPluginClass *klass; - MetaPlugin *plugin; - MetaMonitorManager *monitors; - - plugin_mgr = g_new0 (MetaPluginManager, 1); - plugin_mgr->compositor = compositor; - plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL); - - _meta_plugin_set_compositor (plugin, compositor); - - klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->start) - klass->start (plugin); - - monitors = meta_monitor_manager_get (); - g_signal_connect (monitors, "confirm-display-change", - G_CALLBACK (on_confirm_display_change), plugin_mgr); - - return plugin_mgr; -} - -static void -meta_plugin_manager_kill_window_effects (MetaPluginManager *plugin_mgr, - MetaWindowActor *actor) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->kill_window_effects) - klass->kill_window_effects (plugin, actor); -} - -static void -meta_plugin_manager_kill_switch_workspace (MetaPluginManager *plugin_mgr) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->kill_switch_workspace) - klass->kill_switch_workspace (plugin); -} - -/* - * Public method that the compositor hooks into for events that require - * no additional parameters. - * - * Returns TRUE if the plugin handled the event type (i.e., - * if the return value is FALSE, there will be no subsequent call to the - * manager completed() callback, and the compositor must ensure that any - * appropriate post-effect cleanup is carried out. - */ -gboolean -meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, - MetaWindowActor *actor, - MetaPluginEffect event) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - gboolean retval = FALSE; - - if (display->display_opening) - return FALSE; - - switch (event) - { - case META_PLUGIN_MINIMIZE: - if (klass->minimize) - { - retval = TRUE; - meta_plugin_manager_kill_window_effects (plugin_mgr, - actor); - klass->minimize (plugin, actor); - } - break; - case META_PLUGIN_UNMINIMIZE: - if (klass->unminimize) - { - retval = TRUE; - meta_plugin_manager_kill_window_effects (plugin_mgr, - actor); - klass->unminimize (plugin, actor); - } - break; - case META_PLUGIN_MAP: - if (klass->map) - { - retval = TRUE; - meta_plugin_manager_kill_window_effects (plugin_mgr, - actor); - klass->map (plugin, actor); - } - break; - case META_PLUGIN_DESTROY: - if (klass->destroy) - { - retval = TRUE; - meta_plugin_manager_kill_window_effects (plugin_mgr, - actor); - klass->destroy (plugin, actor); - } - break; - default: - g_warning ("Incorrect handler called for event %d", event); - } - - return retval; -} - -void -meta_plugin_manager_event_size_changed (MetaPluginManager *plugin_mgr, - MetaWindowActor *actor) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->size_changed) - klass->size_changed (plugin, actor); -} - -gboolean -meta_plugin_manager_event_size_change (MetaPluginManager *plugin_mgr, - MetaWindowActor *actor, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - - if (display->display_opening) - return FALSE; - - if (!klass->size_change) - return FALSE; - - meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - klass->size_change (plugin, actor, which_change, old_frame_rect, old_buffer_rect); - return TRUE; -} - -/* - * The public method that the compositor hooks into for desktop switching. - * - * Returns TRUE if the plugin handled the event type (i.e., - * if the return value is FALSE, there will be no subsequent call to the - * manager completed() callback, and the compositor must ensure that any - * appropriate post-effect cleanup is carried out. - */ -gboolean -meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, - gint from, - gint to, - MetaMotionDirection direction) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - gboolean retval = FALSE; - - if (display->display_opening) - return FALSE; - - if (klass->switch_workspace) - { - retval = TRUE; - meta_plugin_manager_kill_switch_workspace (plugin_mgr); - klass->switch_workspace (plugin, from, to, direction); - } - - return retval; -} - -gboolean -meta_plugin_manager_filter_keybinding (MetaPluginManager *plugin_mgr, - MetaKeyBinding *binding) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->keybinding_filter) - return klass->keybinding_filter (plugin, binding); - - return FALSE; -} - -gboolean -meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr, - XEvent *xev) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - - return _meta_plugin_xevent_filter (plugin, xev); -} - -void -meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->confirm_display_change) - klass->confirm_display_change (plugin); - else - meta_plugin_complete_display_change (plugin, TRUE); -} - -gboolean -meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr, - MetaWindow *window, - MetaRectangle *tile_rect, - int tile_monitor_number) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - - if (display->display_opening) - return FALSE; - - if (klass->show_tile_preview) - { - klass->show_tile_preview (plugin, window, tile_rect, tile_monitor_number); - return TRUE; - } - - return FALSE; -} - -gboolean -meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - - if (display->display_opening) - return FALSE; - - if (klass->hide_tile_preview) - { - klass->hide_tile_preview (plugin); - return TRUE; - } - - return FALSE; -} - -void -meta_plugin_manager_show_window_menu (MetaPluginManager *plugin_mgr, - MetaWindow *window, - MetaWindowMenuType menu, - int x, - int y) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - - if (display->display_opening) - return; - - if (klass->show_window_menu) - klass->show_window_menu (plugin, window, menu, x, y); -} - -void -meta_plugin_manager_show_window_menu_for_rect (MetaPluginManager *plugin_mgr, - MetaWindow *window, - MetaWindowMenuType menu, - MetaRectangle *rect) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_compositor_get_display (plugin_mgr->compositor); - - if (display->display_opening) - return; - - if (klass->show_window_menu_for_rect) - klass->show_window_menu_for_rect (plugin, window, menu, rect); -} - -MetaCloseDialog * -meta_plugin_manager_create_close_dialog (MetaPluginManager *plugin_mgr, - MetaWindow *window) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->create_close_dialog) - return klass->create_close_dialog (plugin, window); - - return meta_close_dialog_default_new (window); -} - -MetaInhibitShortcutsDialog * -meta_plugin_manager_create_inhibit_shortcuts_dialog (MetaPluginManager *plugin_mgr, - MetaWindow *window) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->create_inhibit_shortcuts_dialog) - return klass->create_inhibit_shortcuts_dialog (plugin, window); - - return meta_inhibit_shortcuts_dialog_default_new (window); -} - -void -meta_plugin_manager_locate_pointer (MetaPluginManager *plugin_mgr) -{ - MetaPlugin *plugin = plugin_mgr->plugin; - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->locate_pointer) - klass->locate_pointer (plugin); -} diff --git a/src/compositor/meta-plugin-manager.h b/src/compositor/meta-plugin-manager.h deleted file mode 100644 index d1c007fa1..000000000 --- a/src/compositor/meta-plugin-manager.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef META_PLUGIN_MANAGER_H_ -#define META_PLUGIN_MANAGER_H_ - -#include "core/util-private.h" -#include "meta/meta-plugin.h" -#include "meta/types.h" - -typedef enum -{ - META_PLUGIN_NONE, - META_PLUGIN_MINIMIZE, - META_PLUGIN_MAP, - META_PLUGIN_DESTROY, - META_PLUGIN_SWITCH_WORKSPACE, - META_PLUGIN_UNMINIMIZE, - META_PLUGIN_SIZE_CHANGE, -} MetaPluginEffect; - -/** - * MetaPluginManager: (skip) - * - */ -typedef struct MetaPluginManager MetaPluginManager; - -MetaPluginManager * meta_plugin_manager_new (MetaCompositor *compositor); - -META_EXPORT_TEST -void meta_plugin_manager_load (const gchar *plugin_name); - -gboolean meta_plugin_manager_event_simple (MetaPluginManager *mgr, - MetaWindowActor *actor, - MetaPluginEffect event); - -void meta_plugin_manager_event_size_changed (MetaPluginManager *mgr, - MetaWindowActor *actor); - -gboolean meta_plugin_manager_event_size_change (MetaPluginManager *mgr, - MetaWindowActor *actor, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect); - -gboolean meta_plugin_manager_switch_workspace (MetaPluginManager *mgr, - gint from, - gint to, - MetaMotionDirection direction); - -gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager *mgr, - MetaKeyBinding *binding); - -gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr, - XEvent *xev); -gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin, - XEvent *xev); - -void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr); - -gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr, - MetaWindow *window, - MetaRectangle *tile_rect, - int tile_monitor_number); -gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr); - -void meta_plugin_manager_show_window_menu (MetaPluginManager *mgr, - MetaWindow *window, - MetaWindowMenuType menu, - int x, - int y); - -void meta_plugin_manager_show_window_menu_for_rect (MetaPluginManager *mgr, - MetaWindow *window, - MetaWindowMenuType menu, - MetaRectangle *rect); - -MetaCloseDialog * meta_plugin_manager_create_close_dialog (MetaPluginManager *plugin_mgr, - MetaWindow *window); - -MetaInhibitShortcutsDialog * - meta_plugin_manager_create_inhibit_shortcuts_dialog (MetaPluginManager *plugin_mgr, - MetaWindow *window); - -void meta_plugin_manager_locate_pointer (MetaPluginManager *mgr); - -#endif diff --git a/src/compositor/meta-plugin.c b/src/compositor/meta-plugin.c deleted file mode 100644 index 188675a4d..000000000 --- a/src/compositor/meta-plugin.c +++ /dev/null @@ -1,223 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -/** - * SECTION:meta-plugin - * @title: MetaPlugin - * @short_description: Entry point for plugins - * - */ - -#include "config.h" - -#include "meta/meta-plugin.h" - -#include <string.h> -#include <X11/Xlib.h> -#include <X11/extensions/Xfixes.h> -#include <X11/extensions/shape.h> - -#include "backends/meta-monitor-manager-private.h" -#include "backends/x11/meta-clutter-backend-x11.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-window-actor-private.h" -#include "compositor/meta-plugin-manager.h" -#include "meta/display.h" -#include "meta/util.h" - - -typedef struct _MetaPluginPrivate -{ - MetaCompositor *compositor; -} MetaPluginPrivate; - -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaPlugin, meta_plugin, G_TYPE_OBJECT); - -static void -meta_plugin_class_init (MetaPluginClass *klass) -{ -} - -static void -meta_plugin_init (MetaPlugin *self) -{ -} - -const MetaPluginInfo * -meta_plugin_get_info (MetaPlugin *plugin) -{ - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass && klass->plugin_info) - return klass->plugin_info (plugin); - - return NULL; -} - -gboolean -_meta_plugin_xevent_filter (MetaPlugin *plugin, - XEvent *xev) -{ - MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - - if (klass->xevent_filter) - return klass->xevent_filter (plugin, xev); - else - return FALSE; -} - -void -meta_plugin_switch_workspace_completed (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = meta_plugin_get_instance_private (plugin); - - meta_switch_workspace_completed (priv->compositor); -} - -static void -meta_plugin_window_effect_completed (MetaPlugin *plugin, - MetaWindowActor *actor, - unsigned long event) -{ - meta_window_actor_effect_completed (actor, event); -} - -void -meta_plugin_minimize_completed (MetaPlugin *plugin, - MetaWindowActor *actor) -{ - meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MINIMIZE); -} - -void -meta_plugin_unminimize_completed (MetaPlugin *plugin, - MetaWindowActor *actor) -{ - meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_UNMINIMIZE); -} - -void -meta_plugin_size_change_completed (MetaPlugin *plugin, - MetaWindowActor *actor) -{ - meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_SIZE_CHANGE); -} - -void -meta_plugin_map_completed (MetaPlugin *plugin, - MetaWindowActor *actor) -{ - meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAP); -} - -void -meta_plugin_destroy_completed (MetaPlugin *plugin, - MetaWindowActor *actor) -{ - meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_DESTROY); -} - -/** - * meta_plugin_begin_modal: - * @plugin: a #MetaPlugin - * @options: flags that modify the behavior of the modal grab - * @timestamp: the timestamp used for establishing grabs - * - * This function is used to grab the keyboard and mouse for the exclusive - * use of the plugin. Correct operation requires that both the keyboard - * and mouse are grabbed, or thing will break. (In particular, other - * passive X grabs in Meta can trigger but not be handled by the normal - * keybinding handling code.) However, the plugin can establish the keyboard - * and/or mouse grabs ahead of time and pass in the - * %META_MODAL_POINTER_ALREADY_GRABBED and/or %META_MODAL_KEYBOARD_ALREADY_GRABBED - * options. This facility is provided for two reasons: first to allow using - * this function to establish modality after a passive grab, and second to - * allow using obscure features of XGrabPointer() and XGrabKeyboard() without - * having to add them to this API. - * - * Return value: whether we successfully grabbed the keyboard and - * mouse and made the plugin modal. - */ -gboolean -meta_plugin_begin_modal (MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp) -{ - MetaPluginPrivate *priv = meta_plugin_get_instance_private (plugin); - - return meta_begin_modal_for_plugin (priv->compositor, plugin, - options, timestamp); -} - -/** - * meta_plugin_end_modal: - * @plugin: a #MetaPlugin - * @timestamp: the time used for releasing grabs - * - * Ends the modal operation begun with meta_plugin_begin_modal(). This - * ungrabs both the mouse and keyboard even when - * %META_MODAL_POINTER_ALREADY_GRABBED or - * %META_MODAL_KEYBOARD_ALREADY_GRABBED were provided as options - * when beginnning the modal operation. - */ -void -meta_plugin_end_modal (MetaPlugin *plugin, - guint32 timestamp) -{ - MetaPluginPrivate *priv = meta_plugin_get_instance_private (plugin); - - meta_end_modal_for_plugin (priv->compositor, plugin, timestamp); -} - -/** - * meta_plugin_get_display: - * @plugin: a #MetaPlugin - * - * Gets the #MetaDisplay corresponding to a plugin. - * - * Return value: (transfer none): the #MetaDisplay for the plugin - */ -MetaDisplay * -meta_plugin_get_display (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = meta_plugin_get_instance_private (plugin); - MetaDisplay *display = meta_compositor_get_display (priv->compositor); - - return display; -} - -void -_meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor) -{ - MetaPluginPrivate *priv = meta_plugin_get_instance_private (plugin); - - priv->compositor = compositor; -} - -void -meta_plugin_complete_display_change (MetaPlugin *plugin, - gboolean ok) -{ - MetaMonitorManager *manager; - - manager = meta_monitor_manager_get (); - meta_monitor_manager_confirm_configuration (manager, ok); -} diff --git a/src/compositor/meta-shadow-factory.c b/src/compositor/meta-shadow-factory.c deleted file mode 100644 index d6424d3be..000000000 --- a/src/compositor/meta-shadow-factory.c +++ /dev/null @@ -1,1066 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -/** - * SECTION:meta-shadow-factory - * @title: MetaShadowFactory - * @short_description: Create and cache shadow textures for arbitrary window shapes - */ - -#include "config.h" - -#include <math.h> -#include <string.h> - -#include "compositor/cogl-utils.h" -#include "compositor/region-utils.h" -#include "meta/meta-shadow-factory.h" -#include "meta/util.h" - -/* This file implements blurring the shape of a window to produce a - * shadow texture. The details are discussed below; a quick summary - * of the optimizations we use: - * - * - If the window shape is along the lines of a rounded rectangle - - * a rectangular center portion with stuff at the corners - then - * the blur of this - the shadow - can also be represented as a - * 9-sliced texture and the same texture can be used for different - * size. - * - * - We use the fact that a Gaussian blur is separable to do a - * 2D blur as 1D blur of the rows followed by a 1D blur of the - * columns. - * - * - For better cache efficiency, we blur rows, transpose the image - * in blocks, blur rows again, and then transpose back. - * - * - We approximate the 1D gaussian blur as 3 successive box filters. - */ - -typedef struct _MetaShadowCacheKey MetaShadowCacheKey; -typedef struct _MetaShadowClassInfo MetaShadowClassInfo; - -struct _MetaShadowCacheKey -{ - MetaWindowShape *shape; - int radius; - int top_fade; -}; - -struct _MetaShadow -{ - int ref_count; - - MetaShadowFactory *factory; - MetaShadowCacheKey key; - CoglTexture *texture; - CoglPipeline *pipeline; - - /* The outer order is the distance the shadow extends outside the window - * shape; the inner border is the unscaled portion inside the window - * shape */ - int outer_border_top; - int inner_border_top; - int outer_border_right; - int inner_border_right; - int outer_border_bottom; - int inner_border_bottom; - int outer_border_left; - int inner_border_left; - - guint scale_width : 1; - guint scale_height : 1; -}; - -struct _MetaShadowClassInfo -{ - const char *name; /* const so we can reuse for static definitions */ - MetaShadowParams focused; - MetaShadowParams unfocused; -}; - -struct _MetaShadowFactory -{ - GObject parent_instance; - - /* MetaShadowCacheKey => MetaShadow; the shadows are not referenced - * by the factory, they are simply removed from the table when freed */ - GHashTable *shadows; - - /* class name => MetaShadowClassInfo */ - GHashTable *shadow_classes; -}; - -enum -{ - CHANGED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -/* The first element in this array also defines the default parameters - * for newly created classes */ -MetaShadowClassInfo default_shadow_classes[] = { - { "normal", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - { "dialog", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - { "modal_dialog", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - { "utility", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - { "border", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - { "menu", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, - - { "popup-menu", { 1, -1, 0, 0, 128 }, { 1, -1, 0, 0, 128 } }, - { "dropdown-menu", { 1, -1, 0, 0, 128 }, { 1, -1, 0, 0, 128 } }, - - { "attached", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } } -}; - -G_DEFINE_TYPE (MetaShadowFactory, meta_shadow_factory, G_TYPE_OBJECT); - -static guint -meta_shadow_cache_key_hash (gconstpointer val) -{ - const MetaShadowCacheKey *key = val; - - return 59 * key->radius + 67 * key->top_fade + 73 * meta_window_shape_hash (key->shape); -} - -static gboolean -meta_shadow_cache_key_equal (gconstpointer a, - gconstpointer b) -{ - const MetaShadowCacheKey *key_a = a; - const MetaShadowCacheKey *key_b = b; - - return (key_a->radius == key_b->radius && key_a->top_fade == key_b->top_fade && - meta_window_shape_equal (key_a->shape, key_b->shape)); -} - -MetaShadow * -meta_shadow_ref (MetaShadow *shadow) -{ - shadow->ref_count++; - - return shadow; -} - -void -meta_shadow_unref (MetaShadow *shadow) -{ - shadow->ref_count--; - if (shadow->ref_count == 0) - { - if (shadow->factory) - { - g_hash_table_remove (shadow->factory->shadows, - &shadow->key); - } - - meta_window_shape_unref (shadow->key.shape); - cogl_object_unref (shadow->texture); - cogl_object_unref (shadow->pipeline); - - g_free (shadow); - } -} - -/** - * meta_shadow_paint: - * @window_x: x position of the region to paint a shadow for - * @window_y: y position of the region to paint a shadow for - * @window_width: actual width of the region to paint a shadow for - * @window_height: actual height of the region to paint a shadow for - * @clip: (nullable): if non-%NULL specifies the visible portion - * of the shadow. - * @clip_strictly: if %TRUE, drawing will be clipped strictly - * to @clip, otherwise, it will be only used to optimize - * drawing. - * - * Paints the shadow at the given position, for the specified actual - * size of the region. (Since a #MetaShadow can be shared between - * different sizes with the same extracted #MetaWindowShape the - * size needs to be passed in here.) - */ -void -meta_shadow_paint (MetaShadow *shadow, - CoglFramebuffer *framebuffer, - int window_x, - int window_y, - int window_width, - int window_height, - guint8 opacity, - cairo_region_t *clip, - gboolean clip_strictly) -{ - float texture_width = cogl_texture_get_width (shadow->texture); - float texture_height = cogl_texture_get_height (shadow->texture); - int i, j; - float src_x[4]; - float src_y[4]; - int dest_x[4]; - int dest_y[4]; - int n_x, n_y; - - if (clip && cairo_region_is_empty (clip)) - return; - - cogl_pipeline_set_color4ub (shadow->pipeline, - opacity, opacity, opacity, opacity); - - if (shadow->scale_width) - { - n_x = 3; - - src_x[0] = 0.0; - src_x[1] = (shadow->inner_border_left + shadow->outer_border_left) / texture_width; - src_x[2] = (texture_width - (shadow->inner_border_right + shadow->outer_border_right)) / texture_width; - src_x[3] = 1.0; - - dest_x[0] = window_x - shadow->outer_border_left; - dest_x[1] = window_x + shadow->inner_border_left; - dest_x[2] = window_x + window_width - shadow->inner_border_right; - dest_x[3] = window_x + window_width + shadow->outer_border_right; - } - else - { - n_x = 1; - - src_x[0] = 0.0; - src_x[1] = 1.0; - - dest_x[0] = window_x - shadow->outer_border_left; - dest_x[1] = window_x + window_width + shadow->outer_border_right; - } - - if (shadow->scale_height) - { - n_y = 3; - - src_y[0] = 0.0; - src_y[1] = (shadow->inner_border_top + shadow->outer_border_top) / texture_height; - src_y[2] = (texture_height - (shadow->inner_border_bottom + shadow->outer_border_bottom)) / texture_height; - src_y[3] = 1.0; - - dest_y[0] = window_y - shadow->outer_border_top; - dest_y[1] = window_y + shadow->inner_border_top; - dest_y[2] = window_y + window_height - shadow->inner_border_bottom; - dest_y[3] = window_y + window_height + shadow->outer_border_bottom; - } - else - { - n_y = 1; - - src_y[0] = 0.0; - src_y[1] = 1.0; - - dest_y[0] = window_y - shadow->outer_border_top; - dest_y[1] = window_y + window_height + shadow->outer_border_bottom; - } - - for (j = 0; j < n_y; j++) - { - cairo_rectangle_int_t dest_rect; - dest_rect.y = dest_y[j]; - dest_rect.height = dest_y[j + 1] - dest_y[j]; - - if (dest_rect.height == 0) - continue; - - for (i = 0; i < n_x; i++) - { - cairo_region_overlap_t overlap; - - dest_rect.x = dest_x[i]; - dest_rect.width = dest_x[i + 1] - dest_x[i]; - - if (dest_rect.width == 0) - continue; - - if (clip) - overlap = cairo_region_contains_rectangle (clip, &dest_rect); - else - overlap = CAIRO_REGION_OVERLAP_IN; - - if (overlap == CAIRO_REGION_OVERLAP_OUT) - continue; - - /* There's quite a bit of overhead from allocating a new - * region in order to find an exact intersection and - * generating more geometry - we make the assumption that - * unless we have to clip strictly it will be cheaper to - * just draw the entire rectangle. - */ - if (overlap == CAIRO_REGION_OVERLAP_IN || - (overlap == CAIRO_REGION_OVERLAP_PART && !clip_strictly)) - { - cogl_framebuffer_draw_textured_rectangle (framebuffer, - shadow->pipeline, - dest_x[i], dest_y[j], - dest_x[i + 1], dest_y[j + 1], - src_x[i], src_y[j], - src_x[i + 1], src_y[j + 1]); - } - else if (overlap == CAIRO_REGION_OVERLAP_PART) - { - cairo_region_t *intersection; - int n_rectangles, k; - - intersection = cairo_region_create_rectangle (&dest_rect); - cairo_region_intersect (intersection, clip); - - n_rectangles = cairo_region_num_rectangles (intersection); - for (k = 0; k < n_rectangles; k++) - { - cairo_rectangle_int_t rect; - float src_x1, src_x2, src_y1, src_y2; - - cairo_region_get_rectangle (intersection, k, &rect); - - /* Separately linear interpolate X and Y coordinates in the source - * based on the destination X and Y coordinates */ - - src_x1 = (src_x[i] * (dest_rect.x + dest_rect.width - rect.x) + - src_x[i + 1] * (rect.x - dest_rect.x)) / dest_rect.width; - src_x2 = (src_x[i] * (dest_rect.x + dest_rect.width - (rect.x + rect.width)) + - src_x[i + 1] * (rect.x + rect.width - dest_rect.x)) / dest_rect.width; - - src_y1 = (src_y[j] * (dest_rect.y + dest_rect.height - rect.y) + - src_y[j + 1] * (rect.y - dest_rect.y)) / dest_rect.height; - src_y2 = (src_y[j] * (dest_rect.y + dest_rect.height - (rect.y + rect.height)) + - src_y[j + 1] * (rect.y + rect.height - dest_rect.y)) / dest_rect.height; - - cogl_framebuffer_draw_textured_rectangle (framebuffer, - shadow->pipeline, - rect.x, rect.y, - rect.x + rect.width, rect.y + rect.height, - src_x1, src_y1, src_x2, src_y2); - } - - cairo_region_destroy (intersection); - } - } - } -} - -/** - * meta_shadow_get_bounds: - * @shadow: a #MetaShadow - * @window_x: x position of the region to paint a shadow for - * @window_y: y position of the region to paint a shadow for - * @window_width: actual width of the region to paint a shadow for - * @window_height: actual height of the region to paint a shadow for - * - * Computes the bounds of the pixels that will be affected by - * meta_shadow_paint() - */ -void -meta_shadow_get_bounds (MetaShadow *shadow, - int window_x, - int window_y, - int window_width, - int window_height, - cairo_rectangle_int_t *bounds) -{ - bounds->x = window_x - shadow->outer_border_left; - bounds->y = window_y - shadow->outer_border_top; - bounds->width = window_width + shadow->outer_border_left + shadow->outer_border_right; - bounds->height = window_height + shadow->outer_border_top + shadow->outer_border_bottom; -} - -static void -meta_shadow_class_info_free (MetaShadowClassInfo *class_info) -{ - g_free ((char *)class_info->name); - g_free (class_info); -} - -static void -meta_shadow_factory_init (MetaShadowFactory *factory) -{ - guint i; - - factory->shadows = g_hash_table_new (meta_shadow_cache_key_hash, - meta_shadow_cache_key_equal); - - factory->shadow_classes = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - (GDestroyNotify)meta_shadow_class_info_free); - - for (i = 0; i < G_N_ELEMENTS (default_shadow_classes); i++) - { - MetaShadowClassInfo *class_info = g_new0 (MetaShadowClassInfo, 1); - - *class_info = default_shadow_classes[i]; - class_info->name = g_strdup (class_info->name); - - g_hash_table_insert (factory->shadow_classes, - (char *)class_info->name, class_info); - } -} - -static void -meta_shadow_factory_finalize (GObject *object) -{ - MetaShadowFactory *factory = META_SHADOW_FACTORY (object); - GHashTableIter iter; - gpointer key, value; - - /* Detach from the shadows in the table so we won't try to - * remove them when they're freed. */ - g_hash_table_iter_init (&iter, factory->shadows); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - MetaShadow *shadow = key; - shadow->factory = NULL; - } - - g_hash_table_destroy (factory->shadows); - g_hash_table_destroy (factory->shadow_classes); - - G_OBJECT_CLASS (meta_shadow_factory_parent_class)->finalize (object); -} - -static void -meta_shadow_factory_class_init (MetaShadowFactoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_shadow_factory_finalize; - - signals[CHANGED] = - g_signal_new ("changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -MetaShadowFactory * -meta_shadow_factory_new (void) -{ - return g_object_new (META_TYPE_SHADOW_FACTORY, NULL); -} - -/** - * meta_shadow_factory_get_default: - * - * Return value: (transfer none): the global singleton shadow factory - */ -MetaShadowFactory * -meta_shadow_factory_get_default (void) -{ - static MetaShadowFactory *factory; - - if (factory == NULL) - factory = meta_shadow_factory_new (); - - return factory; -} - -/* We emulate a 1D Gaussian blur by using 3 consecutive box blurs; - * this produces a result that's within 3% of the original and can be - * implemented much faster for large filter sizes because of the - * efficiency of implementation of a box blur. Idea and formula - * for choosing the box blur size come from: - * - * http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement - * - * The 2D blur is then done by blurring the rows, flipping the - * image and blurring the columns. (This is possible because the - * Gaussian kernel is separable - it's the product of a horizontal - * blur and a vertical blur.) - */ -static int -get_box_filter_size (int radius) -{ - return (int)(0.5 + radius * (0.75 * sqrt(2*M_PI))); -} - -/* The "spread" of the filter is the number of pixels from an original - * pixel that it's blurred image extends. (A no-op blur that doesn't - * blur would have a spread of 0.) See comment in blur_rows() for why the - * odd and even cases are different - */ -static int -get_shadow_spread (int radius) -{ - int d; - - if (radius == 0) - return 0; - - d = get_box_filter_size (radius); - - if (d % 2 == 1) - return 3 * (d / 2); - else - return 3 * (d / 2) - 1; -} - -/* This applies a single box blur pass to a horizontal range of pixels; - * since the box blur has the same weight for all pixels, we can - * implement an efficient sliding window algorithm where we add - * in pixels coming into the window from the right and remove - * them when they leave the windw to the left. - * - * d is the filter width; for even d shift indicates how the blurred - * result is aligned with the original - does ' x ' go to ' yy' (shift=1) - * or 'yy ' (shift=-1) - */ -static void -blur_xspan (guchar *row, - guchar *tmp_buffer, - int row_width, - int x0, - int x1, - int d, - int shift) -{ - int offset; - int sum = 0; - int i; - - if (d % 2 == 1) - offset = d / 2; - else - offset = (d - shift) / 2; - - /* All the conditionals in here look slow, but the branches will - * be well predicted and there are enough different possibilities - * that trying to write this as a series of unconditional loops - * is hard and not an obvious win. The main slow down here seems - * to be the integer division per pixel; one possible optimization - * would be to accumulate into two 16-bit integer buffers and - * only divide down after all three passes. (SSE parallel implementation - * of the divide step is possible.) - */ - for (i = x0 - d + offset; i < x1 + offset; i++) - { - if (i >= 0 && i < row_width) - sum += row[i]; - - if (i >= x0 + offset) - { - if (i >= d) - sum -= row[i - d]; - - tmp_buffer[i - offset] = (sum + d / 2) / d; - } - } - - memcpy (row + x0, tmp_buffer + x0, x1 - x0); -} - -static void -blur_rows (cairo_region_t *convolve_region, - int x_offset, - int y_offset, - guchar *buffer, - int buffer_width, - int buffer_height, - int d) -{ - int i, j; - int n_rectangles; - guchar *tmp_buffer; - - tmp_buffer = g_malloc (buffer_width); - - n_rectangles = cairo_region_num_rectangles (convolve_region); - for (i = 0; i < n_rectangles; i++) - { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (convolve_region, i, &rect); - - for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++) - { - guchar *row = buffer + j * buffer_width; - int x0 = x_offset + rect.x; - int x1 = x0 + rect.width; - - /* We want to produce a symmetric blur that spreads a pixel - * equally far to the left and right. If d is odd that happens - * naturally, but for d even, we approximate by using a blur - * on either side and then a centered blur of size d + 1. - * (technique also from the SVG specification) - */ - if (d % 2 == 1) - { - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0); - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0); - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0); - } - else - { - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 1); - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, -1); - blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d + 1, 0); - } - } - } - - g_free (tmp_buffer); -} - -static void -fade_bytes (guchar *bytes, - int width, - int distance, - int total) -{ - guint32 multiplier = (distance * 0x10000 + 0x8000) / total; - int i; - - for (i = 0; i < width; i++) - bytes[i] = (bytes[i] * multiplier) >> 16; -} - -/* Swaps width and height. Either swaps in-place and returns the original - * buffer or allocates a new buffer, frees the original buffer and returns - * the new buffer. - */ -static guchar * -flip_buffer (guchar *buffer, - int width, - int height) -{ - /* Working in blocks increases cache efficiency, compared to reading - * or writing an entire column at once */ -#define BLOCK_SIZE 16 - - if (width == height) - { - int i0, j0; - - for (j0 = 0; j0 < height; j0 += BLOCK_SIZE) - for (i0 = 0; i0 <= j0; i0 += BLOCK_SIZE) - { - int max_j = MIN(j0 + BLOCK_SIZE, height); - int max_i = MIN(i0 + BLOCK_SIZE, width); - int i, j; - - if (i0 == j0) - { - for (j = j0; j < max_j; j++) - for (i = i0; i < j; i++) - { - guchar tmp = buffer[j * width + i]; - buffer[j * width + i] = buffer[i * width + j]; - buffer[i * width + j] = tmp; - } - } - else - { - for (j = j0; j < max_j; j++) - for (i = i0; i < max_i; i++) - { - guchar tmp = buffer[j * width + i]; - buffer[j * width + i] = buffer[i * width + j]; - buffer[i * width + j] = tmp; - } - } - } - - return buffer; - } - else - { - guchar *new_buffer = g_malloc (height * width); - int i0, j0; - - for (i0 = 0; i0 < width; i0 += BLOCK_SIZE) - for (j0 = 0; j0 < height; j0 += BLOCK_SIZE) - { - int max_j = MIN(j0 + BLOCK_SIZE, height); - int max_i = MIN(i0 + BLOCK_SIZE, width); - int i, j; - - for (i = i0; i < max_i; i++) - for (j = j0; j < max_j; j++) - new_buffer[i * height + j] = buffer[j * width + i]; - } - - g_free (buffer); - - return new_buffer; - } -#undef BLOCK_SIZE -} - -static void -make_shadow (MetaShadow *shadow, - cairo_region_t *region) -{ - ClutterBackend *backend = clutter_get_default_backend (); - CoglContext *ctx = clutter_backend_get_cogl_context (backend); - GError *error = NULL; - int d = get_box_filter_size (shadow->key.radius); - int spread = get_shadow_spread (shadow->key.radius); - cairo_rectangle_int_t extents; - cairo_region_t *row_convolve_region; - cairo_region_t *column_convolve_region; - guchar *buffer; - int buffer_width; - int buffer_height; - int x_offset; - int y_offset; - int n_rectangles, j, k; - - cairo_region_get_extents (region, &extents); - - /* In the case where top_fade >= 0 and the portion above the top - * edge of the shape will be cropped, it seems like we could create - * a smaller buffer and omit the top portion, but actually, in our - * multi-pass blur algorithm, the blur into the area above the window - * in the first pass will contribute back to the final pixel values - * for the top pixels, so we create a buffer as if we weren't cropping - * and only crop when creating the CoglTexture. - */ - - buffer_width = extents.width + 2 * spread; - buffer_height = extents.height + 2 * spread; - - /* Round up so we have aligned rows/columns */ - buffer_width = (buffer_width + 3) & ~3; - buffer_height = (buffer_height + 3) & ~3; - - /* Square buffer allows in-place swaps, which are roughly 70% faster, but we - * don't want to over-allocate too much memory. - */ - if (buffer_height < buffer_width && buffer_height > (3 * buffer_width) / 4) - buffer_height = buffer_width; - if (buffer_width < buffer_height && buffer_width > (3 * buffer_height) / 4) - buffer_width = buffer_height; - - buffer = g_malloc0 (buffer_width * buffer_height); - - /* Blurring with multiple box-blur passes is fast, but (especially for - * large shadow sizes) we can improve efficiency by restricting the blur - * to the region that actually needs to be blurred. - */ - row_convolve_region = meta_make_border_region (region, spread, spread, FALSE); - column_convolve_region = meta_make_border_region (region, 0, spread, TRUE); - - /* Offsets between coordinates of the regions and coordinates in the buffer */ - x_offset = spread; - y_offset = spread; - - /* Step 1: unblurred image */ - n_rectangles = cairo_region_num_rectangles (region); - for (k = 0; k < n_rectangles; k++) - { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, k, &rect); - for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++) - memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width); - } - - /* Step 2: swap rows and columns */ - buffer = flip_buffer (buffer, buffer_width, buffer_height); - - /* Step 3: blur rows (really columns) */ - blur_rows (column_convolve_region, y_offset, x_offset, - buffer, buffer_height, buffer_width, - d); - - /* Step 4: swap rows and columns */ - buffer = flip_buffer (buffer, buffer_height, buffer_width); - - /* Step 5: blur rows */ - blur_rows (row_convolve_region, x_offset, y_offset, - buffer, buffer_width, buffer_height, - d); - - /* Step 6: fade out the top, if applicable */ - if (shadow->key.top_fade >= 0) - { - for (j = y_offset; j < y_offset + MIN (shadow->key.top_fade, extents.height + shadow->outer_border_bottom); j++) - fade_bytes(buffer + j * buffer_width, buffer_width, j - y_offset, shadow->key.top_fade); - } - - /* We offset the passed in pixels to crop off the extra area we allocated at the top - * in the case of top_fade >= 0. We also account for padding at the left for symmetry - * though that doesn't currently occur. - */ - shadow->texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, - shadow->outer_border_left + extents.width + shadow->outer_border_right, - shadow->outer_border_top + extents.height + shadow->outer_border_bottom, - COGL_PIXEL_FORMAT_A_8, - buffer_width, - (buffer + - (y_offset - shadow->outer_border_top) * buffer_width + - (x_offset - shadow->outer_border_left)), - &error)); - - if (error) - { - meta_warning ("Failed to allocate shadow texture: %s", error->message); - g_error_free (error); - } - - cairo_region_destroy (row_convolve_region); - cairo_region_destroy (column_convolve_region); - g_free (buffer); - - shadow->pipeline = meta_create_texture_pipeline (shadow->texture); -} - -static MetaShadowParams * -get_shadow_params (MetaShadowFactory *factory, - const char *class_name, - gboolean focused, - gboolean create) -{ - MetaShadowClassInfo *class_info = g_hash_table_lookup (factory->shadow_classes, - class_name); - if (class_info == NULL) - { - if (create) - { - class_info = g_new0 (MetaShadowClassInfo, 1); - *class_info = default_shadow_classes[0]; - class_info->name = g_strdup (class_info->name); - - g_hash_table_insert (factory->shadow_classes, - (char *)class_info->name, class_info); - } - else - { - class_info = &default_shadow_classes[0]; - } - } - - if (focused) - return &class_info->focused; - else - return &class_info->unfocused; -} - -/** - * meta_shadow_factory_get_shadow: - * @factory: a #MetaShadowFactory - * @shape: the size-invariant shape of the window's region - * @width: the actual width of the window's region - * @height: the actual height of the window's region - * @class_name: name of the class of window shadows - * @focused: whether the shadow is for a focused window - * - * Gets the appropriate shadow object for drawing shadows for the - * specified window shape. The region that we are shadowing is specified - * as a combination of a size-invariant extracted shape and the size. - * In some cases, the same shadow object can be shared between sizes; - * in other cases a different shadow object is used for each size. - * - * Return value: (transfer full): a newly referenced #MetaShadow; unref with - * meta_shadow_unref() - */ -MetaShadow * -meta_shadow_factory_get_shadow (MetaShadowFactory *factory, - MetaWindowShape *shape, - int width, - int height, - const char *class_name, - gboolean focused) -{ - MetaShadowParams *params; - MetaShadowCacheKey key; - MetaShadow *shadow; - cairo_region_t *region; - int spread; - int shape_border_top, shape_border_right, shape_border_bottom, shape_border_left; - int inner_border_top, inner_border_right, inner_border_bottom, inner_border_left; - int outer_border_top, outer_border_right, outer_border_bottom, outer_border_left; - gboolean scale_width, scale_height; - gboolean cacheable; - int center_width, center_height; - - g_return_val_if_fail (META_IS_SHADOW_FACTORY (factory), NULL); - g_return_val_if_fail (shape != NULL, NULL); - - /* Using a single shadow texture for different window sizes only works - * when there is a central scaled area that is greater than twice - * the spread of the gaussian blur we are applying to get to the - * shadow image. - * ********* *********** - * /----------\ *###########* *#############* - * | | => **#*********#** => **#***********#** - * | | **#** **#** **#** **#** - * | | **#*********#** **#***********#** - * \----------/ *###########* *#############* - * ********** ************ - * Original Blur Stretched Blur - * - * For smaller sizes, we create a separate shadow image for each size; - * since we assume that there will be little reuse, we don't try to - * cache such images but just recreate them. (Since the current cache - * policy is to only keep around referenced shadows, there wouldn't - * be any harm in caching them, it would just make the book-keeping - * a bit tricker.) - * - * In the case where we are fading a the top, that also has to fit - * within the top unscaled border. - */ - - params = get_shadow_params (factory, class_name, focused, FALSE); - - spread = get_shadow_spread (params->radius); - meta_window_shape_get_borders (shape, - &shape_border_top, - &shape_border_right, - &shape_border_bottom, - &shape_border_left); - - inner_border_top = MAX (shape_border_top + spread, params->top_fade); - outer_border_top = params->top_fade >= 0 ? 0 : spread; - inner_border_right = shape_border_right + spread; - outer_border_right = spread; - inner_border_bottom = shape_border_bottom + spread; - outer_border_bottom = spread; - inner_border_left = shape_border_left + spread; - outer_border_left = spread; - - scale_width = inner_border_left + inner_border_right <= width; - scale_height = inner_border_top + inner_border_bottom <= height; - cacheable = scale_width && scale_height; - - if (cacheable) - { - key.shape = shape; - key.radius = params->radius; - key.top_fade = params->top_fade; - - shadow = g_hash_table_lookup (factory->shadows, &key); - if (shadow) - return meta_shadow_ref (shadow); - } - - shadow = g_new0 (MetaShadow, 1); - - shadow->ref_count = 1; - shadow->factory = factory; - shadow->key.shape = meta_window_shape_ref (shape); - shadow->key.radius = params->radius; - shadow->key.top_fade = params->top_fade; - - shadow->outer_border_top = outer_border_top; - shadow->inner_border_top = inner_border_top; - shadow->outer_border_right = outer_border_right; - shadow->inner_border_right = inner_border_right; - shadow->outer_border_bottom = outer_border_bottom; - shadow->inner_border_bottom = inner_border_bottom; - shadow->outer_border_left = outer_border_left; - shadow->inner_border_left = inner_border_left; - - shadow->scale_width = scale_width; - if (scale_width) - center_width = inner_border_left + inner_border_right - (shape_border_left + shape_border_right); - else - center_width = width - (shape_border_left + shape_border_right); - - shadow->scale_height = scale_height; - if (scale_height) - center_height = inner_border_top + inner_border_bottom - (shape_border_top + shape_border_bottom); - else - center_height = height - (shape_border_top + shape_border_bottom); - - g_assert (center_width >= 0 && center_height >= 0); - - region = meta_window_shape_to_region (shape, center_width, center_height); - make_shadow (shadow, region); - - cairo_region_destroy (region); - - if (cacheable) - g_hash_table_insert (factory->shadows, &shadow->key, shadow); - - return shadow; -} - -/** - * meta_shadow_factory_set_params: - * @factory: a #MetaShadowFactory - * @class_name: name of the class of shadow to set the params for. - * the default shadow classes are the names of the different - * theme frame types (normal, dialog, modal_dialog, utility, - * border, menu, attached) and in addition, popup-menu - * and dropdown-menu. - * @focused: whether the shadow is for a focused window - * @params: new parameter values - * - * Updates the shadow parameters for a particular class of shadows - * for either the focused or unfocused state. If the class name - * does not name an existing class, a new class will be created - * (the other focus state for that class will have default values - * assigned to it.) - */ -void -meta_shadow_factory_set_params (MetaShadowFactory *factory, - const char *class_name, - gboolean focused, - MetaShadowParams *params) -{ - MetaShadowParams *stored_params; - - g_return_if_fail (META_IS_SHADOW_FACTORY (factory)); - g_return_if_fail (class_name != NULL); - g_return_if_fail (params != NULL); - g_return_if_fail (params->radius >= 0); - - stored_params = get_shadow_params (factory, class_name, focused, TRUE); - - *stored_params = *params; - - g_signal_emit (factory, signals[CHANGED], 0); -} - -/** - * meta_shadow_factory_get_params: - * @factory: a #MetaShadowFactory - * @class_name: name of the class of shadow to get the params for - * @focused: whether the shadow is for a focused window - * @params: (out caller-allocates): location to store the current parameter values - * - * Gets the shadow parameters for a particular class of shadows - * for either the focused or unfocused state. If the class name - * does not name an existing class, default values will be returned - * without printing an error. - */ -void -meta_shadow_factory_get_params (MetaShadowFactory *factory, - const char *class_name, - gboolean focused, - MetaShadowParams *params) -{ - MetaShadowParams *stored_params; - - g_return_if_fail (META_IS_SHADOW_FACTORY (factory)); - g_return_if_fail (class_name != NULL); - - stored_params = get_shadow_params (factory, class_name, focused, FALSE); - - if (params) - *params = *stored_params; -} - -G_DEFINE_BOXED_TYPE (MetaShadow, meta_shadow, - meta_shadow_ref, meta_shadow_unref) diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h deleted file mode 100644 index 2fe1b8ea4..000000000 --- a/src/compositor/meta-shaped-texture-private.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * shaped texture - * - * An actor to draw a texture clipped to a list of rectangles - * - * Authored By Neil Roberts <neil@linux.intel.com> - * - * Copyright (C) 2008 Intel Corporation - * 2013 Red Hat, 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. - */ - -#ifndef __META_SHAPED_TEXTURE_PRIVATE_H__ -#define __META_SHAPED_TEXTURE_PRIVATE_H__ - -#include "backends/meta-monitor-manager-private.h" -#include "meta/meta-shaped-texture.h" - -MetaShapedTexture *meta_shaped_texture_new (void); -void meta_shaped_texture_set_texture (MetaShapedTexture *stex, - CoglTexture *texture); -void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex, - gboolean is_y_inverted); -void meta_shaped_texture_set_snippet (MetaShapedTexture *stex, - CoglSnippet *snippet); -void meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, - int fallback_width, - int fallback_height); -cairo_region_t * meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex); -gboolean meta_shaped_texture_is_opaque (MetaShapedTexture *stex); -gboolean meta_shaped_texture_has_alpha (MetaShapedTexture *stex); -void meta_shaped_texture_set_transform (MetaShapedTexture *stex, - MetaMonitorTransform transform); -void meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex, - graphene_rect_t *src_rect); -void meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex); -void meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex, - int dst_width, - int dst_height); -void meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex); -void meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, - int buffer_scale); -int meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex); - -gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, - int x, - int y, - int width, - int height, - cairo_rectangle_int_t *clip); - -int meta_shaped_texture_get_width (MetaShapedTexture *stex); -int meta_shaped_texture_get_height (MetaShapedTexture *stex); - -void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex, - cairo_region_t *clip_region); -void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, - cairo_region_t *opaque_region); - -void meta_shaped_texture_ensure_size_valid (MetaShapedTexture *stex); - -#endif diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c deleted file mode 100644 index 6a8af828f..000000000 --- a/src/compositor/meta-shaped-texture.c +++ /dev/null @@ -1,1676 +0,0 @@ -/* - * Authored By Neil Roberts <neil@linux.intel.com> - * and Jasper St. Pierre <jstpierre@mecheye.net> - * - * Copyright (C) 2008 Intel Corporation - * Copyright (C) 2012 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -/** - * SECTION:meta-shaped-texture - * @title: MetaShapedTexture - * @short_description: A ClutterContent which draws a shaped texture - * - * A MetaShapedTexture draws a #CoglTexture (often provided from a client - * surface) in such a way that it matches any required transformations that - * give its final shape, such as a #MetaMonitorTransform, y-invertedness, or a - * crop-and-scale operation. - */ - -#include "config.h" - -#include "backends/meta-monitor-transform.h" -#include "compositor/meta-shaped-texture-private.h" -#include "core/boxes-private.h" - -#include <gdk/gdk.h> -#include <math.h> - -#include "cogl/cogl.h" -#include "compositor/clutter-utils.h" -#include "compositor/meta-texture-tower.h" -#include "compositor/region-utils.h" -#include "core/boxes-private.h" -#include "meta/meta-shaped-texture.h" - -/* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU - * performance, but higher than the refresh rate of commonly slow updating - * windows like top or a blinking cursor, so that such windows do get - * mipmapped. - */ -#define MAX_MIPMAPPING_FPS 5 -#define MIN_MIPMAP_AGE_USEC (G_USEC_PER_SEC / MAX_MIPMAPPING_FPS) - -/* MIN_FAST_UPDATES_BEFORE_UNMIPMAP allows windows to update themselves - * occasionally without causing mipmapping to be disabled, so long as such - * an update takes fewer update_area calls than: - */ -#define MIN_FAST_UPDATES_BEFORE_UNMIPMAP 20 - -static void meta_shaped_texture_dispose (GObject *object); - -static void clutter_content_iface_init (ClutterContentInterface *iface); - -enum -{ - SIZE_CHANGED, - - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL]; - -static CoglPipelineKey opaque_overlay_pipeline_key = - "meta-shaped-texture-opaque-pipeline-key"; -static CoglPipelineKey blended_overlay_pipeline_key = - "meta-shaped-texture-blended-pipeline-key"; - -struct _MetaShapedTexture -{ - GObject parent; - - MetaTextureTower *paint_tower; - - CoglTexture *texture; - CoglTexture *mask_texture; - CoglSnippet *snippet; - - CoglPipeline *base_pipeline; - CoglPipeline *masked_pipeline; - CoglPipeline *unblended_pipeline; - - gboolean is_y_inverted; - - /* The region containing only fully opaque pixels */ - cairo_region_t *opaque_region; - - /* MetaCullable regions, see that documentation for more details */ - cairo_region_t *clip_region; - - gboolean size_invalid; - MetaMonitorTransform transform; - gboolean has_viewport_src_rect; - graphene_rect_t viewport_src_rect; - gboolean has_viewport_dst_size; - int viewport_dst_width; - int viewport_dst_height; - - int tex_width, tex_height; - int fallback_width, fallback_height; - int dst_width, dst_height; - - gint64 prev_invalidation, last_invalidation; - guint fast_updates; - guint remipmap_timeout_id; - gint64 earliest_remipmap; - - int buffer_scale; - - guint create_mipmaps : 1; -}; - -G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, - clutter_content_iface_init)); - -static void -meta_shaped_texture_class_init (MetaShapedTextureClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - - gobject_class->dispose = meta_shaped_texture_dispose; - - signals[SIZE_CHANGED] = g_signal_new ("size-changed", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -static void -invalidate_size (MetaShapedTexture *stex) -{ - stex->size_invalid = TRUE; -} - -static void -meta_shaped_texture_init (MetaShapedTexture *stex) -{ - stex->paint_tower = meta_texture_tower_new (); - - stex->buffer_scale = 1; - stex->texture = NULL; - stex->mask_texture = NULL; - stex->create_mipmaps = TRUE; - stex->is_y_inverted = TRUE; - stex->transform = META_MONITOR_TRANSFORM_NORMAL; -} - -static void -update_size (MetaShapedTexture *stex) -{ - int buffer_scale = stex->buffer_scale; - int dst_width; - int dst_height; - - if (stex->has_viewport_dst_size) - { - dst_width = stex->viewport_dst_width; - dst_height = stex->viewport_dst_height; - } - else if (stex->has_viewport_src_rect) - { - dst_width = stex->viewport_src_rect.size.width; - dst_height = stex->viewport_src_rect.size.height; - } - else - { - if (meta_monitor_transform_is_rotated (stex->transform)) - { - if (stex->texture) - { - dst_width = stex->tex_height / buffer_scale; - dst_height = stex->tex_width / buffer_scale; - } - else - { - dst_width = stex->fallback_height / buffer_scale; - dst_height = stex->fallback_width / buffer_scale; - } - } - else - { - if (stex->texture) - { - dst_width = stex->tex_width / buffer_scale; - dst_height = stex->tex_height / buffer_scale; - } - else - { - dst_width = stex->fallback_width / buffer_scale; - dst_height = stex->fallback_height / buffer_scale; - } - } - } - - stex->size_invalid = FALSE; - - if (stex->dst_width != dst_width || - stex->dst_height != dst_height) - { - stex->dst_width = dst_width; - stex->dst_height = dst_height; - meta_shaped_texture_set_mask_texture (stex, NULL); - clutter_content_invalidate_size (CLUTTER_CONTENT (stex)); - g_signal_emit (stex, signals[SIZE_CHANGED], 0); - } -} - -void -meta_shaped_texture_ensure_size_valid (MetaShapedTexture *stex) -{ - if (stex->size_invalid) - update_size (stex); -} - -void -meta_shaped_texture_set_clip_region (MetaShapedTexture *stex, - cairo_region_t *clip_region) -{ - g_clear_pointer (&stex->clip_region, cairo_region_destroy); - if (clip_region) - stex->clip_region = cairo_region_reference (clip_region); -} - -static void -meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex) -{ - g_clear_pointer (&stex->base_pipeline, cogl_object_unref); - g_clear_pointer (&stex->masked_pipeline, cogl_object_unref); - g_clear_pointer (&stex->unblended_pipeline, cogl_object_unref); -} - -static void -meta_shaped_texture_dispose (GObject *object) -{ - MetaShapedTexture *stex = (MetaShapedTexture *) object; - - g_clear_handle_id (&stex->remipmap_timeout_id, g_source_remove); - - if (stex->paint_tower) - meta_texture_tower_free (stex->paint_tower); - stex->paint_tower = NULL; - - g_clear_pointer (&stex->texture, cogl_object_unref); - - meta_shaped_texture_set_mask_texture (stex, NULL); - meta_shaped_texture_reset_pipelines (stex); - - g_clear_pointer (&stex->opaque_region, cairo_region_destroy); - g_clear_pointer (&stex->clip_region, cairo_region_destroy); - - g_clear_pointer (&stex->snippet, cogl_object_unref); - - G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object); -} - -static CoglPipeline * -get_base_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) -{ - CoglPipeline *pipeline; - graphene_matrix_t matrix; - - if (stex->base_pipeline) - return stex->base_pipeline; - - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); - cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); - cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); - cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); - - graphene_matrix_init_identity (&matrix); - - if (stex->has_viewport_src_rect) - { - float scaled_tex_width = stex->tex_width / (float) stex->buffer_scale; - float scaled_tex_height = stex->tex_height / (float) stex->buffer_scale; - graphene_point3d_t p; - - graphene_point3d_init (&p, - stex->viewport_src_rect.origin.x / - stex->viewport_src_rect.size.width, - stex->viewport_src_rect.origin.y / - stex->viewport_src_rect.size.height, - 0); - graphene_matrix_translate (&matrix, &p); - - if (meta_monitor_transform_is_rotated (stex->transform)) - { - graphene_matrix_scale (&matrix, - stex->viewport_src_rect.size.width / - scaled_tex_height, - stex->viewport_src_rect.size.height / - scaled_tex_width, - 1); - } - else - { - graphene_matrix_scale (&matrix, - stex->viewport_src_rect.size.width / - scaled_tex_width, - stex->viewport_src_rect.size.height / - scaled_tex_height, - 1); - } - } - - if (stex->transform != META_MONITOR_TRANSFORM_NORMAL) - { - graphene_euler_t euler; - - graphene_matrix_translate (&matrix, - &GRAPHENE_POINT3D_INIT (-0.5, -0.5, 0.0)); - switch (stex->transform) - { - case META_MONITOR_TRANSFORM_90: - graphene_euler_init_with_order (&euler, 0.0, 0.0, 90.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_180: - graphene_euler_init_with_order (&euler, 0.0, 0.0, 180.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_270: - graphene_euler_init_with_order (&euler, 0.0, 0.0, 270.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_FLIPPED: - graphene_euler_init_with_order (&euler, 0.0, 180.0, 0.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_FLIPPED_90: - graphene_euler_init_with_order (&euler, 180.0, 0.0, 90.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_FLIPPED_180: - graphene_euler_init_with_order (&euler, 0.0, 180.0, 180.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_FLIPPED_270: - graphene_euler_init_with_order (&euler, 180.0, 0.0, 270.0, - GRAPHENE_EULER_ORDER_SYXZ); - break; - case META_MONITOR_TRANSFORM_NORMAL: - g_assert_not_reached (); - } - graphene_matrix_rotate_euler (&matrix, &euler); - graphene_matrix_translate (&matrix, - &GRAPHENE_POINT3D_INIT (0.5, 0.5, 0.0)); - } - - if (!stex->is_y_inverted) - { - graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT (0, -1, 0)); - graphene_matrix_scale (&matrix, 1, -1, 1); - cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); - } - - cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); - cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix); - - if (stex->snippet) - cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet); - - stex->base_pipeline = pipeline; - - return stex->base_pipeline; -} - -static CoglPipeline * -get_unmasked_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) -{ - return get_base_pipeline (stex, ctx); -} - -static CoglPipeline * -get_masked_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) -{ - CoglPipeline *pipeline; - - if (stex->masked_pipeline) - return stex->masked_pipeline; - - pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx)); - cogl_pipeline_set_layer_combine (pipeline, 1, - "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", - NULL); - - stex->masked_pipeline = pipeline; - - return pipeline; -} - -static CoglPipeline * -get_unblended_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) -{ - CoglPipeline *pipeline; - - if (stex->unblended_pipeline) - return stex->unblended_pipeline; - - pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx)); - cogl_pipeline_set_layer_combine (pipeline, 0, - "RGBA = REPLACE (TEXTURE)", - NULL); - - stex->unblended_pipeline = pipeline; - - return pipeline; -} - -static CoglPipeline * -get_opaque_overlay_pipeline (CoglContext *ctx) -{ - CoglPipeline *pipeline; - - pipeline = cogl_context_get_named_pipeline (ctx, - &opaque_overlay_pipeline_key); - if (!pipeline) - { - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_color4ub (pipeline, 0x00, 0x33, 0x00, 0x33); - - cogl_context_set_named_pipeline (ctx, - &opaque_overlay_pipeline_key, - pipeline); - } - - return pipeline; -} - -static CoglPipeline * -get_blended_overlay_pipeline (CoglContext *ctx) -{ - CoglPipeline *pipeline; - - pipeline = cogl_context_get_named_pipeline (ctx, - &blended_overlay_pipeline_key); - if (!pipeline) - { - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_color4ub (pipeline, 0x33, 0x00, 0x33, 0x33); - - cogl_context_set_named_pipeline (ctx, - &blended_overlay_pipeline_key, - pipeline); - } - - return pipeline; -} - -static void -paint_clipped_rectangle_node (MetaShapedTexture *stex, - ClutterPaintNode *root_node, - CoglPipeline *pipeline, - cairo_rectangle_int_t *rect, - ClutterActorBox *alloc) -{ - g_autoptr (ClutterPaintNode) node = NULL; - float ratio_h, ratio_v; - float x1, y1, x2, y2; - float coords[8]; - float alloc_width; - float alloc_height; - - ratio_h = clutter_actor_box_get_width (alloc) / (float) stex->dst_width; - ratio_v = clutter_actor_box_get_height (alloc) / (float) stex->dst_height; - - x1 = alloc->x1 + rect->x * ratio_h; - y1 = alloc->y1 + rect->y * ratio_v; - x2 = alloc->x1 + (rect->x + rect->width) * ratio_h; - y2 = alloc->y1 + (rect->y + rect->height) * ratio_v; - - alloc_width = alloc->x2 - alloc->x1; - alloc_height = alloc->y2 - alloc->y1; - - coords[0] = rect->x / alloc_width * ratio_h; - coords[1] = rect->y / alloc_height * ratio_v; - coords[2] = (rect->x + rect->width) / alloc_width * ratio_h; - coords[3] = (rect->y + rect->height) / alloc_height * ratio_v; - - coords[4] = coords[0]; - coords[5] = coords[1]; - coords[6] = coords[2]; - coords[7] = coords[3]; - - node = clutter_pipeline_node_new (pipeline); - clutter_paint_node_set_static_name (node, "MetaShapedTexture (clipped)"); - clutter_paint_node_add_child (root_node, node); - - clutter_paint_node_add_multitexture_rectangle (node, - &(ClutterActorBox) { - .x1 = x1, - .y1 = y1, - .x2 = x2, - .y2 = y2, - }, - coords, 8); -} - -static void -set_cogl_texture (MetaShapedTexture *stex, - CoglTexture *cogl_tex) -{ - int width, height; - - cogl_clear_object (&stex->texture); - - if (cogl_tex != NULL) - { - stex->texture = cogl_object_ref (cogl_tex); - width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); - height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); - } - else - { - width = 0; - height = 0; - } - - if (stex->tex_width != width || - stex->tex_height != height) - { - stex->tex_width = width; - stex->tex_height = height; - update_size (stex); - } - - /* NB: We don't queue a redraw of the actor here because we don't - * know how much of the buffer has changed with respect to the - * previous buffer. We only queue a redraw in response to surface - * damage. */ - - if (stex->create_mipmaps) - meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex); -} - -static gboolean -texture_is_idle_and_not_mipmapped (gpointer user_data) -{ - MetaShapedTexture *stex = META_SHAPED_TEXTURE (user_data); - - if ((g_get_monotonic_time () - stex->earliest_remipmap) < 0) - return G_SOURCE_CONTINUE; - - clutter_content_invalidate (CLUTTER_CONTENT (stex)); - stex->remipmap_timeout_id = 0; - - return G_SOURCE_REMOVE; -} - -static inline void -flip_ints (int *x, - int *y) -{ - int tmp; - - tmp = *x; - *x = *y; - *y = tmp; -} - -static void -do_paint_content (MetaShapedTexture *stex, - ClutterPaintNode *root_node, - ClutterPaintContext *paint_context, - CoglTexture *paint_tex, - ClutterActorBox *alloc, - uint8_t opacity) -{ - int dst_width, dst_height; - cairo_rectangle_int_t content_rect; - gboolean use_opaque_region; - cairo_region_t *blended_tex_region; - CoglContext *ctx; - CoglPipelineFilter filter; - CoglFramebuffer *framebuffer; - int sample_width, sample_height; - gboolean debug_paint_opaque_region; - - meta_shaped_texture_ensure_size_valid (stex); - - dst_width = stex->dst_width; - dst_height = stex->dst_height; - - if (dst_width == 0 || dst_height == 0) /* no contents yet */ - return; - - content_rect = (cairo_rectangle_int_t) { - .x = 0, - .y = 0, - .width = dst_width, - .height = dst_height, - }; - - debug_paint_opaque_region = - meta_get_debug_paint_flags() & META_DEBUG_PAINT_OPAQUE_REGION; - - /* Use nearest-pixel interpolation if the texture is unscaled. This - * improves performance, especially with software rendering. - */ - - framebuffer = clutter_paint_node_get_framebuffer (root_node); - if (!framebuffer) - framebuffer = clutter_paint_context_get_framebuffer (paint_context); - - if (stex->has_viewport_src_rect) - { - sample_width = stex->viewport_src_rect.size.width * stex->buffer_scale; - sample_height = stex->viewport_src_rect.size.height * stex->buffer_scale; - } - else - { - sample_width = cogl_texture_get_width (stex->texture); - sample_height = cogl_texture_get_height (stex->texture); - } - if (meta_monitor_transform_is_rotated (stex->transform)) - flip_ints (&sample_width, &sample_height); - - if (meta_actor_painting_untransformed (framebuffer, - dst_width, dst_height, - sample_width, sample_height, - NULL, NULL)) - filter = COGL_PIPELINE_FILTER_NEAREST; - else - filter = COGL_PIPELINE_FILTER_LINEAR; - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - - use_opaque_region = stex->opaque_region && opacity == 255; - - if (use_opaque_region) - { - if (stex->clip_region) - blended_tex_region = cairo_region_copy (stex->clip_region); - else - blended_tex_region = cairo_region_create_rectangle (&content_rect); - - cairo_region_subtract (blended_tex_region, stex->opaque_region); - } - else - { - if (stex->clip_region) - blended_tex_region = cairo_region_reference (stex->clip_region); - else - blended_tex_region = NULL; - } - - /* Limit to how many separate rectangles we'll draw; beyond this just - * fall back and draw the whole thing */ -#define MAX_RECTS 16 - - if (blended_tex_region) - { - int n_rects = cairo_region_num_rectangles (blended_tex_region); - if (n_rects > MAX_RECTS) - { - /* Fall back to taking the fully blended path. */ - use_opaque_region = FALSE; - - g_clear_pointer (&blended_tex_region, cairo_region_destroy); - } - } - - /* First, paint the unblended parts, which are part of the opaque region. */ - if (use_opaque_region) - { - cairo_region_t *region; - int n_rects; - int i; - - if (stex->clip_region) - { - region = cairo_region_copy (stex->clip_region); - cairo_region_intersect (region, stex->opaque_region); - } - else - { - region = cairo_region_reference (stex->opaque_region); - } - - if (!cairo_region_is_empty (region)) - { - CoglPipeline *opaque_pipeline; - - opaque_pipeline = get_unblended_pipeline (stex, ctx); - cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); - cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); - - n_rects = cairo_region_num_rectangles (region); - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - paint_clipped_rectangle_node (stex, root_node, - opaque_pipeline, - &rect, alloc); - - if (G_UNLIKELY (debug_paint_opaque_region)) - { - CoglPipeline *opaque_overlay_pipeline; - - opaque_overlay_pipeline = get_opaque_overlay_pipeline (ctx); - paint_clipped_rectangle_node (stex, root_node, - opaque_overlay_pipeline, - &rect, alloc); - } - } - } - - cairo_region_destroy (region); - } - - /* Now, go ahead and paint the blended parts. */ - - /* We have three cases: - * 1) blended_tex_region has rectangles - paint the rectangles. - * 2) blended_tex_region is empty - don't paint anything - * 3) blended_tex_region is NULL - paint fully-blended. - * - * 1) and 3) are the times where we have to paint stuff. This tests - * for 1) and 3). - */ - if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region)) - { - CoglPipeline *blended_pipeline; - - if (stex->mask_texture == NULL) - { - blended_pipeline = get_unmasked_pipeline (stex, ctx); - } - else - { - blended_pipeline = get_masked_pipeline (stex, ctx); - cogl_pipeline_set_layer_texture (blended_pipeline, 1, stex->mask_texture); - cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter); - } - - cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex); - cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter); - - CoglColor color; - cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); - cogl_pipeline_set_color (blended_pipeline, &color); - - if (blended_tex_region) - { - /* 1) blended_tex_region is not empty. Paint the rectangles. */ - int i; - int n_rects = cairo_region_num_rectangles (blended_tex_region); - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (blended_tex_region, i, &rect); - - if (!gdk_rectangle_intersect (&content_rect, &rect, &rect)) - continue; - - paint_clipped_rectangle_node (stex, root_node, - blended_pipeline, - &rect, alloc); - - if (G_UNLIKELY (debug_paint_opaque_region)) - { - CoglPipeline *blended_overlay_pipeline; - - blended_overlay_pipeline = get_blended_overlay_pipeline (ctx); - paint_clipped_rectangle_node (stex, root_node, - blended_overlay_pipeline, - &rect, alloc); - } - } - } - else - { - g_autoptr (ClutterPaintNode) node = NULL; - - node = clutter_pipeline_node_new (blended_pipeline); - clutter_paint_node_set_static_name (node, "MetaShapedTexture (unclipped)"); - clutter_paint_node_add_child (root_node, node); - - /* 3) blended_tex_region is NULL. Do a full paint. */ - clutter_paint_node_add_rectangle (node, alloc); - - if (G_UNLIKELY (debug_paint_opaque_region)) - { - CoglPipeline *blended_overlay_pipeline; - g_autoptr (ClutterPaintNode) node_overlay = NULL; - - blended_overlay_pipeline = get_blended_overlay_pipeline (ctx); - - node_overlay = clutter_pipeline_node_new (blended_overlay_pipeline); - clutter_paint_node_set_static_name (node_overlay, - "MetaShapedTexture (unclipped overlay)"); - clutter_paint_node_add_child (root_node, node_overlay); - clutter_paint_node_add_rectangle (node_overlay, alloc); - } - } - } - - g_clear_pointer (&blended_tex_region, cairo_region_destroy); -} - -static CoglTexture * -select_texture_for_paint (MetaShapedTexture *stex, - ClutterPaintContext *paint_context) -{ - CoglTexture *texture = NULL; - int64_t now; - - if (!stex->texture) - return NULL; - - now = g_get_monotonic_time (); - - if (stex->create_mipmaps && stex->last_invalidation) - { - int64_t age = now - stex->last_invalidation; - - if (age >= MIN_MIPMAP_AGE_USEC || - stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) - { - texture = meta_texture_tower_get_paint_texture (stex->paint_tower, - paint_context); - } - } - - if (!texture) - { - texture = stex->texture; - - if (stex->create_mipmaps) - { - /* Minus 1000 to ensure we don't fail the age test in timeout */ - stex->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000; - - if (!stex->remipmap_timeout_id) - stex->remipmap_timeout_id = - g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000, - texture_is_idle_and_not_mipmapped, - stex); - } - } - - return texture; -} - -static void -meta_shaped_texture_paint_content (ClutterContent *content, - ClutterActor *actor, - ClutterPaintNode *root_node, - ClutterPaintContext *paint_context) -{ - MetaShapedTexture *stex = META_SHAPED_TEXTURE (content); - ClutterActorBox alloc; - CoglTexture *paint_tex = NULL; - uint8_t opacity; - - if (stex->clip_region && cairo_region_is_empty (stex->clip_region)) - return; - - /* The GL EXT_texture_from_pixmap extension does allow for it to be - * used together with SGIS_generate_mipmap, however this is very - * rarely supported. Also, even when it is supported there - * are distinct performance implications from: - * - * - Updating mipmaps that we don't need - * - Having to reallocate pixmaps on the server into larger buffers - * - * So, we just unconditionally use our mipmap emulation code. If we - * wanted to use SGIS_generate_mipmap, we'd have to query COGL to - * see if it was supported (no API currently), and then if and only - * if that was the case, set the clutter texture quality to HIGH. - * Setting the texture quality to high without SGIS_generate_mipmap - * support for TFP textures will result in fallbacks to XGetImage. - */ - paint_tex = select_texture_for_paint (stex, paint_context); - if (!paint_tex) - return; - - opacity = clutter_actor_get_paint_opacity (actor); - clutter_actor_get_content_box (actor, &alloc); - - do_paint_content (stex, root_node, paint_context, paint_tex, &alloc, opacity); -} - -static gboolean -meta_shaped_texture_get_preferred_size (ClutterContent *content, - float *width, - float *height) -{ - MetaShapedTexture *stex = META_SHAPED_TEXTURE (content); - - meta_shaped_texture_ensure_size_valid (stex); - - if (width) - *width = stex->dst_width; - - if (height) - *height = stex->dst_height; - - return TRUE; -} - -static void -clutter_content_iface_init (ClutterContentInterface *iface) -{ - iface->paint_content = meta_shaped_texture_paint_content; - iface->get_preferred_size = meta_shaped_texture_get_preferred_size; -} - -void -meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, - gboolean create_mipmaps) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - create_mipmaps = create_mipmaps != FALSE; - - if (create_mipmaps != stex->create_mipmaps) - { - CoglTexture *base_texture; - stex->create_mipmaps = create_mipmaps; - base_texture = create_mipmaps ? stex->texture : NULL; - meta_texture_tower_set_base_texture (stex->paint_tower, base_texture); - } -} - -void -meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, - CoglTexture *mask_texture) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - g_clear_pointer (&stex->mask_texture, cogl_object_unref); - - if (mask_texture != NULL) - { - stex->mask_texture = mask_texture; - cogl_object_ref (stex->mask_texture); - } - - clutter_content_invalidate (CLUTTER_CONTENT (stex)); -} - -/** - * meta_shaped_texture_update_area: - * @stex: #MetaShapedTexture - * @x: the x coordinate of the damaged area - * @y: the y coordinate of the damaged area - * @width: the width of the damaged area - * @height: the height of the damaged area - * @clip: (out): the resulting clip region - * - * Repairs the damaged area indicated by @x, @y, @width and @height - * and potentially queues a redraw. - * - * Return value: Whether a redraw have been queued or not - */ -gboolean -meta_shaped_texture_update_area (MetaShapedTexture *stex, - int x, - int y, - int width, - int height, - cairo_rectangle_int_t *clip) -{ - MetaMonitorTransform inverted_transform; - int scaled_and_transformed_width; - int scaled_and_transformed_height; - - if (stex->texture == NULL) - return FALSE; - - *clip = (cairo_rectangle_int_t) { - .x = x, - .y = y, - .width = width, - .height = height - }; - - meta_rectangle_scale_double (clip, - 1.0 / stex->buffer_scale, - META_ROUNDING_STRATEGY_GROW, - clip); - - if (meta_monitor_transform_is_rotated (stex->transform)) - { - scaled_and_transformed_width = stex->tex_height / stex->buffer_scale; - scaled_and_transformed_height = stex->tex_width / stex->buffer_scale; - } - else - { - scaled_and_transformed_width = stex->tex_width / stex->buffer_scale; - scaled_and_transformed_height = stex->tex_height / stex->buffer_scale; - } - inverted_transform = meta_monitor_transform_invert (stex->transform); - meta_rectangle_transform (clip, - inverted_transform, - scaled_and_transformed_width, - scaled_and_transformed_height, - clip); - - if (stex->has_viewport_src_rect || stex->has_viewport_dst_size) - { - graphene_rect_t viewport; - graphene_rect_t inverted_viewport; - float dst_width; - float dst_height; - int inverted_dst_width; - int inverted_dst_height; - - if (stex->has_viewport_src_rect) - { - viewport = stex->viewport_src_rect; - } - else - { - viewport = (graphene_rect_t) { - .origin.x = 0, - .origin.y = 0, - .size.width = scaled_and_transformed_width, - .size.height = scaled_and_transformed_height, - }; - } - - if (stex->has_viewport_dst_size) - { - dst_width = (float) stex->viewport_dst_width; - dst_height = (float) stex->viewport_dst_height; - } - else - { - dst_width = (float) viewport.size.width; - dst_height = (float) viewport.size.height; - } - - inverted_viewport = (graphene_rect_t) { - .origin.x = -(viewport.origin.x * (dst_width / viewport.size.width)), - .origin.y = -(viewport.origin.y * (dst_height / viewport.size.height)), - .size.width = dst_width, - .size.height = dst_height - }; - inverted_dst_width = ceilf (viewport.size.width); - inverted_dst_height = ceilf (viewport.size.height); - - meta_rectangle_crop_and_scale (clip, - &inverted_viewport, - inverted_dst_width, - inverted_dst_height, - clip); - } - - meta_texture_tower_update_area (stex->paint_tower, - x, - y, - width, - height); - - stex->prev_invalidation = stex->last_invalidation; - stex->last_invalidation = g_get_monotonic_time (); - - if (stex->prev_invalidation) - { - gint64 interval = stex->last_invalidation - stex->prev_invalidation; - gboolean fast_update = interval < MIN_MIPMAP_AGE_USEC; - - if (!fast_update) - stex->fast_updates = 0; - else if (stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) - stex->fast_updates++; - } - - return TRUE; -} - -/** - * meta_shaped_texture_set_texture: - * @stex: The #MetaShapedTexture - * @pixmap: The #CoglTexture to display - */ -void -meta_shaped_texture_set_texture (MetaShapedTexture *stex, - CoglTexture *texture) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - if (stex->texture == texture) - return; - - set_cogl_texture (stex, texture); -} - -/** - * meta_shaped_texture_set_is_y_inverted: (skip) - */ -void -meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex, - gboolean is_y_inverted) -{ - if (stex->is_y_inverted == is_y_inverted) - return; - - meta_shaped_texture_reset_pipelines (stex); - - stex->is_y_inverted = is_y_inverted; -} - -/** - * meta_shaped_texture_set_snippet: (skip) - */ -void -meta_shaped_texture_set_snippet (MetaShapedTexture *stex, - CoglSnippet *snippet) -{ - if (stex->snippet == snippet) - return; - - meta_shaped_texture_reset_pipelines (stex); - - g_clear_pointer (&stex->snippet, cogl_object_unref); - if (snippet) - stex->snippet = cogl_object_ref (snippet); -} - -/** - * meta_shaped_texture_get_texture: - * @stex: The #MetaShapedTexture - * - * Returns: (transfer none): the unshaped texture - */ -CoglTexture * -meta_shaped_texture_get_texture (MetaShapedTexture *stex) -{ - g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); - return COGL_TEXTURE (stex->texture); -} - -/** - * meta_shaped_texture_set_opaque_region: - * @stex: a #MetaShapedTexture - * @opaque_region: (transfer full): the region of the texture that - * can have blending turned off. - * - * As most windows have a large portion that does not require blending, - * we can easily turn off blending if we know the areas that do not - * require blending. This sets the region where we will not blend for - * optimization purposes. - */ -void -meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, - cairo_region_t *opaque_region) -{ - g_clear_pointer (&stex->opaque_region, cairo_region_destroy); - if (opaque_region) - stex->opaque_region = cairo_region_reference (opaque_region); -} - -cairo_region_t * -meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex) -{ - return stex->opaque_region; -} - -gboolean -meta_shaped_texture_has_alpha (MetaShapedTexture *stex) -{ - CoglTexture *texture; - - texture = stex->texture; - if (!texture) - return TRUE; - - switch (cogl_texture_get_components (texture)) - { - case COGL_TEXTURE_COMPONENTS_A: - case COGL_TEXTURE_COMPONENTS_RGBA: - return TRUE; - case COGL_TEXTURE_COMPONENTS_RG: - case COGL_TEXTURE_COMPONENTS_RGB: - case COGL_TEXTURE_COMPONENTS_DEPTH: - return FALSE; - } - - g_warn_if_reached (); - return FALSE; -} - -gboolean -meta_shaped_texture_is_opaque (MetaShapedTexture *stex) -{ - CoglTexture *texture; - cairo_rectangle_int_t opaque_rect; - - texture = stex->texture; - if (!texture) - return FALSE; - - if (!meta_shaped_texture_has_alpha (stex)) - return TRUE; - - if (!stex->opaque_region) - return FALSE; - - if (cairo_region_num_rectangles (stex->opaque_region) != 1) - return FALSE; - - cairo_region_get_extents (stex->opaque_region, &opaque_rect); - - meta_shaped_texture_ensure_size_valid (stex); - - return meta_rectangle_equal (&opaque_rect, - &(MetaRectangle) { - .width = stex->dst_width, - .height = stex->dst_height - }); -} - -void -meta_shaped_texture_set_transform (MetaShapedTexture *stex, - MetaMonitorTransform transform) -{ - if (stex->transform == transform) - return; - - stex->transform = transform; - - meta_shaped_texture_reset_pipelines (stex); - invalidate_size (stex); -} - -/** - * meta_shaped_texture_set_viewport_src_rect: - * @stex: A #MetaShapedTexture - * @src_rect: The viewport source rectangle - * - * Sets the viewport area that can be used to crop the original texture. The - * cropped result can then be optionally scaled afterwards using - * meta_shaped_texture_set_viewport_dst_size() as part of a crop-and-scale - * operation. - * - * Note that the viewport's geometry should be provided in the coordinate space - * of the texture received by the client, which might've been scaled as noted by - * meta_shaped_texture_set_buffer_scale(). - * - * %NULL is an invalid value for @src_rect. Use - * meta_shaped_texture_reset_viewport_src_rect() if you want to remove the - * cropping source rectangle. - */ -void -meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex, - graphene_rect_t *src_rect) -{ - if (!stex->has_viewport_src_rect || - !G_APPROX_VALUE (stex->viewport_src_rect.origin.x, - src_rect->origin.x, FLT_EPSILON) || - !G_APPROX_VALUE (stex->viewport_src_rect.origin.y, - src_rect->origin.y, FLT_EPSILON) || - !G_APPROX_VALUE (stex->viewport_src_rect.size.width, - src_rect->size.width, FLT_EPSILON) || - !G_APPROX_VALUE (stex->viewport_src_rect.size.height, - src_rect->size.height, FLT_EPSILON)) - { - stex->has_viewport_src_rect = TRUE; - stex->viewport_src_rect = *src_rect; - meta_shaped_texture_reset_pipelines (stex); - invalidate_size (stex); - } -} - -void -meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex) -{ - if (!stex->has_viewport_src_rect) - return; - - stex->has_viewport_src_rect = FALSE; - meta_shaped_texture_reset_pipelines (stex); - invalidate_size (stex); -} - -/** - * meta_shaped_texture_set_viewport_dst_size: - * @stex: #MetaShapedTexture - * @dst_width: The final viewport width (> 0) - * @dst_height: The final viewport height (> 0) - * - * Sets a viewport size on @stex of the given @width and @height, which may - * lead to scaling the texture. If you need to have cropping, use - * meta_shaped_texture_set_viewport_src_rect() first, after which the scaling - * stemming from this method will be applied. - * - * If you no longer want to have any scaling, use - * meta_shaped_texture_reset_viewport_dst_size() to clear the current - * parameters. - */ -void -meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex, - int dst_width, - int dst_height) -{ - if (!stex->has_viewport_dst_size || - stex->viewport_dst_width != dst_width || - stex->viewport_dst_height != dst_height) - { - stex->has_viewport_dst_size = TRUE; - stex->viewport_dst_width = dst_width; - stex->viewport_dst_height = dst_height; - invalidate_size (stex); - } -} - -void -meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex) -{ - if (!stex->has_viewport_dst_size) - return; - - stex->has_viewport_dst_size = FALSE; - invalidate_size (stex); -} - -static gboolean -should_get_via_offscreen (MetaShapedTexture *stex) -{ - if (!cogl_texture_is_get_data_supported (stex->texture)) - return TRUE; - - if (stex->has_viewport_src_rect || stex->has_viewport_dst_size) - return TRUE; - - switch (stex->transform) - { - case META_MONITOR_TRANSFORM_90: - case META_MONITOR_TRANSFORM_180: - case META_MONITOR_TRANSFORM_270: - case META_MONITOR_TRANSFORM_FLIPPED: - case META_MONITOR_TRANSFORM_FLIPPED_90: - case META_MONITOR_TRANSFORM_FLIPPED_180: - case META_MONITOR_TRANSFORM_FLIPPED_270: - return TRUE; - case META_MONITOR_TRANSFORM_NORMAL: - break; - } - - return FALSE; -} - -static cairo_surface_t * -get_image_via_offscreen (MetaShapedTexture *stex, - cairo_rectangle_int_t *clip, - int image_width, - int image_height) -{ - g_autoptr (ClutterPaintNode) root_node = NULL; - ClutterBackend *clutter_backend = clutter_get_default_backend (); - CoglContext *cogl_context = - clutter_backend_get_cogl_context (clutter_backend); - CoglTexture *image_texture; - GError *error = NULL; - CoglOffscreen *offscreen; - CoglFramebuffer *fb; - graphene_matrix_t projection_matrix; - cairo_rectangle_int_t fallback_clip; - ClutterColor clear_color; - ClutterPaintContext *paint_context; - cairo_surface_t *surface; - - if (!clip) - { - fallback_clip = (cairo_rectangle_int_t) { - .width = image_width, - .height = image_height, - }; - clip = &fallback_clip; - } - - image_texture = - COGL_TEXTURE (cogl_texture_2d_new_with_size (cogl_context, - image_width, - image_height)); - cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (image_texture), - FALSE); - if (!cogl_texture_allocate (COGL_TEXTURE (image_texture), &error)) - { - g_error_free (error); - cogl_object_unref (image_texture); - return FALSE; - } - - offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (image_texture)); - fb = COGL_FRAMEBUFFER (offscreen); - cogl_object_unref (image_texture); - if (!cogl_framebuffer_allocate (fb, &error)) - { - g_error_free (error); - g_object_unref (fb); - return FALSE; - } - - cogl_framebuffer_push_matrix (fb); - graphene_matrix_init_translate (&projection_matrix, - &GRAPHENE_POINT3D_INIT (-(image_width / 2.0), - -(image_height / 2.0), - 0)); - graphene_matrix_scale (&projection_matrix, - 1.0 / (image_width / 2.0), - -1.0 / (image_height / 2.0), 0); - - cogl_framebuffer_set_projection_matrix (fb, &projection_matrix); - - clear_color = (ClutterColor) { 0, 0, 0, 0 }; - - root_node = clutter_root_node_new (fb, &clear_color, COGL_BUFFER_BIT_COLOR); - clutter_paint_node_set_static_name (root_node, "MetaShapedTexture.offscreen"); - - paint_context = - clutter_paint_context_new_for_framebuffer (fb, NULL, - CLUTTER_PAINT_FLAG_NONE); - - do_paint_content (stex, root_node, paint_context, - stex->texture, - &(ClutterActorBox) { - 0, 0, - image_width, - image_height, - }, - 255); - - clutter_paint_node_paint (root_node, paint_context); - clutter_paint_context_destroy (paint_context); - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - clip->width, clip->height); - cogl_framebuffer_read_pixels (fb, - clip->x, clip->y, - clip->width, clip->height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_data (surface)); - g_object_unref (fb); - - cairo_surface_mark_dirty (surface); - - return surface; -} - -/** - * meta_shaped_texture_get_image: - * @stex: A #MetaShapedTexture - * @clip: (nullable): A clipping rectangle, to help prevent extra processing. - * In the case that the clipping rectangle is partially or fully - * outside the bounds of the texture, the rectangle will be clipped. - * - * Flattens the two layers of the shaped texture into one ARGB32 - * image by alpha blending the two images, and returns the flattened - * image. - * - * Returns: (nullable) (transfer full): a new cairo surface to be freed with - * cairo_surface_destroy(). - */ -cairo_surface_t * -meta_shaped_texture_get_image (MetaShapedTexture *stex, - cairo_rectangle_int_t *clip) -{ - cairo_rectangle_int_t *image_clip = NULL; - CoglTexture *texture, *mask_texture; - cairo_surface_t *surface; - - g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); - - texture = COGL_TEXTURE (stex->texture); - - if (texture == NULL) - return NULL; - - meta_shaped_texture_ensure_size_valid (stex); - - if (stex->dst_width == 0 || stex->dst_height == 0) - return NULL; - - if (clip != NULL) - { - cairo_rectangle_int_t dst_rect; - - image_clip = alloca (sizeof (cairo_rectangle_int_t)); - dst_rect = (cairo_rectangle_int_t) { - .width = stex->dst_width, - .height = stex->dst_height, - }; - - if (!meta_rectangle_intersect (&dst_rect, clip, - image_clip)) - return NULL; - - *image_clip = (MetaRectangle) { - .x = image_clip->x * stex->buffer_scale, - .y = image_clip->y * stex->buffer_scale, - .width = image_clip->width * stex->buffer_scale, - .height = image_clip->height * stex->buffer_scale, - }; - } - - if (should_get_via_offscreen (stex)) - { - int image_width; - int image_height; - - image_width = stex->dst_width * stex->buffer_scale; - image_height = stex->dst_height * stex->buffer_scale; - return get_image_via_offscreen (stex, - image_clip, - image_width, - image_height); - } - - if (image_clip) - texture = cogl_texture_new_from_sub_texture (texture, - image_clip->x, - image_clip->y, - image_clip->width, - image_clip->height); - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - cogl_texture_get_width (texture), - cogl_texture_get_height (texture)); - - cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_stride (surface), - cairo_image_surface_get_data (surface)); - - cairo_surface_mark_dirty (surface); - - if (image_clip) - cogl_object_unref (texture); - - mask_texture = stex->mask_texture; - if (mask_texture != NULL) - { - cairo_t *cr; - cairo_surface_t *mask_surface; - - if (image_clip) - mask_texture = - cogl_texture_new_from_sub_texture (mask_texture, - image_clip->x, - image_clip->y, - image_clip->width, - image_clip->height); - - mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, - cogl_texture_get_width (mask_texture), - cogl_texture_get_height (mask_texture)); - - cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8, - cairo_image_surface_get_stride (mask_surface), - cairo_image_surface_get_data (mask_surface)); - - cairo_surface_mark_dirty (mask_surface); - - cr = cairo_create (surface); - cairo_set_source_surface (cr, mask_surface, 0, 0); - cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); - cairo_paint (cr); - cairo_destroy (cr); - - cairo_surface_destroy (mask_surface); - - if (image_clip) - cogl_object_unref (mask_texture); - } - - return surface; -} - -void -meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, - int fallback_width, - int fallback_height) -{ - stex->fallback_width = fallback_width; - stex->fallback_height = fallback_height; - - invalidate_size (stex); -} - -MetaShapedTexture * -meta_shaped_texture_new (void) -{ - return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); -} - -/** - * meta_shaped_texture_set_buffer_scale: - * @stex: A #MetaShapedTexture - * @buffer_scale: The scale that should be applied to coorsinate space - * - * Instructs @stex to interpret the geometry of the input texture by scaling it - * with @buffer_scale. This means that the #CoglTexture that is provided by a - * client is already scaled by that factor. - */ -void -meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, - int buffer_scale) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - if (buffer_scale == stex->buffer_scale) - return; - - stex->buffer_scale = buffer_scale; - - invalidate_size (stex); -} - -int -meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex) -{ - g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 1.0); - - return stex->buffer_scale; -} - -/** - * meta_shaped_texture_get_width: - * @stex: A #MetaShapedTexture - * - * Returns: The final width of @stex after its shaping operations are applied. - */ -int -meta_shaped_texture_get_width (MetaShapedTexture *stex) -{ - g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0); - - meta_shaped_texture_ensure_size_valid (stex); - - return stex->dst_width; -} - -/** - * meta_shaped_texture_get_height: - * @stex: A #MetaShapedTexture - * - * Returns: The final height of @stex after its shaping operations are applied. - */ -int -meta_shaped_texture_get_height (MetaShapedTexture *stex) -{ - g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0); - - meta_shaped_texture_ensure_size_valid (stex); - - return stex->dst_height; -} diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c deleted file mode 100644 index a182ad851..000000000 --- a/src/compositor/meta-surface-actor-wayland.c +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2013 Red Hat - * - * 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: - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#include "config.h" - -#include "compositor/meta-surface-actor-wayland.h" - -#include <math.h> - -#include "backends/meta-backend-private.h" -#include "backends/meta-logical-monitor.h" -#include "cogl/cogl-wayland-server.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/region-utils.h" -#include "wayland/meta-wayland-buffer.h" -#include "wayland/meta-wayland-private.h" -#include "wayland/meta-window-wayland.h" - -struct _MetaSurfaceActorWayland -{ - MetaSurfaceActor parent; - - MetaWaylandSurface *surface; -}; - -G_DEFINE_TYPE (MetaSurfaceActorWayland, - meta_surface_actor_wayland, - META_TYPE_SURFACE_ACTOR) - -static void -meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor, - int x, - int y, - int width, - int height) -{ - meta_surface_actor_update_area (actor, x, y, width, height); -} - -static gboolean -meta_surface_actor_wayland_is_opaque (MetaSurfaceActor *actor) -{ - MetaShapedTexture *stex = meta_surface_actor_get_texture (actor); - - return meta_shaped_texture_is_opaque (stex); -} - -CoglScanout * -meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, - CoglOnscreen *onscreen) -{ - MetaWaylandSurface *surface; - CoglScanout *scanout; - - surface = meta_surface_actor_wayland_get_surface (self); - if (!surface) - return NULL; - - scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen); - if (!scanout) - return NULL; - - return scanout; -} - -#define UNOBSCURED_TRESHOLD 0.1 - -ClutterStageView * -meta_surface_actor_wayland_get_current_primary_view (MetaSurfaceActor *actor, - ClutterStage *stage) -{ - ClutterStageView *current_primary_view = NULL; - float highest_refresh_rate = 0.f; - float biggest_unobscurred_fraction = 0.f; - GList *l; - - for (l = clutter_stage_peek_stage_views (stage); l; l = l->next) - { - ClutterStageView *stage_view = l->data; - float refresh_rate; - float unobscurred_fraction = 1.f; - - if (clutter_actor_has_mapped_clones (CLUTTER_ACTOR (actor))) - { - if (!clutter_actor_is_effectively_on_stage_view (CLUTTER_ACTOR (actor), - stage_view)) - continue; - } - else - { - if (l->next || biggest_unobscurred_fraction > 0.f) - { - if (meta_surface_actor_is_obscured_on_stage_view (actor, - stage_view, - &unobscurred_fraction)) - continue; - } - else - { - if (meta_surface_actor_is_obscured (actor)) - continue; - } - } - - refresh_rate = clutter_stage_view_get_refresh_rate (stage_view); - - if ((refresh_rate > highest_refresh_rate && - (unobscurred_fraction > UNOBSCURED_TRESHOLD || - biggest_unobscurred_fraction < UNOBSCURED_TRESHOLD)) || - (biggest_unobscurred_fraction < UNOBSCURED_TRESHOLD && - unobscurred_fraction > UNOBSCURED_TRESHOLD)) - { - current_primary_view = stage_view; - highest_refresh_rate = refresh_rate; - biggest_unobscurred_fraction = unobscurred_fraction; - } - } - - return current_primary_view; -} - -static void -meta_surface_actor_wayland_dispose (GObject *object) -{ - MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object); - MetaShapedTexture *stex; - - stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - if (stex) - meta_shaped_texture_set_texture (stex, NULL); - - if (self->surface) - { - g_object_remove_weak_pointer (G_OBJECT (self->surface), - (gpointer *) &self->surface); - self->surface = NULL; - } - - G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object); -} - -static void -meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) -{ - MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; - surface_actor_class->is_opaque = meta_surface_actor_wayland_is_opaque; - - object_class->dispose = meta_surface_actor_wayland_dispose; -} - -static void -meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self) -{ -} - -MetaSurfaceActor * -meta_surface_actor_wayland_new (MetaWaylandSurface *surface) -{ - MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL); - - g_assert (meta_is_wayland_compositor ()); - - self->surface = surface; - g_object_add_weak_pointer (G_OBJECT (self->surface), - (gpointer *) &self->surface); - - return META_SURFACE_ACTOR (self); -} - -MetaWaylandSurface * -meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self) -{ - return self->surface; -} diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h deleted file mode 100644 index 10eb3326a..000000000 --- a/src/compositor/meta-surface-actor-wayland.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2013 Red Hat - * - * 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: - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#ifndef __META_SURFACE_ACTOR_WAYLAND_H__ -#define __META_SURFACE_ACTOR_WAYLAND_H__ - -#include <glib-object.h> - -#include "backends/meta-monitor-manager-private.h" -#include "compositor/meta-surface-actor.h" -#include "wayland/meta-wayland-private.h" -#include "wayland/meta-wayland.h" - -G_BEGIN_DECLS - -#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ()) -G_DECLARE_FINAL_TYPE (MetaSurfaceActorWayland, - meta_surface_actor_wayland, - META, SURFACE_ACTOR_WAYLAND, - MetaSurfaceActor) - -MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface); -MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self); -void meta_surface_actor_wayland_surface_destroyed (MetaSurfaceActorWayland *self); - -double meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor); - -void meta_surface_actor_wayland_get_subsurface_rect (MetaSurfaceActorWayland *self, - MetaRectangle *rect); - -void meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self, - struct wl_list *frame_callbacks); - -CoglScanout * meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, - CoglOnscreen *onscreen); - -ClutterStageView * meta_surface_actor_wayland_get_current_primary_view (MetaSurfaceActor *actor, - ClutterStage *stage); - -G_END_DECLS - -#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c deleted file mode 100644 index 41ae2dffb..000000000 --- a/src/compositor/meta-surface-actor-x11.c +++ /dev/null @@ -1,422 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2013 Red Hat - * - * 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: - * Owen Taylor <otaylor@redhat.com> - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#include "config.h" - -#include "compositor/meta-surface-actor-x11.h" - -#include <X11/extensions/Xcomposite.h> - -#include "cogl/winsys/cogl-texture-pixmap-x11.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/meta-window-actor-private.h" -#include "core/window-private.h" -#include "meta/meta-x11-errors.h" -#include "x11/meta-x11-display-private.h" -#include "x11/window-x11.h" - -struct _MetaSurfaceActorX11 -{ - MetaSurfaceActor parent; - - MetaWindow *window; - - MetaDisplay *display; - - CoglTexture *texture; - Pixmap pixmap; - Damage damage; - - int last_width; - int last_height; - - /* This is used to detect fullscreen windows that need to be unredirected */ - guint full_damage_frames_count; - guint does_full_damage : 1; - - /* Other state... */ - guint received_damage : 1; - guint size_changed : 1; - - guint unredirected : 1; -}; - -G_DEFINE_TYPE (MetaSurfaceActorX11, - meta_surface_actor_x11, - META_TYPE_SURFACE_ACTOR) - -static void -free_damage (MetaSurfaceActorX11 *self) -{ - MetaDisplay *display = self->display; - Display *xdisplay; - - if (self->damage == None) - return; - - xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - meta_x11_error_trap_push (display->x11_display); - XDamageDestroy (xdisplay, self->damage); - self->damage = None; - meta_x11_error_trap_pop (display->x11_display); -} - -static void -detach_pixmap (MetaSurfaceActorX11 *self) -{ - MetaDisplay *display = self->display; - MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - Display *xdisplay; - - if (self->pixmap == None) - return; - - xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - /* Get rid of all references to the pixmap before freeing it; it's unclear whether - * you are supposed to be able to free a GLXPixmap after freeing the underlying - * pixmap, but it certainly doesn't work with current DRI/Mesa - */ - meta_shaped_texture_set_texture (stex, NULL); - cogl_flush (); - - meta_x11_error_trap_push (display->x11_display); - XFreePixmap (xdisplay, self->pixmap); - self->pixmap = None; - meta_x11_error_trap_pop (display->x11_display); - - g_clear_pointer (&self->texture, cogl_object_unref); -} - -static void -set_pixmap (MetaSurfaceActorX11 *self, - Pixmap pixmap) -{ - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - GError *error = NULL; - CoglTexture *texture; - - g_assert (self->pixmap == None); - self->pixmap = pixmap; - - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, self->pixmap, FALSE, &error)); - - if (error != NULL) - { - g_warning ("Failed to allocate stex texture: %s", error->message); - g_error_free (error); - } - else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) - g_warning ("NOTE: Not using GLX TFP!"); - - self->texture = texture; - meta_shaped_texture_set_texture (stex, texture); -} - -static void -update_pixmap (MetaSurfaceActorX11 *self) -{ - MetaDisplay *display = self->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - if (self->size_changed) - { - detach_pixmap (self); - self->size_changed = FALSE; - } - - if (self->pixmap == None) - { - Pixmap new_pixmap; - Window xwindow = meta_window_x11_get_toplevel_xwindow (self->window); - - meta_x11_error_trap_push (display->x11_display); - new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); - - if (meta_x11_error_trap_pop_with_return (display->x11_display) != Success) - { - /* Probably a BadMatch if the window isn't viewable; we could - * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync - * to avoid this, but there's no reason to take two round trips - * when one will do. (We need that Sync if we want to handle failures - * for any reason other than !viewable. That's unlikely, but maybe - * we'll BadAlloc or something.) - */ - new_pixmap = None; - } - - if (new_pixmap == None) - { - meta_verbose ("Unable to get named pixmap for %s", - meta_window_get_description (self->window)); - return; - } - - set_pixmap (self, new_pixmap); - } -} - -gboolean -meta_surface_actor_x11_is_visible (MetaSurfaceActorX11 *self) -{ - return (self->pixmap != None) && !self->unredirected; -} - -static void -meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor, - int x, int y, int width, int height) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); - - self->received_damage = TRUE; - - if (meta_window_is_fullscreen (self->window) && !self->unredirected && !self->does_full_damage) - { - MetaRectangle window_rect; - meta_window_get_frame_rect (self->window, &window_rect); - - if (x == 0 && - y == 0 && - window_rect.width == width && - window_rect.height == height) - self->full_damage_frames_count++; - else - self->full_damage_frames_count = 0; - - if (self->full_damage_frames_count >= 100) - self->does_full_damage = TRUE; - } - - if (!meta_surface_actor_x11_is_visible (self)) - return; - - cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (self->texture), - x, y, width, height); - meta_surface_actor_update_area (actor, x, y, width, height); -} - -void -meta_surface_actor_x11_handle_updates (MetaSurfaceActorX11 *self) -{ - MetaDisplay *display = self->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - if (self->received_damage) - { - meta_x11_error_trap_push (display->x11_display); - XDamageSubtract (xdisplay, self->damage, None, None); - meta_x11_error_trap_pop (display->x11_display); - - self->received_damage = FALSE; - } - - update_pixmap (self); -} - -static gboolean -meta_surface_actor_x11_is_opaque (MetaSurfaceActor *actor) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); - MetaShapedTexture *stex = meta_surface_actor_get_texture (actor); - - if (meta_surface_actor_x11_is_unredirected (self)) - return TRUE; - - return meta_shaped_texture_is_opaque (stex); -} - -gboolean -meta_surface_actor_x11_should_unredirect (MetaSurfaceActorX11 *self) -{ - if (!meta_surface_actor_x11_is_opaque (META_SURFACE_ACTOR (self))) - return FALSE; - - if (!self->does_full_damage && - !meta_window_is_override_redirect (self->window)) - return FALSE; - - return TRUE; -} - -static void -sync_unredirected (MetaSurfaceActorX11 *self) -{ - MetaDisplay *display = self->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - Window xwindow = meta_window_x11_get_toplevel_xwindow (self->window); - - meta_x11_error_trap_push (display->x11_display); - - if (self->unredirected) - { - XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual); - XSync (xdisplay, False); - detach_pixmap (self); - } - else - { - XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual); - XSync (xdisplay, False); - clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); - } - - meta_x11_error_trap_pop (display->x11_display); -} - -void -meta_surface_actor_x11_set_unredirected (MetaSurfaceActorX11 *self, - gboolean unredirected) -{ - if (self->unredirected == unredirected) - return; - - self->unredirected = unredirected; - sync_unredirected (self); -} - -gboolean -meta_surface_actor_x11_is_unredirected (MetaSurfaceActorX11 *self) -{ - return self->unredirected; -} - -static void -release_x11_resources (MetaSurfaceActorX11 *self) -{ - detach_pixmap (self); - free_damage (self); -} - -static void -meta_surface_actor_x11_dispose (GObject *object) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object); - - release_x11_resources (self); - - G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object); -} - -static void -meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); - - object_class->dispose = meta_surface_actor_x11_dispose; - - surface_actor_class->process_damage = meta_surface_actor_x11_process_damage; - surface_actor_class->is_opaque = meta_surface_actor_x11_is_opaque; -} - -static void -meta_surface_actor_x11_init (MetaSurfaceActorX11 *self) -{ - self->last_width = -1; - self->last_height = -1; -} - -static void -create_damage (MetaSurfaceActorX11 *self) -{ - Display *xdisplay = meta_x11_display_get_xdisplay (self->display->x11_display); - Window xwindow = meta_window_x11_get_toplevel_xwindow (self->window); - - self->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox); -} - -static void -window_decorated_notify (MetaWindow *window, - GParamSpec *pspec, - gpointer user_data) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data); - - release_x11_resources (self); - create_damage (self); -} - -static void -reset_texture (MetaSurfaceActorX11 *self) -{ - MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - - if (!self->texture) - return; - - /* Setting the texture to NULL will cause all the FBO's cached by the - * shaped texture's MetaTextureTower to be discarded and recreated. - */ - meta_shaped_texture_set_texture (stex, NULL); - meta_shaped_texture_set_texture (stex, self->texture); -} - -MetaSurfaceActor * -meta_surface_actor_x11_new (MetaWindow *window) -{ - MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL); - MetaDisplay *display = meta_window_get_display (window); - - g_assert (!meta_is_wayland_compositor ()); - - self->window = window; - self->display = display; - - g_signal_connect_object (self->display, "gl-video-memory-purged", - G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED); - - create_damage (self); - g_signal_connect_object (self->window, "notify::decorated", - G_CALLBACK (window_decorated_notify), self, 0); - - g_signal_connect_object (meta_window_actor_from_window (window), "destroy", - G_CALLBACK (release_x11_resources), self, - G_CONNECT_SWAPPED); - - self->unredirected = FALSE; - sync_unredirected (self); - - clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); - return META_SURFACE_ACTOR (self); -} - -void -meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, - int width, int height) -{ - MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - - if (self->last_width == width && - self->last_height == height) - return; - - self->size_changed = TRUE; - self->last_width = width; - self->last_height = height; - meta_shaped_texture_set_fallback_size (stex, width, height); -} diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h deleted file mode 100644 index 0a8517236..000000000 --- a/src/compositor/meta-surface-actor-x11.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2013 Red Hat - * - * 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: - * Owen Taylor <otaylor@redhat.com> - * Jasper St. Pierre <jstpierre@mecheye.net> - */ - -#ifndef __META_SURFACE_ACTOR_X11_H__ -#define __META_SURFACE_ACTOR_X11_H__ - -#include <glib-object.h> - -#include <X11/extensions/Xdamage.h> - -#include "compositor/meta-surface-actor.h" -#include "meta/display.h" -#include "meta/window.h" - -G_BEGIN_DECLS - -#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ()) -G_DECLARE_FINAL_TYPE (MetaSurfaceActorX11, - meta_surface_actor_x11, - META, SURFACE_ACTOR_X11, - MetaSurfaceActor) - -MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window); - -void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, - int width, int height); -gboolean meta_surface_actor_x11_should_unredirect (MetaSurfaceActorX11 *self); - -void meta_surface_actor_x11_set_unredirected (MetaSurfaceActorX11 *self, - gboolean unredirected); - -gboolean meta_surface_actor_x11_is_unredirected (MetaSurfaceActorX11 *self); - -gboolean meta_surface_actor_x11_is_visible (MetaSurfaceActorX11 *self); - -void meta_surface_actor_x11_handle_updates (MetaSurfaceActorX11 *self); - -G_END_DECLS - -#endif /* __META_SURFACE_ACTOR_X11_H__ */ diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c deleted file mode 100644 index 48042b227..000000000 --- a/src/compositor/meta-surface-actor.c +++ /dev/null @@ -1,698 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/** - * SECTION:meta-surface-actor - * @title: MetaSurfaceActor - * @short_description: An actor representing a surface in the scene graph - * - * MetaSurfaceActor is an abstract class which represents a surface in the - * Clutter scene graph. A subclass can implement the specifics of a surface - * depending on the way it is handled by a display protocol. - * - * An important feature of #MetaSurfaceActor is that it allows you to set an - * "input region": all events that occur in the surface, but outside of the - * input region are to be explicitly ignored. By default, this region is to - * %NULL, which means events on the whole surface is allowed. - */ - -#include "config.h" - -#include "compositor/meta-surface-actor.h" - -#include "clutter/clutter.h" -#include "compositor/clutter-utils.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/meta-window-actor-private.h" -#include "compositor/region-utils.h" -#include "meta/meta-shaped-texture.h" - -typedef struct _MetaSurfaceActorPrivate -{ - MetaShapedTexture *texture; - - cairo_region_t *input_region; - - /* MetaCullable regions, see that documentation for more details */ - cairo_region_t *unobscured_region; - - /* Freeze/thaw accounting */ - cairo_region_t *pending_damage; - guint frozen : 1; -} MetaSurfaceActorPrivate; - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, - G_ADD_PRIVATE (MetaSurfaceActor) - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); - -enum -{ - REPAINT_SCHEDULED, - SIZE_CHANGED, - - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL]; - -typedef enum -{ - IN_STAGE_PERSPECTIVE, - IN_ACTOR_PERSPECTIVE -} ScalePerspectiveType; - -static cairo_region_t * -effective_unobscured_region (MetaSurfaceActor *surface_actor) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (surface_actor); - ClutterActor *actor = CLUTTER_ACTOR (surface_actor); - - /* Fail if we have any mapped clones. */ - if (clutter_actor_has_mapped_clones (actor)) - return NULL; - - return priv->unobscured_region; -} - -static cairo_region_t* -get_scaled_region (MetaSurfaceActor *surface_actor, - cairo_region_t *region, - ScalePerspectiveType scale_perspective) -{ - MetaWindowActor *window_actor; - cairo_region_t *scaled_region = NULL; - int geometry_scale; - float x, y; - - window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor)); - geometry_scale = meta_window_actor_get_geometry_scale (window_actor); - - clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y); - cairo_region_translate (region, x, y); - - switch (scale_perspective) - { - case IN_STAGE_PERSPECTIVE: - scaled_region = meta_region_scale_double (region, - geometry_scale, - META_ROUNDING_STRATEGY_GROW); - break; - case IN_ACTOR_PERSPECTIVE: - scaled_region = meta_region_scale_double (region, - 1.0 / geometry_scale, - META_ROUNDING_STRATEGY_GROW); - break; - } - - g_assert (scaled_region != NULL); - cairo_region_translate (region, -x, -y); - cairo_region_translate (scaled_region, -x, -y); - - return scaled_region; -} - -static void -set_unobscured_region (MetaSurfaceActor *surface_actor, - cairo_region_t *unobscured_region) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (surface_actor); - - g_clear_pointer (&priv->unobscured_region, cairo_region_destroy); - if (unobscured_region) - { - if (cairo_region_is_empty (unobscured_region)) - { - priv->unobscured_region = cairo_region_reference (unobscured_region); - } - else - { - cairo_rectangle_int_t bounds = { 0, }; - float width, height; - - clutter_content_get_preferred_size (CLUTTER_CONTENT (priv->texture), - &width, - &height); - bounds = (cairo_rectangle_int_t) { - .width = width, - .height = height, - }; - - priv->unobscured_region = get_scaled_region (surface_actor, - unobscured_region, - IN_ACTOR_PERSPECTIVE); - - cairo_region_intersect_rectangle (priv->unobscured_region, &bounds); - } - } -} - -static void -set_clip_region (MetaSurfaceActor *surface_actor, - cairo_region_t *clip_region) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (surface_actor); - MetaShapedTexture *stex = priv->texture; - - if (clip_region && !cairo_region_is_empty (clip_region)) - { - cairo_region_t *region; - - region = get_scaled_region (surface_actor, - clip_region, - IN_ACTOR_PERSPECTIVE); - meta_shaped_texture_set_clip_region (stex, region); - - cairo_region_destroy (region); - } - else - { - meta_shaped_texture_set_clip_region (stex, clip_region); - } -} - -static void -meta_surface_actor_pick (ClutterActor *actor, - ClutterPickContext *pick_context) -{ - MetaSurfaceActor *self = META_SURFACE_ACTOR (actor); - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - ClutterActorIter iter; - ClutterActor *child; - - if (!clutter_actor_should_pick (actor, pick_context)) - return; - - /* If there is no region then use the regular pick */ - if (priv->input_region == NULL) - { - ClutterActorClass *actor_class = - CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class); - - actor_class->pick (actor, pick_context); - } - else - { - int n_rects; - int i; - - n_rects = cairo_region_num_rectangles (priv->input_region); - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - ClutterActorBox box; - - cairo_region_get_rectangle (priv->input_region, i, &rect); - - box.x1 = rect.x; - box.y1 = rect.y; - box.x2 = rect.x + rect.width; - box.y2 = rect.y + rect.height; - clutter_actor_pick_box (actor, pick_context, &box); - } - } - - clutter_actor_iter_init (&iter, actor); - - while (clutter_actor_iter_next (&iter, &child)) - clutter_actor_pick (child, pick_context); -} - -static gboolean -meta_surface_actor_get_paint_volume (ClutterActor *actor, - ClutterPaintVolume *volume) -{ - return clutter_paint_volume_set_from_allocation (volume, actor); -} - -static void -meta_surface_actor_dispose (GObject *object) -{ - MetaSurfaceActor *self = META_SURFACE_ACTOR (object); - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - g_clear_pointer (&priv->input_region, cairo_region_destroy); - g_clear_object (&priv->texture); - - set_unobscured_region (self, NULL); - - G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); -} - -static void -meta_surface_actor_class_init (MetaSurfaceActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - - object_class->dispose = meta_surface_actor_dispose; - actor_class->pick = meta_surface_actor_pick; - actor_class->get_paint_volume = meta_surface_actor_get_paint_volume; - - signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[SIZE_CHANGED] = g_signal_new ("size-changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -gboolean -meta_surface_actor_is_opaque (MetaSurfaceActor *self) -{ - return META_SURFACE_ACTOR_GET_CLASS (self)->is_opaque (self); -} - -static void -meta_surface_actor_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (cullable); - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (surface_actor); - uint8_t opacity = clutter_actor_get_opacity (CLUTTER_ACTOR (cullable)); - - set_unobscured_region (surface_actor, unobscured_region); - set_clip_region (surface_actor, clip_region); - - if (opacity == 0xff) - { - cairo_region_t *opaque_region; - cairo_region_t *scaled_opaque_region; - - opaque_region = meta_shaped_texture_get_opaque_region (priv->texture); - - if (!opaque_region) - return; - - scaled_opaque_region = get_scaled_region (surface_actor, - opaque_region, - IN_STAGE_PERSPECTIVE); - - if (unobscured_region) - cairo_region_subtract (unobscured_region, scaled_opaque_region); - if (clip_region) - cairo_region_subtract (clip_region, scaled_opaque_region); - - cairo_region_destroy (scaled_opaque_region); - } -} - -static gboolean -meta_surface_actor_is_untransformed (MetaCullable *cullable) -{ - ClutterActor *actor = CLUTTER_ACTOR (cullable); - MetaWindowActor *window_actor; - float width, height; - graphene_point3d_t verts[4]; - int geometry_scale; - - clutter_actor_get_size (actor, &width, &height); - clutter_actor_get_abs_allocation_vertices (actor, verts); - - window_actor = meta_window_actor_from_actor (actor); - geometry_scale = meta_window_actor_get_geometry_scale (window_actor); - - return meta_actor_vertices_are_untransformed (verts, - width * geometry_scale, - height * geometry_scale, - NULL, NULL); -} - -static void -meta_surface_actor_reset_culling (MetaCullable *cullable) -{ - MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (cullable); - - set_clip_region (surface_actor, NULL); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_surface_actor_cull_out; - iface->is_untransformed = meta_surface_actor_is_untransformed; - iface->reset_culling = meta_surface_actor_reset_culling; -} - -static void -texture_size_changed (MetaShapedTexture *texture, - gpointer user_data) -{ - MetaSurfaceActor *actor = META_SURFACE_ACTOR (user_data); - g_signal_emit (actor, signals[SIZE_CHANGED], 0); -} - -static void -meta_surface_actor_init (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - priv->texture = meta_shaped_texture_new (); - g_signal_connect_object (priv->texture, "size-changed", - G_CALLBACK (texture_size_changed), self, 0); - clutter_actor_set_content (CLUTTER_ACTOR (self), - CLUTTER_CONTENT (priv->texture)); - clutter_actor_set_request_mode (CLUTTER_ACTOR (self), - CLUTTER_REQUEST_CONTENT_SIZE); -} - -/** - * meta_surface_actor_get_image: - * @self: A #MetaSurfaceActor - * @clip: (nullable): A clipping rectangle. The clip region is in - * the same coordinate space as the contents preferred size. - * For a shaped texture of a wl_surface, this means surface - * coordinate space. If NULL, the whole content will be used. - * - * Get the image from the texture content. The resulting size of - * the returned image may be different from the preferred size of - * the shaped texture content. - * - * Returns: (nullable) (transfer full): a new cairo surface to be freed - * with cairo_surface_destroy(). - */ -cairo_surface_t * -meta_surface_actor_get_image (MetaSurfaceActor *self, - cairo_rectangle_int_t *clip) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - return meta_shaped_texture_get_image (priv->texture, clip); -} - -MetaShapedTexture * -meta_surface_actor_get_texture (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - return priv->texture; -} - -void -meta_surface_actor_update_area (MetaSurfaceActor *self, - int x, - int y, - int width, - int height) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - gboolean repaint_scheduled = FALSE; - cairo_rectangle_int_t clip; - - if (meta_shaped_texture_update_area (priv->texture, x, y, width, height, &clip)) - { - cairo_region_t *unobscured_region; - - unobscured_region = effective_unobscured_region (self); - - if (unobscured_region) - { - cairo_region_t *intersection; - - if (cairo_region_is_empty (unobscured_region)) - return; - - intersection = cairo_region_copy (unobscured_region); - cairo_region_intersect_rectangle (intersection, &clip); - - if (!cairo_region_is_empty (intersection)) - { - cairo_rectangle_int_t damage_rect; - - cairo_region_get_extents (intersection, &damage_rect); - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &damage_rect); - repaint_scheduled = TRUE; - } - - cairo_region_destroy (intersection); - } - else - { - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &clip); - repaint_scheduled = TRUE; - } - } - - if (repaint_scheduled) - g_signal_emit (self, signals[REPAINT_SCHEDULED], 0); -} - -gboolean -meta_surface_actor_is_obscured (MetaSurfaceActor *self) -{ - cairo_region_t *unobscured_region; - - unobscured_region = effective_unobscured_region (self); - - if (unobscured_region) - return cairo_region_is_empty (unobscured_region); - else - return FALSE; -} - -gboolean -meta_surface_actor_is_obscured_on_stage_view (MetaSurfaceActor *self, - ClutterStageView *stage_view, - float *unobscurred_fraction) -{ - cairo_region_t *unobscured_region; - - unobscured_region = effective_unobscured_region (self); - - if (unobscured_region) - { - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - cairo_region_t *intersection_region; - cairo_rectangle_int_t stage_rect; - float x, y; - float bounds_width, bounds_height; - float bounds_size; - int intersection_size = 0; - int n_rects, i; - - if (cairo_region_is_empty (unobscured_region)) - return TRUE; - - intersection_region = cairo_region_copy (unobscured_region); - clutter_actor_get_transformed_position (CLUTTER_ACTOR (self), &x, &y); - cairo_region_translate (intersection_region, x, y); - - clutter_stage_view_get_layout (stage_view, &stage_rect); - cairo_region_intersect_rectangle (intersection_region, - &stage_rect); - - if (cairo_region_is_empty (intersection_region)) - { - cairo_region_destroy (intersection_region); - return TRUE; - } - else if (!unobscurred_fraction) - { - cairo_region_destroy (intersection_region); - return FALSE; - } - - clutter_content_get_preferred_size (CLUTTER_CONTENT (priv->texture), - &bounds_width, - &bounds_height); - bounds_size = bounds_width * bounds_height; - - n_rects = cairo_region_num_rectangles (intersection_region); - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (intersection_region, i, &rect); - intersection_size += (rect.width - rect.x) * (rect.height - rect.x); - } - cairo_region_destroy (intersection_region); - - g_return_val_if_fail (bounds_size > 0, FALSE); - - *unobscurred_fraction = CLAMP (intersection_size / bounds_size, 0, 1); - return FALSE; - } - - return !clutter_actor_is_effectively_on_stage_view (CLUTTER_ACTOR (self), - stage_view); -} - -void -meta_surface_actor_set_input_region (MetaSurfaceActor *self, - cairo_region_t *region) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - if (priv->input_region) - cairo_region_destroy (priv->input_region); - - if (region) - priv->input_region = cairo_region_reference (region); - else - priv->input_region = NULL; -} - -void -meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, - cairo_region_t *region) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_set_opaque_region (priv->texture, region); -} - -cairo_region_t * -meta_surface_actor_get_opaque_region (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - return meta_shaped_texture_get_opaque_region (priv->texture); -} - -void -meta_surface_actor_process_damage (MetaSurfaceActor *self, - int x, int y, int width, int height) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - if (meta_surface_actor_is_frozen (self)) - { - /* The window is frozen due to an effect in progress: we ignore damage - * here on the off chance that this will stop the corresponding - * texture_from_pixmap from being update. - * - * pending_damage tracks any damage that happened while the window was - * frozen so that when can apply it when the window becomes unfrozen. - * - * It should be noted that this is an unreliable mechanism since it's - * quite likely that drivers will aim to provide a zero-copy - * implementation of the texture_from_pixmap extension and in those cases - * any drawing done to the window is always immediately reflected in the - * texture regardless of damage event handling. - */ - cairo_rectangle_int_t rect = { .x = x, .y = y, .width = width, .height = height }; - - if (!priv->pending_damage) - priv->pending_damage = cairo_region_create_rectangle (&rect); - else - cairo_region_union_rectangle (priv->pending_damage, &rect); - return; - } - - META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height); -} - -void -meta_surface_actor_set_frozen (MetaSurfaceActor *self, - gboolean frozen) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - if (priv->frozen == frozen) - return; - - priv->frozen = frozen; - - if (!frozen && priv->pending_damage) - { - int i, n_rects = cairo_region_num_rectangles (priv->pending_damage); - cairo_rectangle_int_t rect; - - /* Since we ignore damage events while a window is frozen for certain effects - * we need to apply the tracked damage now. */ - - for (i = 0; i < n_rects; i++) - { - cairo_region_get_rectangle (priv->pending_damage, i, &rect); - meta_surface_actor_process_damage (self, rect.x, rect.y, - rect.width, rect.height); - } - g_clear_pointer (&priv->pending_damage, cairo_region_destroy); - } -} - -gboolean -meta_surface_actor_is_frozen (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - return priv->frozen; -} - -void -meta_surface_actor_set_transform (MetaSurfaceActor *self, - MetaMonitorTransform transform) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_set_transform (priv->texture, transform); -} - -void -meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor *self, - graphene_rect_t *src_rect) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_set_viewport_src_rect (priv->texture, src_rect); -} - -void -meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_reset_viewport_src_rect (priv->texture); -} - -void -meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor *self, - int dst_width, - int dst_height) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_set_viewport_dst_size (priv->texture, - dst_width, - dst_height); -} - -void -meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self) -{ - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); - - meta_shaped_texture_reset_viewport_dst_size (priv->texture); -} diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h deleted file mode 100644 index a61251049..000000000 --- a/src/compositor/meta-surface-actor.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_SURFACE_ACTOR_PRIVATE_H -#define META_SURFACE_ACTOR_PRIVATE_H - -#include "config.h" - -#include "backends/meta-backend-types.h" -#include "meta/meta-shaped-texture.h" -#include "meta/window.h" - -G_BEGIN_DECLS - -#define META_TYPE_SURFACE_ACTOR (meta_surface_actor_get_type ()) -G_DECLARE_DERIVABLE_TYPE (MetaSurfaceActor, - meta_surface_actor, - META, SURFACE_ACTOR, - ClutterActor) - -struct _MetaSurfaceActorClass -{ - /*< private >*/ - ClutterActorClass parent_class; - - void (* process_damage) (MetaSurfaceActor *actor, - int x, int y, int width, int height); - gboolean (* is_opaque) (MetaSurfaceActor *actor); -}; - -cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self, - cairo_rectangle_int_t *clip); - -MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self); - -void meta_surface_actor_update_area (MetaSurfaceActor *self, - int x, - int y, - int width, - int height); - -gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self); -gboolean meta_surface_actor_is_obscured_on_stage_view (MetaSurfaceActor *self, - ClutterStageView *stage_view, - float *unobscurred_fraction); - -void meta_surface_actor_set_input_region (MetaSurfaceActor *self, - cairo_region_t *region); -void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, - cairo_region_t *region); -cairo_region_t * meta_surface_actor_get_opaque_region (MetaSurfaceActor *self); - -void meta_surface_actor_process_damage (MetaSurfaceActor *actor, - int x, int y, int width, int height); - -gboolean meta_surface_actor_is_opaque (MetaSurfaceActor *actor); - -gboolean meta_surface_actor_is_frozen (MetaSurfaceActor *actor); -void meta_surface_actor_set_frozen (MetaSurfaceActor *actor, - gboolean frozen); - -void meta_surface_actor_set_transform (MetaSurfaceActor *self, - MetaMonitorTransform transform); -void meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor *self, - graphene_rect_t *src_rect); -void meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self); -void meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor *self, - int dst_width, - int dst_height); -void meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self); -G_END_DECLS - -#endif /* META_SURFACE_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c deleted file mode 100644 index 917bf1235..000000000 --- a/src/compositor/meta-sync-ring.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * This is based on an original C++ implementation for compiz that - * carries the following copyright notice: - * - * - * Copyright © 2011 NVIDIA Corporation - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of NVIDIA - * Corporation not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. NVIDIA Corporation makes no representations about the - * suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - * Authors: James Jones <jajones@nvidia.com> - */ - -#include "config.h" - -#include "compositor/meta-sync-ring.h" - -#include <string.h> -#include <GL/gl.h> -#include <GL/glx.h> -#include <X11/extensions/sync.h> - -#include "clutter/clutter.h" -#include "cogl/cogl.h" -#include "meta/util.h" - -/* Theory of operation: - * - * We use a ring of NUM_SYNCS fence objects. On each frame we advance - * to the next fence in the ring. For each fence we do: - * - * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d - * 2. NUM_SYNCS / 2 frames later, fence should be triggered - * 3. fence is XSyncResetFence()'d - * 4. NUM_SYNCS / 2 frames later, fence should be reset - * 5. go back to 1 and re-use fence - * - * glClientWaitSync() and XAlarms are used in steps 2 and 4, - * respectively, to double-check the expectections. - */ - -#define NUM_SYNCS 10 -#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */ -#define MAX_REBOOT_ATTEMPTS 2 - -typedef enum -{ - META_SYNC_STATE_READY, - META_SYNC_STATE_WAITING, - META_SYNC_STATE_DONE, - META_SYNC_STATE_RESET_PENDING, -} MetaSyncState; - -typedef struct -{ - Display *xdisplay; - - XSyncFence xfence; - GLsync gl_x11_sync; - GLsync gpu_fence; - - XSyncCounter xcounter; - XSyncAlarm xalarm; - XSyncValue next_counter_value; - - MetaSyncState state; -} MetaSync; - -typedef struct -{ - Display *xdisplay; - int xsync_event_base; - int xsync_error_base; - - GHashTable *alarm_to_sync; - - MetaSync *syncs_array[NUM_SYNCS]; - guint current_sync_idx; - MetaSync *current_sync; - guint warmup_syncs; - - guint reboots; -} MetaSyncRing; - -static MetaSyncRing meta_sync_ring = { 0 }; - -static XSyncValue SYNC_VALUE_ZERO; -static XSyncValue SYNC_VALUE_ONE; - -static const char* (*meta_gl_get_string) (GLenum name); -static void (*meta_gl_get_integerv) (GLenum pname, - GLint *params); -static const char* (*meta_gl_get_stringi) (GLenum name, - GLuint index); -static void (*meta_gl_delete_sync) (GLsync sync); -static GLenum (*meta_gl_client_wait_sync) (GLsync sync, - GLbitfield flags, - GLuint64 timeout); -static void (*meta_gl_wait_sync) (GLsync sync, - GLbitfield flags, - GLuint64 timeout); -static GLsync (*meta_gl_import_sync) (GLenum external_sync_type, - GLintptr external_sync, - GLbitfield flags); -static GLsync (*meta_gl_fence_sync) (GLenum condition, - GLbitfield flags); - -static MetaSyncRing * -meta_sync_ring_get (void) -{ - if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS) - return NULL; - - return &meta_sync_ring; -} - -static gboolean -load_gl_symbol (const char *name, - void **func) -{ - *func = cogl_get_proc_address (name); - if (!*func) - { - meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"", name); - return FALSE; - } - return TRUE; -} - -static gboolean -check_gl_extensions (void) -{ - ClutterBackend *backend; - CoglContext *cogl_context; - CoglDisplay *cogl_display; - CoglRenderer *cogl_renderer; - - backend = clutter_get_default_backend (); - cogl_context = clutter_backend_get_cogl_context (backend); - cogl_display = cogl_context_get_display (cogl_context); - cogl_renderer = cogl_display_get_renderer (cogl_display); - - switch (cogl_renderer_get_driver (cogl_renderer)) - { - case COGL_DRIVER_GL3: - { - int num_extensions, i; - gboolean arb_sync = FALSE; - gboolean x11_sync_object = FALSE; - - meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions); - - for (i = 0; i < num_extensions; ++i) - { - const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i); - - if (g_strcmp0 ("GL_ARB_sync", ext) == 0) - arb_sync = TRUE; - else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0) - x11_sync_object = TRUE; - } - - return arb_sync && x11_sync_object; - } - case COGL_DRIVER_GL: - { - const char *extensions = meta_gl_get_string (GL_EXTENSIONS); - return (extensions != NULL && - strstr (extensions, "GL_ARB_sync") != NULL && - strstr (extensions, "GL_EXT_x11_sync_object") != NULL); - } - default: - break; - } - - return FALSE; -} - -static gboolean -load_required_symbols (void) -{ - static gboolean success = FALSE; - - if (success) - return TRUE; - - /* We don't link against libGL directly because cogl may want to - * use something else. This assumes that cogl has been initialized - * and dynamically loaded libGL at this point. - */ - - if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string)) - goto out; - if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv)) - goto out; - if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi)) - goto out; - - if (!check_gl_extensions ()) - { - meta_verbose ("MetaSyncRing: couldn't find required GL extensions"); - goto out; - } - - if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync)) - goto out; - if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync)) - goto out; - if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync)) - goto out; - if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync)) - goto out; - if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync)) - goto out; - - success = TRUE; - out: - return success; -} - -static void -meta_sync_insert (MetaSync *self) -{ - g_return_if_fail (self->state == META_SYNC_STATE_READY); - - XSyncTriggerFence (self->xdisplay, self->xfence); - XFlush (self->xdisplay); - - meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED); - self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - - self->state = META_SYNC_STATE_WAITING; -} - -static GLenum -meta_sync_check_update_finished (MetaSync *self, - GLuint64 timeout) -{ - GLenum status = GL_WAIT_FAILED; - - switch (self->state) - { - case META_SYNC_STATE_DONE: - status = GL_ALREADY_SIGNALED; - break; - case META_SYNC_STATE_WAITING: - status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout); - if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED) - { - self->state = META_SYNC_STATE_DONE; - meta_gl_delete_sync (self->gpu_fence); - self->gpu_fence = 0; - } - break; - default: - break; - } - - g_warn_if_fail (status != GL_WAIT_FAILED); - - return status; -} - -static void -meta_sync_reset (MetaSync *self) -{ - XSyncAlarmAttributes attrs; - int overflow; - - g_return_if_fail (self->state == META_SYNC_STATE_DONE); - - XSyncResetFence (self->xdisplay, self->xfence); - - attrs.trigger.wait_value = self->next_counter_value; - - XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs); - XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value); - - XSyncValueAdd (&self->next_counter_value, - self->next_counter_value, - SYNC_VALUE_ONE, - &overflow); - - self->state = META_SYNC_STATE_RESET_PENDING; -} - -static void -meta_sync_handle_event (MetaSync *self, - XSyncAlarmNotifyEvent *event) -{ - g_return_if_fail (event->alarm == self->xalarm); - g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING); - - self->state = META_SYNC_STATE_READY; -} - -static MetaSync * -meta_sync_new (Display *xdisplay) -{ - MetaSync *self; - XSyncAlarmAttributes attrs; - - self = g_malloc0 (sizeof (MetaSync)); - - self->xdisplay = xdisplay; - - self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE); - self->gl_x11_sync = 0; - self->gpu_fence = 0; - - self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO); - - attrs.trigger.counter = self->xcounter; - attrs.trigger.value_type = XSyncAbsolute; - attrs.trigger.wait_value = SYNC_VALUE_ONE; - attrs.trigger.test_type = XSyncPositiveTransition; - attrs.events = TRUE; - self->xalarm = XSyncCreateAlarm (xdisplay, - XSyncCACounter | - XSyncCAValueType | - XSyncCAValue | - XSyncCATestType | - XSyncCAEvents, - &attrs); - - XSyncIntToValue (&self->next_counter_value, 1); - - self->state = META_SYNC_STATE_READY; - - return self; -} - -static void -meta_sync_import (MetaSync *self) -{ - g_return_if_fail (self->gl_x11_sync == 0); - self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0); -} - -static Bool -alarm_event_predicate (Display *dpy, - XEvent *event, - XPointer data) -{ - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return False; - - if (event->type == ring->xsync_event_base + XSyncAlarmNotify) - { - if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm) - return True; - } - return False; -} - -static void -meta_sync_free (MetaSync *self) -{ - /* When our assumptions don't hold, something has gone wrong but we - * don't know what, so we reboot the ring. While doing that, we - * trigger fences before deleting them to try to get ourselves out - * of a potentially stuck GPU state. - */ - switch (self->state) - { - case META_SYNC_STATE_WAITING: - meta_gl_delete_sync (self->gpu_fence); - break; - case META_SYNC_STATE_DONE: - /* nothing to do */ - break; - case META_SYNC_STATE_RESET_PENDING: - { - XEvent event; - XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self); - meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event); - } - G_GNUC_FALLTHROUGH; - case META_SYNC_STATE_READY: - XSyncTriggerFence (self->xdisplay, self->xfence); - XFlush (self->xdisplay); - break; - default: - break; - } - - meta_gl_delete_sync (self->gl_x11_sync); - XSyncDestroyFence (self->xdisplay, self->xfence); - XSyncDestroyCounter (self->xdisplay, self->xcounter); - XSyncDestroyAlarm (self->xdisplay, self->xalarm); - - g_free (self); -} - -gboolean -meta_sync_ring_init (Display *xdisplay) -{ - gint major, minor; - guint i; - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return FALSE; - - g_return_val_if_fail (xdisplay != NULL, FALSE); - g_return_val_if_fail (ring->xdisplay == NULL, FALSE); - - if (!load_required_symbols ()) - return FALSE; - - if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) || - !XSyncInitialize (xdisplay, &major, &minor)) - return FALSE; - - XSyncIntToValue (&SYNC_VALUE_ZERO, 0); - XSyncIntToValue (&SYNC_VALUE_ONE, 1); - - ring->xdisplay = xdisplay; - - ring->alarm_to_sync = g_hash_table_new (NULL, NULL); - - for (i = 0; i < NUM_SYNCS; ++i) - { - MetaSync *sync = meta_sync_new (ring->xdisplay); - ring->syncs_array[i] = sync; - g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync); - } - /* Since the connection we create the X fences on isn't the same as - * the one used for the GLX context, we need to XSync() here to - * ensure glImportSync() succeeds. */ - XSync (xdisplay, False); - for (i = 0; i < NUM_SYNCS; ++i) - meta_sync_import (ring->syncs_array[i]); - - ring->current_sync_idx = 0; - ring->current_sync = ring->syncs_array[0]; - ring->warmup_syncs = 0; - - return TRUE; -} - -void -meta_sync_ring_destroy (void) -{ - guint i; - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return; - - g_return_if_fail (ring->xdisplay != NULL); - - ring->current_sync_idx = 0; - ring->current_sync = NULL; - ring->warmup_syncs = 0; - - for (i = 0; i < NUM_SYNCS; ++i) - meta_sync_free (ring->syncs_array[i]); - - g_hash_table_destroy (ring->alarm_to_sync); - - ring->xsync_event_base = 0; - ring->xsync_error_base = 0; - ring->xdisplay = NULL; -} - -static gboolean -meta_sync_ring_reboot (Display *xdisplay) -{ - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return FALSE; - - meta_sync_ring_destroy (); - - ring->reboots += 1; - - if (!meta_sync_ring_get ()) - { - meta_warning ("MetaSyncRing: Too many reboots -- disabling"); - return FALSE; - } - - return meta_sync_ring_init (xdisplay); -} - -gboolean -meta_sync_ring_after_frame (void) -{ - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return FALSE; - - g_return_val_if_fail (ring->xdisplay != NULL, FALSE); - - if (ring->warmup_syncs >= NUM_SYNCS / 2) - { - guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS; - MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx]; - - GLenum status = meta_sync_check_update_finished (sync_to_reset, 0); - if (status == GL_TIMEOUT_EXPIRED) - { - meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?"); - status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME); - } - - if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED) - { - meta_warning ("MetaSyncRing: Timed out waiting for sync object."); - return meta_sync_ring_reboot (ring->xdisplay); - } - - meta_sync_reset (sync_to_reset); - } - else - { - ring->warmup_syncs += 1; - } - - ring->current_sync_idx += 1; - ring->current_sync_idx %= NUM_SYNCS; - - ring->current_sync = ring->syncs_array[ring->current_sync_idx]; - - return TRUE; -} - -gboolean -meta_sync_ring_insert_wait (void) -{ - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return FALSE; - - g_return_val_if_fail (ring->xdisplay != NULL, FALSE); - - if (ring->current_sync->state != META_SYNC_STATE_READY) - { - meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?"); - if (!meta_sync_ring_reboot (ring->xdisplay)) - return FALSE; - } - - meta_sync_insert (ring->current_sync); - - return TRUE; -} - -void -meta_sync_ring_handle_event (XEvent *xevent) -{ - XSyncAlarmNotifyEvent *event; - MetaSync *sync; - MetaSyncRing *ring = meta_sync_ring_get (); - - if (!ring) - return; - - g_return_if_fail (ring->xdisplay != NULL); - - if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify)) - return; - - event = (XSyncAlarmNotifyEvent *) xevent; - - sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm); - if (sync) - meta_sync_handle_event (sync, event); -} diff --git a/src/compositor/meta-sync-ring.h b/src/compositor/meta-sync-ring.h deleted file mode 100644 index d9739455b..000000000 --- a/src/compositor/meta-sync-ring.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _META_SYNC_RING_H_ -#define _META_SYNC_RING_H_ - -#include <glib.h> -#include <X11/Xlib.h> - -gboolean meta_sync_ring_init (Display *dpy); -void meta_sync_ring_destroy (void); -gboolean meta_sync_ring_after_frame (void); -gboolean meta_sync_ring_insert_wait (void); -void meta_sync_ring_handle_event (XEvent *event); - -#endif /* _META_SYNC_RING_H_ */ diff --git a/src/compositor/meta-texture-tower.c b/src/compositor/meta-texture-tower.c deleted file mode 100644 index 1fc4623e5..000000000 --- a/src/compositor/meta-texture-tower.c +++ /dev/null @@ -1,484 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * MetaTextureTower - * - * Mipmap emulation by creation of scaled down images - * - * Copyright (C) 2009 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include <math.h> -#include <string.h> - -#include "compositor/meta-texture-tower.h" - -#ifndef M_LOG2E -#define M_LOG2E 1.4426950408889634074 -#endif - -#define MAX_TEXTURE_LEVELS 12 - -/* If the texture format in memory doesn't match this, then Mesa - * will do the conversion, so things will still work, but it might - * be slow depending on how efficient Mesa is. These should be the - * native formats unless the display is 16bpp. If conversions - * here are a bottleneck, investigate whether we are converting when - * storing window data *into* the texture before adding extra code - * to handle multiple texture formats. - */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE -#else -#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE -#endif - -typedef struct -{ - guint16 x1; - guint16 y1; - guint16 x2; - guint16 y2; -} Box; - -struct _MetaTextureTower -{ - int n_levels; - CoglTexture *textures[MAX_TEXTURE_LEVELS]; - CoglOffscreen *fbos[MAX_TEXTURE_LEVELS]; - Box invalid[MAX_TEXTURE_LEVELS]; - CoglPipeline *pipeline_template; -}; - -/** - * meta_texture_tower_new: - * - * Creates a new texture tower. The base texture has to be set with - * meta_texture_tower_set_base_texture() before use. - * - * Return value: the new texture tower. Free with meta_texture_tower_free() - */ -MetaTextureTower * -meta_texture_tower_new (void) -{ - MetaTextureTower *tower; - - tower = g_new0 (MetaTextureTower, 1); - - return tower; -} - -/** - * meta_texture_tower_free: - * @tower: a #MetaTextureTower - * - * Frees a texture tower created with meta_texture_tower_new(). - */ -void -meta_texture_tower_free (MetaTextureTower *tower) -{ - g_return_if_fail (tower != NULL); - - if (tower->pipeline_template != NULL) - cogl_object_unref (tower->pipeline_template); - - meta_texture_tower_set_base_texture (tower, NULL); - - g_free (tower); -} - -/** - * meta_texture_tower_set_base_texture: - * @tower: a #MetaTextureTower - * @texture: the new texture used as a base for scaled down versions - * - * Sets the base texture that is the scaled texture that the - * scaled textures of the tower are derived from. The texture itself - * will be used as level 0 of the tower and will be referenced until - * unset or until the tower is freed. - */ -void -meta_texture_tower_set_base_texture (MetaTextureTower *tower, - CoglTexture *texture) -{ - int i; - - g_return_if_fail (tower != NULL); - - if (texture == tower->textures[0]) - return; - - if (tower->textures[0] != NULL) - { - for (i = 1; i < tower->n_levels; i++) - { - cogl_clear_object (&tower->textures[i]); - g_clear_object (&tower->fbos[i]); - } - - cogl_object_unref (tower->textures[0]); - } - - tower->textures[0] = texture; - - if (tower->textures[0] != NULL) - { - int width, height; - - cogl_object_ref (tower->textures[0]); - - width = cogl_texture_get_width (tower->textures[0]); - height = cogl_texture_get_height (tower->textures[0]); - - tower->n_levels = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height))); - tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS); - - meta_texture_tower_update_area (tower, 0, 0, width, height); - } - else - { - tower->n_levels = 0; - } -} - -/** - * meta_texture_tower_update_area: - * @tower: a #MetaTextureTower - * @x: X coordinate of upper left of rectangle that changed - * @y: Y coordinate of upper left of rectangle that changed - * @width: width of rectangle that changed - * @height: height rectangle that changed - * - * Mark a region of the base texture as having changed; the next - * time a scaled down version of the base texture is retrieved, - * the appropriate area of the scaled down texture will be updated. - */ -void -meta_texture_tower_update_area (MetaTextureTower *tower, - int x, - int y, - int width, - int height) -{ - int texture_width, texture_height; - Box invalid; - int i; - - g_return_if_fail (tower != NULL); - - if (tower->textures[0] == NULL) - return; - - texture_width = cogl_texture_get_width (tower->textures[0]); - texture_height = cogl_texture_get_height (tower->textures[0]); - - invalid.x1 = x; - invalid.y1 = y; - invalid.x2 = x + width; - invalid.y2 = y + height; - - for (i = 1; i < tower->n_levels; i++) - { - texture_width = MAX (1, texture_width / 2); - texture_height = MAX (1, texture_height / 2); - - invalid.x1 = invalid.x1 / 2; - invalid.y1 = invalid.y1 / 2; - invalid.x2 = MIN (texture_width, (invalid.x2 + 1) / 2); - invalid.y2 = MIN (texture_height, (invalid.y2 + 1) / 2); - - if (tower->invalid[i].x1 == tower->invalid[i].x2 || - tower->invalid[i].y1 == tower->invalid[i].y2) - { - tower->invalid[i] = invalid; - } - else - { - tower->invalid[i].x1 = MIN (tower->invalid[i].x1, invalid.x1); - tower->invalid[i].y1 = MIN (tower->invalid[i].y1, invalid.y1); - tower->invalid[i].x2 = MAX (tower->invalid[i].x2, invalid.x2); - tower->invalid[i].y2 = MAX (tower->invalid[i].y2, invalid.y2); - } - } -} - -/* It generally looks worse if we scale up a window texture by even a - * small amount than if we scale it down using bilinear filtering, so - * we always pick the *larger* adjacent level. */ -#define LOD_BIAS (-0.49) - -/* This determines the appropriate level of detail to use when drawing the - * texture, in a way that corresponds to what the GL specification does - * when mip-mapping. This is probably fancier and slower than what we need, - * but we do the computation only once each time we paint a window, and - * its easier to just use the equations from the specification than to - * come up with something simpler. - * - * If window is being painted at an angle from the viewer, then we have to - * pick a point in the texture; we use the middle of the texture (which is - * why the width/height are passed in.) This is not the normal case for - * Meta. - */ -static int -get_paint_level (ClutterPaintContext *paint_context, - int width, - int height) -{ - CoglFramebuffer *framebuffer; - graphene_matrix_t projection, modelview, pm; - float xx, xy, xw; - float yx, yy, yw; - float wx, wy, ww; - float v[4]; - double viewport_width, viewport_height; - double u0, v0; - double xc, yc, wc; - double dxdu_, dxdv_, dydu_, dydv_; - double det_, det_sq; - double rho_sq; - double lambda; - - /* See - * http://www.opengl.org/registry/doc/glspec32.core.20090803.pdf - * Section 3.8.9, p. 1.6.2. Here we have - * - * u(x,y) = x_o; - * v(x,y) = y_o; - * - * Since we are mapping 1:1 from object coordinates into pixel - * texture coordinates, the clip coordinates are: - * - * (x_c) (x_o) (u) - * (y_c) = (M_projection)(M_modelview) (y_o) = (PM) (v) - * (z_c) (z_o) (0) - * (w_c) (w_o) (1) - */ - - framebuffer = clutter_paint_context_get_framebuffer (paint_context); - cogl_framebuffer_get_projection_matrix (framebuffer, &projection); - cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview); - - graphene_matrix_multiply (&modelview, &projection, &pm); - - xx = graphene_matrix_get_value (&pm, 0, 0); - xy = graphene_matrix_get_value (&pm, 0, 1); - xw = graphene_matrix_get_value (&pm, 0, 3); - yx = graphene_matrix_get_value (&pm, 1, 0); - yy = graphene_matrix_get_value (&pm, 1, 1); - yw = graphene_matrix_get_value (&pm, 1, 3); - wx = graphene_matrix_get_value (&pm, 3, 0); - wy = graphene_matrix_get_value (&pm, 3, 1); - ww = graphene_matrix_get_value (&pm, 3, 3); - - cogl_framebuffer_get_viewport4fv (framebuffer, v); - viewport_width = v[2]; - viewport_height = v[3]; - - u0 = width / 2.; - v0 = height / 2.; - - xc = xx * u0 + yx * v0 + wx; - yc = xy * u0 + yy * v0 + wy; - wc = xw * u0 + yw * v0 + ww; - - /* We'll simplify the equations below for a bit of micro-optimization. - * The commented out code is the unsimplified version. - - // Partial derivates of window coordinates: - // - // x_w = 0.5 * viewport_width * x_c / w_c + viewport_center_x - // y_w = 0.5 * viewport_height * y_c / w_c + viewport_center_y - // - // with respect to u, v, using - // d(a/b)/dx = da/dx * (1/b) - a * db/dx / (b^2) - - dxdu = 0.5 * viewport_width * (xx - xw * (xc/wc)) / wc; - dxdv = 0.5 * viewport_width * (yx - yw * (xc/wc)) / wc; - dydu = 0.5 * viewport_height * (xy - xw * (yc/wc)) / wc; - dydv = 0.5 * viewport_height * (yy - yw * (yc/wc)) / wc; - - // Compute the inverse partials as the matrix inverse - det = dxdu * dydv - dxdv * dydu; - - dudx = dydv / det; - dudy = - dxdv / det; - dvdx = - dydu / det; - dvdy = dvdu / det; - - // Scale factor; maximum of the distance in texels for a change of 1 pixel - // in the X direction or 1 pixel in the Y direction - rho = MAX (sqrt (dudx * dudx + dvdx * dvdx), sqrt(dudy * dudy + dvdy * dvdy)); - - // Level of detail - lambda = log2 (rho) + LOD_BIAS; - */ - - /* dxdu * wc, etc */ - dxdu_ = 0.5 * viewport_width * (xx - xw * (xc/wc)); - dxdv_ = 0.5 * viewport_width * (yx - yw * (xc/wc)); - dydu_ = 0.5 * viewport_height * (xy - xw * (yc/wc)); - dydv_ = 0.5 * viewport_height * (yy - yw * (yc/wc)); - - /* det * wc^2 */ - det_ = dxdu_ * dydv_ - dxdv_ * dydu_; - det_sq = det_ * det_; - if (det_sq == 0.0) - return -1; - - /* (rho * det * wc)^2 */ - rho_sq = MAX (dydv_ * dydv_ + dydu_ * dydu_, dxdv_ * dxdv_ + dxdu_ * dxdu_); - lambda = 0.5 * M_LOG2E * log (rho_sq * wc * wc / det_sq) + LOD_BIAS; - -#if 0 - g_print ("%g %g %g\n", 0.5 * viewport_width * xx / ww, 0.5 * viewport_height * yy / ww, lambda); -#endif - - if (lambda <= 0.) - return 0; - else - return (int)(0.5 + lambda); -} - -static void -texture_tower_create_texture (MetaTextureTower *tower, - int level, - int width, - int height) -{ - tower->textures[level] = cogl_texture_new_with_size (width, height, - COGL_TEXTURE_NO_AUTO_MIPMAP, - TEXTURE_FORMAT); - - tower->invalid[level].x1 = 0; - tower->invalid[level].y1 = 0; - tower->invalid[level].x2 = width; - tower->invalid[level].y2 = height; -} - -static void -texture_tower_revalidate (MetaTextureTower *tower, - int level) -{ - CoglTexture *source_texture = tower->textures[level - 1]; - int source_texture_width = cogl_texture_get_width (source_texture); - int source_texture_height = cogl_texture_get_height (source_texture); - CoglTexture *dest_texture = tower->textures[level]; - int dest_texture_width = cogl_texture_get_width (dest_texture); - int dest_texture_height = cogl_texture_get_height (dest_texture); - Box *invalid = &tower->invalid[level]; - CoglFramebuffer *fb; - GError *catch_error = NULL; - CoglPipeline *pipeline; - - if (tower->fbos[level] == NULL) - tower->fbos[level] = cogl_offscreen_new_with_texture (dest_texture); - - fb = COGL_FRAMEBUFFER (tower->fbos[level]); - - if (!cogl_framebuffer_allocate (fb, &catch_error)) - { - g_error_free (catch_error); - return; - } - - cogl_framebuffer_orthographic (fb, 0, 0, dest_texture_width, dest_texture_height, -1., 1.); - - if (!tower->pipeline_template) - { - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - tower->pipeline_template = cogl_pipeline_new (ctx); - cogl_pipeline_set_blend (tower->pipeline_template, "RGBA = ADD (SRC_COLOR, 0)", NULL); - } - - pipeline = cogl_pipeline_copy (tower->pipeline_template); - cogl_pipeline_set_layer_texture (pipeline, 0, tower->textures[level - 1]); - - cogl_framebuffer_draw_textured_rectangle (fb, pipeline, - invalid->x1, invalid->y1, - invalid->x2, invalid->y2, - (2. * invalid->x1) / source_texture_width, - (2. * invalid->y1) / source_texture_height, - (2. * invalid->x2) / source_texture_width, - (2. * invalid->y2) / source_texture_height); - - cogl_object_unref (pipeline); - - tower->invalid[level].x1 = tower->invalid[level].x2 = 0; - tower->invalid[level].y1 = tower->invalid[level].y2 = 0; -} - -/** - * meta_texture_tower_get_paint_texture: - * @tower: a #MetaTextureTower - * @paint_context: a #ClutterPaintContext - * - * Gets the texture from the tower that best matches the current - * rendering scale. (On the assumption here the texture is going to - * be rendered with vertex coordinates that correspond to its - * size in pixels, so a 200x200 texture will be rendered on the - * rectangle (0, 0, 200, 200). - * - * Return value: the COGL texture handle to use for painting, or - * %NULL if no base texture has yet been set. - */ -CoglTexture * -meta_texture_tower_get_paint_texture (MetaTextureTower *tower, - ClutterPaintContext *paint_context) -{ - int texture_width, texture_height; - int level; - - g_return_val_if_fail (tower != NULL, NULL); - - if (tower->textures[0] == NULL) - return NULL; - - texture_width = cogl_texture_get_width (tower->textures[0]); - texture_height = cogl_texture_get_height (tower->textures[0]); - - level = get_paint_level (paint_context, texture_width, texture_height); - if (level < 0) /* singular paint matrix, scaled to nothing */ - return NULL; - level = MIN (level, tower->n_levels - 1); - - if (tower->textures[level] == NULL || - (tower->invalid[level].x2 != tower->invalid[level].x1 && - tower->invalid[level].y2 != tower->invalid[level].y1)) - { - int i; - - for (i = 1; i <= level; i++) - { - /* Use "floor" convention here to be consistent with the NPOT texture extension */ - texture_width = MAX (1, texture_width / 2); - texture_height = MAX (1, texture_height / 2); - - if (tower->textures[i] == NULL) - texture_tower_create_texture (tower, i, texture_width, texture_height); - } - - for (i = 1; i <= level; i++) - { - if (tower->invalid[level].x2 != tower->invalid[level].x1 && - tower->invalid[level].y2 != tower->invalid[level].y1) - texture_tower_revalidate (tower, i); - } - } - - return tower->textures[level]; -} diff --git a/src/compositor/meta-texture-tower.h b/src/compositor/meta-texture-tower.h deleted file mode 100644 index 1f5b37146..000000000 --- a/src/compositor/meta-texture-tower.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * MetaTextureTower - * - * Mipmap emulation by creation of scaled down images - * - * Copyright (C) 2009 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __META_TEXTURE_TOWER_H__ -#define __META_TEXTURE_TOWER_H__ - -#include "clutter/clutter.h" - -G_BEGIN_DECLS - -/** - * SECTION:MetaTextureTower - * @short_description: mipmap emulation by creation of scaled down images - * - * A #MetaTextureTower is used to get good looking scaled down images when - * we can't use the GL drivers mipmap support. There are two separate reasons - * - * - Some cards (including radeon cards <= r5xx) only support - * TEXTURE_RECTANGLE_ARB and not NPOT textures. Rectangular textures - * are defined not to support mipmapping. - * - Even when NPOT textures are available, the combination of NPOT - * textures, texture_from_pixmap, and mipmapping doesn't typically - * work, since the X server doesn't allocate pixmaps in the right - * layout for mipmapping. - * - * So, what we do is create the "mipmap" levels ourselves by successive - * power-of-two scaledowns, and when rendering pick the single texture - * that best matches the scale we are rendering at. (Since we aren't - * typically using perspective transforms, we'll frequently have a single - * scale for the entire texture.) - */ - -typedef struct _MetaTextureTower MetaTextureTower; - -MetaTextureTower *meta_texture_tower_new (void); -void meta_texture_tower_free (MetaTextureTower *tower); -void meta_texture_tower_set_base_texture (MetaTextureTower *tower, - CoglTexture *texture); -void meta_texture_tower_update_area (MetaTextureTower *tower, - int x, - int y, - int width, - int height); -CoglTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower, - ClutterPaintContext *paint_context); - -G_END_DECLS - -#endif /* __META_TEXTURE_TOWER_H__ */ diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h deleted file mode 100644 index 64741e416..000000000 --- a/src/compositor/meta-window-actor-private.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_WINDOW_ACTOR_PRIVATE_H -#define META_WINDOW_ACTOR_PRIVATE_H - -#include <X11/extensions/Xdamage.h> - -#include "compositor/meta-plugin-manager.h" -#include "compositor/meta-surface-actor.h" -#include "meta/compositor-mutter.h" - -struct _MetaWindowActorClass -{ - ClutterActorClass parent; - - void (*frame_complete) (MetaWindowActor *actor, - ClutterFrameInfo *frame_info, - int64_t presentation_time); - - void (*assign_surface_actor) (MetaWindowActor *actor, - MetaSurfaceActor *surface_actor); - - void (*queue_frame_drawn) (MetaWindowActor *actor, - gboolean skip_sync_delay); - - void (*before_paint) (MetaWindowActor *actor, - ClutterStageView *stage_view); - void (*after_paint) (MetaWindowActor *actor, - ClutterStageView *stage_view); - - void (*queue_destroy) (MetaWindowActor *actor); - void (*set_frozen) (MetaWindowActor *actor, - gboolean frozen); - void (*update_regions) (MetaWindowActor *actor); - gboolean (*can_freeze_commits) (MetaWindowActor *actor); -}; - -typedef enum -{ - META_WINDOW_ACTOR_CHANGE_SIZE = 1 << 0, - META_WINDOW_ACTOR_CHANGE_POSITION = 1 << 1 -} MetaWindowActorChanges; - -void meta_window_actor_queue_destroy (MetaWindowActor *self); - -void meta_window_actor_show (MetaWindowActor *self, - MetaCompEffect effect); -void meta_window_actor_hide (MetaWindowActor *self, - MetaCompEffect effect); - -void meta_window_actor_size_change (MetaWindowActor *self, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect); - -void meta_window_actor_before_paint (MetaWindowActor *self, - ClutterStageView *stage_view); -void meta_window_actor_after_paint (MetaWindowActor *self, - ClutterStageView *stage_view); -void meta_window_actor_frame_complete (MetaWindowActor *self, - ClutterFrameInfo *frame_info, - gint64 presentation_time); - -gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self); - -MetaWindowActorChanges meta_window_actor_sync_actor_geometry (MetaWindowActor *self, - gboolean did_placement); - -void meta_window_actor_update_opacity (MetaWindowActor *self); -void meta_window_actor_mapped (MetaWindowActor *self); -void meta_window_actor_unmapped (MetaWindowActor *self); -void meta_window_actor_sync_updates_frozen (MetaWindowActor *self); -void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, - gboolean no_delay_frame); - -void meta_window_actor_effect_completed (MetaWindowActor *actor, - MetaPluginEffect event); - -MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self); - -void meta_window_actor_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor); - -MetaWindowActor *meta_window_actor_from_window (MetaWindow *window); -MetaWindowActor *meta_window_actor_from_actor (ClutterActor *actor); - -void meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor, - int geometry_scale); - -int meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor); - -void meta_window_actor_notify_damaged (MetaWindowActor *window_actor); - -gboolean meta_window_actor_is_frozen (MetaWindowActor *self); - -gboolean meta_window_actor_is_opaque (MetaWindowActor *self); - -void meta_window_actor_update_regions (MetaWindowActor *self); - -gboolean meta_window_actor_can_freeze_commits (MetaWindowActor *self); - -#endif /* META_WINDOW_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c deleted file mode 100644 index b1fe61641..000000000 --- a/src/compositor/meta-window-actor-wayland.c +++ /dev/null @@ -1,171 +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 "compositor/meta-surface-actor-wayland.h" -#include "compositor/meta-window-actor-wayland.h" -#include "meta/meta-window-actor.h" -#include "wayland/meta-wayland-surface.h" - -struct _MetaWindowActorWayland -{ - MetaWindowActor parent; -}; - -G_DEFINE_TYPE (MetaWindowActorWayland, meta_window_actor_wayland, META_TYPE_WINDOW_ACTOR) - -typedef struct _SurfaceTreeTraverseData -{ - MetaWindowActor *window_actor; - int index; -} SurfaceTreeTraverseData; - -static gboolean -set_surface_actor_index (GNode *node, - gpointer data) -{ - MetaWaylandSurface *surface = node->data; - MetaSurfaceActor *surface_actor = meta_wayland_surface_get_actor (surface); - SurfaceTreeTraverseData *traverse_data = data; - - if (clutter_actor_contains (CLUTTER_ACTOR (traverse_data->window_actor), - CLUTTER_ACTOR (surface_actor))) - { - clutter_actor_set_child_at_index ( - CLUTTER_ACTOR (traverse_data->window_actor), - CLUTTER_ACTOR (surface_actor), - traverse_data->index); - } - else - { - clutter_actor_insert_child_at_index ( - CLUTTER_ACTOR (traverse_data->window_actor), - CLUTTER_ACTOR (surface_actor), - traverse_data->index); - } - traverse_data->index++; - - return FALSE; -} - -void -meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor) -{ - MetaSurfaceActor *surface_actor = - meta_window_actor_get_surface (actor); - MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface ( - META_SURFACE_ACTOR_WAYLAND (surface_actor)); - GNode *root_node = surface->subsurface_branch_node; - SurfaceTreeTraverseData traverse_data; - - traverse_data = (SurfaceTreeTraverseData) { - .window_actor = actor, - .index = 0, - }; - g_node_traverse (root_node, - G_IN_ORDER, - G_TRAVERSE_LEAVES, - -1, - set_surface_actor_index, - &traverse_data); -} - -static void -meta_window_actor_wayland_assign_surface_actor (MetaWindowActor *actor, - MetaSurfaceActor *surface_actor) -{ - MetaWindowActorClass *parent_class = - META_WINDOW_ACTOR_CLASS (meta_window_actor_wayland_parent_class); - - g_warn_if_fail (!meta_window_actor_get_surface (actor)); - - parent_class->assign_surface_actor (actor, surface_actor); - - meta_window_actor_wayland_rebuild_surface_tree (actor); -} - -static void -meta_window_actor_wayland_frame_complete (MetaWindowActor *actor, - ClutterFrameInfo *frame_info, - int64_t presentation_time) -{ -} - -static void -meta_window_actor_wayland_queue_frame_drawn (MetaWindowActor *actor, - gboolean skip_sync_delay) -{ -} - -static void -meta_window_actor_wayland_before_paint (MetaWindowActor *actor, - ClutterStageView *stage_view) -{ -} - -static void -meta_window_actor_wayland_after_paint (MetaWindowActor *actor, - ClutterStageView *stage_view) -{ -} - -static void -meta_window_actor_wayland_queue_destroy (MetaWindowActor *actor) -{ -} - -static void -meta_window_actor_wayland_set_frozen (MetaWindowActor *actor, - gboolean frozen) -{ -} - -static void -meta_window_actor_wayland_update_regions (MetaWindowActor *actor) -{ -} - -static gboolean -meta_window_actor_wayland_can_freeze_commits (MetaWindowActor *actor) -{ - return FALSE; -} - -static void -meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass) -{ - MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass); - - window_actor_class->assign_surface_actor = meta_window_actor_wayland_assign_surface_actor; - window_actor_class->frame_complete = meta_window_actor_wayland_frame_complete; - window_actor_class->queue_frame_drawn = meta_window_actor_wayland_queue_frame_drawn; - window_actor_class->before_paint = meta_window_actor_wayland_before_paint; - window_actor_class->after_paint = meta_window_actor_wayland_after_paint; - window_actor_class->queue_destroy = meta_window_actor_wayland_queue_destroy; - window_actor_class->set_frozen = meta_window_actor_wayland_set_frozen; - window_actor_class->update_regions = meta_window_actor_wayland_update_regions; - window_actor_class->can_freeze_commits = meta_window_actor_wayland_can_freeze_commits; -} - -static void -meta_window_actor_wayland_init (MetaWindowActorWayland *self) -{ -} diff --git a/src/compositor/meta-window-actor-wayland.h b/src/compositor/meta-window-actor-wayland.h deleted file mode 100644 index d94de8106..000000000 --- a/src/compositor/meta-window-actor-wayland.h +++ /dev/null @@ -1,37 +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> - */ - -#ifndef META_WINDOW_ACTOR_WAYLAND_H -#define META_WINDOW_ACTOR_WAYLAND_H - -#include "compositor/meta-window-actor-private.h" -#include "wayland/meta-wayland-surface.h" - -#define META_TYPE_WINDOW_ACTOR_WAYLAND (meta_window_actor_wayland_get_type()) -G_DECLARE_FINAL_TYPE (MetaWindowActorWayland, - meta_window_actor_wayland, - META, WINDOW_ACTOR_WAYLAND, - MetaWindowActor) - -void meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor); - -#endif /*META_WINDOW_ACTOR_WAYLAND_H */ 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); -} diff --git a/src/compositor/meta-window-actor-x11.h b/src/compositor/meta-window-actor-x11.h deleted file mode 100644 index 86b80034d..000000000 --- a/src/compositor/meta-window-actor-x11.h +++ /dev/null @@ -1,47 +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> - */ - -#ifndef META_WINDOW_ACTOR_X11_H -#define META_WINDOW_ACTOR_X11_H - -#include "compositor/meta-window-actor-private.h" - -#define META_TYPE_WINDOW_ACTOR_X11 (meta_window_actor_x11_get_type()) -G_DECLARE_FINAL_TYPE (MetaWindowActorX11, - meta_window_actor_x11, - META, WINDOW_ACTOR_X11, - MetaWindowActor) - -void meta_window_actor_x11_process_x11_damage (MetaWindowActorX11 *actor_x11, - XDamageNotifyEvent *event); - -gboolean meta_window_actor_x11_should_unredirect (MetaWindowActorX11 *actor_x11); - -void meta_window_actor_x11_set_unredirected (MetaWindowActorX11 *actor_x11, - gboolean unredirected); - -void meta_window_actor_x11_update_shape (MetaWindowActorX11 *actor_x11); - -void meta_window_actor_x11_process_damage (MetaWindowActorX11 *actor_x11, - XDamageNotifyEvent *event); - -#endif /* META_WINDOW_ACTOR_X11_H */ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c deleted file mode 100644 index d4fc9a43a..000000000 --- a/src/compositor/meta-window-actor.c +++ /dev/null @@ -1,1559 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/** - * SECTION:meta-window-actor - * @title: MetaWindowActor - * @short_description: An actor representing a top-level window in the scene - * graph - * - * #MetaWindowActor is a #ClutterActor that adds a notion of a window to the - * Clutter scene graph. It contains a #MetaWindow which provides the windowing - * API, and the #MetaCompositor that handles it. For the actual content of the - * window, it contains a #MetaSurfaceActor. - * - * #MetaWindowActor takes care of the rendering features you need for your - * window. For example, it will take the windows' requested opacity and use - * that for clutter_actor_set_opacity(). Furthermore, it will also draw a - * shadow around the window (using #MetaShadow) and deal with synchronization - * between events of the window and the actual render loop. See - * MetaWindowActor::first-frame for an example of the latter. - */ - -#include "config.h" - -#include <gdk/gdk.h> -#include <math.h> -#include <string.h> - -#include "backends/meta-screen-cast-window.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-shaped-texture-private.h" -#include "compositor/meta-surface-actor-x11.h" -#include "compositor/meta-surface-actor.h" -#include "compositor/meta-window-actor-private.h" -#include "core/boxes-private.h" -#include "core/window-private.h" -#include "meta/window.h" - -#ifdef HAVE_WAYLAND -#include "compositor/meta-surface-actor-wayland.h" -#include "wayland/meta-wayland-surface.h" -#endif - -typedef enum -{ - INITIALLY_FROZEN, - DRAWING_FIRST_FRAME, - EMITTED_FIRST_FRAME -} FirstFrameState; - -typedef struct _MetaWindowActorPrivate -{ - MetaWindow *window; - MetaCompositor *compositor; - - MetaSurfaceActor *surface; - - int geometry_scale; - - /* - * These need to be counters rather than flags, since more plugins - * can implement same effect; the practicality of stacking effects - * might be dubious, but we have to at least handle it correctly. - */ - gint minimize_in_progress; - gint unminimize_in_progress; - gint size_change_in_progress; - gint map_in_progress; - gint destroy_in_progress; - - guint freeze_count; - - guint visible : 1; - guint disposed : 1; - - guint needs_destroy : 1; - - guint updates_frozen : 1; - guint first_frame_state : 2; /* FirstFrameState */ -} MetaWindowActorPrivate; - -enum -{ - FIRST_FRAME, - EFFECTS_COMPLETED, - DAMAGED, - THAWED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -enum -{ - PROP_META_WINDOW = 1, -}; - -static void meta_window_actor_dispose (GObject *object); -static void meta_window_actor_constructed (GObject *object); -static void meta_window_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void meta_window_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void meta_window_actor_real_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor); - -static void cullable_iface_init (MetaCullableInterface *iface); - -static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface); - -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR, - G_ADD_PRIVATE (MetaWindowActor) - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init) - G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init)); - -static void -meta_window_actor_class_init (MetaWindowActorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->dispose = meta_window_actor_dispose; - object_class->set_property = meta_window_actor_set_property; - object_class->get_property = meta_window_actor_get_property; - object_class->constructed = meta_window_actor_constructed; - - klass->assign_surface_actor = meta_window_actor_real_assign_surface_actor; - - /** - * MetaWindowActor::first-frame: - * @actor: the #MetaWindowActor instance - * - * The ::first-frame signal will be emitted the first time a frame - * of window contents has been drawn by the application and Mutter - * has had the chance to drawn that frame to the screen. If the - * window starts off initially hidden, obscured, or on on a - * different workspace, the ::first-frame signal will be emitted - * even though the user doesn't see the contents. - * - * MetaDisplay::window-created is a good place to connect to this - * signal - at that point, the MetaWindowActor for the window - * exists, but the window has reliably not yet been drawn. - * Connecting to an existing window that has already been drawn to - * the screen is not useful. - */ - signals[FIRST_FRAME] = - g_signal_new ("first-frame", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::effects-completed: - * @actor: the #MetaWindowActor instance - * - * The ::effects-completed signal will be emitted once all pending compositor - * effects are completed. - */ - signals[EFFECTS_COMPLETED] = - g_signal_new ("effects-completed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::damaged: - * @actor: the #MetaWindowActor instance - * - * Notify that one or more of the surfaces of the window have been damaged. - */ - signals[DAMAGED] = - g_signal_new ("damaged", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - /** - * MetaWindowActor::thawed: - * @actor: the #MetaWindowActor instance - */ - signals[THAWED] = - g_signal_new ("thawed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - pspec = g_param_spec_object ("meta-window", - "MetaWindow", - "The displayed MetaWindow", - META_TYPE_WINDOW, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, - PROP_META_WINDOW, - pspec); -} - -static void -meta_window_actor_init (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - priv->geometry_scale = 1; -} - -static void -window_appears_focused_notify (MetaWindow *mw, - GParamSpec *arg1, - gpointer data) -{ - clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); -} - -gboolean -meta_window_actor_is_opaque (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - if (window->opacity != 0xff) - return FALSE; - - if (!priv->surface) - return FALSE; - - return meta_surface_actor_is_opaque (priv->surface); -} - -gboolean -meta_window_actor_is_frozen (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->surface == NULL || priv->freeze_count > 0; -} - -void -meta_window_actor_update_regions (MetaWindowActor *self) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->update_regions (self); -} - -gboolean -meta_window_actor_can_freeze_commits (MetaWindowActor *self) -{ - g_return_val_if_fail (META_IS_WINDOW_ACTOR (self), FALSE); - - return META_WINDOW_ACTOR_GET_CLASS (self)->can_freeze_commits (self); -} - -static void -meta_window_actor_set_frozen (MetaWindowActor *self, - gboolean frozen) -{ - ClutterActor *child; - ClutterActorIter iter; - - clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self)); - while (clutter_actor_iter_next (&iter, &child)) - { - if (META_IS_SURFACE_ACTOR (child)) - meta_surface_actor_set_frozen (META_SURFACE_ACTOR (child), frozen); - } - - META_WINDOW_ACTOR_GET_CLASS (self)->set_frozen (self, frozen); -} - -/** - * meta_window_actor_freeze: - * @self: The #MetaWindowActor - * - * Freezes the #MetaWindowActor, which inhibits updates and geometry - * changes of the window. This property is refcounted, so make sure - * to call meta_window_actor_thaw() the exact same amount of times - * as this function to allow updates again. - */ -void -meta_window_actor_freeze (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv; - - g_return_if_fail (META_IS_WINDOW_ACTOR (self)); - - priv = meta_window_actor_get_instance_private (self); - - if (priv->freeze_count == 0 && priv->surface) - meta_window_actor_set_frozen (self, TRUE); - - priv->freeze_count ++; -} - -static void -meta_window_actor_sync_thawed_state (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (priv->first_frame_state == INITIALLY_FROZEN) - priv->first_frame_state = DRAWING_FIRST_FRAME; - - if (priv->surface) - meta_window_actor_set_frozen (self, FALSE); - - /* We sometimes ignore moves and resizes on frozen windows */ - meta_window_actor_sync_actor_geometry (self, FALSE); -} - -/** - * meta_window_actor_thaw: - * @self: The #MetaWindowActor - * - * Thaws/unfreezes the #MetaWindowActor to allow updates and geometry - * changes after a window was frozen using meta_window_actor_freeze(). - */ -void -meta_window_actor_thaw (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv; - - g_return_if_fail (META_IS_WINDOW_ACTOR (self)); - - priv = meta_window_actor_get_instance_private (self); - - if (priv->freeze_count <= 0) - g_error ("Error in freeze/thaw accounting"); - - priv->freeze_count--; - if (priv->freeze_count > 0) - return; - - /* We still might be frozen due to lack of a MetaSurfaceActor */ - if (meta_window_actor_is_frozen (self)) - return; - - meta_window_actor_sync_thawed_state (self); - - g_signal_emit (self, signals[THAWED], 0); -} - -static void -meta_window_actor_real_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - g_clear_object (&priv->surface); - priv->surface = g_object_ref_sink (surface_actor); - - if (meta_window_actor_is_frozen (self)) - meta_window_actor_set_frozen (self, TRUE); - else - meta_window_actor_sync_thawed_state (self); -} - -void -meta_window_actor_assign_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface_actor) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->assign_surface_actor (self, - surface_actor); -} - -static void -init_surface_actor (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - MetaSurfaceActor *surface_actor; - - if (!meta_is_wayland_compositor ()) - surface_actor = meta_surface_actor_x11_new (window); -#ifdef HAVE_WAYLAND - else if (window->surface) - surface_actor = meta_wayland_surface_get_actor (window->surface); -#endif - else - surface_actor = NULL; - - if (surface_actor) - meta_window_actor_assign_surface_actor (self, surface_actor); -} - -static void -meta_window_actor_constructed (GObject *object) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - priv->compositor = window->display->compositor; - - /* Hang our compositor window state off the MetaWindow for fast retrieval */ - meta_window_set_compositor_private (window, object); - - init_surface_actor (self); - - meta_window_actor_update_opacity (self); - - meta_window_actor_sync_updates_frozen (self); - - if (meta_window_actor_is_frozen (self)) - priv->first_frame_state = INITIALLY_FROZEN; - else - priv->first_frame_state = DRAWING_FIRST_FRAME; - - meta_window_actor_sync_actor_geometry (self, priv->window->placed); -} - -static void -meta_window_actor_dispose (GObject *object) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - - if (priv->disposed) - { - G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - - meta_compositor_remove_window_actor (compositor, self); - - g_clear_object (&priv->window); - - if (priv->surface) - { - clutter_actor_remove_child (CLUTTER_ACTOR (self), - CLUTTER_ACTOR (priv->surface)); - g_clear_object (&priv->surface); - } - - G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); -} - -static void -meta_window_actor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_META_WINDOW: - priv->window = g_value_dup_object (value); - g_signal_connect_object (priv->window, "notify::appears-focused", - G_CALLBACK (window_appears_focused_notify), self, 0); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_window_actor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - switch (prop_id) - { - case PROP_META_WINDOW: - g_value_set_object (value, priv->window); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/** - * meta_window_actor_get_meta_window: - * @self: a #MetaWindowActor - * - * Gets the #MetaWindow object that the the #MetaWindowActor is displaying - * - * Return value: (transfer none): the displayed #MetaWindow - */ -MetaWindow * -meta_window_actor_get_meta_window (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->window; -} - -/** - * meta_window_actor_get_texture: - * @self: a #MetaWindowActor - * - * Gets the ClutterActor that is used to display the contents of the window, - * or NULL if no texture is shown yet, because the window is not mapped. - * - * Return value: (transfer none): the #ClutterActor for the contents - */ -MetaShapedTexture * -meta_window_actor_get_texture (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (priv->surface) - return meta_surface_actor_get_texture (priv->surface); - else - return NULL; -} - -/** - * meta_window_actor_get_surface: - * @self: a #MetaWindowActor - * - * Gets the MetaSurfaceActor that draws the content of this window, - * or NULL if there is no surface yet associated with this window. - * - * Return value: (transfer none): the #MetaSurfaceActor for the contents - */ -MetaSurfaceActor * -meta_window_actor_get_surface (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->surface; -} - -/** - * meta_window_actor_is_destroyed: - * @self: a #MetaWindowActor - * - * Gets whether the X window that the actor was displaying has been destroyed - * - * Return value: %TRUE when the window is destroyed, otherwise %FALSE - */ -gboolean -meta_window_actor_is_destroyed (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return priv->disposed || priv->needs_destroy; -} - -void -meta_window_actor_queue_frame_drawn (MetaWindowActor *self, - gboolean no_delay_frame) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->queue_frame_drawn (self, - no_delay_frame); -} - -gboolean -meta_window_actor_effect_in_progress (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - return (priv->minimize_in_progress || - priv->size_change_in_progress || - priv->map_in_progress || - priv->destroy_in_progress); -} - -static gboolean -is_freeze_thaw_effect (MetaPluginEffect event) -{ - switch (event) - { - case META_PLUGIN_DESTROY: - return TRUE; - break; - default: - return FALSE; - } -} - -static gboolean -start_simple_effect (MetaWindowActor *self, - MetaPluginEffect event) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginManager *plugin_mgr = - meta_compositor_get_plugin_manager (compositor); - gint *counter = NULL; - gboolean use_freeze_thaw = FALSE; - - g_assert (plugin_mgr != NULL); - - switch (event) - { - case META_PLUGIN_NONE: - return FALSE; - case META_PLUGIN_MINIMIZE: - counter = &priv->minimize_in_progress; - break; - case META_PLUGIN_UNMINIMIZE: - counter = &priv->unminimize_in_progress; - break; - case META_PLUGIN_MAP: - counter = &priv->map_in_progress; - break; - case META_PLUGIN_DESTROY: - counter = &priv->destroy_in_progress; - break; - case META_PLUGIN_SIZE_CHANGE: - case META_PLUGIN_SWITCH_WORKSPACE: - g_assert_not_reached (); - break; - } - - g_assert (counter); - - use_freeze_thaw = is_freeze_thaw_effect (event); - - if (use_freeze_thaw) - meta_window_actor_freeze (self); - - (*counter)++; - - if (!meta_plugin_manager_event_simple (plugin_mgr, self, event)) - { - (*counter)--; - if (use_freeze_thaw) - meta_window_actor_thaw (self); - return FALSE; - } - - return TRUE; -} - -static void -meta_window_actor_after_effects (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - ClutterStage *stage; - ClutterSeat *seat; - - stage = CLUTTER_STAGE (clutter_actor_get_stage (CLUTTER_ACTOR (self))); - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - - if (priv->needs_destroy) - { - clutter_actor_destroy (CLUTTER_ACTOR (self)); - } - else - { - g_signal_emit (self, signals[EFFECTS_COMPLETED], 0); - meta_window_actor_sync_visibility (self); - meta_window_actor_sync_actor_geometry (self, FALSE); - } - - clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat)); -} - -void -meta_window_actor_effect_completed (MetaWindowActor *self, - MetaPluginEffect event) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - gboolean inconsistent = FALSE; - - /* NB: Keep in mind that when effects get completed it possible - * that the corresponding MetaWindow may have be been destroyed. - * In this case priv->window will == NULL */ - - switch (event) - { - case META_PLUGIN_NONE: - break; - case META_PLUGIN_MINIMIZE: - { - priv->minimize_in_progress--; - if (priv->minimize_in_progress < 0) - { - g_warning ("Error in minimize accounting."); - priv->minimize_in_progress = 0; - inconsistent = TRUE; - } - } - break; - case META_PLUGIN_UNMINIMIZE: - { - priv->unminimize_in_progress--; - if (priv->unminimize_in_progress < 0) - { - g_warning ("Error in unminimize accounting."); - priv->unminimize_in_progress = 0; - inconsistent = TRUE; - } - } - break; - case META_PLUGIN_MAP: - /* - * Make sure that the actor is at the correct place in case - * the plugin fscked. - */ - priv->map_in_progress--; - - if (priv->map_in_progress < 0) - { - g_warning ("Error in map accounting."); - priv->map_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_DESTROY: - priv->destroy_in_progress--; - - if (priv->destroy_in_progress < 0) - { - g_warning ("Error in destroy accounting."); - priv->destroy_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_SIZE_CHANGE: - priv->size_change_in_progress--; - if (priv->size_change_in_progress < 0) - { - g_warning ("Error in size change accounting."); - priv->size_change_in_progress = 0; - inconsistent = TRUE; - } - break; - case META_PLUGIN_SWITCH_WORKSPACE: - g_assert_not_reached (); - break; - } - - if (is_freeze_thaw_effect (event) && !inconsistent) - meta_window_actor_thaw (self); - - if (!meta_window_actor_effect_in_progress (self)) - meta_window_actor_after_effects (self); -} - -void -meta_window_actor_queue_destroy (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - MetaWindowType window_type = meta_window_get_window_type (window); - - meta_window_set_compositor_private (window, NULL); - - META_WINDOW_ACTOR_GET_CLASS (self)->queue_destroy (self); - - if (window_type == META_WINDOW_DROPDOWN_MENU || - window_type == META_WINDOW_POPUP_MENU || - window_type == META_WINDOW_TOOLTIP || - window_type == META_WINDOW_NOTIFICATION || - window_type == META_WINDOW_COMBO || - window_type == META_WINDOW_DND || - window_type == META_WINDOW_OVERRIDE_OTHER) - { - /* - * No effects, just kill it. - */ - clutter_actor_destroy (CLUTTER_ACTOR (self)); - return; - } - - priv->needs_destroy = TRUE; - - if (!meta_window_actor_effect_in_progress (self)) - clutter_actor_destroy (CLUTTER_ACTOR (self)); -} - -MetaWindowActorChanges -meta_window_actor_sync_actor_geometry (MetaWindowActor *self, - gboolean did_placement) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaRectangle window_rect; - ClutterActor *actor = CLUTTER_ACTOR (self); - MetaWindowActorChanges changes = 0; - - meta_window_get_buffer_rect (priv->window, &window_rect); - - /* When running as a Wayland compositor we catch size changes when new - * buffers are attached */ - if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) - meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface), - window_rect.width, window_rect.height); - - /* Normally we want freezing a window to also freeze its position; this allows - * windows to atomically move and resize together, either under app control, - * or because the user is resizing from the left/top. But on initial placement - * we need to assign a position, since immediately after the window - * is shown, the map effect will go into effect and prevent further geometry - * updates. - */ - if (meta_window_actor_is_frozen (self) && !did_placement) - return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE; - - if (clutter_actor_has_allocation (actor)) - { - ClutterActorBox box; - float old_x, old_y; - float old_width, old_height; - - clutter_actor_get_allocation_box (actor, &box); - - old_x = box.x1; - old_y = box.y1; - old_width = box.x2 - box.x1; - old_height = box.y2 - box.y1; - - if (old_x != window_rect.x || old_y != window_rect.y) - changes |= META_WINDOW_ACTOR_CHANGE_POSITION; - - if (old_width != window_rect.width || old_height != window_rect.height) - changes |= META_WINDOW_ACTOR_CHANGE_SIZE; - } - else - { - changes = META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE; - } - - if (changes & META_WINDOW_ACTOR_CHANGE_POSITION) - clutter_actor_set_position (actor, window_rect.x, window_rect.y); - - if (changes & META_WINDOW_ACTOR_CHANGE_SIZE) - clutter_actor_set_size (actor, window_rect.width, window_rect.height); - - return changes; -} - -void -meta_window_actor_show (MetaWindowActor *self, - MetaCompEffect effect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginEffect event; - - g_return_if_fail (!priv->visible); - - priv->visible = TRUE; - - switch (effect) - { - case META_COMP_EFFECT_CREATE: - event = META_PLUGIN_MAP; - break; - case META_COMP_EFFECT_UNMINIMIZE: - event = META_PLUGIN_UNMINIMIZE; - break; - case META_COMP_EFFECT_NONE: - event = META_PLUGIN_NONE; - break; - default: - g_assert_not_reached(); - } - - if (event == META_PLUGIN_MAP) - meta_window_actor_sync_actor_geometry (self, TRUE); - - if (meta_compositor_is_switching_workspace (compositor) || - !start_simple_effect (self, event)) - { - clutter_actor_show (CLUTTER_ACTOR (self)); - } -} - -void -meta_window_actor_hide (MetaWindowActor *self, - MetaCompEffect effect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginEffect event; - - g_return_if_fail (priv->visible); - - priv->visible = FALSE; - - /* If a plugin is animating a workspace transition, we have to - * hold off on hiding the window, and do it after the workspace - * switch completes - */ - if (meta_compositor_is_switching_workspace (compositor)) - return; - - switch (effect) - { - case META_COMP_EFFECT_DESTROY: - event = META_PLUGIN_DESTROY; - break; - case META_COMP_EFFECT_MINIMIZE: - event = META_PLUGIN_MINIMIZE; - break; - case META_COMP_EFFECT_NONE: - event = META_PLUGIN_NONE; - break; - default: - g_assert_not_reached(); - } - - if (!start_simple_effect (self, event)) - clutter_actor_hide (CLUTTER_ACTOR (self)); -} - -void -meta_window_actor_size_change (MetaWindowActor *self, - MetaSizeChange which_change, - MetaRectangle *old_frame_rect, - MetaRectangle *old_buffer_rect) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaCompositor *compositor = priv->compositor; - MetaPluginManager *plugin_mgr = - meta_compositor_get_plugin_manager (compositor); - - priv->size_change_in_progress++; - - if (!meta_plugin_manager_event_size_change (plugin_mgr, self, - which_change, old_frame_rect, old_buffer_rect)) - priv->size_change_in_progress--; -} - -#if 0 -/* Print out a region; useful for debugging */ -static void -print_region (cairo_region_t *region) -{ - int n_rects; - int i; - - n_rects = cairo_region_num_rectangles (region); - g_print ("["); - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - g_print ("+%d+%dx%dx%d ", - rect.x, rect.y, rect.width, rect.height); - } - g_print ("]\n"); -} -#endif - -#if 0 -/* Dump a region to a PNG file; useful for debugging */ -static void -see_region (cairo_region_t *region, - int width, - int height, - char *filename) -{ - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); - cairo_t *cr = cairo_create (surface); - - gdk_cairo_region (cr, region); - cairo_fill (cr); - - cairo_surface_write_to_png (surface, filename); - cairo_destroy (cr); - cairo_surface_destroy (surface); -} -#endif - - -static void -meta_window_actor_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); -} - -static void -meta_window_actor_reset_culling (MetaCullable *cullable) -{ - meta_cullable_reset_culling_children (cullable); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_window_actor_cull_out; - iface->reset_culling = meta_window_actor_reset_culling; -} - -void -meta_window_actor_sync_visibility (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible) - { - if (priv->visible) - clutter_actor_show (CLUTTER_ACTOR (self)); - else - clutter_actor_hide (CLUTTER_ACTOR (self)); - } -} - -void -meta_window_actor_before_paint (MetaWindowActor *self, - ClutterStageView *stage_view) -{ - if (meta_window_actor_is_destroyed (self)) - return; - - META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self, stage_view); -} - -void -meta_window_actor_after_paint (MetaWindowActor *self, - ClutterStageView *stage_view) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - META_WINDOW_ACTOR_GET_CLASS (self)->after_paint (self, stage_view); - - if (meta_window_actor_is_destroyed (self)) - return; - - if (priv->first_frame_state == DRAWING_FIRST_FRAME) - { - priv->first_frame_state = EMITTED_FIRST_FRAME; - g_signal_emit (self, signals[FIRST_FRAME], 0); - } -} - -void -meta_window_actor_frame_complete (MetaWindowActor *self, - ClutterFrameInfo *frame_info, - gint64 presentation_time) -{ - META_WINDOW_ACTOR_GET_CLASS (self)->frame_complete (self, - frame_info, - presentation_time); -} - -void -meta_window_actor_update_opacity (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - if (priv->surface) - clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity); -} - -static void -meta_window_actor_set_updates_frozen (MetaWindowActor *self, - gboolean updates_frozen) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - - updates_frozen = updates_frozen != FALSE; - - if (priv->updates_frozen != updates_frozen) - { - priv->updates_frozen = updates_frozen; - if (updates_frozen) - meta_window_actor_freeze (self); - else - meta_window_actor_thaw (self); - } -} - -void -meta_window_actor_sync_updates_frozen (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; - - meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window)); -} - -MetaWindowActor * -meta_window_actor_from_window (MetaWindow *window) -{ - return META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); -} - -void -meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor, - int geometry_scale) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - graphene_matrix_t child_transform; - - if (priv->geometry_scale == geometry_scale) - return; - - priv->geometry_scale = geometry_scale; - - graphene_matrix_init_scale (&child_transform, - geometry_scale, - geometry_scale, - 1); - clutter_actor_set_child_transform (CLUTTER_ACTOR (window_actor), - &child_transform); -} - -int -meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor) -{ - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - - return priv->geometry_scale; -} - -static void -meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaShapedTexture *stex; - int buffer_scale; - - stex = meta_surface_actor_get_texture (priv->surface); - buffer_scale = meta_shaped_texture_get_buffer_scale (stex); - *bounds = (MetaRectangle) { - .width = meta_shaped_texture_get_width (stex) * buffer_scale, - .height = meta_shaped_texture_get_height (stex) * buffer_scale, - }; -} - -static void -meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast_window, - double x, - double y, - double *x_out, - double *y_out) - -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaRectangle bounds; - graphene_point3d_t v1 = { 0.f, }, v2 = { 0.f, }; - - meta_window_actor_get_buffer_bounds (screen_cast_window, &bounds); - - v1.x = CLAMP ((float) x, - bounds.x, - bounds.x + bounds.width); - v1.y = CLAMP ((float) y, - bounds.y, - bounds.y + bounds.height); - - clutter_actor_apply_transform_to_point (CLUTTER_ACTOR (priv->surface), - &v1, - &v2); - - *x_out = (double) v2.x; - *y_out = (double) v2.y; -} - -static gboolean -meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_window, - MetaCursorSprite *cursor_sprite, - graphene_point_t *cursor_position, - float *out_cursor_scale, - graphene_point_t *out_relative_cursor_position) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (window_actor); - MetaWindow *window; - - window = priv->window; - if (!meta_window_has_pointer (window)) - return FALSE; - - if (cursor_sprite && - meta_cursor_sprite_get_cogl_texture (cursor_sprite) && - out_cursor_scale) - { - MetaShapedTexture *stex; - double texture_scale; - float cursor_texture_scale; - - stex = meta_surface_actor_get_texture (priv->surface); - texture_scale = meta_shaped_texture_get_buffer_scale (stex); - cursor_texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); - - *out_cursor_scale = texture_scale / cursor_texture_scale; - } - - if (out_relative_cursor_position) - { - clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->surface), - cursor_position->x, - cursor_position->y, - &out_relative_cursor_position->x, - &out_relative_cursor_position->y); - } - - return TRUE; -} - -static void -meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds, - uint8_t *data) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - cairo_surface_t *image; - uint8_t *cr_data; - int cr_stride; - int cr_width; - int cr_height; - int bpp = 4; - - if (meta_window_actor_is_destroyed (window_actor)) - return; - - image = meta_window_actor_get_image (window_actor, bounds); - cr_data = cairo_image_surface_get_data (image); - cr_width = cairo_image_surface_get_width (image); - cr_height = cairo_image_surface_get_height (image); - cr_stride = cairo_image_surface_get_stride (image); - - if (cr_width == bounds->width && cr_height == bounds->height) - { - memcpy (data, cr_data, cr_height * cr_stride); - } - else - { - int width = MIN (bounds->width, cr_width); - int height = MIN (bounds->height, cr_height); - int stride = width * bpp; - uint8_t *src, *dst; - - src = cr_data; - dst = data; - - for (int i = 0; i < height; i++) - { - memcpy (dst, src, stride); - if (width < bounds->width) - memset (dst + stride, 0, (bounds->width * bpp) - stride); - - src += cr_stride; - dst += bounds->width * bpp; - } - - for (int i = height; i < bounds->height; i++) - { - memset (dst, 0, bounds->width * bpp); - dst += bounds->width * bpp; - } - } - - cairo_surface_destroy (image); -} - -static gboolean -meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds, - CoglFramebuffer *framebuffer) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - ClutterPaintContext *paint_context; - MetaRectangle scaled_clip; - CoglColor clear_color; - float resource_scale; - float width, height; - float x, y; - - if (meta_window_actor_is_destroyed (window_actor)) - return FALSE; - - clutter_actor_get_size (actor, &width, &height); - - if (width == 0 || height == 0) - return FALSE; - - resource_scale = clutter_actor_get_resource_scale (actor); - - clutter_actor_inhibit_culling (actor); - - width = ceilf (width * resource_scale); - height = ceilf (height * resource_scale); - - clutter_actor_get_position (actor, &x, &y); - - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); - cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); - cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height); - - meta_rectangle_scale_double (bounds, resource_scale, - META_ROUNDING_STRATEGY_GROW, - &scaled_clip); - meta_rectangle_intersect (&scaled_clip, - &(MetaRectangle) { - .width = width, - .height = height, - }, - &scaled_clip); - - cogl_framebuffer_push_rectangle_clip (framebuffer, - scaled_clip.x, scaled_clip.y, - scaled_clip.x + scaled_clip.width, - scaled_clip.y + scaled_clip.height); - - cogl_framebuffer_push_matrix (framebuffer); - cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); - cogl_framebuffer_translate (framebuffer, -x, -y, 0); - - paint_context = - clutter_paint_context_new_for_framebuffer (framebuffer, NULL, - CLUTTER_PAINT_FLAG_NONE); - clutter_actor_paint (actor, paint_context); - clutter_paint_context_destroy (paint_context); - - cogl_framebuffer_pop_matrix (framebuffer); - cogl_framebuffer_pop_clip (framebuffer); - - clutter_actor_uninhibit_culling (actor); - - return TRUE; -} - -static gboolean -meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window) -{ - return clutter_actor_has_damage (CLUTTER_ACTOR (screen_cast_window)); -} - -static void -screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface) -{ - iface->get_buffer_bounds = meta_window_actor_get_buffer_bounds; - iface->transform_relative_position = meta_window_actor_transform_relative_position; - iface->transform_cursor_position = meta_window_actor_transform_cursor_position; - iface->capture_into = meta_window_actor_capture_into; - iface->blit_to_framebuffer = meta_window_actor_blit_to_framebuffer; - iface->has_damage = meta_window_actor_has_damage; -} - -MetaWindowActor * -meta_window_actor_from_actor (ClutterActor *actor) -{ - if (!META_IS_SURFACE_ACTOR (actor)) - return NULL; - - do - { - actor = clutter_actor_get_parent (actor); - - if (META_IS_WINDOW_ACTOR (actor)) - return META_WINDOW_ACTOR (actor); - } - while (actor != NULL); - - return NULL; -} - -void -meta_window_actor_notify_damaged (MetaWindowActor *window_actor) -{ - g_signal_emit (window_actor, signals[DAMAGED], 0); -} - -/** - * meta_window_actor_get_image: - * @self: A #MetaWindowActor - * @clip: (nullable): A clipping rectangle, to help prevent extra processing. - * In the case that the clipping rectangle is partially or fully - * outside the bounds of the actor, the rectangle will be clipped. - * - * Flattens the layers of @self into one ARGB32 image by alpha blending - * the images, and returns the flattened image. - * - * Returns: (nullable) (transfer full): a new cairo surface to be freed with - * cairo_surface_destroy(). - */ -cairo_surface_t * -meta_window_actor_get_image (MetaWindowActor *self, - MetaRectangle *clip) -{ - MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); - ClutterActor *actor = CLUTTER_ACTOR (self); - MetaBackend *backend = meta_get_backend (); - ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - CoglContext *cogl_context = - clutter_backend_get_cogl_context (clutter_backend); - float resource_scale; - float width, height; - CoglTexture2D *texture; - g_autoptr (GError) error = NULL; - CoglOffscreen *offscreen; - CoglFramebuffer *framebuffer; - CoglColor clear_color; - float x, y; - MetaRectangle scaled_clip; - ClutterPaintContext *paint_context; - cairo_surface_t *surface = NULL; - - if (!priv->surface) - return NULL; - - clutter_actor_inhibit_culling (actor); - - if (clutter_actor_get_n_children (actor) == 1) - { - MetaShapedTexture *stex; - MetaRectangle *surface_clip = NULL; - - if (clip) - { - - int geometry_scale; - - geometry_scale = - meta_window_actor_get_geometry_scale (self); - - surface_clip = g_alloca (sizeof (MetaRectangle)); - surface_clip->x = clip->x / geometry_scale, - surface_clip->y = clip->y / geometry_scale; - surface_clip->width = clip->width / geometry_scale; - surface_clip->height = clip->height / geometry_scale; - } - - stex = meta_surface_actor_get_texture (priv->surface); - surface = meta_shaped_texture_get_image (stex, surface_clip); - goto out; - } - - clutter_actor_get_size (actor, &width, &height); - - if (width == 0 || height == 0) - goto out; - - resource_scale = clutter_actor_get_resource_scale (actor); - - width = ceilf (width * resource_scale); - height = ceilf (height * resource_scale); - - texture = cogl_texture_2d_new_with_size (cogl_context, width, height); - if (!texture) - goto out; - - cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture), - FALSE); - - offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture)); - framebuffer = COGL_FRAMEBUFFER (offscreen); - - cogl_object_unref (texture); - - if (!cogl_framebuffer_allocate (framebuffer, &error)) - { - g_warning ("Failed to allocate framebuffer for screenshot: %s", - error->message); - g_object_unref (framebuffer); - cogl_object_unref (texture); - goto out; - } - - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - clutter_actor_get_position (actor, &x, &y); - - cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); - cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); - cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); - cogl_framebuffer_translate (framebuffer, -x, -y, 0); - - paint_context = - clutter_paint_context_new_for_framebuffer (framebuffer, NULL, - CLUTTER_PAINT_FLAG_NONE); - clutter_actor_paint (actor, paint_context); - clutter_paint_context_destroy (paint_context); - - if (clip) - { - meta_rectangle_scale_double (clip, resource_scale, - META_ROUNDING_STRATEGY_GROW, - &scaled_clip); - meta_rectangle_intersect (&scaled_clip, - &(MetaRectangle) { - .width = width, - .height = height, - }, - &scaled_clip); - } - else - { - scaled_clip = (MetaRectangle) { - .width = width, - .height = height, - }; - } - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - scaled_clip.width, scaled_clip.height); - cogl_framebuffer_read_pixels (framebuffer, - scaled_clip.x, scaled_clip.y, - scaled_clip.width, scaled_clip.height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_data (surface)); - - g_object_unref (framebuffer); - - cairo_surface_mark_dirty (surface); - -out: - clutter_actor_uninhibit_culling (actor); - return surface; -} diff --git a/src/compositor/meta-window-group-private.h b/src/compositor/meta-window-group-private.h deleted file mode 100644 index c3467066b..000000000 --- a/src/compositor/meta-window-group-private.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef META_WINDOW_GROUP_PRIVATE_H -#define META_WINDOW_GROUP_PRIVATE_H - -#include "meta/display.h" -#include "meta/meta-window-group.h" - -/** - * MetaWindowGroup: - * - * This class is a subclass of ClutterActor with special handling for - * #MetaCullable when painting children. It uses code similar to - * meta_cullable_cull_out_children(), but also has additional special - * cases for the undirected window, and similar. - */ - - -typedef struct _MetaWindowGroupPrivate MetaWindowGroupPrivate; - -ClutterActor *meta_window_group_new (MetaDisplay *display); - -#endif /* META_WINDOW_GROUP_PRIVATE_H */ diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c deleted file mode 100644 index d526805fe..000000000 --- a/src/compositor/meta-window-group.c +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#include "config.h" - -#include <gdk/gdk.h> -#include <math.h> - -#include "compositor/clutter-utils.h" -#include "compositor/compositor-private.h" -#include "compositor/meta-cullable.h" -#include "compositor/meta-window-actor-private.h" -#include "compositor/meta-window-group-private.h" -#include "core/display-private.h" -#include "core/window-private.h" - -struct _MetaWindowGroupClass -{ - ClutterActorClass parent_class; -}; - -struct _MetaWindowGroup -{ - ClutterActor parent; - - MetaDisplay *display; -}; - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); - -static void -meta_window_group_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); -} - -static void -meta_window_group_reset_culling (MetaCullable *cullable) -{ - meta_cullable_reset_culling_children (cullable); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_window_group_cull_out; - iface->reset_culling = meta_window_group_reset_culling; -} - -static void -meta_window_group_paint (ClutterActor *actor, - ClutterPaintContext *paint_context) -{ - MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); - ClutterActorClass *parent_actor_class = - CLUTTER_ACTOR_CLASS (meta_window_group_parent_class); - ClutterActor *stage = clutter_actor_get_stage (actor); - const cairo_region_t *redraw_clip; - cairo_region_t *clip_region; - cairo_region_t *unobscured_region; - cairo_rectangle_int_t visible_rect; - int paint_x_origin, paint_y_origin; - int screen_width, screen_height; - - redraw_clip = clutter_paint_context_get_redraw_clip (paint_context); - if (!redraw_clip) - { - parent_actor_class->paint (actor, paint_context); - return; - } - - meta_display_get_size (window_group->display, &screen_width, &screen_height); - - /* Normally we expect an actor to be drawn at it's position on the screen. - * However, if we're inside the paint of a ClutterClone, that won't be the - * case and we need to compensate. We look at the position of the window - * group under the current model-view matrix and the position of the actor. - * If they are both simply integer translations, then we can compensate - * easily, otherwise we give up. - * - * Possible cleanup: work entirely in paint space - we can compute the - * combination of the model-view matrix with the local matrix for each child - * actor and get a total transformation for that actor for how we are - * painting currently, and never worry about how actors are positioned - * on the stage. - */ - if (clutter_actor_is_in_clone_paint (actor)) - { - CoglFramebuffer *fb; - - fb = clutter_paint_context_get_framebuffer (paint_context); - if (!meta_actor_painting_untransformed (fb, - screen_width, - screen_height, - screen_width, - screen_height, - &paint_x_origin, - &paint_y_origin) || - !meta_cullable_is_untransformed (META_CULLABLE (actor))) - { - parent_actor_class->paint (actor, paint_context); - return; - } - } - else - { - paint_x_origin = 0; - paint_y_origin = 0; - } - - visible_rect.x = visible_rect.y = 0; - visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); - - unobscured_region = cairo_region_create_rectangle (&visible_rect); - - /* Get the clipped redraw bounds so that we can avoid painting shadows on - * windows that don't need to be painted in this frame. In the case of a - * multihead setup with mismatched monitor sizes, we could intersect this - * with an accurate union of the monitors to avoid painting shadows that are - * visible only in the holes. */ - clip_region = cairo_region_copy (redraw_clip); - - cairo_region_translate (clip_region, -paint_x_origin, -paint_y_origin); - - meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region); - - cairo_region_destroy (unobscured_region); - cairo_region_destroy (clip_region); - - parent_actor_class->paint (actor, paint_context); - - meta_cullable_reset_culling (META_CULLABLE (window_group)); -} - -/* Adapted from clutter_actor_update_default_paint_volume() */ -static gboolean -meta_window_group_get_paint_volume (ClutterActor *self, - ClutterPaintVolume *volume) -{ - ClutterActorIter iter; - ClutterActor *child; - - clutter_actor_iter_init (&iter, self); - while (clutter_actor_iter_next (&iter, &child)) - { - const ClutterPaintVolume *child_volume; - - if (!CLUTTER_ACTOR_IS_MAPPED (child)) - continue; - - child_volume = clutter_actor_get_transformed_paint_volume (child, self); - if (child_volume == NULL) - return FALSE; - - clutter_paint_volume_union (volume, child_volume); - } - - return TRUE; -} - -/* This is a workaround for Clutter's awful allocation tracking. - * Without this, any time the window group changed size, which is - * any time windows are dragged around, we'll do a full repaint - * of the window group, which includes the background actor, meaning - * a full-stage repaint. - * - * Since actors are allowed to paint outside their allocation, and - * since child actors are allowed to be outside their parents, this - * doesn't affect anything, but it means that we'll get much more - * sane and consistent clipped repaints from Clutter. */ -static void -meta_window_group_get_preferred_width (ClutterActor *actor, - gfloat for_height, - gfloat *min_width, - gfloat *nat_width) -{ - *min_width = 0; - *nat_width = 0; -} - -static void -meta_window_group_get_preferred_height (ClutterActor *actor, - gfloat for_width, - gfloat *min_height, - gfloat *nat_height) -{ - *min_height = 0; - *nat_height = 0; -} - -static void -meta_window_group_class_init (MetaWindowGroupClass *klass) -{ - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - - actor_class->paint = meta_window_group_paint; - actor_class->get_paint_volume = meta_window_group_get_paint_volume; - actor_class->get_preferred_width = meta_window_group_get_preferred_width; - actor_class->get_preferred_height = meta_window_group_get_preferred_height; -} - -static void -meta_window_group_init (MetaWindowGroup *window_group) -{ -} - -ClutterActor * -meta_window_group_new (MetaDisplay *display) -{ - MetaWindowGroup *window_group; - - window_group = g_object_new (META_TYPE_WINDOW_GROUP, NULL); - - window_group->display = display; - - return CLUTTER_ACTOR (window_group); -} diff --git a/src/compositor/meta-window-shape.c b/src/compositor/meta-window-shape.c deleted file mode 100644 index 3bb6409c4..000000000 --- a/src/compositor/meta-window-shape.c +++ /dev/null @@ -1,259 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * MetaWindowShape - * - * Extracted invariant window shape - * - * Copyright (C) 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "meta/meta-window-shape.h" - -#include <string.h> - -#include "compositor/region-utils.h" - -struct _MetaWindowShape -{ - guint ref_count; - - int top, right, bottom, left; - int n_rectangles; - cairo_rectangle_int_t *rectangles; - guint hash; -}; - -MetaWindowShape * -meta_window_shape_new (cairo_region_t *region) -{ - MetaWindowShape *shape; - MetaRegionIterator iter; - cairo_rectangle_int_t extents; - int max_yspan_y1 = 0; - int max_yspan_y2 = 0; - int max_xspan_x1 = -1; - int max_xspan_x2 = -1; - guint hash; - - shape = g_new0 (MetaWindowShape, 1); - shape->ref_count = 1; - - cairo_region_get_extents (region, &extents); - - shape->n_rectangles = cairo_region_num_rectangles (region); - - if (shape->n_rectangles == 0) - { - shape->rectangles = NULL; - shape->top = shape->right = shape->bottom = shape->left = 0; - shape->hash = 0; - return shape; - } - - for (meta_region_iterator_init (&iter, region); - !meta_region_iterator_at_end (&iter); - meta_region_iterator_next (&iter)) - { - int max_line_xspan_x1 = -1; - int max_line_xspan_x2 = -1; - - if (iter.rectangle.width > max_line_xspan_x2 - max_line_xspan_x1) - { - max_line_xspan_x1 = iter.rectangle.x; - max_line_xspan_x2 = iter.rectangle.x + iter.rectangle.width; - } - - if (iter.line_end) - { - if (iter.rectangle.height > max_yspan_y2 - max_yspan_y1) - { - max_yspan_y1 = iter.rectangle.y; - max_yspan_y2 = iter.rectangle.y + iter.rectangle.height; - } - - if (max_xspan_x1 < 0) /* First line */ - { - max_xspan_x1 = max_line_xspan_x1; - max_xspan_x2 = max_line_xspan_x2; - } - else - { - max_xspan_x1 = MAX (max_xspan_x1, max_line_xspan_x1); - max_xspan_x2 = MIN (max_xspan_x2, max_line_xspan_x2); - - if (max_xspan_x2 < max_xspan_x1) - max_xspan_x2 = max_xspan_x1; - } - } - } - -#if 0 - g_print ("xspan: %d -> %d, yspan: %d -> %d\n", - max_xspan_x1, max_xspan_x2, - max_yspan_y1, max_yspan_y2); -#endif - - shape->top = max_yspan_y1 - extents.y; - shape->right = extents.x + extents.width - max_xspan_x2; - shape->bottom = extents.y + extents.height - max_yspan_y2; - shape->left = max_xspan_x1 - extents.x; - - shape->rectangles = g_new (cairo_rectangle_int_t, shape->n_rectangles); - - hash = 0; - for (meta_region_iterator_init (&iter, region); - !meta_region_iterator_at_end (&iter); - meta_region_iterator_next (&iter)) - { - int x1, x2, y1, y2; - - x1 = iter.rectangle.x; - x2 = iter.rectangle.x + iter.rectangle.width; - y1 = iter.rectangle.y; - y2 = iter.rectangle.y + iter.rectangle.height; - - if (x1 > max_xspan_x1) - x1 -= MIN (x1, max_xspan_x2 - 1) - max_xspan_x1; - if (x2 > max_xspan_x1) - x2 -= MIN (x2, max_xspan_x2 - 1) - max_xspan_x1; - if (y1 > max_yspan_y1) - y1 -= MIN (y1, max_yspan_y2 - 1) - max_yspan_y1; - if (y2 > max_yspan_y1) - y2 -= MIN (y2, max_yspan_y2 - 1) - max_yspan_y1; - - shape->rectangles[iter.i].x = x1 - extents.x; - shape->rectangles[iter.i].y = y1 - extents.y; - shape->rectangles[iter.i].width = x2 - x1; - shape->rectangles[iter.i].height = y2 - y1; - -#if 0 - g_print ("%d: +%d+%dx%dx%d => +%d+%dx%dx%d\n", - iter.i, iter.rectangle.x, iter.rectangle.y, iter.rectangle.width, iter.rectangle.height, - shape->rectangles[iter.i].x, shape->rectangles[iter.i].y, - hape->rectangles[iter.i].width, shape->rectangles[iter.i].height); -#endif - - hash = hash * 31 + x1 * 17 + x2 * 27 + y1 * 37 + y2 * 43; - } - - shape->hash = hash; - -#if 0 - g_print ("%d %d %d %d: %#x\n\n", shape->top, shape->right, shape->bottom, shape->left, shape->hash); -#endif - - return shape; -} - -MetaWindowShape * -meta_window_shape_ref (MetaWindowShape *shape) -{ - shape->ref_count++; - - return shape; -} - -void -meta_window_shape_unref (MetaWindowShape *shape) -{ - shape->ref_count--; - if (shape->ref_count == 0) - { - g_free (shape->rectangles); - g_free (shape); - } -} - -guint -meta_window_shape_hash (MetaWindowShape *shape) -{ - return shape->hash; -} - -gboolean -meta_window_shape_equal (MetaWindowShape *shape_a, - MetaWindowShape *shape_b) -{ - if (shape_a->n_rectangles != shape_b->n_rectangles) - return FALSE; - - return memcmp (shape_a->rectangles, shape_b->rectangles, - sizeof (cairo_rectangle_int_t) * shape_a->n_rectangles) == 0; -} - -void -meta_window_shape_get_borders (MetaWindowShape *shape, - int *border_top, - int *border_right, - int *border_bottom, - int *border_left) -{ - if (border_top) - *border_top = shape->top; - if (border_right) - *border_right = shape->right; - if (border_bottom) - *border_bottom = shape->bottom; - if (border_left) - *border_left = shape->left; -} - -/** - * meta_window_shape_to_region: - * @shape: a #MetaWindowShape - * @center_width: size of the central region horizontally - * @center_height: size of the central region vertically - * - * Converts the shape to to a cairo_region_t using the given width - * and height for the central scaled region. - * - * Return value: a newly created region - */ -cairo_region_t * -meta_window_shape_to_region (MetaWindowShape *shape, - int center_width, - int center_height) -{ - cairo_region_t *region; - int i; - - region = cairo_region_create (); - - for (i = 0; i < shape->n_rectangles; i++) - { - cairo_rectangle_int_t rect = shape->rectangles[i]; - - if (rect.x <= shape->left && rect.x + rect.width >= shape->left + 1) - rect.width += center_width; - else if (rect.x >= shape->left + 1) - rect.x += center_width; - - if (rect.y <= shape->top && rect.y + rect.height >= shape->top + 1) - rect.height += center_height; - else if (rect.y >= shape->top + 1) - rect.y += center_height; - - cairo_region_union_rectangle (region, &rect); - } - - return region; -} - -G_DEFINE_BOXED_TYPE (MetaWindowShape, meta_window_shape, - meta_window_shape_ref, meta_window_shape_unref) diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c deleted file mode 100644 index c89c84121..000000000 --- a/src/compositor/plugins/default.c +++ /dev/null @@ -1,923 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (c) 2008 Intel Corp. - * - * Author: Tomas Frydrych <tf@linux.intel.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "meta/display.h" - -#include <glib/gi18n-lib.h> -#include <gmodule.h> -#include <string.h> - -#include "clutter/clutter.h" -#include "meta/meta-backend.h" -#include "meta/meta-background-actor.h" -#include "meta/meta-background-content.h" -#include "meta/meta-background-group.h" -#include "meta/meta-monitor-manager.h" -#include "meta/meta-plugin.h" -#include "meta/util.h" -#include "meta/window.h" - -#define DESTROY_TIMEOUT 100 -#define MINIMIZE_TIMEOUT 250 -#define MAP_TIMEOUT 250 -#define SWITCH_TIMEOUT 500 - -#define ACTOR_DATA_KEY "MCCP-Default-actor-data" -#define DISPLAY_TILE_PREVIEW_DATA_KEY "MCCP-Default-display-tile-preview-data" - -#define META_TYPE_DEFAULT_PLUGIN (meta_default_plugin_get_type ()) -#define META_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPlugin)) -#define META_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass)) -#define META_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_DEFAULT_PLUGIN_TYPE)) -#define META_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DEFAULT_PLUGIN)) -#define META_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass)) - -typedef struct _MetaDefaultPlugin MetaDefaultPlugin; -typedef struct _MetaDefaultPluginClass MetaDefaultPluginClass; -typedef struct _MetaDefaultPluginPrivate MetaDefaultPluginPrivate; - -struct _MetaDefaultPlugin -{ - MetaPlugin parent; - - MetaDefaultPluginPrivate *priv; -}; - -struct _MetaDefaultPluginClass -{ - MetaPluginClass parent_class; -}; - -static GQuark actor_data_quark = 0; -static GQuark display_tile_preview_data_quark = 0; - -static void start (MetaPlugin *plugin); -static void minimize (MetaPlugin *plugin, - MetaWindowActor *actor); -static void map (MetaPlugin *plugin, - MetaWindowActor *actor); -static void destroy (MetaPlugin *plugin, - MetaWindowActor *actor); - -static void switch_workspace (MetaPlugin *plugin, - gint from, - gint to, - MetaMotionDirection direction); - -static void kill_window_effects (MetaPlugin *plugin, - MetaWindowActor *actor); -static void kill_switch_workspace (MetaPlugin *plugin); - -static void show_tile_preview (MetaPlugin *plugin, - MetaWindow *window, - MetaRectangle *tile_rect, - int tile_monitor_number); -static void hide_tile_preview (MetaPlugin *plugin); - -static void confirm_display_change (MetaPlugin *plugin); - -static const MetaPluginInfo * plugin_info (MetaPlugin *plugin); - -/* - * Plugin private data that we store in the .plugin_private member. - */ -struct _MetaDefaultPluginPrivate -{ - /* Valid only when switch_workspace effect is in progress */ - ClutterTimeline *tml_switch_workspace1; - ClutterTimeline *tml_switch_workspace2; - ClutterActor *desktop1; - ClutterActor *desktop2; - - ClutterActor *background_group; - - MetaPluginInfo info; -}; - -META_PLUGIN_DECLARE_WITH_CODE (MetaDefaultPlugin, meta_default_plugin, - G_ADD_PRIVATE_DYNAMIC (MetaDefaultPlugin)); - -/* - * Per actor private data we attach to each actor. - */ -typedef struct _ActorPrivate -{ - ClutterActor *orig_parent; - - ClutterTimeline *tml_minimize; - ClutterTimeline *tml_destroy; - ClutterTimeline *tml_map; -} ActorPrivate; - -/* callback data for when animations complete */ -typedef struct -{ - ClutterActor *actor; - MetaPlugin *plugin; -} EffectCompleteData; - - -typedef struct _DisplayTilePreview -{ - ClutterActor *actor; - - GdkRGBA *preview_color; - - MetaRectangle tile_rect; -} DisplayTilePreview; - -static void -meta_default_plugin_dispose (GObject *object) -{ - /* MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (object)->priv; - */ - G_OBJECT_CLASS (meta_default_plugin_parent_class)->dispose (object); -} - -static void -meta_default_plugin_finalize (GObject *object) -{ - G_OBJECT_CLASS (meta_default_plugin_parent_class)->finalize (object); -} - -static void -meta_default_plugin_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_default_plugin_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_default_plugin_class_init (MetaDefaultPluginClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass); - - gobject_class->finalize = meta_default_plugin_finalize; - gobject_class->dispose = meta_default_plugin_dispose; - gobject_class->set_property = meta_default_plugin_set_property; - gobject_class->get_property = meta_default_plugin_get_property; - - plugin_class->start = start; - plugin_class->map = map; - plugin_class->minimize = minimize; - plugin_class->destroy = destroy; - plugin_class->switch_workspace = switch_workspace; - plugin_class->show_tile_preview = show_tile_preview; - plugin_class->hide_tile_preview = hide_tile_preview; - plugin_class->plugin_info = plugin_info; - plugin_class->kill_window_effects = kill_window_effects; - plugin_class->kill_switch_workspace = kill_switch_workspace; - plugin_class->confirm_display_change = confirm_display_change; -} - -static void -meta_default_plugin_init (MetaDefaultPlugin *self) -{ - MetaDefaultPluginPrivate *priv; - - self->priv = priv = meta_default_plugin_get_instance_private (self); - - priv->info.name = "Default Effects"; - priv->info.version = "0.1"; - priv->info.author = "Intel Corp."; - priv->info.license = "GPL"; - priv->info.description = "This is an example of a plugin implementation."; -} - -/* - * Actor private data accessor - */ -static void -free_actor_private (gpointer data) -{ - if (G_LIKELY (data != NULL)) - g_free (data); -} - -static ActorPrivate * -get_actor_private (MetaWindowActor *actor) -{ - ActorPrivate *priv = g_object_get_qdata (G_OBJECT (actor), actor_data_quark); - - if (G_UNLIKELY (actor_data_quark == 0)) - actor_data_quark = g_quark_from_static_string (ACTOR_DATA_KEY); - - if (G_UNLIKELY (!priv)) - { - priv = g_new0 (ActorPrivate, 1); - - g_object_set_qdata_full (G_OBJECT (actor), - actor_data_quark, priv, - free_actor_private); - } - - return priv; -} - -static ClutterTimeline * -actor_animate (ClutterActor *actor, - ClutterAnimationMode mode, - guint duration, - const gchar *first_property, - ...) -{ - va_list args; - ClutterTransition *transition; - - clutter_actor_save_easing_state (actor); - clutter_actor_set_easing_mode (actor, mode); - clutter_actor_set_easing_duration (actor, duration); - - va_start (args, first_property); - g_object_set_valist (G_OBJECT (actor), first_property, args); - va_end (args); - - transition = clutter_actor_get_transition (actor, first_property); - - clutter_actor_restore_easing_state (actor); - - return CLUTTER_TIMELINE (transition); -} - -static void -on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data) -{ - MetaPlugin *plugin = META_PLUGIN (data); - MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; - MetaDisplay *display = meta_plugin_get_display (plugin); - GList *l = meta_get_window_actors (display); - - while (l) - { - ClutterActor *a = l->data; - MetaWindowActor *window_actor = META_WINDOW_ACTOR (a); - ActorPrivate *apriv = get_actor_private (window_actor); - - if (apriv->orig_parent) - { - g_object_ref (a); - clutter_actor_remove_child (clutter_actor_get_parent (a), a); - clutter_actor_add_child (apriv->orig_parent, a); - g_object_unref (a); - apriv->orig_parent = NULL; - } - - l = l->next; - } - - clutter_actor_destroy (priv->desktop1); - clutter_actor_destroy (priv->desktop2); - - priv->tml_switch_workspace1 = NULL; - priv->tml_switch_workspace2 = NULL; - priv->desktop1 = NULL; - priv->desktop2 = NULL; - - meta_plugin_switch_workspace_completed (plugin); -} - -static void -on_monitors_changed (MetaMonitorManager *monitor_manager, - MetaPlugin *plugin) -{ - MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin); - MetaDisplay *display = meta_plugin_get_display (plugin); - - int i, n; - GRand *rand = g_rand_new_with_seed (123456); - - clutter_actor_destroy_all_children (self->priv->background_group); - - n = meta_display_get_n_monitors (display); - for (i = 0; i < n; i++) - { - MetaBackgroundContent *background_content; - ClutterContent *content; - MetaRectangle rect; - ClutterActor *background_actor; - MetaBackground *background; - uint8_t red; - uint8_t green; - uint8_t blue; - ClutterColor color; - - meta_display_get_monitor_geometry (display, i, &rect); - - background_actor = meta_background_actor_new (display, i); - content = clutter_actor_get_content (background_actor); - background_content = META_BACKGROUND_CONTENT (content); - - clutter_actor_set_position (background_actor, rect.x, rect.y); - clutter_actor_set_size (background_actor, rect.width, rect.height); - - /* Don't use rand() here, mesa calls srand() internally when - parsing the driconf XML, but it's nice if the colors are - reproducible. - */ - - blue = g_rand_int_range (rand, 0, 255); - green = g_rand_int_range (rand, 0, 255); - red = g_rand_int_range (rand, 0, 255); - clutter_color_init (&color, red, green, blue, 255); - - background = meta_background_new (display); - meta_background_set_color (background, &color); - meta_background_content_set_background (background_content, background); - g_object_unref (background); - - meta_background_content_set_vignette (background_content, TRUE, 0.5, 0.5); - - clutter_actor_add_child (self->priv->background_group, background_actor); - } - - g_rand_free (rand); -} - -static void -init_keymap (MetaDefaultPlugin *self) -{ - g_autoptr (GError) error = NULL; - g_autoptr (GDBusProxy) proxy = NULL; - g_autoptr (GVariant) result = NULL; - g_autoptr (GVariant) props = NULL; - g_autofree char *x11_layout = NULL; - g_autofree char *x11_options = NULL; - g_autofree char *x11_variant = NULL; - - proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - "org.freedesktop.DBus.Properties", - NULL, - &error); - if (!proxy) - { - g_message ("Failed to acquire org.freedesktop.locale1 proxy: %s, " - "probably running in CI", - error->message); - return; - } - - result = g_dbus_proxy_call_sync (proxy, - "GetAll", - g_variant_new ("(s)", - "org.freedesktop.locale1"), - G_DBUS_CALL_FLAGS_NONE, - 100, - NULL, - &error); - if (!result) - { - g_warning ("Failed to retrieve locale properties: %s", error->message); - return; - } - - props = g_variant_get_child_value (result, 0); - if (!props) - { - g_warning ("No locale properties found"); - return; - } - - if (!g_variant_lookup (props, "X11Layout", "s", &x11_layout)) - x11_layout = g_strdup ("us"); - - if (!g_variant_lookup (props, "X11Options", "s", &x11_options)) - x11_options = g_strdup (""); - - if (!g_variant_lookup (props, "X11Variant", "s", &x11_variant)) - x11_variant = g_strdup (""); - - meta_backend_set_keymap (meta_get_backend (), - x11_layout, x11_variant, x11_options); -} - -static void -start (MetaPlugin *plugin) -{ - MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin); - MetaDisplay *display = meta_plugin_get_display (plugin); - MetaMonitorManager *monitor_manager = meta_monitor_manager_get (); - - self->priv->background_group = meta_background_group_new (); - clutter_actor_insert_child_below (meta_get_window_group_for_display (display), - self->priv->background_group, NULL); - - g_signal_connect (monitor_manager, "monitors-changed", - G_CALLBACK (on_monitors_changed), plugin); - - on_monitors_changed (monitor_manager, plugin); - - if (meta_is_wayland_compositor ()) - init_keymap (self); - - clutter_actor_show (meta_get_stage_for_display (display)); -} - -static void -switch_workspace (MetaPlugin *plugin, - gint from, gint to, - MetaMotionDirection direction) -{ - MetaDisplay *display; - MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; - GList *l; - ClutterActor *workspace0 = clutter_actor_new (); - ClutterActor *workspace1 = clutter_actor_new (); - ClutterActor *stage; - int screen_width, screen_height; - - display = meta_plugin_get_display (plugin); - stage = meta_get_stage_for_display (display); - - meta_display_get_size (display, - &screen_width, - &screen_height); - - clutter_actor_set_pivot_point (workspace1, 1.0, 1.0); - clutter_actor_set_position (workspace1, - screen_width, - screen_height); - - clutter_actor_set_scale (workspace1, 0.0, 0.0); - - clutter_actor_add_child (stage, workspace1); - clutter_actor_add_child (stage, workspace0); - - if (from == to) - { - meta_plugin_switch_workspace_completed (plugin); - return; - } - - l = g_list_last (meta_get_window_actors (display)); - - while (l) - { - MetaWindowActor *window_actor = l->data; - ActorPrivate *apriv = get_actor_private (window_actor); - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - MetaWorkspace *workspace; - gint win_workspace; - - workspace = meta_window_get_workspace (meta_window_actor_get_meta_window (window_actor)); - win_workspace = meta_workspace_index (workspace); - - if (win_workspace == to || win_workspace == from) - { - ClutterActor *parent = win_workspace == to ? workspace1 : workspace0; - apriv->orig_parent = clutter_actor_get_parent (actor); - - g_object_ref (actor); - clutter_actor_remove_child (clutter_actor_get_parent (actor), actor); - clutter_actor_add_child (parent, actor); - clutter_actor_show (actor); - clutter_actor_set_child_below_sibling (parent, actor, NULL); - g_object_unref (actor); - } - else if (win_workspace < 0) - { - /* Sticky window */ - apriv->orig_parent = NULL; - } - else - { - /* Window on some other desktop */ - clutter_actor_hide (actor); - apriv->orig_parent = NULL; - } - - l = l->prev; - } - - priv->desktop1 = workspace0; - priv->desktop2 = workspace1; - - priv->tml_switch_workspace1 = actor_animate (workspace0, CLUTTER_EASE_IN_SINE, - SWITCH_TIMEOUT, - "scale-x", 1.0, - "scale-y", 1.0, - NULL); - g_signal_connect (priv->tml_switch_workspace1, - "completed", - G_CALLBACK (on_switch_workspace_effect_complete), - plugin); - - priv->tml_switch_workspace2 = actor_animate (workspace1, CLUTTER_EASE_IN_SINE, - SWITCH_TIMEOUT, - "scale-x", 0.0, - "scale-y", 0.0, - NULL); -} - - -/* - * Minimize effect completion callback; this function restores actor state, and - * calls the manager callback function. - */ -static void -on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) -{ - /* - * Must reverse the effect of the effect; must hide it first to ensure - * that the restoration will not be visible. - */ - MetaPlugin *plugin = data->plugin; - ActorPrivate *apriv; - MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor); - - apriv = get_actor_private (META_WINDOW_ACTOR (data->actor)); - apriv->tml_minimize = NULL; - - clutter_actor_hide (data->actor); - - /* FIXME - we shouldn't assume the original scale, it should be saved - * at the start of the effect */ - clutter_actor_set_scale (data->actor, 1.0, 1.0); - - /* Now notify the manager that we are done with this effect */ - meta_plugin_minimize_completed (plugin, window_actor); - - g_free (data); -} - -/* - * Simple minimize handler: it applies a scale effect (which must be reversed on - * completion). - */ -static void -minimize (MetaPlugin *plugin, MetaWindowActor *window_actor) -{ - MetaWindowType type; - MetaRectangle icon_geometry; - MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); - ClutterTimeline *timeline = NULL; - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - - - type = meta_window_get_window_type (meta_window); - - if (!meta_window_get_icon_geometry(meta_window, &icon_geometry)) - { - icon_geometry.x = 0; - icon_geometry.y = 0; - } - - if (type == META_WINDOW_NORMAL) - { - timeline = actor_animate (actor, - CLUTTER_EASE_IN_SINE, - MINIMIZE_TIMEOUT, - "scale-x", 0.0, - "scale-y", 0.0, - "x", (double)icon_geometry.x, - "y", (double)icon_geometry.y, - NULL); - } - - if (timeline) - { - EffectCompleteData *data = g_new0 (EffectCompleteData, 1); - ActorPrivate *apriv = get_actor_private (window_actor); - - apriv->tml_minimize = timeline; - data->plugin = plugin; - data->actor = actor; - g_signal_connect (apriv->tml_minimize, "completed", - G_CALLBACK (on_minimize_effect_complete), - data); - } - else - meta_plugin_minimize_completed (plugin, window_actor); -} - -static void -on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) -{ - /* - * Must reverse the effect of the effect. - */ - MetaPlugin *plugin = data->plugin; - MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor); - ActorPrivate *apriv = get_actor_private (window_actor); - - apriv->tml_map = NULL; - - /* Now notify the manager that we are done with this effect */ - meta_plugin_map_completed (plugin, window_actor); - - g_free (data); -} - -/* - * Simple map handler: it applies a scale effect which must be reversed on - * completion). - */ -static void -map (MetaPlugin *plugin, MetaWindowActor *window_actor) -{ - MetaWindowType type; - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); - - type = meta_window_get_window_type (meta_window); - - if (type == META_WINDOW_NORMAL) - { - EffectCompleteData *data = g_new0 (EffectCompleteData, 1); - ActorPrivate *apriv = get_actor_private (window_actor); - - clutter_actor_set_pivot_point (actor, 0.5, 0.5); - clutter_actor_set_opacity (actor, 0); - clutter_actor_set_scale (actor, 0.5, 0.5); - clutter_actor_show (actor); - - apriv->tml_map = actor_animate (actor, - CLUTTER_EASE_OUT_QUAD, - MAP_TIMEOUT, - "opacity", 255, - "scale-x", 1.0, - "scale-y", 1.0, - NULL); - data->actor = actor; - data->plugin = plugin; - g_signal_connect (apriv->tml_map, "completed", - G_CALLBACK (on_map_effect_complete), - data); - } - else - meta_plugin_map_completed (plugin, window_actor); -} - -/* - * Destroy effect completion callback; this is a simple effect that requires no - * further action than notifying the manager that the effect is completed. - */ -static void -on_destroy_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) -{ - MetaPlugin *plugin = data->plugin; - MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor); - ActorPrivate *apriv = get_actor_private (window_actor); - - apriv->tml_destroy = NULL; - - meta_plugin_destroy_completed (plugin, window_actor); -} - -/* - * Simple TV-out like effect. - */ -static void -destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) -{ - MetaWindowType type; - ClutterActor *actor = CLUTTER_ACTOR (window_actor); - MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); - ClutterTimeline *timeline = NULL; - - type = meta_window_get_window_type (meta_window); - - if (type == META_WINDOW_NORMAL) - { - timeline = actor_animate (actor, - CLUTTER_EASE_OUT_QUAD, - DESTROY_TIMEOUT, - "opacity", 0, - "scale-x", 0.8, - "scale-y", 0.8, - NULL); - } - - if (timeline) - { - EffectCompleteData *data = g_new0 (EffectCompleteData, 1); - ActorPrivate *apriv = get_actor_private (window_actor); - - apriv->tml_destroy = timeline; - data->plugin = plugin; - data->actor = actor; - g_signal_connect (apriv->tml_destroy, "completed", - G_CALLBACK (on_destroy_effect_complete), - data); - } - else - meta_plugin_destroy_completed (plugin, window_actor); -} - -/* - * Tile preview private data accessor - */ -static void -free_display_tile_preview (DisplayTilePreview *preview) -{ - - if (G_LIKELY (preview != NULL)) { - clutter_actor_destroy (preview->actor); - g_free (preview); - } -} - -static void -on_display_closing (MetaDisplay *display, - DisplayTilePreview *preview) -{ - free_display_tile_preview (preview); -} - -static DisplayTilePreview * -get_display_tile_preview (MetaDisplay *display) -{ - DisplayTilePreview *preview; - - if (!display_tile_preview_data_quark) - { - display_tile_preview_data_quark = - g_quark_from_static_string (DISPLAY_TILE_PREVIEW_DATA_KEY); - } - - preview = g_object_get_qdata (G_OBJECT (display), - display_tile_preview_data_quark); - if (!preview) - { - preview = g_new0 (DisplayTilePreview, 1); - - preview->actor = clutter_actor_new (); - clutter_actor_set_background_color (preview->actor, CLUTTER_COLOR_Blue); - clutter_actor_set_opacity (preview->actor, 100); - - clutter_actor_add_child (meta_get_window_group_for_display (display), preview->actor); - g_signal_connect (display, - "closing", - G_CALLBACK (on_display_closing), - preview); - g_object_set_qdata (G_OBJECT (display), - display_tile_preview_data_quark, - preview); - } - - return preview; -} - -static void -show_tile_preview (MetaPlugin *plugin, - MetaWindow *window, - MetaRectangle *tile_rect, - int tile_monitor_number) -{ - MetaDisplay *display = meta_plugin_get_display (plugin); - DisplayTilePreview *preview = get_display_tile_preview (display); - ClutterActor *window_actor; - - if (clutter_actor_is_visible (preview->actor) - && preview->tile_rect.x == tile_rect->x - && preview->tile_rect.y == tile_rect->y - && preview->tile_rect.width == tile_rect->width - && preview->tile_rect.height == tile_rect->height) - return; /* nothing to do */ - - clutter_actor_set_position (preview->actor, tile_rect->x, tile_rect->y); - clutter_actor_set_size (preview->actor, tile_rect->width, tile_rect->height); - - clutter_actor_show (preview->actor); - - window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window)); - clutter_actor_set_child_below_sibling (clutter_actor_get_parent (preview->actor), - preview->actor, - window_actor); - - preview->tile_rect = *tile_rect; -} - -static void -hide_tile_preview (MetaPlugin *plugin) -{ - MetaDisplay *display = meta_plugin_get_display (plugin); - DisplayTilePreview *preview = get_display_tile_preview (display); - - clutter_actor_hide (preview->actor); -} - -static void -finish_timeline (ClutterTimeline *timeline) -{ - g_object_ref (timeline); - clutter_timeline_stop (timeline); - g_signal_emit_by_name (timeline, "completed", NULL); - g_object_unref (timeline); -} - -static void -kill_switch_workspace (MetaPlugin *plugin) -{ - MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; - - if (priv->tml_switch_workspace1) - { - g_object_ref (priv->tml_switch_workspace1); - clutter_timeline_stop (priv->tml_switch_workspace1); - clutter_timeline_stop (priv->tml_switch_workspace2); - g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL); - g_object_unref (priv->tml_switch_workspace1); - } -} - -static void -kill_window_effects (MetaPlugin *plugin, - MetaWindowActor *window_actor) -{ - ActorPrivate *apriv; - - apriv = get_actor_private (window_actor); - - if (apriv->tml_minimize) - finish_timeline (apriv->tml_minimize); - - if (apriv->tml_map) - finish_timeline (apriv->tml_map); - - if (apriv->tml_destroy) - finish_timeline (apriv->tml_destroy); -} - -static const MetaPluginInfo * -plugin_info (MetaPlugin *plugin) -{ - MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; - - return &priv->info; -} - -static void -on_dialog_closed (GPid pid, - gint status, - gpointer user_data) -{ - MetaPlugin *plugin = user_data; - gboolean ok; - - ok = g_spawn_check_exit_status (status, NULL); - meta_plugin_complete_display_change (plugin, ok); -} - -static void -confirm_display_change (MetaPlugin *plugin) -{ - GPid pid; - - pid = meta_show_dialog ("--question", - "Does the display look OK?", - "20", - NULL, - "_Keep This Configuration", - "_Restore Previous Configuration", - "preferences-desktop-display", - 0, - NULL, NULL); - - g_child_watch_add (pid, on_dialog_closed, plugin); -} diff --git a/src/compositor/plugins/meson.build b/src/compositor/plugins/meson.build deleted file mode 100644 index 9dd06814d..000000000 --- a/src/compositor/plugins/meson.build +++ /dev/null @@ -1,20 +0,0 @@ -default_plugin_c_args = [ - '-fPIC', - '-DG_LOG_DOMAIN="mutter"', - '-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), -] - -default_plugin = shared_module('default', - sources: ['default.c'], - include_directories: mutter_includes, - c_args: default_plugin_c_args, - dependencies: [ - glib_dep, - gtk3_dep, - json_glib_dep, - gsettings_desktop_schemas_dep, - libmutter_clutter_dep, - ], - install_dir: join_paths(pkglibdir, 'plugins'), - install: true, -) diff --git a/src/compositor/region-utils.c b/src/compositor/region-utils.c deleted file mode 100644 index ac4048a98..000000000 --- a/src/compositor/region-utils.c +++ /dev/null @@ -1,458 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for region manipulation - * - * Copyright (C) 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "backends/meta-monitor-transform.h" -#include "compositor/region-utils.h" -#include "core/boxes-private.h" - -#include <math.h> - -#define META_REGION_MAX_STACK_RECTS 256 - -#define META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED(n_rects, rects) \ - g_autofree cairo_rectangle_int_t *G_PASTE(__n, __LINE__) = NULL; \ - if (n_rects < META_REGION_MAX_STACK_RECTS) \ - rects = g_newa (cairo_rectangle_int_t, n_rects); \ - else \ - rects = G_PASTE(__n, __LINE__) = g_new (cairo_rectangle_int_t, n_rects); - -/* MetaRegionBuilder */ - -/* Various algorithms in this file require unioning together a set of rectangles - * that are unsorted or overlap; unioning such a set of rectangles 1-by-1 - * using cairo_region_union_rectangle() produces O(N^2) behavior (if the union - * adds or removes rectangles in the middle of the region, then it has to - * move all the rectangles after that.) To avoid this behavior, MetaRegionBuilder - * creates regions for small groups of rectangles and merges them together in - * a binary tree. - * - * Possible improvement: From a glance at the code, accumulating all the rectangles - * into a flat array and then calling the (not usefully documented) - * cairo_region_create_rectangles() would have the same behavior and would be - * simpler and a bit more efficient. - */ - -/* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower. - * But using 8 may be more robust to systems with slow malloc(). */ -#define MAX_CHUNK_RECTANGLES 8 - -void -meta_region_builder_init (MetaRegionBuilder *builder) -{ - int i; - for (i = 0; i < META_REGION_BUILDER_MAX_LEVELS; i++) - builder->levels[i] = NULL; - builder->n_levels = 1; -} - -void -meta_region_builder_add_rectangle (MetaRegionBuilder *builder, - int x, - int y, - int width, - int height) -{ - cairo_rectangle_int_t rect; - int i; - - if (builder->levels[0] == NULL) - builder->levels[0] = cairo_region_create (); - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - - cairo_region_union_rectangle (builder->levels[0], &rect); - if (cairo_region_num_rectangles (builder->levels[0]) >= MAX_CHUNK_RECTANGLES) - { - for (i = 1; i < builder->n_levels + 1; i++) - { - if (builder->levels[i] == NULL) - { - if (i < META_REGION_BUILDER_MAX_LEVELS) - { - builder->levels[i] = builder->levels[i - 1]; - builder->levels[i - 1] = NULL; - if (i == builder->n_levels) - builder->n_levels++; - } - - break; - } - else - { - cairo_region_union (builder->levels[i], builder->levels[i - 1]); - cairo_region_destroy (builder->levels[i - 1]); - builder->levels[i - 1] = NULL; - } - } - } -} - -cairo_region_t * -meta_region_builder_finish (MetaRegionBuilder *builder) -{ - cairo_region_t *result = NULL; - int i; - - for (i = 0; i < builder->n_levels; i++) - { - if (builder->levels[i]) - { - if (result == NULL) - result = builder->levels[i]; - else - { - cairo_region_union(result, builder->levels[i]); - cairo_region_destroy (builder->levels[i]); - } - } - } - - if (result == NULL) - result = cairo_region_create (); - - return result; -} - - -/* MetaRegionIterator */ - -void -meta_region_iterator_init (MetaRegionIterator *iter, - cairo_region_t *region) -{ - iter->region = region; - iter->i = 0; - iter->n_rectangles = cairo_region_num_rectangles (region); - iter->line_start = TRUE; - - if (iter->n_rectangles > 1) - { - cairo_region_get_rectangle (region, 0, &iter->rectangle); - cairo_region_get_rectangle (region, 1, &iter->next_rectangle); - - iter->line_end = iter->next_rectangle.y != iter->rectangle.y; - } - else if (iter->n_rectangles > 0) - { - cairo_region_get_rectangle (region, 0, &iter->rectangle); - iter->line_end = TRUE; - } -} - -gboolean -meta_region_iterator_at_end (MetaRegionIterator *iter) -{ - return iter->i >= iter->n_rectangles; -} - -void -meta_region_iterator_next (MetaRegionIterator *iter) -{ - iter->i++; - iter->rectangle = iter->next_rectangle; - iter->line_start = iter->line_end; - - if (iter->i + 1 < iter->n_rectangles) - { - cairo_region_get_rectangle (iter->region, iter->i + 1, &iter->next_rectangle); - iter->line_end = iter->next_rectangle.y != iter->rectangle.y; - } - else - { - iter->line_end = TRUE; - } -} - -cairo_region_t * -meta_region_scale_double (cairo_region_t *region, - double scale, - MetaRoundingStrategy rounding_strategy) -{ - int n_rects, i; - cairo_rectangle_int_t *rects; - cairo_region_t *scaled_region; - - g_return_val_if_fail (scale > 0.0, NULL); - - if (G_APPROX_VALUE (scale, 1.f, FLT_EPSILON)) - return cairo_region_copy (region); - - n_rects = cairo_region_num_rectangles (region); - META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED (n_rects, rects); - for (i = 0; i < n_rects; i++) - { - cairo_region_get_rectangle (region, i, &rects[i]); - - meta_rectangle_scale_double (&rects[i], scale, rounding_strategy, - &rects[i]); - } - - scaled_region = cairo_region_create_rectangles (rects, n_rects); - - return scaled_region; -} - -cairo_region_t * -meta_region_scale (cairo_region_t *region, int scale) -{ - int n_rects, i; - cairo_rectangle_int_t *rects; - cairo_region_t *scaled_region; - - if (scale == 1) - return cairo_region_copy (region); - - n_rects = cairo_region_num_rectangles (region); - META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED (n_rects, rects); - for (i = 0; i < n_rects; i++) - { - cairo_region_get_rectangle (region, i, &rects[i]); - rects[i].x *= scale; - rects[i].y *= scale; - rects[i].width *= scale; - rects[i].height *= scale; - } - - scaled_region = cairo_region_create_rectangles (rects, n_rects); - - return scaled_region; -} - -static void -add_expanded_rect (MetaRegionBuilder *builder, - int x, - int y, - int width, - int height, - int x_amount, - int y_amount, - gboolean flip) -{ - if (flip) - meta_region_builder_add_rectangle (builder, - y - y_amount, x - x_amount, - height + 2 * y_amount, width + 2 * x_amount); - else - meta_region_builder_add_rectangle (builder, - x - x_amount, y - y_amount, - width + 2 * x_amount, height + 2 * y_amount); -} - -static cairo_region_t * -expand_region (cairo_region_t *region, - int x_amount, - int y_amount, - gboolean flip) -{ - MetaRegionBuilder builder; - int n; - int i; - - meta_region_builder_init (&builder); - - n = cairo_region_num_rectangles (region); - for (i = 0; i < n; i++) - { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - add_expanded_rect (&builder, - rect.x, rect.y, rect.width, rect.height, - x_amount, y_amount, flip); - } - - return meta_region_builder_finish (&builder); -} - -/* This computes a (clipped version) of the inverse of the region - * and expands it by the given amount */ -static cairo_region_t * -expand_region_inverse (cairo_region_t *region, - int x_amount, - int y_amount, - gboolean flip) -{ - MetaRegionBuilder builder; - MetaRegionIterator iter; - cairo_rectangle_int_t extents; - - int last_x; - - meta_region_builder_init (&builder); - - cairo_region_get_extents (region, &extents); - add_expanded_rect (&builder, - extents.x, extents.y - 1, extents.width, 1, - x_amount, y_amount, flip); - add_expanded_rect (&builder, - extents.x - 1, extents.y, 1, extents.height, - x_amount, y_amount, flip); - add_expanded_rect (&builder, - extents.x + extents.width, extents.y, 1, extents.height, - x_amount, y_amount, flip); - add_expanded_rect (&builder, - extents.x, extents.y + extents.height, extents.width, 1, - x_amount, y_amount, flip); - - last_x = extents.x; - for (meta_region_iterator_init (&iter, region); - !meta_region_iterator_at_end (&iter); - meta_region_iterator_next (&iter)) - { - if (iter.rectangle.x > last_x) - add_expanded_rect (&builder, - last_x, iter.rectangle.y, - iter.rectangle.x - last_x, iter.rectangle.height, - x_amount, y_amount, flip); - - if (iter.line_end) - { - if (extents.x + extents.width > iter.rectangle.x + iter.rectangle.width) - add_expanded_rect (&builder, - iter.rectangle.x + iter.rectangle.width, iter.rectangle.y, - (extents.x + extents.width) - (iter.rectangle.x + iter.rectangle.width), iter.rectangle.height, - x_amount, y_amount, flip); - last_x = extents.x; - } - else - last_x = iter.rectangle.x + iter.rectangle.width; - } - - return meta_region_builder_finish (&builder); -} - -/** - * meta_make_border_region: - * @region: a #cairo_region_t - * @x_amount: distance from the border to extend horizontally - * @y_amount: distance from the border to extend vertically - * @flip: if true, the result is computed with x and y interchanged - * - * Computes the "border region" of a given region, which is roughly - * speaking the set of points near the boundary of the region. If we - * define the operation of growing a region as computing the set of - * points within a given manhattan distance of the region, then the - * border is 'grow(region) intersect grow(inverse(region))'. - * - * If we create an image by filling the region with a solid color, - * the border is the region affected by blurring the region. - * - * Return value: a new region which is the border of the given region - */ -cairo_region_t * -meta_make_border_region (cairo_region_t *region, - int x_amount, - int y_amount, - gboolean flip) -{ - cairo_region_t *border_region; - cairo_region_t *inverse_region; - - border_region = expand_region (region, x_amount, y_amount, flip); - inverse_region = expand_region_inverse (region, x_amount, y_amount, flip); - cairo_region_intersect (border_region, inverse_region); - cairo_region_destroy (inverse_region); - - return border_region; -} - -cairo_region_t * -meta_region_transform (const cairo_region_t *region, - MetaMonitorTransform transform, - int width, - int height) -{ - int n_rects, i; - cairo_rectangle_int_t *rects; - cairo_region_t *transformed_region; - - if (transform == META_MONITOR_TRANSFORM_NORMAL) - return cairo_region_copy (region); - - n_rects = cairo_region_num_rectangles (region); - META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED (n_rects, rects); - for (i = 0; i < n_rects; i++) - { - cairo_region_get_rectangle (region, i, &rects[i]); - - meta_rectangle_transform (&rects[i], - transform, - width, - height, - &rects[i]); - } - - transformed_region = cairo_region_create_rectangles (rects, n_rects); - - return transformed_region; -} - -cairo_region_t * -meta_region_crop_and_scale (cairo_region_t *region, - graphene_rect_t *src_rect, - int dst_width, - int dst_height) -{ - int n_rects, i; - cairo_rectangle_int_t *rects; - cairo_region_t *viewport_region; - - if (G_APPROX_VALUE (src_rect->size.width, dst_width, FLT_EPSILON) && - G_APPROX_VALUE (src_rect->size.height, dst_height, FLT_EPSILON) && - G_APPROX_VALUE (roundf (src_rect->origin.x), - src_rect->origin.x, FLT_EPSILON) && - G_APPROX_VALUE (roundf (src_rect->origin.y), - src_rect->origin.y, FLT_EPSILON)) - { - viewport_region = cairo_region_copy (region); - - if (!G_APPROX_VALUE (src_rect->origin.x, 0, FLT_EPSILON) || - !G_APPROX_VALUE (src_rect->origin.y, 0, FLT_EPSILON)) - { - cairo_region_translate (viewport_region, - (int) src_rect->origin.x, - (int) src_rect->origin.y); - } - - return viewport_region; - } - - n_rects = cairo_region_num_rectangles (region); - META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED (n_rects, rects); - for (i = 0; i < n_rects; i++) - { - cairo_region_get_rectangle (region, i, &rects[i]); - - meta_rectangle_crop_and_scale (&rects[i], - src_rect, - dst_width, - dst_height, - &rects[i]); - } - - viewport_region = cairo_region_create_rectangles (rects, n_rects); - - return viewport_region; -} diff --git a/src/compositor/region-utils.h b/src/compositor/region-utils.h deleted file mode 100644 index 298c5540e..000000000 --- a/src/compositor/region-utils.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Utilities for region manipulation - * - * Copyright (C) 2010 Red Hat, 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __META_REGION_UTILS_H__ -#define __META_REGION_UTILS_H__ - -#include <cairo.h> -#include <glib.h> - -#include "backends/meta-backend-types.h" -#include "clutter/clutter.h" -#include "core/boxes-private.h" - -/** - * MetaRegionIterator: - * @region: region being iterated - * @rectangle: current rectangle - * @line_start: whether the current rectangle starts a horizontal band - * @line_end: whether the current rectangle ends a horizontal band - * - * cairo_region_t is a yx banded region; sometimes its useful to iterate through - * such a region treating the start and end of each horizontal band in a distinct - * fashion. - * - * Usage: - * - * MetaRegionIterator iter; - * for (meta_region_iterator_init (&iter, region); - * !meta_region_iterator_at_end (&iter); - * meta_region_iterator_next (&iter)) - * { - * [ Use iter.rectangle, iter.line_start, iter.line_end ] - * } - */ -typedef struct _MetaRegionIterator MetaRegionIterator; - -struct _MetaRegionIterator { - cairo_region_t *region; - cairo_rectangle_int_t rectangle; - gboolean line_start; - gboolean line_end; - int i; - - /*< private >*/ - int n_rectangles; - cairo_rectangle_int_t next_rectangle; -}; - -typedef struct _MetaRegionBuilder MetaRegionBuilder; - -#define META_REGION_BUILDER_MAX_LEVELS 16 -struct _MetaRegionBuilder { - /* To merge regions in binary tree order, we need to keep track of - * the regions that we've already merged together at different - * levels of the tree. We fill in an array in the pattern: - * - * |a | - * |b |a | - * |c | |ab | - * |d |c |ab | - * |e | | |abcd| - */ - cairo_region_t *levels[META_REGION_BUILDER_MAX_LEVELS]; - int n_levels; -}; - -void meta_region_builder_init (MetaRegionBuilder *builder); -void meta_region_builder_add_rectangle (MetaRegionBuilder *builder, - int x, - int y, - int width, - int height); -cairo_region_t * meta_region_builder_finish (MetaRegionBuilder *builder); - -void meta_region_iterator_init (MetaRegionIterator *iter, - cairo_region_t *region); -gboolean meta_region_iterator_at_end (MetaRegionIterator *iter); -void meta_region_iterator_next (MetaRegionIterator *iter); - -cairo_region_t * meta_region_scale (cairo_region_t *region, - int scale); - -cairo_region_t * meta_region_scale_double (cairo_region_t *region, - double scale, - MetaRoundingStrategy rounding_strategy); - -cairo_region_t * meta_make_border_region (cairo_region_t *region, - int x_amount, - int y_amount, - gboolean flip); - -cairo_region_t * meta_region_transform (const cairo_region_t *region, - MetaMonitorTransform transform, - int width, - int height); - -cairo_region_t * meta_region_crop_and_scale (cairo_region_t *region, - graphene_rect_t *src_rect, - int dst_width, - int dst_height); - -#endif /* __META_REGION_UTILS_H__ */ |