Compare commits

...

14 Commits

Author SHA1 Message Date
0f214e24ee Switch to using ClutterStage::after-paint
The experimental API clutter_stage_set_paint_callback() is replaced
with an ::after-paint signal as of Clutter 1.19.5.
2014-07-08 23:09:12 -04:00
cf67327f0e Leave windows in place on a crash respawn
When Mutter is restarted and cleans up the window positions
cleanly, we need to add gravity adjustments. We can detect
this easily.

 - Windows started before the window manager (should add
   add gravity adjustments)
 - Replacing a different window manager (should add gravity
   adjustments)
 - A crash (no adjustments needed)

In GNOME the first two cases shouldn't happen in normal
usage, so assume the third case (though that *shouldn't*
happen in normal usage either.)
2014-07-08 23:05:01 -04:00
8e5bb17750 Fix windows walking up the screen on restart
When a window is initially created, we need to save it's user rect
after any adjustments for gravity. Otherwise, the next time the window is
queued for a resize, it will jump back to it's initial position.

We did that for newly created windows, but on restart, when windows
were already placed, the logic skipped saving the position. Use an
explicit flag so that we always save the position for newly created
MetaWindows.
2014-07-08 23:05:01 -04:00
14d2f8fddc Add support for quad-buffer stereo
Track the stereo status of windows using the new EXT_stereo_tree
GLX extension.

When stereo is enabled or disabled, a restart is triggered via
meta_restart() after a timeout, setting a _META_ENABLE_STEREO
property on the root window to indicate whether we should
turn on a stereo stage for clutter. The property avoids a loop,
since we need to enable stereo *before* initializing Clutter and GL,
but we need GL to figure out whether we have stereo windows.

Stereo windows are drawn to the stage using new functionality
in Cogl to setup a stereo context, select which buffer to draw
to, and draw either the left or right buffer of a stereo
texture_from_pixmap.
2014-07-08 23:04:57 -04:00
c249c3f3e5 Add a framework for restarting the compositor with nice visuals
The current GNOME Shell Alt-F2 restart looks very messy and also
provides no indication to the user what is going on. We need to
restart the compositor to switch in and out of stereo mode, so
add a framework for doing this more cleanly:

Additions:

 meta_restart(): restarts the compositor with a message
 MetaDisplay::show-restart-message: signal the embedding
    shell to show a message
 MetaDisplay::restart: signal the embedding shell to restart
    itself.
 meta_is_restart(): indicates whether the current instance is a
                    restart so we can suppress login animations.

A helper program meta-restart-helper holds the composite overlay
window up during the restart to avoid visual artifacts.
2014-05-08 19:07:34 -04:00
db0383d19f MetaIdleMonitorDBus: unref the objects after exporting them
The object manager already has a reference.

https://bugzilla.gnome.org/show_bug.cgi?id=729732
2014-05-07 19:09:35 +02:00
a175b3c947 default: free the option context after parsing
We don't need it, we should free it.

https://bugzilla.gnome.org/show_bug.cgi?id=729732
2014-05-07 19:09:12 +02:00
554be56639 MetaMonitorConfig: don't always restore the previous config when opening the laptop lid
Only do it if the current configuration was actually created
as the result of closing the laptop lid.

https://bugzilla.gnome.org/show_bug.cgi?id=725637
2014-05-06 21:31:46 +02:00
b4de2458ab MetaMonitorConfig: don't keep a previous config with the wrong outputs
We can only apply a configuration if its outputs match the connected
ones, so discard the current configuration if the set of output changes
(for example for hotplug), otherwise we will crash trying to apply
the bogus previous configuration.

https://bugzilla.gnome.org/show_bug.cgi?id=725637
2014-05-06 21:31:46 +02:00
49952bdc69 [l10n] Update Catalan translation 2014-05-02 12:43:44 +02:00
b2fd24a098 Updated German translation 2014-05-01 17:47:54 +00:00
fe9d2570d0 window: Queue a fullscreen check when moving between monitors
We track changes to windows fullscreen state and stacking order
to determine a monitor's in-fullscreen state, but missed the
obvious case of moving a fullscreen window between monitors.

https://bugzilla.gnome.org/show_bug.cgi?id=728395
2014-04-17 18:33:28 +02:00
b16ac1ba8c keybindings: Handle switch-to-workspace-{up,down,left,right} again
Commit 585fdd781c not only removed the tabpopup, but set invalid
handlers (a.k.a. NULL) for those shortcuts; add back handling of
basic handling of those shortcuts by switching instantly without any
popups.

https://bugzilla.gnome.org/show_bug.cgi?id=728423
2014-04-17 17:06:25 +02:00
330ce648d3 Bump version to 3.12.1
Update NEWS.
2014-04-15 21:56:45 +02:00
27 changed files with 1519 additions and 585 deletions

11
NEWS
View File

@ -1,3 +1,14 @@
3.12.1
======
* Fix opacity values from _NET_WM_WINDOW_OPACITY [Nirbheek; #727874]
* Misc. cleanups [Jasper; #720631]
Contributors:
Nirbheek Chauhan, Jasper St. Pierre
Translations:
Inaki Larranaga Murgoitio [eu], marablack3 [el]
3.12.0
======

View File

@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [12])
m4_define([mutter_micro_version], [0])
m4_define([mutter_micro_version], [1])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -70,12 +70,12 @@ CLUTTER_PACKAGE=clutter-1.0
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.9.11
gio-2.0 >= 2.25.10
gio-unix-2.0 >= 2.25.10
pango >= 1.2.0
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.15.90
$CLUTTER_PACKAGE >= 1.19.5
cogl-1.0 >= 1.17.1
upower-glib >= 0.99.0
gnome-desktop-3.0

531
po/ca.po

File diff suppressed because it is too large Load Diff

531
po/de.po

File diff suppressed because it is too large Load Diff

View File

@ -132,8 +132,11 @@ libmutter_la_SOURCES = \
core/screen-private.h \
meta/screen.h \
meta/types.h \
core/restart.c \
core/session.c \
core/session.h \
core/stereo.c \
core/stereo.h \
core/stack.c \
core/stack.h \
core/stack-tracker.c \
@ -220,6 +223,10 @@ bin_PROGRAMS=mutter
mutter_SOURCES = core/mutter.c
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
libexec_PROGRAMS = mutter-restart-helper
mutter_restart_helper_SOURCES = core/restart-helper.c
mutter_restart_helper_LDADD = $(MUTTER_LIBS)
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)

View File

@ -26,6 +26,8 @@ struct _MetaCompositor
gint64 server_time_query_time;
gint64 server_time_offset;
int glx_opcode;
guint server_time_is_monotonic_time : 1;
guint show_redraw : 1;
guint debug : 1;
@ -51,6 +53,9 @@ struct _MetaCompScreen
gint switch_workspace_in_progress;
guint stereo_tree_ext : 1;
guint have_stereo_windows : 1;
MetaPluginManager *plugin_mgr;
};
@ -72,4 +77,9 @@ gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
void meta_check_end_modal (MetaScreen *screen);
gboolean meta_compositor_window_is_stereo (MetaScreen *screen,
Window xwindow);
void meta_compositor_select_stereo_notify (MetaScreen *screen,
Window xwindow);
#endif /* META_COMPOSITOR_PRIVATE_H */

View File

@ -74,7 +74,8 @@
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#include "display-private.h"
#include "stereo.h"
#include "util-private.h"
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
@ -181,6 +182,10 @@ get_output_window (MetaScreen *screen)
xroot = meta_screen_get_xroot (screen);
output = XCompositeGetOverlayWindow (xdisplay, xroot);
/* Now that we've gotten taken a reference count on the COW, we
* can close the helper that is holding on to it */
meta_restart_finish ();
meta_core_add_old_event_mask (xdisplay, output, &mask);
XISetMask (mask.mask, XI_KeyPress);
@ -540,6 +545,101 @@ redirect_windows (MetaCompositor *compositor,
}
}
#define GLX_STEREO_TREE_EXT 0x20F5
#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
#define GLX_STEREO_NOTIFY_EXT 0x00000000
typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
int extension;
int evtype;
Drawable window;
Bool stereo_tree;
} StereoNotifyEvent;
static gboolean
screen_has_stereo_tree_ext (MetaScreen *screen)
{
#if 0
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
const char *extensions_string;
static const char * (*query_extensions_string) (Display *display,
int screen);
if (query_extensions_string == NULL)
query_extensions_string =
(const char * (*) (Display *, int))
cogl_get_proc_address ("glXQueryExtensionsString");
extensions_string = query_extensions_string (xdisplay,
meta_screen_get_screen_number (screen));
return strstr (extensions_string, "EXT_stereo_tree") != 0;
#else
return TRUE;
#endif
}
#include <GL/gl.h>
gboolean
meta_compositor_window_is_stereo (MetaScreen *screen,
Window xwindow)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
static int (*query_drawable) (Display *dpy,
Drawable draw,
int attribute,
unsigned int *value);
if (info->stereo_tree_ext)
{
unsigned int stereo_tree = 0;
if (query_drawable == NULL)
query_drawable =
(int (*) (Display *, Drawable, int, unsigned int *))
cogl_get_proc_address ("glXQueryDrawable");
query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
return stereo_tree != 0;
}
else
return FALSE;
}
void
meta_compositor_select_stereo_notify (MetaScreen *screen,
Window xwindow)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
static void (*select_event) (Display *dpy,
Drawable draw,
unsigned long event_mask);
if (info->stereo_tree_ext)
{
if (select_event == NULL)
select_event =
(void (*) (Display *, Drawable, unsigned long))
cogl_get_proc_address ("glXSelectEvent");
select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
}
}
void
meta_compositor_manage_screen (MetaCompositor *compositor,
MetaScreen *screen)
@ -562,14 +662,14 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
info->output = None;
info->windows = NULL;
info->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
meta_screen_set_cm_selection (screen);
info->stage = clutter_stage_new ();
clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage),
after_stage_paint,
info,
NULL);
g_signal_connect (CLUTTER_STAGE (info->stage), "after-paint",
G_CALLBACK (after_stage_paint), info);
clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
@ -952,6 +1052,22 @@ meta_compositor_process_event (MetaCompositor *compositor,
}
}
if (event->type == GenericEvent &&
event->xcookie.extension == compositor->glx_opcode)
{
if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
{
StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
if (window != NULL)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
}
}
}
if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
{
/* Core code doesn't handle damage events, so we need to extract the MetaWindow
@ -1179,6 +1295,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
{
GList *old_stack;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
int stereo_window_count = 0;
DEBUG_TRACE ("meta_compositor_sync_stack\n");
@ -1256,12 +1373,16 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
* near the front of the other.)
*/
info->windows = g_list_prepend (info->windows, actor);
if (meta_window_actor_is_stereo (actor))
stereo_window_count++;
stack = g_list_remove (stack, window);
old_stack = g_list_remove (old_stack, actor);
}
sync_actor_stacking (info);
meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
}
void
@ -1427,6 +1548,7 @@ MetaCompositor *
meta_compositor_new (MetaDisplay *display)
{
MetaCompositor *compositor;
int glx_major_opcode, glx_first_event, glx_first_error;
if (!composite_at_least_version (display, 0, 3))
return NULL;
@ -1446,6 +1568,10 @@ meta_compositor_new (MetaDisplay *display)
compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
compositor,
NULL);
if (XQueryExtension (meta_display_get_xdisplay (display),
"GLX",
&glx_major_opcode, &glx_first_event, &glx_first_error))
compositor->glx_opcode = glx_major_opcode;
return compositor;
}

View File

@ -31,7 +31,8 @@
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
CoglTexture *texture,
gboolean stereo);
gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *stex,
cairo_rectangle_int_t *unobscured_bounds);
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);

View File

@ -36,6 +36,7 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
#include "meta-cullable.h"
@ -69,8 +70,10 @@ G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_AC
struct _MetaShapedTexturePrivate
{
MetaTextureTower *paint_tower;
MetaTextureTower *paint_tower_right;
CoglTexture *texture;
CoglTexture *texture_right;
CoglTexture *mask_texture;
cairo_region_t *input_shape_region;
@ -84,6 +87,7 @@ struct _MetaShapedTexturePrivate
guint tex_width, tex_height;
guint stereo : 1;
guint create_mipmaps : 1;
};
@ -112,8 +116,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->paint_tower = meta_texture_tower_new ();
priv->paint_tower_right = NULL; /* demand create */
priv->texture = NULL;
priv->texture_right = NULL;
priv->mask_texture = NULL;
priv->create_mipmaps = TRUE;
}
@ -150,11 +156,10 @@ meta_shaped_texture_dispose (GObject *object)
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
if (priv->paint_tower)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->texture_right, cogl_object_unref);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (self, NULL);
@ -233,49 +238,20 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
}
static void
meta_shaped_texture_paint (ClutterActor *actor)
paint_texture (MetaShapedTexture *stex,
CoglTexture *paint_tex)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
ClutterActor *actor = CLUTTER_ACTOR (stex);
MetaShapedTexturePrivate *priv = stex->priv;
guint tex_width, tex_height;
guchar opacity;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglPipeline *pipeline = NULL;
CoglTexture *paint_tex;
ClutterActorBox alloc;
cairo_region_t *blended_region = NULL;
CoglPipelineFilter filter;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there
* are distinct performance implications from:
*
* - Updating mipmaps that we don't need
* - Having to reallocate pixmaps on the server into larger buffers
*
* So, we just unconditionally use our mipmap emulation code. If we
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
* see if it was supported (no API currently), and then if and only
* if that was the case, set the clutter texture quality to HIGH.
* Setting the texture quality to high without SGIS_generate_mipmap
* support for TFP textures will result in fallbacks to XGetImage.
*/
if (priv->create_mipmaps)
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
else
paint_tex = COGL_TEXTURE (priv->texture);
if (paint_tex == NULL)
return;
tex_width = priv->tex_width;
tex_height = priv->tex_height;
@ -291,8 +267,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (!clutter_actor_is_in_clone_paint (actor) && meta_actor_is_untransformed (actor, NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box (actor, &alloc);
@ -415,6 +391,74 @@ meta_shaped_texture_paint (ClutterActor *actor)
cairo_region_destroy (blended_region);
}
static void
meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
CoglFramebuffer *fb;
gboolean stereo;
CoglTexture *paint_tex;
CoglTexture *paint_tex_right;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there
* are distinct performance implications from:
*
* - Updating mipmaps that we don't need
* - Having to reallocate pixmaps on the server into larger buffers
*
* So, we just unconditionally use our mipmap emulation code. If we
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
* see if it was supported (no API currently), and then if and only
* if that was the case, set the clutter texture quality to HIGH.
* Setting the texture quality to high without SGIS_generate_mipmap
* support for TFP textures will result in fallbacks to XGetImage.
*/
if (priv->create_mipmaps)
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
else
paint_tex = COGL_TEXTURE (priv->texture);
fb = cogl_get_draw_framebuffer ();
stereo = priv->stereo && cogl_framebuffer_get_is_stereo (fb);
if (stereo)
{
if (priv->create_mipmaps)
paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
else
paint_tex_right = COGL_TEXTURE (priv->texture_right);
}
else
paint_tex_right = NULL;
if (paint_tex != NULL)
{
if (stereo)
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
else
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
paint_texture (stex, paint_tex);
}
if (paint_tex_right != NULL)
{
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
paint_texture (stex, paint_tex_right);
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
}
}
static void
meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
@ -570,6 +614,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
priv->create_mipmaps = create_mipmaps;
base_texture = create_mipmaps ? priv->texture : NULL;
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
if (priv->stereo)
{
base_texture = create_mipmaps ? priv->texture_right : NULL;
meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
}
}
}
@ -668,6 +718,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
return FALSE;
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
if (priv->stereo)
meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
unobscured_region = effective_unobscured_region (stex);
if (unobscured_region)
@ -701,7 +753,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
CoglTexture *cogl_tex,
gboolean stereo)
{
MetaShapedTexturePrivate *priv;
guint width, height;
@ -712,8 +765,23 @@ set_cogl_texture (MetaShapedTexture *stex,
if (priv->texture != NULL)
cogl_object_unref (priv->texture);
if (priv->texture_right != NULL)
cogl_object_unref (priv->texture_right);
priv->stereo = stereo;
priv->texture = cogl_tex;
if (priv->stereo)
{
priv->texture_right = cogl_texture_pixmap_x11_new_right ((CoglTexturePixmapX11 *)cogl_tex);
if (priv->paint_tower_right == NULL)
priv->paint_tower_right = meta_texture_tower_new ();
}
else
{
priv->texture_right = NULL;
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
}
if (cogl_tex != NULL)
{
@ -743,7 +811,11 @@ set_cogl_texture (MetaShapedTexture *stex,
* damage. */
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
{
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
if (priv->stereo)
meta_texture_tower_set_base_texture (priv->paint_tower_right, priv->texture_right);
}
}
/**
@ -753,11 +825,12 @@ set_cogl_texture (MetaShapedTexture *stex,
*/
void
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture)
CoglTexture *texture,
gboolean stereo)
{
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
set_cogl_texture (stex, texture);
set_cogl_texture (stex, texture, stereo);
}
/**

View File

@ -58,4 +58,11 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
void meta_window_actor_stereo_notify (MetaWindowActor *actor,
gboolean stereo_tree);
gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
void meta_window_actor_detach (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

View File

@ -94,6 +94,7 @@ struct _MetaWindowActorPrivate
guint visible : 1;
guint argb32 : 1;
guint stereo : 1;
guint disposed : 1;
guint redecorating : 1;
@ -157,7 +158,6 @@ 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_handle_updates (MetaWindowActor *self);
@ -318,6 +318,9 @@ meta_window_actor_constructed (GObject *object)
if (format && format->type == PictTypeDirect && format->direct.alphaMask)
priv->argb32 = TRUE;
priv->stereo = meta_compositor_window_is_stereo (screen, xwindow);
meta_compositor_select_stereo_notify (screen, xwindow);
if (!priv->actor)
{
priv->actor = meta_shaped_texture_new ();
@ -1130,7 +1133,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
* when the window is unmapped or when we want to update to a new
* pixmap for a new size.
*/
static void
void
meta_window_actor_detach (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
@ -1145,7 +1148,7 @@ meta_window_actor_detach (MetaWindowActor *self)
* you are supposed to be able to free a GLXPixmap after freeing the underlying
* pixmap, but it certainly doesn't work with current DRI/Mesa
*/
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL, FALSE);
cogl_flush();
XFreePixmap (xdisplay, priv->back_pixmap);
@ -1669,11 +1672,15 @@ check_needs_pixmap (MetaWindowActor *self)
meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor),
FALSE);
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
if (priv->stereo)
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new_left (ctx, priv->back_pixmap, FALSE, NULL));
else
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
g_warning ("NOTE: Not using GLX TFP!\n");
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture);
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture, priv->stereo);
}
priv->needs_pixmap = FALSE;
@ -2350,3 +2357,20 @@ meta_window_actor_set_updates_frozen (MetaWindowActor *self,
meta_window_actor_thaw (self);
}
}
void
meta_window_actor_stereo_notify (MetaWindowActor *self,
gboolean stereo_tree)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
priv->stereo = stereo_tree;
meta_window_actor_detach (self);
}
gboolean
meta_window_actor_is_stereo (MetaWindowActor *self)
{
return self->priv->stereo;
}

View File

@ -33,7 +33,9 @@ typedef enum
META_DO_GRAVITY_ADJUST = 1 << 1,
META_IS_USER_ACTION = 1 << 2,
META_IS_MOVE_ACTION = 1 << 3,
META_IS_RESIZE_ACTION = 1 << 4
META_IS_RESIZE_ACTION = 1 << 4,
META_FORCE_STATIC_GRAVITY = 1 << 5,
META_IS_INITIAL_RESIZE = 1 << 6
} MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window,

View File

@ -483,4 +483,11 @@ void meta_display_set_input_focus_xwindow (MetaDisplay *display,
Window window,
guint32 timestamp);
gboolean meta_display_show_restart_message (MetaDisplay *display,
const char *message);
gboolean meta_display_request_restart (MetaDisplay *display);
void meta_restart_init (void);
void meta_restart_finish (void);
#endif

View File

@ -130,6 +130,8 @@ enum
WINDOW_MARKED_URGENT,
GRAB_OP_BEGIN,
GRAB_OP_END,
SHOW_RESTART_MESSAGE,
RESTART,
LAST_SIGNAL
};
@ -306,6 +308,59 @@ meta_display_class_init (MetaDisplayClass *klass)
META_TYPE_WINDOW,
META_TYPE_GRAB_OP);
/**
* MetaDisplay::show-restart-message:
* @display: the #MetaDisplay instance
* @message: (allow-none): The message to display, or %NULL
* to clear a previous restart message.
*
* The ::show-restart-message signal will be emitted to indicate
* that the compositor should show a message during restart. This is
* emitted when meta_restart() is called, either by Mutter
* internally or by the embedding compositor. The message should be
* immediately added to the Clutter stage in its final form -
* ::restart will be emitted to exit the application and leave the
* stage contents frozen as soon as the the stage is painted again.
*
* On case of failure to restart, this signal will be emitted again
* with %NULL for @message.
*
* Returns: %TRUE means the message was added to the stage; %FALSE
* indicates that the compositor did not show the message.
*/
display_signals[SHOW_RESTART_MESSAGE] =
g_signal_new ("show-restart-message",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled,
NULL, NULL,
G_TYPE_BOOLEAN, 1,
G_TYPE_STRING);
/**
* MetaDisplay::restart:
* @display: the #MetaDisplay instance
*
* The ::restart signal is emitted to indicate that compositor
* should reexec the process. This is
* emitted when meta_restart() is called, either by Mutter
* internally or by the embedding compositor. See also
* ::show-restart-message.
*
* Returns: %FALSE to indicate that the compositor could not
* be restarted. When the compositor is restarted, the signal
* should not return.
*/
display_signals[RESTART] =
g_signal_new ("restart",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled,
NULL, NULL,
G_TYPE_BOOLEAN, 0);
g_object_class_install_property (object_class,
PROP_FOCUS_WINDOW,
g_param_spec_object ("focus-window",
@ -2781,14 +2836,14 @@ event_callback (XEvent *event,
&& meta_display_screen_for_root (display, event->xmap.event))
{
window = meta_window_new (display, event->xmap.window,
FALSE, META_COMP_EFFECT_CREATE);
FALSE, FALSE);
}
break;
case MapRequest:
if (window == NULL)
{
window = meta_window_new (display, event->xmaprequest.window,
FALSE, META_COMP_EFFECT_CREATE);
FALSE, FALSE);
}
/* if frame was receiver it's some malicious send event or something */
else if (!frame_was_receiver && window)
@ -5939,3 +5994,28 @@ meta_display_clear_mouse_mode (MetaDisplay *display)
{
display->mouse_mode = FALSE;
}
gboolean
meta_display_show_restart_message (MetaDisplay *display,
const char *message)
{
gboolean result = FALSE;
g_signal_emit (display,
display_signals[SHOW_RESTART_MESSAGE], 0,
message, &result);
return result;
}
gboolean
meta_display_request_restart (MetaDisplay *display)
{
gboolean result = FALSE;
g_signal_emit (display,
display_signals[RESTART], 0,
&result);
return result;
}

View File

@ -2522,7 +2522,19 @@ handle_switch_to_workspace (MetaDisplay *display,
gint which = binding->handler->data;
MetaWorkspace *workspace;
workspace = meta_screen_get_workspace_by_index (screen, which);
if (which < 0)
{
/* Negative workspace numbers are directions with respect to the
* current workspace.
*/
workspace = meta_workspace_get_neighbor (screen->active_workspace,
which);
}
else
{
workspace = meta_screen_get_workspace_by_index (screen, which);
}
if (workspace)
{
@ -3359,28 +3371,28 @@ init_builtin_key_bindings (MetaDisplay *display)
common_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_WORKSPACE_LEFT,
NULL, 0);
handle_switch_to_workspace, META_MOTION_LEFT);
add_builtin_keybinding (display,
"switch-to-workspace-right",
common_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_WORKSPACE_RIGHT,
NULL, 0);
handle_switch_to_workspace, META_MOTION_RIGHT);
add_builtin_keybinding (display,
"switch-to-workspace-up",
common_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_WORKSPACE_UP,
NULL, 0);
handle_switch_to_workspace, META_MOTION_UP);
add_builtin_keybinding (display,
"switch-to-workspace-down",
common_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_WORKSPACE_DOWN,
NULL, 0);
handle_switch_to_workspace, META_MOTION_DOWN);
/* The ones which have inverses. These can't be bound to any keystroke

View File

@ -51,6 +51,7 @@
#include <meta/errors.h>
#include "ui.h"
#include "session.h"
#include "stereo.h"
#include <meta/prefs.h>
#include <meta/compositor.h>
@ -444,6 +445,10 @@ meta_init (void)
meta_ui_init ();
meta_restart_init ();
meta_stereo_init ();
/*
* Clutter can only be initialized after the UI.
*/

View File

@ -778,6 +778,9 @@ create_monitor_skeleton (GDBusObjectManagerServer *manager,
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
g_object_unref (skeleton);
g_object_unref (object);
}
static void

View File

@ -77,6 +77,7 @@ struct _MetaMonitorConfig {
GHashTable *configs;
MetaConfiguration *current;
gboolean current_is_stored;
gboolean current_is_for_laptop_lid;
MetaConfiguration *previous;
GFile *file;
@ -876,7 +877,8 @@ apply_configuration (MetaMonitorConfig *self,
/* Stored (persistent) configurations override the previous one always.
Also, we clear the previous configuration if the current one (which is
about to become previous) is stored.
about to become previous) is stored, or if the current one has
different outputs.
*/
if (stored ||
(self->current && self->current_is_stored))
@ -887,11 +889,27 @@ apply_configuration (MetaMonitorConfig *self,
}
else
{
self->previous = self->current;
/* Despite the name, config_equal() only checks the set of outputs,
not their modes
*/
if (self->current && config_equal (self->current, config))
{
self->previous = self->current;
}
else
{
if (self->current)
config_free (self->current);
self->previous = NULL;
}
}
self->current = config;
self->current_is_stored = stored;
/* If true, we'll be overridden at the end of this call
inside turn_off_laptop_display()
*/
self->current_is_for_laptop_lid = FALSE;
if (self->current == self->previous)
self->previous = NULL;
@ -1008,8 +1026,16 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
if (self->lid_is_closed &&
stored->n_outputs > 1 &&
laptop_display_is_on (stored))
return apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE);
{
if (apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE))
{
self->current_is_for_laptop_lid = TRUE;
return TRUE;
}
else
return FALSE;
}
else
return apply_configuration (self, stored, manager, TRUE);
}
@ -1356,6 +1382,7 @@ turn_off_laptop_display (MetaMonitorConfig *self,
new = make_laptop_lid_config (self->current);
apply_configuration (self, new, manager, FALSE);
self->current_is_for_laptop_lid = TRUE;
}
static void
@ -1375,7 +1402,7 @@ power_client_changed_cb (UpClient *client,
if (is_closed)
turn_off_laptop_display (self, manager);
else
else if (self->current_is_for_laptop_lid)
meta_monitor_config_restore_previous (self, manager);
}
}

View File

@ -75,6 +75,7 @@ main (int argc, char **argv)
g_printerr ("mutter: %s\n", error->message);
exit (1);
}
g_option_context_free (ctx);
if (plugin)
meta_plugin_manager_load (plugin);

82
src/core/restart-helper.c Normal file
View File

@ -0,0 +1,82 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* SECTION:restart-helper
* @short_description: helper program during a restart
*
* To smoothly restart Mutter, we want to keep the composite
* overlay window enabled during the restart. This is done by
* spawning this program, which keeps a reference to the the composite
* overlay window until Mutter picks it back up.
*/
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
int
main (int argc,
char **argv)
{
Display *display = XOpenDisplay (NULL);
Window selection_window;
XSetWindowAttributes xwa;
unsigned long mask = 0;
xwa.override_redirect = True;
mask |= CWOverrideRedirect;
XCompositeGetOverlayWindow (display, DefaultRootWindow (display));
selection_window = XCreateWindow (display,
DefaultRootWindow (display),
-100, -100, 1, 1, 0,
0,
InputOnly,
DefaultVisual (display, DefaultScreen (display)),
mask, &xwa);
XSetSelectionOwner (display,
XInternAtom (display, "_MUTTER_RESTART_HELPER", False),
selection_window,
CurrentTime);
/* Mutter looks for an (arbitrary) line printed to stdout to know that
* we have started and have a reference to the COW. XSync() so that
* everything is set on the X server before Mutter starts restarting.
*/
XSync (display, False);
printf ("STARTED\n");
fflush (stdout);
while (True)
{
XEvent xev;
XNextEvent (display, &xev);
/* Mutter restarted and unset the selection to indicate that
* it has a reference on the COW again */
if (xev.xany.type == SelectionClear)
return 0;
}
}

208
src/core/restart.c Normal file
View File

@ -0,0 +1,208 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* SECTION:restart
* @short_description: Smoothly restart the compositor
*
* There are some cases where we need to restart Mutter in order
* to deal with changes in state - the particular case inspiring
* this is enabling or disabling stereo output. To make this
* fairly smooth for the user, we need to do two things:
*
* - Display a message to the user and make sure that it is
* actually painted before we exit.
* - Use a helper program so that the Composite Overlay Window
* isn't unmapped and mapped.
*
* This handles both of these.
*/
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <clutter/clutter.h>
#include <gio/gunixinputstream.h>
#include <meta/main.h>
#include "ui.h"
#include "util-private.h"
#include "display-private.h"
static gboolean restart_helper_started = FALSE;
static gboolean restart_message_shown = FALSE;
static gboolean is_restart = FALSE;
void
meta_restart_init (void)
{
Display *xdisplay = meta_ui_get_display ();
Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
Window restart_helper_window = NULL;
restart_helper_window = XGetSelectionOwner (xdisplay, atom_restart_helper);
if (restart_helper_window)
is_restart = TRUE;
}
static void
restart_check_ready (void)
{
if (restart_helper_started && restart_message_shown)
meta_display_request_restart (meta_get_display ());
}
static void
restart_helper_read_line_callback (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
gsize length;
char *line = g_data_input_stream_read_line_finish_utf8 (G_DATA_INPUT_STREAM (source_object),
res,
&length, &error);
if (line == NULL)
{
meta_warning ("Failed to read output from restart helper%s%s\n",
error ? ": " : NULL,
error ? error->message : NULL);
}
else
g_free (line); /* We don't actually care what the restart helper outputs */
g_object_unref (source_object);
restart_helper_started = TRUE;
restart_check_ready ();
}
static gboolean
restart_message_painted (gpointer data)
{
restart_message_shown = TRUE;
restart_check_ready ();
return FALSE;
}
/**
* meta_restart:
* @message: message to display to the user.
*
* Starts the process of restarting the compositor. Note that Mutter's
* involvement here is to make the restart visually smooth for the
* user - it cannot itself safely reexec a program that embeds libmuttter.
* So in order for this to work, the compositor must handle two
* signals - MetaDisplay::show-restart-message, to display the
* message passed here on the Clutter stage, and ::restart to actually
* reexec the compositor.
*/
void
meta_restart (const char *message)
{
MetaDisplay *display = meta_get_display();
GError *error = NULL;
int helper_out_fd;
static const char * const helper_argv[] = {
MUTTER_LIBEXECDIR "/mutter-restart-helper", NULL
};
if (meta_display_show_restart_message (display, message))
{
/* Wait until the stage was painted */
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
restart_message_painted,
NULL, NULL);
}
else
{
/* Can't show the message, show the message as soon as the
* restart helper starts
*/
restart_message_painted (NULL);
}
/* We also need to wait for the restart helper to get its
* reference to the Composite Overlay Window.
*/
if (!g_spawn_async_with_pipes (NULL, /* working directory */
(char **)helper_argv,
NULL, /* envp */
G_SPAWN_DEFAULT,
NULL, NULL, /* child_setup */
NULL, /* child_pid */
NULL, /* standard_input */
&helper_out_fd,
NULL, /* standard_error */
&error))
{
meta_warning ("Failed to start restart helper: %s\n", error->message);
goto error;
}
else
{
GInputStream *unix_stream = g_unix_input_stream_new (helper_out_fd, TRUE);
GDataInputStream *data_stream = g_data_input_stream_new (unix_stream);
g_object_unref (unix_stream);
g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
NULL, restart_helper_read_line_callback,
&error);
if (error != NULL)
{
meta_warning ("Failed to read from restart helper: %s\n", error->message);
g_object_unref (data_stream);
goto error;
}
}
return;
error:
restart_helper_started = TRUE;
restart_check_ready ();
return;
}
void
meta_restart_finish (void)
{
if (is_restart)
{
Display *xdisplay = meta_ui_get_display ();
Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
XSetSelectionOwner (xdisplay, atom_restart_helper, None, CurrentTime);
}
}
/**
* meta_is_restart:
*
* Returns %TRUE if this instance of Mutter comes from Mutter
* restarting itself (for example to enable/disable stereo.)
* See meta_restart(). If this is the case, any startup visuals
* or animations should be suppressed.
*/
gboolean
meta_is_restart (void)
{
return is_restart;
}

View File

@ -891,8 +891,7 @@ meta_screen_manage_all_windows (MetaScreen *screen)
for (i = 0; i < n_children; ++i)
{
meta_window_new (screen->display, children[i], TRUE,
META_COMP_EFFECT_NONE);
meta_window_new (screen->display, children[i], TRUE, TRUE);
}
g_free (children);

144
src/core/stereo.c Normal file
View File

@ -0,0 +1,144 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* SECTION:stereo
* @short_description: Keep track of whether we are a stereo compositor
*
* With GLX, we need to use a different GL context for stereo and
* non-stereo support. Support for multiple GL contexts is unfinished
* in Cogl and entirely lacking in Clutter, so it's by far easier
* to just restart Mutter when we detect a stereo window.
*
* A property _MUTTER_ENABLE_STEREO is maintained on the root window
* to know whether we should initialize clutter for stereo or not.
* When the presence or absence of stereo windows mismatches the
* stereo-enabled state for a sufficiently long period of time,
* we restart Mutter.
*/
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <clutter/x11/clutter-x11.h>
#include <gio/gunixinputstream.h>
#include <X11/Xatom.h>
#include <meta/main.h>
#include "ui.h"
#include "util-private.h"
#include "display-private.h"
#include "stereo.h"
static guint stereo_switch_id = 0;
static gboolean stereo_enabled = FALSE;
/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
* we avoid the short-circuit and set up a timeout to restart
* if necessary */
static gboolean stereo_have_windows = (gboolean)-1;
static gboolean stereo_restart = FALSE;
#define STEREO_ENABLE_WAIT 1000
#define STEREO_DISABLE_WAIT 5000
void
meta_stereo_init (void)
{
Display *xdisplay = meta_ui_get_display ();
Window root = DefaultRootWindow (xdisplay);
Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
Atom type;
int format;
unsigned long n_items, bytes_after;
guchar *data;
XGetWindowProperty (xdisplay, root, atom_enable_stereo,
0, 1, False, XA_INTEGER,
&type, &format, &n_items, &bytes_after, &data);
if (type == XA_INTEGER)
{
if (format == 32 && n_items == 1 && bytes_after == 0)
{
stereo_enabled = *(long *)data;
}
else
{
meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
}
XFree (data);
}
else if (type != None)
{
meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
}
meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
stereo_enabled ? "yes" : "no");
clutter_x11_set_use_stereo_stage (stereo_enabled);
}
static gboolean
meta_stereo_switch (gpointer data)
{
stereo_switch_id = 0;
stereo_restart = TRUE;
meta_restart (stereo_have_windows ?
_("Enabling stereo...") :
_("Disabling stereo..."));
return FALSE;
}
void
meta_stereo_set_have_stereo_windows (gboolean have_windows)
{
have_windows = have_windows != FALSE;
if (!stereo_restart && have_windows != stereo_have_windows)
{
MetaDisplay *display = meta_get_display ();
Display *xdisplay = meta_display_get_xdisplay (display);
Window root = DefaultRootWindow (xdisplay);
Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
long value;
stereo_have_windows = have_windows;
if (stereo_have_windows)
meta_verbose ("Detected stereo windows\n");
else
meta_verbose ("No stereo windows detected\n");
value = stereo_have_windows;
XChangeProperty (xdisplay, root,
atom_enable_stereo, XA_INTEGER, 32,
PropModeReplace, (guchar *)&value, 1);
if (stereo_switch_id != 0)
{
g_source_remove (stereo_switch_id);
stereo_switch_id = 0;
}
if (stereo_have_windows != stereo_enabled)
stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
meta_stereo_switch, NULL);
}
}

28
src/core/stereo.h Normal file
View File

@ -0,0 +1,28 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_STEREO_H
#define META_STEREO_H
void meta_stereo_init (void);
void meta_stereo_set_have_stereo_windows (gboolean have_windows);
gboolean meta_stereo_is_restart (void);
void meta_stereo_finish_restart (void);
#endif

View File

@ -488,8 +488,8 @@ struct _MetaWindowClass
MetaWindow* meta_window_new (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
MetaCompEffect effect);
gboolean managing_screen,
gboolean must_be_viewable);
void meta_window_unmanage (MetaWindow *window,
guint32 timestamp);
void meta_window_calc_showing (MetaWindow *window);

View File

@ -38,6 +38,7 @@
#include "keybindings-private.h"
#include "ui.h"
#include "place.h"
#include <meta/main.h>
#include "session.h"
#include <meta/prefs.h>
#include "resizepopup.h"
@ -844,8 +845,8 @@ sync_client_window_mapped (MetaWindow *window)
MetaWindow*
meta_window_new (MetaDisplay *display,
Window xwindow,
gboolean must_be_viewable,
MetaCompEffect effect)
gboolean managing_screen,
gboolean must_be_viewable)
{
XWindowAttributes attrs;
MetaWindow *window;
@ -855,6 +856,8 @@ meta_window_new (MetaDisplay *display,
gulong event_mask;
MetaMoveResizeFlags flags;
MetaScreen *screen;
MetaCompEffect effect =
managing_screen ? META_COMP_EFFECT_NONE : META_COMP_EFFECT_CREATE;
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
@ -1434,12 +1437,27 @@ meta_window_new (MetaDisplay *display,
else
window->layer = META_LAYER_OVERRIDE_REDIRECT; /* otherwise set by MetaStack */
/* Put our state back where it should be,
* passing TRUE for is_configure_request, ICCCM says
* initial map is handled same as configure request
*/
flags =
META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_INITIAL_RESIZE;
/* ICCCM says initial map is handled same as configure request. When
* we are initially managing the screen, we distinguish two cases:
*
* Restart: in this case, we put the windows back to the unframed
* position before exiting, so we need to give them gravity
* adjustments.
* Something else: (perhaps a crash) if we didn't exit cleanly, then
* windows will be reparented by the X server so that the client
* origin stays the same, and no frame adjustment is needed.
*
* We don't have any way to distinguish replacing a different window
* manager from respawning on crash, so when we replace a different
* window manager, windows will shift onscreen, but this is expected
* to only happen in development.
*/
if (!managing_screen || meta_is_restart())
flags |= META_IS_CONFIGURE_REQUEST;
if (!window->override_redirect)
meta_window_move_resize_internal (window,
flags,
@ -5180,7 +5198,8 @@ meta_window_move_resize_internal (MetaWindow *window,
if (need_configure_notify)
send_configure_notify (window);
if (!window->placed && window->force_save_user_rect && !window->fullscreen)
if ((flags & META_IS_INITIAL_RESIZE) != 0 &&
window->force_save_user_rect && !window->fullscreen)
force_save_user_window_placement (window);
else if (is_user_action)
save_user_window_placement (window);
@ -5397,6 +5416,9 @@ meta_window_move_to_monitor (MetaWindow *window,
window->tile_monitor_number = monitor;
meta_window_move_between_rects (window, &old_area, &new_area);
if (window->fullscreen || window->override_redirect)
meta_screen_queue_check_fullscreen (window->screen);
}
void

View File

@ -33,6 +33,9 @@ gboolean meta_get_replace_current_wm (void); /* Actually defined in util
void meta_set_wm_name (const char *wm_name);
void meta_set_gnome_wm_keybindings (const char *wm_keybindings);
void meta_restart (const char *message);
gboolean meta_is_restart (void);
/**
* MetaExitCode:
* @META_EXIT_SUCCESS: Success