|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
|
|
|
#include <X11/extensions/Xdamage.h>
|
|
|
|
#include <X11/extensions/Xrender.h>
|
|
|
|
|
|
|
|
#include <clutter/x11/clutter-x11.h>
|
|
|
|
#define COGL_ENABLE_EXPERIMENTAL_API
|
|
|
|
#include <cogl/cogl-texture-pixmap-x11.h>
|
|
|
|
#include <gdk/gdk.h> /* for gdk_rectangle_union() */
|
|
|
|
|
|
|
|
#include <meta/display.h>
|
|
|
|
#include <meta/errors.h>
|
|
|
|
#include "frame.h"
|
|
|
|
#include <meta/window.h>
|
|
|
|
#include <meta/meta-shaped-texture.h>
|
|
|
|
#include "xprops.h"
|
|
|
|
|
|
|
|
#include "compositor-private.h"
|
|
|
|
#include "meta-shadow-factory-private.h"
|
|
|
|
#include "meta-window-actor-private.h"
|
|
|
|
|
|
|
|
enum {
|
|
|
|
POSITION_CHANGED,
|
|
|
|
SIZE_CHANGED,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = {0};
|
|
|
|
|
|
|
|
|
|
|
|
struct _MetaWindowActorPrivate
|
|
|
|
{
|
|
|
|
MetaWindow *window;
|
|
|
|
Window xwindow;
|
|
|
|
MetaScreen *screen;
|
|
|
|
|
|
|
|
ClutterActor *actor;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
Pixmap back_pixmap;
|
|
|
|
|
|
|
|
Damage damage;
|
|
|
|
|
|
|
|
guint8 opacity;
|
|
|
|
guint8 shadow_opacity;
|
|
|
|
|
|
|
|
gchar * desc;
|
|
|
|
|
|
|
|
/* If the window is shaped, a region that matches the shape */
|
|
|
|
cairo_region_t *shape_region;
|
|
|
|
/* A rectangular region with the visible extents of the window */
|
|
|
|
cairo_region_t *bounding_region;
|
|
|
|
/* The region we should clip to when painting the shadow */
|
|
|
|
cairo_region_t *shadow_clip;
|
|
|
|
|
|
|
|
/* Extracted size-invariant shape used for shadows */
|
|
|
|
MetaWindowShape *shadow_shape;
|
|
|
|
|
|
|
|
gint last_width;
|
|
|
|
gint last_height;
|
|
|
|
MetaFrameBorders last_borders;
|
|
|
|
|
|
|
|
gint freeze_count;
|
|
|
|
|
|
|
|
char * shadow_class;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 maximize_in_progress;
|
|
|
|
gint unmaximize_in_progress;
|
|
|
|
gint map_in_progress;
|
|
|
|
gint destroy_in_progress;
|
|
|
|
|
|
|
|
guint visible : 1;
|
|
|
|
guint mapped : 1;
|
|
|
|
guint argb32 : 1;
|
|
|
|
guint disposed : 1;
|
|
|
|
guint redecorating : 1;
|
|
|
|
|
|
|
|
guint needs_damage_all : 1;
|
|
|
|
guint received_damage : 1;
|
|
|
|
|
|
|
|
guint needs_pixmap : 1;
|
|
|
|
guint needs_reshape : 1;
|
|
|
|
guint recompute_focused_shadow : 1;
|
|
|
|
guint recompute_unfocused_shadow : 1;
|
|
|
|
guint size_changed : 1;
|
|
|
|
|
|
|
|
guint needs_destroy : 1;
|
|
|
|
|
|
|
|
guint no_shadow : 1;
|
|
|
|
|
|
|
|
guint no_more_x_calls : 1;
|
|
|
|
|
|
|
|
guint unredirected : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_META_WINDOW = 1,
|
|
|
|
PROP_META_SCREEN,
|
|
|
|
PROP_X_WINDOW,
|
|
|
|
PROP_X_WINDOW_ATTRIBUTES,
|
|
|
|
PROP_NO_SHADOW,
|
|
|
|
PROP_SHADOW_CLASS
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEFAULT_SHADOW_RADIUS 12
|
|
|
|
#define DEFAULT_SHADOW_X_OFFSET 0
|
|
|
|
#define DEFAULT_SHADOW_Y_OFFSET 8
|
|
|
|
|
|
|
|
static void meta_window_actor_dispose (GObject *object);
|
|
|
|
static void meta_window_actor_finalize (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_paint (ClutterActor *actor);
|
|
|
|
|
|
|
|
static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
|
|
|
|
ClutterPaintVolume *volume);
|
|
|
|
|
|
|
|
|
|
|
|
static void meta_window_actor_detach (MetaWindowActor *self);
|
|
|
|
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
|
|
|
|
|
|
|
static void meta_window_actor_clear_shape_region (MetaWindowActor *self);
|
|
|
|
static void meta_window_actor_clear_bounding_region (MetaWindowActor *self);
|
|
|
|
static void meta_window_actor_clear_shadow_clip (MetaWindowActor *self);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_GROUP);
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_class_init (MetaWindowActorClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
|
|
|
GParamSpec *pspec;
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (MetaWindowActorPrivate));
|
|
|
|
|
|
|
|
object_class->dispose = meta_window_actor_dispose;
|
|
|
|
object_class->finalize = meta_window_actor_finalize;
|
|
|
|
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;
|
|
|
|
|
|
|
|
actor_class->paint = meta_window_actor_paint;
|
|
|
|
actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
|
|
|
|
|
|
|
|
pspec = g_param_spec_object ("meta-window",
|
|
|
|
"MetaWindow",
|
|
|
|
"The displayed MetaWindow",
|
|
|
|
META_TYPE_WINDOW,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
PROP_META_WINDOW,
|
|
|
|
pspec);
|
|
|
|
|
|
|
|
pspec = g_param_spec_pointer ("meta-screen",
|
|
|
|
"MetaScreen",
|
|
|
|
"MetaScreen",
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
PROP_META_SCREEN,
|
|
|
|
pspec);
|
|
|
|
|
|
|
|
pspec = g_param_spec_ulong ("x-window",
|
|
|
|
"Window",
|
|
|
|
"Window",
|
|
|
|
0,
|
|
|
|
G_MAXULONG,
|
|
|
|
0,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
PROP_X_WINDOW,
|
|
|
|
pspec);
|
|
|
|
|
|
|
|
pspec = g_param_spec_boolean ("no-shadow",
|
|
|
|
"No shadow",
|
|
|
|
"Do not add shaddow to this window",
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
PROP_NO_SHADOW,
|
|
|
|
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);
|
|
|
|
|
|
|
|
signals[POSITION_CHANGED] =
|
|
|
|
g_signal_new ("position-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[SIZE_CHANGED] =
|
|
|
|
g_signal_new ("size-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_init (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv;
|
|
|
|
|
|
|
|
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
|
|
|
META_TYPE_WINDOW_ACTOR,
|
|
|
|
MetaWindowActorPrivate);
|
|
|
|
priv->opacity = 0xff;
|
|
|
|
priv->shadow_class = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
window_decorated_notify (MetaWindow *mw,
|
|
|
|
GParamSpec *arg1,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (data);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaFrame *frame = meta_window_get_frame (mw);
|
|
|
|
MetaScreen *screen = priv->screen;
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
Window new_xwindow;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Basically, we have to reconstruct the the internals of this object
|
|
|
|
* from scratch, as everything has changed.
|
|
|
|
*/
|
|
|
|
priv->redecorating = TRUE;
|
|
|
|
|
|
|
|
if (frame)
|
|
|
|
new_xwindow = meta_frame_get_xwindow (frame);
|
|
|
|
else
|
|
|
|
new_xwindow = meta_window_get_xwindow (mw);
|
|
|
|
|
|
|
|
meta_window_actor_detach (self);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First of all, clean up any resources we are currently using and will
|
|
|
|
* be replacing.
|
|
|
|
*/
|
|
|
|
if (priv->damage != None)
|
|
|
|
{
|
|
|
|
meta_error_trap_push (display);
|
|
|
|
XDamageDestroy (xdisplay, priv->damage);
|
|
|
|
meta_error_trap_pop (display);
|
|
|
|
priv->damage = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (priv->desc);
|
|
|
|
priv->desc = NULL;
|
|
|
|
|
|
|
|
priv->xwindow = new_xwindow;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recreate the contents.
|
|
|
|
*/
|
|
|
|
meta_window_actor_constructed (G_OBJECT (self));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
window_appears_focused_notify (MetaWindow *mw,
|
|
|
|
GParamSpec *arg1,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (object);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaScreen *screen = priv->screen;
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Window xwindow = priv->xwindow;
|
|
|
|
MetaWindow *window = priv->window;
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
XRenderPictFormat *format;
|
|
|
|
|
|
|
|
priv->damage = XDamageCreate (xdisplay, xwindow,
|
|
|
|
XDamageReportBoundingBox);
|
|
|
|
|
|
|
|
format = XRenderFindVisualFormat (xdisplay, window->xvisual);
|
|
|
|
|
|
|
|
if (format && format->type == PictTypeDirect && format->direct.alphaMask)
|
|
|
|
priv->argb32 = TRUE;
|
|
|
|
|
|
|
|
if (!priv->actor)
|
|
|
|
{
|
|
|
|
priv->actor = meta_shaped_texture_new ();
|
|
|
|
|
|
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->actor);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we are holding a pointer to this actor independently of the
|
|
|
|
* ClutterContainer internals, and provide a public API to access it,
|
|
|
|
* add a reference here, so that if someone is messing about with us
|
|
|
|
* via the container interface, we do not end up with a dangling pointer.
|
|
|
|
* We will release it in dispose().
|
|
|
|
*/
|
|
|
|
g_object_ref (priv->actor);
|
|
|
|
|
|
|
|
g_signal_connect (window, "notify::decorated",
|
|
|
|
G_CALLBACK (window_decorated_notify), self);
|
|
|
|
g_signal_connect (window, "notify::appears-focused",
|
|
|
|
G_CALLBACK (window_appears_focused_notify), self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is the case where existing window is gaining/loosing frame.
|
|
|
|
* Just ensure the actor is top most (i.e., above shadow).
|
|
|
|
*/
|
|
|
|
clutter_actor_raise_top (priv->actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_window_actor_update_opacity (self);
|
|
|
|
meta_window_actor_update_shape (self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (object);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaScreen *screen;
|
|
|
|
MetaDisplay *display;
|
|
|
|
Display *xdisplay;
|
|
|
|
MetaCompScreen *info;
|
|
|
|
|
|
|
|
if (priv->disposed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
priv->disposed = TRUE;
|
|
|
|
|
|
|
|
screen = priv->screen;
|
|
|
|
display = meta_screen_get_display (screen);
|
|
|
|
xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
meta_window_actor_detach (self);
|
|
|
|
|
|
|
|
meta_window_actor_clear_shape_region (self);
|
|
|
|
meta_window_actor_clear_bounding_region (self);
|
|
|
|
meta_window_actor_clear_shadow_clip (self);
|
|
|
|
|
|
|
|
if (priv->shadow_class != NULL)
|
|
|
|
{
|
|
|
|
g_free (priv->shadow_class);
|
|
|
|
priv->shadow_class = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->focused_shadow != NULL)
|
|
|
|
{
|
|
|
|
meta_shadow_unref (priv->focused_shadow);
|
|
|
|
priv->focused_shadow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->unfocused_shadow != NULL)
|
|
|
|
{
|
|
|
|
meta_shadow_unref (priv->unfocused_shadow);
|
|
|
|
priv->unfocused_shadow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->shadow_shape != NULL)
|
|
|
|
{
|
|
|
|
meta_window_shape_unref (priv->shadow_shape);
|
|
|
|
priv->shadow_shape = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->damage != None)
|
|
|
|
{
|
|
|
|
meta_error_trap_push (display);
|
|
|
|
XDamageDestroy (xdisplay, priv->damage);
|
|
|
|
meta_error_trap_pop (display);
|
|
|
|
|
|
|
|
priv->damage = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->windows = g_list_remove (info->windows, (gconstpointer) self);
|
|
|
|
|
|
|
|
if (priv->window)
|
|
|
|
{
|
|
|
|
g_object_unref (priv->window);
|
|
|
|
priv->window = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release the extra reference we took on the actor.
|
|
|
|
*/
|
|
|
|
g_object_unref (priv->actor);
|
|
|
|
priv->actor = NULL;
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (object);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
g_free (priv->desc);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (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 = self->priv;
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_META_WINDOW:
|
|
|
|
{
|
|
|
|
if (priv->window)
|
|
|
|
g_object_unref (priv->window);
|
|
|
|
priv->window = g_value_dup_object (value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_META_SCREEN:
|
|
|
|
priv->screen = g_value_get_pointer (value);
|
|
|
|
break;
|
|
|
|
case PROP_X_WINDOW:
|
|
|
|
priv->xwindow = g_value_get_ulong (value);
|
|
|
|
break;
|
|
|
|
case PROP_NO_SHADOW:
|
|
|
|
{
|
|
|
|
gboolean newv = g_value_get_boolean (value);
|
|
|
|
|
|
|
|
if (newv == priv->no_shadow)
|
|
|
|
return;
|
|
|
|
|
|
|
|
priv->no_shadow = newv;
|
|
|
|
|
|
|
|
meta_window_actor_invalidate_shadow (self);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_SHADOW_CLASS:
|
|
|
|
{
|
|
|
|
const char *newv = g_value_get_string (value);
|
|
|
|
|
|
|
|
if (g_strcmp0 (newv, priv->shadow_class) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free (priv->shadow_class);
|
|
|
|
priv->shadow_class = g_strdup (newv);
|
|
|
|
|
|
|
|
meta_window_actor_invalidate_shadow (self);
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = META_WINDOW_ACTOR (object)->priv;
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_META_WINDOW:
|
|
|
|
g_value_set_object (value, priv->window);
|
|
|
|
break;
|
|
|
|
case PROP_META_SCREEN:
|
|
|
|
g_value_set_pointer (value, priv->screen);
|
|
|
|
break;
|
|
|
|
case PROP_X_WINDOW:
|
|
|
|
g_value_set_ulong (value, priv->xwindow);
|
|
|
|
break;
|
|
|
|
case PROP_NO_SHADOW:
|
|
|
|
g_value_set_boolean (value, priv->no_shadow);
|
|
|
|
break;
|
|
|
|
case PROP_SHADOW_CLASS:
|
|
|
|
g_value_set_string (value, priv->shadow_class);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
meta_window_actor_get_shadow_class (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->shadow_class != NULL)
|
|
|
|
return priv->shadow_class;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaWindowType window_type = meta_window_get_window_type (priv->window);
|
|
|
|
|
|
|
|
switch (window_type)
|
|
|
|
{
|
|
|
|
case META_WINDOW_DROPDOWN_MENU:
|
|
|
|
return "dropdown-menu";
|
|
|
|
case META_WINDOW_POPUP_MENU:
|
|
|
|
return "popup-menu";
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
MetaFrameType frame_type = meta_window_get_frame_type (priv->window);
|
|
|
|
return meta_frame_type_to_string (frame_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_get_shadow_params (MetaWindowActor *self,
|
|
|
|
gboolean appears_focused,
|
|
|
|
MetaShadowParams *params)
|
|
|
|
{
|
|
|
|
const char *shadow_class = meta_window_actor_get_shadow_class (self);
|
|
|
|
|
|
|
|
meta_shadow_factory_get_params (meta_shadow_factory_get_default (),
|
|
|
|
shadow_class, appears_focused,
|
|
|
|
params);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_window_actor_get_shape_bounds (MetaWindowActor *self,
|
|
|
|
cairo_rectangle_int_t *bounds)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
/* We need to be defensive here because there are corner cases
|
|
|
|
* where getting the shape fails on a window being destroyed
|
|
|
|
* and similar.
|
|
|
|
*/
|
|
|
|
if (priv->shape_region)
|
|
|
|
cairo_region_get_extents (priv->shape_region, bounds);
|
|
|
|
else if (priv->bounding_region)
|
|
|
|
cairo_region_get_extents (priv->bounding_region, bounds);
|
|
|
|
else
|
|
|
|
bounds->x = bounds->y = bounds->width = bounds->height = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_get_shadow_bounds (MetaWindowActor *self,
|
|
|
|
gboolean appears_focused,
|
|
|
|
cairo_rectangle_int_t *bounds)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
|
|
|
cairo_rectangle_int_t shape_bounds;
|
|
|
|
MetaShadowParams params;
|
|
|
|
|
|
|
|
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
|
|
|
meta_window_actor_get_shadow_params (self, 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 (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
return (priv->argb32 || priv->opacity != 0xff) && priv->window->frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_paint (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
gboolean appears_focused = meta_window_appears_focused (priv->window);
|
|
|
|
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
|
|
|
if (g_getenv ("MUFFIN_NO_SHADOWS")) {
|
|
|
|
shadow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shadow != NULL)
|
|
|
|
{
|
|
|
|
MetaShadowParams params;
|
|
|
|
cairo_rectangle_int_t shape_bounds;
|
|
|
|
cairo_region_t *clip = priv->shadow_clip;
|
|
|
|
|
|
|
|
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
|
|
|
meta_window_actor_get_shadow_params (self, appears_focused, ¶ms);
|
|
|
|
|
|
|
|
/* The frame bounds are already subtracted from priv->shadow_clip
|
|
|
|
* if that exists.
|
|
|
|
*/
|
|
|
|
if (!clip && clip_shadow_under_window (self))
|
|
|
|
{
|
|
|
|
cairo_region_t *frame_bounds = meta_window_get_frame_bounds (priv->window);
|
|
|
|
cairo_rectangle_int_t bounds;
|
|
|
|
|
|
|
|
meta_window_actor_get_shadow_bounds (self, appears_focused, &bounds);
|
|
|
|
clip = cairo_region_create_rectangle (&bounds);
|
|
|
|
|
|
|
|
cairo_region_subtract (clip, frame_bounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_shadow_paint (shadow,
|
|
|
|
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 * priv->opacity) / (255 * 255),
|
|
|
|
clip,
|
|
|
|
clip_shadow_under_window (self)); /* clip_strictly - not just as an optimization */
|
|
|
|
|
|
|
|
if (clip && clip != priv->shadow_clip)
|
|
|
|
cairo_region_destroy (clip);
|
|
|
|
}
|
|
|
|
|
|
|
|
CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_window_actor_get_paint_volume (ClutterActor *actor,
|
|
|
|
ClutterPaintVolume *volume)
|
|
|
|
{
|
|
|
|
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
cairo_rectangle_int_t bounds;
|
|
|
|
gboolean appears_focused = meta_window_appears_focused (priv->window);
|
|
|
|
ClutterVertex origin;
|
|
|
|
|
|
|
|
/* The paint volume is computed before paint functions are called
|
|
|
|
* so our bounds might not be updated yet. Force an update. */
|
|
|
|
meta_window_actor_pre_paint (self);
|
|
|
|
|
|
|
|
meta_window_actor_get_shape_bounds (self, &bounds);
|
|
|
|
|
|
|
|
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t shadow_bounds;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
|
|
|
|
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
origin.x = bounds.x;
|
|
|
|
origin.y = bounds.y;
|
|
|
|
origin.z = 0.0f;
|
|
|
|
clutter_paint_volume_set_origin (volume, &origin);
|
|
|
|
|
|
|
|
clutter_paint_volume_set_width (volume, bounds.width);
|
|
|
|
clutter_paint_volume_set_height (volume, bounds.height);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_window_actor_has_shadow (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaWindowType window_type = meta_window_get_window_type (priv->window);
|
|
|
|
|
|
|
|
if (priv->no_shadow)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Leaving out shadows for maximized and fullscreen windows is an effeciency
|
|
|
|
* win and also prevents the unsightly effect of the shadow of maximized
|
|
|
|
* window appearing on an adjacent window */
|
|
|
|
if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
|
|
|
|
meta_window_is_fullscreen (priv->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 (priv->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 (priv->window)
|
|
|
|
{
|
|
|
|
if (meta_window_get_frame (priv->window))
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has shadow because it has a frame\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not add shadows to ARGB windows; eventually we should generate a
|
|
|
|
* shadow from the input shape for such windows.
|
|
|
|
*/
|
|
|
|
if (priv->argb32 || priv->opacity != 0xff)
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has no shadow as it is ARGB\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add shadows to override redirect windows (e.g., Gtk menus).
|
|
|
|
*/
|
|
|
|
if (priv->window->override_redirect)
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has shadow because it is override redirect.\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't put shadow around DND icon windows
|
|
|
|
*/
|
|
|
|
if (window_type == META_WINDOW_DND ||
|
|
|
|
window_type == META_WINDOW_DESKTOP)
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has no shadow as it is DND or Desktop\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window_type == META_WINDOW_MENU
|
|
|
|
#if 0
|
|
|
|
|| window_type == META_WINDOW_DROPDOWN_MENU
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has shadow as it is a menu\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (window_type == META_WINDOW_TOOLTIP)
|
|
|
|
{
|
|
|
|
meta_verbose ("Window 0x%x has shadow as it is a tooltip\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
meta_verbose ("Window 0x%x has no shadow as it fell through\n",
|
|
|
|
(guint)priv->xwindow);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_window_actor_get_x_window: (skip)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
Window
|
|
|
|
meta_window_actor_get_x_window (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
if (!self)
|
|
|
|
return None;
|
|
|
|
|
|
|
|
return self->priv->xwindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_window_actor_get_meta_window:
|
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
return self->priv->window;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_window_actor_get_texture:
|
|
|
|
*
|
|
|
|
* Gets the ClutterActor that is used to display the contents of the window
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the #ClutterActor for the contents
|
|
|
|
*/
|
|
|
|
ClutterActor *
|
|
|
|
meta_window_actor_get_texture (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
return self->priv->actor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_window_actor_is_destroyed:
|
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
return self->priv->disposed;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_window_actor_is_override_redirect (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
return meta_window_is_override_redirect (self->priv->window);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *meta_window_actor_get_description (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For windows managed by the WM, we just defer to the WM for the window
|
|
|
|
* description. For override-redirect windows, we create the description
|
|
|
|
* ourselves, but only on demand.
|
|
|
|
*/
|
|
|
|
if (self->priv->window)
|
|
|
|
return meta_window_get_description (self->priv->window);
|
|
|
|
|
|
|
|
if (G_UNLIKELY (self->priv->desc == NULL))
|
|
|
|
{
|
|
|
|
self->priv->desc = g_strdup_printf ("Override Redirect (0x%x)",
|
|
|
|
(guint) self->priv->xwindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->priv->desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_window_actor_get_workspace:
|
|
|
|
* @self: #MetaWindowActor
|
|
|
|
*
|
|
|
|
* Returns the index of workspace on which this window is located; if the
|
|
|
|
* window is sticky, or is not currently located on any workspace, returns -1.
|
|
|
|
* This function is deprecated and should not be used in newly written code;
|
|
|
|
* meta_window_get_workspace() instead.
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): index of workspace on which this window is
|
|
|
|
* located.
|
|
|
|
*/
|
|
|
|
gint
|
|
|
|
meta_window_actor_get_workspace (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv;
|
|
|
|
MetaWorkspace *workspace;
|
|
|
|
|
|
|
|
if (!self)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (!priv->window || meta_window_is_on_all_workspaces (priv->window))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
workspace = meta_window_get_workspace (priv->window);
|
|
|
|
|
|
|
|
if (!workspace)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return meta_workspace_index (workspace);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_window_actor_showing_on_its_workspace (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
if (!self)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* If override redirect: */
|
|
|
|
if (!self->priv->window)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return meta_window_showing_on_its_workspace (self->priv->window);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_freeze (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
self->priv->freeze_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_damage_all (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
CoglHandle texture;
|
|
|
|
|
|
|
|
if (!priv->needs_damage_all)
|
|
|
|
return;
|
|
|
|
|
|
|
|
texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
|
|
|
|
|
|
|
|
if (!priv->mapped || priv->needs_pixmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
|
|
|
|
0, 0,
|
|
|
|
cogl_texture_get_width (texture),
|
|
|
|
cogl_texture_get_height (texture));
|
|
|
|
|
|
|
|
priv->needs_damage_all = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_thaw (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
self->priv->freeze_count--;
|
|
|
|
|
|
|
|
if (G_UNLIKELY (self->priv->freeze_count < 0))
|
|
|
|
{
|
|
|
|
g_warning ("Error in freeze/thaw accounting.");
|
|
|
|
self->priv->freeze_count = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self->priv->freeze_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Since we ignore damage events while a window is frozen for certain effects
|
|
|
|
* we may need to issue an update_area() covering the whole pixmap if we
|
|
|
|
* don't know what real damage has happened. */
|
|
|
|
|
|
|
|
if (self->priv->needs_damage_all)
|
|
|
|
meta_window_actor_damage_all (self);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_window_actor_effect_in_progress (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
return (self->priv->minimize_in_progress ||
|
|
|
|
self->priv->maximize_in_progress ||
|
|
|
|
self->priv->unmaximize_in_progress ||
|
|
|
|
self->priv->map_in_progress ||
|
|
|
|
self->priv->destroy_in_progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_window_actor_queue_create_pixmap (MetaWindowActor *self)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
priv->needs_pixmap = TRUE;
|
|
|
|
|
|
|
|
if (!priv->mapped)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* This will cause the compositor paint function to be run
|
|
|
|
* if the actor is visible or a clone of the actor is visible.
|
|
|
|
* if the actor isn't visible in any way, then we don't
|
|
|
|
* need to repair the window anyways, and can wait until
|
|
|
|
* the stage is redrawn for some other reason
|
|
|
|
*
|
|
|
|
* The compositor paint function repairs all windows.
|
|
|
|
*/
|
|
|
|
clutter_actor_queue_redraw (priv->actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
is_freeze_thaw_effect (gulong event)
|
|
|
|
{
|
|
|
|
switch (event)
|
|
|
|
{
|
|
|
|
case META_PLUGIN_DESTROY:
|
|
|
|
case META_PLUGIN_MAXIMIZE:
|
|
|
|
case META_PLUGIN_UNMAXIMIZE:
|
|
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
start_simple_effect (MetaWindowActor *self,
|
|
|
|
gulong event)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
|
|
|
|
gint *counter = NULL;
|
|
|
|
gboolean use_freeze_thaw = FALSE;
|
|
|
|
|
|
|
|
if (!info->plugin_mgr)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (event)
|
|
|
|
{
|
|
|
|
case META_PLUGIN_MINIMIZE:
|
|
|
|
counter = &priv->minimize_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_UNMAXIMIZE:
|
|
|
|
case META_PLUGIN_MAXIMIZE:
|
|
|
|
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 (info->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 = self->priv;
|
|
|
|
|
|
|
|
if (priv->needs_destroy)
|
|
|
|
{
|
|
|
|
clutter_actor_destroy (CLUTTER_ACTOR (self));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_window_actor_sync_visibility (self);
|
|
|
|
meta_window_actor_sync_actor_position (self);
|
|
|
|
|
|
|
|
if (!meta_window_is_mapped (priv->window))
|
|
|
|
meta_window_actor_detach (self);
|
|
|
|
|
|
|
|
if (priv->needs_pixmap)
|
|
|
|
clutter_actor_queue_redraw (priv->actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_window_actor_effect_completed (MetaWindowActor *self,
|
|
|
|
gulong event)
|
|
|
|
{
|
|
|
|
MetaWindowActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
/* 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_MINIMIZE:
|
|
|
|
{
|
|
|
|
priv->minimize_in_progress--;
|
|
|
|
if (priv->minimize_in_progress < 0)
|
|
|
|
{
|
|
|
|
g_warning ("Error in minimize accounting.");
|
|
|
|
priv->minimize_in_progress = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case META_PLUGIN_UNMAXIMIZE:
|
|
|
|
priv->unmaximize_in_progress--;
|
|
|
|
if (priv->unmaximize_in_progress < 0)
|
|
|
|
{
|
|
|
|
g_warning ("Error in unmaximize accounting.");
|
|
|
|
priv->unmaximize_in_progress = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case META_PLUGIN_MAXIMIZE:
|
|
|
|
priv->maximize_in_progress--;
|
|
|
|
if (priv->maximize_in_progress < 0)
|
|
|
|
{
|
|
|
|
g_warning ("Error in maximize accounting.");
|
|
|
|
priv->maximize_in_progress = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case META_PLUGIN_SWITCH_WORKSPACE:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_freeze_thaw_effect (event))
|
|
|
|
meta_window_actor_thaw (self);
|
|
|
|
|
|
|
|
if (!meta_window_actor_effect_in_progress (self))
|
|
|
|
meta_window_actor_after_effects (self);
|
|