Compare commits
	
		
			14 Commits
		
	
	
		
			3.33.4
			...
			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