2008-10-24 05:07:24 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2013-02-18 08:19:28 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:compositor
|
|
|
|
* @Title: MetaCompositor
|
|
|
|
* @Short_Description: Compositor API
|
2013-03-15 06:28:53 -04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* meta_compositor_maximize_window() and meta_compositor_unmaximize_window()
|
|
|
|
* are transitions within the visible state. The window is resized __before__
|
|
|
|
* the call, so it may be necessary to readjust the display based on the
|
|
|
|
* old_rect to start the animation.
|
|
|
|
*
|
2013-03-15 06:29:19 -04:00
|
|
|
* # Containers #
|
|
|
|
*
|
2013-05-22 12:24:00 -04:00
|
|
|
* There's two containers in the stage that are used to place window actors, here
|
2013-03-15 06:29:19 -04:00
|
|
|
* are listed in the order in which they are painted:
|
|
|
|
*
|
|
|
|
* - window group, accessible with meta_get_window_group_for_screen()
|
|
|
|
* - top window group, accessible with meta_get_top_window_group_for_screen()
|
|
|
|
*
|
|
|
|
* 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
|
2013-05-22 12:24:00 -04:00
|
|
|
* top window group.
|
2013-02-18 08:19:28 -05:00
|
|
|
*/
|
2008-10-24 05:07:24 -04:00
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
#include <config.h>
|
|
|
|
|
2009-06-26 15:33:20 -04:00
|
|
|
#include <clutter/x11/clutter-x11.h>
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2013-02-07 17:33:17 -05:00
|
|
|
#include "core.h"
|
2011-03-05 19:29:12 -05:00
|
|
|
#include <meta/screen.h>
|
|
|
|
#include <meta/errors.h>
|
|
|
|
#include <meta/window.h>
|
2009-06-25 18:56:15 -04:00
|
|
|
#include "compositor-private.h"
|
2011-03-05 19:29:12 -05:00
|
|
|
#include <meta/compositor-mutter.h>
|
2008-06-04 08:58:36 -04:00
|
|
|
#include "xprops.h"
|
2011-03-05 19:29:12 -05:00
|
|
|
#include <meta/prefs.h>
|
2011-06-21 14:05:59 -04:00
|
|
|
#include <meta/main.h>
|
2013-01-23 15:54:41 -05:00
|
|
|
#include <meta/meta-background-actor.h>
|
|
|
|
#include <meta/meta-background-group.h>
|
2011-03-05 19:29:12 -05:00
|
|
|
#include <meta/meta-shadow-factory.h>
|
2010-10-18 13:27:14 -04:00
|
|
|
#include "meta-window-actor-private.h"
|
|
|
|
#include "meta-window-group.h"
|
2011-03-05 19:29:12 -05:00
|
|
|
#include "window-private.h" /* to check window->hidden */
|
|
|
|
#include "display-private.h" /* for meta_display_lookup_x_window() */
|
2013-09-11 04:18:53 -04:00
|
|
|
#include "util-private.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
#include "meta-wayland-private.h"
|
2013-08-13 10:51:33 -04:00
|
|
|
#include "meta-wayland-pointer.h"
|
|
|
|
#include "meta-wayland-keyboard.h"
|
2008-06-04 08:58:36 -04:00
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
2008-10-24 05:07:24 -04:00
|
|
|
|
2008-11-27 08:40:52 -05:00
|
|
|
/* #define DEBUG_TRACE g_print */
|
2008-12-18 07:41:56 -05:00
|
|
|
#define DEBUG_TRACE(X)
|
2008-10-24 05:07:24 -04:00
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
static inline gboolean
|
2008-08-20 04:33:39 -04:00
|
|
|
composite_at_least_version (MetaDisplay *display, int maj, int min)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
|
|
|
static int major = -1;
|
|
|
|
static int minor = -1;
|
|
|
|
|
|
|
|
if (major == -1)
|
|
|
|
meta_display_get_compositor_version (display, &major, &minor);
|
2008-08-18 10:44:26 -04:00
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
return (major > maj || (major == maj && minor >= min));
|
|
|
|
}
|
|
|
|
|
2010-11-13 14:45:01 -05:00
|
|
|
static void sync_actor_stacking (MetaCompScreen *info);
|
2009-06-26 15:33:20 -04:00
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
static void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_finish_workspace_switch (MetaCompScreen *info)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2009-06-26 15:33:20 -04:00
|
|
|
GList *l;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
Simplify relationship between mapping and visibility
Previously, changes to the visibility of a window could be indicated
by meta_compositor_map_window(), meta_compositor_unminimize_window(),
meta_compositor_set_window_hidden(), etc, with the exact behavior
depending on the 'live_hidden_windows' preference.
Simplify this so that visibility is controlled by:
meta_compositor_show_window()
meta_compositor_hide_window()
With an 'effect' parameter provided to indicate the appropriate
effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
The map state of the window is signalled separately by:
meta_compositor_map_window()
meta_compositor_unmap_window()
And is used only to control resource handling.
Other changes:
* The desired effect on show/hide is explicitly stored in
MetaWindow, avoiding the need for the was_minimized flag.
At idle, once we calculate the window state, we pass the
effect to the compositor if it matches the new window
state, and then clear the effect to start over for future
map state changes.
* meta_compositor_switch_workspace() is called before any windows
are hidden or shown, allowing the compositor to avoid hiding
or showing an effect for windows involved in the switch.
http://bugzilla.gnome.org/show_bug.cgi?id=582341
* Handling of post-effect cleanups for MutterWindow are
simplified - instead of trying to do different things based
on the individual needs of different effects, we just wait until
all effects complete and sync the window state to what it
should be.
* On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
that we've done so, so it can clean up and unbind. (The
unbinding doesn't seem to be working properly because of
ClutterGLXPixmap or video driver issues.)
http://bugzilla.gnome.org/show_bug.cgi?id=587251
2009-06-28 17:10:40 -04:00
|
|
|
/* Finish hiding and showing actors for the new workspace */
|
|
|
|
for (l = info->windows; l; l = l->next)
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_sync_visibility (l->data);
|
2008-06-06 09:17:38 -04:00
|
|
|
|
2008-09-18 11:09:11 -04:00
|
|
|
/*
|
2009-06-26 15:33:20 -04:00
|
|
|
* Fix up stacking order in case the plugin messed it up.
|
2008-09-18 11:09:11 -04:00
|
|
|
*/
|
2010-11-13 14:45:01 -05:00
|
|
|
sync_actor_stacking (info);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-26 15:33:20 -04:00
|
|
|
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
|
2008-09-18 11:09:11 -04:00
|
|
|
|
|
|
|
}
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-26 15:33:20 -04:00
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_switch_workspace_completed (MetaScreen *screen)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2009-06-26 15:33:20 -04:00
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-26 15:33:20 -04:00
|
|
|
/* FIXME -- must redo stacking order */
|
|
|
|
info->switch_workspace_in_progress--;
|
|
|
|
if (info->switch_workspace_in_progress < 0)
|
2008-09-18 11:09:11 -04:00
|
|
|
{
|
2009-06-26 15:33:20 -04:00
|
|
|
g_warning ("Error in workspace_switch accounting!");
|
|
|
|
info->switch_workspace_in_progress = 0;
|
2008-09-18 11:09:11 -04:00
|
|
|
}
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-26 15:33:20 -04:00
|
|
|
if (!info->switch_workspace_in_progress)
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_finish_workspace_switch (info);
|
2009-06-26 15:33:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compositor_destroy (MetaCompositor *compositor)
|
|
|
|
{
|
2009-06-28 12:26:23 -04:00
|
|
|
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-11-23 14:28:40 -05:00
|
|
|
add_win (MetaWindow *window)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2008-11-23 14:28:40 -05:00
|
|
|
MetaScreen *screen = meta_window_get_screen (window);
|
2008-08-20 04:33:39 -04:00
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2008-11-23 14:28:40 -05:00
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_new (window);
|
2008-11-23 14:28:40 -05:00
|
|
|
|
2010-11-13 14:45:01 -05:00
|
|
|
sync_actor_stacking (info);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-06-25 16:29:20 -04:00
|
|
|
process_damage (MetaCompositor *compositor,
|
2010-04-06 14:10:44 -04:00
|
|
|
XDamageNotifyEvent *event,
|
|
|
|
MetaWindow *window)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor;
|
2010-04-06 14:10:44 -04:00
|
|
|
|
|
|
|
if (window == NULL)
|
|
|
|
return;
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
if (window_actor == NULL)
|
2008-08-19 12:02:00 -04:00
|
|
|
return;
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
meta_window_actor_process_x11_damage (window_actor, event);
|
2008-09-24 17:53:39 -04:00
|
|
|
}
|
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
static Window
|
|
|
|
get_output_window (MetaScreen *screen)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
2008-08-20 04:33:39 -04:00
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
Window output, xroot;
|
2009-01-09 11:28:12 -05:00
|
|
|
XWindowAttributes attr;
|
|
|
|
long event_mask;
|
2012-11-20 20:15:09 -05:00
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
2008-06-04 08:58:36 -04:00
|
|
|
|
|
|
|
xroot = meta_screen_get_xroot (screen);
|
2008-06-04 15:51:08 -04:00
|
|
|
output = XCompositeGetOverlayWindow (xdisplay, xroot);
|
2009-01-09 11:28:12 -05:00
|
|
|
|
2013-02-07 17:33:17 -05:00
|
|
|
meta_core_add_old_event_mask (xdisplay, output, &mask);
|
|
|
|
|
2012-11-20 20:15:09 -05:00
|
|
|
XISetMask (mask.mask, XI_KeyPress);
|
|
|
|
XISetMask (mask.mask, XI_KeyRelease);
|
|
|
|
XISetMask (mask.mask, XI_ButtonPress);
|
|
|
|
XISetMask (mask.mask, XI_ButtonRelease);
|
|
|
|
XISetMask (mask.mask, XI_Enter);
|
|
|
|
XISetMask (mask.mask, XI_Leave);
|
|
|
|
XISetMask (mask.mask, XI_FocusIn);
|
|
|
|
XISetMask (mask.mask, XI_FocusOut);
|
|
|
|
XISetMask (mask.mask, XI_Motion);
|
|
|
|
XISelectEvents (xdisplay, output, &mask, 1);
|
|
|
|
|
|
|
|
event_mask = ExposureMask | PropertyChangeMask;
|
2009-01-09 11:28:12 -05:00
|
|
|
if (XGetWindowAttributes (xdisplay, output, &attr))
|
2012-11-20 20:15:09 -05:00
|
|
|
event_mask |= attr.your_event_mask;
|
2009-01-09 11:28:12 -05:00
|
|
|
|
|
|
|
XSelectInput (xdisplay, output, event_mask);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
2010-10-18 13:27:14 -04:00
|
|
|
* meta_get_stage_for_screen:
|
2010-09-01 15:39:53 -04:00
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): The #ClutterStage for the screen
|
|
|
|
*/
|
2008-10-09 08:22:32 -04:00
|
|
|
ClutterActor *
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_get_stage_for_screen (MetaScreen *screen)
|
2008-10-09 08:22:32 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return info->stage;
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
2010-10-18 13:27:14 -04:00
|
|
|
* meta_get_window_group_for_screen:
|
2010-09-01 15:39:53 -04:00
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): The window group corresponding to @screen
|
|
|
|
*/
|
2008-10-28 07:30:29 -04:00
|
|
|
ClutterActor *
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_get_window_group_for_screen (MetaScreen *screen)
|
2008-10-28 07:30:29 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return info->window_group;
|
|
|
|
}
|
|
|
|
|
2012-12-27 08:04:12 -05:00
|
|
|
/**
|
|
|
|
* meta_get_top_window_group_for_screen:
|
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): The top window group corresponding to @screen
|
|
|
|
*/
|
|
|
|
ClutterActor *
|
|
|
|
meta_get_top_window_group_for_screen (MetaScreen *screen)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return info->top_window_group;
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
2010-10-18 13:27:14 -04:00
|
|
|
* meta_get_window_actors:
|
2010-09-01 15:39:53 -04:00
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
2010-10-18 13:27:14 -04:00
|
|
|
* Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @screen
|
2010-09-01 15:39:53 -04:00
|
|
|
*/
|
2008-10-24 05:07:24 -04:00
|
|
|
GList *
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_get_window_actors (MetaScreen *screen)
|
2008-10-24 05:07:24 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return info->windows;
|
|
|
|
}
|
2008-10-09 08:22:32 -04:00
|
|
|
|
2009-04-23 16:33:16 -04:00
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_set_stage_input_region (MetaScreen *screen,
|
|
|
|
XserverRegion region)
|
2009-04-23 16:33:16 -04:00
|
|
|
{
|
2012-01-07 17:21:32 -05:00
|
|
|
/* As a wayland compositor we can simply ignore all this trickery
|
|
|
|
* for setting an input region on the stage for capturing events in
|
|
|
|
* clutter since all input comes to us first and we get to choose
|
|
|
|
* who else sees them.
|
|
|
|
*/
|
|
|
|
if (!meta_is_wayland_compositor ())
|
2009-04-23 16:33:16 -04:00
|
|
|
{
|
2014-01-16 15:27:58 -05:00
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdpy = meta_display_get_xdisplay (display);
|
|
|
|
Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-01-16 15:27:58 -05:00
|
|
|
XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
|
|
|
|
|
|
|
|
/* It's generally a good heuristic that when a crossing event is generated because
|
|
|
|
* we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
|
|
|
|
* it's not the user doing something, it's the environment changing under the user.
|
|
|
|
*/
|
|
|
|
meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
|
|
|
|
XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
2009-04-23 16:33:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_empty_stage_input_region (MetaScreen *screen)
|
2009-04-23 16:33:16 -04:00
|
|
|
{
|
|
|
|
/* Using a static region here is a bit hacky, but Metacity never opens more than
|
|
|
|
* one XDisplay, so it works fine. */
|
|
|
|
static XserverRegion region = None;
|
|
|
|
|
|
|
|
if (region == None)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdpy = meta_display_get_xdisplay (display);
|
|
|
|
region = XFixesCreateRegion (xdpy, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_set_stage_input_region (screen, region);
|
2009-04-23 16:33:16 -04:00
|
|
|
}
|
|
|
|
|
2013-05-23 16:21:24 -04:00
|
|
|
void
|
|
|
|
meta_focus_stage_window (MetaScreen *screen,
|
|
|
|
guint32 timestamp)
|
|
|
|
{
|
|
|
|
ClutterStage *stage;
|
|
|
|
Window window;
|
|
|
|
|
|
|
|
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
|
|
|
if (!stage)
|
|
|
|
return;
|
|
|
|
|
2013-08-13 08:54:55 -04:00
|
|
|
if (!meta_is_wayland_compositor ())
|
|
|
|
{
|
|
|
|
window = clutter_x11_get_stage_window (stage);
|
2013-05-23 16:21:24 -04:00
|
|
|
|
2013-08-13 08:54:55 -04:00
|
|
|
if (window == None)
|
|
|
|
return;
|
2013-05-23 16:21:24 -04:00
|
|
|
|
2013-08-13 08:54:55 -04:00
|
|
|
meta_display_set_input_focus_xwindow (screen->display,
|
|
|
|
screen,
|
|
|
|
META_FOCUS_STAGE,
|
|
|
|
window,
|
|
|
|
timestamp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
meta_display_set_input_focus_xwindow (screen->display,
|
|
|
|
screen,
|
|
|
|
META_FOCUS_STAGE,
|
|
|
|
None,
|
|
|
|
timestamp);
|
|
|
|
}
|
2013-05-23 16:21:24 -04:00
|
|
|
}
|
|
|
|
|
2013-05-24 17:58:55 -04:00
|
|
|
gboolean
|
|
|
|
meta_stage_is_focused (MetaScreen *screen)
|
|
|
|
{
|
|
|
|
ClutterStage *stage;
|
|
|
|
|
|
|
|
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
|
|
|
if (!stage)
|
|
|
|
return FALSE;
|
|
|
|
|
2013-08-13 08:54:55 -04:00
|
|
|
return (screen->display->focus_type == META_FOCUS_STAGE);
|
2013-05-24 17:58:55 -04:00
|
|
|
}
|
|
|
|
|
2013-08-13 10:51:33 -04:00
|
|
|
static gboolean
|
|
|
|
begin_modal_x11 (MetaScreen *screen,
|
|
|
|
MetaPlugin *plugin,
|
|
|
|
MetaModalOptions options,
|
|
|
|
guint32 timestamp)
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
2013-08-13 10:51:33 -04:00
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdpy = meta_display_get_xdisplay (display);
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
|
|
|
Cursor cursor = None;
|
|
|
|
int result;
|
|
|
|
gboolean pointer_grabbed = FALSE;
|
|
|
|
gboolean keyboard_grabbed = FALSE;
|
2009-08-12 00:12:52 -04:00
|
|
|
|
|
|
|
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
|
|
|
|
{
|
2012-11-20 16:59:20 -05:00
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
|
|
|
|
|
|
|
XISetMask (mask.mask, XI_ButtonPress);
|
|
|
|
XISetMask (mask.mask, XI_ButtonRelease);
|
|
|
|
XISetMask (mask.mask, XI_Enter);
|
|
|
|
XISetMask (mask.mask, XI_Leave);
|
|
|
|
XISetMask (mask.mask, XI_Motion);
|
|
|
|
|
|
|
|
result = XIGrabDevice (xdpy,
|
|
|
|
META_VIRTUAL_CORE_POINTER_ID,
|
|
|
|
grab_window,
|
|
|
|
timestamp,
|
2009-08-12 00:12:52 -04:00
|
|
|
cursor,
|
2012-11-20 16:59:20 -05:00
|
|
|
XIGrabModeAsync, XIGrabModeAsync,
|
|
|
|
False, /* owner_events */
|
|
|
|
&mask);
|
2009-08-12 00:12:52 -04:00
|
|
|
if (result != Success)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
pointer_grabbed = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
|
|
|
|
{
|
2012-11-20 16:59:20 -05:00
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
|
|
|
|
|
|
|
XISetMask (mask.mask, XI_KeyPress);
|
|
|
|
XISetMask (mask.mask, XI_KeyRelease);
|
|
|
|
|
|
|
|
result = XIGrabDevice (xdpy,
|
|
|
|
META_VIRTUAL_CORE_KEYBOARD_ID,
|
|
|
|
grab_window,
|
|
|
|
timestamp,
|
|
|
|
None,
|
|
|
|
XIGrabModeAsync, XIGrabModeAsync,
|
|
|
|
False, /* owner_events */
|
|
|
|
&mask);
|
2009-08-12 00:12:52 -04:00
|
|
|
|
|
|
|
if (result != Success)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
keyboard_grabbed = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (pointer_grabbed)
|
2012-11-20 16:59:20 -05:00
|
|
|
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
|
2009-08-12 00:12:52 -04:00
|
|
|
if (keyboard_grabbed)
|
2012-11-20 16:59:20 -05:00
|
|
|
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
|
2009-08-12 00:12:52 -04:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-08-13 10:51:33 -04:00
|
|
|
static gboolean
|
|
|
|
begin_modal_wayland (MetaScreen *screen,
|
|
|
|
MetaPlugin *plugin,
|
|
|
|
MetaModalOptions options,
|
|
|
|
guint32 timestamp)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor;
|
|
|
|
gboolean pointer_grabbed = FALSE;
|
|
|
|
gboolean keyboard_grabbed = FALSE;
|
|
|
|
|
|
|
|
compositor = meta_wayland_compositor_get_default ();
|
|
|
|
|
|
|
|
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
|
|
|
|
{
|
|
|
|
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
pointer_grabbed = TRUE;
|
|
|
|
}
|
|
|
|
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
|
|
|
|
{
|
|
|
|
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
|
|
|
|
timestamp))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
keyboard_grabbed = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (pointer_grabbed)
|
|
|
|
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
|
|
|
if (keyboard_grabbed)
|
|
|
|
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_begin_modal_for_plugin (MetaScreen *screen,
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
MetaCompositor *compositor = display->compositor;
|
|
|
|
gboolean ok;
|
|
|
|
|
|
|
|
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
ok = begin_modal_wayland (screen, plugin, options, timestamp);
|
|
|
|
else
|
|
|
|
ok = begin_modal_x11 (screen, plugin, options, timestamp);
|
|
|
|
if (!ok)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
display->grab_op = META_GRAB_OP_COMPOSITOR;
|
|
|
|
display->grab_window = NULL;
|
|
|
|
display->grab_screen = screen;
|
|
|
|
display->grab_have_pointer = TRUE;
|
|
|
|
display->grab_have_keyboard = TRUE;
|
|
|
|
|
|
|
|
compositor->modal_plugin = plugin;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-08-12 00:12:52 -04:00
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_end_modal_for_plugin (MetaScreen *screen,
|
|
|
|
MetaPlugin *plugin,
|
|
|
|
guint32 timestamp)
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdpy = meta_display_get_xdisplay (display);
|
|
|
|
MetaCompositor *compositor = display->compositor;
|
|
|
|
|
|
|
|
g_return_if_fail (compositor->modal_plugin == plugin);
|
|
|
|
|
2013-08-13 10:51:33 -04:00
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
|
|
|
|
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
|
|
|
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
|
|
|
|
timestamp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
|
|
|
|
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
|
|
|
|
}
|
2009-08-12 00:12:52 -04:00
|
|
|
|
|
|
|
display->grab_op = META_GRAB_OP_NONE;
|
|
|
|
display->grab_window = NULL;
|
|
|
|
display->grab_screen = NULL;
|
|
|
|
display->grab_have_pointer = FALSE;
|
|
|
|
display->grab_have_keyboard = FALSE;
|
|
|
|
|
|
|
|
compositor->modal_plugin = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is used when reloading plugins to make sure we don't have
|
|
|
|
* a left-over modal grab for this screen.
|
|
|
|
*/
|
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_check_end_modal (MetaScreen *screen)
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
MetaCompositor *compositor = display->compositor;
|
|
|
|
|
|
|
|
if (compositor->modal_plugin &&
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_plugin_get_screen (compositor->modal_plugin) == screen)
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_end_modal_for_plugin (screen,
|
2009-08-12 00:12:52 -04:00
|
|
|
compositor->modal_plugin,
|
2013-04-24 16:49:06 -04:00
|
|
|
|
|
|
|
CurrentTime);
|
2009-08-12 00:12:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-24 16:49:06 -04:00
|
|
|
static void
|
|
|
|
after_stage_paint (ClutterStage *stage,
|
|
|
|
gpointer data)
|
2011-06-13 18:09:59 -04:00
|
|
|
{
|
2013-03-02 07:15:23 -05:00
|
|
|
MetaCompScreen *info = (MetaCompScreen*) data;
|
2011-06-13 18:09:59 -04:00
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = info->windows; l; l = l->next)
|
|
|
|
meta_window_actor_post_paint (l->data);
|
2013-12-03 14:43:53 -05:00
|
|
|
|
2013-12-05 15:39:40 -05:00
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
|
2011-06-13 18:09:59 -04:00
|
|
|
}
|
|
|
|
|
2013-03-01 14:41:11 -05:00
|
|
|
static void
|
|
|
|
redirect_windows (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2013-03-01 14:41:11 -05:00
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
Window xroot = meta_screen_get_xroot (screen);
|
|
|
|
int screen_number = meta_screen_get_screen_number (screen);
|
|
|
|
guint n_retries;
|
|
|
|
guint max_retries;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2011-06-21 14:05:59 -04:00
|
|
|
if (meta_get_replace_current_wm ())
|
|
|
|
max_retries = 5;
|
|
|
|
else
|
|
|
|
max_retries = 1;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2011-06-21 14:05:59 -04:00
|
|
|
n_retries = 0;
|
|
|
|
|
2011-06-30 15:23:41 -04:00
|
|
|
/* 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.
|
2011-06-21 14:05:59 -04:00
|
|
|
*/
|
|
|
|
while (TRUE)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2011-06-21 14:05:59 -04:00
|
|
|
meta_error_trap_push_with_return (display);
|
|
|
|
XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
|
|
|
XSync (xdisplay, FALSE);
|
|
|
|
|
|
|
|
if (!meta_error_trap_pop_with_return (display))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (n_retries == max_retries)
|
2011-06-30 15:23:41 -04:00
|
|
|
{
|
|
|
|
/* 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, display->name);
|
|
|
|
}
|
2011-06-21 14:05:59 -04:00
|
|
|
|
|
|
|
n_retries++;
|
|
|
|
g_usleep (G_USEC_PER_SEC);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
2013-03-01 14:41:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compositor_manage_screen (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info;
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
2013-09-03 10:55:26 -04:00
|
|
|
Window xwin = None;
|
2013-03-01 14:41:11 -05:00
|
|
|
gint width, height;
|
2012-01-07 17:21:32 -05:00
|
|
|
MetaWaylandCompositor *wayland_compositor;
|
2013-03-01 14:41:11 -05:00
|
|
|
|
|
|
|
/* Check if the screen is already managed */
|
|
|
|
if (meta_screen_get_compositor_data (screen))
|
|
|
|
return;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
|
|
|
info = g_new0 (MetaCompScreen, 1);
|
|
|
|
info->screen = screen;
|
2008-08-18 10:44:26 -04:00
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
meta_screen_set_compositor_data (screen, info);
|
|
|
|
|
2009-03-30 11:56:52 -04:00
|
|
|
info->output = None;
|
2008-06-04 08:58:36 -04:00
|
|
|
info->windows = NULL;
|
|
|
|
|
|
|
|
meta_screen_set_cm_selection (screen);
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
/* We will have already created a stage if running as a wayland
|
|
|
|
* compositor... */
|
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
{
|
|
|
|
wayland_compositor = meta_wayland_compositor_get_default ();
|
|
|
|
info->stage = wayland_compositor->stage;
|
2013-08-19 05:12:42 -04:00
|
|
|
|
|
|
|
meta_screen_get_size (screen, &width, &height);
|
|
|
|
clutter_actor_set_size (info->stage, width, height);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->stage = clutter_stage_new ();
|
|
|
|
|
|
|
|
meta_screen_get_size (screen, &width, &height);
|
|
|
|
clutter_actor_realize (info->stage);
|
|
|
|
|
|
|
|
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
|
|
|
|
|
|
|
XResizeWindow (xdisplay, xwin, width, height);
|
|
|
|
|
|
|
|
{
|
|
|
|
long event_mask;
|
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
|
|
|
meta_core_add_old_event_mask (xdisplay, xwin, &mask);
|
|
|
|
|
|
|
|
XISetMask (mask.mask, XI_KeyPress);
|
|
|
|
XISetMask (mask.mask, XI_KeyRelease);
|
|
|
|
XISetMask (mask.mask, XI_ButtonPress);
|
|
|
|
XISetMask (mask.mask, XI_ButtonRelease);
|
|
|
|
XISetMask (mask.mask, XI_Enter);
|
|
|
|
XISetMask (mask.mask, XI_Leave);
|
|
|
|
XISetMask (mask.mask, XI_FocusIn);
|
|
|
|
XISetMask (mask.mask, XI_FocusOut);
|
|
|
|
XISetMask (mask.mask, XI_Motion);
|
|
|
|
XIClearMask (mask.mask, XI_TouchBegin);
|
|
|
|
XIClearMask (mask.mask, XI_TouchEnd);
|
|
|
|
XIClearMask (mask.mask, XI_TouchUpdate);
|
|
|
|
XISelectEvents (xdisplay, xwin, &mask, 1);
|
|
|
|
|
|
|
|
event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
|
|
|
|
if (XGetWindowAttributes (xdisplay, xwin, &attr))
|
|
|
|
event_mask |= attr.your_event_mask;
|
|
|
|
|
|
|
|
XSelectInput (xdisplay, xwin, event_mask);
|
|
|
|
}
|
|
|
|
}
|
2013-03-02 07:15:23 -05:00
|
|
|
|
2013-04-24 16:49:06 -04:00
|
|
|
clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage),
|
|
|
|
after_stage_paint,
|
|
|
|
info,
|
|
|
|
NULL);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2012-11-12 14:11:08 -05:00
|
|
|
clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
|
2012-11-12 13:39:59 -05:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
info->window_group = meta_window_group_new (screen);
|
2012-12-27 08:04:12 -05:00
|
|
|
info->top_window_group = meta_window_group_new (screen);
|
2008-10-02 07:16:15 -04:00
|
|
|
|
2012-01-17 09:16:46 -05:00
|
|
|
clutter_actor_add_child (info->stage, info->window_group);
|
|
|
|
clutter_actor_add_child (info->stage, info->top_window_group);
|
2008-10-02 07:16:15 -04:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
if (meta_is_wayland_compositor ())
|
2009-04-23 16:33:16 -04:00
|
|
|
{
|
2012-01-07 17:21:32 -05:00
|
|
|
/* NB: When running as a wayland compositor we don't need an X
|
|
|
|
* composite overlay window, and we don't need to play any input
|
|
|
|
* region tricks to redirect events into clutter. */
|
|
|
|
info->output = None;
|
2009-04-23 16:33:16 -04:00
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
info->output = get_output_window (screen);
|
|
|
|
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
|
|
|
|
|
2014-01-16 15:27:58 -05:00
|
|
|
meta_empty_stage_input_region (screen);
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
/* 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, info->output, ShapeBounding, 0, 0, None);
|
2009-04-23 16:33:16 -04:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
/* Map overlay window before redirecting windows offscreen so we catch their
|
|
|
|
* contents until we show the stage.
|
|
|
|
*/
|
|
|
|
XMapWindow (xdisplay, info->output);
|
|
|
|
}
|
2013-11-19 15:37:31 -05:00
|
|
|
|
2013-11-25 06:00:55 -05:00
|
|
|
redirect_windows (compositor, screen);
|
|
|
|
|
2013-11-19 15:37:31 -05:00
|
|
|
info->plugin_mgr = meta_plugin_manager_new (screen);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2012-01-07 17:21:32 -05:00
|
|
|
if (!meta_is_wayland_compositor ())
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
Window xroot = meta_screen_get_xroot (screen);
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2011-08-27 05:43:09 -04:00
|
|
|
/*
|
|
|
|
* Shapes the cow so that the given window is exposed,
|
2011-09-15 15:50:28 -04:00
|
|
|
* when metaWindow is NULL it clears the shape again
|
2011-08-27 05:43:09 -04:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
meta_shape_cow_for_window (MetaScreen *screen,
|
2011-09-15 15:50:28 -04:00
|
|
|
MetaWindow *metaWindow)
|
2011-08-27 05:43:09 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));
|
|
|
|
|
2011-09-15 15:50:28 -04:00
|
|
|
if (metaWindow == NULL)
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
|
2011-08-27 05:43:09 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
XserverRegion output_region;
|
2011-09-15 15:50:28 -04:00
|
|
|
XRectangle screen_rect, window_bounds;
|
2011-08-27 05:43:09 -04:00
|
|
|
int width, height;
|
2011-09-15 15:50:28 -04:00
|
|
|
MetaRectangle rect;
|
|
|
|
|
2013-11-19 12:24:45 -05:00
|
|
|
meta_window_get_frame_rect (metaWindow, &rect);
|
2011-09-15 15:50:28 -04:00
|
|
|
|
|
|
|
window_bounds.x = rect.x;
|
|
|
|
window_bounds.y = rect.y;
|
|
|
|
window_bounds.width = rect.width;
|
|
|
|
window_bounds.height = rect.height;
|
2011-08-27 05:43:09 -04:00
|
|
|
|
|
|
|
meta_screen_get_size (screen, &width, &height);
|
|
|
|
screen_rect.x = 0;
|
|
|
|
screen_rect.y = 0;
|
|
|
|
screen_rect.width = width;
|
|
|
|
screen_rect.height = height;
|
|
|
|
|
2011-09-15 15:50:28 -04:00
|
|
|
output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);
|
|
|
|
|
2011-08-27 05:43:09 -04:00
|
|
|
XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region);
|
|
|
|
XFixesDestroyRegion (xdisplay, output_region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-06 17:10:44 -05:00
|
|
|
static void
|
|
|
|
set_unredirected_window (MetaCompScreen *info,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
if (info->unredirected_window == window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (info->unredirected_window != NULL)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window));
|
2013-12-06 17:36:09 -05:00
|
|
|
meta_window_actor_set_unredirected (window_actor, FALSE);
|
2013-12-06 17:10:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
info->unredirected_window = window;
|
|
|
|
|
|
|
|
if (info->unredirected_window != NULL)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window));
|
2013-12-06 17:36:09 -05:00
|
|
|
meta_window_actor_set_unredirected (window_actor, TRUE);
|
2013-12-06 17:10:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
meta_shape_cow_for_window (info->screen, info->unredirected_window);
|
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_add_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2008-11-23 14:28:40 -05:00
|
|
|
MetaScreen *screen = meta_window_get_screen (window);
|
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_add_window\n");
|
2008-11-23 14:28:40 -05:00
|
|
|
meta_error_trap_push (display);
|
2008-10-24 05:07:24 -04:00
|
|
|
|
2008-11-23 14:28:40 -05:00
|
|
|
add_win (window);
|
|
|
|
|
2010-10-25 14:44:30 -04:00
|
|
|
meta_error_trap_pop (display);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_remove_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = NULL;
|
2011-08-27 05:43:09 -04:00
|
|
|
MetaScreen *screen;
|
|
|
|
MetaCompScreen *info;
|
2008-12-18 07:41:56 -05:00
|
|
|
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_remove_window\n");
|
2010-10-18 13:27:14 -04:00
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
if (!window_actor)
|
2008-11-23 14:28:40 -05:00
|
|
|
return;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2013-12-06 17:10:44 -05:00
|
|
|
screen = meta_window_get_screen (window);
|
|
|
|
info = meta_screen_get_compositor_data (screen);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-12-06 17:10:44 -05:00
|
|
|
if (info->unredirected_window == window)
|
|
|
|
set_unredirected_window (info, NULL);
|
2011-08-27 05:43:09 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_destroy (window_actor);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
2011-06-13 17:53:23 -04:00
|
|
|
meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
|
|
|
gboolean updates_frozen)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2011-06-13 17:53:23 -04:00
|
|
|
MetaWindowActor *window_actor;
|
|
|
|
|
|
|
|
DEBUG_TRACE ("meta_compositor_set_updates_frozen\n");
|
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
if (!window_actor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2013-02-14 13:40:55 -05:00
|
|
|
void
|
|
|
|
meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
|
|
|
gboolean no_delay_frame)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor;
|
|
|
|
|
|
|
|
DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n");
|
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
if (!window_actor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
|
|
|
|
}
|
|
|
|
|
2009-08-12 00:12:52 -04:00
|
|
|
static gboolean
|
2012-11-20 19:27:02 -05:00
|
|
|
is_grabbed_event (MetaDisplay *display,
|
|
|
|
XEvent *event)
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
2012-11-20 19:27:02 -05:00
|
|
|
if (event->type == GenericEvent &&
|
|
|
|
event->xcookie.extension == display->xinput_opcode)
|
|
|
|
{
|
|
|
|
XIEvent *xev = (XIEvent *) event->xcookie.data;
|
|
|
|
|
|
|
|
switch (xev->evtype)
|
|
|
|
{
|
|
|
|
case XI_Motion:
|
|
|
|
case XI_ButtonPress:
|
|
|
|
case XI_ButtonRelease:
|
|
|
|
case XI_KeyPress:
|
|
|
|
case XI_KeyRelease:
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-12 00:12:52 -04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-07-20 00:29:06 -04:00
|
|
|
|
|
|
|
void
|
2013-08-23 22:20:49 -04:00
|
|
|
meta_compositor_window_shape_changed (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
2011-07-20 00:29:06 -04:00
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor;
|
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
2013-03-13 22:34:20 -04:00
|
|
|
if (!window_actor)
|
|
|
|
return;
|
|
|
|
|
2011-07-20 00:29:06 -04:00
|
|
|
meta_window_actor_update_shape (window_actor);
|
|
|
|
}
|
|
|
|
|
2013-12-06 13:44:31 -05:00
|
|
|
void
|
|
|
|
meta_compositor_window_opacity_changed (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor;
|
|
|
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
if (!window_actor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_window_actor_update_opacity (window_actor);
|
|
|
|
}
|
|
|
|
|
2012-12-21 07:32:41 -05:00
|
|
|
/* Clutter makes the assumption that there is only one X window
|
|
|
|
* per stage, which is a valid assumption to make for a generic
|
|
|
|
* application toolkit. As such, it will ignore any events sent
|
|
|
|
* to the a stage that isn't its X window.
|
|
|
|
*
|
2013-12-05 16:36:40 -05:00
|
|
|
* When running as an X window manager, we need to respond to
|
|
|
|
* events from lots of windows. Trick Clutter into translating
|
|
|
|
* these events by pretending we got an event on the stage window.
|
2012-12-21 07:32:41 -05:00
|
|
|
*/
|
|
|
|
static void
|
2013-12-05 16:36:40 -05:00
|
|
|
maybe_spoof_event_as_stage_event (MetaCompScreen *info,
|
|
|
|
XEvent *event)
|
2012-12-21 07:32:41 -05:00
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_screen_get_display (info->screen);
|
|
|
|
|
|
|
|
if (event->type == GenericEvent &&
|
|
|
|
event->xcookie.extension == display->xinput_opcode)
|
|
|
|
{
|
|
|
|
XIEvent *input_event = (XIEvent *) event->xcookie.data;
|
|
|
|
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_Motion:
|
|
|
|
case XI_ButtonPress:
|
|
|
|
case XI_ButtonRelease:
|
2013-12-05 16:36:40 -05:00
|
|
|
case XI_KeyPress:
|
|
|
|
case XI_KeyRelease:
|
2012-12-21 07:32:41 -05:00
|
|
|
{
|
|
|
|
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
|
2013-12-05 16:36:40 -05:00
|
|
|
|
|
|
|
/* If this is a GTK+ widget, like a window menu, let GTK+ handle
|
|
|
|
* it as-is without mangling. */
|
|
|
|
if (meta_ui_window_is_widget (info->screen->ui, device_event->event))
|
|
|
|
break;
|
|
|
|
|
|
|
|
device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
2012-12-21 07:32:41 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
|
|
|
* meta_compositor_process_event: (skip)
|
2013-02-15 13:42:08 -05:00
|
|
|
* @compositor:
|
|
|
|
* @event:
|
|
|
|
* @window:
|
2010-09-01 15:39:53 -04:00
|
|
|
*
|
|
|
|
*/
|
2009-06-25 16:17:27 -04:00
|
|
|
gboolean
|
|
|
|
meta_compositor_process_event (MetaCompositor *compositor,
|
|
|
|
XEvent *event,
|
|
|
|
MetaWindow *window)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2012-11-20 19:27:02 -05:00
|
|
|
if (compositor->modal_plugin && is_grabbed_event (compositor->display, event))
|
2009-08-12 00:12:52 -04:00
|
|
|
{
|
2013-09-04 12:11:43 -04:00
|
|
|
_meta_plugin_xevent_filter (compositor->modal_plugin, event);
|
2009-08-12 00:12:52 -04:00
|
|
|
|
|
|
|
/* We always consume events even if the plugin says it didn't handle them;
|
|
|
|
* exclusive is exclusive */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-10-02 07:16:15 -04:00
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info;
|
|
|
|
MetaScreen *screen;
|
|
|
|
|
|
|
|
screen = meta_window_get_screen (window);
|
|
|
|
info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
|
2008-11-27 08:40:52 -05:00
|
|
|
{
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
|
2008-11-22 13:07:32 -05:00
|
|
|
return TRUE;
|
2008-11-27 08:40:52 -05:00
|
|
|
}
|
2008-10-02 07:16:15 -04:00
|
|
|
}
|
2008-10-16 10:50:03 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
2009-06-25 16:29:20 -04:00
|
|
|
l = meta_display_get_screens (compositor->display);
|
2008-10-16 10:50:03 -04:00
|
|
|
|
|
|
|
while (l)
|
|
|
|
{
|
|
|
|
MetaScreen *screen = l->data;
|
|
|
|
MetaCompScreen *info;
|
|
|
|
|
|
|
|
info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
2013-12-05 16:36:40 -05:00
|
|
|
maybe_spoof_event_as_stage_event (info, event);
|
2012-12-21 07:32:41 -05:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
|
2008-10-16 10:50:03 -04:00
|
|
|
{
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
|
2008-11-22 13:07:32 -05:00
|
|
|
return TRUE;
|
2008-10-16 10:50:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
l = l->next;
|
|
|
|
}
|
|
|
|
}
|
2008-10-02 07:16:15 -04:00
|
|
|
|
2013-12-06 13:44:31 -05:00
|
|
|
if (!meta_is_wayland_compositor () &&
|
|
|
|
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2013-12-06 13:44:31 -05:00
|
|
|
/* Core code doesn't handle damage events, so we need to extract the MetaWindow
|
|
|
|
* ourselves
|
|
|
|
*/
|
|
|
|
if (window == NULL)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2013-12-06 13:44:31 -05:00
|
|
|
Window xwin = ((XDamageNotifyEvent *) event)->drawable;
|
|
|
|
window = meta_display_lookup_x_window (compositor->display, xwin);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
2013-12-06 13:44:31 -05:00
|
|
|
|
|
|
|
DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
|
|
|
|
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
2008-08-18 10:44:26 -04:00
|
|
|
|
2009-01-30 06:57:46 -05:00
|
|
|
/* Clutter needs to know about MapNotify events otherwise it will
|
|
|
|
think the stage is invisible */
|
2012-01-07 17:21:32 -05:00
|
|
|
if (!meta_is_wayland_compositor () && event->type == MapNotify)
|
2009-01-30 06:57:46 -05:00
|
|
|
clutter_x11_handle_event (event);
|
|
|
|
|
2008-11-22 13:07:32 -05:00
|
|
|
/* The above handling is basically just "observing" the events, so we return
|
|
|
|
* FALSE to indicate that the event should not be filtered out; if we have
|
|
|
|
* GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
2008-06-04 08:58:36 -04:00
|
|
|
}
|
|
|
|
|
2012-08-09 20:27:18 -04:00
|
|
|
gboolean
|
|
|
|
meta_compositor_filter_keybinding (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen,
|
|
|
|
MetaKeyBinding *binding)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
if (info->plugin_mgr)
|
|
|
|
return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
Simplify relationship between mapping and visibility
Previously, changes to the visibility of a window could be indicated
by meta_compositor_map_window(), meta_compositor_unminimize_window(),
meta_compositor_set_window_hidden(), etc, with the exact behavior
depending on the 'live_hidden_windows' preference.
Simplify this so that visibility is controlled by:
meta_compositor_show_window()
meta_compositor_hide_window()
With an 'effect' parameter provided to indicate the appropriate
effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
The map state of the window is signalled separately by:
meta_compositor_map_window()
meta_compositor_unmap_window()
And is used only to control resource handling.
Other changes:
* The desired effect on show/hide is explicitly stored in
MetaWindow, avoiding the need for the was_minimized flag.
At idle, once we calculate the window state, we pass the
effect to the compositor if it matches the new window
state, and then clear the effect to start over for future
map state changes.
* meta_compositor_switch_workspace() is called before any windows
are hidden or shown, allowing the compositor to avoid hiding
or showing an effect for windows involved in the switch.
http://bugzilla.gnome.org/show_bug.cgi?id=582341
* Handling of post-effect cleanups for MutterWindow are
simplified - instead of trying to do different things based
on the individual needs of different effects, we just wait until
all effects complete and sync the window state to what it
should be.
* On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
that we've done so, so it can clean up and unbind. (The
unbinding doesn't seem to be working properly because of
ClutterGLXPixmap or video driver issues.)
http://bugzilla.gnome.org/show_bug.cgi?id=587251
2009-06-28 17:10:40 -04:00
|
|
|
meta_compositor_show_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
|
|
|
MetaCompEffect effect)
|
2008-06-09 12:50:56 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
Simplify relationship between mapping and visibility
Previously, changes to the visibility of a window could be indicated
by meta_compositor_map_window(), meta_compositor_unminimize_window(),
meta_compositor_set_window_hidden(), etc, with the exact behavior
depending on the 'live_hidden_windows' preference.
Simplify this so that visibility is controlled by:
meta_compositor_show_window()
meta_compositor_hide_window()
With an 'effect' parameter provided to indicate the appropriate
effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
The map state of the window is signalled separately by:
meta_compositor_map_window()
meta_compositor_unmap_window()
And is used only to control resource handling.
Other changes:
* The desired effect on show/hide is explicitly stored in
MetaWindow, avoiding the need for the was_minimized flag.
At idle, once we calculate the window state, we pass the
effect to the compositor if it matches the new window
state, and then clear the effect to start over for future
map state changes.
* meta_compositor_switch_workspace() is called before any windows
are hidden or shown, allowing the compositor to avoid hiding
or showing an effect for windows involved in the switch.
http://bugzilla.gnome.org/show_bug.cgi?id=582341
* Handling of post-effect cleanups for MutterWindow are
simplified - instead of trying to do different things based
on the individual needs of different effects, we just wait until
all effects complete and sync the window state to what it
should be.
* On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
that we've done so, so it can clean up and unbind. (The
unbinding doesn't seem to be working properly because of
ClutterGLXPixmap or video driver issues.)
http://bugzilla.gnome.org/show_bug.cgi?id=587251
2009-06-28 17:10:40 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_show_window\n");
|
2010-10-18 13:27:14 -04:00
|
|
|
if (!window_actor)
|
2008-11-23 14:28:40 -05:00
|
|
|
return;
|
2008-09-18 11:09:11 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_show (window_actor, effect);
|
2008-11-23 14:28:40 -05:00
|
|
|
}
|
2008-06-09 12:50:56 -04:00
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
Simplify relationship between mapping and visibility
Previously, changes to the visibility of a window could be indicated
by meta_compositor_map_window(), meta_compositor_unminimize_window(),
meta_compositor_set_window_hidden(), etc, with the exact behavior
depending on the 'live_hidden_windows' preference.
Simplify this so that visibility is controlled by:
meta_compositor_show_window()
meta_compositor_hide_window()
With an 'effect' parameter provided to indicate the appropriate
effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
The map state of the window is signalled separately by:
meta_compositor_map_window()
meta_compositor_unmap_window()
And is used only to control resource handling.
Other changes:
* The desired effect on show/hide is explicitly stored in
MetaWindow, avoiding the need for the was_minimized flag.
At idle, once we calculate the window state, we pass the
effect to the compositor if it matches the new window
state, and then clear the effect to start over for future
map state changes.
* meta_compositor_switch_workspace() is called before any windows
are hidden or shown, allowing the compositor to avoid hiding
or showing an effect for windows involved in the switch.
http://bugzilla.gnome.org/show_bug.cgi?id=582341
* Handling of post-effect cleanups for MutterWindow are
simplified - instead of trying to do different things based
on the individual needs of different effects, we just wait until
all effects complete and sync the window state to what it
should be.
* On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
that we've done so, so it can clean up and unbind. (The
unbinding doesn't seem to be working properly because of
ClutterGLXPixmap or video driver issues.)
http://bugzilla.gnome.org/show_bug.cgi?id=587251
2009-06-28 17:10:40 -04:00
|
|
|
meta_compositor_hide_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
|
|
|
MetaCompEffect effect)
|
2008-11-23 14:28:40 -05:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
Simplify relationship between mapping and visibility
Previously, changes to the visibility of a window could be indicated
by meta_compositor_map_window(), meta_compositor_unminimize_window(),
meta_compositor_set_window_hidden(), etc, with the exact behavior
depending on the 'live_hidden_windows' preference.
Simplify this so that visibility is controlled by:
meta_compositor_show_window()
meta_compositor_hide_window()
With an 'effect' parameter provided to indicate the appropriate
effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
The map state of the window is signalled separately by:
meta_compositor_map_window()
meta_compositor_unmap_window()
And is used only to control resource handling.
Other changes:
* The desired effect on show/hide is explicitly stored in
MetaWindow, avoiding the need for the was_minimized flag.
At idle, once we calculate the window state, we pass the
effect to the compositor if it matches the new window
state, and then clear the effect to start over for future
map state changes.
* meta_compositor_switch_workspace() is called before any windows
are hidden or shown, allowing the compositor to avoid hiding
or showing an effect for windows involved in the switch.
http://bugzilla.gnome.org/show_bug.cgi?id=582341
* Handling of post-effect cleanups for MutterWindow are
simplified - instead of trying to do different things based
on the individual needs of different effects, we just wait until
all effects complete and sync the window state to what it
should be.
* On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
that we've done so, so it can clean up and unbind. (The
unbinding doesn't seem to be working properly because of
ClutterGLXPixmap or video driver issues.)
http://bugzilla.gnome.org/show_bug.cgi?id=587251
2009-06-28 17:10:40 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_hide_window\n");
|
2010-10-18 13:27:14 -04:00
|
|
|
if (!window_actor)
|
2008-10-24 05:07:24 -04:00
|
|
|
return;
|
2008-09-18 11:09:11 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_hide (window_actor, effect);
|
2008-06-09 12:50:56 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_maximize_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
2009-06-28 12:26:23 -04:00
|
|
|
MetaRectangle *old_rect,
|
|
|
|
MetaRectangle *new_rect)
|
2008-09-18 11:09:11 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_maximize_window\n");
|
2010-10-18 13:27:14 -04:00
|
|
|
if (!window_actor)
|
2008-09-18 11:09:11 -04:00
|
|
|
return;
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_maximize (window_actor, old_rect, new_rect);
|
2008-09-18 11:09:11 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_unmaximize_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window,
|
2009-06-28 12:26:23 -04:00
|
|
|
MetaRectangle *old_rect,
|
|
|
|
MetaRectangle *new_rect)
|
2008-08-19 06:47:30 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_unmaximize_window\n");
|
2010-10-18 13:27:14 -04:00
|
|
|
if (!window_actor)
|
2008-08-19 06:47:30 -04:00
|
|
|
return;
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
|
2008-09-18 11:09:11 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_switch_workspace (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen,
|
|
|
|
MetaWorkspace *from,
|
|
|
|
MetaWorkspace *to,
|
|
|
|
MetaMotionDirection direction)
|
2008-09-18 11:09:11 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info;
|
|
|
|
gint to_indx, from_indx;
|
|
|
|
|
|
|
|
info = meta_screen_get_compositor_data (screen);
|
|
|
|
to_indx = meta_workspace_index (to);
|
|
|
|
from_indx = meta_workspace_index (from);
|
2008-11-07 05:13:40 -05:00
|
|
|
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_switch_workspace\n");
|
2008-09-18 11:09:11 -04:00
|
|
|
|
2009-07-06 03:41:59 -04:00
|
|
|
if (!info) /* During startup before manage_screen() */
|
|
|
|
return;
|
|
|
|
|
2008-09-18 11:09:11 -04:00
|
|
|
info->switch_workspace_in_progress++;
|
|
|
|
|
|
|
|
if (!info->plugin_mgr ||
|
2010-10-18 13:27:14 -04:00
|
|
|
!meta_plugin_manager_switch_workspace (info->plugin_mgr,
|
2008-10-24 05:07:24 -04:00
|
|
|
from_indx,
|
|
|
|
to_indx,
|
|
|
|
direction))
|
2008-09-18 11:09:11 -04:00
|
|
|
{
|
|
|
|
info->switch_workspace_in_progress--;
|
2008-10-24 05:07:24 -04:00
|
|
|
|
|
|
|
/* We have to explicitely 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.
|
|
|
|
*/
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_finish_workspace_switch (info);
|
2008-09-18 11:09:11 -04:00
|
|
|
}
|
2008-08-19 06:47:30 -04:00
|
|
|
}
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2008-11-23 14:28:40 -05:00
|
|
|
static void
|
2010-11-13 14:45:01 -05:00
|
|
|
sync_actor_stacking (MetaCompScreen *info)
|
2008-11-23 14:28:40 -05:00
|
|
|
{
|
2010-11-13 14:45:01 -05:00
|
|
|
GList *children;
|
2013-02-13 23:10:33 -05:00
|
|
|
GList *expected_window_node;
|
2008-11-23 14:28:40 -05:00
|
|
|
GList *tmp;
|
2010-11-13 14:45:01 -05:00
|
|
|
GList *old;
|
2013-01-23 15:54:41 -05:00
|
|
|
GList *backgrounds;
|
2013-02-13 23:10:33 -05:00
|
|
|
gboolean has_windows;
|
2010-11-13 14:45:01 -05:00
|
|
|
gboolean reordered;
|
2008-12-18 07:41:56 -05:00
|
|
|
|
2010-11-13 14:45:01 -05:00
|
|
|
/* NB: The first entries in the lists are stacked the lowest */
|
2008-11-23 14:28:40 -05:00
|
|
|
|
2010-11-13 14:45:01 -05:00
|
|
|
/* 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 */
|
|
|
|
|
2012-01-17 09:16:46 -05:00
|
|
|
children = clutter_actor_get_children (info->window_group);
|
2013-09-03 16:03:17 -04:00
|
|
|
has_windows = FALSE;
|
2010-11-13 14:45:01 -05:00
|
|
|
reordered = FALSE;
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
/* 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.)
|
|
|
|
*/
|
|
|
|
|
2013-01-23 15:54:41 -05:00
|
|
|
/* 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;
|
2013-02-13 23:10:33 -05:00
|
|
|
expected_window_node = info->windows;
|
|
|
|
for (old = children; old != NULL; old = old->next)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2013-02-13 23:10:33 -05:00
|
|
|
ClutterActor *actor = old->data;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2013-01-23 15:54:41 -05:00
|
|
|
if (META_IS_BACKGROUND_GROUP (actor) ||
|
|
|
|
META_IS_BACKGROUND_ACTOR (actor))
|
2010-11-13 14:45:01 -05:00
|
|
|
{
|
2013-01-23 15:54:41 -05:00
|
|
|
backgrounds = g_list_prepend (backgrounds, actor);
|
|
|
|
|
2013-02-13 23:10:33 -05:00
|
|
|
if (has_windows)
|
|
|
|
reordered = TRUE;
|
2010-11-13 14:45:01 -05:00
|
|
|
}
|
2013-02-13 23:10:33 -05:00
|
|
|
else if (META_IS_WINDOW_ACTOR (actor) && !reordered)
|
|
|
|
{
|
|
|
|
has_windows = TRUE;
|
2010-11-13 14:45:01 -05:00
|
|
|
|
2013-02-13 23:10:33 -05:00
|
|
|
if (expected_window_node != NULL && actor == expected_window_node->data)
|
|
|
|
expected_window_node = expected_window_node->next;
|
|
|
|
else
|
|
|
|
reordered = TRUE;
|
|
|
|
}
|
2010-11-13 14:45:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (children);
|
|
|
|
|
|
|
|
if (!reordered)
|
2013-01-23 15:54:41 -05:00
|
|
|
{
|
|
|
|
g_list_free (backgrounds);
|
|
|
|
return;
|
|
|
|
}
|
2010-11-13 14:45:01 -05:00
|
|
|
|
2013-02-13 23:10:33 -05:00
|
|
|
/* reorder the actors by lowering them in turn to the bottom of the stack.
|
2013-03-12 12:01:51 -04:00
|
|
|
* 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)
|
|
|
|
*/
|
2010-11-13 14:45:01 -05:00
|
|
|
for (tmp = g_list_last (info->windows); tmp != NULL; tmp = tmp->prev)
|
2008-11-23 14:28:40 -05:00
|
|
|
{
|
2013-03-12 12:01:51 -04:00
|
|
|
ClutterActor *actor = tmp->data, *parent;
|
2008-11-23 14:28:40 -05:00
|
|
|
|
2013-03-12 12:01:51 -04:00
|
|
|
parent = clutter_actor_get_parent (actor);
|
|
|
|
clutter_actor_set_child_below_sibling (parent, actor, NULL);
|
2008-11-23 14:28:40 -05:00
|
|
|
}
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2013-01-23 15:54:41 -05:00
|
|
|
/* 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)
|
|
|
|
{
|
2013-03-12 12:01:51 -04:00
|
|
|
ClutterActor *actor = tmp->data, *parent;
|
2013-01-23 15:54:41 -05:00
|
|
|
|
2013-03-12 12:01:51 -04:00
|
|
|
parent = clutter_actor_get_parent (actor);
|
|
|
|
clutter_actor_set_child_below_sibling (parent, actor, NULL);
|
2013-01-23 15:54:41 -05:00
|
|
|
}
|
|
|
|
g_list_free (backgrounds);
|
2008-11-23 14:28:40 -05:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_sync_stack (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen,
|
|
|
|
GList *stack)
|
2008-10-24 05:07:24 -04:00
|
|
|
{
|
2009-06-26 17:05:11 -04:00
|
|
|
GList *old_stack;
|
2008-11-03 09:50:22 -05:00
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
2008-11-27 08:40:52 -05:00
|
|
|
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_sync_stack\n");
|
2008-11-07 05:13:40 -05:00
|
|
|
|
2009-06-26 17:05:11 -04:00
|
|
|
/* 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 */
|
2010-10-18 13:27:14 -04:00
|
|
|
old_stack = g_list_reverse (info->windows); /* The old stack of MetaWindowActor */
|
2009-06-26 17:05:11 -04:00
|
|
|
info->windows = NULL;
|
|
|
|
|
|
|
|
while (TRUE)
|
2008-10-24 05:07:24 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor;
|
2009-06-26 17:05:11 -04:00
|
|
|
MetaWindow *old_window = NULL, *stack_window = NULL, *window;
|
2008-11-03 09:50:22 -05:00
|
|
|
|
2009-06-26 17:05:11 -04:00
|
|
|
/* 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;
|
2010-10-18 13:27:14 -04:00
|
|
|
old_window = meta_window_actor_get_meta_window (old_actor);
|
2009-06-26 17:05:11 -04:00
|
|
|
|
|
|
|
if (old_window->hidden &&
|
2010-10-18 13:27:14 -04:00
|
|
|
!meta_window_actor_effect_in_progress (old_actor))
|
2011-01-26 16:35:18 -05:00
|
|
|
{
|
|
|
|
old_stack = g_list_delete_link (old_stack, old_stack);
|
|
|
|
old_actor = NULL;
|
|
|
|
}
|
2009-06-26 17:05:11 -04:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And the remaining top actor in the new stack */
|
|
|
|
while (stack)
|
|
|
|
{
|
|
|
|
stack_window = stack->data;
|
2010-10-18 13:27:14 -04:00
|
|
|
stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window));
|
2009-06-26 17:05:11 -04:00
|
|
|
if (!stack_actor)
|
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_verbose ("Failed to find corresponding MetaWindowActor "
|
2009-06-26 17:05:11 -04:00
|
|
|
"for window %s\n", 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))
|
|
|
|
{
|
|
|
|
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.)
|
|
|
|
*/
|
|
|
|
info->windows = g_list_prepend (info->windows, actor);
|
2008-11-07 05:13:40 -05:00
|
|
|
|
2009-06-26 17:05:11 -04:00
|
|
|
stack = g_list_remove (stack, window);
|
|
|
|
old_stack = g_list_remove (old_stack, actor);
|
2008-11-03 09:50:22 -05:00
|
|
|
}
|
2008-11-23 14:28:40 -05:00
|
|
|
|
2010-11-13 14:45:01 -05:00
|
|
|
sync_actor_stacking (info);
|
2008-11-03 09:50:22 -05:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_sync_window_geometry (MetaCompositor *compositor,
|
2013-02-15 21:27:00 -05:00
|
|
|
MetaWindow *window,
|
|
|
|
gboolean did_placement)
|
2008-11-27 08:40:52 -05:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
|
|
|
MetaScreen *screen = meta_window_get_screen (window);
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
2008-11-27 08:40:52 -05:00
|
|
|
|
2009-06-27 12:10:32 -04:00
|
|
|
DEBUG_TRACE ("meta_compositor_sync_window_geometry\n");
|
2008-11-27 08:40:52 -05:00
|
|
|
g_return_if_fail (info);
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
if (!window_actor)
|
2008-11-27 08:40:52 -05:00
|
|
|
return;
|
|
|
|
|
2013-02-15 21:27:00 -05:00
|
|
|
meta_window_actor_sync_actor_geometry (window_actor, did_placement);
|
2008-11-27 08:40:52 -05:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:17:27 -04:00
|
|
|
void
|
|
|
|
meta_compositor_sync_screen_size (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen,
|
|
|
|
guint width,
|
|
|
|
guint height)
|
2008-11-27 08:40:52 -05:00
|
|
|
{
|
2013-08-19 05:12:42 -04:00
|
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
{
|
2013-08-19 05:12:42 -04:00
|
|
|
/* FIXME: when we support a sliced stage, this is the place to do it
|
|
|
|
But! This is not the place to apply KMS config, here we only
|
|
|
|
notify Clutter/Cogl/GL that the framebuffer sizes changed.
|
|
|
|
|
|
|
|
And because for now clutter does not do sliced, we use one
|
|
|
|
framebuffer the size of the whole screen, and when running on
|
|
|
|
bare metal MetaMonitorManager will do the necessary tricks to
|
|
|
|
show the right portions on the right screens.
|
|
|
|
*/
|
|
|
|
|
|
|
|
clutter_actor_set_size (info->stage, width, height);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Display *xdisplay;
|
|
|
|
Window xwin;
|
2008-11-27 08:40:52 -05:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
|
|
|
|
g_return_if_fail (info);
|
2008-11-27 08:40:52 -05:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
compositor: Use raw Xlib to resize the compositor window
If we get two configure events on the root window in close
sequence, then we could get the sequence:
ConfigureNotify on the root window w1xh1
Processed by Mutter
clutter_actor_set_size(stage, w1, h1)
<relayout happens, stage window resized by clutter>
ConfigureNotify on the root window, w2xh2
Processed by Mutter
clutter_actor_set_size(stage, w2, h2)
ConfigureNotify on the stage window, w1, h1)
Processed by Clutter
clutter_actor_set_size(stage, w1, h1)
<relayout happens, stage window resized by clutter>
Leaving the stage at the wrong size. To avoid fighting with Clutter,
switch to resizing the stage with XResizeWindow(), similar to how a
toplevel window is handled by a window manager.
2011-12-15 16:03:00 -05:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
XResizeWindow (xdisplay, xwin, width, height);
|
|
|
|
}
|
2013-08-19 05:12:42 -04:00
|
|
|
|
|
|
|
meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
|
|
|
|
meta_screen_get_screen_number (screen),
|
|
|
|
width, height);
|
2008-11-27 08:40:52 -05:00
|
|
|
}
|
|
|
|
|
2012-11-12 14:11:08 -05:00
|
|
|
static void
|
|
|
|
frame_callback (CoglOnscreen *onscreen,
|
|
|
|
CoglFrameEvent event,
|
|
|
|
CoglFrameInfo *frame_info,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info = user_data;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
if (event == COGL_FRAME_EVENT_COMPLETE)
|
|
|
|
{
|
|
|
|
gint64 presentation_time_cogl = cogl_frame_info_get_presentation_time (frame_info);
|
|
|
|
gint64 presentation_time;
|
|
|
|
|
|
|
|
if (presentation_time_cogl != 0)
|
|
|
|
{
|
|
|
|
/* Cogl reports presentation in terms of its own clock, which is
|
|
|
|
* guaranteed to be in nanoseconds but with no specified base. The
|
|
|
|
* normal case with the open source GPU drivers on Linux 3.8 and
|
|
|
|
* newer is that the base of cogl_get_clock_time() is that of
|
|
|
|
* clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time),
|
|
|
|
* but there's no exposure of that through the API. clock_gettime()
|
|
|
|
* is fairly fast, so calling it twice and subtracting to get a
|
|
|
|
* nearly-zero number is acceptable, if a litle ugly.
|
|
|
|
*/
|
|
|
|
CoglContext *context = cogl_framebuffer_get_context (COGL_FRAMEBUFFER (onscreen));
|
|
|
|
gint64 current_cogl_time = cogl_get_clock_time (context);
|
|
|
|
gint64 current_monotonic_time = g_get_monotonic_time ();
|
|
|
|
|
|
|
|
presentation_time =
|
|
|
|
current_monotonic_time + (presentation_time_cogl - current_cogl_time) / 1000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
presentation_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (l = info->windows; l; l = l->next)
|
|
|
|
meta_window_actor_frame_complete (l->data, frame_info, presentation_time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-28 12:26:23 -04:00
|
|
|
static void
|
|
|
|
pre_paint_windows (MetaCompScreen *info)
|
|
|
|
{
|
|
|
|
GList *l;
|
2011-08-27 05:43:09 -04:00
|
|
|
MetaWindowActor *top_window;
|
|
|
|
|
2012-11-12 14:11:08 -05:00
|
|
|
if (info->onscreen == NULL)
|
|
|
|
{
|
|
|
|
info->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ());
|
|
|
|
info->frame_closure = cogl_onscreen_add_frame_callback (info->onscreen,
|
|
|
|
frame_callback,
|
|
|
|
info,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2011-08-30 06:42:01 -04:00
|
|
|
if (info->windows == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-12-06 17:10:44 -05:00
|
|
|
top_window = g_list_last (info->windows)->data;
|
2011-08-27 05:43:09 -04:00
|
|
|
|
2013-12-06 17:10:44 -05:00
|
|
|
if (meta_window_actor_should_unredirect (top_window) &&
|
|
|
|
info->disable_unredirect_count == 0)
|
|
|
|
set_unredirected_window (info, meta_window_actor_get_meta_window (top_window));
|
|
|
|
else
|
|
|
|
set_unredirected_window (info, NULL);
|
2009-06-28 12:26:23 -04:00
|
|
|
|
|
|
|
for (l = info->windows; l; l = l->next)
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_window_actor_pre_paint (l->data);
|
2009-06-28 12:26:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_repaint_func (gpointer data)
|
2009-06-28 12:26:23 -04:00
|
|
|
{
|
|
|
|
MetaCompositor *compositor = data;
|
|
|
|
GSList *screens = meta_display_get_screens (compositor->display);
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = screens; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaScreen *screen = l->data;
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
if (!info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pre_paint_windows (info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-11-11 16:24:43 -05:00
|
|
|
static void
|
|
|
|
on_shadow_factory_changed (MetaShadowFactory *factory,
|
|
|
|
MetaCompositor *compositor)
|
|
|
|
{
|
|
|
|
GSList *screens = meta_display_get_screens (compositor->display);
|
|
|
|
GList *l;
|
|
|
|
GSList *sl;
|
|
|
|
|
|
|
|
for (sl = screens; sl; sl = sl->next)
|
|
|
|
{
|
|
|
|
MetaScreen *screen = sl->data;
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
if (!info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (l = info->windows; l; l = l->next)
|
|
|
|
meta_window_actor_invalidate_shadow (l->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
|
|
|
* meta_compositor_new: (skip)
|
2013-02-15 13:42:08 -05:00
|
|
|
* @display:
|
2010-09-01 15:39:53 -04:00
|
|
|
*
|
|
|
|
*/
|
2008-06-04 08:58:36 -04:00
|
|
|
MetaCompositor *
|
2009-06-25 16:17:27 -04:00
|
|
|
meta_compositor_new (MetaDisplay *display)
|
2008-06-04 08:58:36 -04:00
|
|
|
{
|
2008-08-20 04:33:39 -04:00
|
|
|
MetaCompositor *compositor;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2008-06-04 15:51:08 -04:00
|
|
|
if (!composite_at_least_version (display, 0, 3))
|
|
|
|
return NULL;
|
|
|
|
|
2009-06-25 16:29:20 -04:00
|
|
|
compositor = g_new0 (MetaCompositor, 1);
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2009-06-25 16:29:20 -04:00
|
|
|
compositor->display = display;
|
2008-06-04 08:58:36 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
if (g_getenv("META_DISABLE_MIPMAPS"))
|
2009-06-25 16:29:20 -04:00
|
|
|
compositor->no_mipmaps = TRUE;
|
2008-11-05 06:48:07 -05:00
|
|
|
|
2010-11-11 16:24:43 -05:00
|
|
|
g_signal_connect (meta_shadow_factory_get_default (),
|
|
|
|
"changed",
|
|
|
|
G_CALLBACK (on_shadow_factory_changed),
|
|
|
|
compositor);
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
|
2009-06-28 12:26:23 -04:00
|
|
|
compositor,
|
|
|
|
NULL);
|
|
|
|
|
2008-06-04 08:58:36 -04:00
|
|
|
return compositor;
|
|
|
|
}
|
2008-06-06 09:17:38 -04:00
|
|
|
|
2010-09-01 15:39:53 -04:00
|
|
|
/**
|
2010-10-18 13:27:14 -04:00
|
|
|
* meta_get_overlay_window: (skip)
|
2013-02-15 13:42:08 -05:00
|
|
|
* @screen: a #MetaScreen
|
2010-09-01 15:39:53 -04:00
|
|
|
*
|
|
|
|
*/
|
2008-10-16 02:50:49 -04:00
|
|
|
Window
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_get_overlay_window (MetaScreen *screen)
|
2008-10-16 02:50:49 -04:00
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
|
|
|
|
return info->output;
|
|
|
|
}
|
2011-03-18 09:36:28 -04:00
|
|
|
|
2011-08-27 05:43:09 -04:00
|
|
|
/**
|
|
|
|
* meta_disable_unredirect_for_screen:
|
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
|
|
|
* Disables unredirection, can be usefull in situations where having
|
|
|
|
* unredirected windows is undesireable like when recording a video.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_disable_unredirect_for_screen (MetaScreen *screen)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
|
|
|
if (info != NULL)
|
|
|
|
info->disable_unredirect_count = info->disable_unredirect_count + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_enable_unredirect_for_screen:
|
|
|
|
* @screen: a #MetaScreen
|
|
|
|
*
|
|
|
|
* Enables unredirection which reduces the overhead for apps like games.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_enable_unredirect_for_screen (MetaScreen *screen)
|
|
|
|
{
|
|
|
|
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
2013-06-18 15:36:20 -04:00
|
|
|
if (info != NULL && info->disable_unredirect_count == 0)
|
|
|
|
g_warning ("Called enable_unredirect_for_screen while unredirection is enabled.");
|
|
|
|
if (info != NULL && info->disable_unredirect_count > 0)
|
|
|
|
info->disable_unredirect_count = info->disable_unredirect_count - 1;
|
2011-08-27 05:43:09 -04:00
|
|
|
}
|
|
|
|
|
2011-03-18 09:36:28 -04:00
|
|
|
#define FLASH_TIME_MS 50
|
|
|
|
|
|
|
|
static void
|
2012-01-17 09:16:46 -05:00
|
|
|
flash_out_completed (ClutterTimeline *timeline,
|
2013-03-03 18:17:17 -05:00
|
|
|
gboolean is_finished,
|
2012-01-17 09:16:46 -05:00
|
|
|
gpointer user_data)
|
2011-03-18 09:36:28 -04:00
|
|
|
{
|
2012-01-17 09:16:46 -05:00
|
|
|
ClutterActor *flash = CLUTTER_ACTOR (user_data);
|
2011-03-18 09:36:28 -04:00
|
|
|
clutter_actor_destroy (flash);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compositor_flash_screen (MetaCompositor *compositor,
|
|
|
|
MetaScreen *screen)
|
|
|
|
{
|
|
|
|
ClutterActor *stage;
|
|
|
|
ClutterActor *flash;
|
2012-01-17 09:16:46 -05:00
|
|
|
ClutterTransition *transition;
|
2011-03-18 09:36:28 -04:00
|
|
|
gfloat width, height;
|
|
|
|
|
|
|
|
stage = meta_get_stage_for_screen (screen);
|
|
|
|
clutter_actor_get_size (stage, &width, &height);
|
|
|
|
|
2012-01-17 09:16:46 -05:00
|
|
|
flash = clutter_actor_new ();
|
|
|
|
clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black);
|
2011-03-18 09:36:28 -04:00
|
|
|
clutter_actor_set_size (flash, width, height);
|
|
|
|
clutter_actor_set_opacity (flash, 0);
|
2012-01-17 09:16:46 -05:00
|
|
|
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);
|
|
|
|
|
2013-03-03 18:17:17 -05:00
|
|
|
g_signal_connect (transition, "stopped",
|
2012-01-17 09:16:46 -05:00
|
|
|
G_CALLBACK (flash_out_completed), flash);
|
2011-03-18 09:36:28 -04:00
|
|
|
|
2012-01-17 09:16:46 -05:00
|
|
|
clutter_actor_restore_easing_state (flash);
|
2011-03-18 09:36:28 -04:00
|
|
|
}
|
2012-11-12 14:09:38 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_compositor_monotonic_time_to_server_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.
|
|
|
|
*/
|
|
|
|
gint64
|
|
|
|
meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
|
|
|
gint64 monotonic_time)
|
|
|
|
{
|
|
|
|
MetaCompositor *compositor = display->compositor;
|
|
|
|
|
|
|
|
if (compositor->server_time_query_time == 0 ||
|
|
|
|
(!compositor->server_time_is_monotonic_time &&
|
|
|
|
monotonic_time > compositor->server_time_query_time + 10*1000*1000)) /* 10 seconds */
|
|
|
|
{
|
|
|
|
guint32 server_time = meta_display_get_current_time_roundtrip (display);
|
|
|
|
gint64 server_time_usec = (gint64)server_time * 1000;
|
|
|
|
gint64 current_monotonic_time = g_get_monotonic_time ();
|
|
|
|
compositor->server_time_query_time = current_monotonic_time;
|
|
|
|
|
|
|
|
/* If the server time 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 (server_time_usec > current_monotonic_time - 1000*1000 &&
|
|
|
|
server_time_usec < current_monotonic_time + 1000*1000)
|
|
|
|
compositor->server_time_is_monotonic_time = TRUE;
|
|
|
|
|
|
|
|
compositor->server_time_offset = server_time_usec - current_monotonic_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compositor->server_time_is_monotonic_time)
|
|
|
|
return monotonic_time;
|
|
|
|
else
|
|
|
|
return monotonic_time + compositor->server_time_offset;
|
|
|
|
}
|