Compare commits
	
		
			14 Commits
		
	
	
		
			wip/gbsnet
			...
			wip/quadbu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0f214e24ee | ||
| 
						 | 
					cf67327f0e | ||
| 
						 | 
					8e5bb17750 | ||
| 
						 | 
					14d2f8fddc | ||
| 
						 | 
					c249c3f3e5 | ||
| 
						 | 
					db0383d19f | ||
| 
						 | 
					a175b3c947 | ||
| 
						 | 
					554be56639 | ||
| 
						 | 
					b4de2458ab | ||
| 
						 | 
					49952bdc69 | ||
| 
						 | 
					b2fd24a098 | ||
| 
						 | 
					fe9d2570d0 | ||
| 
						 | 
					b16ac1ba8c | ||
| 
						 | 
					330ce648d3 | 
							
								
								
									
										11
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								NEWS
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
									
								
							
							
						
						
									
										82
									
								
								src/core/restart-helper.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										208
									
								
								src/core/restart.c
									
									
									
									
									
										Normal 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;
 | 
			
		||||
}
 | 
			
		||||
@@ -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
									
								
							
							
						
						
									
										144
									
								
								src/core/stereo.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										28
									
								
								src/core/stereo.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user