Compare commits
59 Commits
wip/carlos
...
gnome-3-32
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c2e12b3434 | ||
![]() |
002299fbef | ||
![]() |
f0b7cf4d91 | ||
![]() |
ad4dbefbc0 | ||
![]() |
5a486f5b6b | ||
![]() |
bb5c7b97ba | ||
![]() |
b7f1588119 | ||
![]() |
88e492cac0 | ||
![]() |
ed03ce53b2 | ||
![]() |
ccab0f470d | ||
![]() |
61691bacc8 | ||
![]() |
63f3f5d59f | ||
![]() |
80869e0737 | ||
![]() |
763092a4b6 | ||
![]() |
e50cdda4ff | ||
![]() |
c50df14311 | ||
![]() |
194d93efd8 | ||
![]() |
947da2c5d5 | ||
![]() |
0a8fbbe5cc | ||
![]() |
001076339a | ||
![]() |
0d570f2dd3 | ||
![]() |
c5fb1d1975 | ||
![]() |
83ce89ef59 | ||
![]() |
da3195288b | ||
![]() |
8b986cd065 | ||
![]() |
5efb11acad | ||
![]() |
2db94e2e40 | ||
![]() |
866d6780c9 | ||
![]() |
9009f8d48f | ||
![]() |
3d9771b25a | ||
![]() |
1be5a57ade | ||
![]() |
afcea966c0 | ||
![]() |
9c079a5261 | ||
![]() |
d56bd28f64 | ||
![]() |
225d18761a | ||
![]() |
e0922bffea | ||
![]() |
8307c0f7ab | ||
![]() |
cded69da61 | ||
![]() |
a3a97621be | ||
![]() |
8b79c83ad5 | ||
![]() |
2ce4a20c8e | ||
![]() |
fb03e198e5 | ||
![]() |
07c9cd498d | ||
![]() |
e716f9d143 | ||
![]() |
13a1624c10 | ||
![]() |
30d6e3abe2 | ||
![]() |
18e44bb64c | ||
![]() |
15803b9558 | ||
![]() |
3fdc651179 | ||
![]() |
189f71f5d1 | ||
![]() |
0a3cddeecf | ||
![]() |
ee92e4fe13 | ||
![]() |
6933ce0976 | ||
![]() |
f9d6627fe0 | ||
![]() |
668c44e66b | ||
![]() |
3495a43810 | ||
![]() |
9a795d3d0f | ||
![]() |
abc3fdcc65 | ||
![]() |
4705a31049 |
11
NEWS
11
NEWS
@@ -1,3 +1,14 @@
|
||||
3.32.2
|
||||
======
|
||||
* Disable mouse keys with Numlock on [Olivier; #530]
|
||||
* Fix crash when restarting on X11 [Marco; #576]
|
||||
* Fix mapping of touchscreens that don't report dimensions [Carlos; #581]
|
||||
* Fix spurious idle signals that prevent session unblank [Jonas; !543]
|
||||
* Misc. bug fixes and cleanups [Olivier, Marco, Carlos; !552, !557, #586]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, Marco Trevisan (Treviño)
|
||||
|
||||
3.32.1
|
||||
======
|
||||
* Fix fallback app menu on wayland [Florian; #493]
|
||||
|
@@ -1975,6 +1975,7 @@ selection_paint (ClutterText *self,
|
||||
else
|
||||
{
|
||||
/* Paint selection background first */
|
||||
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
|
||||
PangoLayout *layout = clutter_text_get_layout (self);
|
||||
CoglPath *selection_path = cogl_path_new ();
|
||||
CoglColor cogl_color = { 0, };
|
||||
@@ -1987,11 +1988,19 @@ selection_paint (ClutterText *self,
|
||||
else
|
||||
color = &priv->text_color;
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color,
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
paint_opacity * color->alpha / 255);
|
||||
cogl_color_premultiply (&cogl_color);
|
||||
cogl_pipeline_set_color (color_pipeline, &cogl_color);
|
||||
|
||||
clutter_text_foreach_selection_rectangle_prescaled (self,
|
||||
add_selection_rectangle_to_path,
|
||||
selection_path);
|
||||
|
||||
cogl_path_fill (selection_path);
|
||||
cogl_framebuffer_fill_path (fb, color_pipeline, selection_path);
|
||||
|
||||
/* Paint selected text */
|
||||
cogl_framebuffer_push_path_clip (fb, selection_path);
|
||||
|
@@ -855,6 +855,14 @@ emulate_pointer_motion (ClutterInputDeviceEvdev *device,
|
||||
clutter_virtual_input_device_notify_relative_motion (device->mousekeys_virtual_device,
|
||||
time_us, dx_motion, dy_motion);
|
||||
}
|
||||
static gboolean
|
||||
is_numlock_active (ClutterInputDeviceEvdev *device)
|
||||
{
|
||||
ClutterSeatEvdev *seat = device->seat;
|
||||
return xkb_state_mod_name_is_active (seat->xkb,
|
||||
"Mod2",
|
||||
XKB_STATE_MODS_LOCKED);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_mousekeys (ClutterInputDeviceEvdev *device)
|
||||
@@ -1013,6 +1021,10 @@ handle_mousekeys_press (ClutterEvent *event,
|
||||
if (!(event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
|
||||
stop_mousekeys_move (device);
|
||||
|
||||
/* Do not handle mousekeys if NumLock is ON */
|
||||
if (is_numlock_active (device))
|
||||
return FALSE;
|
||||
|
||||
/* Button selection */
|
||||
switch (event->key.keyval)
|
||||
{
|
||||
@@ -1084,6 +1096,10 @@ static gboolean
|
||||
handle_mousekeys_release (ClutterEvent *event,
|
||||
ClutterInputDeviceEvdev *device)
|
||||
{
|
||||
/* Do not handle mousekeys if NumLock is ON */
|
||||
if (is_numlock_active (device))
|
||||
return FALSE;
|
||||
|
||||
switch (event->key.keyval)
|
||||
{
|
||||
case XKB_KEY_KP_0:
|
||||
|
@@ -54,6 +54,7 @@
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-settings-private.h"
|
||||
#include "clutter-xkb-a11y-x11.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND)
|
||||
|
||||
@@ -276,6 +277,20 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
|
||||
_clutter_backend_add_event_translator (backend, translator);
|
||||
}
|
||||
|
||||
static void
|
||||
on_keymap_state_change (ClutterKeymapX11 *keymap_x11,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data);
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
|
||||
/* On keymaps state change, just reapply the current settings, it'll
|
||||
* take care of enabling/disabling mousekeys based on NumLock state.
|
||||
*/
|
||||
clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
|
||||
clutter_device_manager_x11_apply_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11)
|
||||
{
|
||||
@@ -292,6 +307,11 @@ clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11)
|
||||
backend = CLUTTER_BACKEND (backend_x11);
|
||||
translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->keymap);
|
||||
_clutter_backend_add_event_translator (backend, translator);
|
||||
|
||||
g_signal_connect (backend_x11->keymap,
|
||||
"state-changed",
|
||||
G_CALLBACK (on_keymap_state_change),
|
||||
backend->device_manager);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -241,8 +241,13 @@ clutter_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *devi
|
||||
}
|
||||
|
||||
/* mouse keys */
|
||||
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
|
||||
if (clutter_keymap_get_num_lock_state (CLUTTER_KEYMAP (backend_x11->keymap)))
|
||||
{
|
||||
/* Disable mousekeys when NumLock is ON */
|
||||
desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask);
|
||||
}
|
||||
else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
|
||||
{
|
||||
gint mk_max_speed;
|
||||
gint mk_accel_time;
|
||||
|
@@ -460,9 +460,7 @@ cogl_path_fill (CoglPath *path);
|
||||
* use while filling a path.</note>
|
||||
*
|
||||
* Stability: unstable
|
||||
* Deprecated: 1.16: Use cogl_path_fill() instead
|
||||
*/
|
||||
COGL_DEPRECATED_FOR (cogl_path_fill)
|
||||
void
|
||||
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
@@ -492,9 +490,7 @@ cogl_path_stroke (CoglPath *path);
|
||||
* regardless of the current transformation matrix.
|
||||
*
|
||||
* Stability: unstable
|
||||
* Deprecated: 1.16: Use cogl_path_stroke() instead
|
||||
*/
|
||||
COGL_DEPRECATED_FOR (cogl_path_stroke)
|
||||
void
|
||||
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
@@ -529,9 +525,7 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
|
||||
*
|
||||
* Since: 1.8
|
||||
* Stability: Unstable
|
||||
* Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead
|
||||
*/
|
||||
COGL_DEPRECATED_FOR (cogl_framebuffer_push_path_clip)
|
||||
void
|
||||
cogl_clip_push_from_path (CoglPath *path);
|
||||
|
||||
|
@@ -1504,7 +1504,6 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
|
||||
COGL_FRAMEBUFFER_STATE_CLIP;
|
||||
}
|
||||
|
||||
/* XXX: deprecated */
|
||||
void
|
||||
cogl_clip_push_from_path (CoglPath *path)
|
||||
{
|
||||
@@ -1575,7 +1574,6 @@ _cogl_path_build_stroke_attribute_buffer (CoglPath *path)
|
||||
data->stroke_n_attributes = n_attributes;
|
||||
}
|
||||
|
||||
/* XXX: deprecated */
|
||||
void
|
||||
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
@@ -1588,7 +1586,6 @@ cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
|
||||
_cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */);
|
||||
}
|
||||
|
||||
/* XXX: deprecated */
|
||||
void
|
||||
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
|
@@ -455,9 +455,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,
|
||||
@@ -471,6 +468,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);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
project('mutter', 'c',
|
||||
version: '3.32.1',
|
||||
meson_version: '>= 0.48.0',
|
||||
version: '3.32.2',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
|
||||
|
12
po/de.po
12
po/de.po
@@ -13,9 +13,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2019-02-04 17:52+0000\n"
|
||||
"PO-Revision-Date: 2019-02-26 20:43+0100\n"
|
||||
"Last-Translator: Tim Sabsch <tim@sabsch.com>\n"
|
||||
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
|
||||
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
|
||||
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
|
||||
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -152,13 +152,15 @@ msgstr "Zur Arbeitsfläche 4 wechseln"
|
||||
msgid "Switch to last workspace"
|
||||
msgstr "Zur letzten Arbeitsfläche wechseln"
|
||||
|
||||
# Wechsel der Arbeitsfläche. Es wird nichts verschoben.
|
||||
#: data/50-mutter-navigation.xml:123
|
||||
msgid "Move to workspace above"
|
||||
msgstr "Auf Arbeitsfläche darüber verschieben"
|
||||
msgstr "Zur Arbeitsfläche darüber wechseln"
|
||||
|
||||
# Wechsel der Arbeitsfläche. Es wird nichts verschoben.
|
||||
#: data/50-mutter-navigation.xml:126
|
||||
msgid "Move to workspace below"
|
||||
msgstr "Auf Arbeitsfläche darunter verschieben"
|
||||
msgstr "Zur Arbeitsfläche darunter wechseln"
|
||||
|
||||
#: data/50-mutter-system.xml:6 data/50-mutter-wayland.xml:6
|
||||
msgid "System"
|
||||
|
@@ -49,6 +49,14 @@
|
||||
#define DEFAULT_XKB_RULES_FILE "evdev"
|
||||
#define DEFAULT_XKB_MODEL "pc105+inet"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_SEQUENCE_NONE,
|
||||
META_SEQUENCE_ACCEPTED,
|
||||
META_SEQUENCE_REJECTED,
|
||||
META_SEQUENCE_PENDING_END
|
||||
} MetaSequenceState;
|
||||
|
||||
struct _MetaBackendClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
@@ -71,6 +79,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);
|
||||
@@ -135,6 +147,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);
|
||||
|
@@ -1007,6 +1007,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)
|
||||
*/
|
||||
|
@@ -207,6 +207,8 @@ update_inhibited (MetaIdleMonitor *monitor,
|
||||
if (inhibited == monitor->inhibited)
|
||||
return;
|
||||
|
||||
monitor->inhibited = inhibited;
|
||||
|
||||
g_hash_table_foreach (monitor->watches,
|
||||
update_inhibited_watch,
|
||||
monitor);
|
||||
@@ -316,11 +318,18 @@ idle_monitor_dispatch_timeout (GSource *source,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data;
|
||||
int64_t now;
|
||||
int64_t ready_time;
|
||||
|
||||
now = g_source_get_time (source);
|
||||
ready_time = g_source_get_ready_time (source);
|
||||
if (ready_time > now)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
g_source_set_ready_time (watch->timeout_source, -1);
|
||||
|
||||
return TRUE;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs idle_monitor_source_funcs = {
|
||||
@@ -508,9 +517,16 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
monitor->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
if (monitor->inhibited)
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
monitor->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -381,7 +381,7 @@ guess_candidates (MetaInputMapper *mapper,
|
||||
info->candidates[META_MATCH_SIZE] = matched_monitor;
|
||||
}
|
||||
|
||||
if (input->builtin)
|
||||
if (input->builtin || best == N_OUTPUT_MATCHES)
|
||||
{
|
||||
best = MIN (best, META_MATCH_IS_BUILTIN);
|
||||
find_builtin_output (mapper, &info->candidates[META_MATCH_IS_BUILTIN]);
|
||||
|
@@ -1216,7 +1216,7 @@ load_keyboard_a11y_settings (MetaInputSettings *input_settings,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
ClutterKbdA11ySettings kbd_a11y_settings = { 0 };
|
||||
ClutterInputDevice *core_keyboard;
|
||||
guint i;
|
||||
|
||||
|
@@ -90,6 +90,12 @@ meta_renderer_create_view (MetaRenderer *renderer,
|
||||
*/
|
||||
void
|
||||
meta_renderer_rebuild_views (MetaRenderer *renderer)
|
||||
{
|
||||
return META_RENDERER_GET_CLASS (renderer)->rebuild_views (renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_renderer_real_rebuild_views (MetaRenderer *renderer)
|
||||
{
|
||||
MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
@@ -181,4 +187,6 @@ meta_renderer_class_init (MetaRendererClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_renderer_finalize;
|
||||
|
||||
klass->rebuild_views = meta_renderer_real_rebuild_views;
|
||||
}
|
||||
|
@@ -43,6 +43,7 @@ struct _MetaRendererClass
|
||||
CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer);
|
||||
MetaRendererView * (* create_view) (MetaRenderer *renderer,
|
||||
MetaLogicalMonitor *logical_monitor);
|
||||
void (* rebuild_views) (MetaRenderer *renderer);
|
||||
};
|
||||
|
||||
CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);
|
||||
|
@@ -368,12 +368,8 @@ parse_transforms (MetaCrtc *crtc,
|
||||
|
||||
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_90;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_180;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_270;
|
||||
|
||||
if (transform != -1)
|
||||
{
|
||||
|
@@ -823,6 +823,7 @@ static void
|
||||
cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
|
||||
{
|
||||
g_hash_table_destroy (cursor_priv->gpu_states);
|
||||
g_free (cursor_priv);
|
||||
}
|
||||
|
||||
static MetaCursorNativePrivate *
|
||||
|
@@ -258,6 +258,9 @@ cogl_pixel_format_from_drm_format (uint32_t drm_format,
|
||||
CoglPixelFormat *out_format,
|
||||
CoglTextureComponents *out_components);
|
||||
|
||||
static void
|
||||
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
|
||||
|
||||
static MetaBackend *
|
||||
backend_from_renderer_native (MetaRendererNative *renderer_native)
|
||||
{
|
||||
@@ -1277,7 +1280,7 @@ meta_renderer_native_egl_context_created (CoglDisplay *cogl_display,
|
||||
cogl_display_egl->dummy_surface,
|
||||
cogl_display_egl->egl_context))
|
||||
{
|
||||
_cogl_set_error (error, COGL_WINSYS_ERROR,
|
||||
g_set_error (error, COGL_WINSYS_ERROR,
|
||||
COGL_WINSYS_ERROR_CREATE_CONTEXT,
|
||||
"Failed to make context current");
|
||||
return FALSE;
|
||||
@@ -3035,11 +3038,53 @@ meta_onscreen_native_allocate (CoglOnscreen *onscreen,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_egl_surface (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
|
||||
if (onscreen_egl->egl_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *cogl_context = framebuffer->context;
|
||||
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
||||
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
||||
|
||||
meta_egl_destroy_surface (egl,
|
||||
cogl_renderer_egl->edpy,
|
||||
onscreen_egl->egl_surface,
|
||||
NULL);
|
||||
onscreen_egl->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
discard_onscreen_page_flip_retries (MetaOnscreenNative *onscreen_native)
|
||||
{
|
||||
g_list_free_full (onscreen_native->pending_page_flip_retries,
|
||||
(GDestroyNotify) retry_page_flip_data_free);
|
||||
onscreen_native->pending_page_flip_retries = NULL;
|
||||
|
||||
if (onscreen_native->retry_page_flips_source)
|
||||
{
|
||||
MetaBackend *backend =
|
||||
backend_from_renderer_native (onscreen_native->renderer_native);
|
||||
|
||||
meta_backend_thaw_updates (backend);
|
||||
g_clear_pointer (&onscreen_native->retry_page_flips_source,
|
||||
g_source_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *cogl_context = framebuffer->context;
|
||||
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
||||
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
||||
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
||||
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
@@ -3052,28 +3097,18 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
|
||||
|
||||
onscreen_native = onscreen_egl->platform;
|
||||
|
||||
g_list_free_full (onscreen_native->pending_page_flip_retries,
|
||||
(GDestroyNotify) retry_page_flip_data_free);
|
||||
if (onscreen_native->retry_page_flips_source)
|
||||
if (onscreen_egl->egl_surface != EGL_NO_SURFACE &&
|
||||
(cogl_display_egl->current_draw_surface == onscreen_egl->egl_surface ||
|
||||
cogl_display_egl->current_read_surface == onscreen_egl->egl_surface))
|
||||
{
|
||||
MetaBackend *backend =
|
||||
backend_from_renderer_native (onscreen_native->renderer_native);
|
||||
|
||||
meta_backend_thaw_updates (backend);
|
||||
g_clear_pointer (&onscreen_native->retry_page_flips_source,
|
||||
g_source_destroy);
|
||||
if (!_cogl_winsys_egl_make_current (cogl_display,
|
||||
cogl_display_egl->dummy_surface,
|
||||
cogl_display_egl->dummy_surface,
|
||||
cogl_display_egl->egl_context))
|
||||
g_warning ("Failed to clear current context");
|
||||
}
|
||||
|
||||
if (onscreen_egl->egl_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
||||
|
||||
meta_egl_destroy_surface (egl,
|
||||
cogl_renderer_egl->edpy,
|
||||
onscreen_egl->egl_surface,
|
||||
NULL);
|
||||
onscreen_egl->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
discard_onscreen_page_flip_retries (onscreen_native);
|
||||
|
||||
renderer_gpu_data =
|
||||
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
|
||||
@@ -3087,6 +3122,8 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
|
||||
|
||||
free_current_bo (onscreen);
|
||||
|
||||
destroy_egl_surface (onscreen);
|
||||
|
||||
if (onscreen_native->gbm.surface)
|
||||
{
|
||||
gbm_surface_destroy (onscreen_native->gbm.surface);
|
||||
@@ -3097,6 +3134,9 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
|
||||
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
||||
release_dumb_fb (&onscreen_native->egl.dumb_fb,
|
||||
onscreen_native->render_gpu);
|
||||
|
||||
destroy_egl_surface (onscreen);
|
||||
|
||||
if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
|
||||
{
|
||||
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
||||
@@ -3157,7 +3197,7 @@ meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
|
||||
{
|
||||
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
||||
@@ -3523,6 +3563,37 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
|
||||
return view;
|
||||
}
|
||||
|
||||
static void
|
||||
discard_page_flip_retries (MetaRenderer *renderer)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *stage_view = l->data;
|
||||
CoglFramebuffer *framebuffer =
|
||||
clutter_stage_view_get_onscreen (stage_view);
|
||||
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||
|
||||
discard_onscreen_page_flip_retries (onscreen_native);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_renderer_native_rebuild_views (MetaRenderer *renderer)
|
||||
{
|
||||
MetaRendererClass *parent_renderer_class =
|
||||
META_RENDERER_CLASS (meta_renderer_native_parent_class);
|
||||
|
||||
discard_page_flip_retries (renderer);
|
||||
|
||||
parent_renderer_class->rebuild_views (renderer);
|
||||
|
||||
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
|
||||
}
|
||||
|
||||
void
|
||||
meta_renderer_native_finish_frame (MetaRendererNative *renderer_native)
|
||||
{
|
||||
@@ -4038,6 +4109,7 @@ create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Missing EGL extensions required for EGLDevice renderer: %s",
|
||||
missing_extensions_str);
|
||||
meta_egl_terminate (egl, egl_display, NULL);
|
||||
g_free (missing_extensions_str);
|
||||
g_free (missing_extensions);
|
||||
return NULL;
|
||||
@@ -4320,6 +4392,7 @@ meta_renderer_native_class_init (MetaRendererNativeClass *klass)
|
||||
|
||||
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
|
||||
renderer_class->create_view = meta_renderer_native_create_view;
|
||||
renderer_class->rebuild_views = meta_renderer_native_rebuild_views;
|
||||
|
||||
obj_props[PROP_MONITOR_MANAGER] =
|
||||
g_param_spec_object ("monitor-manager",
|
||||
|
@@ -53,20 +53,6 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
|
||||
|
||||
gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native);
|
||||
|
||||
void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
|
||||
|
||||
gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
|
||||
MetaRendererView *view,
|
||||
int width,
|
||||
int height,
|
||||
GError **error);
|
||||
|
||||
void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native,
|
||||
uint32_t id,
|
||||
gboolean ignore);
|
||||
|
||||
MetaRendererView * meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native);
|
||||
|
||||
void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native);
|
||||
|
||||
int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native);
|
||||
|
@@ -140,7 +140,6 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native)
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
|
||||
meta_renderer_rebuild_views (renderer);
|
||||
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
|
||||
clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
|
||||
ensure_frame_callbacks (stage_native);
|
||||
}
|
||||
|
@@ -66,6 +66,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;
|
||||
@@ -174,6 +178,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 != META_CURRENT_TIME &&
|
||||
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)
|
||||
@@ -183,19 +207,7 @@ translate_device_event (MetaBackendX11 *x11,
|
||||
meta_backend_x11_translate_device_event (x11, device_event);
|
||||
|
||||
if (!device_event->send_event && device_event->time != META_CURRENT_TIME)
|
||||
{
|
||||
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
|
||||
@@ -260,6 +272,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:
|
||||
@@ -327,6 +342,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);
|
||||
|
||||
{
|
||||
@@ -534,6 +560,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 *
|
||||
@@ -591,6 +621,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,
|
||||
@@ -776,6 +843,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;
|
||||
|
@@ -18,6 +18,9 @@ struct _MetaCompositor
|
||||
guint pre_paint_func_id;
|
||||
guint post_paint_func_id;
|
||||
|
||||
guint stage_presented_id;
|
||||
guint stage_after_paint_id;
|
||||
|
||||
gint64 server_time_query_time;
|
||||
gint64 server_time_offset;
|
||||
|
||||
|
@@ -92,6 +92,10 @@ on_presented (ClutterStage *stage,
|
||||
ClutterFrameInfo *frame_info,
|
||||
MetaCompositor *compositor);
|
||||
|
||||
static void
|
||||
on_top_window_actor_destroyed (MetaWindowActor *window_actor,
|
||||
MetaCompositor *compositor);
|
||||
|
||||
static gboolean
|
||||
is_modal (MetaDisplay *display)
|
||||
{
|
||||
@@ -131,9 +135,31 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
|
||||
void
|
||||
meta_compositor_destroy (MetaCompositor *compositor)
|
||||
{
|
||||
g_signal_handler_disconnect (compositor->stage,
|
||||
compositor->stage_after_paint_id);
|
||||
g_signal_handler_disconnect (compositor->stage,
|
||||
compositor->stage_presented_id);
|
||||
|
||||
compositor->stage_after_paint_id = 0;
|
||||
compositor->stage_presented_id = 0;
|
||||
compositor->stage = NULL;
|
||||
|
||||
clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
|
||||
clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
|
||||
|
||||
if (compositor->top_window_actor)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
|
||||
on_top_window_actor_destroyed,
|
||||
compositor);
|
||||
compositor->top_window_actor = NULL;
|
||||
}
|
||||
|
||||
g_clear_pointer (&compositor->window_group, clutter_actor_destroy);
|
||||
g_clear_pointer (&compositor->top_window_group, clutter_actor_destroy);
|
||||
g_clear_pointer (&compositor->feedback_group, clutter_actor_destroy);
|
||||
g_clear_pointer (&compositor->windows, g_list_free);
|
||||
|
||||
if (compositor->have_x11_sync_object)
|
||||
meta_sync_ring_destroy ();
|
||||
}
|
||||
@@ -503,9 +529,10 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
|
||||
compositor->stage = meta_backend_get_stage (backend);
|
||||
|
||||
g_signal_connect (compositor->stage, "presented",
|
||||
G_CALLBACK (on_presented),
|
||||
compositor);
|
||||
compositor->stage_presented_id =
|
||||
g_signal_connect (compositor->stage, "presented",
|
||||
G_CALLBACK (on_presented),
|
||||
compositor);
|
||||
|
||||
/* We use connect_after() here to accomodate code in GNOME Shell that,
|
||||
* when benchmarking drawing performance, connects to ::after-paint
|
||||
@@ -515,8 +542,9 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
* connections to ::after-paint, connect() vs. connect_after() doesn't
|
||||
* matter.
|
||||
*/
|
||||
g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint",
|
||||
G_CALLBACK (after_stage_paint), compositor);
|
||||
compositor->stage_after_paint_id =
|
||||
g_signal_connect_after (compositor->stage, "after-paint",
|
||||
G_CALLBACK (after_stage_paint), compositor);
|
||||
|
||||
clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY);
|
||||
|
||||
|
@@ -252,12 +252,11 @@ static void
|
||||
set_file (MetaBackground *self,
|
||||
GFile **filep,
|
||||
MetaBackgroundImage **imagep,
|
||||
GFile *file)
|
||||
GFile *file,
|
||||
gboolean force_reload)
|
||||
{
|
||||
if (!file_equal0 (*filep, file))
|
||||
if (force_reload || !file_equal0 (*filep, file))
|
||||
{
|
||||
g_clear_object (filep);
|
||||
|
||||
if (*imagep)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (*imagep,
|
||||
@@ -267,11 +266,12 @@ set_file (MetaBackground *self,
|
||||
*imagep = NULL;
|
||||
}
|
||||
|
||||
g_set_object (filep, file);
|
||||
|
||||
if (file)
|
||||
{
|
||||
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
|
||||
|
||||
*filep = g_object_ref (file);
|
||||
*imagep = meta_background_image_cache_load (cache, file);
|
||||
g_signal_connect (*imagep, "loaded",
|
||||
G_CALLBACK (on_background_loaded), self);
|
||||
@@ -279,6 +279,32 @@ set_file (MetaBackground *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_gl_video_memory_purged (MetaBackground *self)
|
||||
{
|
||||
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
|
||||
|
||||
/* The GPU memory that just got invalidated is the texture inside
|
||||
* self->background_image1,2 and/or its mipmaps. However, to save memory the
|
||||
* original pixbuf isn't kept in RAM so we can't do a simple re-upload. The
|
||||
* only copy of the image was the one in texture memory that got invalidated.
|
||||
* So we need to do a full reload from disk.
|
||||
*/
|
||||
if (self->file1)
|
||||
{
|
||||
meta_background_image_cache_purge (cache, self->file1);
|
||||
set_file (self, &self->file1, &self->background_image1, self->file1, TRUE);
|
||||
}
|
||||
|
||||
if (self->file2)
|
||||
{
|
||||
meta_background_image_cache_purge (cache, self->file2);
|
||||
set_file (self, &self->file2, &self->background_image2, self->file2, TRUE);
|
||||
}
|
||||
|
||||
mark_changed (self);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_dispose (GObject *object)
|
||||
{
|
||||
@@ -287,8 +313,8 @@ meta_background_dispose (GObject *object)
|
||||
free_color_texture (self);
|
||||
free_wallpaper_texture (self);
|
||||
|
||||
set_file (self, &self->file1, &self->background_image1, NULL);
|
||||
set_file (self, &self->file2, &self->background_image2, NULL);
|
||||
set_file (self, &self->file1, &self->background_image1, NULL, FALSE);
|
||||
set_file (self, &self->file2, &self->background_image2, NULL, FALSE);
|
||||
|
||||
set_display (self, NULL);
|
||||
|
||||
@@ -312,7 +338,7 @@ meta_background_constructed (GObject *object)
|
||||
G_OBJECT_CLASS (meta_background_parent_class)->constructed (object);
|
||||
|
||||
g_signal_connect_object (self->display, "gl-video-memory-purged",
|
||||
G_CALLBACK (mark_changed), object, G_CONNECT_SWAPPED);
|
||||
G_CALLBACK (on_gl_video_memory_purged), object, G_CONNECT_SWAPPED);
|
||||
|
||||
g_signal_connect_object (monitor_manager, "monitors-changed",
|
||||
G_CALLBACK (on_monitors_changed), self,
|
||||
@@ -937,8 +963,8 @@ meta_background_set_blend (MetaBackground *self,
|
||||
g_return_if_fail (META_IS_BACKGROUND (self));
|
||||
g_return_if_fail (blend_factor >= 0.0 && blend_factor <= 1.0);
|
||||
|
||||
set_file (self, &self->file1, &self->background_image1, file1);
|
||||
set_file (self, &self->file2, &self->background_image2, file2);
|
||||
set_file (self, &self->file1, &self->background_image1, file1, FALSE);
|
||||
set_file (self, &self->file2, &self->background_image2, file2, FALSE);
|
||||
|
||||
self->blend_factor = blend_factor;
|
||||
self->style = style;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "cogl/winsys/cogl-texture-pixmap-x11.h"
|
||||
#include "compositor/meta-cullable.h"
|
||||
#include "compositor/meta-shaped-texture-private.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "core/window-private.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
@@ -71,11 +72,13 @@ static void
|
||||
free_damage (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaDisplay *display = self->display;
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
Display *xdisplay;
|
||||
|
||||
if (self->damage == None)
|
||||
return;
|
||||
|
||||
xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
XDamageDestroy (xdisplay, self->damage);
|
||||
self->damage = None;
|
||||
@@ -86,12 +89,14 @@ static void
|
||||
detach_pixmap (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaDisplay *display = self->display;
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||
Display *xdisplay;
|
||||
|
||||
if (self->pixmap == None)
|
||||
return;
|
||||
|
||||
xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
|
||||
/* Get rid of all references to the pixmap before freeing it; it's unclear whether
|
||||
* you are supposed to be able to free a GLXPixmap after freeing the underlying
|
||||
* pixmap, but it certainly doesn't work with current DRI/Mesa
|
||||
@@ -343,13 +348,19 @@ meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor)
|
||||
return self->unredirected;
|
||||
}
|
||||
|
||||
static void
|
||||
release_x11_resources (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
detach_pixmap (self);
|
||||
free_damage (self);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_dispose (GObject *object)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object);
|
||||
|
||||
detach_pixmap (self);
|
||||
free_damage (self);
|
||||
release_x11_resources (self);
|
||||
|
||||
G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -403,8 +414,7 @@ window_decorated_notify (MetaWindow *window,
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
|
||||
|
||||
detach_pixmap (self);
|
||||
free_damage (self);
|
||||
release_x11_resources (self);
|
||||
create_damage (self);
|
||||
}
|
||||
|
||||
@@ -441,6 +451,10 @@ meta_surface_actor_x11_new (MetaWindow *window)
|
||||
g_signal_connect_object (self->window, "notify::decorated",
|
||||
G_CALLBACK (window_decorated_notify), self, 0);
|
||||
|
||||
g_signal_connect_object (meta_window_actor_from_window (window), "destroy",
|
||||
G_CALLBACK (release_x11_resources), self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
self->unredirected = FALSE;
|
||||
sync_unredirected (self);
|
||||
|
||||
|
@@ -52,8 +52,6 @@ typedef enum
|
||||
|
||||
typedef struct _MetaWindowActorPrivate
|
||||
{
|
||||
ClutterActor parent;
|
||||
|
||||
MetaWindow *window;
|
||||
MetaCompositor *compositor;
|
||||
|
||||
@@ -417,7 +415,7 @@ meta_window_actor_update_surface (MetaWindowActor *self)
|
||||
else
|
||||
surface_actor = NULL;
|
||||
|
||||
set_surface (self, surface_actor);
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, surface_actor);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -430,6 +428,9 @@ meta_window_actor_constructed (GObject *object)
|
||||
|
||||
priv->compositor = window->display->compositor;
|
||||
|
||||
/* Hang our compositor window state off the MetaWindow for fast retrieval */
|
||||
meta_window_set_compositor_private (window, object);
|
||||
|
||||
meta_window_actor_update_surface (self);
|
||||
|
||||
meta_window_actor_update_opacity (self);
|
||||
@@ -446,9 +447,6 @@ meta_window_actor_constructed (GObject *object)
|
||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||
|
||||
meta_window_actor_sync_actor_geometry (self, priv->window->placed);
|
||||
|
||||
/* Hang our compositor window state off the MetaWindow for fast retrieval */
|
||||
meta_window_set_compositor_private (window, object);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -476,7 +474,7 @@ meta_window_actor_dispose (GObject *object)
|
||||
|
||||
g_clear_object (&priv->window);
|
||||
|
||||
set_surface (self, NULL);
|
||||
META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-cursor-sprite-xcursor.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-idle-monitor-dbus.h"
|
||||
@@ -598,27 +599,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->x11_display->xdisplay), event_mode);
|
||||
backend = meta_get_backend ();
|
||||
meta_backend_finish_touch_sequence (backend, sequence, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,10 +917,6 @@ meta_display_close (MetaDisplay *display,
|
||||
|
||||
g_clear_object (&display->gesture_tracker);
|
||||
|
||||
g_clear_pointer (&display->stack, meta_stack_free);
|
||||
g_clear_pointer (&display->stack_tracker,
|
||||
meta_stack_tracker_free);
|
||||
|
||||
if (display->focus_timeout_id)
|
||||
g_source_remove (display->focus_timeout_id);
|
||||
display->focus_timeout_id = 0;
|
||||
@@ -940,12 +933,6 @@ meta_display_close (MetaDisplay *display,
|
||||
/* Stop caring about events */
|
||||
meta_display_free_events (display);
|
||||
|
||||
/* Must be after all calls to meta_window_unmanage() since they
|
||||
* unregister windows
|
||||
*/
|
||||
g_hash_table_destroy (display->wayland_windows);
|
||||
g_hash_table_destroy (display->stamps);
|
||||
|
||||
if (display->compositor)
|
||||
meta_compositor_destroy (display->compositor);
|
||||
|
||||
@@ -956,6 +943,16 @@ meta_display_close (MetaDisplay *display,
|
||||
g_clear_object (&display->x11_display);
|
||||
}
|
||||
|
||||
/* Must be after all calls to meta_window_unmanage() since they
|
||||
* unregister windows
|
||||
*/
|
||||
g_hash_table_destroy (display->wayland_windows);
|
||||
g_hash_table_destroy (display->stamps);
|
||||
|
||||
g_clear_pointer (&display->stack, meta_stack_free);
|
||||
g_clear_pointer (&display->stack_tracker,
|
||||
meta_stack_tracker_free);
|
||||
|
||||
meta_display_shutdown_keys (display);
|
||||
|
||||
g_clear_object (&display->bell);
|
||||
|
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "meta/window.h"
|
||||
|
||||
@@ -39,14 +40,6 @@
|
||||
typedef struct _MetaGestureTracker MetaGestureTracker;
|
||||
typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_SEQUENCE_NONE,
|
||||
META_SEQUENCE_ACCEPTED,
|
||||
META_SEQUENCE_REJECTED,
|
||||
META_SEQUENCE_PENDING_END
|
||||
} MetaSequenceState;
|
||||
|
||||
struct _MetaGestureTracker
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
@@ -110,13 +110,24 @@ static void
|
||||
meta_launch_context_constructed (GObject *object)
|
||||
{
|
||||
MetaLaunchContext *context = META_LAUNCH_CONTEXT (object);
|
||||
const char *x11_display, *wayland_display;
|
||||
|
||||
G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object);
|
||||
|
||||
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
|
||||
"DISPLAY", getenv ("DISPLAY"));
|
||||
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
|
||||
"WAYLAND_DISPLAY", getenv ("WAYLAND_DISPLAY"));
|
||||
x11_display = getenv ("DISPLAY");
|
||||
wayland_display = getenv ("WAYLAND_DISPLAY");
|
||||
|
||||
if (x11_display)
|
||||
{
|
||||
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
|
||||
"DISPLAY", x11_display);
|
||||
}
|
||||
|
||||
if (wayland_display)
|
||||
{
|
||||
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
|
||||
"WAYLAND_DISPLAY", wayland_display);
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
|
@@ -1194,6 +1194,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 (!meta_window_is_focusable (window))
|
||||
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,
|
||||
@@ -1221,24 +1242,12 @@ get_default_focus_window (MetaStack *stack,
|
||||
if (window == not_this_one)
|
||||
continue;
|
||||
|
||||
if (window->unmaps_pending > 0)
|
||||
continue;
|
||||
|
||||
if (window->unmanaging)
|
||||
continue;
|
||||
|
||||
if (!meta_window_is_focusable (window))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1293,6 +1302,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.
|
||||
|
@@ -3683,6 +3683,13 @@ meta_window_activate_full (MetaWindow *window,
|
||||
{
|
||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||
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",
|
||||
@@ -8562,6 +8569,8 @@ meta_window_shortcuts_inhibited (MetaWindow *window,
|
||||
gboolean
|
||||
meta_window_is_focusable (MetaWindow *window)
|
||||
{
|
||||
g_return_val_if_fail (!window->unmanaging, FALSE);
|
||||
|
||||
return META_WINDOW_GET_CLASS (window)->is_focusable (window);
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
@@ -1322,13 +1328,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 && meta_window_is_focusable (window) &&
|
||||
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 */
|
||||
@@ -1350,11 +1363,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",
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "wayland/meta-wayland.h"
|
||||
|
||||
#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
#define FRAME_WARNING "Frame has assigned frame counter but no frame drawn time"
|
||||
|
||||
static gboolean
|
||||
run_tests (gpointer data)
|
||||
@@ -40,6 +41,8 @@ run_tests (gpointer data)
|
||||
MetaSettings *settings = meta_backend_get_settings (backend);
|
||||
gboolean ret;
|
||||
|
||||
g_test_log_set_fatal_handler (NULL, NULL);
|
||||
|
||||
meta_settings_override_experimental_features (settings);
|
||||
|
||||
meta_settings_enable_experimental_feature (
|
||||
@@ -53,6 +56,20 @@ run_tests (gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ignore_frame_counter_warning (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
if ((log_level & G_LOG_LEVEL_WARNING) &&
|
||||
g_strcmp0 (log_domain, "mutter") == 0 &&
|
||||
g_str_has_suffix (message, FRAME_WARNING))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_headless_start (void)
|
||||
{
|
||||
@@ -193,6 +210,8 @@ main (int argc, char *argv[])
|
||||
meta_init ();
|
||||
meta_register_with_session ();
|
||||
|
||||
g_test_log_set_fatal_handler (ignore_frame_counter_warning, NULL);
|
||||
|
||||
g_idle_add (run_tests, NULL);
|
||||
|
||||
return meta_run ();
|
||||
|
@@ -38,6 +38,7 @@ test_client = executable('mutter-test-client',
|
||||
dependencies: [
|
||||
gtk3_dep,
|
||||
gio_unix_dep,
|
||||
x11_dep,
|
||||
xext_dep,
|
||||
],
|
||||
install: have_installed_tests,
|
||||
@@ -104,6 +105,13 @@ headless_start_test = executable('mutter-headless-start-test',
|
||||
stacking_tests = files([
|
||||
'stacking/basic-x11.metatest',
|
||||
'stacking/basic-wayland.metatest',
|
||||
'stacking/closed-transient-no-input-no-take-focus-parent.metatest',
|
||||
'stacking/closed-transient-no-input-no-take-focus-parents.metatest',
|
||||
'stacking/closed-transient-no-input-parent.metatest',
|
||||
'stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest',
|
||||
'stacking/closed-transient-no-input-parents.metatest',
|
||||
'stacking/closed-transient-no-input-parents-queued-default-focus-destroyed.metatest',
|
||||
'stacking/closed-transient-only-take-focus-parents.metatest',
|
||||
'stacking/minimized.metatest',
|
||||
'stacking/mixed-windows.metatest',
|
||||
'stacking/set-parent.metatest',
|
||||
|
@@ -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
|
||||
dispatch
|
||||
|
||||
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
|
@@ -0,0 +1,34 @@
|
||||
new_client 0 x11
|
||||
create 0/1
|
||||
show 0/1
|
||||
|
||||
new_client 1 x11
|
||||
create 1/1
|
||||
accept_focus 1/1 false
|
||||
can_take_focus 1/1 true
|
||||
accept_take_focus 1/1 true
|
||||
show 1/1
|
||||
|
||||
create 1/2 csd
|
||||
set_parent 1/2 1
|
||||
accept_focus 1/2 false
|
||||
can_take_focus 1/2 true
|
||||
accept_take_focus 1/2 true
|
||||
show 1/2
|
||||
|
||||
create 1/3
|
||||
set_parent 1/3 2
|
||||
show 1/3
|
||||
|
||||
assert_focused 1/3
|
||||
assert_stacking 0/1 1/1 1/2 1/3
|
||||
|
||||
destroy 1/3
|
||||
wait
|
||||
|
||||
assert_focused 1/2
|
||||
assert_stacking 0/1 1/1 1/2
|
||||
|
||||
sleep 150
|
||||
assert_focused 1/2
|
||||
assert_stacking 0/1 1/1 1/2
|
@@ -31,6 +31,11 @@
|
||||
const char *client_id = "0";
|
||||
static gboolean wayland;
|
||||
GHashTable *windows;
|
||||
GQuark event_source_quark;
|
||||
GQuark event_handlers_quark;
|
||||
GQuark can_take_focus_quark;
|
||||
|
||||
typedef void (*XEventHandler) (GtkWidget *window, XEvent *event);
|
||||
|
||||
static void read_next_line (GDataInputStream *in);
|
||||
|
||||
@@ -57,6 +62,186 @@ lookup_window (const char *window_id)
|
||||
return window;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GSource base;
|
||||
GSource **self_ref;
|
||||
GPollFD event_poll_fd;
|
||||
Display *xdisplay;
|
||||
} XClientEventSource;
|
||||
|
||||
static gboolean
|
||||
x_event_source_prepare (GSource *source,
|
||||
int *timeout)
|
||||
{
|
||||
XClientEventSource *x_source = (XClientEventSource *) source;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
return XPending (x_source->xdisplay);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_source_check (GSource *source)
|
||||
{
|
||||
XClientEventSource *x_source = (XClientEventSource *) source;
|
||||
|
||||
return XPending (x_source->xdisplay);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_source_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
XClientEventSource *x_source = (XClientEventSource *) source;
|
||||
|
||||
while (XPending (x_source->xdisplay))
|
||||
{
|
||||
GHashTableIter iter;
|
||||
XEvent event;
|
||||
gpointer value;
|
||||
|
||||
XNextEvent (x_source->xdisplay, &event);
|
||||
|
||||
g_hash_table_iter_init (&iter, windows);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
{
|
||||
GList *l;
|
||||
GtkWidget *window = value;
|
||||
GList *handlers =
|
||||
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
|
||||
|
||||
for (l = handlers; l; l = l->next)
|
||||
{
|
||||
XEventHandler handler = l->data;
|
||||
handler (window, &event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
x_event_source_finalize (GSource *source)
|
||||
{
|
||||
XClientEventSource *x_source = (XClientEventSource *) source;
|
||||
|
||||
*x_source->self_ref = NULL;
|
||||
}
|
||||
|
||||
static GSourceFuncs x_event_funcs = {
|
||||
x_event_source_prepare,
|
||||
x_event_source_check,
|
||||
x_event_source_dispatch,
|
||||
x_event_source_finalize,
|
||||
};
|
||||
|
||||
static GSource*
|
||||
ensure_xsource_handler (GdkDisplay *gdkdisplay)
|
||||
{
|
||||
static GSource *source = NULL;
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
|
||||
XClientEventSource *x_source;
|
||||
|
||||
if (source)
|
||||
return g_source_ref (source);
|
||||
|
||||
source = g_source_new (&x_event_funcs, sizeof (XClientEventSource));
|
||||
x_source = (XClientEventSource *) source;
|
||||
x_source->self_ref = &source;
|
||||
x_source->xdisplay = xdisplay;
|
||||
x_source->event_poll_fd.fd = ConnectionNumber (xdisplay);
|
||||
x_source->event_poll_fd.events = G_IO_IN;
|
||||
g_source_add_poll (source, &x_source->event_poll_fd);
|
||||
|
||||
g_source_set_priority (source, GDK_PRIORITY_EVENTS - 1);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
g_source_attach (source, NULL);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_has_x11_event_handler (GtkWidget *window,
|
||||
XEventHandler handler)
|
||||
{
|
||||
GList *handlers =
|
||||
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
|
||||
|
||||
g_return_val_if_fail (handler, FALSE);
|
||||
g_return_val_if_fail (!wayland, FALSE);
|
||||
|
||||
return g_list_find (handlers, handler) != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
unref_and_maybe_destroy_gsource (GSource *source)
|
||||
{
|
||||
g_source_unref (source);
|
||||
|
||||
if (source->ref_count == 1)
|
||||
g_source_destroy (source);
|
||||
}
|
||||
|
||||
static void
|
||||
window_add_x11_event_handler (GtkWidget *window,
|
||||
XEventHandler handler)
|
||||
{
|
||||
GSource *source;
|
||||
GList *handlers =
|
||||
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
|
||||
|
||||
g_return_if_fail (!window_has_x11_event_handler (window, handler));
|
||||
|
||||
source = ensure_xsource_handler (gtk_widget_get_display (window));
|
||||
g_object_set_qdata_full (G_OBJECT (window), event_source_quark, source,
|
||||
(GDestroyNotify) unref_and_maybe_destroy_gsource);
|
||||
|
||||
handlers = g_list_append (handlers, handler);
|
||||
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
||||
}
|
||||
|
||||
static void
|
||||
window_remove_x11_event_handler (GtkWidget *window,
|
||||
XEventHandler handler)
|
||||
{
|
||||
GList *handlers =
|
||||
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
|
||||
|
||||
g_return_if_fail (window_has_x11_event_handler (window, handler));
|
||||
|
||||
g_object_set_qdata (G_OBJECT (window), event_source_quark, NULL);
|
||||
|
||||
handlers = g_list_remove (handlers, handler);
|
||||
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_take_focus (GtkWidget *window,
|
||||
XEvent *xevent)
|
||||
{
|
||||
GdkWindow *gdkwindow = gtk_widget_get_window (window);
|
||||
GdkDisplay *display = gtk_widget_get_display (window);
|
||||
Atom wm_protocols =
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS");
|
||||
Atom wm_take_focus =
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
|
||||
|
||||
if (xevent->xany.type != ClientMessage ||
|
||||
xevent->xany.window != GDK_WINDOW_XID (gdkwindow))
|
||||
return;
|
||||
|
||||
if (xevent->xclient.message_type == wm_protocols &&
|
||||
xevent->xclient.data.l[0] == wm_take_focus)
|
||||
{
|
||||
XSetInputFocus (xevent->xany.display,
|
||||
GDK_WINDOW_XID (gdkwindow),
|
||||
RevertToParent,
|
||||
xevent->xclient.data.l[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_line (const char *line)
|
||||
{
|
||||
@@ -125,6 +310,9 @@ process_line (const char *line)
|
||||
gtk_window_set_title (GTK_WINDOW (window), title);
|
||||
g_free (title);
|
||||
|
||||
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
|
||||
GUINT_TO_POINTER (TRUE));
|
||||
|
||||
gtk_widget_realize (window);
|
||||
|
||||
if (!wayland)
|
||||
@@ -196,6 +384,130 @@ 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;
|
||||
}
|
||||
|
||||
if (!wayland &&
|
||||
window_has_x11_event_handler (window, handle_take_focus))
|
||||
{
|
||||
g_print ("Impossible to use %s for windows accepting take focus",
|
||||
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;
|
||||
}
|
||||
|
||||
if (window_has_x11_event_handler (window, handle_take_focus))
|
||||
{
|
||||
g_print ("Impossible to change %s for windows accepting take focus",
|
||||
argv[1]);
|
||||
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);
|
||||
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
|
||||
GUINT_TO_POINTER (add));
|
||||
|
||||
XFree (new_protocols);
|
||||
XFree (protocols);
|
||||
}
|
||||
else if (strcmp (argv[0], "accept_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;
|
||||
}
|
||||
|
||||
if (gtk_window_get_accept_focus (GTK_WINDOW (window)))
|
||||
{
|
||||
g_print ("%s not supported for input windows", argv[0]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_object_get_qdata (G_OBJECT (window), can_take_focus_quark))
|
||||
{
|
||||
g_print ("%s not supported for windows with no WM_TAKE_FOCUS set",
|
||||
argv[0]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (g_ascii_strcasecmp (argv[2], "true") == 0)
|
||||
window_add_x11_event_handler (window, handle_take_focus);
|
||||
else
|
||||
window_remove_x11_event_handler (window, handle_take_focus);
|
||||
}
|
||||
else if (strcmp (argv[0], "show") == 0)
|
||||
{
|
||||
if (argc != 2)
|
||||
@@ -460,6 +772,9 @@ main(int argc, char **argv)
|
||||
|
||||
windows = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
event_source_quark = g_quark_from_static_string ("event-source");
|
||||
event_handlers_quark = g_quark_from_static_string ("event-handlers");
|
||||
can_take_focus_quark = g_quark_from_static_string ("can-take-focus");
|
||||
|
||||
GInputStream *raw_in = g_unix_input_stream_new (0, FALSE);
|
||||
GDataInputStream *in = g_data_input_stream_new (raw_in);
|
||||
|
@@ -77,7 +77,7 @@ test_case_new (void)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_case_before_redraw (gpointer data)
|
||||
test_case_loop_quit (gpointer data)
|
||||
{
|
||||
TestCase *test = data;
|
||||
|
||||
@@ -86,6 +86,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)
|
||||
@@ -102,16 +120,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
|
||||
@@ -121,6 +131,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, \
|
||||
@@ -237,6 +258,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)
|
||||
@@ -385,6 +437,9 @@ test_case_do (TestCase *test,
|
||||
argc == 3 ? argv[2] : NULL,
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!test_client_wait (client, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (argv[0], "set_parent") == 0 ||
|
||||
strcmp (argv[0], "set_parent_exported") == 0)
|
||||
@@ -398,6 +453,63 @@ 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], "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], "accept_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],
|
||||
@@ -477,6 +589,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))
|
||||
@@ -485,6 +619,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]);
|
||||
|
@@ -170,8 +170,9 @@ meta_wayland_cursor_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||
wl_list_init (&pending->frame_callback_list);
|
||||
|
||||
if (pending->newly_attached &&
|
||||
(!cairo_region_is_empty (pending->surface_damage) ||
|
||||
!cairo_region_is_empty (pending->buffer_damage)))
|
||||
((!cairo_region_is_empty (pending->surface_damage) ||
|
||||
!cairo_region_is_empty (pending->buffer_damage)) ||
|
||||
!priv->buffer))
|
||||
update_cursor_sprite_texture (META_WAYLAND_CURSOR_SURFACE (surface_role));
|
||||
}
|
||||
|
||||
|
@@ -266,7 +266,7 @@ meta_wayland_seat_free (MetaWaylandSeat *seat)
|
||||
meta_wayland_gtk_text_input_destroy (seat->gtk_text_input);
|
||||
meta_wayland_text_input_destroy (seat->text_input);
|
||||
|
||||
g_slice_free (MetaWaylandSeat, seat);
|
||||
g_free (seat);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@@ -737,6 +737,10 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
|
||||
g_clear_pointer (&snippet, cogl_object_unref);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cogl_clear_object (&surface->texture);
|
||||
}
|
||||
|
||||
/* If the newly attached buffer is going to be accessed directly without
|
||||
* making a copy, such as an EGL buffer, mark it as in-use don't release
|
||||
|
@@ -50,6 +50,8 @@
|
||||
#include "x11/window-props.h"
|
||||
#include "x11/xprops.h"
|
||||
|
||||
#define TAKE_FOCUS_FALLBACK_DELAY_MS 150
|
||||
|
||||
enum _MetaGtkEdgeConstraints
|
||||
{
|
||||
META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0,
|
||||
@@ -64,6 +66,11 @@ enum _MetaGtkEdgeConstraints
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -776,6 +783,158 @@ request_take_focus (MetaWindow *window,
|
||||
send_icccm_message (window, display->x11_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);
|
||||
}
|
||||
|
||||
g_clear_handle_id (&data->timeout_id, g_source_remove);
|
||||
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 (MetaDisplay *display,
|
||||
MetaWindow *not_this_one,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWorkspace *workspace;
|
||||
MetaStack *stack = display->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 = display->workspace_manager->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)
|
||||
@@ -827,13 +986,20 @@ 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_x11_display_focus_the_no_focus_window (window->display->x11_display,
|
||||
timestamp);
|
||||
{
|
||||
MetaX11Display *x11_display = window->display->x11_display;
|
||||
|
||||
meta_x11_display_focus_the_no_focus_window (x11_display,
|
||||
timestamp);
|
||||
maybe_focus_default_window (window->display, window,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
request_take_focus (window, timestamp);
|
||||
|
Reference in New Issue
Block a user