Compare commits
	
		
			13 Commits
		
	
	
		
			3.15.90
			...
			wip/compos
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					27bec68c67 | ||
| 
						 | 
					8ce4407a9f | ||
| 
						 | 
					cebb6b2779 | ||
| 
						 | 
					d7771a30ee | ||
| 
						 | 
					10fb5e527f | ||
| 
						 | 
					7116786ad3 | ||
| 
						 | 
					d294fa45d1 | ||
| 
						 | 
					e278d65f05 | ||
| 
						 | 
					42408c1c38 | ||
| 
						 | 
					9ac086a613 | ||
| 
						 | 
					de06346766 | ||
| 
						 | 
					c22d6ad69c | ||
| 
						 | 
					64be6cf4f0 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -48,7 +48,6 @@ po/*.pot
 | 
			
		||||
50-metacity-key.xml
 | 
			
		||||
libmutter-wayland.pc
 | 
			
		||||
mutter-wayland
 | 
			
		||||
mutter-launch
 | 
			
		||||
org.gnome.mutter.gschema.valid
 | 
			
		||||
org.gnome.mutter.gschema.xml
 | 
			
		||||
org.gnome.mutter.wayland.gschema.valid
 | 
			
		||||
@@ -77,6 +76,7 @@ src/mutter-marshal.[ch]
 | 
			
		||||
src/stamp-mutter-marshal.h
 | 
			
		||||
src/meta-dbus-xrandr.[ch]
 | 
			
		||||
src/meta-dbus-idle-monitor.[ch]
 | 
			
		||||
src/meta-dbus-login1.[ch]
 | 
			
		||||
src/mutter-plugins.pc
 | 
			
		||||
src/wayland/gtk-shell-protocol.c
 | 
			
		||||
src/wayland/gtk-shell-server-protocol.h
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,6 @@ AM_GLIB_GNU_GETTEXT
 | 
			
		||||
## here we get the flags we'll actually use
 | 
			
		||||
# GRegex requires Glib-2.14.0
 | 
			
		||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
 | 
			
		||||
 | 
			
		||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
 | 
			
		||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
 | 
			
		||||
@@ -213,7 +212,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
 | 
			
		||||
AC_SUBST([WAYLAND_SCANNER])
 | 
			
		||||
AC_SUBST(XWAYLAND_PATH)
 | 
			
		||||
 | 
			
		||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
 | 
			
		||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm libsystemd"
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
 | 
			
		||||
 
 | 
			
		||||
@@ -201,6 +201,37 @@
 | 
			
		||||
      <arg name="app_id" type="string"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <enum name="surface_type">
 | 
			
		||||
      <description summary="surface types">
 | 
			
		||||
        Surface
 | 
			
		||||
      </description>
 | 
			
		||||
      <entry name="normal" value="0" summary="A normal window. This is the default type."/>
 | 
			
		||||
      <entry name="modal_dialog" value="1" summary="A modal dialog."/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="set_surface_type">
 | 
			
		||||
      <description summary="set the surface type">
 | 
			
		||||
        Sets the type of the surface. These are high-level "roles" of
 | 
			
		||||
        surfaces designed to give the compositor more heuristics about
 | 
			
		||||
        how to place and manage the window.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="surface_type" type="uint" summary="a surface type from surface_type"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="show_window_menu">
 | 
			
		||||
      <description summary="show the window menu">
 | 
			
		||||
        Clients implementing client-side decorations might want to show
 | 
			
		||||
        a context menu when right-clicking on the decorations, giving the
 | 
			
		||||
        user a menu that they can use to maximize or minimize the window.
 | 
			
		||||
 | 
			
		||||
        The seat passed must have either pointer or keyboard focus to pop
 | 
			
		||||
        up the window menu for a surface.
 | 
			
		||||
      </description>
 | 
			
		||||
 | 
			
		||||
      <arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/>
 | 
			
		||||
      <arg name="serial" type="uint" summary="serial of the event to pop up the window for"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="move">
 | 
			
		||||
      <description summary="start an interactive move">
 | 
			
		||||
	Start a pointer-driven move of the surface.
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ INCLUDES += \
 | 
			
		||||
mutter_built_sources = \
 | 
			
		||||
	$(dbus_idle_built_sources)		\
 | 
			
		||||
	$(dbus_xrandr_built_sources)		\
 | 
			
		||||
	$(dbus_login1_built_sources)		\
 | 
			
		||||
	mutter-enum-types.h 			\
 | 
			
		||||
	mutter-enum-types.c			\
 | 
			
		||||
	wayland/gtk-shell-protocol.c		\
 | 
			
		||||
@@ -177,10 +178,6 @@ libmutter_wayland_la_SOURCES =			\
 | 
			
		||||
	ui/ui.h					\
 | 
			
		||||
	ui/frames.c				\
 | 
			
		||||
	ui/frames.h				\
 | 
			
		||||
	ui/menu.c				\
 | 
			
		||||
	ui/menu.h				\
 | 
			
		||||
	ui/metaaccellabel.c			\
 | 
			
		||||
	ui/metaaccellabel.h			\
 | 
			
		||||
	ui/resizepopup.c			\
 | 
			
		||||
	ui/resizepopup.h			\
 | 
			
		||||
	ui/theme-parser.c			\
 | 
			
		||||
@@ -207,8 +204,8 @@ libmutter_wayland_la_SOURCES =			\
 | 
			
		||||
	wayland/meta-wayland-surface.h		\
 | 
			
		||||
	wayland/meta-wayland-types.h		\
 | 
			
		||||
	wayland/meta-wayland-versions.h		\
 | 
			
		||||
	wayland/meta-weston-launch.c		\
 | 
			
		||||
	wayland/meta-weston-launch.h
 | 
			
		||||
	wayland/meta-login1.c			\
 | 
			
		||||
	wayland/meta-login1.h
 | 
			
		||||
 | 
			
		||||
nodist_libmutter_wayland_la_SOURCES =		\
 | 
			
		||||
	$(mutter_built_sources)
 | 
			
		||||
@@ -263,17 +260,6 @@ bin_PROGRAMS=mutter-wayland
 | 
			
		||||
mutter_wayland_SOURCES = core/mutter.c
 | 
			
		||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
 | 
			
		||||
 | 
			
		||||
bin_PROGRAMS+=mutter-launch
 | 
			
		||||
 | 
			
		||||
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
 | 
			
		||||
 | 
			
		||||
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
 | 
			
		||||
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
 | 
			
		||||
 | 
			
		||||
install-exec-hook:
 | 
			
		||||
	-chown root $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
	-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
 | 
			
		||||
if HAVE_INTROSPECTION
 | 
			
		||||
include $(INTROSPECTION_MAKEFILE)
 | 
			
		||||
 | 
			
		||||
@@ -409,6 +395,15 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
 | 
			
		||||
		--c-generate-object-manager						\
 | 
			
		||||
		$(srcdir)/idle-monitor.xml
 | 
			
		||||
 | 
			
		||||
dbus_login1_built_sources = meta-dbus-login1.c meta-dbus-login1.h
 | 
			
		||||
 | 
			
		||||
$(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
 | 
			
		||||
	$(AM_V_GEN)gdbus-codegen							\
 | 
			
		||||
		--interface-prefix org.freedesktop.login1				\
 | 
			
		||||
		--c-namespace Login1							\
 | 
			
		||||
		--generate-c-code meta-dbus-login1					\
 | 
			
		||||
		$(srcdir)/org.freedesktop.login1.xml
 | 
			
		||||
 | 
			
		||||
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
 | 
			
		||||
	mkdir -p wayland
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 | 
			
		||||
 
 | 
			
		||||
@@ -1723,3 +1723,15 @@ meta_compositor_hide_tile_preview (MetaCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  meta_plugin_manager_hide_tile_preview (info->plugin_mgr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_compositor_show_window_menu (MetaCompositor *compositor,
 | 
			
		||||
                                  MetaWindow     *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaCompScreen *info = meta_screen_get_compositor_data (window->screen);
 | 
			
		||||
 | 
			
		||||
  if (!info->plugin_mgr)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_plugin_manager_show_window_menu (info->plugin_mgr, window);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -365,3 +365,18 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_plugin_manager_show_window_menu (MetaPluginManager *plugin_mgr,
 | 
			
		||||
                                      MetaWindow        *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaPlugin *plugin = plugin_mgr->plugin;
 | 
			
		||||
  MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
 | 
			
		||||
  MetaDisplay *display  = meta_screen_get_display (plugin_mgr->screen);
 | 
			
		||||
 | 
			
		||||
  if (display->display_opening)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (klass->show_window_menu)
 | 
			
		||||
    klass->show_window_menu (plugin, window);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -80,4 +80,8 @@ gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
 | 
			
		||||
                                                MetaRectangle     *tile_rect,
 | 
			
		||||
                                                int                tile_monitor_number);
 | 
			
		||||
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
 | 
			
		||||
 | 
			
		||||
void meta_plugin_manager_show_window_menu (MetaPluginManager *mgr,
 | 
			
		||||
                                           MetaWindow        *window);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -714,7 +714,7 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
 | 
			
		||||
  /* Leaving out shadows for maximized and fullscreen windows is an effeciency
 | 
			
		||||
   * win and also prevents the unsightly effect of the shadow of maximized
 | 
			
		||||
   * window appearing on an adjacent window */
 | 
			
		||||
  if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
 | 
			
		||||
  if ((meta_window_get_maximized (priv->window) == META_MAXIMIZE_BOTH) ||
 | 
			
		||||
      meta_window_is_fullscreen (priv->window))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -817,7 +817,7 @@ constrain_maximization (MetaWindow         *window,
 | 
			
		||||
                                                active_workspace_struts);
 | 
			
		||||
   }
 | 
			
		||||
  /* Now make target_size = maximized size of client window */
 | 
			
		||||
  unextend_by_frame (window, &target_size);
 | 
			
		||||
  /* unextend_by_frame (window, &target_size); */
 | 
			
		||||
 | 
			
		||||
  /* Check min size constraints; max size constraints are ignored for maximized
 | 
			
		||||
   * windows, as per bug 327543.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										143
									
								
								src/core/core.c
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								src/core/core.c
									
									
									
									
									
								
							@@ -328,8 +328,7 @@ meta_core_maximize (Display *xdisplay,
 | 
			
		||||
  if (meta_prefs_get_raise_on_click ())
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
 | 
			
		||||
  meta_window_maximize (window, 
 | 
			
		||||
                        META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
  meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -342,11 +341,9 @@ meta_core_toggle_maximize_vertically (Display *xdisplay,
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
 | 
			
		||||
  if (META_WINDOW_MAXIMIZED_VERTICALLY (window))
 | 
			
		||||
    meta_window_unmaximize (window, 
 | 
			
		||||
                            META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
 | 
			
		||||
  else
 | 
			
		||||
    meta_window_maximize (window,
 | 
			
		||||
    			    META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -359,11 +356,9 @@ meta_core_toggle_maximize_horizontally (Display *xdisplay,
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
 | 
			
		||||
  if (META_WINDOW_MAXIMIZED_HORIZONTALLY (window))
 | 
			
		||||
    meta_window_unmaximize (window, 
 | 
			
		||||
                            META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
    meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
  else
 | 
			
		||||
    meta_window_maximize (window,
 | 
			
		||||
    			    META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
    meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -376,11 +371,9 @@ meta_core_toggle_maximize (Display *xdisplay,
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
 | 
			
		||||
  if (META_WINDOW_MAXIMIZED (window))
 | 
			
		||||
    meta_window_unmaximize (window, 
 | 
			
		||||
                            META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
  else
 | 
			
		||||
    meta_window_maximize (window,
 | 
			
		||||
                          META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -392,8 +385,7 @@ meta_core_unmaximize (Display *xdisplay,
 | 
			
		||||
  if (meta_prefs_get_raise_on_click ())
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
 | 
			
		||||
  meta_window_unmaximize (window,
 | 
			
		||||
                          META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
  meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -477,9 +469,6 @@ meta_core_change_workspace (Display *xdisplay,
 | 
			
		||||
void
 | 
			
		||||
meta_core_show_window_menu (Display *xdisplay,
 | 
			
		||||
                            Window   frame_xwindow,
 | 
			
		||||
                            int      root_x,
 | 
			
		||||
                            int      root_y,
 | 
			
		||||
                            int      button,
 | 
			
		||||
                            guint32  timestamp)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *window = get_window (xdisplay, frame_xwindow);
 | 
			
		||||
@@ -488,121 +477,7 @@ meta_core_show_window_menu (Display *xdisplay,
 | 
			
		||||
    meta_window_raise (window);
 | 
			
		||||
  meta_window_focus (window, timestamp);
 | 
			
		||||
 | 
			
		||||
  meta_window_show_menu (window, root_x, root_y, button, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_core_get_menu_accelerator (MetaMenuOp           menu_op,
 | 
			
		||||
                                int                  workspace,
 | 
			
		||||
                                unsigned int        *keysym,
 | 
			
		||||
                                MetaVirtualModifier *modifiers)
 | 
			
		||||
{
 | 
			
		||||
  const char *name;
 | 
			
		||||
 | 
			
		||||
  name = NULL;
 | 
			
		||||
  
 | 
			
		||||
  switch (menu_op)
 | 
			
		||||
    {
 | 
			
		||||
    case META_MENU_OP_NONE:
 | 
			
		||||
      /* No keybinding for this one */
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_DELETE:
 | 
			
		||||
      name = "close";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MINIMIZE:
 | 
			
		||||
      name = "minimize";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_UNMAXIMIZE:
 | 
			
		||||
      name = "unmaximize";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MAXIMIZE:
 | 
			
		||||
      name = "maximize";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_UNSHADE:
 | 
			
		||||
    case META_MENU_OP_SHADE:
 | 
			
		||||
      name = "toggle_shaded";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_UNSTICK:
 | 
			
		||||
    case META_MENU_OP_STICK:
 | 
			
		||||
      name = "toggle-on-all-workspaces";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_ABOVE:
 | 
			
		||||
    case META_MENU_OP_UNABOVE:
 | 
			
		||||
      name = "toggle-above";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_WORKSPACES:
 | 
			
		||||
      switch (workspace)
 | 
			
		||||
        {
 | 
			
		||||
        case 1:
 | 
			
		||||
          name = "move-to-workspace-1";
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          name = "move-to-workspace-2";
 | 
			
		||||
          break;
 | 
			
		||||
        case 3:
 | 
			
		||||
          name = "move-to-workspace-3";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 4:
 | 
			
		||||
          name = "move-to-workspace-4";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 5:
 | 
			
		||||
          name = "move-to-workspace-5";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 6:
 | 
			
		||||
          name = "move-to-workspace-6";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 7:
 | 
			
		||||
          name = "move-to-workspace-7";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 8:
 | 
			
		||||
          name = "move-to-workspace-8";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 9:
 | 
			
		||||
          name = "move-to-workspace-9";
 | 
			
		||||
          break; 
 | 
			
		||||
        case 10:
 | 
			
		||||
          name = "move-to-workspace-10";
 | 
			
		||||
          break;
 | 
			
		||||
        case 11:
 | 
			
		||||
          name = "move-to-workspace-11";
 | 
			
		||||
          break;
 | 
			
		||||
        case 12:
 | 
			
		||||
          name = "move-to-workspace-12";
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MOVE:
 | 
			
		||||
      name = "begin-move";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_RESIZE:
 | 
			
		||||
      name = "begin-resize";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MOVE_LEFT:
 | 
			
		||||
      name = "move-to-workspace-left";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MOVE_RIGHT:
 | 
			
		||||
      name = "move-to-workspace-right";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MOVE_UP:
 | 
			
		||||
      name = "move-to-workspace-up";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_MOVE_DOWN:
 | 
			
		||||
      name = "move-to-workspace-down";
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MENU_OP_RECOVER:
 | 
			
		||||
      /* No keybinding for this one */
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (name)
 | 
			
		||||
    {
 | 
			
		||||
      meta_prefs_get_window_binding (name, keysym, modifiers);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      *keysym = 0;
 | 
			
		||||
      *modifiers = 0;
 | 
			
		||||
    }
 | 
			
		||||
  meta_window_show_menu (window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char*
 | 
			
		||||
 
 | 
			
		||||
@@ -159,15 +159,8 @@ const char* meta_core_get_workspace_name_with_index (Display *xdisplay,
 | 
			
		||||
 | 
			
		||||
void meta_core_show_window_menu (Display *xdisplay,
 | 
			
		||||
                                 Window   frame_xwindow,
 | 
			
		||||
                                 int      root_x,
 | 
			
		||||
                                 int      root_y,
 | 
			
		||||
                                 int      button,
 | 
			
		||||
                                 guint32  timestamp);
 | 
			
		||||
 | 
			
		||||
void meta_core_get_menu_accelerator (MetaMenuOp           menu_op,
 | 
			
		||||
                                     int                  workspace,
 | 
			
		||||
                                     unsigned int        *keysym,
 | 
			
		||||
                                     MetaVirtualModifier *modifiers);
 | 
			
		||||
 | 
			
		||||
gboolean   meta_core_begin_grab_op (Display    *xdisplay,
 | 
			
		||||
                                    Window      frame_xwindow,
 | 
			
		||||
 
 | 
			
		||||
@@ -263,10 +263,6 @@ struct _MetaDisplay
 | 
			
		||||
  /* Managed by group.c */
 | 
			
		||||
  GHashTable *groups_by_leader;
 | 
			
		||||
 | 
			
		||||
  /* currently-active window menu if any */
 | 
			
		||||
  MetaWindowMenu *window_menu;
 | 
			
		||||
  MetaWindow *window_with_menu;
 | 
			
		||||
 | 
			
		||||
  /* Managed by window-props.c */
 | 
			
		||||
  MetaWindowPropHooks *prop_hooks_table;
 | 
			
		||||
  GHashTable *prop_hooks;
 | 
			
		||||
 
 | 
			
		||||
@@ -564,9 +564,6 @@ meta_display_open (void)
 | 
			
		||||
  the_display->monitor_cache_invalidated = TRUE;
 | 
			
		||||
 | 
			
		||||
  the_display->groups_by_leader = NULL;
 | 
			
		||||
 | 
			
		||||
  the_display->window_with_menu = NULL;
 | 
			
		||||
  the_display->window_menu = NULL;
 | 
			
		||||
  
 | 
			
		||||
  the_display->screens = NULL;
 | 
			
		||||
  the_display->active_screen = NULL;
 | 
			
		||||
@@ -2206,11 +2203,7 @@ meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
            {
 | 
			
		||||
              if (meta_prefs_get_raise_on_click ())
 | 
			
		||||
                meta_window_raise (window);
 | 
			
		||||
              meta_window_show_menu (window,
 | 
			
		||||
                                     event->button.x,
 | 
			
		||||
                                     event->button.y,
 | 
			
		||||
                                     event->button.button,
 | 
			
		||||
                                     event->any.time);
 | 
			
		||||
              meta_window_show_menu (window);
 | 
			
		||||
              bypass_clutter = TRUE;
 | 
			
		||||
              bypass_wayland = TRUE;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1975,9 +1975,7 @@ process_mouse_move_resize_grab (MetaDisplay     *display,
 | 
			
		||||
       * moveresize now to get the position back to the original.
 | 
			
		||||
       */
 | 
			
		||||
      if (window->shaken_loose || window->tile_mode == META_TILE_MAXIMIZED)
 | 
			
		||||
        meta_window_maximize (window,
 | 
			
		||||
                              META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                              META_MAXIMIZE_VERTICAL);
 | 
			
		||||
        meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      else if (window->tile_mode != META_TILE_NONE)
 | 
			
		||||
        meta_window_tile (window);
 | 
			
		||||
      else
 | 
			
		||||
@@ -2038,9 +2036,7 @@ process_keyboard_move_grab (MetaDisplay     *display,
 | 
			
		||||
       * now to get the position back to the original.
 | 
			
		||||
       */
 | 
			
		||||
      if (window->shaken_loose)
 | 
			
		||||
        meta_window_maximize (window,
 | 
			
		||||
                              META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                              META_MAXIMIZE_VERTICAL);
 | 
			
		||||
        meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      else
 | 
			
		||||
        meta_window_move_resize (display->grab_window,
 | 
			
		||||
                                 TRUE,
 | 
			
		||||
@@ -2786,20 +2782,7 @@ handle_activate_window_menu (MetaDisplay     *display,
 | 
			
		||||
                             gpointer         dummy)
 | 
			
		||||
{
 | 
			
		||||
  if (display->focus_window)
 | 
			
		||||
    {
 | 
			
		||||
      int x, y;
 | 
			
		||||
 | 
			
		||||
      meta_window_get_position (display->focus_window,
 | 
			
		||||
                                &x, &y);
 | 
			
		||||
 | 
			
		||||
      if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
 | 
			
		||||
        x += display->focus_window->rect.width;
 | 
			
		||||
 | 
			
		||||
      meta_window_show_menu (display->focus_window,
 | 
			
		||||
                             x, y,
 | 
			
		||||
                             0,
 | 
			
		||||
                             event->time);
 | 
			
		||||
    }
 | 
			
		||||
    meta_window_show_menu (display->focus_window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -2901,11 +2884,9 @@ handle_toggle_tiled (MetaDisplay     *display,
 | 
			
		||||
        : META_TILE_NONE;
 | 
			
		||||
 | 
			
		||||
      if (window->saved_maximize)
 | 
			
		||||
        meta_window_maximize (window, META_MAXIMIZE_VERTICAL |
 | 
			
		||||
                              META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
        meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      else
 | 
			
		||||
        meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL |
 | 
			
		||||
                                META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
        meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
    }
 | 
			
		||||
  else if (meta_window_can_tile_side_by_side (window))
 | 
			
		||||
    {
 | 
			
		||||
@@ -2931,13 +2912,9 @@ handle_toggle_maximized    (MetaDisplay     *display,
 | 
			
		||||
                            gpointer         dummy)
 | 
			
		||||
{
 | 
			
		||||
  if (META_WINDOW_MAXIMIZED (window))
 | 
			
		||||
    meta_window_unmaximize (window,
 | 
			
		||||
                            META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                            META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
  else if (window->has_maximize_func)
 | 
			
		||||
    meta_window_maximize (window,
 | 
			
		||||
                          META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                          META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -2949,9 +2926,7 @@ handle_maximize           (MetaDisplay     *display,
 | 
			
		||||
                           gpointer         dummy)
 | 
			
		||||
{
 | 
			
		||||
  if (window->has_maximize_func)
 | 
			
		||||
    meta_window_maximize (window,
 | 
			
		||||
                          META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                          META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -2963,9 +2938,7 @@ handle_unmaximize         (MetaDisplay     *display,
 | 
			
		||||
                           gpointer         dummy)
 | 
			
		||||
{
 | 
			
		||||
  if (window->maximized_vertically || window->maximized_horizontally)
 | 
			
		||||
    meta_window_unmaximize (window,
 | 
			
		||||
                            META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                            META_MAXIMIZE_VERTICAL);
 | 
			
		||||
    meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -2241,43 +2241,6 @@ meta_prefs_get_keybinding_action (const char *name)
 | 
			
		||||
              : META_KEYBINDING_ACTION_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This is used by the menu system to decide what key binding
 | 
			
		||||
 * to display next to an option. We return the first non-disabled
 | 
			
		||||
 * binding, if any.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_prefs_get_window_binding (const char          *name,
 | 
			
		||||
                               unsigned int        *keysym,
 | 
			
		||||
                               MetaVirtualModifier *modifiers)
 | 
			
		||||
{
 | 
			
		||||
  MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
 | 
			
		||||
 | 
			
		||||
  if (pref->per_window)
 | 
			
		||||
    {
 | 
			
		||||
      GSList *s = pref->combos;
 | 
			
		||||
 | 
			
		||||
      while (s)
 | 
			
		||||
        {
 | 
			
		||||
          MetaKeyCombo *c = s->data;
 | 
			
		||||
 | 
			
		||||
          if (c->keysym != 0 || c->modifiers != 0)
 | 
			
		||||
            {
 | 
			
		||||
              *keysym = c->keysym;
 | 
			
		||||
              *modifiers = c->modifiers;
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          s = s->next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Not found; return the disabled value */
 | 
			
		||||
      *keysym = *modifiers = 0;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gint
 | 
			
		||||
meta_prefs_get_mouse_button_resize (void)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -310,6 +310,7 @@ set_supported_hint (MetaScreen *screen)
 | 
			
		||||
#undef EWMH_ATOMS_ONLY
 | 
			
		||||
 | 
			
		||||
    screen->display->atom__GTK_FRAME_EXTENTS,
 | 
			
		||||
    screen->display->atom__GTK_SHOW_WINDOW_MENU,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  XChangeProperty (screen->display->xdisplay, screen->xroot,
 | 
			
		||||
 
 | 
			
		||||
@@ -628,11 +628,7 @@ void     meta_window_set_current_workspace_hint (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
unsigned long meta_window_get_net_wm_desktop (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
void meta_window_show_menu (MetaWindow *window,
 | 
			
		||||
                            int         root_x,
 | 
			
		||||
                            int         root_y,
 | 
			
		||||
                            int         button,
 | 
			
		||||
                            guint32     timestamp);
 | 
			
		||||
void meta_window_show_menu (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
gboolean meta_window_titlebar_is_onscreen    (MetaWindow *window);
 | 
			
		||||
void     meta_window_shove_titlebar_onscreen (MetaWindow *window);
 | 
			
		||||
 
 | 
			
		||||
@@ -1165,6 +1165,11 @@ meta_window_x11_client_message (MetaWindow *window,
 | 
			
		||||
 | 
			
		||||
      meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
 | 
			
		||||
    }
 | 
			
		||||
  else if (event->xclient.message_type ==
 | 
			
		||||
           display->atom__GTK_SHOW_WINDOW_MENU)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_show_menu (window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1368,9 +1368,7 @@ meta_window_apply_session_info (MetaWindow *window,
 | 
			
		||||
 | 
			
		||||
      if (window->has_maximize_func && info->maximized)
 | 
			
		||||
        {
 | 
			
		||||
          meta_window_maximize (window,
 | 
			
		||||
                                META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                                META_MAXIMIZE_VERTICAL);
 | 
			
		||||
          meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
 | 
			
		||||
          if (info->saved_rect_set)
 | 
			
		||||
            {
 | 
			
		||||
@@ -1524,13 +1522,6 @@ meta_window_unmanage (MetaWindow  *window,
 | 
			
		||||
      meta_compositor_remove_window (window->display->compositor, window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (window->display->window_with_menu == window)
 | 
			
		||||
    {
 | 
			
		||||
      meta_ui_window_menu_free (window->display->window_menu);
 | 
			
		||||
      window->display->window_menu = NULL;
 | 
			
		||||
      window->display->window_with_menu = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (destroying_windows_disallowed > 0)
 | 
			
		||||
    meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
 | 
			
		||||
              window->desc);
 | 
			
		||||
@@ -3370,7 +3361,7 @@ meta_window_tile (MetaWindow *window)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (window->tile_mode == META_TILE_MAXIMIZED)
 | 
			
		||||
    directions = META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL;
 | 
			
		||||
    directions = META_MAXIMIZE_BOTH;
 | 
			
		||||
  else
 | 
			
		||||
    directions = META_MAXIMIZE_VERTICAL;
 | 
			
		||||
 | 
			
		||||
@@ -7420,272 +7411,11 @@ meta_window_recalc_features (MetaWindow *window)
 | 
			
		||||
   */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
menu_callback (MetaWindowMenu *menu,
 | 
			
		||||
               Display        *xdisplay,
 | 
			
		||||
               Window          client_xwindow,
 | 
			
		||||
               guint32         timestamp,
 | 
			
		||||
               MetaMenuOp      op,
 | 
			
		||||
               int             workspace_index,
 | 
			
		||||
               gpointer        data)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  MetaWorkspace *workspace;
 | 
			
		||||
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  window = meta_display_lookup_x_window (display, client_xwindow);
 | 
			
		||||
  workspace = NULL;
 | 
			
		||||
 | 
			
		||||
  if (window != NULL) /* window can be NULL */
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Menu op %u on %s\n", op, window->desc);
 | 
			
		||||
 | 
			
		||||
      switch (op)
 | 
			
		||||
        {
 | 
			
		||||
        case META_MENU_OP_NONE:
 | 
			
		||||
          /* nothing */
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_DELETE:
 | 
			
		||||
          meta_window_delete (window, timestamp);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MINIMIZE:
 | 
			
		||||
          meta_window_minimize (window);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_UNMAXIMIZE:
 | 
			
		||||
          meta_window_unmaximize (window,
 | 
			
		||||
                                  META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                                  META_MAXIMIZE_VERTICAL);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MAXIMIZE:
 | 
			
		||||
          meta_window_maximize (window,
 | 
			
		||||
                                META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                                META_MAXIMIZE_VERTICAL);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_UNSHADE:
 | 
			
		||||
          meta_window_unshade (window, timestamp);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_SHADE:
 | 
			
		||||
          meta_window_shade (window, timestamp);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MOVE_LEFT:
 | 
			
		||||
          workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
 | 
			
		||||
                                                   META_MOTION_LEFT);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MOVE_RIGHT:
 | 
			
		||||
          workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
 | 
			
		||||
                                                   META_MOTION_RIGHT);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MOVE_UP:
 | 
			
		||||
          workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
 | 
			
		||||
                                                   META_MOTION_UP);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MOVE_DOWN:
 | 
			
		||||
          workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
 | 
			
		||||
                                                   META_MOTION_DOWN);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_WORKSPACES:
 | 
			
		||||
          workspace = meta_screen_get_workspace_by_index (window->screen,
 | 
			
		||||
                                                          workspace_index);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_STICK:
 | 
			
		||||
          meta_window_stick (window);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_UNSTICK:
 | 
			
		||||
          meta_window_unstick (window);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_ABOVE:
 | 
			
		||||
        case META_MENU_OP_UNABOVE:
 | 
			
		||||
          if (window->wm_state_above == FALSE)
 | 
			
		||||
            meta_window_make_above (window);
 | 
			
		||||
          else
 | 
			
		||||
            meta_window_unmake_above (window);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_MOVE:
 | 
			
		||||
          meta_window_begin_grab_op (window,
 | 
			
		||||
                                     META_GRAB_OP_KEYBOARD_MOVING,
 | 
			
		||||
                                     TRUE,
 | 
			
		||||
                                     timestamp);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_RESIZE:
 | 
			
		||||
          meta_window_begin_grab_op (window,
 | 
			
		||||
                                     META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
 | 
			
		||||
                                     TRUE,
 | 
			
		||||
                                     timestamp);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case META_MENU_OP_RECOVER:
 | 
			
		||||
          meta_window_shove_titlebar_onscreen (window);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
          meta_warning (G_STRLOC": Unknown window op\n");
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (workspace)
 | 
			
		||||
	{
 | 
			
		||||
	  meta_window_change_workspace (window,
 | 
			
		||||
					workspace);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Menu callback on nonexistent window\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (display->window_menu == menu)
 | 
			
		||||
    {
 | 
			
		||||
      display->window_menu = NULL;
 | 
			
		||||
      display->window_with_menu = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_ui_window_menu_free (menu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_show_menu (MetaWindow *window,
 | 
			
		||||
                       int         root_x,
 | 
			
		||||
                       int         root_y,
 | 
			
		||||
                       int         button,
 | 
			
		||||
                       guint32     timestamp)
 | 
			
		||||
meta_window_show_menu (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaMenuOp ops;
 | 
			
		||||
  MetaMenuOp insensitive;
 | 
			
		||||
  MetaWindowMenu *menu;
 | 
			
		||||
  MetaWorkspaceLayout layout;
 | 
			
		||||
  int n_workspaces;
 | 
			
		||||
  gboolean ltr;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (window->display->window_menu)
 | 
			
		||||
    {
 | 
			
		||||
      meta_ui_window_menu_free (window->display->window_menu);
 | 
			
		||||
      window->display->window_menu = NULL;
 | 
			
		||||
      window->display->window_with_menu = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ops = META_MENU_OP_NONE;
 | 
			
		||||
  insensitive = META_MENU_OP_NONE;
 | 
			
		||||
 | 
			
		||||
  ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE);
 | 
			
		||||
 | 
			
		||||
  if (!meta_window_titlebar_is_onscreen (window) &&
 | 
			
		||||
      window->type != META_WINDOW_DOCK &&
 | 
			
		||||
      window->type != META_WINDOW_DESKTOP)
 | 
			
		||||
    ops |= META_MENU_OP_RECOVER;
 | 
			
		||||
 | 
			
		||||
  if (!meta_prefs_get_workspaces_only_on_primary () ||
 | 
			
		||||
      meta_window_is_on_primary_monitor (window))
 | 
			
		||||
    {
 | 
			
		||||
      n_workspaces = meta_screen_get_n_workspaces (window->screen);
 | 
			
		||||
 | 
			
		||||
      if (n_workspaces > 1)
 | 
			
		||||
        ops |= META_MENU_OP_WORKSPACES;
 | 
			
		||||
 | 
			
		||||
      meta_screen_calc_workspace_layout (window->screen,
 | 
			
		||||
                                         n_workspaces,
 | 
			
		||||
                                         meta_workspace_index ( window->screen->active_workspace),
 | 
			
		||||
                                         &layout);
 | 
			
		||||
 | 
			
		||||
      if (!window->on_all_workspaces)
 | 
			
		||||
        {
 | 
			
		||||
          ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
 | 
			
		||||
 | 
			
		||||
          if (layout.current_col > 0)
 | 
			
		||||
            ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
 | 
			
		||||
          if ((layout.current_col < layout.cols - 1) &&
 | 
			
		||||
              (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
 | 
			
		||||
            ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
 | 
			
		||||
          if (layout.current_row > 0)
 | 
			
		||||
            ops |= META_MENU_OP_MOVE_UP;
 | 
			
		||||
          if ((layout.current_row < layout.rows - 1) &&
 | 
			
		||||
              ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
 | 
			
		||||
            ops |= META_MENU_OP_MOVE_DOWN;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_screen_free_workspace_layout (&layout);
 | 
			
		||||
 | 
			
		||||
      ops |= META_MENU_OP_UNSTICK;
 | 
			
		||||
      ops |= META_MENU_OP_STICK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (META_WINDOW_MAXIMIZED (window))
 | 
			
		||||
    ops |= META_MENU_OP_UNMAXIMIZE;
 | 
			
		||||
  else
 | 
			
		||||
    ops |= META_MENU_OP_MAXIMIZE;
 | 
			
		||||
 | 
			
		||||
  if (window->wm_state_above)
 | 
			
		||||
    ops |= META_MENU_OP_UNABOVE;
 | 
			
		||||
  else
 | 
			
		||||
    ops |= META_MENU_OP_ABOVE;
 | 
			
		||||
 | 
			
		||||
  if (!window->has_maximize_func)
 | 
			
		||||
    insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE;
 | 
			
		||||
 | 
			
		||||
  if (!window->has_minimize_func)
 | 
			
		||||
    insensitive |= META_MENU_OP_MINIMIZE;
 | 
			
		||||
 | 
			
		||||
  if (!window->has_close_func)
 | 
			
		||||
    insensitive |= META_MENU_OP_DELETE;
 | 
			
		||||
 | 
			
		||||
  if (!window->has_shade_func)
 | 
			
		||||
    insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE;
 | 
			
		||||
 | 
			
		||||
  if (!META_WINDOW_ALLOWS_MOVE (window))
 | 
			
		||||
    insensitive |= META_MENU_OP_MOVE;
 | 
			
		||||
 | 
			
		||||
  if (!META_WINDOW_ALLOWS_RESIZE (window))
 | 
			
		||||
    insensitive |= META_MENU_OP_RESIZE;
 | 
			
		||||
 | 
			
		||||
   if (window->always_sticky)
 | 
			
		||||
     insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES;
 | 
			
		||||
 | 
			
		||||
  if ((window->type == META_WINDOW_DESKTOP) ||
 | 
			
		||||
      (window->type == META_WINDOW_DOCK) ||
 | 
			
		||||
      (window->type == META_WINDOW_SPLASHSCREEN ||
 | 
			
		||||
      META_WINDOW_MAXIMIZED (window)))
 | 
			
		||||
    insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE;
 | 
			
		||||
 | 
			
		||||
  /* If all operations are disabled, just quit without showing the menu.
 | 
			
		||||
   * This is the case, for example, with META_WINDOW_DESKTOP windows.
 | 
			
		||||
   */
 | 
			
		||||
  if ((ops & ~insensitive) == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  menu =
 | 
			
		||||
    meta_ui_window_menu_new (window->screen->ui,
 | 
			
		||||
                             window->xwindow,
 | 
			
		||||
                             ops,
 | 
			
		||||
                             insensitive,
 | 
			
		||||
                             meta_window_get_net_wm_desktop (window),
 | 
			
		||||
                             meta_screen_get_n_workspaces (window->screen),
 | 
			
		||||
                             menu_callback,
 | 
			
		||||
                             NULL);
 | 
			
		||||
 | 
			
		||||
  window->display->window_menu = menu;
 | 
			
		||||
  window->display->window_with_menu = window;
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Popping up window menu for %s\n", window->desc);
 | 
			
		||||
 | 
			
		||||
  meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp);
 | 
			
		||||
  meta_compositor_show_window_menu (window->display->compositor, window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -7981,10 +7711,7 @@ update_move (MetaWindow  *window,
 | 
			
		||||
      display->grab_anchor_root_x = x;
 | 
			
		||||
      display->grab_anchor_root_y = y;
 | 
			
		||||
 | 
			
		||||
      meta_window_unmaximize (window,
 | 
			
		||||
                              META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                              META_MAXIMIZE_VERTICAL);
 | 
			
		||||
 | 
			
		||||
      meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -8028,9 +7755,7 @@ update_move (MetaWindow  *window,
 | 
			
		||||
                  window->user_rect.x = window->saved_rect.x;
 | 
			
		||||
                  window->user_rect.y = window->saved_rect.y;
 | 
			
		||||
 | 
			
		||||
                  meta_window_unmaximize (window,
 | 
			
		||||
                                          META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                                          META_MAXIMIZE_VERTICAL);
 | 
			
		||||
                  meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              display->grab_initial_window_pos = work_area;
 | 
			
		||||
@@ -8038,10 +7763,7 @@ update_move (MetaWindow  *window,
 | 
			
		||||
              display->grab_anchor_root_y = y;
 | 
			
		||||
              window->shaken_loose = FALSE;
 | 
			
		||||
 | 
			
		||||
              meta_window_maximize (window,
 | 
			
		||||
                                    META_MAXIMIZE_HORIZONTAL |
 | 
			
		||||
                                    META_MAXIMIZE_VERTICAL);
 | 
			
		||||
 | 
			
		||||
              meta_window_maximize (window, META_MAXIMIZE_BOTH);
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -10065,12 +9787,6 @@ meta_window_compute_tile_match (MetaWindow *window)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_can_close (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->has_close_func;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_set_title (MetaWindow *window,
 | 
			
		||||
                       const char *title)
 | 
			
		||||
@@ -10412,3 +10128,51 @@ meta_window_set_custom_frame_extents (MetaWindow *window,
 | 
			
		||||
 | 
			
		||||
  meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_can_maximize (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->has_maximize_func;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_can_minimize (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->has_minimize_func;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_can_shade (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->has_shade_func;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_can_close (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->has_close_func;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_is_always_on_all_workspaces (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->always_sticky;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_is_above (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return window->wm_state_above;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_allows_move (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return META_WINDOW_ALLOWS_MOVE (window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_window_allows_resize (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  return META_WINDOW_ALLOWS_RESIZE (window);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ item(_GTK_WINDOW_OBJECT_PATH)
 | 
			
		||||
item(_GTK_APP_MENU_OBJECT_PATH)
 | 
			
		||||
item(_GTK_MENUBAR_OBJECT_PATH)
 | 
			
		||||
item(_GTK_FRAME_EXTENTS)
 | 
			
		||||
item(_GTK_SHOW_WINDOW_MENU)
 | 
			
		||||
item(_GNOME_WM_KEYBINDINGS)
 | 
			
		||||
item(_GNOME_PANEL_ACTION)
 | 
			
		||||
item(_GNOME_PANEL_ACTION_MAIN_MENU)
 | 
			
		||||
 
 | 
			
		||||
@@ -86,61 +86,6 @@ typedef enum
 | 
			
		||||
  META_FRAME_TILED_RIGHT              = 1 << 16
 | 
			
		||||
} MetaFrameFlags;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaMenuOp:
 | 
			
		||||
 * @META_MENU_OP_NONE: No menu operation
 | 
			
		||||
 * @META_MENU_OP_DELETE: Menu operation delete
 | 
			
		||||
 * @META_MENU_OP_MINIMIZE: Menu operation minimize
 | 
			
		||||
 * @META_MENU_OP_UNMAXIMIZE: Menu operation unmaximize
 | 
			
		||||
 * @META_MENU_OP_MAXIMIZE: Menu operation maximize
 | 
			
		||||
 * @META_MENU_OP_UNSHADE: Menu operation unshade
 | 
			
		||||
 * @META_MENU_OP_SHADE: Menu operation shade
 | 
			
		||||
 * @META_MENU_OP_UNSTICK: Menu operation unstick
 | 
			
		||||
 * @META_MENU_OP_STICK: Menu operation stick
 | 
			
		||||
 * @META_MENU_OP_WORKSPACES: Menu operation workspaces
 | 
			
		||||
 * @META_MENU_OP_MOVE: Menu operation move
 | 
			
		||||
 * @META_MENU_OP_RESIZE: Menu operation resize
 | 
			
		||||
 * @META_MENU_OP_ABOVE: Menu operation above
 | 
			
		||||
 * @META_MENU_OP_UNABOVE: Menu operation unabove
 | 
			
		||||
 * @META_MENU_OP_MOVE_LEFT: Menu operation left
 | 
			
		||||
 * @META_MENU_OP_MOVE_RIGHT: Menu operation right
 | 
			
		||||
 * @META_MENU_OP_MOVE_UP: Menu operation up
 | 
			
		||||
 * @META_MENU_OP_MOVE_DOWN: Menu operation down
 | 
			
		||||
 * @META_MENU_OP_RECOVER: Menu operation recover
 | 
			
		||||
 */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_MENU_OP_NONE        = 0,
 | 
			
		||||
  META_MENU_OP_DELETE      = 1 << 0,
 | 
			
		||||
  META_MENU_OP_MINIMIZE    = 1 << 1,
 | 
			
		||||
  META_MENU_OP_UNMAXIMIZE  = 1 << 2,
 | 
			
		||||
  META_MENU_OP_MAXIMIZE    = 1 << 3,
 | 
			
		||||
  META_MENU_OP_UNSHADE     = 1 << 4,
 | 
			
		||||
  META_MENU_OP_SHADE       = 1 << 5,
 | 
			
		||||
  META_MENU_OP_UNSTICK     = 1 << 6,
 | 
			
		||||
  META_MENU_OP_STICK       = 1 << 7,
 | 
			
		||||
  META_MENU_OP_WORKSPACES  = 1 << 8,
 | 
			
		||||
  META_MENU_OP_MOVE        = 1 << 9,
 | 
			
		||||
  META_MENU_OP_RESIZE      = 1 << 10,
 | 
			
		||||
  META_MENU_OP_ABOVE       = 1 << 11,
 | 
			
		||||
  META_MENU_OP_UNABOVE     = 1 << 12,
 | 
			
		||||
  META_MENU_OP_MOVE_LEFT   = 1 << 13,
 | 
			
		||||
  META_MENU_OP_MOVE_RIGHT  = 1 << 14,
 | 
			
		||||
  META_MENU_OP_MOVE_UP     = 1 << 15,
 | 
			
		||||
  META_MENU_OP_MOVE_DOWN   = 1 << 16,
 | 
			
		||||
  META_MENU_OP_RECOVER     = 1 << 17
 | 
			
		||||
} MetaMenuOp;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWindowMenu MetaWindowMenu;
 | 
			
		||||
 | 
			
		||||
typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
 | 
			
		||||
                                     Display        *xdisplay,
 | 
			
		||||
                                     Window          client_xwindow,
 | 
			
		||||
                                     guint32         timestamp,
 | 
			
		||||
                                     MetaMenuOp      op,
 | 
			
		||||
                                     int             workspace,
 | 
			
		||||
                                     gpointer        user_data);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaGrabOp:
 | 
			
		||||
 * @META_GRAB_OP_NONE: None
 | 
			
		||||
 
 | 
			
		||||
@@ -130,5 +130,7 @@ void meta_compositor_show_tile_preview (MetaCompositor *compositor,
 | 
			
		||||
                                        int             tile_monitor_number);
 | 
			
		||||
void meta_compositor_hide_tile_preview (MetaCompositor *compositor,
 | 
			
		||||
                                        MetaScreen     *screen);
 | 
			
		||||
void meta_compositor_show_window_menu (MetaCompositor *compositor,
 | 
			
		||||
                                       MetaWindow     *window);
 | 
			
		||||
 | 
			
		||||
#endif /* META_COMPOSITOR_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -164,6 +164,9 @@ struct _MetaPluginClass
 | 
			
		||||
                             int              tile_monitor_number);
 | 
			
		||||
  void (*hide_tile_preview) (MetaPlugin      *plugin);
 | 
			
		||||
 | 
			
		||||
  void (*show_window_menu)  (MetaPlugin      *plugin,
 | 
			
		||||
                             MetaWindow      *window);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * MetaPluginClass::kill_window_effects:
 | 
			
		||||
   * @actor: a #MetaWindowActor
 | 
			
		||||
 
 | 
			
		||||
@@ -392,10 +392,6 @@ GType meta_key_binding_get_type    (void);
 | 
			
		||||
 | 
			
		||||
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
 | 
			
		||||
 | 
			
		||||
void meta_prefs_get_window_binding (const char          *name,
 | 
			
		||||
                                    unsigned int        *keysym,
 | 
			
		||||
                                    MetaVirtualModifier *modifiers);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_prefs_get_visual_bell      (void);
 | 
			
		||||
gboolean           meta_prefs_bell_is_audible      (void);
 | 
			
		||||
GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);
 | 
			
		||||
 
 | 
			
		||||
@@ -72,11 +72,13 @@ typedef enum
 | 
			
		||||
 * MetaMaximizeFlags:
 | 
			
		||||
 * @META_MAXIMIZE_HORIZONTAL: Horizontal
 | 
			
		||||
 * @META_MAXIMIZE_VERTICAL: Vertical
 | 
			
		||||
 * @META_MAXIMIZE_BOTH: Both
 | 
			
		||||
 */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_MAXIMIZE_HORIZONTAL = 1 << 0,
 | 
			
		||||
  META_MAXIMIZE_VERTICAL   = 1 << 1
 | 
			
		||||
  META_MAXIMIZE_VERTICAL   = 1 << 1,
 | 
			
		||||
  META_MAXIMIZE_BOTH       = (1 << 0 | 1 << 1),
 | 
			
		||||
} MetaMaximizeFlags;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -252,6 +254,13 @@ void meta_window_begin_grab_op (MetaWindow *window,
 | 
			
		||||
                                gboolean    frame_action,
 | 
			
		||||
                                guint32     timestamp);
 | 
			
		||||
 | 
			
		||||
gboolean meta_window_can_maximize (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_can_minimize (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_can_shade (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_can_close (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_is_always_on_all_workspaces (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_is_above (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_allows_move (MetaWindow *window);
 | 
			
		||||
gboolean meta_window_allows_resize (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
[Desktop Entry]
 | 
			
		||||
Type=Application
 | 
			
		||||
_Name=Mutter (wayland compositor)
 | 
			
		||||
Exec=mutter-launch -- mutter --wayland --display-server
 | 
			
		||||
Exec=mutter --wayland --display-server
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
# name of loadable control center module
 | 
			
		||||
X-GNOME-WMSettingsModule=metacity
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								src/org.freedesktop.login1.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/org.freedesktop.login1.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
 | 
			
		||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
 | 
			
		||||
<node>
 | 
			
		||||
  <interface name="org.freedesktop.login1.Session">
 | 
			
		||||
    <property name="Active" type="b" access="read" />
 | 
			
		||||
 | 
			
		||||
    <method name="Activate">
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="TakeControl">
 | 
			
		||||
      <arg name="force" type="b"/>
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="TakeDevice">
 | 
			
		||||
      <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
 | 
			
		||||
      <arg name="major" type="u" direction="in"/>
 | 
			
		||||
      <arg name="minor" type="u" direction="in"/>
 | 
			
		||||
      <arg name="fd" type="h" direction="out"/>
 | 
			
		||||
      <arg name="paused" type="b" direction="out"/>
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="ReleaseDevice">
 | 
			
		||||
      <arg name="major" type="u"/>
 | 
			
		||||
      <arg name="minor" type="u"/>
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="PauseDeviceComplete">
 | 
			
		||||
      <arg name="major" type="u"/>
 | 
			
		||||
      <arg name="minor" type="u"/>
 | 
			
		||||
    </method>
 | 
			
		||||
    <signal name="PauseDevice">
 | 
			
		||||
      <arg name="major" type="u"/>
 | 
			
		||||
      <arg name="minor" type="u"/>
 | 
			
		||||
      <arg name="type" type="s"/>
 | 
			
		||||
    </signal>
 | 
			
		||||
    <signal name="ResumeDevice">
 | 
			
		||||
      <arg name="major" type="u"/>
 | 
			
		||||
      <arg name="minor" type="u"/>
 | 
			
		||||
      <arg name="fd" type="h"/>
 | 
			
		||||
    </signal>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="org.freedesktop.login1.Seat">
 | 
			
		||||
    <method name="SwitchTo">
 | 
			
		||||
      <arg name="vt" type="u"/>
 | 
			
		||||
    </method>
 | 
			
		||||
  </interface>
 | 
			
		||||
</node>
 | 
			
		||||
@@ -1106,9 +1106,6 @@ meta_frame_titlebar_event (MetaUIFrame    *frame,
 | 
			
		||||
    case G_DESKTOP_TITLEBAR_ACTION_MENU:
 | 
			
		||||
      meta_core_show_window_menu (display,
 | 
			
		||||
                                  frame->xwindow,
 | 
			
		||||
                                  event->x_root,
 | 
			
		||||
                                  event->y_root,
 | 
			
		||||
                                  event->button,
 | 
			
		||||
                                  event->time);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1268,30 +1265,9 @@ meta_frames_button_press_event (GtkWidget      *widget,
 | 
			
		||||
      redraw_control (frames, frame, control);
 | 
			
		||||
 | 
			
		||||
      if (op == META_GRAB_OP_CLICKING_MENU)
 | 
			
		||||
        {
 | 
			
		||||
          MetaFrameGeometry fgeom;
 | 
			
		||||
          GdkRectangle *rect;
 | 
			
		||||
          int dx, dy;
 | 
			
		||||
          
 | 
			
		||||
          meta_frames_calc_geometry (frames, frame, &fgeom);
 | 
			
		||||
          
 | 
			
		||||
          rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
 | 
			
		||||
 | 
			
		||||
          /* get delta to convert to root coords */
 | 
			
		||||
          dx = event->x_root - event->x;
 | 
			
		||||
          dy = event->y_root - event->y;
 | 
			
		||||
          
 | 
			
		||||
          /* Align to the right end of the menu rectangle if RTL */
 | 
			
		||||
          if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
 | 
			
		||||
            dx += rect->width;
 | 
			
		||||
 | 
			
		||||
          meta_core_show_window_menu (display,
 | 
			
		||||
                                      frame->xwindow,
 | 
			
		||||
                                      rect->x + dx,
 | 
			
		||||
                                      rect->y + rect->height + dy,
 | 
			
		||||
                                      event->button,
 | 
			
		||||
                                      event->time);
 | 
			
		||||
        }
 | 
			
		||||
        meta_core_show_window_menu (display,
 | 
			
		||||
                                    frame->xwindow,
 | 
			
		||||
                                    event->time);
 | 
			
		||||
    }
 | 
			
		||||
  else if (event->button == 1 &&
 | 
			
		||||
           (control == META_FRAME_CONTROL_RESIZE_SE ||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										518
									
								
								src/ui/menu.c
									
									
									
									
									
								
							
							
						
						
									
										518
									
								
								src/ui/menu.c
									
									
									
									
									
								
							@@ -1,518 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Mutter window menu */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2001 Havoc Pennington
 | 
			
		||||
 * Copyright (C) 2004 Rob Adams
 | 
			
		||||
 * Copyright (C) 2005 Elijah Newren
 | 
			
		||||
 * 
 | 
			
		||||
 * 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 <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "menu.h"
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include "util-private.h"
 | 
			
		||||
#include "core.h"
 | 
			
		||||
#include "metaaccellabel.h"
 | 
			
		||||
#include "ui.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MenuItem MenuItem;
 | 
			
		||||
typedef struct _MenuData MenuData;
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  MENU_ITEM_SEPARATOR = 0,
 | 
			
		||||
  MENU_ITEM_NORMAL,
 | 
			
		||||
  MENU_ITEM_CHECKBOX,
 | 
			
		||||
  MENU_ITEM_RADIOBUTTON,
 | 
			
		||||
  MENU_ITEM_WORKSPACE_LIST,
 | 
			
		||||
} MetaMenuItemType;
 | 
			
		||||
 | 
			
		||||
struct _MenuItem
 | 
			
		||||
{
 | 
			
		||||
  MetaMenuOp op;
 | 
			
		||||
  MetaMenuItemType type;
 | 
			
		||||
  const gboolean checked;
 | 
			
		||||
  const char *label;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct _MenuData
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowMenu *menu;
 | 
			
		||||
  MetaMenuOp op;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void activate_cb (GtkWidget *menuitem, gpointer data);
 | 
			
		||||
 | 
			
		||||
static MenuItem menuitems[] = {
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MINIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Mi_nimize") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Ma_ximize") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_UNMAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Unma_ximize") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_SHADE, MENU_ITEM_NORMAL, FALSE, N_("Roll _Up") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_UNSHADE, MENU_ITEM_NORMAL, FALSE, N_("_Unroll") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MOVE, MENU_ITEM_NORMAL, FALSE, N_("_Move") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_RESIZE, MENU_ITEM_NORMAL, FALSE, N_("_Resize") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_RECOVER, MENU_ITEM_NORMAL, FALSE, N_("Move Titlebar On_screen") },
 | 
			
		||||
  { META_MENU_OP_WORKSPACES, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_ABOVE, MENU_ITEM_CHECKBOX, FALSE, N_("Always on _Top") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_UNABOVE, MENU_ITEM_CHECKBOX, TRUE, N_("Always on _Top") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_STICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Always on Visible Workspace") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_UNSTICK, MENU_ITEM_RADIOBUTTON, FALSE,  N_("_Only on This Workspace") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MOVE_LEFT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Left") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MOVE_RIGHT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace R_ight") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MOVE_UP, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Up") },
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_MOVE_DOWN, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Down") },
 | 
			
		||||
  { 0, MENU_ITEM_WORKSPACE_LIST, FALSE, NULL },
 | 
			
		||||
  { 0, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
 | 
			
		||||
  /* Translators: Translate this string the same way as you do in libwnck! */
 | 
			
		||||
  { META_MENU_OP_DELETE, MENU_ITEM_NORMAL, FALSE, N_("_Close") }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
popup_position_func (GtkMenu   *menu,
 | 
			
		||||
                     gint      *x,
 | 
			
		||||
                     gint      *y,
 | 
			
		||||
                     gboolean  *push_in,
 | 
			
		||||
                     gpointer  user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkRequisition req;      
 | 
			
		||||
  GdkPoint *pos;
 | 
			
		||||
 | 
			
		||||
  pos = user_data;
 | 
			
		||||
  
 | 
			
		||||
  gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
 | 
			
		||||
 | 
			
		||||
  *x = pos->x;
 | 
			
		||||
  *y = pos->y;
 | 
			
		||||
  
 | 
			
		||||
  if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
 | 
			
		||||
    *x = MAX (0, *x - req.width); 
 | 
			
		||||
 | 
			
		||||
  /* Ensure onscreen */
 | 
			
		||||
  *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
 | 
			
		||||
  *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
menu_closed (GtkMenu *widget,
 | 
			
		||||
             gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowMenu *menu;
 | 
			
		||||
  
 | 
			
		||||
  menu = data;
 | 
			
		||||
 | 
			
		||||
  meta_frames_notify_menu_hide (menu->frames);
 | 
			
		||||
  (* menu->func) (menu,
 | 
			
		||||
                  GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 | 
			
		||||
                  menu->client_xwindow,
 | 
			
		||||
                  gtk_get_current_event_time (),
 | 
			
		||||
                  0, 0,
 | 
			
		||||
                  menu->data);
 | 
			
		||||
  
 | 
			
		||||
  /* menu may now be freed */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
activate_cb (GtkWidget *menuitem, gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MenuData *md;
 | 
			
		||||
  
 | 
			
		||||
  g_return_if_fail (GTK_IS_WIDGET (menuitem));
 | 
			
		||||
  
 | 
			
		||||
  md = data;
 | 
			
		||||
 | 
			
		||||
  meta_frames_notify_menu_hide (md->menu->frames);
 | 
			
		||||
  (* md->menu->func) (md->menu,
 | 
			
		||||
                      GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 | 
			
		||||
                      md->menu->client_xwindow,
 | 
			
		||||
                      gtk_get_current_event_time (),
 | 
			
		||||
                      md->op,
 | 
			
		||||
                      GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
 | 
			
		||||
                                                          "workspace")),
 | 
			
		||||
                      md->menu->data);
 | 
			
		||||
 | 
			
		||||
  /* menu may now be freed */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given a Display and an index, get the workspace name and add any
 | 
			
		||||
 * accelerators. At the moment this means adding a _ if the name is of
 | 
			
		||||
 * the form "Workspace n" where n is less than 10, and escaping any
 | 
			
		||||
 * other '_'s so they do not create inadvertant accelerators.
 | 
			
		||||
 * 
 | 
			
		||||
 * The calling code owns the string, and is reponsible to free the
 | 
			
		||||
 * memory after use.
 | 
			
		||||
 *
 | 
			
		||||
 * See also http://mail.gnome.org/archives/gnome-i18n/2008-March/msg00380.html
 | 
			
		||||
 * which discusses possible i18n concerns.
 | 
			
		||||
 */
 | 
			
		||||
static char*
 | 
			
		||||
get_workspace_name_with_accel (Display *display,
 | 
			
		||||
                               Window   xroot,
 | 
			
		||||
                               int      index)
 | 
			
		||||
{
 | 
			
		||||
  const char *name;
 | 
			
		||||
  int number;
 | 
			
		||||
  int charcount=0;
 | 
			
		||||
 | 
			
		||||
  name = meta_core_get_workspace_name_with_index (display, xroot, index);
 | 
			
		||||
 | 
			
		||||
  g_assert (name != NULL);
 | 
			
		||||
  
 | 
			
		||||
  /*
 | 
			
		||||
   * If the name is of the form "Workspace x" where x is an unsigned
 | 
			
		||||
   * integer, insert a '_' before the number if it is less than 10 and
 | 
			
		||||
   * return it
 | 
			
		||||
   */
 | 
			
		||||
  number = 0;
 | 
			
		||||
  if (sscanf (name, _("Workspace %d%n"), &number, &charcount) != 0 &&
 | 
			
		||||
      *(name + charcount)=='\0')
 | 
			
		||||
    {
 | 
			
		||||
      char *new_name;
 | 
			
		||||
      
 | 
			
		||||
      /*
 | 
			
		||||
       * Above name is a pointer into the Workspace struct. Here we make
 | 
			
		||||
       * a copy copy so we can have our wicked way with it.
 | 
			
		||||
       */
 | 
			
		||||
      if (number == 10)
 | 
			
		||||
        new_name = g_strdup_printf (_("Workspace 1_0"));
 | 
			
		||||
      else
 | 
			
		||||
        new_name = g_strdup_printf (_("Workspace %s%d"),
 | 
			
		||||
                                    number < 10 ? "_" : "",
 | 
			
		||||
                                    number);
 | 
			
		||||
      return new_name;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /*
 | 
			
		||||
       * Otherwise this is just a normal name. Escape any _ characters so that
 | 
			
		||||
       * the user's workspace names do not get mangled.  If the number is less
 | 
			
		||||
       * than 10 we provide an accelerator.
 | 
			
		||||
       */
 | 
			
		||||
      char *new_name;
 | 
			
		||||
      const char *source;
 | 
			
		||||
      char *dest;
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * Assume the worst case, that every character is a _.  We also
 | 
			
		||||
       * provide memory for " (_#)"
 | 
			
		||||
       */
 | 
			
		||||
      new_name = g_malloc0 (strlen (name) * 2 + 6 + 1);
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * Now iterate down the strings, adding '_' to escape as we go
 | 
			
		||||
       */
 | 
			
		||||
      dest = new_name;
 | 
			
		||||
      source = name;
 | 
			
		||||
      while (*source != '\0')
 | 
			
		||||
        {
 | 
			
		||||
          if (*source == '_')
 | 
			
		||||
            *dest++ = '_';
 | 
			
		||||
          *dest++ = *source++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* People don't start at workspace 0, but workspace 1 */
 | 
			
		||||
      if (index < 9)
 | 
			
		||||
        {
 | 
			
		||||
          g_snprintf (dest, 6, " (_%d)", index + 1);
 | 
			
		||||
        }
 | 
			
		||||
      else if (index == 9)
 | 
			
		||||
        {
 | 
			
		||||
          g_snprintf (dest, 6, " (_0)");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      return new_name;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GtkWidget *
 | 
			
		||||
menu_item_new (MenuItem *menuitem, int workspace_id)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int key;
 | 
			
		||||
  MetaVirtualModifier mods;
 | 
			
		||||
  const char *i18n_label;
 | 
			
		||||
  GtkWidget *mi;
 | 
			
		||||
  GtkWidget *accel_label;
 | 
			
		||||
 | 
			
		||||
  if (menuitem->type == MENU_ITEM_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
      mi = gtk_menu_item_new ();
 | 
			
		||||
    }
 | 
			
		||||
  else if (menuitem->type == MENU_ITEM_CHECKBOX)
 | 
			
		||||
    {
 | 
			
		||||
      mi = gtk_check_menu_item_new ();
 | 
			
		||||
      
 | 
			
		||||
      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
 | 
			
		||||
                                      menuitem->checked);
 | 
			
		||||
    }    
 | 
			
		||||
  else if (menuitem->type == MENU_ITEM_RADIOBUTTON)
 | 
			
		||||
    {
 | 
			
		||||
      mi = gtk_check_menu_item_new ();
 | 
			
		||||
 | 
			
		||||
      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (mi),
 | 
			
		||||
                                             TRUE);
 | 
			
		||||
      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
 | 
			
		||||
                                      menuitem->checked);
 | 
			
		||||
    }
 | 
			
		||||
  else if (menuitem->type == MENU_ITEM_WORKSPACE_LIST)
 | 
			
		||||
    return NULL;
 | 
			
		||||
  else
 | 
			
		||||
    return gtk_separator_menu_item_new ();
 | 
			
		||||
 | 
			
		||||
  i18n_label = _(menuitem->label);
 | 
			
		||||
  meta_core_get_menu_accelerator (menuitem->op, workspace_id, &key, &mods);
 | 
			
		||||
 | 
			
		||||
  accel_label = meta_accel_label_new_with_mnemonic (i18n_label);
 | 
			
		||||
  gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
 | 
			
		||||
 | 
			
		||||
  gtk_container_add (GTK_CONTAINER (mi), accel_label);
 | 
			
		||||
  gtk_widget_show (accel_label);
 | 
			
		||||
 | 
			
		||||
  meta_accel_label_set_accelerator (META_ACCEL_LABEL (accel_label),
 | 
			
		||||
                                    key, mods);
 | 
			
		||||
  
 | 
			
		||||
  return mi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWindowMenu*
 | 
			
		||||
meta_window_menu_new   (MetaFrames         *frames,
 | 
			
		||||
                        MetaMenuOp          ops,
 | 
			
		||||
                        MetaMenuOp          insensitive,
 | 
			
		||||
                        Window              client_xwindow,
 | 
			
		||||
                        unsigned long       active_workspace,
 | 
			
		||||
                        int                 n_workspaces,
 | 
			
		||||
                        MetaWindowMenuFunc  func,
 | 
			
		||||
                        gpointer            data)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
  MetaWindowMenu *menu;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */
 | 
			
		||||
  if (n_workspaces < 2)
 | 
			
		||||
    ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES);
 | 
			
		||||
  else if (n_workspaces == 2) 
 | 
			
		||||
    /* #151183: If we only have two workspaces, disable the menu listing them. */
 | 
			
		||||
    ops &= ~(META_MENU_OP_WORKSPACES);
 | 
			
		||||
  
 | 
			
		||||
  menu = g_new (MetaWindowMenu, 1);
 | 
			
		||||
  menu->frames = frames;
 | 
			
		||||
  menu->client_xwindow = client_xwindow;
 | 
			
		||||
  menu->func = func;
 | 
			
		||||
  menu->data = data;
 | 
			
		||||
  menu->ops = ops;
 | 
			
		||||
  menu->insensitive = insensitive;  
 | 
			
		||||
  
 | 
			
		||||
  menu->menu = gtk_menu_new ();
 | 
			
		||||
 | 
			
		||||
  gtk_menu_set_screen (GTK_MENU (menu->menu),
 | 
			
		||||
                       gtk_widget_get_screen (GTK_WIDGET (frames)));
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++)
 | 
			
		||||
    {
 | 
			
		||||
      MenuItem menuitem = menuitems[i];
 | 
			
		||||
      if (ops & menuitem.op || menuitem.op == 0)
 | 
			
		||||
        {
 | 
			
		||||
          GtkWidget *mi;
 | 
			
		||||
          MenuData *md;
 | 
			
		||||
          unsigned int key;
 | 
			
		||||
          MetaVirtualModifier mods;
 | 
			
		||||
 | 
			
		||||
          mi = menu_item_new (&menuitem, -1);
 | 
			
		||||
 | 
			
		||||
          /* Set the activeness of radiobuttons. */
 | 
			
		||||
          switch (menuitem.op)
 | 
			
		||||
            {
 | 
			
		||||
            case META_MENU_OP_STICK:
 | 
			
		||||
              gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
 | 
			
		||||
                                              active_workspace == 0xFFFFFFFF);
 | 
			
		||||
              break;
 | 
			
		||||
            case META_MENU_OP_UNSTICK:
 | 
			
		||||
              gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
 | 
			
		||||
                                              active_workspace != 0xFFFFFFFF);
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (menuitem.type == MENU_ITEM_WORKSPACE_LIST)
 | 
			
		||||
            {
 | 
			
		||||
              if (ops & META_MENU_OP_WORKSPACES)
 | 
			
		||||
                {
 | 
			
		||||
                  Display *display;
 | 
			
		||||
                  Window xroot;
 | 
			
		||||
                  GdkScreen *screen;
 | 
			
		||||
                  GdkWindow *window;
 | 
			
		||||
                  GtkWidget *submenu;
 | 
			
		||||
                  int j;
 | 
			
		||||
 | 
			
		||||
                  MenuItem to_another_workspace = {
 | 
			
		||||
                    0, MENU_ITEM_NORMAL, FALSE,
 | 
			
		||||
                    N_("Move to Another _Workspace")
 | 
			
		||||
                  };
 | 
			
		||||
 | 
			
		||||
                  meta_verbose ("Creating %d-workspace menu current space %lu\n",
 | 
			
		||||
                      n_workspaces, active_workspace);
 | 
			
		||||
 | 
			
		||||
                  window = gtk_widget_get_window (GTK_WIDGET (frames));
 | 
			
		||||
                  display = GDK_WINDOW_XDISPLAY (window);
 | 
			
		||||
 | 
			
		||||
                  screen = gdk_window_get_screen (window);
 | 
			
		||||
                  xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
 | 
			
		||||
 | 
			
		||||
                  submenu = gtk_menu_new ();
 | 
			
		||||
 | 
			
		||||
                  g_assert (mi==NULL);
 | 
			
		||||
                  mi = menu_item_new (&to_another_workspace, -1);
 | 
			
		||||
                  gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);
 | 
			
		||||
 | 
			
		||||
                  for (j = 0; j < n_workspaces; j++)
 | 
			
		||||
                    {
 | 
			
		||||
                      char *label;
 | 
			
		||||
                      MenuData *md;
 | 
			
		||||
                      unsigned int key;
 | 
			
		||||
                      MetaVirtualModifier mods;
 | 
			
		||||
                      MenuItem moveitem;
 | 
			
		||||
                      GtkWidget *submi;
 | 
			
		||||
 | 
			
		||||
                      meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES,
 | 
			
		||||
                          j + 1,
 | 
			
		||||
                          &key, &mods);
 | 
			
		||||
 | 
			
		||||
                      label = get_workspace_name_with_accel (display, xroot, j);
 | 
			
		||||
 | 
			
		||||
                      moveitem.type = MENU_ITEM_NORMAL;
 | 
			
		||||
                      moveitem.op = META_MENU_OP_WORKSPACES;
 | 
			
		||||
                      moveitem.label = label;
 | 
			
		||||
                      submi = menu_item_new (&moveitem, j + 1);
 | 
			
		||||
 | 
			
		||||
                      g_free (label);
 | 
			
		||||
 | 
			
		||||
                      if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK))
 | 
			
		||||
                        gtk_widget_set_sensitive (submi, FALSE);
 | 
			
		||||
 | 
			
		||||
                      md = g_new (MenuData, 1);
 | 
			
		||||
 | 
			
		||||
                      md->menu = menu;
 | 
			
		||||
                      md->op = META_MENU_OP_WORKSPACES;
 | 
			
		||||
 | 
			
		||||
                      g_object_set_data (G_OBJECT (submi),
 | 
			
		||||
                          "workspace",
 | 
			
		||||
                          GINT_TO_POINTER (j));
 | 
			
		||||
 | 
			
		||||
                      g_signal_connect_data (G_OBJECT (submi),
 | 
			
		||||
                          "activate",
 | 
			
		||||
                          G_CALLBACK (activate_cb),
 | 
			
		||||
                          md,
 | 
			
		||||
                          (GClosureNotify) g_free, 0);
 | 
			
		||||
 | 
			
		||||
                      gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi);
 | 
			
		||||
 | 
			
		||||
                      gtk_widget_show (submi);
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                else
 | 
			
		||||
                  meta_verbose ("not creating workspace menu\n");
 | 
			
		||||
            }
 | 
			
		||||
          else if (menuitem.type != MENU_ITEM_SEPARATOR)
 | 
			
		||||
            {
 | 
			
		||||
              meta_core_get_menu_accelerator (menuitems[i].op, -1,
 | 
			
		||||
                                              &key, &mods);
 | 
			
		||||
 | 
			
		||||
              if (insensitive & menuitem.op)
 | 
			
		||||
                gtk_widget_set_sensitive (mi, FALSE);
 | 
			
		||||
              
 | 
			
		||||
              md = g_new (MenuData, 1);
 | 
			
		||||
              
 | 
			
		||||
              md->menu = menu;
 | 
			
		||||
              md->op = menuitem.op;
 | 
			
		||||
              
 | 
			
		||||
              g_signal_connect_data (G_OBJECT (mi),
 | 
			
		||||
                                     "activate",
 | 
			
		||||
                                     G_CALLBACK (activate_cb),
 | 
			
		||||
                                     md,
 | 
			
		||||
                                     (GClosureNotify) g_free, 0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (mi)
 | 
			
		||||
            {
 | 
			
		||||
              gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi);
 | 
			
		||||
          
 | 
			
		||||
              gtk_widget_show (mi);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
  g_signal_connect (menu->menu, "selection_done",
 | 
			
		||||
                    G_CALLBACK (menu_closed), menu);  
 | 
			
		||||
 | 
			
		||||
  return menu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_menu_popup (MetaWindowMenu     *menu,
 | 
			
		||||
                        int                 root_x,
 | 
			
		||||
                        int                 root_y,
 | 
			
		||||
                        int                 button,
 | 
			
		||||
                        guint32             timestamp)
 | 
			
		||||
{
 | 
			
		||||
  GdkPoint *pt;
 | 
			
		||||
  
 | 
			
		||||
  pt = g_new (GdkPoint, 1);
 | 
			
		||||
 | 
			
		||||
  g_object_set_data_full (G_OBJECT (menu->menu),
 | 
			
		||||
                          "destroy-point",
 | 
			
		||||
                          pt,
 | 
			
		||||
                          g_free);
 | 
			
		||||
 | 
			
		||||
  pt->x = root_x;
 | 
			
		||||
  pt->y = root_y;
 | 
			
		||||
  
 | 
			
		||||
  gtk_menu_popup (GTK_MENU (menu->menu),
 | 
			
		||||
                  NULL, NULL,
 | 
			
		||||
                  popup_position_func, pt,
 | 
			
		||||
                  button,
 | 
			
		||||
                  timestamp);
 | 
			
		||||
 | 
			
		||||
  if (!gtk_widget_get_visible (menu->menu))
 | 
			
		||||
    meta_warning ("GtkMenu failed to grab the pointer\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_menu_free (MetaWindowMenu *menu)
 | 
			
		||||
{
 | 
			
		||||
  gtk_widget_destroy (menu->menu);
 | 
			
		||||
  g_free (menu);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,55 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Mutter window menu */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2001 Havoc Pennington
 | 
			
		||||
 * 
 | 
			
		||||
 * 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_MENU_H
 | 
			
		||||
#define META_MENU_H
 | 
			
		||||
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include "frames.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaWindowMenu
 | 
			
		||||
{
 | 
			
		||||
  MetaFrames *frames;
 | 
			
		||||
  Window client_xwindow;
 | 
			
		||||
  GtkWidget *menu;
 | 
			
		||||
  MetaWindowMenuFunc func;
 | 
			
		||||
  gpointer data;
 | 
			
		||||
  MetaMenuOp ops;
 | 
			
		||||
  MetaMenuOp insensitive;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MetaWindowMenu* meta_window_menu_new      (MetaFrames         *frames,
 | 
			
		||||
                                           MetaMenuOp          ops,
 | 
			
		||||
                                           MetaMenuOp          insensitive,
 | 
			
		||||
                                           Window              client_xwindow,
 | 
			
		||||
                                           unsigned long       active_workspace,
 | 
			
		||||
                                           int                 n_workspaces,
 | 
			
		||||
                                           MetaWindowMenuFunc  func,
 | 
			
		||||
                                           gpointer            data);
 | 
			
		||||
void            meta_window_menu_popup    (MetaWindowMenu     *menu,
 | 
			
		||||
                                           int                 root_x,
 | 
			
		||||
                                           int                 root_y,
 | 
			
		||||
                                           int                 button,
 | 
			
		||||
                                           guint32             timestamp);
 | 
			
		||||
void            meta_window_menu_free     (MetaWindowMenu     *menu);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,451 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Metacity hacked-up GtkAccelLabel */
 | 
			
		||||
/* Copyright (C) 2002 Red Hat, Inc. */
 | 
			
		||||
/* GTK - The GIMP Toolkit
 | 
			
		||||
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 | 
			
		||||
 *
 | 
			
		||||
 * MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
 | 
			
		||||
 * Copyright (C) 1998 Tim Janik
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
 | 
			
		||||
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 | 
			
		||||
 * files for a list of changes.  These files are distributed with
 | 
			
		||||
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#include "metaaccellabel.h"
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "util-private.h"
 | 
			
		||||
 | 
			
		||||
static void     meta_accel_label_destroy      (GtkWidget           *object);
 | 
			
		||||
static void     meta_accel_label_finalize     (GObject             *object);
 | 
			
		||||
static void     meta_accel_label_get_preferred_width  (GtkWidget *widget,
 | 
			
		||||
                                                       gint      *minimum,
 | 
			
		||||
                                                       gint      *natural);
 | 
			
		||||
static void     meta_accel_label_get_preferred_height (GtkWidget *widget,
 | 
			
		||||
                                                       gint      *minimum,
 | 
			
		||||
                                                       gint      *natural);
 | 
			
		||||
static gboolean meta_accel_label_draw         (GtkWidget           *widget,
 | 
			
		||||
                                               cairo_t             *cr);
 | 
			
		||||
 | 
			
		||||
static void  meta_accel_label_update          (MetaAccelLabel *accel_label);
 | 
			
		||||
static int   meta_accel_label_get_accel_width (MetaAccelLabel *accel_label);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaAccelLabel, meta_accel_label, GTK_TYPE_LABEL);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_class_init (MetaAccelLabelClass *class)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 | 
			
		||||
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 | 
			
		||||
 | 
			
		||||
  gobject_class->finalize = meta_accel_label_finalize;
 | 
			
		||||
 | 
			
		||||
  widget_class->destroy = meta_accel_label_destroy;
 | 
			
		||||
 | 
			
		||||
  widget_class->get_preferred_width = meta_accel_label_get_preferred_width;
 | 
			
		||||
  widget_class->get_preferred_height = meta_accel_label_get_preferred_height;
 | 
			
		||||
  widget_class->draw = meta_accel_label_draw;
 | 
			
		||||
 | 
			
		||||
  class->signal_quote1 = g_strdup ("<:");
 | 
			
		||||
  class->signal_quote2 = g_strdup (":>");
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the shift key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_shift = g_strdup (_("Shift"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the control key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_control = g_strdup (_("Ctrl"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the alt key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_alt = g_strdup (_("Alt"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the meta key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_meta = g_strdup (_("Meta"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the super key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_super = g_strdup (_("Super"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the hyper key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_hyper = g_strdup (_("Hyper"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the mod2 key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_mod2 = g_strdup (_("Mod2"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the mod3 key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_mod3 = g_strdup (_("Mod3"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the mod4 key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_mod4 = g_strdup (_("Mod4"));
 | 
			
		||||
  /* This is the text that should appear next to menu accelerators
 | 
			
		||||
   * that use the mod5 key. If the text on this key isn't typically
 | 
			
		||||
   * translated on keyboards used for your language, don't translate
 | 
			
		||||
   * this.
 | 
			
		||||
   */
 | 
			
		||||
  class->mod_name_mod5 = g_strdup (_("Mod5"));
 | 
			
		||||
 | 
			
		||||
  class->mod_separator = g_strdup ("+");
 | 
			
		||||
  class->accel_seperator = g_strdup (" / ");
 | 
			
		||||
  class->latin1_to_char = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_init (MetaAccelLabel *accel_label)
 | 
			
		||||
{
 | 
			
		||||
  accel_label->accel_padding = 3;
 | 
			
		||||
  accel_label->accel_string = NULL;
 | 
			
		||||
 | 
			
		||||
  meta_accel_label_update (accel_label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkWidget*
 | 
			
		||||
meta_accel_label_new_with_mnemonic (const gchar *string)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabel *accel_label;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (string != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL);
 | 
			
		||||
 | 
			
		||||
  gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string);
 | 
			
		||||
 | 
			
		||||
  return GTK_WIDGET (accel_label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_destroy (GtkWidget *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  g_free (accel_label->accel_string);
 | 
			
		||||
  accel_label->accel_string = NULL;
 | 
			
		||||
 | 
			
		||||
  accel_label->accel_mods = 0;
 | 
			
		||||
  accel_label->accel_key = 0;
 | 
			
		||||
 | 
			
		||||
  GTK_WIDGET_CLASS (meta_accel_label_parent_class)->destroy (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
 | 
			
		||||
 | 
			
		||||
  g_free (accel_label->accel_string);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_accel_label_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_accel_label_set_accelerator (MetaAccelLabel         *accel_label,
 | 
			
		||||
                                  guint                   accelerator_key,
 | 
			
		||||
                                  MetaVirtualModifier     accelerator_mods)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
 | 
			
		||||
 | 
			
		||||
  if (accelerator_key != accel_label->accel_key ||
 | 
			
		||||
      accelerator_mods != accel_label->accel_mods)
 | 
			
		||||
    {
 | 
			
		||||
      accel_label->accel_mods = accelerator_mods;
 | 
			
		||||
      accel_label->accel_key = accelerator_key;
 | 
			
		||||
 | 
			
		||||
      meta_accel_label_update (accel_label);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
meta_accel_label_get_accel_width (MetaAccelLabel *accel_label)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0);
 | 
			
		||||
 | 
			
		||||
  return (accel_label->accel_string_width +
 | 
			
		||||
	  (accel_label->accel_string_width ? accel_label->accel_padding : 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_get_preferred_width (GtkWidget *widget,
 | 
			
		||||
                                      gint      *minimum,
 | 
			
		||||
                                      gint      *natural)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
 | 
			
		||||
  PangoLayout *layout;
 | 
			
		||||
  gint width;
 | 
			
		||||
 | 
			
		||||
  GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_width (widget, minimum, natural);
 | 
			
		||||
 | 
			
		||||
  layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
 | 
			
		||||
  pango_layout_get_pixel_size (layout, &width, NULL);
 | 
			
		||||
  accel_label->accel_string_width = width;
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (layout));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_get_preferred_height (GtkWidget *widget,
 | 
			
		||||
                                       gint      *minimum,
 | 
			
		||||
                                       gint      *natural)
 | 
			
		||||
{
 | 
			
		||||
  GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_height (widget, minimum, natural);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Mostly taken from GTK3. */
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_accel_label_draw (GtkWidget *widget,
 | 
			
		||||
                       cairo_t   *cr)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
 | 
			
		||||
  GtkMisc *misc = GTK_MISC (accel_label);
 | 
			
		||||
  GtkTextDirection direction;
 | 
			
		||||
  int ac_width;
 | 
			
		||||
  GtkAllocation allocation;
 | 
			
		||||
  GtkRequisition requisition;
 | 
			
		||||
 | 
			
		||||
  direction = gtk_widget_get_direction (widget);
 | 
			
		||||
  ac_width = meta_accel_label_get_accel_width (accel_label);
 | 
			
		||||
  gtk_widget_get_allocation (widget, &allocation);
 | 
			
		||||
  gtk_widget_get_preferred_size (widget,
 | 
			
		||||
                                 &requisition, NULL);
 | 
			
		||||
 | 
			
		||||
  if (allocation.width >= requisition.width + ac_width)
 | 
			
		||||
    {
 | 
			
		||||
      GtkStyleContext *style;
 | 
			
		||||
      PangoLayout *label_layout;
 | 
			
		||||
      PangoLayout *accel_layout;
 | 
			
		||||
      GtkLabel *label = GTK_LABEL (widget);
 | 
			
		||||
      gint x, y, xpad, ypad;
 | 
			
		||||
      gfloat xalign, yalign;
 | 
			
		||||
 | 
			
		||||
      label_layout = gtk_label_get_layout (GTK_LABEL (accel_label));
 | 
			
		||||
      gtk_misc_get_alignment (misc, &xalign, &yalign);
 | 
			
		||||
 | 
			
		||||
      cairo_save (cr);
 | 
			
		||||
 | 
			
		||||
      /* XXX: Mad hack: We modify the label's width so it renders
 | 
			
		||||
       * properly in its draw function that we chain to. */
 | 
			
		||||
      if (direction == GTK_TEXT_DIR_RTL)
 | 
			
		||||
        cairo_translate (cr, ac_width, 0);
 | 
			
		||||
      if (gtk_label_get_ellipsize (label))
 | 
			
		||||
        pango_layout_set_width (label_layout,
 | 
			
		||||
                                pango_layout_get_width (label_layout) 
 | 
			
		||||
                                - ac_width * PANGO_SCALE);
 | 
			
		||||
      
 | 
			
		||||
      allocation.width -= ac_width;
 | 
			
		||||
      gtk_widget_set_allocation (widget, &allocation);
 | 
			
		||||
      if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
 | 
			
		||||
        GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget,
 | 
			
		||||
                                                               cr);
 | 
			
		||||
      allocation.width += ac_width;
 | 
			
		||||
      gtk_widget_set_allocation (widget, &allocation);
 | 
			
		||||
      if (gtk_label_get_ellipsize (label))
 | 
			
		||||
        pango_layout_set_width (label_layout,
 | 
			
		||||
                                pango_layout_get_width (label_layout) 
 | 
			
		||||
                                + ac_width * PANGO_SCALE);
 | 
			
		||||
 | 
			
		||||
      cairo_restore (cr);
 | 
			
		||||
 | 
			
		||||
      gtk_misc_get_padding (misc, &xpad, &ypad);
 | 
			
		||||
 | 
			
		||||
      if (direction == GTK_TEXT_DIR_RTL)
 | 
			
		||||
        x = xpad;
 | 
			
		||||
      else
 | 
			
		||||
        x = gtk_widget_get_allocated_width (widget) - xpad - ac_width;
 | 
			
		||||
 | 
			
		||||
      gtk_label_get_layout_offsets (GTK_LABEL (accel_label), NULL, &y);
 | 
			
		||||
 | 
			
		||||
      accel_layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
 | 
			
		||||
 | 
			
		||||
      y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 1.5;
 | 
			
		||||
 | 
			
		||||
      style = gtk_widget_get_style_context (widget);
 | 
			
		||||
      gtk_style_context_save (style);
 | 
			
		||||
      gtk_style_context_set_state (style,
 | 
			
		||||
                                   gtk_widget_get_state_flags (widget));
 | 
			
		||||
      gtk_render_layout (gtk_widget_get_style_context (widget),
 | 
			
		||||
                         cr,
 | 
			
		||||
                         x, y,
 | 
			
		||||
                         accel_layout);
 | 
			
		||||
      gtk_style_context_restore (style);
 | 
			
		||||
 | 
			
		||||
      g_object_unref (accel_layout);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
 | 
			
		||||
        GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget, cr);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_accel_label_update (MetaAccelLabel *accel_label)
 | 
			
		||||
{
 | 
			
		||||
  MetaAccelLabelClass *class;
 | 
			
		||||
  GString *gstring;
 | 
			
		||||
  gboolean seen_mod = FALSE;
 | 
			
		||||
  gunichar ch;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
 | 
			
		||||
 | 
			
		||||
  class = META_ACCEL_LABEL_GET_CLASS (accel_label);
 | 
			
		||||
 | 
			
		||||
  g_free (accel_label->accel_string);
 | 
			
		||||
  accel_label->accel_string = NULL;
 | 
			
		||||
 | 
			
		||||
  gstring = g_string_new (accel_label->accel_string);
 | 
			
		||||
  g_string_append (gstring, gstring->len ? class->accel_seperator : "   ");
 | 
			
		||||
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      g_string_append (gstring, class->mod_name_shift);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_control);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_alt);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_META_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_meta);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_super);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_hyper);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_mod2);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_mod3);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_mod4);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK)
 | 
			
		||||
    {
 | 
			
		||||
      if (seen_mod)
 | 
			
		||||
        g_string_append (gstring, class->mod_separator);
 | 
			
		||||
      g_string_append (gstring, class->mod_name_mod5);
 | 
			
		||||
      seen_mod = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (seen_mod)
 | 
			
		||||
    g_string_append (gstring, class->mod_separator);
 | 
			
		||||
 | 
			
		||||
  ch = gdk_keyval_to_unicode (accel_label->accel_key);
 | 
			
		||||
  if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
 | 
			
		||||
      (ch < 0x80 || class->latin1_to_char))
 | 
			
		||||
    {
 | 
			
		||||
      switch (ch)
 | 
			
		||||
        {
 | 
			
		||||
        case ' ':
 | 
			
		||||
          g_string_append (gstring, "Space");
 | 
			
		||||
          break;
 | 
			
		||||
        case '\\':
 | 
			
		||||
          g_string_append (gstring, "Backslash");
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          g_string_append_unichar (gstring, g_unichar_toupper (ch));
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      gchar *tmp;
 | 
			
		||||
 | 
			
		||||
      tmp = gtk_accelerator_name (accel_label->accel_key, 0);
 | 
			
		||||
      if (tmp[0] != 0 && tmp[1] == 0)
 | 
			
		||||
        tmp[0] = g_ascii_toupper (tmp[0]);
 | 
			
		||||
      g_string_append (gstring, tmp);
 | 
			
		||||
      g_free (tmp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (accel_label->accel_string);
 | 
			
		||||
  accel_label->accel_string = gstring->str;
 | 
			
		||||
  g_string_free (gstring, FALSE);
 | 
			
		||||
 | 
			
		||||
  g_assert (accel_label->accel_string);
 | 
			
		||||
  /* accel_label->accel_string = g_strdup ("-/-"); */
 | 
			
		||||
 | 
			
		||||
  gtk_widget_queue_resize (GTK_WIDGET (accel_label));
 | 
			
		||||
}
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Metacity hacked-up GtkAccelLabel */
 | 
			
		||||
/* Copyright (C) 2002 Red Hat, Inc. */
 | 
			
		||||
/* GTK - The GIMP Toolkit
 | 
			
		||||
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 | 
			
		||||
 *
 | 
			
		||||
 * MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
 | 
			
		||||
 * Copyright (C) 1998 Tim Janik
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
 | 
			
		||||
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 | 
			
		||||
 * files for a list of changes.  These files are distributed with
 | 
			
		||||
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __META_ACCEL_LABEL_H__
 | 
			
		||||
#define __META_ACCEL_LABEL_H__
 | 
			
		||||
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include <meta/common.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif /* __cplusplus */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_ACCEL_LABEL		(meta_accel_label_get_type ())
 | 
			
		||||
#define META_ACCEL_LABEL(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabel))
 | 
			
		||||
#define META_ACCEL_LABEL_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
 | 
			
		||||
#define META_IS_ACCEL_LABEL(obj)	 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_ACCEL_LABEL))
 | 
			
		||||
#define META_IS_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_ACCEL_LABEL))
 | 
			
		||||
#define META_ACCEL_LABEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaAccelLabel	    MetaAccelLabel;
 | 
			
		||||
typedef struct _MetaAccelLabelClass  MetaAccelLabelClass;
 | 
			
		||||
 | 
			
		||||
struct _MetaAccelLabel
 | 
			
		||||
{
 | 
			
		||||
  GtkLabel label;
 | 
			
		||||
 | 
			
		||||
  MetaVirtualModifier accel_mods;
 | 
			
		||||
  guint accel_key;
 | 
			
		||||
  guint accel_padding;
 | 
			
		||||
  gchar *accel_string;
 | 
			
		||||
  guint16 accel_string_width;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaAccelLabelClass
 | 
			
		||||
{
 | 
			
		||||
  GtkLabelClass	 parent_class;
 | 
			
		||||
 | 
			
		||||
  gchar		*signal_quote1;
 | 
			
		||||
  gchar		*signal_quote2;
 | 
			
		||||
  gchar		*mod_name_shift;
 | 
			
		||||
  gchar		*mod_name_control;
 | 
			
		||||
  gchar		*mod_name_alt;
 | 
			
		||||
  gchar		*mod_name_meta;
 | 
			
		||||
  gchar		*mod_name_super;
 | 
			
		||||
  gchar		*mod_name_hyper;
 | 
			
		||||
  gchar		*mod_name_mod2;
 | 
			
		||||
  gchar		*mod_name_mod3;
 | 
			
		||||
  gchar		*mod_name_mod4;
 | 
			
		||||
  gchar		*mod_name_mod5;
 | 
			
		||||
  gchar		*mod_separator;
 | 
			
		||||
  gchar		*accel_seperator;
 | 
			
		||||
  guint		 latin1_to_char : 1;
 | 
			
		||||
 | 
			
		||||
  /* Padding for future expansion */
 | 
			
		||||
  void (*_gtk_reserved1) (void);
 | 
			
		||||
  void (*_gtk_reserved2) (void);
 | 
			
		||||
  void (*_gtk_reserved3) (void);
 | 
			
		||||
  void (*_gtk_reserved4) (void);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType	   meta_accel_label_get_type          (void) G_GNUC_CONST;
 | 
			
		||||
GtkWidget* meta_accel_label_new_with_mnemonic (const gchar            *string);
 | 
			
		||||
void       meta_accel_label_set_accelerator   (MetaAccelLabel         *accel_label,
 | 
			
		||||
                                               guint                   accelerator_key,
 | 
			
		||||
                                               MetaVirtualModifier     accelerator_mods);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif /* __cplusplus */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* __META_ACCEL_LABEL_H__ */
 | 
			
		||||
							
								
								
									
										34
									
								
								src/ui/ui.c
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/ui/ui.c
									
									
									
									
									
								
							@@ -514,40 +514,6 @@ meta_ui_set_frame_title (MetaUI     *ui,
 | 
			
		||||
  meta_frames_set_title (ui->frames, xwindow, title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWindowMenu*
 | 
			
		||||
meta_ui_window_menu_new  (MetaUI             *ui,
 | 
			
		||||
                          Window              client_xwindow,
 | 
			
		||||
                          MetaMenuOp          ops,
 | 
			
		||||
                          MetaMenuOp          insensitive,
 | 
			
		||||
                          unsigned long       active_workspace,
 | 
			
		||||
                          int                 n_workspaces,
 | 
			
		||||
                          MetaWindowMenuFunc  func,
 | 
			
		||||
                          gpointer            data)
 | 
			
		||||
{
 | 
			
		||||
  return meta_window_menu_new (ui->frames,
 | 
			
		||||
                               ops, insensitive,
 | 
			
		||||
                               client_xwindow,
 | 
			
		||||
                               active_workspace,
 | 
			
		||||
                               n_workspaces,
 | 
			
		||||
                               func, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_ui_window_menu_popup (MetaWindowMenu     *menu,
 | 
			
		||||
                           int                 root_x,
 | 
			
		||||
                           int                 root_y,
 | 
			
		||||
                           int                 button,
 | 
			
		||||
                           guint32             timestamp)
 | 
			
		||||
{
 | 
			
		||||
  meta_window_menu_popup (menu, root_x, root_y, button, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_ui_window_menu_free (MetaWindowMenu *menu)
 | 
			
		||||
{
 | 
			
		||||
  meta_window_menu_free (menu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GdkPixbuf*
 | 
			
		||||
meta_gdk_pixbuf_get_from_pixmap (Pixmap       xpixmap,
 | 
			
		||||
                                 int          src_x,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								src/ui/ui.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/ui/ui.h
									
									
									
									
									
								
							@@ -120,21 +120,6 @@ void meta_ui_update_frame_style (MetaUI  *ui,
 | 
			
		||||
void meta_ui_repaint_frame (MetaUI *ui,
 | 
			
		||||
                            Window xwindow);
 | 
			
		||||
 | 
			
		||||
MetaWindowMenu* meta_ui_window_menu_new   (MetaUI             *ui,
 | 
			
		||||
                                           Window              client_xwindow,
 | 
			
		||||
                                           MetaMenuOp          ops,
 | 
			
		||||
                                           MetaMenuOp          insensitive,
 | 
			
		||||
                                           unsigned long       active_workspace,
 | 
			
		||||
                                           int                 n_workspaces,
 | 
			
		||||
                                           MetaWindowMenuFunc  func,
 | 
			
		||||
                                           gpointer            data);
 | 
			
		||||
void            meta_ui_window_menu_popup (MetaWindowMenu     *menu,
 | 
			
		||||
                                           int                 root_x,
 | 
			
		||||
                                           int                 root_y,
 | 
			
		||||
                                           int                 button,
 | 
			
		||||
                                           guint32             timestamp);
 | 
			
		||||
void            meta_ui_window_menu_free  (MetaWindowMenu     *menu);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* FIXME these lack a display arg */
 | 
			
		||||
GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap       xpixmap,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										441
									
								
								src/wayland/meta-login1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										441
									
								
								src/wayland/meta-login1.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,441 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-login1.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-dbus-login1.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
 | 
			
		||||
#include <gio/gunixfdlist.h>
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <clutter/evdev/clutter-evdev.h>
 | 
			
		||||
#include <clutter/egl/clutter-egl.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <systemd/sd-login.h>
 | 
			
		||||
 | 
			
		||||
struct _MetaLogin1
 | 
			
		||||
{
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
  Login1Seat *seat_proxy;
 | 
			
		||||
 | 
			
		||||
  gboolean session_active;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Stolen from tp_escape_as_identifier, from tp-glib,
 | 
			
		||||
 * which follows the same escaping convention as systemd.
 | 
			
		||||
 */
 | 
			
		||||
static inline gboolean
 | 
			
		||||
_esc_ident_bad (gchar c, gboolean is_first)
 | 
			
		||||
{
 | 
			
		||||
  return ((c < 'a' || c > 'z') &&
 | 
			
		||||
          (c < 'A' || c > 'Z') &&
 | 
			
		||||
          (c < '0' || c > '9' || is_first));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gchar *
 | 
			
		||||
escape_dbus_component (const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
  gboolean bad = FALSE;
 | 
			
		||||
  size_t len = 0;
 | 
			
		||||
  GString *op;
 | 
			
		||||
  const gchar *ptr, *first_ok;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (name != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  /* fast path for empty name */
 | 
			
		||||
  if (name[0] == '\0')
 | 
			
		||||
    return g_strdup ("_");
 | 
			
		||||
 | 
			
		||||
  for (ptr = name; *ptr; ptr++)
 | 
			
		||||
    {
 | 
			
		||||
      if (_esc_ident_bad (*ptr, ptr == name))
 | 
			
		||||
        {
 | 
			
		||||
          bad = TRUE;
 | 
			
		||||
          len += 3;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        len++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* fast path if it's clean */
 | 
			
		||||
  if (!bad)
 | 
			
		||||
    return g_strdup (name);
 | 
			
		||||
 | 
			
		||||
  /* If strictly less than ptr, first_ok is the first uncopied safe character.
 | 
			
		||||
   */
 | 
			
		||||
  first_ok = name;
 | 
			
		||||
  op = g_string_sized_new (len);
 | 
			
		||||
  for (ptr = name; *ptr; ptr++)
 | 
			
		||||
    {
 | 
			
		||||
      if (_esc_ident_bad (*ptr, ptr == name))
 | 
			
		||||
        {
 | 
			
		||||
          /* copy preceding safe characters if any */
 | 
			
		||||
          if (first_ok < ptr)
 | 
			
		||||
            {
 | 
			
		||||
              g_string_append_len (op, first_ok, ptr - first_ok);
 | 
			
		||||
            }
 | 
			
		||||
          /* escape the unsafe character */
 | 
			
		||||
          g_string_append_printf (op, "_%02x", (unsigned char)(*ptr));
 | 
			
		||||
          /* restart after it */
 | 
			
		||||
          first_ok = ptr + 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  /* copy trailing safe characters if any */
 | 
			
		||||
  if (first_ok < ptr)
 | 
			
		||||
    {
 | 
			
		||||
      g_string_append_len (op, first_ok, ptr - first_ok);
 | 
			
		||||
    }
 | 
			
		||||
  return g_string_free (op, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
get_escaped_dbus_path (const char *prefix,
 | 
			
		||||
                       const char *component)
 | 
			
		||||
{
 | 
			
		||||
  char *escaped_component = escape_dbus_component (component);
 | 
			
		||||
  char *path = g_strconcat (prefix, "/", component, NULL);
 | 
			
		||||
 | 
			
		||||
  g_free (escaped_component);
 | 
			
		||||
  return path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Login1Session *
 | 
			
		||||
get_session_proxy (GCancellable *cancellable)
 | 
			
		||||
{
 | 
			
		||||
  char *proxy_path;
 | 
			
		||||
  char *session_id;
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
 | 
			
		||||
  if (sd_pid_get_session (getpid (), &session_id) < 0)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
 | 
			
		||||
 | 
			
		||||
  session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 | 
			
		||||
                                                         G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 | 
			
		||||
                                                         "org.freedesktop.login1",
 | 
			
		||||
                                                         proxy_path,
 | 
			
		||||
                                                         cancellable, NULL);
 | 
			
		||||
  free (proxy_path);
 | 
			
		||||
 | 
			
		||||
  return session_proxy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Login1Seat *
 | 
			
		||||
get_seat_proxy (GCancellable *cancellable)
 | 
			
		||||
{
 | 
			
		||||
  return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 | 
			
		||||
                                             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 | 
			
		||||
                                             "org.freedesktop.login1",
 | 
			
		||||
                                             "/org/freedesktop/login1/seat/self",
 | 
			
		||||
                                             cancellable, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
session_unpause (void)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  CoglDisplay *cogl_display;
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  cogl_display = cogl_context_get_display (cogl_context);
 | 
			
		||||
  cogl_kms_display_queue_modes_reset (cogl_display);
 | 
			
		||||
 | 
			
		||||
  clutter_set_paused (FALSE);
 | 
			
		||||
  /* clutter_evdev_reclaim_devices (); */
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
 | 
			
		||||
    /* When we mode-switch back, we need to immediately queue a redraw
 | 
			
		||||
     * in case nothing else quueed one for us, and force the cursor to
 | 
			
		||||
     * update. */
 | 
			
		||||
 | 
			
		||||
    clutter_actor_queue_redraw (compositor->stage);
 | 
			
		||||
    meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
session_pause (void)
 | 
			
		||||
{
 | 
			
		||||
  clutter_set_paused (TRUE);
 | 
			
		||||
  /* clutter_evdev_release_devices (); */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sync_active (MetaLogin1 *self)
 | 
			
		||||
{
 | 
			
		||||
  gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
 | 
			
		||||
 | 
			
		||||
  if (active == self->session_active)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->session_active = active;
 | 
			
		||||
 | 
			
		||||
  if (active)
 | 
			
		||||
    session_unpause ();
 | 
			
		||||
  else
 | 
			
		||||
    session_pause ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_active_changed (Login1Session *session,
 | 
			
		||||
                   GParamSpec    *pspec,
 | 
			
		||||
                   gpointer       user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaLogin1 *self = user_data;
 | 
			
		||||
  sync_active (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
take_device (Login1Session *session_proxy,
 | 
			
		||||
             int            dev_major,
 | 
			
		||||
             int            dev_minor,
 | 
			
		||||
             int           *out_fd,
 | 
			
		||||
             GCancellable  *cancellable,
 | 
			
		||||
             GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
  GVariant *fd_variant = NULL;
 | 
			
		||||
  int fd = -1;
 | 
			
		||||
  GUnixFDList *fd_list;
 | 
			
		||||
 | 
			
		||||
  if (!login1_session_call_take_device_sync (session_proxy,
 | 
			
		||||
                                             dev_major,
 | 
			
		||||
                                             dev_minor,
 | 
			
		||||
                                             NULL,
 | 
			
		||||
                                             &fd_variant,
 | 
			
		||||
                                             NULL, /* paused */
 | 
			
		||||
                                             &fd_list,
 | 
			
		||||
                                             cancellable,
 | 
			
		||||
                                             error))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
 | 
			
		||||
  if (fd == -1)
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  *out_fd = fd;
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  if (fd_variant)
 | 
			
		||||
    g_variant_unref (fd_variant);
 | 
			
		||||
  if (fd_list)
 | 
			
		||||
    g_object_unref (fd_list);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
get_device_info_from_path (const char *path,
 | 
			
		||||
                           int        *out_major,
 | 
			
		||||
                           int        *out_minor)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
  int r;
 | 
			
		||||
  struct stat st;
 | 
			
		||||
 | 
			
		||||
  r = stat (path, &st);
 | 
			
		||||
  if (r < 0)
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!S_ISCHR (st.st_mode))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  *out_major = major (st.st_rdev);
 | 
			
		||||
  *out_minor = minor (st.st_rdev);
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
get_device_info_from_fd (int  fd,
 | 
			
		||||
                         int *out_major,
 | 
			
		||||
                         int *out_minor)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
  int r;
 | 
			
		||||
  struct stat st;
 | 
			
		||||
 | 
			
		||||
  r = fstat (fd, &st);
 | 
			
		||||
  if (r < 0)
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!S_ISCHR (st.st_mode))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  *out_major = major (st.st_rdev);
 | 
			
		||||
  *out_minor = minor (st.st_rdev);
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
open_evdev_device (const char  *path,
 | 
			
		||||
                   int          flags,
 | 
			
		||||
                   gpointer     user_data,
 | 
			
		||||
                   GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaLogin1 *self = user_data;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int major, minor;
 | 
			
		||||
 | 
			
		||||
  if (!get_device_info_from_path (path, &major, &minor))
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "Could not get device info for path %s: %m", path);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
close_evdev_device (int      fd,
 | 
			
		||||
                    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaLogin1 *self = user_data;
 | 
			
		||||
  int major, minor;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!get_device_info_from_fd (fd, &major, &minor))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not get device info for fd %d: %m", fd);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!login1_session_call_release_device_sync (self->session_proxy,
 | 
			
		||||
                                                major, minor,
 | 
			
		||||
                                                NULL, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
get_kms_fd (Login1Session *session_proxy,
 | 
			
		||||
            int *fd_out)
 | 
			
		||||
{
 | 
			
		||||
  int major, minor;
 | 
			
		||||
  int fd;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  /* XXX -- use udev to find the DRM master device */
 | 
			
		||||
  if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not stat /dev/dri/card0: %m");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not open DRM device: %s\n", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *fd_out = fd;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaLogin1 *
 | 
			
		||||
meta_login1_new (void)
 | 
			
		||||
{
 | 
			
		||||
  MetaLogin1 *self;
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
 | 
			
		||||
  session_proxy = get_session_proxy (NULL);
 | 
			
		||||
  if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not take control: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!get_kms_fd (session_proxy, &kms_fd))
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  self = g_slice_new0 (MetaLogin1);
 | 
			
		||||
  self->session_proxy = session_proxy;
 | 
			
		||||
  self->seat_proxy = get_seat_proxy (NULL);
 | 
			
		||||
 | 
			
		||||
  /* Clutter/Cogl start out in a state that assumes the session is active */
 | 
			
		||||
  self->session_active = TRUE;
 | 
			
		||||
 | 
			
		||||
  clutter_egl_set_kms_fd (kms_fd);
 | 
			
		||||
  clutter_evdev_set_device_callbacks (open_evdev_device,
 | 
			
		||||
                                      close_evdev_device,
 | 
			
		||||
                                      self);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
 | 
			
		||||
  sync_active (self);
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_login1_free (MetaLogin1 *self)
 | 
			
		||||
{
 | 
			
		||||
  g_object_unref (self->seat_proxy);
 | 
			
		||||
  g_object_unref (self->session_proxy);
 | 
			
		||||
  g_slice_free (MetaLogin1, self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_login1_activate_session (MetaLogin1  *self,
 | 
			
		||||
                              GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  if (!login1_session_call_activate_sync (self->session_proxy, NULL, error))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  sync_active (self);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_login1_activate_vt (MetaLogin1  *self,
 | 
			
		||||
                         int          vt,
 | 
			
		||||
                         GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  return login1_seat_call_switch_to_sync (self->seat_proxy, vt, NULL, error);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 Red Hat, Inc.
 | 
			
		||||
 * 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
 | 
			
		||||
@@ -17,22 +17,19 @@
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_WESTON_LAUNCH_H
 | 
			
		||||
#define META_WESTON_LAUNCH_H
 | 
			
		||||
#ifndef META_LOGIN1_H
 | 
			
		||||
#define META_LOGIN1_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include "weston-launch.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaLauncher MetaLauncher;
 | 
			
		||||
typedef struct _MetaLogin1 MetaLogin1;
 | 
			
		||||
 | 
			
		||||
MetaLauncher     *meta_launcher_new                     (void);
 | 
			
		||||
void              meta_launcher_free                    (MetaLauncher  *self);
 | 
			
		||||
MetaLogin1 *meta_login1_new              (void);
 | 
			
		||||
void        meta_login1_free             (MetaLogin1  *self);
 | 
			
		||||
gboolean    meta_login1_activate_session (MetaLogin1  *self,
 | 
			
		||||
                                          GError     **error);
 | 
			
		||||
gboolean    meta_login1_activate_vt      (MetaLogin1  *self,
 | 
			
		||||
                                          int          vt,
 | 
			
		||||
                                          GError     **error);
 | 
			
		||||
 | 
			
		||||
gboolean          meta_launcher_activate_vt             (MetaLauncher  *self,
 | 
			
		||||
							 signed char    vt,
 | 
			
		||||
							 GError       **error);
 | 
			
		||||
 | 
			
		||||
gboolean          meta_launcher_set_drm_fd              (MetaLauncher  *self,
 | 
			
		||||
							 int            drm_fd,
 | 
			
		||||
							 GError       **error);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
#include <cairo.h>
 | 
			
		||||
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
#include "meta-weston-launch.h"
 | 
			
		||||
#include "meta-login1.h"
 | 
			
		||||
#include <meta/meta-cursor-tracker.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland.h"
 | 
			
		||||
@@ -85,7 +85,7 @@ struct _MetaWaylandCompositor
 | 
			
		||||
 | 
			
		||||
  MetaXWaylandManager xwayland_manager;
 | 
			
		||||
 | 
			
		||||
  MetaLauncher *launcher;
 | 
			
		||||
  MetaLogin1 *login1;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandSeat *seat;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -749,6 +749,49 @@ xdg_surface_set_app_id (struct wl_client *client,
 | 
			
		||||
  meta_window_set_wm_class (surface->window, app_id, app_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWindowType
 | 
			
		||||
window_type_from_surface_type (uint32_t surface_type)
 | 
			
		||||
{
 | 
			
		||||
  switch (surface_type)
 | 
			
		||||
    {
 | 
			
		||||
    case XDG_SURFACE_SURFACE_TYPE_NORMAL:
 | 
			
		||||
      return META_WINDOW_NORMAL;
 | 
			
		||||
    case XDG_SURFACE_SURFACE_TYPE_MODAL_DIALOG:
 | 
			
		||||
      return META_WINDOW_MODAL_DIALOG;
 | 
			
		||||
    default:
 | 
			
		||||
      g_warning ("Unknown surface type: %d\n", surface_type);
 | 
			
		||||
      return META_WINDOW_NORMAL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
xdg_surface_set_surface_type (struct wl_client *client,
 | 
			
		||||
                              struct wl_resource *resource,
 | 
			
		||||
                              uint32_t surface_type)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  meta_window_set_type (surface->window,
 | 
			
		||||
                        window_type_from_surface_type (surface_type));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
xdg_surface_show_window_menu (struct wl_client *client,
 | 
			
		||||
                              struct wl_resource *resource,
 | 
			
		||||
                              struct wl_resource *seat_resource,
 | 
			
		||||
                              uint32_t serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (seat->pointer.button_count == 0 ||
 | 
			
		||||
      seat->pointer.grab_serial != serial ||
 | 
			
		||||
      seat->pointer.focus_surface != surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_window_show_menu (surface->window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
begin_grab_op_on_surface (MetaWaylandSurface *surface,
 | 
			
		||||
                          MetaWaylandSeat    *seat,
 | 
			
		||||
@@ -857,9 +900,9 @@ xdg_surface_request_change_state (struct wl_client *client,
 | 
			
		||||
    {
 | 
			
		||||
    case XDG_SURFACE_STATE_MAXIMIZED:
 | 
			
		||||
      if (value)
 | 
			
		||||
        meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
        meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      else
 | 
			
		||||
        meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
 | 
			
		||||
        meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
 | 
			
		||||
      break;
 | 
			
		||||
    case XDG_SURFACE_STATE_FULLSCREEN:
 | 
			
		||||
      if (value)
 | 
			
		||||
@@ -898,6 +941,8 @@ static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
 | 
			
		||||
  xdg_surface_set_margin,
 | 
			
		||||
  xdg_surface_set_title,
 | 
			
		||||
  xdg_surface_set_app_id,
 | 
			
		||||
  xdg_surface_set_surface_type,
 | 
			
		||||
  xdg_surface_show_window_menu,
 | 
			
		||||
  xdg_surface_move,
 | 
			
		||||
  xdg_surface_resize,
 | 
			
		||||
  xdg_surface_set_output,
 | 
			
		||||
@@ -1153,9 +1198,9 @@ wl_shell_surface_set_state (MetaWaylandSurface *surface,
 | 
			
		||||
    meta_window_unmake_fullscreen (surface->window);
 | 
			
		||||
 | 
			
		||||
  if (state == SURFACE_STATE_MAXIMIZED)
 | 
			
		||||
    meta_window_maximize (surface->window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
    meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
 | 
			
		||||
  else
 | 
			
		||||
    meta_window_unmaximize (surface->window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL);
 | 
			
		||||
    meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include "frame.h"
 | 
			
		||||
#include "meta-idle-monitor-private.h"
 | 
			
		||||
#include "meta-weston-launch.h"
 | 
			
		||||
#include "meta-login1.h"
 | 
			
		||||
#include "monitor-private.h"
 | 
			
		||||
 | 
			
		||||
static MetaWaylandCompositor _meta_wayland_compositor;
 | 
			
		||||
@@ -644,26 +644,15 @@ meta_wayland_init (void)
 | 
			
		||||
  clutter_wayland_set_compositor_display (compositor->wayland_display);
 | 
			
		||||
 | 
			
		||||
  /* If we're running on bare metal, we're a display server,
 | 
			
		||||
   * so start talking to weston-launch. */
 | 
			
		||||
   * so start talking to logind. */
 | 
			
		||||
#if defined(CLUTTER_WINDOWING_EGL)
 | 
			
		||||
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
 | 
			
		||||
    compositor->launcher = meta_launcher_new ();
 | 
			
		||||
    compositor->login1 = meta_login1_new ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
 | 
			
		||||
    g_error ("Failed to initialize Clutter");
 | 
			
		||||
 | 
			
		||||
#if defined(CLUTTER_WINDOWING_EGL)
 | 
			
		||||
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
 | 
			
		||||
    {
 | 
			
		||||
      ClutterBackend *backend = clutter_get_default_backend ();
 | 
			
		||||
      CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
      CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
 | 
			
		||||
      int drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
 | 
			
		||||
      meta_launcher_set_drm_fd (compositor->launcher, drm_fd, NULL);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_initialize ();
 | 
			
		||||
  monitors = meta_monitor_manager_get ();
 | 
			
		||||
  g_signal_connect (monitors, "monitors-changed",
 | 
			
		||||
@@ -715,8 +704,8 @@ meta_wayland_finalize (void)
 | 
			
		||||
 | 
			
		||||
  meta_xwayland_stop (&compositor->xwayland_manager);
 | 
			
		||||
 | 
			
		||||
  if (compositor->launcher)
 | 
			
		||||
    meta_launcher_free (compositor->launcher);
 | 
			
		||||
  if (compositor->login1)
 | 
			
		||||
    meta_login1_free (compositor->login1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -724,9 +713,9 @@ meta_wayland_compositor_activate_vt (MetaWaylandCompositor  *compositor,
 | 
			
		||||
                                     int                     vt,
 | 
			
		||||
                                     GError                **error)
 | 
			
		||||
{
 | 
			
		||||
  if (compositor->launcher)
 | 
			
		||||
  if (compositor->login1)
 | 
			
		||||
    {
 | 
			
		||||
      return meta_launcher_activate_vt (compositor->launcher, vt, error);
 | 
			
		||||
      return meta_login1_activate_vt (compositor->login1, vt, error);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
@@ -739,9 +728,9 @@ gboolean
 | 
			
		||||
meta_wayland_compositor_activate_session (MetaWaylandCompositor  *compositor,
 | 
			
		||||
                                          GError                **error)
 | 
			
		||||
{
 | 
			
		||||
  if (compositor->launcher)
 | 
			
		||||
  if (compositor->login1)
 | 
			
		||||
    {
 | 
			
		||||
      return meta_launcher_activate_vt (compositor->launcher, -1, error);
 | 
			
		||||
      return meta_login1_activate_session (compositor->login1, error);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,423 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <gio/gunixfdmessage.h>
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <clutter/evdev/clutter-evdev.h>
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
 | 
			
		||||
#include <drm.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
#include "meta-weston-launch.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaLauncher
 | 
			
		||||
{
 | 
			
		||||
  GSocket *weston_launch;
 | 
			
		||||
 | 
			
		||||
  gboolean vt_switched;
 | 
			
		||||
 | 
			
		||||
  GMainContext *nested_context;
 | 
			
		||||
  GMainLoop *nested_loop;
 | 
			
		||||
 | 
			
		||||
  GSource *inner_source;
 | 
			
		||||
  GSource *outer_source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_request_vt_switch (MetaLauncher *self);
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
request_vt_switch_idle (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  handle_request_vt_switch (user_data);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
send_message_to_wl (MetaLauncher           *self,
 | 
			
		||||
		    void                   *message,
 | 
			
		||||
		    gsize                   size,
 | 
			
		||||
		    GSocketControlMessage  *out_cmsg,
 | 
			
		||||
		    GSocketControlMessage **in_cmsg,
 | 
			
		||||
		    GError                **error)
 | 
			
		||||
{
 | 
			
		||||
  struct weston_launcher_reply reply;
 | 
			
		||||
  GInputVector in_iov = { &reply, sizeof (reply) };
 | 
			
		||||
  GOutputVector out_iov = { message, size };
 | 
			
		||||
  GSocketControlMessage *out_all_cmsg[2];
 | 
			
		||||
  GSocketControlMessage **in_all_cmsg;
 | 
			
		||||
  int flags = 0;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  out_all_cmsg[0] = out_cmsg;
 | 
			
		||||
  out_all_cmsg[1] = NULL;
 | 
			
		||||
  if (g_socket_send_message (self->weston_launch, NULL,
 | 
			
		||||
			     &out_iov, 1,
 | 
			
		||||
			     out_all_cmsg, -1,
 | 
			
		||||
			     flags, NULL, error) != (gssize)size)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (g_socket_receive_message (self->weston_launch, NULL,
 | 
			
		||||
				&in_iov, 1,
 | 
			
		||||
			        &in_all_cmsg, NULL,
 | 
			
		||||
				&flags, NULL, error) != sizeof (reply))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
 | 
			
		||||
    {
 | 
			
		||||
      /* There were events queued */
 | 
			
		||||
      g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
 | 
			
		||||
 | 
			
		||||
      /* This can never happen, because the only time mutter-launch can queue
 | 
			
		||||
         this event is after confirming a VT switch, and we don't make requests
 | 
			
		||||
         during that time.
 | 
			
		||||
 | 
			
		||||
         Note that getting this event would be really bad, because we would be
 | 
			
		||||
         in the wrong loop/context.
 | 
			
		||||
      */
 | 
			
		||||
      g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
 | 
			
		||||
 | 
			
		||||
      switch (reply.header.opcode)
 | 
			
		||||
	{
 | 
			
		||||
	case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
 | 
			
		||||
	  g_idle_add (request_vt_switch_idle, self);
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
	  g_assert_not_reached ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      if (g_socket_receive_message (self->weston_launch, NULL,
 | 
			
		||||
				    &in_iov, 1,
 | 
			
		||||
				    NULL, NULL,
 | 
			
		||||
				    &flags, NULL, error) != sizeof (reply))
 | 
			
		||||
	return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (reply.ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (reply.ret == -1)
 | 
			
		||||
	g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 | 
			
		||||
		     "Got failure from weston-launch");
 | 
			
		||||
      else
 | 
			
		||||
	g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
 | 
			
		||||
		     "Got failure from weston-launch: %s", strerror (-reply.ret));
 | 
			
		||||
 | 
			
		||||
      for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
 | 
			
		||||
	g_object_unref (in_all_cmsg[i]);
 | 
			
		||||
      g_free (in_all_cmsg);
 | 
			
		||||
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (in_all_cmsg && in_all_cmsg[0])
 | 
			
		||||
    {
 | 
			
		||||
      for (i = 1; in_all_cmsg[i]; i++)
 | 
			
		||||
	g_object_unref (in_all_cmsg[i]);
 | 
			
		||||
      *in_cmsg = in_all_cmsg[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (in_all_cmsg);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_launcher_set_drm_fd (MetaLauncher  *self,
 | 
			
		||||
			  int            drm_fd,
 | 
			
		||||
			  GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  struct weston_launcher_message message;
 | 
			
		||||
  GSocketControlMessage *cmsg;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  message.opcode = WESTON_LAUNCHER_DRM_SET_FD;
 | 
			
		||||
 | 
			
		||||
  cmsg = g_unix_fd_message_new ();
 | 
			
		||||
  if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
 | 
			
		||||
				   drm_fd, error) == FALSE)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (cmsg);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ok = send_message_to_wl (self, &message, sizeof message, cmsg, NULL, error);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (cmsg);
 | 
			
		||||
  return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
meta_launcher_open_input_device (MetaLauncher  *self,
 | 
			
		||||
                                 const char    *name,
 | 
			
		||||
                                 int            flags,
 | 
			
		||||
                                 GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  struct weston_launcher_open *message;
 | 
			
		||||
  GSocketControlMessage *cmsg;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
  gsize size;
 | 
			
		||||
  int *fds, n_fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
 | 
			
		||||
  message = g_malloc (size);
 | 
			
		||||
  message->header.opcode = WESTON_LAUNCHER_OPEN;
 | 
			
		||||
  message->flags = flags;
 | 
			
		||||
  strcpy (message->path, name);
 | 
			
		||||
  message->path[strlen(name)] = 0;
 | 
			
		||||
 | 
			
		||||
  ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
 | 
			
		||||
 | 
			
		||||
  if (ok)
 | 
			
		||||
    {
 | 
			
		||||
      g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
 | 
			
		||||
 | 
			
		||||
      fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
 | 
			
		||||
      g_assert (n_fd == 1);
 | 
			
		||||
 | 
			
		||||
      ret = fds[0];
 | 
			
		||||
      g_free (fds);
 | 
			
		||||
      g_object_unref (cmsg);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    ret = -1;
 | 
			
		||||
 | 
			
		||||
  g_free (message);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_launcher_enter (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  CoglDisplay *cogl_display;
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  cogl_display = cogl_context_get_display (cogl_context);
 | 
			
		||||
  cogl_kms_display_queue_modes_reset (cogl_display);
 | 
			
		||||
 | 
			
		||||
  clutter_evdev_reclaim_devices ();
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
 | 
			
		||||
    /* When we mode-switch back, we need to immediately queue a redraw
 | 
			
		||||
     * in case nothing else queued one for us, and force the cursor to
 | 
			
		||||
     * update. */
 | 
			
		||||
 | 
			
		||||
    clutter_actor_queue_redraw (compositor->stage);
 | 
			
		||||
    meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_launcher_leave (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  clutter_evdev_release_devices ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
on_evdev_device_open (const char  *path,
 | 
			
		||||
		      int          flags,
 | 
			
		||||
		      gpointer     user_data,
 | 
			
		||||
		      GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *launcher = user_data;
 | 
			
		||||
 | 
			
		||||
  return meta_launcher_open_input_device (launcher, path, flags, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_evdev_device_close (int          fd,
 | 
			
		||||
                       gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  close (fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_vt_enter (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (launcher->vt_switched);
 | 
			
		||||
 | 
			
		||||
  g_main_loop_quit (launcher->nested_loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_request_vt_switch (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  struct weston_launcher_message message;
 | 
			
		||||
  GError *error;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  meta_launcher_leave (launcher);
 | 
			
		||||
 | 
			
		||||
  message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
 | 
			
		||||
  if (!ok) {
 | 
			
		||||
    g_warning ("Failed to acknowledge VT switch: %s", error->message);
 | 
			
		||||
    g_error_free (error);
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  g_assert (!launcher->vt_switched);
 | 
			
		||||
  launcher->vt_switched = TRUE;
 | 
			
		||||
 | 
			
		||||
  /* We can't do anything at this point, because we don't
 | 
			
		||||
     have input devices and we don't have the DRM master,
 | 
			
		||||
     so let's run a nested busy loop until the VT is reentered */
 | 
			
		||||
  g_main_loop_run (launcher->nested_loop);
 | 
			
		||||
 | 
			
		||||
  g_assert (launcher->vt_switched);
 | 
			
		||||
  launcher->vt_switched = FALSE;
 | 
			
		||||
 | 
			
		||||
  meta_launcher_enter (launcher);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_socket_readable (GSocket      *socket,
 | 
			
		||||
		    GIOCondition  condition,
 | 
			
		||||
		    gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *launcher = user_data;
 | 
			
		||||
  struct weston_launcher_event event;
 | 
			
		||||
  gssize read;
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  if ((condition & G_IO_IN) == 0)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
 | 
			
		||||
  if (read < (gssize)sizeof(event))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Error reading from weston-launcher socket: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  switch (event.header.opcode)
 | 
			
		||||
    {
 | 
			
		||||
    case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
 | 
			
		||||
      handle_request_vt_switch (launcher);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case WESTON_LAUNCHER_SERVER_VT_ENTER:
 | 
			
		||||
      handle_vt_enter (launcher);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
env_get_fd (const char *env)
 | 
			
		||||
{
 | 
			
		||||
  const char *value;
 | 
			
		||||
 | 
			
		||||
  value = g_getenv (env);
 | 
			
		||||
 | 
			
		||||
  if (value == NULL)
 | 
			
		||||
    return -1;
 | 
			
		||||
  else
 | 
			
		||||
    return g_ascii_strtoll (value, NULL, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaLauncher *
 | 
			
		||||
meta_launcher_new (void)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *self = g_slice_new0 (MetaLauncher);
 | 
			
		||||
  int launch_fd;
 | 
			
		||||
 | 
			
		||||
  launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
 | 
			
		||||
  if (launch_fd < 0)
 | 
			
		||||
    g_error ("Invalid mutter-launch socket");
 | 
			
		||||
 | 
			
		||||
  self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
 | 
			
		||||
 | 
			
		||||
  self->nested_context = g_main_context_new ();
 | 
			
		||||
  self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
 | 
			
		||||
 | 
			
		||||
  self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
 | 
			
		||||
  g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
 | 
			
		||||
  g_source_attach (self->outer_source, NULL);
 | 
			
		||||
  g_source_unref (self->outer_source);
 | 
			
		||||
 | 
			
		||||
  self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
 | 
			
		||||
  g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
 | 
			
		||||
  g_source_attach (self->inner_source, self->nested_context);
 | 
			
		||||
  g_source_unref (self->inner_source);
 | 
			
		||||
 | 
			
		||||
  clutter_evdev_set_device_callbacks (on_evdev_device_open,
 | 
			
		||||
                                      on_evdev_device_close,
 | 
			
		||||
                                      self);
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_launcher_free (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  g_source_destroy (launcher->outer_source);
 | 
			
		||||
  g_source_destroy (launcher->inner_source);
 | 
			
		||||
 | 
			
		||||
  g_main_loop_unref (launcher->nested_loop);
 | 
			
		||||
  g_main_context_unref (launcher->nested_context);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (launcher->weston_launch);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaLauncher, launcher);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_launcher_activate_vt (MetaLauncher  *launcher,
 | 
			
		||||
			   signed char    vt,
 | 
			
		||||
			   GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  struct weston_launcher_activate_vt message;
 | 
			
		||||
 | 
			
		||||
  message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
 | 
			
		||||
  message.vt = vt;
 | 
			
		||||
 | 
			
		||||
  return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,763 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <error.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/signalfd.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <linux/vt.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
#include <linux/kd.h>
 | 
			
		||||
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
 | 
			
		||||
#include <systemd/sd-login.h>
 | 
			
		||||
 | 
			
		||||
#include "weston-launch.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_ARGV_SIZE 256
 | 
			
		||||
#define DRM_MAJOR     226
 | 
			
		||||
 | 
			
		||||
enum vt_state {
 | 
			
		||||
	VT_HAS_VT,
 | 
			
		||||
	VT_PENDING_CONFIRM,
 | 
			
		||||
	VT_NOT_HAVE_VT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launch {
 | 
			
		||||
	int tty;
 | 
			
		||||
	int ttynr;
 | 
			
		||||
	int sock[2];
 | 
			
		||||
	struct passwd *pw;
 | 
			
		||||
 | 
			
		||||
	int signalfd;
 | 
			
		||||
 | 
			
		||||
	pid_t child;
 | 
			
		||||
	int verbose;
 | 
			
		||||
 | 
			
		||||
	struct termios terminal_attributes;
 | 
			
		||||
	int kb_mode;
 | 
			
		||||
	enum vt_state vt_state;
 | 
			
		||||
	unsigned vt;
 | 
			
		||||
 | 
			
		||||
        int drm_fd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union cmsg_data { unsigned char b[4]; int fd; };
 | 
			
		||||
 | 
			
		||||
static void quit (struct weston_launch *wl, int status);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
weston_launch_allowed(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char *session, *seat;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (getuid() == 0)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	err = sd_pid_get_session(getpid(), &session);
 | 
			
		||||
	if (err == 0 && session) {
 | 
			
		||||
		if (sd_session_is_active(session) &&
 | 
			
		||||
		    sd_session_get_seat(session, &seat) == 0) {
 | 
			
		||||
			free(seat);
 | 
			
		||||
			free(session);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		free(session);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_launcher_socket(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
 | 
			
		||||
		error(1, errno, "socketpair failed");
 | 
			
		||||
	
 | 
			
		||||
	fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_signals(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	struct sigaction sa;
 | 
			
		||||
 | 
			
		||||
	memset(&sa, 0, sizeof sa);
 | 
			
		||||
	sa.sa_handler = SIG_DFL;
 | 
			
		||||
	sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 | 
			
		||||
	ret = sigaction(SIGCHLD, &sa, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	sa.sa_handler = SIG_IGN;
 | 
			
		||||
	sa.sa_flags = 0;
 | 
			
		||||
	sigaction(SIGHUP, &sa, NULL);
 | 
			
		||||
 | 
			
		||||
	ret = sigemptyset(&mask);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	sigaddset(&mask, SIGUSR1);
 | 
			
		||||
	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
 | 
			
		||||
	if (wl->signalfd < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
setenv_fd(const char *env, int fd)
 | 
			
		||||
{
 | 
			
		||||
	char buf[32];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof buf, "%d", fd);
 | 
			
		||||
	setenv(env, buf, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_setdrmfd(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
        struct weston_launcher_reply reply;
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
	struct stat s;
 | 
			
		||||
 | 
			
		||||
	reply.header.opcode = WESTON_LAUNCHER_DRM_SET_FD;
 | 
			
		||||
	reply.ret = -1;
 | 
			
		||||
 | 
			
		||||
	if (wl->drm_fd != -1) {
 | 
			
		||||
		error(0, 0, "DRM FD already set");
 | 
			
		||||
		reply.ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmsg = CMSG_FIRSTHDR(msg);
 | 
			
		||||
	if (!cmsg ||
 | 
			
		||||
	    cmsg->cmsg_level != SOL_SOCKET ||
 | 
			
		||||
	    cmsg->cmsg_type != SCM_RIGHTS) {
 | 
			
		||||
		error(0, 0, "invalid control message");
 | 
			
		||||
		reply.ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
	if (data->fd < 0) {
 | 
			
		||||
		error(0, 0, "missing drm fd in socket request");
 | 
			
		||||
		reply.ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fstat(data->fd, &s) < 0) {
 | 
			
		||||
		reply.ret = -errno;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (major(s.st_rdev) != DRM_MAJOR) {
 | 
			
		||||
		fprintf(stderr, "FD is not for DRM\n");
 | 
			
		||||
		reply.ret = -EPERM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl->drm_fd = data->fd;
 | 
			
		||||
	reply.ret = drmSetMaster(data->fd);
 | 
			
		||||
	if (reply.ret < 0)
 | 
			
		||||
		reply.ret = -errno;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "mutter-launch: set drm FD, ret: %d, fd: %d\n",
 | 
			
		||||
			reply.ret, data->fd);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &reply, sizeof reply, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
        struct weston_launcher_reply reply;
 | 
			
		||||
 | 
			
		||||
	reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
 | 
			
		||||
	reply.ret = -1;
 | 
			
		||||
 | 
			
		||||
	if (wl->vt_state != VT_PENDING_CONFIRM) {
 | 
			
		||||
		error(0, 0, "unexpected CONFIRM_VT_SWITCH");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl->drm_fd != -1) {
 | 
			
		||||
		int ret;
 | 
			
		||||
 | 
			
		||||
		ret = drmDropMaster(wl->drm_fd);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			fprintf(stderr, "failed to drop DRM master: %m\n");
 | 
			
		||||
		} else if (wl->verbose) {
 | 
			
		||||
			fprintf(stderr, "dropped DRM master for VT switch\n");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl->vt_state = VT_NOT_HAVE_VT;
 | 
			
		||||
	ioctl(wl->tty, VT_RELDISP, 1);
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "mutter-launcher: confirmed VT switch\n");
 | 
			
		||||
 | 
			
		||||
	reply.ret = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &reply, sizeof reply, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
        struct weston_launcher_reply reply;
 | 
			
		||||
	struct weston_launcher_activate_vt *message;
 | 
			
		||||
	unsigned vt;
 | 
			
		||||
 | 
			
		||||
	reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
 | 
			
		||||
	reply.ret = -1;
 | 
			
		||||
 | 
			
		||||
	if (len != sizeof(*message)) {
 | 
			
		||||
		error(0, 0, "missing value in activate_vt request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
 | 
			
		||||
	/* Negative values mean that we're activating our own VT */
 | 
			
		||||
	if (message->vt > 0)
 | 
			
		||||
		vt = message->vt;
 | 
			
		||||
	else
 | 
			
		||||
		vt = wl->vt;
 | 
			
		||||
 | 
			
		||||
	reply.ret = ioctl(wl->tty, VT_ACTIVATE, vt);
 | 
			
		||||
	if (reply.ret < 0)
 | 
			
		||||
		reply.ret = -errno;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &reply, sizeof reply, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
        struct weston_launcher_reply reply;
 | 
			
		||||
	int fd = -1;
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(fd))];
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	struct stat s;
 | 
			
		||||
	struct msghdr nmsg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	struct weston_launcher_open *message;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
 | 
			
		||||
	reply.header.opcode = WESTON_LAUNCHER_OPEN;
 | 
			
		||||
	reply.ret = -1;
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
	if ((size_t)len < sizeof(*message))
 | 
			
		||||
		goto err0;
 | 
			
		||||
 | 
			
		||||
	/* Ensure path is null-terminated */
 | 
			
		||||
	((char *) message)[len-1] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (stat(message->path, &s) < 0) {
 | 
			
		||||
		reply.ret = -errno;
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (major(s.st_rdev) != INPUT_MAJOR) {
 | 
			
		||||
		fprintf(stderr, "Device %s is not an input device\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		reply.ret = -EPERM;
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd = open(message->path, message->flags);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Error opening device %s: %m\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		reply.ret = -errno;
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
err0:
 | 
			
		||||
	memset(&nmsg, 0, sizeof nmsg);
 | 
			
		||||
	nmsg.msg_iov = &iov;
 | 
			
		||||
	nmsg.msg_iovlen = 1;
 | 
			
		||||
	if (fd != -1) {
 | 
			
		||||
		nmsg.msg_control = control;
 | 
			
		||||
		nmsg.msg_controllen = sizeof control;
 | 
			
		||||
		cmsg = CMSG_FIRSTHDR(&nmsg);
 | 
			
		||||
		cmsg->cmsg_level = SOL_SOCKET;
 | 
			
		||||
		cmsg->cmsg_type = SCM_RIGHTS;
 | 
			
		||||
		cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
 | 
			
		||||
		data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
		data->fd = fd;
 | 
			
		||||
		nmsg.msg_controllen = cmsg->cmsg_len;
 | 
			
		||||
		reply.ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
	iov.iov_base = &reply;
 | 
			
		||||
	iov.iov_len = sizeof reply;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n",
 | 
			
		||||
			message->path, reply.ret, fd);
 | 
			
		||||
	do {
 | 
			
		||||
		len = sendmsg(wl->sock[0], &nmsg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_socket_msg(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(int))];
 | 
			
		||||
	char buf[BUFSIZ];
 | 
			
		||||
	struct msghdr msg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
	struct weston_launcher_message *message;
 | 
			
		||||
 | 
			
		||||
	memset(&msg, 0, sizeof(msg));
 | 
			
		||||
	iov.iov_base = buf;
 | 
			
		||||
	iov.iov_len  = sizeof buf;
 | 
			
		||||
	msg.msg_iov = &iov;
 | 
			
		||||
	msg.msg_iovlen = 1;
 | 
			
		||||
	msg.msg_control = control;
 | 
			
		||||
	msg.msg_controllen = sizeof control;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		len = recvmsg(wl->sock[0], &msg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	if (len < 1)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	message = (void *) buf;
 | 
			
		||||
	switch (message->opcode) {
 | 
			
		||||
	case WESTON_LAUNCHER_OPEN:
 | 
			
		||||
		ret = handle_open(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_DRM_SET_FD:
 | 
			
		||||
		ret = handle_setdrmfd(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
 | 
			
		||||
		ret = handle_confirm_vt_switch(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_ACTIVATE_VT:
 | 
			
		||||
		ret = handle_activate_vt(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
tty_reset(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct vt_mode mode = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
 | 
			
		||||
		fprintf(stderr, "failed to restore keyboard mode: %m\n");
 | 
			
		||||
 | 
			
		||||
	if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
 | 
			
		||||
		fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
 | 
			
		||||
 | 
			
		||||
	if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
 | 
			
		||||
		fprintf(stderr, "could not restore terminal to canonical mode\n");
 | 
			
		||||
 | 
			
		||||
	mode.mode = VT_AUTO;
 | 
			
		||||
	if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
 | 
			
		||||
		fprintf(stderr, "could not reset vt handling\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
quit(struct weston_launch *wl, int status)
 | 
			
		||||
{
 | 
			
		||||
	if (wl->child > 0)
 | 
			
		||||
		kill(wl->child, SIGKILL);
 | 
			
		||||
 | 
			
		||||
	close(wl->signalfd);
 | 
			
		||||
	close(wl->sock[0]);
 | 
			
		||||
 | 
			
		||||
	if (wl->drm_fd > 0)
 | 
			
		||||
		close(wl->drm_fd);
 | 
			
		||||
 | 
			
		||||
	tty_reset(wl);
 | 
			
		||||
 | 
			
		||||
	exit(status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_vt_switch(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct weston_launcher_event message;
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
 | 
			
		||||
	if (wl->vt_state == VT_HAS_VT) {
 | 
			
		||||
		wl->vt_state = VT_PENDING_CONFIRM;
 | 
			
		||||
		message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
 | 
			
		||||
	} else if (wl->vt_state == VT_NOT_HAVE_VT) {
 | 
			
		||||
		wl->vt_state = VT_HAS_VT;
 | 
			
		||||
		ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
 | 
			
		||||
 | 
			
		||||
		if (wl->drm_fd != -1) {
 | 
			
		||||
			int ret;
 | 
			
		||||
 | 
			
		||||
			ret = drmSetMaster(wl->drm_fd);
 | 
			
		||||
			if (ret < 0) {
 | 
			
		||||
				fprintf(stderr, "failed to become DRM master: %m\n");
 | 
			
		||||
				/* This is very, very bad, and the compositor will crash soon,
 | 
			
		||||
				   but oh well... */
 | 
			
		||||
			} else if (wl->verbose) {
 | 
			
		||||
				fprintf(stderr, "became DRM master after VT switch\n");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
 | 
			
		||||
	} else
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	message.detail = 0;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &message, sizeof(message), 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_signal(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct signalfd_siginfo sig;
 | 
			
		||||
	int pid, status, ret;
 | 
			
		||||
 | 
			
		||||
	if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
 | 
			
		||||
		error(0, errno, "reading signalfd failed");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (sig.ssi_signo) {
 | 
			
		||||
	case SIGCHLD:
 | 
			
		||||
		pid = waitpid(-1, &status, 0);
 | 
			
		||||
		if (pid == wl->child) {
 | 
			
		||||
			wl->child = 0;
 | 
			
		||||
			if (WIFEXITED(status))
 | 
			
		||||
				ret = WEXITSTATUS(status);
 | 
			
		||||
			else if (WIFSIGNALED(status))
 | 
			
		||||
				/*
 | 
			
		||||
				 * If weston dies because of signal N, we
 | 
			
		||||
				 * return 10+N. This is distinct from
 | 
			
		||||
				 * weston-launch dying because of a signal
 | 
			
		||||
				 * (128+N).
 | 
			
		||||
				 */
 | 
			
		||||
				ret = 10 + WTERMSIG(status);
 | 
			
		||||
			else
 | 
			
		||||
				ret = 0;
 | 
			
		||||
			quit(wl, ret);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGTERM:
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
		if (wl->child)
 | 
			
		||||
			kill(wl->child, sig.ssi_signo);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
		return handle_vt_switch(wl);
 | 
			
		||||
	default:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_tty(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	struct termios raw_attributes;
 | 
			
		||||
	struct vt_mode mode = { 0 };
 | 
			
		||||
	char *session;
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	int ok;
 | 
			
		||||
 | 
			
		||||
	ok = sd_pid_get_session(getpid(), &session);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
	  error(1, -ok, "could not determine current session");
 | 
			
		||||
 | 
			
		||||
	ok = sd_session_get_vt(session, &wl->vt);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
		error(1, -ok, "could not determine current TTY");
 | 
			
		||||
 | 
			
		||||
	snprintf(path, PATH_MAX, "/dev/tty%u", wl->vt);
 | 
			
		||||
	wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
 | 
			
		||||
 | 
			
		||||
	if (wl->tty < 0)
 | 
			
		||||
		error(1, errno, "failed to open tty");
 | 
			
		||||
 | 
			
		||||
	if (fstat(wl->tty, &buf) < 0)
 | 
			
		||||
		error(1, errno, "stat %s failed", path);
 | 
			
		||||
 | 
			
		||||
	if (major(buf.st_rdev) != TTY_MAJOR)
 | 
			
		||||
		error(1, 0, "invalid tty device: %s", path);
 | 
			
		||||
 | 
			
		||||
	wl->ttynr = minor(buf.st_rdev);
 | 
			
		||||
 | 
			
		||||
	if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
 | 
			
		||||
		error(1, errno, "could not get terminal attributes");
 | 
			
		||||
 | 
			
		||||
	/* Ignore control characters and disable echo */
 | 
			
		||||
	raw_attributes = wl->terminal_attributes;
 | 
			
		||||
	cfmakeraw(&raw_attributes);
 | 
			
		||||
 | 
			
		||||
	/* Fix up line endings to be normal (cfmakeraw hoses them) */
 | 
			
		||||
	raw_attributes.c_oflag |= OPOST | OCRNL;
 | 
			
		||||
	/* Don't generate ttou signals */
 | 
			
		||||
	raw_attributes.c_oflag &= ~TOSTOP;
 | 
			
		||||
 | 
			
		||||
	if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
 | 
			
		||||
	        error(1, errno, "could not put terminal into raw mode");
 | 
			
		||||
 | 
			
		||||
	ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
 | 
			
		||||
	ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
 | 
			
		||||
	if (ok < 0) {
 | 
			
		||||
		ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
 | 
			
		||||
		if (ok < 0)
 | 
			
		||||
			error(1, errno, "failed to set keyboard mode on tty");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
		error(1, errno, "failed to set KD_GRAPHICS mode on tty");
 | 
			
		||||
 | 
			
		||||
	wl->vt_state = VT_HAS_VT;
 | 
			
		||||
	mode.mode = VT_PROCESS;
 | 
			
		||||
	mode.relsig = SIGUSR1;
 | 
			
		||||
	mode.acqsig = SIGUSR1;
 | 
			
		||||
	ok = ioctl(wl->tty, VT_SETMODE, &mode);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
		error(1, errno, "failed to take control of vt handling");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drop_privileges(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	if (setgid(wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#ifdef HAVE_INITGROUPS
 | 
			
		||||
	    initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#endif
 | 
			
		||||
	    setuid(wl->pw->pw_uid) < 0)
 | 
			
		||||
		error(1, errno, "dropping privileges failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	char command[PATH_MAX];
 | 
			
		||||
	char *child_argv[MAX_ARGV_SIZE];
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		printf("weston-launch: spawned weston with pid: %d\n", getpid());
 | 
			
		||||
 | 
			
		||||
	drop_privileges(wl);
 | 
			
		||||
 | 
			
		||||
	setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
 | 
			
		||||
	setenv("LD_LIBRARY_PATH", LIBDIR, 1);
 | 
			
		||||
	unsetenv("DISPLAY");
 | 
			
		||||
 | 
			
		||||
	/* Do not give our signal mask to the new process. */
 | 
			
		||||
	sigemptyset(&mask);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigaddset(&mask, SIGUSR1);
 | 
			
		||||
	sigprocmask(SIG_UNBLOCK, &mask, NULL);
 | 
			
		||||
 | 
			
		||||
	snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
 | 
			
		||||
 | 
			
		||||
	child_argv[0] = wl->pw->pw_shell;
 | 
			
		||||
	child_argv[1] = "-l";
 | 
			
		||||
	child_argv[2] = "-c";
 | 
			
		||||
	child_argv[3] = command;
 | 
			
		||||
	for (i = 0; i < argc; ++i)
 | 
			
		||||
		child_argv[4 + i] = argv[i];
 | 
			
		||||
	child_argv[4 + i] = NULL;
 | 
			
		||||
 | 
			
		||||
	execv(child_argv[0], child_argv);
 | 
			
		||||
	error(1, errno, "exec failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
help(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
 | 
			
		||||
	fprintf(stderr, "  -u, --user      Start session as specified username\n");
 | 
			
		||||
	fprintf(stderr, "  -v, --verbose   Be verbose\n");
 | 
			
		||||
	fprintf(stderr, "  -h, --help      Display this help message\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	struct weston_launch wl;
 | 
			
		||||
	int i, c;
 | 
			
		||||
	struct option opts[] = {
 | 
			
		||||
		{ "verbose", no_argument,       NULL, 'v' },
 | 
			
		||||
		{ "help",    no_argument,       NULL, 'h' },
 | 
			
		||||
		{ 0,         0,                 NULL,  0  }
 | 
			
		||||
	};	
 | 
			
		||||
 | 
			
		||||
	memset(&wl, 0, sizeof wl);
 | 
			
		||||
	wl.drm_fd = -1;
 | 
			
		||||
 | 
			
		||||
	while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'v':
 | 
			
		||||
			wl.verbose = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			help("mutter-launch");
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((argc - optind) > (MAX_ARGV_SIZE - 6))
 | 
			
		||||
		error(1, E2BIG, "Too many arguments to pass to weston");
 | 
			
		||||
 | 
			
		||||
	if (optind >= argc)
 | 
			
		||||
		error(1, 0, "Expected program argument");
 | 
			
		||||
 | 
			
		||||
	wl.pw = getpwuid(getuid());
 | 
			
		||||
	if (wl.pw == NULL)
 | 
			
		||||
		error(1, errno, "failed to get username");
 | 
			
		||||
 | 
			
		||||
	if (!weston_launch_allowed(&wl))
 | 
			
		||||
		error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
 | 
			
		||||
 | 
			
		||||
	if (setup_tty(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_launcher_socket(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_signals(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	wl.child = fork();
 | 
			
		||||
	if (wl.child == -1) {
 | 
			
		||||
		error(1, errno, "fork failed");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl.child == 0)
 | 
			
		||||
		launch_compositor(&wl, argc - optind, argv + optind);
 | 
			
		||||
 | 
			
		||||
	close(wl.sock[1]);
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		struct pollfd fds[2];
 | 
			
		||||
		int n;
 | 
			
		||||
 | 
			
		||||
		fds[0].fd = wl.sock[0];
 | 
			
		||||
		fds[0].events = POLLIN;
 | 
			
		||||
		fds[1].fd = wl.signalfd;
 | 
			
		||||
		fds[1].events = POLLIN;
 | 
			
		||||
 | 
			
		||||
		n = poll(fds, 2, -1);
 | 
			
		||||
		if (n < 0)
 | 
			
		||||
			error(0, errno, "poll failed");
 | 
			
		||||
		if (fds[0].revents & POLLIN)
 | 
			
		||||
			handle_socket_msg(&wl);
 | 
			
		||||
		if (fds[1].revents)
 | 
			
		||||
			handle_signal(&wl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,69 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *             2013 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _WESTON_LAUNCH_H_
 | 
			
		||||
#define _WESTON_LAUNCH_H_
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_message_type {
 | 
			
		||||
	WESTON_LAUNCHER_REQUEST,
 | 
			
		||||
	WESTON_LAUNCHER_EVENT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_OPEN              = (1 << 1 | WESTON_LAUNCHER_REQUEST),
 | 
			
		||||
	WESTON_LAUNCHER_DRM_SET_FD        = (2 << 1 | WESTON_LAUNCHER_REQUEST),
 | 
			
		||||
	WESTON_LAUNCHER_ACTIVATE_VT       = (3 << 1 | WESTON_LAUNCHER_REQUEST),
 | 
			
		||||
	WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (4 << 1 | WESTON_LAUNCHER_REQUEST),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_server_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
 | 
			
		||||
	WESTON_LAUNCHER_SERVER_VT_ENTER          = (2 << 1 | WESTON_LAUNCHER_EVENT),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_message {
 | 
			
		||||
	int opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_open {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int flags;
 | 
			
		||||
	char path[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_activate_vt {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	signed char vt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_reply {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int ret;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_event {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int detail; /* unused, but makes sure replies and events are serialized the same */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user