Compare commits
	
		
			2 Commits
		
	
	
		
			3.32.2
			...
			wip/carlos
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | aea56b6f55 | ||
|   | 217bd31531 | 
							
								
								
									
										41
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								NEWS
									
									
									
									
									
								
							| @@ -1,44 +1,3 @@ | ||||
| 3.32.2 | ||||
| ====== | ||||
| * Disable mouse keys with Numlock on [Olivier; #530] | ||||
| * Fix crash when restarting on X11 [Marco; #576] | ||||
| * Fix mapping of touchscreens that don't report dimensions [Carlos; #581] | ||||
| * Fix spurious idle signals that prevent session unblank [Jonas; !543] | ||||
| * Misc. bug fixes and cleanups [Olivier, Marco, Carlos; !552, !557, #586] | ||||
|  | ||||
| Contributors: | ||||
|   Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, Marco Trevisan (Treviño) | ||||
|  | ||||
| 3.32.1 | ||||
| ====== | ||||
| * Fix fallback app menu on wayland [Florian; #493] | ||||
| * Fix elogind support [Tom; !491] | ||||
| * Fix startup notifications not timing out [Carlos; #501] | ||||
| * Fix keyboard accessibility toggle from keys | ||||
|   [Olivier, Carlos; !501, #529, !531] | ||||
| * Fix touchscreen input on rotated displays [Carlos; #514] | ||||
| * Work around hangul text input bug [Carlos; #1365] | ||||
| * Fix blurry wallpaper scaling [Daniel; !505] | ||||
| * Fix placement of window menu when using fractional scaling [Jan; #527] | ||||
| * Fix repaint issues of offscreen effects on secondary monitors [Daniel; !511] | ||||
| * Fix windows not getting focus after launch [Daniel; #505] | ||||
| * Properly advertise support for 'underscan' property [Jonas; !507] | ||||
| * Improve power-saving handling [Jonas; !506] | ||||
| * Fix moving windows by super+touch [Jonas D.; !495] | ||||
| * Misc. bug fixes and cleanups [Benjamin, Florian, Adam, Marco, Pablo, | ||||
|   Erik, Jonas, Heiher, Pekka, Daniel, Olivier, Carlos; !478, !475, !480, | ||||
|   !482, #490, !488, #491, #480, !477, !496, !492, !485, !515, !519, !521, | ||||
|   !216, !538, #541, #523] | ||||
|  | ||||
| Contributors: | ||||
|   Jonas Ådahl, Pablo Barciela, Benjamin Berg, Tom Briden, Jonas Dreßler, | ||||
|   Olivier Fourdan, Carlos Garnacho, Jan Alexander Steffens (heftig), Heiher, | ||||
|   Adam Jackson, Erik Kurzinger, Florian Müllner, Pekka Paalanen, | ||||
|   Marco Trevisan (Treviño), Daniel van Vugt | ||||
|  | ||||
| Translators: | ||||
|   Khaled Hosny [ar], Goran Vidović [hr], Daniel Mustieles [es] | ||||
|  | ||||
| 3.32.0 | ||||
| ====== | ||||
| * Fix deadlock when cancelling a theme sound [Andrea; !474] | ||||
|   | ||||
| @@ -855,14 +855,6 @@ emulate_pointer_motion (ClutterInputDeviceEvdev *device, | ||||
|   clutter_virtual_input_device_notify_relative_motion (device->mousekeys_virtual_device, | ||||
|                                                        time_us, dx_motion, dy_motion); | ||||
| } | ||||
| static gboolean | ||||
| is_numlock_active (ClutterInputDeviceEvdev *device) | ||||
| { | ||||
|   ClutterSeatEvdev *seat = device->seat; | ||||
|   return xkb_state_mod_name_is_active (seat->xkb, | ||||
|                                        "Mod2", | ||||
|                                        XKB_STATE_MODS_LOCKED); | ||||
| } | ||||
|  | ||||
| static void | ||||
| enable_mousekeys (ClutterInputDeviceEvdev *device) | ||||
| @@ -1021,10 +1013,6 @@ handle_mousekeys_press (ClutterEvent            *event, | ||||
|   if (!(event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC)) | ||||
|     stop_mousekeys_move (device); | ||||
|  | ||||
|   /* Do not handle mousekeys if NumLock is ON */ | ||||
|   if (is_numlock_active (device)) | ||||
|     return FALSE; | ||||
|  | ||||
|   /* Button selection */ | ||||
|   switch (event->key.keyval) | ||||
|     { | ||||
| @@ -1096,10 +1084,6 @@ static gboolean | ||||
| handle_mousekeys_release (ClutterEvent            *event, | ||||
|                           ClutterInputDeviceEvdev *device) | ||||
| { | ||||
|   /* Do not handle mousekeys if NumLock is ON */ | ||||
|   if (is_numlock_active (device)) | ||||
|     return FALSE; | ||||
|  | ||||
|   switch (event->key.keyval) | ||||
|     { | ||||
|     case XKB_KEY_KP_0: | ||||
|   | ||||
| @@ -54,7 +54,6 @@ | ||||
| #include "clutter-main.h" | ||||
| #include "clutter-private.h" | ||||
| #include "clutter-settings-private.h" | ||||
| #include "clutter-xkb-a11y-x11.h" | ||||
|  | ||||
| G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND) | ||||
|  | ||||
| @@ -277,20 +276,6 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11) | ||||
|   _clutter_backend_add_event_translator (backend, translator); | ||||
| } | ||||
|  | ||||
| static void | ||||
| on_keymap_state_change (ClutterKeymapX11 *keymap_x11, | ||||
|                         gpointer          data) | ||||
| { | ||||
|   ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data); | ||||
|   ClutterKbdA11ySettings kbd_a11y_settings; | ||||
|  | ||||
|   /* On keymaps state change, just reapply the current settings, it'll | ||||
|    * take care of enabling/disabling mousekeys based on NumLock state. | ||||
|    */ | ||||
|   clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings); | ||||
|   clutter_device_manager_x11_apply_kbd_a11y_settings (device_manager, &kbd_a11y_settings); | ||||
| } | ||||
|  | ||||
| static void | ||||
| clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11) | ||||
| { | ||||
| @@ -307,11 +292,6 @@ clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11) | ||||
|       backend = CLUTTER_BACKEND (backend_x11); | ||||
|       translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->keymap); | ||||
|       _clutter_backend_add_event_translator (backend, translator); | ||||
|  | ||||
|       g_signal_connect (backend_x11->keymap, | ||||
|                         "state-changed", | ||||
|                         G_CALLBACK (on_keymap_state_change), | ||||
|                         backend->device_manager); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -241,13 +241,8 @@ clutter_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager   *devi | ||||
|     } | ||||
|  | ||||
|   /* mouse keys */ | ||||
|   if (clutter_keymap_get_num_lock_state (CLUTTER_KEYMAP (backend_x11->keymap))) | ||||
|     { | ||||
|       /* Disable mousekeys when NumLock is ON */ | ||||
|       desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask); | ||||
|     } | ||||
|   else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, | ||||
|                          CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask)) | ||||
|   if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, | ||||
|                     CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask)) | ||||
|     { | ||||
|       gint mk_max_speed; | ||||
|       gint mk_accel_time; | ||||
|   | ||||
| @@ -46,9 +46,6 @@ | ||||
| /* Building with SM support */ | ||||
| #mesondefine HAVE_SM | ||||
|  | ||||
| /* Building with startup notification support */ | ||||
| #mesondefine HAVE_STARTUP_NOTIFICATION | ||||
|  | ||||
| /* Path to Xwayland executable */ | ||||
| #mesondefine XWAYLAND_PATH | ||||
|  | ||||
|   | ||||
							
								
								
									
										10
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								meson.build
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| project('mutter', 'c', | ||||
|   version: '3.32.2', | ||||
|   version: '3.32.0', | ||||
|   meson_version: '>= 0.48.0', | ||||
|   license: 'GPLv2+' | ||||
| ) | ||||
| @@ -225,12 +225,6 @@ if have_pango_ft2 | ||||
|   pangoft2_dep = dependency('pangoft2') | ||||
| endif | ||||
|  | ||||
| have_startup_notification = get_option('startup_notification') | ||||
| if have_startup_notification | ||||
|   libstartup_notification_dep = dependency('libstartup-notification-1.0', | ||||
|                                            version: libstartup_notification_req) | ||||
| endif | ||||
|  | ||||
| have_remote_desktop = get_option('remote_desktop') | ||||
| if have_remote_desktop | ||||
|   libpipewire_dep = dependency('libpipewire-0.2', version: libpipewire_req) | ||||
| @@ -334,7 +328,6 @@ cdata.set('HAVE_WAYLAND_EGLSTREAM', have_wayland_eglstream) | ||||
| cdata.set('HAVE_LIBGUDEV', have_libgudev) | ||||
| cdata.set('HAVE_LIBWACOM', have_libwacom) | ||||
| cdata.set('HAVE_SM', have_sm) | ||||
| cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification) | ||||
| cdata.set('HAVE_INTROSPECTION', have_introspection) | ||||
|  | ||||
| xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base') | ||||
| @@ -399,7 +392,6 @@ output = [ | ||||
|   '        gudev.................... ' + have_libgudev.to_string(), | ||||
|   '        Wacom.................... ' + have_libwacom.to_string(), | ||||
|   '        SM....................... ' + have_sm.to_string(), | ||||
|   '        Startup notification..... ' + have_startup_notification.to_string(), | ||||
|   '        Introspection............ ' + have_introspection.to_string(), | ||||
|   '', | ||||
|   '    Tests:', | ||||
|   | ||||
| @@ -316,18 +316,11 @@ idle_monitor_dispatch_timeout (GSource     *source, | ||||
|                                gpointer     user_data) | ||||
| { | ||||
|   MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data; | ||||
|   int64_t now; | ||||
|   int64_t ready_time; | ||||
|  | ||||
|   now = g_source_get_time (source); | ||||
|   ready_time = g_source_get_ready_time (source); | ||||
|   if (ready_time > now) | ||||
|     return G_SOURCE_CONTINUE; | ||||
|  | ||||
|   _meta_idle_monitor_watch_fire (watch); | ||||
|   g_source_set_ready_time (watch->timeout_source, -1); | ||||
|  | ||||
|   return G_SOURCE_CONTINUE; | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static GSourceFuncs idle_monitor_source_funcs = { | ||||
|   | ||||
| @@ -381,7 +381,7 @@ guess_candidates (MetaInputMapper     *mapper, | ||||
|       info->candidates[META_MATCH_SIZE] = matched_monitor; | ||||
|     } | ||||
|  | ||||
|   if (input->builtin || best == N_OUTPUT_MATCHES) | ||||
|   if (input->builtin) | ||||
|     { | ||||
|       best = MIN (best, META_MATCH_IS_BUILTIN); | ||||
|       find_builtin_output (mapper, &info->candidates[META_MATCH_IS_BUILTIN]); | ||||
|   | ||||
| @@ -1216,7 +1216,7 @@ load_keyboard_a11y_settings (MetaInputSettings  *input_settings, | ||||
|                              ClutterInputDevice *device) | ||||
| { | ||||
|   MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings); | ||||
|   ClutterKbdA11ySettings kbd_a11y_settings = { 0 }; | ||||
|   ClutterKbdA11ySettings kbd_a11y_settings; | ||||
|   ClutterInputDevice *core_keyboard; | ||||
|   guint i; | ||||
|  | ||||
|   | ||||
| @@ -18,9 +18,6 @@ struct _MetaCompositor | ||||
|   guint           pre_paint_func_id; | ||||
|   guint           post_paint_func_id; | ||||
|  | ||||
|   guint           stage_presented_id; | ||||
|   guint           stage_after_paint_id; | ||||
|  | ||||
|   gint64          server_time_query_time; | ||||
|   gint64          server_time_offset; | ||||
|  | ||||
|   | ||||
| @@ -92,10 +92,6 @@ on_presented (ClutterStage     *stage, | ||||
|               ClutterFrameInfo *frame_info, | ||||
|               MetaCompositor   *compositor); | ||||
|  | ||||
| static void | ||||
| on_top_window_actor_destroyed (MetaWindowActor *window_actor, | ||||
|                                MetaCompositor  *compositor); | ||||
|  | ||||
| static gboolean | ||||
| is_modal (MetaDisplay *display) | ||||
| { | ||||
| @@ -135,31 +131,9 @@ meta_switch_workspace_completed (MetaCompositor *compositor) | ||||
| void | ||||
| meta_compositor_destroy (MetaCompositor *compositor) | ||||
| { | ||||
|   g_signal_handler_disconnect (compositor->stage, | ||||
|                                compositor->stage_after_paint_id); | ||||
|   g_signal_handler_disconnect (compositor->stage, | ||||
|                                compositor->stage_presented_id); | ||||
|  | ||||
|   compositor->stage_after_paint_id = 0; | ||||
|   compositor->stage_presented_id = 0; | ||||
|   compositor->stage = NULL; | ||||
|  | ||||
|   clutter_threads_remove_repaint_func (compositor->pre_paint_func_id); | ||||
|   clutter_threads_remove_repaint_func (compositor->post_paint_func_id); | ||||
|  | ||||
|   if (compositor->top_window_actor) | ||||
|     { | ||||
|       g_signal_handlers_disconnect_by_func (compositor->top_window_actor, | ||||
|                                             on_top_window_actor_destroyed, | ||||
|                                             compositor); | ||||
|       compositor->top_window_actor = NULL; | ||||
|     } | ||||
|  | ||||
|   g_clear_pointer (&compositor->window_group, clutter_actor_destroy); | ||||
|   g_clear_pointer (&compositor->top_window_group, clutter_actor_destroy); | ||||
|   g_clear_pointer (&compositor->feedback_group, clutter_actor_destroy); | ||||
|   g_clear_pointer (&compositor->windows, g_list_free); | ||||
|  | ||||
|   if (compositor->have_x11_sync_object) | ||||
|     meta_sync_ring_destroy (); | ||||
| } | ||||
| @@ -529,10 +503,9 @@ meta_compositor_manage (MetaCompositor *compositor) | ||||
|  | ||||
|   compositor->stage = meta_backend_get_stage (backend); | ||||
|  | ||||
|   compositor->stage_presented_id = | ||||
|     g_signal_connect (compositor->stage, "presented", | ||||
|                       G_CALLBACK (on_presented), | ||||
|                                                      compositor); | ||||
|   g_signal_connect (compositor->stage, "presented", | ||||
|                     G_CALLBACK (on_presented), | ||||
|                     compositor); | ||||
|  | ||||
|   /* We use connect_after() here to accomodate code in GNOME Shell that, | ||||
|    * when benchmarking drawing performance, connects to ::after-paint | ||||
| @@ -542,9 +515,8 @@ meta_compositor_manage (MetaCompositor *compositor) | ||||
|    * connections to ::after-paint, connect() vs. connect_after() doesn't | ||||
|    * matter. | ||||
|    */ | ||||
|   compositor->stage_after_paint_id = | ||||
|     g_signal_connect_after (compositor->stage, "after-paint", | ||||
|                             G_CALLBACK (after_stage_paint), compositor); | ||||
|   g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint", | ||||
|                           G_CALLBACK (after_stage_paint), compositor); | ||||
|  | ||||
|   clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); | ||||
|  | ||||
|   | ||||
| @@ -31,10 +31,6 @@ | ||||
| #include <X11/extensions/sync.h> | ||||
| #include <X11/Xlib.h> | ||||
|  | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
| #include <libsn/sn.h> | ||||
| #endif | ||||
|  | ||||
| #include "clutter/clutter.h" | ||||
| #include "core/keybindings-private.h" | ||||
| #include "core/meta-gesture-tracker-private.h" | ||||
|   | ||||
| @@ -2236,7 +2236,7 @@ meta_display_get_tab_list (MetaDisplay   *display, | ||||
|         MetaWindow *l_window = w->data; | ||||
|  | ||||
|         if (l_window->wm_state_demands_attention && | ||||
|             !meta_window_located_on_workspace (l_window, workspace) && | ||||
|             l_window->workspace != workspace && | ||||
|             IN_TAB_CHAIN (l_window, type)) | ||||
|           tab_list = g_list_prepend (tab_list, l_window); | ||||
|       } | ||||
|   | ||||
| @@ -118,11 +118,6 @@ static void prefs_changed_callback (MetaPreference pref, | ||||
| static void | ||||
| meta_print_compilation_info (void) | ||||
| { | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
|   meta_verbose ("Compiled with startup notification\n"); | ||||
| #else | ||||
|   meta_verbose ("Compiled without startup notification\n"); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -110,24 +110,25 @@ static void | ||||
| meta_launch_context_constructed (GObject *object) | ||||
| { | ||||
|   MetaLaunchContext *context = META_LAUNCH_CONTEXT (object); | ||||
|   const char *x11_display, *wayland_display; | ||||
|  | ||||
|   G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object); | ||||
|  | ||||
|   x11_display = getenv ("DISPLAY"); | ||||
|   wayland_display = getenv ("WAYLAND_DISPLAY"); | ||||
|   g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), | ||||
|                                "DISPLAY", getenv ("DISPLAY")); | ||||
|   g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), | ||||
|                                "WAYLAND_DISPLAY", getenv ("WAYLAND_DISPLAY")); | ||||
| } | ||||
|  | ||||
|   if (x11_display) | ||||
|     { | ||||
|       g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), | ||||
|                                    "DISPLAY", x11_display); | ||||
|     } | ||||
| static gchar * | ||||
| create_startup_notification_id (uint32_t timestamp) | ||||
| { | ||||
|   gchar *uuid, *id; | ||||
|  | ||||
|   if (wayland_display) | ||||
|     { | ||||
|       g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), | ||||
|                                    "WAYLAND_DISPLAY", wayland_display); | ||||
|     } | ||||
|   uuid = g_uuid_string_random (); | ||||
|   id = g_strdup_printf ("%s_TIME%u", uuid, timestamp); | ||||
|   g_free (uuid); | ||||
|  | ||||
|   return id; | ||||
| } | ||||
|  | ||||
| static gchar * | ||||
| @@ -136,34 +137,19 @@ meta_launch_context_get_startup_notify_id (GAppLaunchContext *launch_context, | ||||
|                                            GList             *files) | ||||
| { | ||||
|   MetaLaunchContext *context = META_LAUNCH_CONTEXT (launch_context); | ||||
|   MetaDisplay *display = context->display; | ||||
|   int workspace_idx = -1; | ||||
|   char *startup_id = NULL; | ||||
|  | ||||
|   if (context->workspace) | ||||
|     workspace_idx = meta_workspace_index (context->workspace); | ||||
|  | ||||
|   if (display->x11_display) | ||||
|     { | ||||
|       /* If there is a X11 display, we prefer going entirely through | ||||
|        * libsn, as SnMonitor expects to keep a view of the full lifetime | ||||
|        * of the startup sequence. We can't avoid it when launching and | ||||
|        * expect that a "remove" message from a X11 client will be handled. | ||||
|        */ | ||||
|       startup_id = | ||||
|         meta_x11_startup_notification_launch (display->x11_display, | ||||
|                                               info, | ||||
|                                               context->timestamp, | ||||
|                                               workspace_idx); | ||||
|     } | ||||
|  | ||||
|   if (!startup_id) | ||||
|     { | ||||
|       const char *application_id = NULL; | ||||
|       MetaStartupNotification *sn; | ||||
|       MetaStartupSequence *seq; | ||||
|  | ||||
|       startup_id = g_uuid_string_random (); | ||||
|       startup_id = create_startup_notification_id (context->timestamp); | ||||
|  | ||||
|       /* Fallback through inserting our own startup sequence, this | ||||
|        * will be enough for wayland clients. | ||||
|   | ||||
| @@ -55,12 +55,6 @@ if have_libgudev | ||||
|   ] | ||||
| endif | ||||
|  | ||||
| if have_startup_notification | ||||
|   mutter_pkg_private_deps += [ | ||||
|     libstartup_notification_dep, | ||||
|   ] | ||||
| endif | ||||
|  | ||||
| if have_libwacom | ||||
|   mutter_pkg_private_deps += [ | ||||
|     libwacom_dep, | ||||
|   | ||||
| @@ -26,266 +26,301 @@ | ||||
| #include "meta/meta-x11-errors.h" | ||||
| #include "x11/meta-x11-display-private.h" | ||||
|  | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
| #define MAX_MESSAGE_LENGTH 4096 | ||||
| #define CLIENT_MESSAGE_DATA_LENGTH 20 | ||||
|  | ||||
| enum | ||||
| { | ||||
|   PROP_SEQ_X11_0, | ||||
|   PROP_SEQ_X11_SEQ, | ||||
|   N_SEQ_X11_PROPS | ||||
| }; | ||||
|  | ||||
| struct _MetaStartupSequenceX11 | ||||
| { | ||||
|   MetaStartupSequence parent_instance; | ||||
|   SnStartupSequence *seq; | ||||
|   MESSAGE_TYPE_NEW, | ||||
|   MESSAGE_TYPE_REMOVE, | ||||
| }; | ||||
|  | ||||
| struct _MetaX11StartupNotification | ||||
| { | ||||
|   SnDisplay *sn_display; | ||||
|   SnMonitorContext *sn_context; | ||||
|   Atom atom_net_startup_info_begin; | ||||
|   Atom atom_net_startup_info; | ||||
|   GHashTable *messages; | ||||
|   MetaX11Display *x11_display; | ||||
| }; | ||||
|  | ||||
| static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS]; | ||||
|  | ||||
| G_DEFINE_TYPE (MetaStartupSequenceX11, | ||||
|                meta_startup_sequence_x11, | ||||
|                META_TYPE_STARTUP_SEQUENCE) | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_complete (MetaStartupSequence *seq) | ||||
| typedef struct | ||||
| { | ||||
|   MetaStartupSequenceX11 *seq_x11; | ||||
|   Window xwindow; | ||||
|   GString *data; | ||||
| } StartupMessage; | ||||
|  | ||||
|   seq_x11 = META_STARTUP_SEQUENCE_X11 (seq); | ||||
|   sn_startup_sequence_complete (seq_x11->seq); | ||||
|  | ||||
| static StartupMessage * | ||||
| startup_message_new (Window window) | ||||
| { | ||||
|   StartupMessage *message; | ||||
|  | ||||
|   message = g_new0 (StartupMessage, 1); | ||||
|   message->xwindow = window; | ||||
|   message->data = g_string_new (NULL); | ||||
|  | ||||
|   return message; | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_finalize (GObject *object) | ||||
| startup_message_free (StartupMessage *message) | ||||
| { | ||||
|   MetaStartupSequenceX11 *seq_x11; | ||||
|  | ||||
|   seq_x11 = META_STARTUP_SEQUENCE_X11 (object); | ||||
|   sn_startup_sequence_unref (seq_x11->seq); | ||||
|  | ||||
|   G_OBJECT_CLASS (meta_startup_sequence_x11_parent_class)->finalize (object); | ||||
|   g_string_free (message->data, TRUE); | ||||
|   g_free (message); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_set_property (GObject      *object, | ||||
|                                         guint         prop_id, | ||||
|                                         const GValue *value, | ||||
|                                         GParamSpec   *pspec) | ||||
| skip_whitespace (const gchar **str) | ||||
| { | ||||
|   MetaStartupSequenceX11 *seq_x11; | ||||
|   while ((*str)[0] == ' ') | ||||
|     (*str)++; | ||||
| } | ||||
|  | ||||
|   seq_x11 = META_STARTUP_SEQUENCE_X11 (object); | ||||
| static gchar * | ||||
| parse_key (const gchar **str) | ||||
| { | ||||
|   const gchar *start = *str; | ||||
|  | ||||
|   switch (prop_id) | ||||
|   while (*str[0] != '\0' && *str[0] != '=') | ||||
|     (*str)++; | ||||
|  | ||||
|   if (start == *str) | ||||
|     return NULL; | ||||
|  | ||||
|   return g_strndup (start, *str - start); | ||||
| } | ||||
|  | ||||
| static gchar * | ||||
| parse_value (const gchar **str) | ||||
| { | ||||
|   const gchar *end; | ||||
|   gboolean escaped = FALSE, quoted = FALSE; | ||||
|   GString *value; | ||||
|  | ||||
|   end = *str; | ||||
|   value = g_string_new (NULL); | ||||
|  | ||||
|   while (end[0] != '\0') | ||||
|     { | ||||
|     case PROP_SEQ_X11_SEQ: | ||||
|       seq_x11->seq = g_value_get_pointer (value); | ||||
|       sn_startup_sequence_ref (seq_x11->seq); | ||||
|       break; | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|       if (escaped) | ||||
|         { | ||||
|           g_string_append_c (value, end[0]); | ||||
|           escaped = FALSE; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           if (!quoted && end[0] == ' ') | ||||
|             break; | ||||
|           else if (end[0] == '"') | ||||
|             quoted = !quoted; | ||||
|           else if (end[0] == '\\') | ||||
|             escaped = TRUE; | ||||
|           else | ||||
|             g_string_append_c (value, end[0]); | ||||
|         } | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_get_property (GObject    *object, | ||||
|                                         guint       prop_id, | ||||
|                                         GValue     *value, | ||||
|                                         GParamSpec *pspec) | ||||
| { | ||||
|   MetaStartupSequenceX11 *seq_x11; | ||||
|  | ||||
|   seq_x11 = META_STARTUP_SEQUENCE_X11 (object); | ||||
|  | ||||
|   switch (prop_id) | ||||
|     { | ||||
|     case PROP_SEQ_X11_SEQ: | ||||
|       g_value_set_pointer (value, seq_x11->seq); | ||||
|       break; | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_init (MetaStartupSequenceX11 *seq) | ||||
| { | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_startup_sequence_x11_class_init (MetaStartupSequenceX11Class *klass) | ||||
| { | ||||
|   MetaStartupSequenceClass *seq_class; | ||||
|   GObjectClass *object_class; | ||||
|  | ||||
|   seq_class = META_STARTUP_SEQUENCE_CLASS (klass); | ||||
|   seq_class->complete = meta_startup_sequence_x11_complete; | ||||
|  | ||||
|   object_class = G_OBJECT_CLASS (klass); | ||||
|   object_class->finalize = meta_startup_sequence_x11_finalize; | ||||
|   object_class->set_property = meta_startup_sequence_x11_set_property; | ||||
|   object_class->get_property = meta_startup_sequence_x11_get_property; | ||||
|  | ||||
|   seq_x11_props[PROP_SEQ_X11_SEQ] = | ||||
|     g_param_spec_pointer ("seq", | ||||
|                           "Sequence", | ||||
|                           "Sequence", | ||||
|                           G_PARAM_READWRITE | | ||||
|                           G_PARAM_CONSTRUCT_ONLY); | ||||
|  | ||||
|   g_object_class_install_properties (object_class, N_SEQ_X11_PROPS, | ||||
|                                      seq_x11_props); | ||||
| } | ||||
|  | ||||
| static MetaStartupSequence * | ||||
| meta_startup_sequence_x11_new (SnStartupSequence *seq) | ||||
| { | ||||
|   gint64 timestamp; | ||||
|  | ||||
|   timestamp = sn_startup_sequence_get_timestamp (seq); | ||||
|   return g_object_new (META_TYPE_STARTUP_SEQUENCE_X11, | ||||
|                        "id", sn_startup_sequence_get_id (seq), | ||||
|                        "icon-name", sn_startup_sequence_get_icon_name (seq), | ||||
|                        "application-id", sn_startup_sequence_get_application_id (seq), | ||||
|                        "wmclass", sn_startup_sequence_get_wmclass (seq), | ||||
|                        "name", sn_startup_sequence_get_name (seq), | ||||
|                        "workspace", sn_startup_sequence_get_workspace (seq), | ||||
|                        "timestamp", timestamp, | ||||
|                        "seq", seq, | ||||
|                        NULL); | ||||
| } | ||||
|  | ||||
| static void | ||||
| sn_error_trap_push (SnDisplay *sn_display, | ||||
|                     Display   *xdisplay) | ||||
| { | ||||
|   MetaDisplay *display; | ||||
|  | ||||
|   display = meta_display_for_x_display (xdisplay); | ||||
|   if (display != NULL) | ||||
|     meta_x11_error_trap_push (display->x11_display); | ||||
| } | ||||
|  | ||||
| static void | ||||
| sn_error_trap_pop (SnDisplay *sn_display, | ||||
|                    Display   *xdisplay) | ||||
| { | ||||
|   MetaDisplay *display; | ||||
|  | ||||
|   display = meta_display_for_x_display (xdisplay); | ||||
|   if (display != NULL) | ||||
|     meta_x11_error_trap_pop (display->x11_display); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_startup_notification_sn_event (SnMonitorEvent *event, | ||||
|                                     void           *user_data) | ||||
| { | ||||
|   MetaX11Display *x11_display = user_data; | ||||
|   MetaStartupNotification *sn = x11_display->display->startup_notification; | ||||
|   MetaStartupSequence *seq; | ||||
|   SnStartupSequence *sequence; | ||||
|  | ||||
|   sequence = sn_monitor_event_get_startup_sequence (event); | ||||
|  | ||||
|   sn_startup_sequence_ref (sequence); | ||||
|  | ||||
|   switch (sn_monitor_event_get_type (event)) | ||||
|     { | ||||
|     case SN_MONITOR_EVENT_INITIATED: | ||||
|       { | ||||
|         const char *wmclass; | ||||
|  | ||||
|         wmclass = sn_startup_sequence_get_wmclass (sequence); | ||||
|  | ||||
|         meta_topic (META_DEBUG_STARTUP, | ||||
|                     "Received startup initiated for %s wmclass %s\n", | ||||
|                     sn_startup_sequence_get_id (sequence), | ||||
|                     wmclass ? wmclass : "(unset)"); | ||||
|  | ||||
|         seq = meta_startup_sequence_x11_new (sequence); | ||||
|         meta_startup_notification_add_sequence (sn, seq); | ||||
|         g_object_unref (seq); | ||||
|       } | ||||
|       break; | ||||
|  | ||||
|     case SN_MONITOR_EVENT_COMPLETED: | ||||
|       { | ||||
|         meta_topic (META_DEBUG_STARTUP, | ||||
|                     "Received startup completed for %s\n", | ||||
|                     sn_startup_sequence_get_id (sequence)); | ||||
|  | ||||
|         seq = meta_startup_notification_lookup_sequence (sn, sn_startup_sequence_get_id (sequence)); | ||||
|         if (seq) | ||||
|           { | ||||
|             meta_startup_sequence_complete (seq); | ||||
|             meta_startup_notification_remove_sequence (sn, seq); | ||||
|           } | ||||
|       } | ||||
|       break; | ||||
|  | ||||
|     case SN_MONITOR_EVENT_CHANGED: | ||||
|       meta_topic (META_DEBUG_STARTUP, | ||||
|                   "Received startup changed for %s\n", | ||||
|                   sn_startup_sequence_get_id (sequence)); | ||||
|       break; | ||||
|  | ||||
|     case SN_MONITOR_EVENT_CANCELED: | ||||
|       meta_topic (META_DEBUG_STARTUP, | ||||
|                   "Received startup canceled for %s\n", | ||||
|                   sn_startup_sequence_get_id (sequence)); | ||||
|       break; | ||||
|       end++; | ||||
|     } | ||||
|  | ||||
|   sn_startup_sequence_unref (sequence); | ||||
|   *str = end; | ||||
|  | ||||
|   if (value->len == 0) | ||||
|     { | ||||
|       g_string_free (value, TRUE); | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|   return g_string_free (value, FALSE); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| startup_message_parse (StartupMessage  *message, | ||||
|                        int             *type, | ||||
|                        gchar          **id, | ||||
|                        GHashTable     **data) | ||||
| { | ||||
|   const gchar *str = message->data->str; | ||||
|  | ||||
|   if (strncmp (str, "new:", 4) == 0) | ||||
|     { | ||||
|       *type = MESSAGE_TYPE_NEW; | ||||
|       str += 4; | ||||
|     } | ||||
|   else if (strncmp (str, "remove:", 7) == 0) | ||||
|     { | ||||
|       *type = MESSAGE_TYPE_REMOVE; | ||||
|       str += 7; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   *data = g_hash_table_new_full (g_str_hash, | ||||
|                                  g_str_equal, | ||||
|                                  g_free, | ||||
|                                  g_free); | ||||
|   while (str[0]) | ||||
|     { | ||||
|       gchar *key, *value; | ||||
|  | ||||
|       skip_whitespace (&str); | ||||
|       key = parse_key (&str); | ||||
|       if (!key) | ||||
|         break; | ||||
|  | ||||
|       str++; | ||||
|       value = parse_value (&str); | ||||
|  | ||||
|       if (!value) | ||||
|         { | ||||
|           g_free (key); | ||||
|           break; | ||||
|         } | ||||
|  | ||||
|       g_hash_table_insert (*data, key, value); | ||||
|     } | ||||
|  | ||||
|   *id = g_strdup (g_hash_table_lookup (*data, "ID")); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| startup_message_add_data (StartupMessage *message, | ||||
|                           const gchar    *data) | ||||
| { | ||||
|   int len; | ||||
|  | ||||
|   len = strnlen (data, CLIENT_MESSAGE_DATA_LENGTH); | ||||
|   g_string_append_len (message->data, data, len); | ||||
|  | ||||
|   return (message->data->len > MAX_MESSAGE_LENGTH || | ||||
|           len < CLIENT_MESSAGE_DATA_LENGTH); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void | ||||
| meta_x11_startup_notification_init (MetaX11Display *x11_display) | ||||
| { | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
|   MetaX11StartupNotification *x11_sn; | ||||
|  | ||||
|   x11_sn = g_new0 (MetaX11StartupNotification, 1); | ||||
|   x11_sn->sn_display = sn_display_new (x11_display->xdisplay, | ||||
|                                             sn_error_trap_push, | ||||
|                                             sn_error_trap_pop); | ||||
|   x11_sn->sn_context = | ||||
|     sn_monitor_context_new (x11_sn->sn_display, | ||||
|                             meta_x11_display_get_screen_number (x11_display), | ||||
|                             meta_startup_notification_sn_event, | ||||
|                             x11_display, | ||||
|                             NULL); | ||||
|  | ||||
|   x11_sn->atom_net_startup_info_begin = XInternAtom (x11_display->xdisplay, | ||||
|                                                      "_NET_STARTUP_INFO_BEGIN", | ||||
|                                                      False); | ||||
|   x11_sn->atom_net_startup_info = XInternAtom (x11_display->xdisplay, | ||||
|                                                "_NET_STARTUP_INFO", | ||||
|                                                False); | ||||
|   x11_sn->messages = g_hash_table_new_full (NULL, NULL, NULL, | ||||
|                                             (GDestroyNotify) startup_message_free); | ||||
|   x11_sn->x11_display = x11_display; | ||||
|   x11_display->startup_notification = x11_sn; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_x11_startup_notification_release (MetaX11Display *x11_display) | ||||
| { | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
|   MetaX11StartupNotification *x11_sn = x11_display->startup_notification; | ||||
|  | ||||
|   x11_display->startup_notification = NULL; | ||||
|  | ||||
|   if (x11_sn) | ||||
|     { | ||||
|       sn_monitor_context_unref (x11_sn->sn_context); | ||||
|       sn_display_unref (x11_sn->sn_display); | ||||
|       g_hash_table_unref (x11_sn->messages); | ||||
|       g_free (x11_sn); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void | ||||
| handle_message (MetaX11StartupNotification *x11_sn, | ||||
|                 StartupMessage             *message) | ||||
| { | ||||
|   MetaStartupNotification *sn = x11_sn->x11_display->display->startup_notification; | ||||
|   MetaStartupSequence *seq; | ||||
|   GHashTable *data; | ||||
|   char *id; | ||||
|   int type; | ||||
|  | ||||
|   if (message->data->len <= MAX_MESSAGE_LENGTH && | ||||
|       g_utf8_validate (message->data->str, -1, NULL) && | ||||
|       startup_message_parse (message, &type, &id, &data)) | ||||
|     { | ||||
|       if (type == MESSAGE_TYPE_NEW) | ||||
|         { | ||||
|           uint64_t timestamp = 0; | ||||
|           int workspace = -1; | ||||
|  | ||||
|           if (g_hash_table_contains (data, "DESKTOP")) | ||||
|             workspace = atoi (g_hash_table_lookup (data, "DESKTOP")); | ||||
|           if (g_hash_table_contains (data, "TIMESTAMP")) | ||||
|             timestamp = g_ascii_strtoull (g_hash_table_lookup (data, "TIMESTAMP"), NULL, 10); | ||||
|  | ||||
|           seq = g_object_new (META_TYPE_STARTUP_SEQUENCE, | ||||
|                               "id", id, | ||||
|                               "icon-name", g_hash_table_lookup (data, "ICON_NAME"), | ||||
|                               "application-id", g_hash_table_lookup (data, "APPLICATION_ID"), | ||||
|                               "wmclass", g_hash_table_lookup (data, "WMCLASS"), | ||||
|                               "name", g_hash_table_lookup (data, "NAME"), | ||||
|                               "workspace", workspace, | ||||
|                               "timestamp", timestamp, | ||||
|                               NULL); | ||||
|  | ||||
|           meta_topic (META_DEBUG_STARTUP, | ||||
|                       "Received startup initiated for %s wmclass %s\n", | ||||
|                       id, (gchar*) g_hash_table_lookup (data, "WMCLASS")); | ||||
|  | ||||
|           meta_startup_notification_add_sequence (sn, seq); | ||||
|           g_object_unref (seq); | ||||
|         } | ||||
|       else if (type == MESSAGE_TYPE_REMOVE) | ||||
|         { | ||||
|           meta_topic (META_DEBUG_STARTUP, | ||||
|                       "Received startup completed for %s\n", id); | ||||
|           seq = meta_startup_notification_lookup_sequence (sn, id); | ||||
|  | ||||
|           if (seq) | ||||
|             { | ||||
|               meta_startup_sequence_complete (seq); | ||||
|               meta_startup_notification_remove_sequence (sn, seq); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|       g_hash_table_unref (data); | ||||
|       g_free (id); | ||||
|     } | ||||
|  | ||||
|   g_hash_table_remove (x11_sn->messages, GINT_TO_POINTER (message->xwindow)); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| handle_startup_notification_event (MetaX11StartupNotification *x11_sn, | ||||
|                                    XClientMessageEvent        *client_event) | ||||
| { | ||||
|   StartupMessage *message; | ||||
|  | ||||
|   if (client_event->message_type == x11_sn->atom_net_startup_info_begin) | ||||
|     { | ||||
|       message = startup_message_new (client_event->window); | ||||
|       g_hash_table_insert (x11_sn->messages, | ||||
|                            GINT_TO_POINTER (client_event->window), | ||||
|                            message); | ||||
|       if (startup_message_add_data (message, client_event->data.b)) | ||||
|         handle_message (x11_sn, message); | ||||
|       return TRUE; | ||||
|     } | ||||
|   else if (client_event->message_type == x11_sn->atom_net_startup_info) | ||||
|     { | ||||
|       message = g_hash_table_lookup (x11_sn->messages, | ||||
|                                      GINT_TO_POINTER (client_event->window)); | ||||
|       if (message) | ||||
|         { | ||||
|           if (startup_message_add_data (message, client_event->data.b)) | ||||
|             handle_message (x11_sn, message); | ||||
|           return TRUE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| @@ -297,74 +332,8 @@ meta_x11_startup_notification_handle_xevent (MetaX11Display *x11_display, | ||||
|   if (!x11_sn) | ||||
|     return FALSE; | ||||
|  | ||||
|   return sn_display_process_event (x11_sn->sn_display, xevent); | ||||
| } | ||||
|  | ||||
| typedef void (* SetAppIdFunc) (SnLauncherContext *context, | ||||
|                                const char        *app_id); | ||||
|  | ||||
| gchar * | ||||
| meta_x11_startup_notification_launch (MetaX11Display *x11_display, | ||||
|                                       GAppInfo       *app_info, | ||||
|                                       uint32_t        timestamp, | ||||
|                                       int             workspace) | ||||
| { | ||||
|   gchar *startup_id = NULL; | ||||
| #ifdef HAVE_STARTUP_NOTIFICATION | ||||
|   MetaX11StartupNotification *x11_sn = x11_display->startup_notification; | ||||
|   SnLauncherContext *sn_launcher; | ||||
|   int screen; | ||||
|  | ||||
|   screen = meta_x11_display_get_screen_number (x11_display); | ||||
|   sn_launcher = sn_launcher_context_new (x11_sn->sn_display, screen); | ||||
|  | ||||
|   sn_launcher_context_set_name (sn_launcher, g_app_info_get_name (app_info)); | ||||
|   sn_launcher_context_set_workspace (sn_launcher, workspace); | ||||
|   sn_launcher_context_set_binary_name (sn_launcher, | ||||
|                                        g_app_info_get_executable (app_info)); | ||||
|  | ||||
|   if (G_IS_DESKTOP_APP_INFO (app_info)) | ||||
|     { | ||||
|       const char *application_id; | ||||
|       SetAppIdFunc func = NULL; | ||||
|       GModule *self; | ||||
|  | ||||
|       application_id = | ||||
|         g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (app_info)); | ||||
|       self = g_module_open (NULL, G_MODULE_BIND_MASK); | ||||
|  | ||||
|       /* This here is a terrible workaround to bypass a libsn bug that is not | ||||
|        * likely to get fixed at this point. | ||||
|        * sn_launcher_context_set_application_id is correctly defined in the | ||||
|        * sn-launcher.h file, but it's mistakenly called | ||||
|        * sn_launcher_set_application_id in the C file. | ||||
|        * | ||||
|        * We look up the symbol instead, but still prefer the correctly named | ||||
|        * function, if one were ever to be added. | ||||
|        */ | ||||
|       if (!g_module_symbol (self, "sn_launcher_context_set_application_id", | ||||
|                             (gpointer *) &func)) | ||||
|         { | ||||
|           g_module_symbol (self, "sn_launcher_set_application_id", | ||||
|                            (gpointer *) &func); | ||||
|         } | ||||
|  | ||||
|       if (func) | ||||
|         func (sn_launcher, application_id); | ||||
|  | ||||
|       g_module_close (self); | ||||
|     } | ||||
|  | ||||
|   sn_launcher_context_initiate (sn_launcher, | ||||
|                                 g_get_prgname (), | ||||
|                                 g_app_info_get_name (app_info), | ||||
|                                 timestamp); | ||||
|  | ||||
|   startup_id = g_strdup (sn_launcher_context_get_startup_id (sn_launcher)); | ||||
|  | ||||
|   /* Fire and forget, we have a SnMonitor in addition */ | ||||
|   sn_launcher_context_unref (sn_launcher); | ||||
| #endif /* HAVE_STARTUP_NOTIFICATION */ | ||||
|  | ||||
|   return startup_id; | ||||
|   if (xevent->xany.type != ClientMessage) | ||||
|     return FALSE; | ||||
|  | ||||
|   return handle_startup_notification_event (x11_sn, &xevent->xclient); | ||||
| } | ||||
|   | ||||
| @@ -36,9 +36,4 @@ void     meta_x11_startup_notification_release (MetaX11Display *x11_display); | ||||
| gboolean meta_x11_startup_notification_handle_xevent (MetaX11Display *x11_display, | ||||
|                                                       XEvent         *xevent); | ||||
|  | ||||
| gchar *  meta_x11_startup_notification_launch (MetaX11Display *x11_display, | ||||
|                                                GAppInfo       *app_info, | ||||
|                                                uint32_t        timestamp, | ||||
|                                                int             workspace); | ||||
|  | ||||
| #endif /* META_X11_STARTUP_NOTIFICATION_H */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user