Compare commits
	
		
			13 Commits
		
	
	
		
			3.25.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