Compare commits
	
		
			14 Commits
		
	
	
		
			3.37.1
			...
			wip/3v1n0/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 9056fb00b0 | ||
|   | 0503ecaf84 | ||
|   | dec20d13e1 | ||
|   | 0242c1a527 | ||
|   | 8652ec9ee2 | ||
|   | 4c607164fd | ||
|   | 08f920606e | ||
|   | ef3ea0a59c | ||
|   | a5f360cb9e | ||
|   | 26cb0a5a75 | ||
|   | 7c89167644 | ||
|   | 984d27f050 | ||
|   | 5b13372fd4 | ||
|   | 4334534742 | 
| @@ -2,10 +2,45 @@ image: registry.gitlab.gnome.org/gnome/mutter/master:v1 | ||||
|  | ||||
| stages: | ||||
|  - build | ||||
|  - test | ||||
|  | ||||
| build-mutter: | ||||
|   stage: build | ||||
|   script: | ||||
|     - meson . build -Degl_device=true -Dwayland_eglstream=true | ||||
|     - meson . build -Degl_device=true -Dwayland_eglstream=true -Dheadless_tests=enabled | ||||
|     - ninja -C build | ||||
|     - ninja -C build install | ||||
|     - meson test -v -C build --suite headless | ||||
|   # artifacts: | ||||
|   #   paths: | ||||
|   #     - build | ||||
|  | ||||
| # test-cogl: | ||||
| #   stage: test | ||||
| #   dependencies: | ||||
| #     - build-mutter | ||||
| #   artifacts: | ||||
| #     paths: | ||||
| #       - build | ||||
| #   script: | ||||
| #     - meson test -v -C build --suite cogl-headless | ||||
|  | ||||
| # test-clutter: | ||||
| #   stage: test | ||||
| #   dependencies: | ||||
| #     - build-mutter | ||||
| #   artifacts: | ||||
| #     paths: | ||||
| #       - build | ||||
| #   script: | ||||
| #     - meson test -v -C build --suite clutter-headless | ||||
|  | ||||
| # test-mutter: | ||||
| #   stage: test | ||||
| #   dependencies: | ||||
| #     - build-mutter | ||||
| #   artifacts: | ||||
| #     paths: | ||||
| #       - build | ||||
| #   script: | ||||
| #     - meson test -v -C build --suite mutter-headless | ||||
|   | ||||
| @@ -7,5 +7,8 @@ RUN dnf -y update && dnf -y upgrade && \ | ||||
| # Until Fedora catches up with meson build-deps | ||||
|     dnf install -y meson xorg-x11-server-Xorg gnome-settings-daemon-devel egl-wayland-devel xorg-x11-server-Xwayland && \ | ||||
|  | ||||
| # To enable testing headless | ||||
|     dnf install -y xorg-x11-server-Xvfb && \ | ||||
|  | ||||
|     dnf install -y intltool redhat-rpm-config make && \ | ||||
|     dnf clean all | ||||
|   | ||||
| @@ -78,7 +78,18 @@ foreach test : clutter_conform_tests | ||||
|     install: false, | ||||
|   ) | ||||
|  | ||||
|   test('clutter/conform/@0@'.format(test), test_executable, | ||||
|   test(test, test_executable, | ||||
|     suite: ['clutter', 'clutter/conform'], | ||||
|     env: test_env | ||||
|   ) | ||||
|  | ||||
|   if have_headless_tests | ||||
|     test(test, xvfb, | ||||
|       args: test_executable, | ||||
|       suite: ['clutter-headless', 'clutter-headless/conform', 'headless'], | ||||
|       env: test_env, | ||||
|       is_parallel: false, | ||||
|       timeout: 60, | ||||
|     ) | ||||
|   endif | ||||
| endforeach | ||||
|   | ||||
| @@ -95,7 +95,8 @@ cogl_conform_unit_tests = custom_target('cogl-tests-conform-unit-tests', | ||||
|   install: false, | ||||
| ) | ||||
|  | ||||
| test('cogl/conform', cogl_run_tests, | ||||
| test('conform', cogl_run_tests, | ||||
|   suite: ['cogl'], | ||||
|   args: [ | ||||
|     cogl_config_env, | ||||
|     libmutter_cogl_test_conformance, | ||||
| @@ -104,3 +105,17 @@ test('cogl/conform', cogl_run_tests, | ||||
|   is_parallel: false, | ||||
|   timeout: 60, | ||||
| ) | ||||
|  | ||||
| if have_headless_tests | ||||
|   test('conform', xvfb, | ||||
|     suite: ['cogl-headless', 'headless'], | ||||
|     args: [ | ||||
|       cogl_run_tests.path(), | ||||
|       cogl_config_env, | ||||
|       libmutter_cogl_test_conformance, | ||||
|       cogl_conform_unit_tests | ||||
|     ], | ||||
|     is_parallel: false, | ||||
|     timeout: 500, | ||||
|   ) | ||||
| endif | ||||
|   | ||||
| @@ -32,11 +32,22 @@ cogl_unit_unit_tests = custom_target('cogl-tests-unit-unit-tests', | ||||
|   install: false, | ||||
| ) | ||||
|  | ||||
| test('cogl/unit', cogl_run_tests, | ||||
|   args: [ | ||||
|     cogl_config_env, | ||||
|     libmutter_cogl_test_unit, | ||||
|     cogl_unit_unit_tests | ||||
|   ], | ||||
| cogl_unit_test_args = [ | ||||
|   cogl_config_env, | ||||
|   libmutter_cogl_test_unit, | ||||
|   cogl_unit_unit_tests | ||||
| ] | ||||
| test('unit', cogl_run_tests, | ||||
|   suite: ['cogl'], | ||||
|   args: cogl_unit_test_args, | ||||
|   is_parallel: false, | ||||
| ) | ||||
|  | ||||
| if have_headless_tests | ||||
|   test('unit', xvfb, | ||||
|     suite: ['cogl-headless', 'headless'], | ||||
|     args: [ cogl_run_tests.path() ] + cogl_unit_test_args, | ||||
|     is_parallel: false, | ||||
|     timeout: 90, | ||||
|   ) | ||||
| endif | ||||
|   | ||||
							
								
								
									
										20
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								meson.build
									
									
									
									
									
								
							| @@ -245,6 +245,26 @@ if have_tests | ||||
|   endif | ||||
| endif | ||||
|  | ||||
| headless_tests_option = get_option('headless_tests') | ||||
| have_headless_tests = not headless_tests_option.disabled() | ||||
| if have_headless_tests | ||||
|   if not have_tests and not have_cogl_tests and not have_clutter_tests | ||||
|     have_headless_tests = false | ||||
|     if headless_tests_option.enabled() | ||||
|       error('Headless tests are enabled, but no other test suite is') | ||||
|     endif | ||||
|   endif | ||||
|   if have_headless_tests | ||||
|     xvfb = find_program('xvfb-run', required: headless_tests_option.enabled()) | ||||
|     have_headless_tests = xvfb.found() | ||||
|   endif | ||||
| endif | ||||
| if have_headless_tests | ||||
|   headless_tests_suite = ['headless'] | ||||
| else | ||||
|   headless_tests_suite = [] | ||||
| endif | ||||
|  | ||||
| required_functions = [ | ||||
|   'ffs', | ||||
|   'clz', | ||||
|   | ||||
| @@ -123,6 +123,12 @@ option('tests', | ||||
|   description: 'Enable mutter tests' | ||||
| ) | ||||
|  | ||||
| option('headless_tests', | ||||
|   type: 'feature', | ||||
|   value: 'auto', | ||||
|   description: 'Enable mutter headless tests' | ||||
| ) | ||||
|  | ||||
| option('verbose', | ||||
|   type: 'boolean', | ||||
|   value: true, | ||||
|   | ||||
| @@ -15,6 +15,9 @@ dist_stacking_DATA =						\ | ||||
| 	$(srcdir)/tests/stacking/basic-x11.metatest 	\ | ||||
| 	$(srcdir)/tests/stacking/basic-wayland.metatest	\ | ||||
| 	$(srcdir)/tests/stacking/closed-transient.metatest	\ | ||||
| 	$(srcdir)/tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest \ | ||||
| 	$(srcdir)/tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest \ | ||||
| 	$(srcdir)/tests/stacking/closed-transient-no-input-parent.metatest \ | ||||
| 	$(srcdir)/tests/stacking/minimized.metatest 	\ | ||||
| 	$(srcdir)/tests/stacking/mixed-windows.metatest     \ | ||||
| 	$(srcdir)/tests/stacking/set-parent.metatest	\ | ||||
|   | ||||
| @@ -1214,10 +1214,7 @@ get_default_focus_window (MetaStack     *stack, | ||||
|       if (window->unmaps_pending > 0) | ||||
|         continue; | ||||
|  | ||||
|       if (window->unmanaging) | ||||
|         continue; | ||||
|  | ||||
|       if (!(window->input || window->take_focus)) | ||||
|       if (!meta_window_is_focusable (window)) | ||||
|         continue; | ||||
|  | ||||
|       if (!meta_window_should_be_showing (window)) | ||||
|   | ||||
| @@ -570,6 +570,7 @@ struct _MetaWindowClass | ||||
|                                    ClutterInputDevice *source); | ||||
|   gboolean (*shortcuts_inhibited) (MetaWindow         *window, | ||||
|                                    ClutterInputDevice *source); | ||||
|   gboolean (*is_focusable)        (MetaWindow *window); | ||||
|   gboolean (*is_stackable)        (MetaWindow *window); | ||||
|   gboolean (*are_updates_frozen)  (MetaWindow *window); | ||||
| }; | ||||
| @@ -664,6 +665,8 @@ void        meta_window_update_unfocused_button_grabs (MetaWindow *window); | ||||
| void     meta_window_set_focused_internal (MetaWindow *window, | ||||
|                                            gboolean    focused); | ||||
|  | ||||
| gboolean meta_window_is_focusable (MetaWindow *window); | ||||
|  | ||||
| void     meta_window_current_workspace_changed (MetaWindow *window); | ||||
|  | ||||
| void meta_window_show_menu (MetaWindow         *window, | ||||
|   | ||||
| @@ -2205,7 +2205,7 @@ window_state_on_map (MetaWindow *window, | ||||
|   /* don't initially focus windows that are intended to not accept | ||||
|    * focus | ||||
|    */ | ||||
|   if (!(window->input || window->take_focus)) | ||||
|   if (!meta_window_is_focusable (window)) | ||||
|     { | ||||
|       *takes_focus = FALSE; | ||||
|       return; | ||||
| @@ -8512,6 +8512,15 @@ meta_window_shortcuts_inhibited (MetaWindow         *window, | ||||
|   return META_WINDOW_GET_CLASS (window)->shortcuts_inhibited (window, source); | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| meta_window_is_focusable (MetaWindow *window) | ||||
| { | ||||
|   if (window->unmanaging) | ||||
|     return FALSE; | ||||
|  | ||||
|   return META_WINDOW_GET_CLASS (window)->is_focusable (window); | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| meta_window_is_stackable (MetaWindow *window) | ||||
| { | ||||
|   | ||||
| @@ -87,6 +87,12 @@ typedef struct _MetaWorkspaceLogicalMonitorData | ||||
|   MetaRectangle logical_monitor_work_area; | ||||
| } MetaWorkspaceLogicalMonitorData; | ||||
|  | ||||
| typedef struct _MetaWorkspaceFocusableAncestorData | ||||
| { | ||||
|   MetaWorkspace *workspace; | ||||
|   MetaWindow   **win; | ||||
| } MetaWorkspaceFocusableAncestorData; | ||||
|  | ||||
| static MetaWorkspaceLogicalMonitorData * | ||||
| meta_workspace_get_logical_monitor_data (MetaWorkspace      *workspace, | ||||
|                                          MetaLogicalMonitor *logical_monitor) | ||||
| @@ -1328,13 +1334,21 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace, | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| record_ancestor (MetaWindow *window, | ||||
|                  void       *data) | ||||
| find_focusable_ancestor (MetaWindow *window, | ||||
|                          void       *data) | ||||
| { | ||||
|   MetaWindow **result = data; | ||||
|   MetaWorkspaceFocusableAncestorData *mwfa = data; | ||||
|   MetaWindow **result = mwfa->win; | ||||
|  | ||||
|   *result = window; | ||||
|   return FALSE; /* quit with the first ancestor we find */ | ||||
|   if (meta_window_is_focusable (window) && | ||||
|       meta_window_located_on_workspace (window, mwfa->workspace) && | ||||
|       meta_window_showing_on_its_workspace (window)) | ||||
|     { | ||||
|       *result = window; | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| /* Focus ancestor of not_this_one if there is one */ | ||||
| @@ -1355,12 +1369,10 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace, | ||||
|   /* First, check to see if we need to focus an ancestor of a window */ | ||||
|   if (not_this_one) | ||||
|     { | ||||
|       MetaWindow *ancestor; | ||||
|       ancestor = NULL; | ||||
|       meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor); | ||||
|       if (ancestor != NULL && | ||||
|           meta_window_located_on_workspace (ancestor, workspace) && | ||||
|           meta_window_showing_on_its_workspace (ancestor)) | ||||
|       MetaWindow *ancestor = NULL; | ||||
|       MetaWorkspaceFocusableAncestorData mwfa = { workspace, &ancestor }; | ||||
|       meta_window_foreach_ancestor (not_this_one, find_focusable_ancestor, &mwfa); | ||||
|       if (ancestor != NULL) | ||||
|         { | ||||
|           meta_topic (META_DEBUG_FOCUS, | ||||
|                       "Focusing %s, ancestor of %s\n", | ||||
|   | ||||
| @@ -191,8 +191,7 @@ main (int argc, char *argv[]) | ||||
|                                           META_TYPE_BACKEND_TEST); | ||||
|   meta_wayland_override_display_name ("mutter-test-display"); | ||||
|  | ||||
|   meta_init (); | ||||
|   meta_register_with_session (); | ||||
|   test_meta_init (); | ||||
|  | ||||
|   g_idle_add (run_tests, NULL); | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,7 @@ test_client = executable('mutter-test-client', | ||||
|   dependencies: [ | ||||
|     gtk3_dep, | ||||
|     gio_unix_dep, | ||||
|     x11_dep, | ||||
|     xext_dep, | ||||
|   ], | ||||
|   install: false, | ||||
| @@ -81,32 +82,73 @@ headless_start_test = executable('mutter-headless-start-test', | ||||
|   install: false, | ||||
| ) | ||||
|  | ||||
| stacking_tests = files([ | ||||
|   'stacking/basic-x11.metatest', | ||||
|   'stacking/basic-wayland.metatest', | ||||
|   'stacking/minimized.metatest', | ||||
|   'stacking/mixed-windows.metatest', | ||||
|   'stacking/set-parent.metatest', | ||||
|   'stacking/override-redirect.metatest', | ||||
| ]) | ||||
| stacking_tests = [ | ||||
|   'basic-x11', | ||||
|   'basic-wayland', | ||||
|   'client-side-decorated', | ||||
|   'closed-transient', | ||||
|   'closed-transient-no-input-no-take-focus-parent', | ||||
|   'closed-transient-no-input-no-take-focus-parents', | ||||
|   'closed-transient-no-input-parent', | ||||
|   'minimized', | ||||
|   'mixed-windows', | ||||
|   'set-parent', | ||||
|   'override-redirect', | ||||
|   'set-parent-exported', | ||||
| ] | ||||
|  | ||||
| test('mutter/stacking', test_runner, | ||||
|   env: test_env, | ||||
|   args: [ | ||||
|     stacking_tests, | ||||
|   ], | ||||
|   is_parallel: false, | ||||
|   timeout: 60, | ||||
| ) | ||||
| foreach stacking_test: stacking_tests | ||||
|   test(stacking_test, test_runner, | ||||
|     suite: ['mutter/stacking'], | ||||
|     env: test_env, | ||||
|     args: [ | ||||
|       files(join_paths('stacking', stacking_test + '.metatest')), | ||||
|     ], | ||||
|     is_parallel: false, | ||||
|     timeout: 60, | ||||
|   ) | ||||
|   if have_headless_tests | ||||
|     test(stacking_test, xvfb, | ||||
|       suite: ['mutter-headless', 'mutter-headless/stacking', 'headless'], | ||||
|       env: test_env, | ||||
|       args: [ | ||||
|         test_runner, | ||||
|         files(join_paths('stacking', stacking_test + '.metatest')), | ||||
|       ], | ||||
|       is_parallel: false, | ||||
|       timeout: 60, | ||||
|     ) | ||||
|   endif | ||||
| endforeach | ||||
|  | ||||
| test('mutter/unit', unit_tests, | ||||
| test('normal', unit_tests, | ||||
|   suite: ['mutter/unit'], | ||||
|   env: test_env, | ||||
|   is_parallel: false, | ||||
|   timeout: 60, | ||||
| ) | ||||
|  | ||||
| test('mutter/unit/headless-start', headless_start_test, | ||||
| test('headless-start', headless_start_test, | ||||
|   suite: ['mutter/unit'], | ||||
|   env: test_env, | ||||
|   is_parallel: false, | ||||
|   timeout: 60, | ||||
| ) | ||||
|  | ||||
| if have_headless_tests | ||||
|   test('normal', xvfb, | ||||
|     args: unit_tests, | ||||
|     suite: ['mutter-headless', 'mutter-headless/unit', 'headless'], | ||||
|     env: test_env, | ||||
|     is_parallel: false, | ||||
|     timeout: 60, | ||||
|   ) | ||||
|  | ||||
|   test('headless-start', xvfb, | ||||
|     args: headless_start_test, | ||||
|     suite: ['mutter-headless', 'mutter-headless/unit', 'headless'], | ||||
|     env: test_env, | ||||
|     is_parallel: false, | ||||
|     timeout: 60, | ||||
|   ) | ||||
| endif | ||||
|   | ||||
| @@ -0,0 +1,25 @@ | ||||
| new_client 1 x11 | ||||
| create 1/1 | ||||
| show 1/1 | ||||
| wait | ||||
|  | ||||
| create 1/2 csd | ||||
| set_parent 1/2 1 | ||||
| take_focus 1/2 false | ||||
| accept_focus 1/2 false | ||||
| show 1/2 | ||||
| wait | ||||
|  | ||||
| create 1/3 csd | ||||
| set_parent 1/3 2 | ||||
| show 1/3 | ||||
| wait | ||||
|  | ||||
| assert_focused 1/3 | ||||
| assert_stacking 1/1 1/2 1/3 | ||||
|  | ||||
| destroy 1/3 | ||||
| wait | ||||
|  | ||||
| assert_focused 1/1 | ||||
| assert_stacking 1/1 1/2 | ||||
| @@ -0,0 +1,32 @@ | ||||
| new_client 2 x11 | ||||
| create 2/1 | ||||
| show 2/1 | ||||
| wait | ||||
|  | ||||
| new_client 1 x11 | ||||
| create 1/1 | ||||
| accept_focus 1/1 false | ||||
| take_focus 1/1 false | ||||
| show 1/1 | ||||
| wait | ||||
|  | ||||
| create 1/2 csd | ||||
| set_parent 1/2 1 | ||||
| take_focus 1/2 false | ||||
| accept_focus 1/2 false | ||||
| show 1/2 | ||||
| wait | ||||
|  | ||||
| create 1/3 csd | ||||
| set_parent 1/3 2 | ||||
| show 1/3 | ||||
| wait | ||||
|  | ||||
| assert_focused 1/3 | ||||
| assert_stacking 2/1 1/1 1/2 1/3 | ||||
|  | ||||
| destroy 1/3 | ||||
| wait | ||||
|  | ||||
| assert_stacking 1/1 1/2 2/1 | ||||
| assert_focused 2/1 | ||||
							
								
								
									
										29
									
								
								src/tests/stacking/closed-transient-no-input-parent.metatest
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/tests/stacking/closed-transient-no-input-parent.metatest
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| new_client 2 x11 | ||||
| create 2/1 | ||||
| show 2/1 | ||||
| wait | ||||
|  | ||||
| new_client 1 x11 | ||||
| create 1/1 | ||||
| show 1/1 | ||||
| wait | ||||
|  | ||||
| create 1/2 csd | ||||
| set_parent 1/2 1 | ||||
| accept_focus 1/2 false | ||||
| show 1/2 | ||||
| wait | ||||
|  | ||||
| create 1/3 csd | ||||
| set_parent 1/3 2 | ||||
| show 1/3 | ||||
| wait | ||||
|  | ||||
| assert_focused 1/3 | ||||
| assert_stacking 2/1 1/1 1/2 1/3 | ||||
|  | ||||
| destroy 1/3 | ||||
| wait | ||||
|  | ||||
| assert_focused 1/1 | ||||
| assert_stacking 2/1 1/1 1/2 | ||||
| @@ -196,6 +196,74 @@ process_line (const char *line) | ||||
|                                              NULL)) | ||||
|         g_print ("Fail to export handle for window id %s", argv[2]); | ||||
|     } | ||||
|   else if (strcmp (argv[0], "accept_focus") == 0) | ||||
|     { | ||||
|       if (argc != 3) | ||||
|         { | ||||
|           g_print ("usage: %s <window-id> [true|false]", argv[0]); | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       GtkWidget *window = lookup_window (argv[1]); | ||||
|       if (!window) | ||||
|         { | ||||
|           g_print ("unknown window %s", argv[1]); | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       gboolean enabled = g_ascii_strcasecmp (argv[2], "true") == 0; | ||||
|       gtk_window_set_accept_focus (GTK_WINDOW (window), enabled); | ||||
|     } | ||||
|   else if (strcmp (argv[0], "take_focus") == 0) | ||||
|     { | ||||
|       if (argc != 3) | ||||
|         { | ||||
|           g_print ("usage: %s <window-id> [true|false]", argv[0]); | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       GtkWidget *window = lookup_window (argv[1]); | ||||
|       if (!window) | ||||
|         { | ||||
|           g_print ("unknown window %s", argv[1]); | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       if (wayland) | ||||
|         { | ||||
|           g_print ("%s not supported under wayland", argv[0]); | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       GdkDisplay *display = gdk_display_get_default (); | ||||
|       GdkWindow *gdkwindow = gtk_widget_get_window (window); | ||||
|       Display *xdisplay = gdk_x11_display_get_xdisplay (display); | ||||
|       Window xwindow = GDK_WINDOW_XID (gdkwindow); | ||||
|       Atom wm_take_focus = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"); | ||||
|       gboolean add = g_ascii_strcasecmp(argv[2], "true") == 0; | ||||
|       Atom *protocols = NULL; | ||||
|       Atom *new_protocols; | ||||
|       int n_protocols = 0; | ||||
|       int i, n = 0; | ||||
|  | ||||
|       gdk_display_sync (display); | ||||
|       XGetWMProtocols (xdisplay, xwindow, &protocols, &n_protocols); | ||||
|       new_protocols = g_malloc0 (sizeof (Atom) * (n_protocols + (add ? 1 : 0))); | ||||
|  | ||||
|       for (i = 0; i < n_protocols; ++i) | ||||
|         { | ||||
|           if (protocols[i] != wm_take_focus) | ||||
|             new_protocols[n++] = protocols[i]; | ||||
|         } | ||||
|  | ||||
|       if (add) | ||||
|         new_protocols[n++] = wm_take_focus; | ||||
|  | ||||
|       XSetWMProtocols (xdisplay, xwindow, new_protocols, n); | ||||
|  | ||||
|       XFree (new_protocols); | ||||
|       XFree (protocols); | ||||
|     } | ||||
|   else if (strcmp (argv[0], "show") == 0) | ||||
|     { | ||||
|       if (argc != 2) | ||||
|   | ||||
| @@ -237,6 +237,38 @@ test_case_assert_stacking (TestCase *test, | ||||
|   return *error == NULL; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| test_case_assert_focused (TestCase   *test, | ||||
|                           const char *expected_window, | ||||
|                           GError    **error) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|  | ||||
|   if (!display->focus_window) | ||||
|     { | ||||
|       if (g_ascii_strcasecmp (expected_window, "null") != 0 && | ||||
|           g_ascii_strcasecmp (expected_window, "none") != 0 && | ||||
|           g_strcmp0 (expected_window, "0") != 0) | ||||
|         { | ||||
|           g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED, | ||||
|                        "focus: expected='%s', actual='NONE'", expected_window); | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       const char *focused = display->focus_window->title; | ||||
|       if (g_str_has_prefix (focused, "test/")) | ||||
|         focused += 5; | ||||
|  | ||||
|       if (g_strcmp0 (focused, expected_window) != 0) | ||||
|         g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED, | ||||
|                     "stacking: expected='%s', actual='%s'", | ||||
|                     expected_window, focused); | ||||
|     } | ||||
|  | ||||
|   return *error == NULL; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| test_case_check_xserver_stacking (TestCase *test, | ||||
|                                   GError  **error) | ||||
| @@ -398,6 +430,44 @@ test_case_do (TestCase *test, | ||||
|       if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error)) | ||||
|         return FALSE; | ||||
|  | ||||
|       if (!test_client_do (client, error, | ||||
|                            argv[0], window_id, | ||||
|                            argv[2], | ||||
|                            NULL)) | ||||
|         return FALSE; | ||||
|     } | ||||
|   else if (strcmp (argv[0], "accept_focus") == 0) | ||||
|     { | ||||
|       if (argc != 3 || | ||||
|           (g_ascii_strcasecmp (argv[2], "true") != 0 && | ||||
|            g_ascii_strcasecmp (argv[2], "false") != 0)) | ||||
|         BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]", | ||||
|                     argv[0]); | ||||
|  | ||||
|       TestClient *client; | ||||
|       const char *window_id; | ||||
|       if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error)) | ||||
|         return FALSE; | ||||
|  | ||||
|       if (!test_client_do (client, error, | ||||
|                            argv[0], window_id, | ||||
|                            argv[2], | ||||
|                            NULL)) | ||||
|         return FALSE; | ||||
|     } | ||||
|   else if (strcmp (argv[0], "take_focus") == 0) | ||||
|     { | ||||
|       if (argc != 3 || | ||||
|           (g_ascii_strcasecmp (argv[2], "true") != 0 && | ||||
|            g_ascii_strcasecmp (argv[2], "false") != 0)) | ||||
|         BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]", | ||||
|                     argv[0]); | ||||
|  | ||||
|       TestClient *client; | ||||
|       const char *window_id; | ||||
|       if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error)) | ||||
|         return FALSE; | ||||
|  | ||||
|       if (!test_client_do (client, error, | ||||
|                            argv[0], window_id, | ||||
|                            argv[2], | ||||
| @@ -485,6 +555,11 @@ test_case_do (TestCase *test, | ||||
|       if (!test_case_check_xserver_stacking (test, error)) | ||||
|         return FALSE; | ||||
|     } | ||||
|   else if (strcmp (argv[0], "assert_focused") == 0) | ||||
|     { | ||||
|       if (!test_case_assert_focused (test, argv[1], error)) | ||||
|         return FALSE; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       BAD_COMMAND("Unknown command %s", argv[0]); | ||||
| @@ -799,8 +874,7 @@ main (int argc, char **argv) | ||||
|   meta_plugin_manager_load (test_get_plugin_name ()); | ||||
|   meta_wayland_override_display_name ("mutter-test-display"); | ||||
|  | ||||
|   meta_init (); | ||||
|   meta_register_with_session (); | ||||
|   test_meta_init (); | ||||
|  | ||||
|   RunTestsInfo info; | ||||
|   info.tests = (char **)tests->pdata; | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
| #include "tests/test-utils.h" | ||||
|  | ||||
| #include <gio/gio.h> | ||||
| #include <meta/main.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "core/display-private.h" | ||||
| @@ -94,6 +95,21 @@ test_init (int    *argc, | ||||
|   ensure_test_client_path (*argc, *argv); | ||||
| } | ||||
|  | ||||
| void | ||||
| test_meta_init () | ||||
| { | ||||
|   GLogLevelFlags log_flags; | ||||
|  | ||||
|   /* Accept warnings in mutter initialization, as `failed to bind` one */ | ||||
|   log_flags = g_log_set_always_fatal (G_LOG_FATAL_MASK); | ||||
|   g_log_set_always_fatal (log_flags & ~G_LOG_LEVEL_WARNING); | ||||
|  | ||||
|   meta_init (); | ||||
|   meta_register_with_session (); | ||||
|  | ||||
|   g_log_set_always_fatal (log_flags); | ||||
| } | ||||
|  | ||||
| AsyncWaiter * | ||||
| async_waiter_new (void) | ||||
| { | ||||
|   | ||||
| @@ -43,6 +43,8 @@ typedef struct _TestClient TestClient; | ||||
| void test_init (int    *argc, | ||||
|                 char ***argv); | ||||
|  | ||||
| void test_meta_init (void); | ||||
|  | ||||
| gboolean async_waiter_alarm_filter (AsyncWaiter           *waiter, | ||||
|                                     MetaX11Display        *x11_display, | ||||
|                                     XSyncAlarmNotifyEvent *event); | ||||
|   | ||||
| @@ -265,8 +265,7 @@ main (int argc, char *argv[]) | ||||
|                                           META_TYPE_BACKEND_TEST); | ||||
|   meta_wayland_override_display_name ("mutter-test-display"); | ||||
|  | ||||
|   meta_init (); | ||||
|   meta_register_with_session (); | ||||
|   test_meta_init (); | ||||
|  | ||||
|   g_idle_add (run_tests, NULL); | ||||
|  | ||||
|   | ||||
| @@ -141,7 +141,7 @@ static void | ||||
| meta_window_wayland_focus (MetaWindow *window, | ||||
|                            guint32     timestamp) | ||||
| { | ||||
|   if (window->input) | ||||
|   if (meta_window_is_focusable (window)) | ||||
|     meta_x11_display_set_input_focus_window (window->display->x11_display, | ||||
|                                              window, | ||||
|                                              FALSE, | ||||
| @@ -585,6 +585,12 @@ meta_window_wayland_shortcuts_inhibited (MetaWindow         *window, | ||||
|   return meta_wayland_compositor_is_shortcuts_inhibited (compositor, source); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_window_wayland_is_focusable (MetaWindow *window) | ||||
| { | ||||
|   return window->input; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_window_wayland_is_stackable (MetaWindow *window) | ||||
| { | ||||
| @@ -618,6 +624,7 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass) | ||||
|   window_class->get_client_pid = meta_window_wayland_get_client_pid; | ||||
|   window_class->force_restore_shortcuts = meta_window_wayland_force_restore_shortcuts; | ||||
|   window_class->shortcuts_inhibited = meta_window_wayland_shortcuts_inhibited; | ||||
|   window_class->is_focusable = meta_window_wayland_is_focusable; | ||||
|   window_class->is_stackable = meta_window_wayland_is_stackable; | ||||
|   window_class->are_updates_frozen = meta_window_wayland_are_updates_frozen; | ||||
| } | ||||
|   | ||||
| @@ -752,8 +752,7 @@ meta_window_x11_focus (MetaWindow *window, | ||||
|    * Still, we have to do this or keynav breaks for these windows. | ||||
|    */ | ||||
|   if (window->frame && | ||||
|       (window->shaded || | ||||
|        !(window->input || window->take_focus))) | ||||
|       (window->shaded || !meta_window_is_focusable (window))) | ||||
|     { | ||||
|       meta_topic (META_DEBUG_FOCUS, | ||||
|                   "Focusing frame of %s\n", window->desc); | ||||
| @@ -790,13 +789,27 @@ meta_window_x11_focus (MetaWindow *window, | ||||
|                * Normally, we want to just leave the focus undisturbed until | ||||
|                * the window responds to WM_TAKE_FOCUS, but if we're unmanaging | ||||
|                * the current focus window we *need* to move the focus away, so | ||||
|                * we focus the no_focus_window now (and set | ||||
|                * display->focus_window to that) before sending WM_TAKE_FOCUS. | ||||
|                * we focus the default focus window excluding this one, | ||||
|                * before sending WM_TAKE_FOCUS. | ||||
|                */ | ||||
|               if (window->display->focus_window != NULL && | ||||
|                   window->display->focus_window->unmanaging) | ||||
|                 meta_x11_display_focus_the_no_focus_window (window->display->x11_display, | ||||
|                                                             timestamp); | ||||
|                 { | ||||
|                   MetaWindow *focus_window = window; | ||||
|                   MetaWorkspace *workspace = window->workspace; | ||||
|  | ||||
|                   do | ||||
|                     { | ||||
|                       focus_window = meta_stack_get_default_focus_window (workspace->display->stack, | ||||
|                                                                           workspace, | ||||
|                                                                           focus_window); | ||||
|                     } | ||||
|                   while (!(!focus_window || focus_window->input || | ||||
|                            (focus_window->frame && focus_window->shaded))); | ||||
|  | ||||
|                   if (focus_window) | ||||
|                     meta_window_x11_focus (focus_window, timestamp); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|           request_take_focus (window, timestamp); | ||||
| @@ -1627,6 +1640,12 @@ meta_window_x11_shortcuts_inhibited (MetaWindow         *window, | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_window_x11_is_focusable (MetaWindow *window) | ||||
| { | ||||
|   return window->input || window->take_focus; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_window_x11_is_stackable (MetaWindow *window) | ||||
| { | ||||
| @@ -1669,6 +1688,7 @@ meta_window_x11_class_init (MetaWindowX11Class *klass) | ||||
|   window_class->get_client_pid = meta_window_x11_get_client_pid; | ||||
|   window_class->force_restore_shortcuts = meta_window_x11_force_restore_shortcuts; | ||||
|   window_class->shortcuts_inhibited = meta_window_x11_shortcuts_inhibited; | ||||
|   window_class->is_focusable = meta_window_x11_is_focusable; | ||||
|   window_class->is_stackable = meta_window_x11_is_stackable; | ||||
|   window_class->are_updates_frozen = meta_window_x11_are_updates_frozen; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user