Compare commits
28 Commits
3.28.4
...
gnome-3-28
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079a625eaa | ||
|
|
f3420b0341 | ||
|
|
dde0906639 | ||
|
|
a611dadc0b | ||
|
|
88e855bf0a | ||
|
|
f205dabc5e | ||
|
|
74e3126b77 | ||
|
|
4f36e82f68 | ||
|
|
b7bc8e56b7 | ||
|
|
d3f75f31c8 | ||
|
|
0ca9d88926 | ||
|
|
0276630671 | ||
|
|
7d54c5621c | ||
|
|
7951ddab40 | ||
|
|
a6df771747 | ||
|
|
90d8fef5f5 | ||
|
|
b462e519e8 | ||
|
|
0060ddc5bf | ||
|
|
8dd564adff | ||
|
|
556d36baa8 | ||
|
|
1dd0799c77 | ||
|
|
1ebf32187a | ||
|
|
ac1503a559 | ||
|
|
93f268a4a8 | ||
|
|
68691cb1b9 | ||
|
|
8d936a410c | ||
|
|
fc74c7def9 | ||
|
|
9b8a3fbaed |
@@ -492,9 +492,6 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
|
||||
_cogl_bitmask_destroy (&uniforms_state->changed_mask);
|
||||
}
|
||||
|
||||
if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
|
||||
g_slice_free (CoglPipelineBigState, pipeline->big_state);
|
||||
|
||||
if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
|
||||
{
|
||||
g_list_foreach (pipeline->layer_differences,
|
||||
@@ -508,6 +505,9 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
|
||||
if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||
_cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets);
|
||||
|
||||
if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
|
||||
g_slice_free (CoglPipelineBigState, pipeline->big_state);
|
||||
|
||||
g_list_free (pipeline->deprecated_get_layers_list);
|
||||
|
||||
recursively_free_layer_caches (pipeline);
|
||||
|
||||
@@ -15,6 +15,12 @@ dist_stacking_DATA = \
|
||||
tests/stacking/basic-x11.metatest \
|
||||
tests/stacking/basic-wayland.metatest \
|
||||
tests/stacking/closed-transient.metatest \
|
||||
tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest \
|
||||
tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest \
|
||||
tests/stacking/closed-transient-no-input-parent.metatest \
|
||||
tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest \
|
||||
tests/stacking/closed-transient-no-input-parents.metatest \
|
||||
tests/stacking/closed-transient-no-input-parents-queued-default-focus-destroyed.metatest \
|
||||
tests/stacking/minimized.metatest \
|
||||
tests/stacking/mixed-windows.metatest \
|
||||
tests/stacking/set-parent.metatest \
|
||||
|
||||
@@ -51,6 +51,14 @@
|
||||
#define META_TYPE_BACKEND (meta_backend_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaBackend, meta_backend, META, BACKEND, GObject)
|
||||
|
||||
typedef enum _MetaSequenceState
|
||||
{
|
||||
META_SEQUENCE_NONE,
|
||||
META_SEQUENCE_ACCEPTED,
|
||||
META_SEQUENCE_REJECTED,
|
||||
META_SEQUENCE_PENDING_END
|
||||
} MetaSequenceState;
|
||||
|
||||
struct _MetaBackendClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
@@ -73,6 +81,10 @@ struct _MetaBackendClass
|
||||
int device_id,
|
||||
uint32_t timestamp);
|
||||
|
||||
void (* finish_touch_sequence) (MetaBackend *backend,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state);
|
||||
|
||||
void (* warp_pointer) (MetaBackend *backend,
|
||||
int x,
|
||||
int y);
|
||||
@@ -134,6 +146,10 @@ gboolean meta_backend_ungrab_device (MetaBackend *backend,
|
||||
int device_id,
|
||||
uint32_t timestamp);
|
||||
|
||||
void meta_backend_finish_touch_sequence (MetaBackend *backend,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state);
|
||||
|
||||
void meta_backend_warp_pointer (MetaBackend *backend,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
@@ -846,6 +846,20 @@ meta_backend_ungrab_device (MetaBackend *backend,
|
||||
return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_finish_touch_sequence: (skip)
|
||||
*/
|
||||
void
|
||||
meta_backend_finish_touch_sequence (MetaBackend *backend,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state)
|
||||
{
|
||||
if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
|
||||
META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
|
||||
sequence,
|
||||
state);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_warp_pointer: (skip)
|
||||
*/
|
||||
|
||||
@@ -330,23 +330,35 @@ MetaMonitorsConfigKey *
|
||||
meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
|
||||
{
|
||||
MetaMonitorsConfigKey *config_key;
|
||||
MetaMonitorSpec *laptop_monitor_spec;
|
||||
GList *l;
|
||||
GList *monitor_specs;
|
||||
|
||||
laptop_monitor_spec = NULL;
|
||||
monitor_specs = NULL;
|
||||
for (l = monitor_manager->monitors; l; l = l->next)
|
||||
{
|
||||
MetaMonitor *monitor = l->data;
|
||||
MetaMonitorSpec *monitor_spec;
|
||||
|
||||
if (meta_monitor_is_laptop_panel (monitor) &&
|
||||
meta_monitor_manager_is_lid_closed (monitor_manager))
|
||||
continue;
|
||||
if (meta_monitor_is_laptop_panel (monitor))
|
||||
{
|
||||
laptop_monitor_spec = meta_monitor_get_spec (monitor);
|
||||
|
||||
if (meta_monitor_manager_is_lid_closed (monitor_manager))
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
|
||||
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
|
||||
}
|
||||
|
||||
if (!monitor_specs && laptop_monitor_spec)
|
||||
{
|
||||
monitor_specs =
|
||||
g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
|
||||
}
|
||||
|
||||
if (!monitor_specs)
|
||||
return NULL;
|
||||
|
||||
@@ -1007,6 +1019,7 @@ meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager
|
||||
MetaMonitorSwitchConfigType config_type)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
||||
MetaMonitorsConfig *config;
|
||||
|
||||
if (!meta_monitor_manager_can_switch_config (monitor_manager))
|
||||
return NULL;
|
||||
@@ -1014,18 +1027,27 @@ meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager
|
||||
switch (config_type)
|
||||
{
|
||||
case META_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
|
||||
return create_for_switch_config_all_mirror (config_manager);
|
||||
case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
|
||||
return meta_monitor_config_manager_create_linear (config_manager);
|
||||
case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
|
||||
return create_for_switch_config_external (config_manager);
|
||||
case META_MONITOR_SWITCH_CONFIG_BUILTIN:
|
||||
return create_for_switch_config_builtin (config_manager);
|
||||
case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
|
||||
g_warn_if_reached ();
|
||||
config = create_for_switch_config_all_mirror (config_manager);
|
||||
break;
|
||||
case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
|
||||
config = meta_monitor_config_manager_create_linear (config_manager);
|
||||
break;
|
||||
case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
|
||||
config = create_for_switch_config_external (config_manager);
|
||||
break;
|
||||
case META_MONITOR_SWITCH_CONFIG_BUILTIN:
|
||||
config = create_for_switch_config_builtin (config_manager);
|
||||
break;
|
||||
case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
if (config)
|
||||
meta_monitors_config_set_switch_config (config, config_type);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1217,6 +1239,19 @@ meta_monitors_config_key_equal (gconstpointer data_a,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaMonitorSwitchConfigType
|
||||
meta_monitors_config_get_switch_config (MetaMonitorsConfig *config)
|
||||
{
|
||||
return config->switch_config;
|
||||
}
|
||||
|
||||
void
|
||||
meta_monitors_config_set_switch_config (MetaMonitorsConfig *config,
|
||||
MetaMonitorSwitchConfigType switch_config)
|
||||
{
|
||||
config->switch_config = switch_config;
|
||||
}
|
||||
|
||||
MetaMonitorsConfig *
|
||||
meta_monitors_config_new_full (GList *logical_monitor_configs,
|
||||
GList *disabled_monitor_specs,
|
||||
@@ -1232,6 +1267,7 @@ meta_monitors_config_new_full (GList *logical_monitor_con
|
||||
disabled_monitor_specs);
|
||||
config->layout_mode = layout_mode;
|
||||
config->flags = flags;
|
||||
config->switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,8 @@ struct _MetaMonitorsConfig
|
||||
MetaMonitorsConfigFlag flags;
|
||||
|
||||
MetaLogicalMonitorLayoutMode layout_mode;
|
||||
|
||||
MetaMonitorSwitchConfigType switch_config;
|
||||
};
|
||||
|
||||
#define META_TYPE_MONITORS_CONFIG (meta_monitors_config_get_type ())
|
||||
@@ -124,6 +126,11 @@ MetaMonitorsConfig * meta_monitors_config_new (MetaMonitorManager *mon
|
||||
MetaLogicalMonitorLayoutMode layout_mode,
|
||||
MetaMonitorsConfigFlag flags);
|
||||
|
||||
MetaMonitorSwitchConfigType meta_monitors_config_get_switch_config (MetaMonitorsConfig *config);
|
||||
|
||||
void meta_monitors_config_set_switch_config (MetaMonitorsConfig *config,
|
||||
MetaMonitorSwitchConfigType switch_config);
|
||||
|
||||
unsigned int meta_monitors_config_key_hash (gconstpointer config_key);
|
||||
|
||||
gboolean meta_monitors_config_key_equal (gconstpointer config_key_a,
|
||||
|
||||
@@ -2652,8 +2652,6 @@ meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
|
||||
static void
|
||||
meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
|
||||
{
|
||||
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
||||
|
||||
meta_backend_monitors_changed (manager->backend);
|
||||
|
||||
g_signal_emit (manager, signals[MONITORS_CHANGED_INTERNAL], 0);
|
||||
@@ -2710,10 +2708,17 @@ meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
|
||||
MetaMonitorsConfig *config)
|
||||
{
|
||||
if (config)
|
||||
manager->layout_mode = config->layout_mode;
|
||||
{
|
||||
manager->layout_mode = config->layout_mode;
|
||||
manager->current_switch_config =
|
||||
meta_monitors_config_get_switch_config (config);
|
||||
}
|
||||
else
|
||||
manager->layout_mode =
|
||||
meta_monitor_manager_get_default_layout_mode (manager);
|
||||
{
|
||||
manager->layout_mode =
|
||||
meta_monitor_manager_get_default_layout_mode (manager);
|
||||
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
||||
}
|
||||
|
||||
meta_monitor_manager_rebuild_logical_monitors (manager, config);
|
||||
}
|
||||
@@ -2755,6 +2760,12 @@ void
|
||||
meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager,
|
||||
MetaMonitorsConfig *config)
|
||||
{
|
||||
if (config)
|
||||
manager->current_switch_config =
|
||||
meta_monitors_config_get_switch_config (config);
|
||||
else
|
||||
manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
|
||||
|
||||
manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
||||
|
||||
meta_monitor_manager_rebuild_logical_monitors_derived (manager, config);
|
||||
|
||||
@@ -710,6 +710,7 @@ static void
|
||||
cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
|
||||
{
|
||||
g_hash_table_destroy (cursor_priv->gpu_states);
|
||||
g_free (cursor_priv);
|
||||
}
|
||||
|
||||
static MetaCursorNativePrivate *
|
||||
|
||||
@@ -60,6 +60,10 @@ struct _MetaBackendX11Private
|
||||
XSyncAlarm user_active_alarm;
|
||||
XSyncCounter counter;
|
||||
|
||||
int current_touch_replay_sync_serial;
|
||||
int pending_touch_replay_sync_serial;
|
||||
Atom touch_replay_sync_atom;
|
||||
|
||||
int xinput_opcode;
|
||||
int xinput_event_base;
|
||||
int xinput_error_base;
|
||||
@@ -168,6 +172,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11,
|
||||
backend_x11_class->translate_device_event (x11, device_event);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11,
|
||||
XIDeviceEvent *device_event)
|
||||
{
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
|
||||
if (!device_event->send_event &&
|
||||
device_event->time != CurrentTime &&
|
||||
priv->current_touch_replay_sync_serial !=
|
||||
priv->pending_touch_replay_sync_serial &&
|
||||
XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
|
||||
{
|
||||
/* Emulated pointer events received after XIRejectTouch is received
|
||||
* on a passive touch grab will contain older timestamps, update those
|
||||
* so we dont get InvalidTime at grabs.
|
||||
*/
|
||||
device_event->time = priv->latest_evtime;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
translate_device_event (MetaBackendX11 *x11,
|
||||
XIDeviceEvent *device_event)
|
||||
@@ -177,19 +201,7 @@ translate_device_event (MetaBackendX11 *x11,
|
||||
meta_backend_x11_translate_device_event (x11, device_event);
|
||||
|
||||
if (!device_event->send_event && device_event->time != CurrentTime)
|
||||
{
|
||||
if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
|
||||
{
|
||||
/* Emulated pointer events received after XIRejectTouch is received
|
||||
* on a passive touch grab will contain older timestamps, update those
|
||||
* so we dont get InvalidTime at grabs.
|
||||
*/
|
||||
device_event->time = priv->latest_evtime;
|
||||
}
|
||||
|
||||
/* Update the internal latest evtime, for any possible later use */
|
||||
priv->latest_evtime = device_event->time;
|
||||
}
|
||||
priv->latest_evtime = device_event->time;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -254,6 +266,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
|
||||
case XI_Motion:
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
maybe_translate_touch_replay_pointer_event (x11,
|
||||
(XIDeviceEvent *) input_event);
|
||||
/* Intentional fall-through */
|
||||
case XI_KeyPress:
|
||||
case XI_KeyRelease:
|
||||
case XI_TouchBegin:
|
||||
@@ -321,6 +336,17 @@ handle_host_xevent (MetaBackend *backend,
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
gboolean bypass_clutter = FALSE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case ClientMessage:
|
||||
if (event->xclient.window == meta_backend_x11_get_xwindow (x11) &&
|
||||
event->xclient.message_type == priv->touch_replay_sync_atom)
|
||||
priv->current_touch_replay_sync_serial = event->xclient.data.l[0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
XGetEventData (priv->xdisplay, &event->xcookie);
|
||||
|
||||
{
|
||||
@@ -528,6 +554,10 @@ meta_backend_x11_post_init (MetaBackend *backend)
|
||||
monitor_manager = meta_backend_get_monitor_manager (backend);
|
||||
g_signal_connect (monitor_manager, "monitors-changed-internal",
|
||||
G_CALLBACK (on_monitors_changed), backend);
|
||||
|
||||
priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
|
||||
"_MUTTER_TOUCH_SEQUENCE_SYNC",
|
||||
False);
|
||||
}
|
||||
|
||||
static ClutterBackend *
|
||||
@@ -584,6 +614,43 @@ meta_backend_x11_ungrab_device (MetaBackend *backend,
|
||||
return (ret == Success);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_finish_touch_sequence (MetaBackend *backend,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
int event_mode;
|
||||
|
||||
if (state == META_SEQUENCE_ACCEPTED)
|
||||
event_mode = XIAcceptTouch;
|
||||
else if (state == META_SEQUENCE_REJECTED)
|
||||
event_mode = XIRejectTouch;
|
||||
else
|
||||
g_return_if_reached ();
|
||||
|
||||
XIAllowTouchEvents (priv->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
clutter_x11_event_sequence_get_touch_detail (sequence),
|
||||
DefaultRootWindow (priv->xdisplay), event_mode);
|
||||
|
||||
if (state == META_SEQUENCE_REJECTED)
|
||||
{
|
||||
XClientMessageEvent ev;
|
||||
|
||||
ev = (XClientMessageEvent) {
|
||||
.type = ClientMessage,
|
||||
.window = meta_backend_x11_get_xwindow (x11),
|
||||
.message_type = priv->touch_replay_sync_atom,
|
||||
.format = 32,
|
||||
.data.l[0] = ++priv->pending_touch_replay_sync_serial,
|
||||
};
|
||||
XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11),
|
||||
False, 0, (XEvent *) &ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_warp_pointer (MetaBackend *backend,
|
||||
int x,
|
||||
@@ -769,6 +836,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
|
||||
backend_class->post_init = meta_backend_x11_post_init;
|
||||
backend_class->grab_device = meta_backend_x11_grab_device;
|
||||
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
|
||||
backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
|
||||
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
|
||||
backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
|
||||
backend_class->get_keymap = meta_backend_x11_get_keymap;
|
||||
|
||||
@@ -73,4 +73,6 @@ MetaCloseDialog * meta_compositor_create_close_dialog (MetaCompositor *composito
|
||||
MetaInhibitShortcutsDialog * meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_compositor_unmanage_window_actors (MetaCompositor *compositor);
|
||||
|
||||
#endif /* META_COMPOSITOR_PRIVATE_H */
|
||||
|
||||
@@ -145,19 +145,6 @@ meta_compositor_destroy (MetaCompositor *compositor)
|
||||
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 ();
|
||||
}
|
||||
@@ -610,6 +597,23 @@ meta_compositor_unmanage (MetaCompositor *compositor)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_unmanage_window_actors (MetaCompositor *compositor)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shape_cow_for_window:
|
||||
* @compositor: A #MetaCompositor
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/meta-input-settings-private.h"
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
|
||||
#ifdef HAVE_RANDR
|
||||
@@ -533,27 +534,23 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
|
||||
MetaSequenceState state,
|
||||
MetaDisplay *display)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
switch (state)
|
||||
{
|
||||
if (state == META_SEQUENCE_ACCEPTED)
|
||||
meta_display_cancel_touch (display);
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||
int event_mode;
|
||||
case META_SEQUENCE_NONE:
|
||||
case META_SEQUENCE_PENDING_END:
|
||||
return;
|
||||
case META_SEQUENCE_ACCEPTED:
|
||||
meta_display_cancel_touch (display);
|
||||
|
||||
if (state == META_SEQUENCE_ACCEPTED)
|
||||
event_mode = XIAcceptTouch;
|
||||
else if (state == META_SEQUENCE_REJECTED)
|
||||
event_mode = XIRejectTouch;
|
||||
else
|
||||
return;
|
||||
/* Intentional fall-through */
|
||||
case META_SEQUENCE_REJECTED:
|
||||
{
|
||||
MetaBackend *backend;
|
||||
|
||||
XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
clutter_x11_event_sequence_get_touch_detail (sequence),
|
||||
DefaultRootWindow (display->xdisplay), event_mode);
|
||||
backend = meta_get_backend ();
|
||||
meta_backend_finish_touch_sequence (backend, sequence, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,7 @@
|
||||
typedef struct _MetaGestureTracker MetaGestureTracker;
|
||||
typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
|
||||
|
||||
typedef enum {
|
||||
META_SEQUENCE_NONE,
|
||||
META_SEQUENCE_ACCEPTED,
|
||||
META_SEQUENCE_REJECTED,
|
||||
META_SEQUENCE_PENDING_END
|
||||
} MetaSequenceState;
|
||||
typedef enum _MetaSequenceState MetaSequenceState;
|
||||
|
||||
struct _MetaGestureTracker
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "config.h"
|
||||
#include "meta-gesture-tracker-private.h"
|
||||
#include "meta-surface-actor.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
#define DISTANCE_THRESHOLD 30
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "stack.h"
|
||||
#include <meta/compositor.h>
|
||||
#include <meta/meta-enum-types.h>
|
||||
#include "compositor-private.h"
|
||||
#include "core.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "boxes-private.h"
|
||||
@@ -835,6 +836,7 @@ meta_screen_free (MetaScreen *screen,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
GList *l;
|
||||
|
||||
display = screen->display;
|
||||
|
||||
@@ -844,6 +846,8 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
|
||||
|
||||
meta_compositor_unmanage_window_actors (display->compositor);
|
||||
|
||||
meta_prefs_remove_listener (prefs_changed_callback, screen);
|
||||
|
||||
meta_screen_ungrab_keys (screen);
|
||||
@@ -874,6 +878,16 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
g_free (screen->screen_name);
|
||||
|
||||
screen->active_workspace = NULL;
|
||||
|
||||
for (l = screen->workspaces; l;)
|
||||
{
|
||||
MetaWorkspace *workspace = l->data;
|
||||
l = l->next;
|
||||
|
||||
meta_workspace_remove (workspace);
|
||||
}
|
||||
|
||||
g_object_unref (screen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1176,6 +1176,27 @@ window_contains_point (MetaWindow *window,
|
||||
return POINT_IN_RECT (root_x, root_y, rect);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_can_get_default_focus (MetaWindow *window)
|
||||
{
|
||||
if (window->unmaps_pending > 0)
|
||||
return FALSE;
|
||||
|
||||
if (window->unmanaging)
|
||||
return FALSE;
|
||||
|
||||
if (!(window->input || window->take_focus))
|
||||
return FALSE;
|
||||
|
||||
if (!meta_window_should_be_showing (window))
|
||||
return FALSE;
|
||||
|
||||
if (window->type == META_WINDOW_DOCK)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static MetaWindow*
|
||||
get_default_focus_window (MetaStack *stack,
|
||||
MetaWorkspace *workspace,
|
||||
@@ -1203,24 +1224,12 @@ get_default_focus_window (MetaStack *stack,
|
||||
if (window == not_this_one)
|
||||
continue;
|
||||
|
||||
if (window->unmaps_pending > 0)
|
||||
continue;
|
||||
|
||||
if (window->unmanaging)
|
||||
continue;
|
||||
|
||||
if (!(window->input || window->take_focus))
|
||||
continue;
|
||||
|
||||
if (!meta_window_should_be_showing (window))
|
||||
if (!window_can_get_default_focus (window))
|
||||
continue;
|
||||
|
||||
if (must_be_at_point && !window_contains_point (window, root_x, root_y))
|
||||
continue;
|
||||
|
||||
if (window->type == META_WINDOW_DOCK)
|
||||
continue;
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1275,6 +1284,26 @@ meta_stack_list_windows (MetaStack *stack,
|
||||
return workspace_windows;
|
||||
}
|
||||
|
||||
GList *
|
||||
meta_stack_get_default_focus_candidates (MetaStack *stack,
|
||||
MetaWorkspace *workspace)
|
||||
{
|
||||
GList *windows = meta_stack_list_windows (stack, workspace);
|
||||
GList *l;
|
||||
|
||||
for (l = windows; l;)
|
||||
{
|
||||
GList *next = l->next;
|
||||
|
||||
if (!window_can_get_default_focus (l->data))
|
||||
windows = g_list_delete_link (windows, l);
|
||||
|
||||
l = next;
|
||||
}
|
||||
|
||||
return windows;
|
||||
}
|
||||
|
||||
int
|
||||
meta_stack_windows_cmp (MetaStack *stack,
|
||||
MetaWindow *window_a,
|
||||
|
||||
@@ -337,6 +337,21 @@ MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack *stack,
|
||||
int root_x,
|
||||
int root_y);
|
||||
|
||||
/**
|
||||
* meta_stack_get_default_focus_candidates:
|
||||
* @stack: The stack to examine.
|
||||
* @workspace: If not %NULL, only windows on this workspace will be
|
||||
* returned; otherwise all windows in the stack will be
|
||||
* returned.
|
||||
*
|
||||
* Returns all the focus candidate windows in the stack, in order.
|
||||
*
|
||||
* Returns: (transfer container) (element-type Meta.Window):
|
||||
* A #GList of #MetaWindow, in stacking order, honouring layers.
|
||||
*/
|
||||
GList * meta_stack_get_default_focus_candidates (MetaStack *stack,
|
||||
MetaWorkspace *workspace);
|
||||
|
||||
/**
|
||||
* meta_stack_list_windows:
|
||||
* @stack: The stack to examine.
|
||||
|
||||
@@ -1272,11 +1272,10 @@ _meta_window_shared_new (MetaDisplay *display,
|
||||
window->desc, window->transient_for->desc);
|
||||
|
||||
set_workspace_state (window,
|
||||
window->transient_for->on_all_workspaces_requested,
|
||||
window->transient_for->on_all_workspaces,
|
||||
window->transient_for->workspace);
|
||||
}
|
||||
|
||||
if (window->on_all_workspaces)
|
||||
else if (window->on_all_workspaces)
|
||||
{
|
||||
meta_topic (META_DEBUG_PLACEMENT,
|
||||
"Putting window %s on all workspaces\n",
|
||||
@@ -3622,6 +3621,13 @@ meta_window_activate_full (MetaWindow *window,
|
||||
MetaWorkspace *workspace)
|
||||
{
|
||||
gboolean allow_workspace_switch;
|
||||
|
||||
if (window->unmanaging)
|
||||
{
|
||||
g_warning ("Trying to activate unmanaged window '%s'", window->desc);
|
||||
return;
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"_NET_ACTIVE_WINDOW message sent for %s at time %u "
|
||||
"by client type %u.\n",
|
||||
|
||||
@@ -85,6 +85,12 @@ typedef struct _MetaWorkspaceLogicalMonitorData
|
||||
MetaRectangle logical_monitor_work_area;
|
||||
} MetaWorkspaceLogicalMonitorData;
|
||||
|
||||
typedef struct _MetaWorkspaceFocusableAncestorData
|
||||
{
|
||||
MetaWorkspace *workspace;
|
||||
MetaWindow *out_window;
|
||||
} MetaWorkspaceFocusableAncestorData;
|
||||
|
||||
static MetaWorkspaceLogicalMonitorData *
|
||||
meta_workspace_get_logical_monitor_data (MetaWorkspace *workspace,
|
||||
MetaLogicalMonitor *logical_monitor)
|
||||
@@ -1319,13 +1325,20 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
record_ancestor (MetaWindow *window,
|
||||
void *data)
|
||||
find_focusable_ancestor (MetaWindow *window,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaWindow **result = data;
|
||||
MetaWorkspaceFocusableAncestorData *data = user_data;
|
||||
|
||||
*result = window;
|
||||
return FALSE; /* quit with the first ancestor we find */
|
||||
if (!window->unmanaging && (window->input || window->take_focus) &&
|
||||
meta_window_located_on_workspace (window, data->workspace) &&
|
||||
meta_window_showing_on_its_workspace (window))
|
||||
{
|
||||
data->out_window = window;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Focus ancestor of not_this_one if there is one */
|
||||
@@ -1347,11 +1360,15 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace,
|
||||
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))
|
||||
MetaWorkspaceFocusableAncestorData data;
|
||||
|
||||
data = (MetaWorkspaceFocusableAncestorData) {
|
||||
.workspace = workspace,
|
||||
};
|
||||
meta_window_foreach_ancestor (not_this_one, find_focusable_ancestor, &data);
|
||||
ancestor = data.out_window;
|
||||
|
||||
if (ancestor)
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing %s, ancestor of %s\n",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
can_take_focus 1/2 false
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
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,30 @@
|
||||
new_client 2 x11
|
||||
create 2/1
|
||||
show 2/1
|
||||
wait
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
accept_focus 1/1 false
|
||||
can_take_focus 1/1 false
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
can_take_focus 1/2 false
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
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
|
||||
@@ -0,0 +1,36 @@
|
||||
new_client 2 x11
|
||||
create 2/1
|
||||
show 2/1
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
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
|
||||
sleep 10
|
||||
|
||||
assert_focused none
|
||||
assert_stacking 2/1 1/1 1/2
|
||||
|
||||
activate 2/1
|
||||
wait
|
||||
|
||||
assert_focused 2/1
|
||||
assert_stacking 1/1 1/2 2/1
|
||||
|
||||
sleep 250
|
||||
assert_focused 2/1
|
||||
assert_stacking 1/1 1/2 2/1
|
||||
30
src/tests/stacking/closed-transient-no-input-parent.metatest
Normal file
30
src/tests/stacking/closed-transient-no-input-parent.metatest
Normal file
@@ -0,0 +1,30 @@
|
||||
new_client 2 x11
|
||||
create 2/1
|
||||
show 2/1
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
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
|
||||
dispatch
|
||||
|
||||
assert_focused none
|
||||
assert_stacking 2/1 1/1 1/2
|
||||
|
||||
sleep 150
|
||||
assert_focused 1/1
|
||||
assert_stacking 2/1 1/1 1/2
|
||||
@@ -0,0 +1,43 @@
|
||||
new_client 0 x11
|
||||
create 0/1
|
||||
show 0/1
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
create 1/3 csd
|
||||
set_parent 1/3 2
|
||||
accept_focus 1/3 false
|
||||
show 1/3
|
||||
|
||||
create 1/4 csd
|
||||
set_parent 1/4 3
|
||||
accept_focus 1/4 false
|
||||
show 1/4
|
||||
|
||||
create 1/5 csd
|
||||
set_parent 1/5 3
|
||||
show 1/5
|
||||
|
||||
wait
|
||||
assert_focused 1/5
|
||||
assert_stacking 0/1 1/1 1/2 1/3 1/4 1/5
|
||||
|
||||
destroy 1/5
|
||||
dispatch
|
||||
|
||||
assert_focused none
|
||||
assert_stacking 0/1 1/1 1/2 1/3 1/4
|
||||
|
||||
destroy 1/2
|
||||
dispatch
|
||||
|
||||
sleep 450
|
||||
assert_focused 1/1
|
||||
assert_stacking 0/1 1/1 1/3 1/4
|
||||
@@ -0,0 +1,46 @@
|
||||
new_client 0 x11
|
||||
create 0/1
|
||||
show 0/1
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
accept_focus 1/2 false
|
||||
show 1/2
|
||||
|
||||
create 1/3 csd
|
||||
set_parent 1/3 2
|
||||
accept_focus 1/3 false
|
||||
show 1/3
|
||||
|
||||
create 1/4 csd
|
||||
set_parent 1/4 3
|
||||
accept_focus 1/4 false
|
||||
show 1/4
|
||||
|
||||
create 1/5 csd
|
||||
set_parent 1/5 3
|
||||
show 1/5
|
||||
|
||||
wait
|
||||
assert_focused 1/5
|
||||
assert_stacking 0/1 1/1 1/2 1/3 1/4 1/5
|
||||
|
||||
destroy 1/5
|
||||
dispatch
|
||||
|
||||
assert_focused none
|
||||
assert_stacking 0/1 1/1 1/2 1/3 1/4
|
||||
|
||||
sleep 600
|
||||
assert_focused 1/1
|
||||
assert_stacking 0/1 1/1 1/2 1/3 1/4
|
||||
|
||||
destroy 1/3
|
||||
wait
|
||||
|
||||
assert_focused 1/1
|
||||
assert_stacking 0/1 1/1 1/2 1/4
|
||||
@@ -161,6 +161,74 @@ process_line (const char *line)
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window),
|
||||
GTK_WINDOW (parent_window));
|
||||
}
|
||||
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], "can_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_new0 (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)
|
||||
|
||||
@@ -113,7 +113,7 @@ test_case_new (void)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_before_redraw (gpointer data)
|
||||
test_case_loop_quit (gpointer data)
|
||||
{
|
||||
TestCase *test = data;
|
||||
|
||||
@@ -122,6 +122,24 @@ test_case_before_redraw (gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_dispatch (TestCase *test,
|
||||
GError **error)
|
||||
{
|
||||
/* Wait until we've done any outstanding queued up work.
|
||||
* Though we add this as BEFORE_REDRAW, the iteration that runs the
|
||||
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
|
||||
* waiting until after *all* frame processing.
|
||||
*/
|
||||
meta_later_add (META_LATER_BEFORE_REDRAW,
|
||||
test_case_loop_quit,
|
||||
test,
|
||||
NULL);
|
||||
g_main_loop_run (test->loop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_wait (TestCase *test,
|
||||
GError **error)
|
||||
@@ -138,16 +156,8 @@ test_case_wait (TestCase *test,
|
||||
if (!test_client_wait (value, error))
|
||||
return FALSE;
|
||||
|
||||
/* Then wait until we've done any outstanding queued up work.
|
||||
* Though we add this as BEFORE_REDRAW, the iteration that runs the
|
||||
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
|
||||
* waiting until after *all* frame processing.
|
||||
*/
|
||||
meta_later_add (META_LATER_BEFORE_REDRAW,
|
||||
test_case_before_redraw,
|
||||
test,
|
||||
NULL);
|
||||
g_main_loop_run (test->loop);
|
||||
/* Then wait until we've done any outstanding queued up work. */
|
||||
test_case_dispatch (test, error);
|
||||
|
||||
/* Then set an XSync counter ourselves and and wait until
|
||||
* we receive the resulting event - this makes sure that we've
|
||||
@@ -157,6 +167,17 @@ test_case_wait (TestCase *test,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_sleep (TestCase *test,
|
||||
guint32 interval,
|
||||
GError **error)
|
||||
{
|
||||
g_timeout_add_full (G_PRIORITY_LOW, interval, test_case_loop_quit, test, NULL);
|
||||
g_main_loop_run (test->loop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define BAD_COMMAND(...) \
|
||||
G_STMT_START { \
|
||||
g_set_error (error, \
|
||||
@@ -273,6 +294,37 @@ 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_strcmp0 (expected_window, "none") != 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,
|
||||
"focus: expected='%s', actual='%s'",
|
||||
expected_window, focused);
|
||||
}
|
||||
|
||||
return *error == NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_check_xserver_stacking (TestCase *test,
|
||||
GError **error)
|
||||
@@ -406,6 +458,44 @@ test_case_do (TestCase *test,
|
||||
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], "can_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],
|
||||
NULL))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (argv[0], "show") == 0 ||
|
||||
strcmp (argv[0], "hide") == 0 ||
|
||||
strcmp (argv[0], "activate") == 0 ||
|
||||
@@ -450,6 +540,28 @@ test_case_do (TestCase *test,
|
||||
if (!test_case_wait (test, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (argv[0], "dispatch") == 0)
|
||||
{
|
||||
if (argc != 1)
|
||||
BAD_COMMAND("usage: %s", argv[0]);
|
||||
|
||||
if (!test_case_dispatch (test, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (argv[0], "sleep") == 0)
|
||||
{
|
||||
guint64 interval;
|
||||
|
||||
if (argc != 2)
|
||||
BAD_COMMAND("usage: %s <milliseconds>", argv[0]);
|
||||
|
||||
if (!g_ascii_string_to_unsigned (argv[1], 10, 0, G_MAXUINT32,
|
||||
&interval, error))
|
||||
return FALSE;
|
||||
|
||||
if (!test_case_sleep (test, (guint32) interval, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (argv[0], "assert_stacking") == 0)
|
||||
{
|
||||
if (!test_case_assert_stacking (test, argv + 1, argc - 1, error))
|
||||
@@ -458,6 +570,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]);
|
||||
|
||||
@@ -264,7 +264,7 @@ meta_wayland_seat_free (MetaWaylandSeat *seat)
|
||||
g_object_unref (seat->touch);
|
||||
meta_wayland_text_input_destroy (seat->text_input);
|
||||
|
||||
g_slice_free (MetaWaylandSeat, seat);
|
||||
g_free (seat);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -53,8 +53,15 @@
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
#define TAKE_FOCUS_FALLBACK_DELAY_MS 150
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW)
|
||||
|
||||
static void
|
||||
meta_window_x11_maybe_focus_delayed (MetaWindow *window,
|
||||
GQueue *other_focus_candidates,
|
||||
guint32 timestamp);
|
||||
|
||||
static void
|
||||
meta_window_x11_init (MetaWindowX11 *window_x11)
|
||||
{
|
||||
@@ -722,6 +729,160 @@ request_take_focus (MetaWindow *window,
|
||||
send_icccm_message (window, display->atom_WM_TAKE_FOCUS, timestamp);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaWindow *window;
|
||||
GQueue *pending_focus_candidates;
|
||||
guint32 timestamp;
|
||||
guint timeout_id;
|
||||
gulong unmanaged_id;
|
||||
gulong focused_changed_id;
|
||||
} MetaWindowX11DelayedFocusData;
|
||||
|
||||
static void
|
||||
disconnect_pending_focus_window_signals (MetaWindow *window,
|
||||
GQueue *focus_candidates)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (window, g_queue_remove,
|
||||
focus_candidates);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_delayed_focus_data_free (MetaWindowX11DelayedFocusData *data)
|
||||
{
|
||||
g_signal_handler_disconnect (data->window, data->unmanaged_id);
|
||||
g_signal_handler_disconnect (data->window->display, data->focused_changed_id);
|
||||
|
||||
if (data->pending_focus_candidates)
|
||||
{
|
||||
g_queue_foreach (data->pending_focus_candidates,
|
||||
(GFunc) disconnect_pending_focus_window_signals,
|
||||
data->pending_focus_candidates);
|
||||
g_queue_free (data->pending_focus_candidates);
|
||||
}
|
||||
|
||||
if (data->timeout_id)
|
||||
g_source_remove (data->timeout_id);
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
focus_candidates_maybe_take_and_focus_next (GQueue **focus_candidates_ptr,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWindow *focus_window;
|
||||
GQueue *focus_candidates;
|
||||
|
||||
g_assert (*focus_candidates_ptr);
|
||||
|
||||
if (g_queue_is_empty (*focus_candidates_ptr))
|
||||
return;
|
||||
|
||||
focus_candidates = g_steal_pointer (focus_candidates_ptr);
|
||||
focus_window = g_queue_pop_head (focus_candidates);
|
||||
|
||||
disconnect_pending_focus_window_signals (focus_window, focus_candidates);
|
||||
meta_window_x11_maybe_focus_delayed (focus_window, focus_candidates, timestamp);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_window_delayed_timeout (gpointer user_data)
|
||||
{
|
||||
MetaWindowX11DelayedFocusData *data = user_data;
|
||||
MetaWindow *window = data->window;
|
||||
guint32 timestamp = data->timestamp;
|
||||
|
||||
focus_candidates_maybe_take_and_focus_next (&data->pending_focus_candidates,
|
||||
timestamp);
|
||||
|
||||
data->timeout_id = 0;
|
||||
meta_window_x11_delayed_focus_data_free (data);
|
||||
|
||||
meta_window_focus (window, timestamp);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_maybe_focus_delayed (MetaWindow *window,
|
||||
GQueue *other_focus_candidates,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWindowX11DelayedFocusData *data;
|
||||
|
||||
data = g_new0 (MetaWindowX11DelayedFocusData, 1);
|
||||
data->window = window;
|
||||
data->timestamp = timestamp;
|
||||
data->pending_focus_candidates = other_focus_candidates;
|
||||
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Requesting delayed focus to %s\n", window->desc);
|
||||
|
||||
data->unmanaged_id =
|
||||
g_signal_connect_swapped (window, "unmanaged",
|
||||
G_CALLBACK (meta_window_x11_delayed_focus_data_free),
|
||||
data);
|
||||
|
||||
data->focused_changed_id =
|
||||
g_signal_connect_swapped (window->display, "notify::focus-window",
|
||||
G_CALLBACK (meta_window_x11_delayed_focus_data_free),
|
||||
data);
|
||||
|
||||
data->timeout_id = g_timeout_add (TAKE_FOCUS_FALLBACK_DELAY_MS,
|
||||
focus_window_delayed_timeout, data);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_focus_default_window (MetaScreen *screen,
|
||||
MetaWindow *not_this_one,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWorkspace *workspace;
|
||||
MetaStack *stack = screen->stack;
|
||||
g_autoptr (GList) focusable_windows = NULL;
|
||||
g_autoptr (GQueue) focus_candidates = NULL;
|
||||
GList *l;
|
||||
|
||||
if (not_this_one && not_this_one->workspace)
|
||||
workspace = not_this_one->workspace;
|
||||
else
|
||||
workspace = screen->active_workspace;
|
||||
|
||||
/* Go through all the focusable windows and try to focus them
|
||||
* in order, waiting for a delay. The first one that replies to
|
||||
* the request (in case of take focus windows) changing the display
|
||||
* focused window, will stop the chained requests.
|
||||
*/
|
||||
focusable_windows =
|
||||
meta_stack_get_default_focus_candidates (stack, workspace);
|
||||
focus_candidates = g_queue_new ();
|
||||
|
||||
for (l = g_list_last (focusable_windows); l; l = l->prev)
|
||||
{
|
||||
MetaWindow *focus_window = l->data;
|
||||
|
||||
if (focus_window == not_this_one)
|
||||
continue;
|
||||
|
||||
g_queue_push_tail (focus_candidates, focus_window);
|
||||
g_signal_connect_swapped (focus_window, "unmanaged",
|
||||
G_CALLBACK (g_queue_remove),
|
||||
focus_candidates);
|
||||
|
||||
if (!META_IS_WINDOW_X11 (focus_window))
|
||||
break;
|
||||
|
||||
if (focus_window->input)
|
||||
break;
|
||||
|
||||
if (focus_window->shaded && focus_window->frame)
|
||||
break;
|
||||
}
|
||||
|
||||
focus_candidates_maybe_take_and_focus_next (&focus_candidates, timestamp);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_focus (MetaWindow *window,
|
||||
guint32 timestamp)
|
||||
@@ -771,14 +932,19 @@ 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 no focus window before sending WM_TAKE_FOCUS,
|
||||
* and eventually the default focus windwo excluding this one,
|
||||
* if meanwhile we don't get any focus request.
|
||||
*/
|
||||
if (window->display->focus_window != NULL &&
|
||||
window->display->focus_window->unmanaging)
|
||||
meta_display_focus_the_no_focus_window (window->display,
|
||||
window->screen,
|
||||
timestamp);
|
||||
{
|
||||
meta_display_focus_the_no_focus_window (window->display,
|
||||
window->screen,
|
||||
timestamp);
|
||||
maybe_focus_default_window (window->screen, window,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
request_take_focus (window, timestamp);
|
||||
|
||||
Reference in New Issue
Block a user