Compare commits
82 Commits
dcvviewer
...
wip/carlos
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f82a0a70c0 | ||
![]() |
a3b86447f7 | ||
![]() |
1d76eace1e | ||
![]() |
c1303bd642 | ||
![]() |
db11a37a68 | ||
![]() |
0d0b9da6f8 | ||
![]() |
ab0b407da4 | ||
![]() |
c33b330799 | ||
![]() |
144b24bfcc | ||
![]() |
4d21650d6d | ||
![]() |
a6fc656e91 | ||
![]() |
a38bae259e | ||
![]() |
c53aa89098 | ||
![]() |
851b7d0639 | ||
![]() |
b4c78726cf | ||
![]() |
c9cc07fd3a | ||
![]() |
f6eb2a8cf8 | ||
![]() |
08e5589836 | ||
![]() |
4f5a5e84fc | ||
![]() |
0786683189 | ||
![]() |
4887de533c | ||
![]() |
57945a730f | ||
![]() |
78254146f3 | ||
![]() |
3e2a2cf532 | ||
![]() |
04b240b50c | ||
![]() |
7810f0e276 | ||
![]() |
9b8f9b65b8 | ||
![]() |
e741cab3f4 | ||
![]() |
53748e3da7 | ||
![]() |
17c5436f6e | ||
![]() |
04fb6f7659 | ||
![]() |
e5e58f8075 | ||
![]() |
1da0355528 | ||
![]() |
e5881156f6 | ||
![]() |
60170cff70 | ||
![]() |
e2bea48073 | ||
![]() |
bbfaf8204b | ||
![]() |
b3e19ee669 | ||
![]() |
75e2bfb062 | ||
![]() |
a859d76c72 | ||
![]() |
2145333969 | ||
![]() |
1b61b9cd73 | ||
![]() |
a2c545c321 | ||
![]() |
3cd8f3b7dc | ||
![]() |
033ce2d956 | ||
![]() |
2b47e89405 | ||
![]() |
80d11287eb | ||
![]() |
f869e4d54b | ||
![]() |
c1059df7f9 | ||
![]() |
e3d3df985f | ||
![]() |
86ff3dfb3c | ||
![]() |
7e0d185120 | ||
![]() |
61c173b777 | ||
![]() |
f99cd18254 | ||
![]() |
0405786573 | ||
![]() |
b016ff29f6 | ||
![]() |
3f2e86f67c | ||
![]() |
0aa4a526c6 | ||
![]() |
85c2aef4bc | ||
![]() |
76664ef891 | ||
![]() |
b1ea768949 | ||
![]() |
ea9d8a895b | ||
![]() |
38432da328 | ||
![]() |
430f354cd9 | ||
![]() |
1cf4279745 | ||
![]() |
7713006f5b | ||
![]() |
465e13128b | ||
![]() |
86de79cfc5 | ||
![]() |
1d77641f0b | ||
![]() |
2f217109aa | ||
![]() |
5e0523cc8b | ||
![]() |
dbe6e01e12 | ||
![]() |
103c469cc9 | ||
![]() |
ef074ea510 | ||
![]() |
39bac6eabd | ||
![]() |
0200f4fcd9 | ||
![]() |
439afb3f19 | ||
![]() |
b01edc22f3 | ||
![]() |
e8bca5052a | ||
![]() |
468882ecec | ||
![]() |
be3c89d823 | ||
![]() |
7719e33e68 |
@@ -35,15 +35,17 @@ test-mutter:
|
||||
variables:
|
||||
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
|
||||
GSETTINGS_SCHEMA_DIR: "$CI_PROJECT_DIR/build/data"
|
||||
G_SLICE: "always-malloc"
|
||||
MALLOC_CHECK_: "3"
|
||||
NO_AT_BRIDGE: "1"
|
||||
MALLOC_PERTURB_: "123"
|
||||
script:
|
||||
- dconf update
|
||||
- mkdir -m 700 $XDG_RUNTIME_DIR
|
||||
- glib-compile-schemas $GSETTINGS_SCHEMA_DIR
|
||||
- >
|
||||
env MALLOC_PERTURB_="$((RANDOM % 256 + 1))"
|
||||
dbus-run-session -- xvfb-run -s '+iglx -noreset'
|
||||
meson test -C build --no-rebuild -t 10 --verbose --no-stdsplit --wrap catchsegv
|
||||
meson test -C build --no-rebuild -t 10 --verbose --no-stdsplit --print-errorlogs --wrap catchsegv
|
||||
only:
|
||||
- merge_requests
|
||||
- /^.*$/
|
||||
|
@@ -15,6 +15,7 @@ RUN dnf -y update && dnf -y upgrade && \
|
||||
|
||||
# Unpackaged versions
|
||||
dnf install -y https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00834984-gsettings-desktop-schemas/gsettings-desktop-schemas-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00834984-gsettings-desktop-schemas/gsettings-desktop-schemas-devel-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm && \
|
||||
dnf install -y https://copr-be.cloud.fedoraproject.org/results/hergertme/sysprof-3/fedora-30-x86_64/00917385-sysprof/libsysprof-ui-3.33.2-1.fc30.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/hergertme/sysprof-3/fedora-30-x86_64/00917385-sysprof/sysprof-cli-3.33.2-1.fc30.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/hergertme/sysprof-3/fedora-30-x86_64/00917385-sysprof/sysprof-3.33.2-1.fc30.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/hergertme/sysprof-3/fedora-30-x86_64/00917385-sysprof/sysprof-devel-3.33.2-1.fc30.x86_64.rpm && \
|
||||
|
||||
dnf install -y intltool redhat-rpm-config make && \
|
||||
|
||||
|
15
NEWS
15
NEWS
@@ -1,3 +1,18 @@
|
||||
3.33.2
|
||||
======
|
||||
* Fix rendering lag on Xorg [Daniel; !520, !281]
|
||||
* Misc. bug fixes and cleanups [Carlos, Marco, Jonas D., Florian, Niels,
|
||||
Daniel, Benjamin, Jonas Å., Ignacio, Vasilis; #598, !576, !547, !578,
|
||||
!583, !582, !469, !524, !119, !571, !584, !585, !586, #425]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Benjamin Berg, Jonas Dreßler, Carlos Garnacho, Niels De Graef,
|
||||
Vasilis Liaskovitis, Florian Müllner, Ignacio Casal Quinteiro,
|
||||
Marco Trevisan (Treviño), Daniel van Vugt
|
||||
|
||||
Translators:
|
||||
Daniel Mustieles [es]
|
||||
|
||||
3.33.1
|
||||
======
|
||||
* Remove unused APIs and outdated driver support
|
||||
|
@@ -69,6 +69,22 @@ typedef struct _ClutterTouchInfo
|
||||
gfloat current_y;
|
||||
} ClutterTouchInfo;
|
||||
|
||||
typedef struct _ClutterPtrA11yData
|
||||
{
|
||||
int n_btn_pressed;
|
||||
float current_x;
|
||||
float current_y;
|
||||
|
||||
float dwell_x;
|
||||
float dwell_y;
|
||||
gboolean dwell_drag_started;
|
||||
gboolean dwell_gesture_started;
|
||||
guint dwell_timer;
|
||||
|
||||
guint secondary_click_timer;
|
||||
gboolean secondary_click_triggered;
|
||||
} ClutterPtrA11yData;
|
||||
|
||||
struct _ClutterInputDevice
|
||||
{
|
||||
GObject parent_instance;
|
||||
@@ -143,6 +159,10 @@ struct _ClutterInputDevice
|
||||
|
||||
guint has_cursor : 1;
|
||||
guint is_enabled : 1;
|
||||
|
||||
/* Accessiblity */
|
||||
ClutterVirtualInputDevice *accessibility_virtual_device;
|
||||
ClutterPtrA11yData *ptr_a11y_data;
|
||||
};
|
||||
|
||||
typedef void (*ClutterEmitInputDeviceEvent) (ClutterEvent *event,
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "clutter-stage-private.h"
|
||||
#include "clutter-virtual-input-device.h"
|
||||
#include "clutter-input-device-tool.h"
|
||||
#include "clutter-input-pointer-a11y-private.h"
|
||||
|
||||
struct _ClutterDeviceManagerPrivate
|
||||
{
|
||||
@@ -55,6 +56,8 @@ struct _ClutterDeviceManagerPrivate
|
||||
|
||||
/* Keyboard a11y */
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
/* Pointer a11y */
|
||||
ClutterPointerA11ySettings pointer_a11y_settings;
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -75,6 +78,9 @@ enum
|
||||
TOOL_CHANGED,
|
||||
KBD_A11Y_MASK_CHANGED,
|
||||
KBD_A11Y_FLAGS_CHANGED,
|
||||
PTR_A11Y_DWELL_CLICK_TYPE_CHANGED,
|
||||
PTR_A11Y_TIMEOUT_STARTED,
|
||||
PTR_A11Y_TIMEOUT_STOPPED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@@ -239,6 +245,67 @@ clutter_device_manager_class_init (ClutterDeviceManagerClass *klass)
|
||||
G_TYPE_NONE, 2,
|
||||
G_TYPE_UINT,
|
||||
G_TYPE_UINT);
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager::ptr-a11y-dwell-click-type-changed:
|
||||
* @manager: the #ClutterDeviceManager that emitted the signal
|
||||
* @click_type: the new #ClutterPointerA11yDwellClickType mode
|
||||
*
|
||||
* The ::ptr-a11y-dwell-click-type-changed signal is emitted each time
|
||||
* the ClutterPointerA11yDwellClickType mode is changed as the result
|
||||
* of pointer accessibility operations.
|
||||
*/
|
||||
manager_signals[PTR_A11Y_DWELL_CLICK_TYPE_CHANGED] =
|
||||
g_signal_new (I_("ptr-a11y-dwell-click-type-changed"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__FLAGS,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_POINTER_A11Y_DWELL_CLICK_TYPE);
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager::ptr-a11y-timeout-started:
|
||||
* @manager: the #ClutterDeviceManager that emitted the signal
|
||||
* @device: the core pointer #ClutterInputDevice
|
||||
* @timeout_type: the type of timeout #ClutterPointerA11yTimeoutType
|
||||
* @delay: the delay in ms before secondary-click is triggered.
|
||||
*
|
||||
* The ::ptr-a11y-timeout-started signal is emitted when a
|
||||
* pointer accessibility timeout delay is started, so that upper
|
||||
* layers can notify the user with some visual feedback.
|
||||
*/
|
||||
manager_signals[PTR_A11Y_TIMEOUT_STARTED] =
|
||||
g_signal_new (I_("ptr-a11y-timeout-started"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_FLAGS_UINT,
|
||||
G_TYPE_NONE, 3,
|
||||
CLUTTER_TYPE_INPUT_DEVICE,
|
||||
CLUTTER_TYPE_POINTER_A11Y_TIMEOUT_TYPE,
|
||||
G_TYPE_UINT);
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager::ptr-a11y-timeout-stopped:
|
||||
* @manager: the #ClutterDeviceManager that emitted the signal
|
||||
* @device: the core pointer #ClutterInputDevice
|
||||
* @timeout_type: the type of timeout #ClutterPointerA11yTimeoutType
|
||||
*
|
||||
* The ::ptr-a11y-timeout-stopped signal is emitted when a running
|
||||
* pointer accessibility timeout delay is stopped, either because
|
||||
* it's triggered at the end of the delay or cancelled, so that
|
||||
* upper layers can notify the user with some visual feedback.
|
||||
*/
|
||||
manager_signals[PTR_A11Y_TIMEOUT_STOPPED] =
|
||||
g_signal_new (I_("ptr-a11y-timeout-stopped"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_FLAGS,
|
||||
G_TYPE_NONE, 2,
|
||||
CLUTTER_TYPE_INPUT_DEVICE,
|
||||
CLUTTER_TYPE_POINTER_A11Y_TIMEOUT_TYPE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -579,3 +646,88 @@ clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_man
|
||||
|
||||
*settings = device_manager->priv->kbd_a11y_settings;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
are_pointer_a11y_settings_equal (ClutterPointerA11ySettings *a,
|
||||
ClutterPointerA11ySettings *b)
|
||||
{
|
||||
return (memcmp (a, b, sizeof (ClutterPointerA11ySettings)) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_enable_pointer_a11y (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
ClutterInputDevice *core_pointer;
|
||||
|
||||
core_pointer = clutter_device_manager_get_core_device (device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
|
||||
_clutter_input_pointer_a11y_add_device (core_pointer);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_disable_pointer_a11y (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
ClutterInputDevice *core_pointer;
|
||||
|
||||
core_pointer = clutter_device_manager_get_core_device (device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
|
||||
_clutter_input_pointer_a11y_remove_device (core_pointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_set_pointer_a11y_settings:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @settings: a pointer to a #ClutterPointerA11ySettings
|
||||
*
|
||||
* Sets the pointer accessibility settings
|
||||
**/
|
||||
void
|
||||
clutter_device_manager_set_pointer_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11ySettings *settings)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
if (are_pointer_a11y_settings_equal (&device_manager->priv->pointer_a11y_settings, settings))
|
||||
return;
|
||||
|
||||
if (device_manager->priv->pointer_a11y_settings.controls == 0 && settings->controls != 0)
|
||||
clutter_device_manager_enable_pointer_a11y (device_manager);
|
||||
else if (device_manager->priv->pointer_a11y_settings.controls != 0 && settings->controls == 0)
|
||||
clutter_device_manager_disable_pointer_a11y (device_manager);
|
||||
|
||||
device_manager->priv->pointer_a11y_settings = *settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_get_pointer_a11y_settings:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @settings: a pointer to a #ClutterPointerA11ySettings
|
||||
*
|
||||
* Gets the current pointer accessibility settings
|
||||
**/
|
||||
void
|
||||
clutter_device_manager_get_pointer_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11ySettings *settings)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
*settings = device_manager->priv->pointer_a11y_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_set_pointer_a11y_dwell_click_type:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @click_type: type of click as #ClutterPointerA11yDwellClickType
|
||||
*
|
||||
* Sets the dwell click type
|
||||
**/
|
||||
void
|
||||
clutter_device_manager_set_pointer_a11y_dwell_click_type (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11yDwellClickType click_type)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
device_manager->priv->pointer_a11y_settings.dwell_click_type = click_type;
|
||||
}
|
||||
|
@@ -73,6 +73,27 @@ typedef struct _ClutterKbdA11ySettings
|
||||
gint mousekeys_accel_time;
|
||||
} ClutterKbdA11ySettings;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11ySettings:
|
||||
*
|
||||
* The #ClutterPointerA11ySettings structure contains pointer accessibility
|
||||
* settings
|
||||
*
|
||||
*/
|
||||
typedef struct _ClutterPointerA11ySettings
|
||||
{
|
||||
ClutterPointerA11yFlags controls;
|
||||
ClutterPointerA11yDwellClickType dwell_click_type;
|
||||
ClutterPointerA11yDwellMode dwell_mode;
|
||||
ClutterPointerA11yDwellDirection dwell_gesture_single;
|
||||
ClutterPointerA11yDwellDirection dwell_gesture_double;
|
||||
ClutterPointerA11yDwellDirection dwell_gesture_drag;
|
||||
ClutterPointerA11yDwellDirection dwell_gesture_secondary;
|
||||
gint secondary_click_delay;
|
||||
gint dwell_delay;
|
||||
gint dwell_threshold;
|
||||
} ClutterPointerA11ySettings;
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager:
|
||||
*
|
||||
@@ -152,10 +173,23 @@ ClutterVirtualDeviceType clutter_device_manager_get_supported_virtual_device_typ
|
||||
CLUTTER_EXPORT
|
||||
void clutter_device_manager_set_kbd_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterKbdA11ySettings *settings);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterKbdA11ySettings *settings);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_device_manager_set_pointer_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11ySettings *settings);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_device_manager_get_pointer_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11ySettings *settings);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_device_manager_set_pointer_a11y_dwell_click_type (ClutterDeviceManager *device_manager,
|
||||
ClutterPointerA11yDwellClickType click_type);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DEVICE_MANAGER_H__ */
|
||||
|
@@ -443,6 +443,88 @@ typedef enum
|
||||
CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
|
||||
} ClutterKeyboardA11yFlags;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11yFlags:
|
||||
* @CLUTTER_A11Y_POINTER_ENABLED:
|
||||
* @CLUTTER_A11Y_SECONDARY_CLICK_ENABLED:
|
||||
* @CLUTTER_A11Y_DWELL_ENABLED:
|
||||
*
|
||||
* Pointer accessibility features applied to a ClutterInputDevice pointer.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_A11Y_SECONDARY_CLICK_ENABLED = 1 << 0,
|
||||
CLUTTER_A11Y_DWELL_ENABLED = 1 << 1,
|
||||
} ClutterPointerA11yFlags;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11yDwellClickType:
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_NONE: Internal use only
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY:
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_SECONDARY:
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_MIDDLE:
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_DOUBLE:
|
||||
* @CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG:
|
||||
*
|
||||
* Dwell click types.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_NONE,
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY,
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_SECONDARY,
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_MIDDLE,
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_DOUBLE,
|
||||
CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG,
|
||||
} ClutterPointerA11yDwellClickType;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11yDwellDirection:
|
||||
* @CLUTTER_A11Y_DWELL_DIRECTION_NONE:
|
||||
* @CLUTTER_A11Y_DWELL_DIRECTION_LEFT:
|
||||
* @CLUTTER_A11Y_DWELL_DIRECTION_RIGHT:
|
||||
* @CLUTTER_A11Y_DWELL_DIRECTION_UP:
|
||||
* @CLUTTER_A11Y_DWELL_DIRECTION_DOWN:
|
||||
*
|
||||
* Dwell gesture directions.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_A11Y_DWELL_DIRECTION_NONE,
|
||||
CLUTTER_A11Y_DWELL_DIRECTION_LEFT,
|
||||
CLUTTER_A11Y_DWELL_DIRECTION_RIGHT,
|
||||
CLUTTER_A11Y_DWELL_DIRECTION_UP,
|
||||
CLUTTER_A11Y_DWELL_DIRECTION_DOWN,
|
||||
} ClutterPointerA11yDwellDirection;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11yDwellMode:
|
||||
* @CLUTTER_A11Y_DWELL_MODE_WINDOW:
|
||||
* @CLUTTER_A11Y_DWELL_MODE_GESTURE:
|
||||
*
|
||||
* Dwell mode.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_A11Y_DWELL_MODE_WINDOW,
|
||||
CLUTTER_A11Y_DWELL_MODE_GESTURE,
|
||||
} ClutterPointerA11yDwellMode;
|
||||
|
||||
/**
|
||||
* ClutterPointerA11yTimeoutType:
|
||||
* @CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK:
|
||||
* @CLUTTER_A11Y_TIMEOUT_TYPE_DWELL:
|
||||
* @CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE:
|
||||
*
|
||||
* Pointer accessibility timeout type.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE,
|
||||
} ClutterPointerA11yTimeoutType;
|
||||
|
||||
/**
|
||||
* ClutterActorFlags:
|
||||
* @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside
|
||||
|
@@ -107,6 +107,9 @@ clutter_input_device_dispose (GObject *gobject)
|
||||
device->associated = NULL;
|
||||
}
|
||||
|
||||
if (device->accessibility_virtual_device)
|
||||
g_clear_object (&device->accessibility_virtual_device);
|
||||
|
||||
g_clear_pointer (&device->axes, g_array_unref);
|
||||
g_clear_pointer (&device->keys, g_array_unref);
|
||||
g_clear_pointer (&device->scroll_info, g_array_unref);
|
||||
|
42
clutter/clutter/clutter-input-pointer-a11y-private.h
Normal file
42
clutter/clutter/clutter-input-pointer-a11y-private.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Olivier Fourdan <ofourdan@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_INPUT_POINTER_A11Y_H__
|
||||
#define __CLUTTER_INPUT_POINTER_A11Y_H__
|
||||
|
||||
#include <clutter/clutter-types.h>
|
||||
#include "clutter-enum-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void _clutter_input_pointer_a11y_add_device (ClutterInputDevice *device);
|
||||
void _clutter_input_pointer_a11y_remove_device (ClutterInputDevice *device);
|
||||
void _clutter_input_pointer_a11y_on_motion_event (ClutterInputDevice *device,
|
||||
float x,
|
||||
float y);
|
||||
void _clutter_input_pointer_a11y_on_button_event (ClutterInputDevice *device,
|
||||
int button,
|
||||
gboolean pressed);
|
||||
gboolean _clutter_is_input_pointer_a11y_enabled (ClutterInputDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_INPUT_POINTER_A11Y_H__ */
|
669
clutter/clutter/clutter-input-pointer-a11y.c
Normal file
669
clutter/clutter/clutter-input-pointer-a11y.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Olivier Fourdan <ofourdan@redhat.com>
|
||||
*
|
||||
* This reimplements in Clutter the same behavior as mousetweaks original
|
||||
* implementation by Gerd Kohlberger <gerdko gmail com>
|
||||
* mousetweaks Copyright (C) 2007-2010 Gerd Kohlberger <gerdko gmail com>
|
||||
*/
|
||||
|
||||
#include "clutter-build-config.h"
|
||||
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-input-device.h"
|
||||
#include "clutter-input-pointer-a11y-private.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-virtual-input-device.h"
|
||||
|
||||
static gboolean
|
||||
is_secondary_click_enabled (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return (settings.controls & CLUTTER_A11Y_SECONDARY_CLICK_ENABLED);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dwell_click_enabled (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return (settings.controls & CLUTTER_A11Y_DWELL_ENABLED);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_secondary_click_delay (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return settings.secondary_click_delay;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_dwell_delay (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return settings.dwell_delay;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_dwell_threshold (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return settings.dwell_threshold;
|
||||
}
|
||||
|
||||
static ClutterPointerA11yDwellMode
|
||||
get_dwell_mode (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
return settings.dwell_mode;
|
||||
}
|
||||
|
||||
static ClutterPointerA11yDwellClickType
|
||||
get_dwell_click_type (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
#
|
||||
return settings.dwell_click_type;
|
||||
}
|
||||
|
||||
static ClutterPointerA11yDwellClickType
|
||||
get_dwell_click_type_for_direction (ClutterInputDevice *device,
|
||||
ClutterPointerA11yDwellDirection direction)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
if (direction == settings.dwell_gesture_single)
|
||||
return CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY;
|
||||
else if (direction == settings.dwell_gesture_double)
|
||||
return CLUTTER_A11Y_DWELL_CLICK_TYPE_DOUBLE;
|
||||
else if (direction == settings.dwell_gesture_drag)
|
||||
return CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG;
|
||||
else if (direction == settings.dwell_gesture_secondary)
|
||||
return CLUTTER_A11Y_DWELL_CLICK_TYPE_SECONDARY;
|
||||
|
||||
return CLUTTER_A11Y_DWELL_CLICK_TYPE_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_button_press (ClutterInputDevice *device,
|
||||
gint button)
|
||||
{
|
||||
clutter_virtual_input_device_notify_button (device->accessibility_virtual_device,
|
||||
g_get_monotonic_time (),
|
||||
button,
|
||||
CLUTTER_BUTTON_STATE_PRESSED);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_button_release (ClutterInputDevice *device,
|
||||
gint button)
|
||||
{
|
||||
clutter_virtual_input_device_notify_button (device->accessibility_virtual_device,
|
||||
g_get_monotonic_time (),
|
||||
button,
|
||||
CLUTTER_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_button_click (ClutterInputDevice *device,
|
||||
gint button)
|
||||
{
|
||||
emit_button_press (device, button);
|
||||
emit_button_release (device, button);
|
||||
}
|
||||
|
||||
static void
|
||||
restore_dwell_position (ClutterInputDevice *device)
|
||||
{
|
||||
clutter_virtual_input_device_notify_absolute_motion (device->accessibility_virtual_device,
|
||||
g_get_monotonic_time (),
|
||||
device->ptr_a11y_data->dwell_x,
|
||||
device->ptr_a11y_data->dwell_y);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
trigger_secondary_click (gpointer data)
|
||||
{
|
||||
ClutterInputDevice *device = data;
|
||||
|
||||
device->ptr_a11y_data->secondary_click_triggered = TRUE;
|
||||
device->ptr_a11y_data->secondary_click_timer = 0;
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-stopped",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_secondary_click_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
unsigned int delay = get_secondary_click_delay (device);
|
||||
|
||||
device->ptr_a11y_data->secondary_click_timer =
|
||||
clutter_threads_add_timeout (delay, trigger_secondary_click, device);
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-started",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK,
|
||||
delay);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_secondary_click_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
if (device->ptr_a11y_data->secondary_click_timer)
|
||||
{
|
||||
g_source_remove (device->ptr_a11y_data->secondary_click_timer);
|
||||
device->ptr_a11y_data->secondary_click_timer = 0;
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-stopped",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK);
|
||||
}
|
||||
device->ptr_a11y_data->secondary_click_triggered = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_has_moved (ClutterInputDevice *device)
|
||||
{
|
||||
float dx, dy;
|
||||
gint threshold;
|
||||
|
||||
dx = device->ptr_a11y_data->dwell_x - device->ptr_a11y_data->current_x;
|
||||
dy = device->ptr_a11y_data->dwell_y - device->ptr_a11y_data->current_y;
|
||||
threshold = get_dwell_threshold (device);
|
||||
|
||||
/* Pythagorean theorem */
|
||||
return ((dx * dx) + (dy * dy)) > (threshold * threshold);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_secondary_click_pending (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->secondary_click_timer != 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_secondary_click_triggered (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->secondary_click_triggered;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dwell_click_pending (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->dwell_timer != 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dwell_dragging (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->dwell_drag_started;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dwell_gesturing (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->dwell_gesture_started;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
has_button_pressed (ClutterInputDevice *device)
|
||||
{
|
||||
return device->ptr_a11y_data->n_btn_pressed > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_start_secondary_click_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
return !is_dwell_dragging (device);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_start_dwell (ClutterInputDevice *device)
|
||||
{
|
||||
/* We should trigger a dwell if we've not already started one, and if
|
||||
* no button is currently pressed or we are in the middle of a dwell
|
||||
* drag action.
|
||||
*/
|
||||
return !is_dwell_click_pending (device) &&
|
||||
(is_dwell_dragging (device) ||
|
||||
!has_button_pressed (device));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_stop_dwell (ClutterInputDevice *device)
|
||||
{
|
||||
/* We should stop a dwell if the motion exceeds the threshold, unless
|
||||
* we've started a gesture, because we want to keep the original dwell
|
||||
* location to both detect a gesture and restore the original pointer
|
||||
* location once the gesture is finished.
|
||||
*/
|
||||
return pointer_has_moved (device) &&
|
||||
!is_dwell_gesturing (device);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
should_update_dwell_position (ClutterInputDevice *device)
|
||||
{
|
||||
return !is_dwell_gesturing (device) &&
|
||||
!is_dwell_click_pending (device) &&
|
||||
!is_secondary_click_pending (device);
|
||||
}
|
||||
|
||||
static void
|
||||
update_dwell_click_type (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterPointerA11ySettings settings;
|
||||
ClutterPointerA11yDwellClickType dwell_click_type;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (device->device_manager, &settings);
|
||||
|
||||
dwell_click_type = settings.dwell_click_type;
|
||||
switch (dwell_click_type)
|
||||
{
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_DOUBLE:
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_SECONDARY:
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_MIDDLE:
|
||||
dwell_click_type = CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY;
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG:
|
||||
if (!is_dwell_dragging (device))
|
||||
dwell_click_type = CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY;
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY:
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dwell_click_type != settings.dwell_click_type)
|
||||
{
|
||||
settings.dwell_click_type = dwell_click_type;
|
||||
clutter_device_manager_set_pointer_a11y_settings (device->device_manager,
|
||||
&settings);
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-dwell-click-type-changed",
|
||||
dwell_click_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emit_dwell_click (ClutterInputDevice *device,
|
||||
ClutterPointerA11yDwellClickType dwell_click_type)
|
||||
{
|
||||
switch (dwell_click_type)
|
||||
{
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY:
|
||||
emit_button_click (device, CLUTTER_BUTTON_PRIMARY);
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_DOUBLE:
|
||||
emit_button_click (device, CLUTTER_BUTTON_PRIMARY);
|
||||
emit_button_click (device, CLUTTER_BUTTON_PRIMARY);
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG:
|
||||
if (is_dwell_dragging (device))
|
||||
{
|
||||
emit_button_release (device, CLUTTER_BUTTON_PRIMARY);
|
||||
device->ptr_a11y_data->dwell_drag_started = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_button_press (device, CLUTTER_BUTTON_PRIMARY);
|
||||
device->ptr_a11y_data->dwell_drag_started = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_SECONDARY:
|
||||
emit_button_click (device, CLUTTER_BUTTON_SECONDARY);
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_MIDDLE:
|
||||
emit_button_click (device, CLUTTER_BUTTON_MIDDLE);
|
||||
break;
|
||||
|
||||
case CLUTTER_A11Y_DWELL_CLICK_TYPE_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ClutterPointerA11yDwellDirection
|
||||
get_dwell_direction (ClutterInputDevice *device)
|
||||
{
|
||||
float dx, dy;
|
||||
|
||||
dx = ABS (device->ptr_a11y_data->dwell_x - device->ptr_a11y_data->current_x);
|
||||
dy = ABS (device->ptr_a11y_data->dwell_y - device->ptr_a11y_data->current_y);
|
||||
|
||||
/* The pointer hasn't moved */
|
||||
if (!pointer_has_moved (device))
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_NONE;
|
||||
|
||||
if (device->ptr_a11y_data->dwell_x < device->ptr_a11y_data->current_x)
|
||||
{
|
||||
if (dx > dy)
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dx > dy)
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_RIGHT;
|
||||
}
|
||||
|
||||
if (device->ptr_a11y_data->dwell_y < device->ptr_a11y_data->current_y)
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_UP;
|
||||
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_DOWN;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
trigger_clear_dwell_gesture (gpointer data)
|
||||
{
|
||||
ClutterInputDevice *device = data;
|
||||
|
||||
device->ptr_a11y_data->dwell_timer = 0;
|
||||
device->ptr_a11y_data->dwell_gesture_started = FALSE;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
trigger_dwell_gesture (gpointer data)
|
||||
{
|
||||
ClutterInputDevice *device = data;
|
||||
ClutterPointerA11yDwellDirection direction;
|
||||
unsigned int delay = get_dwell_delay (device);
|
||||
|
||||
restore_dwell_position (device);
|
||||
direction = get_dwell_direction (device);
|
||||
emit_dwell_click (device,
|
||||
get_dwell_click_type_for_direction (device,
|
||||
direction));
|
||||
|
||||
/* Do not clear the gesture right away, otherwise we'll start another one */
|
||||
device->ptr_a11y_data->dwell_timer =
|
||||
clutter_threads_add_timeout (delay, trigger_clear_dwell_gesture, device);
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-stopped",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_dwell_gesture_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
unsigned int delay = get_dwell_delay (device);
|
||||
|
||||
device->ptr_a11y_data->dwell_timer =
|
||||
clutter_threads_add_timeout (delay, trigger_dwell_gesture, device);
|
||||
device->ptr_a11y_data->dwell_gesture_started = TRUE;
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-started",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE,
|
||||
delay);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
trigger_dwell_click (gpointer data)
|
||||
{
|
||||
ClutterInputDevice *device = data;
|
||||
|
||||
device->ptr_a11y_data->dwell_timer = 0;
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-stopped",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL);
|
||||
|
||||
if (get_dwell_mode (device) == CLUTTER_A11Y_DWELL_MODE_GESTURE)
|
||||
{
|
||||
if (is_dwell_dragging (device))
|
||||
emit_dwell_click (device, CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG);
|
||||
else
|
||||
start_dwell_gesture_timeout (device);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_dwell_click (device, get_dwell_click_type (device));
|
||||
update_dwell_click_type (device);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_dwell_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
unsigned int delay = get_dwell_delay (device);
|
||||
|
||||
device->ptr_a11y_data->dwell_timer =
|
||||
clutter_threads_add_timeout (delay, trigger_dwell_click, device);
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-started",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL,
|
||||
delay);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_dwell_timeout (ClutterInputDevice *device)
|
||||
{
|
||||
if (device->ptr_a11y_data->dwell_timer)
|
||||
{
|
||||
g_source_remove (device->ptr_a11y_data->dwell_timer);
|
||||
device->ptr_a11y_data->dwell_timer = 0;
|
||||
device->ptr_a11y_data->dwell_gesture_started = FALSE;
|
||||
|
||||
g_signal_emit_by_name (device->device_manager,
|
||||
"ptr-a11y-timeout-stopped",
|
||||
device,
|
||||
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_dwell_position (ClutterInputDevice *device)
|
||||
{
|
||||
device->ptr_a11y_data->dwell_x = device->ptr_a11y_data->current_x;
|
||||
device->ptr_a11y_data->dwell_y = device->ptr_a11y_data->current_y;
|
||||
}
|
||||
|
||||
static void
|
||||
update_current_position (ClutterInputDevice *device,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
device->ptr_a11y_data->current_x = x;
|
||||
device->ptr_a11y_data->current_y = y;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_device_core_pointer (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterInputDevice *core_pointer;
|
||||
|
||||
core_pointer = clutter_device_manager_get_core_device (device->device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
if (core_pointer == NULL)
|
||||
return FALSE;
|
||||
|
||||
return (core_pointer == device);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_pointer_a11y_add_device (ClutterInputDevice *device)
|
||||
{
|
||||
if (!is_device_core_pointer (device))
|
||||
return;
|
||||
|
||||
device->accessibility_virtual_device =
|
||||
clutter_device_manager_create_virtual_device (device->device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
|
||||
device->ptr_a11y_data = g_new0 (ClutterPtrA11yData, 1);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_pointer_a11y_remove_device (ClutterInputDevice *device)
|
||||
{
|
||||
if (!is_device_core_pointer (device))
|
||||
return;
|
||||
|
||||
/* Terminate a drag if started */
|
||||
if (is_dwell_dragging (device))
|
||||
emit_dwell_click (device, CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG);
|
||||
|
||||
stop_dwell_timeout (device);
|
||||
stop_secondary_click_timeout (device);
|
||||
|
||||
g_clear_pointer (&device->ptr_a11y_data, g_free);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_pointer_a11y_on_motion_event (ClutterInputDevice *device,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
if (!is_device_core_pointer (device))
|
||||
return;
|
||||
|
||||
if (!_clutter_is_input_pointer_a11y_enabled (device))
|
||||
return;
|
||||
|
||||
update_current_position (device, x, y);
|
||||
|
||||
if (is_secondary_click_enabled (device))
|
||||
{
|
||||
if (pointer_has_moved (device))
|
||||
stop_secondary_click_timeout (device);
|
||||
}
|
||||
|
||||
if (is_dwell_click_enabled (device))
|
||||
{
|
||||
if (should_stop_dwell (device))
|
||||
stop_dwell_timeout (device);
|
||||
else if (should_start_dwell (device))
|
||||
start_dwell_timeout (device);
|
||||
}
|
||||
|
||||
if (should_update_dwell_position (device))
|
||||
update_dwell_position (device);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_pointer_a11y_on_button_event (ClutterInputDevice *device,
|
||||
int button,
|
||||
gboolean pressed)
|
||||
{
|
||||
if (!is_device_core_pointer (device))
|
||||
return;
|
||||
|
||||
if (!_clutter_is_input_pointer_a11y_enabled (device))
|
||||
return;
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
device->ptr_a11y_data->n_btn_pressed++;
|
||||
|
||||
if (is_dwell_click_enabled (device))
|
||||
stop_dwell_timeout (device);
|
||||
|
||||
if (is_dwell_dragging (device))
|
||||
stop_dwell_timeout (device);
|
||||
|
||||
if (is_secondary_click_enabled (device))
|
||||
{
|
||||
if (button == CLUTTER_BUTTON_PRIMARY)
|
||||
{
|
||||
if (should_start_secondary_click_timeout (device))
|
||||
start_secondary_click_timeout (device);
|
||||
}
|
||||
else if (is_secondary_click_pending (device))
|
||||
{
|
||||
stop_secondary_click_timeout (device);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_button_pressed (device))
|
||||
device->ptr_a11y_data->n_btn_pressed--;
|
||||
|
||||
if (is_secondary_click_triggered (device))
|
||||
{
|
||||
emit_button_click (device, CLUTTER_BUTTON_SECONDARY);
|
||||
stop_secondary_click_timeout (device);
|
||||
}
|
||||
|
||||
if (is_secondary_click_pending (device))
|
||||
stop_secondary_click_timeout (device);
|
||||
|
||||
if (is_dwell_dragging (device))
|
||||
emit_dwell_click (device, CLUTTER_A11Y_DWELL_CLICK_TYPE_DRAG);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_is_input_pointer_a11y_enabled (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
|
||||
|
||||
return (is_secondary_click_enabled (device) || is_dwell_click_enabled (device));
|
||||
}
|
@@ -58,6 +58,7 @@
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-event-private.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-input-pointer-a11y-private.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-master-clock.h"
|
||||
#include "clutter-mutter.h"
|
||||
@@ -2261,6 +2262,21 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
|
||||
case CLUTTER_MOTION:
|
||||
#ifdef CLUTTER_WINDOWING_X11
|
||||
if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
|
||||
{
|
||||
if (_clutter_is_input_pointer_a11y_enabled (device))
|
||||
{
|
||||
ClutterInputDevice *core_pointer;
|
||||
gfloat x, y;
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
core_pointer = clutter_device_manager_get_core_device (device->device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
_clutter_input_pointer_a11y_on_motion_event (core_pointer, x, y);
|
||||
}
|
||||
}
|
||||
#endif /* CLUTTER_WINDOWING_X11 */
|
||||
/* only the stage gets motion events if they are enabled */
|
||||
if (!clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)) &&
|
||||
event->any.source == NULL)
|
||||
@@ -2299,6 +2315,22 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
/* fallthrough from motion */
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
#ifdef CLUTTER_WINDOWING_X11
|
||||
if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
|
||||
{
|
||||
if (_clutter_is_input_pointer_a11y_enabled (device) && (event->type != CLUTTER_MOTION))
|
||||
{
|
||||
ClutterInputDevice *core_pointer;
|
||||
|
||||
core_pointer = clutter_device_manager_get_core_device (device->device_manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
|
||||
_clutter_input_pointer_a11y_on_button_event (core_pointer,
|
||||
event->button.button,
|
||||
event->type == CLUTTER_BUTTON_PRESS);
|
||||
}
|
||||
}
|
||||
#endif /* CLUTTER_WINDOWING_X11 */
|
||||
case CLUTTER_SCROLL:
|
||||
case CLUTTER_TOUCHPAD_PINCH:
|
||||
case CLUTTER_TOUCHPAD_SWIPE:
|
||||
|
@@ -23,6 +23,7 @@ VOID:FLOAT,FLOAT
|
||||
VOID:INT,INT,INT,INT
|
||||
VOID:OBJECT
|
||||
VOID:OBJECT,FLAGS
|
||||
VOID:OBJECT,FLAGS,UINT
|
||||
VOID:OBJECT,FLOAT,FLOAT
|
||||
VOID:OBJECT,FLOAT,FLOAT,FLAGS
|
||||
VOID:OBJECT,OBJECT
|
||||
|
@@ -75,6 +75,7 @@
|
||||
#include "clutter-private.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "cogl/cogl-trace.h"
|
||||
|
||||
/* <private>
|
||||
* ClutterStageHint:
|
||||
@@ -688,6 +689,8 @@ _clutter_stage_paint_view (ClutterStage *stage,
|
||||
if (!priv->impl)
|
||||
return;
|
||||
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStagePaintView, "Paint (view)");
|
||||
|
||||
clutter_stage_do_paint_view (stage, view, clip);
|
||||
g_signal_emit (stage, stage_signals[AFTER_PAINT], 0);
|
||||
}
|
||||
@@ -1225,22 +1228,31 @@ _clutter_stage_do_update (ClutterStage *stage)
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
|
||||
return FALSE;
|
||||
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStageDoUpdate, "Update");
|
||||
|
||||
/* NB: We need to ensure we have an up to date layout *before* we
|
||||
* check or clear the pending redraws flag since a relayout may
|
||||
* queue a redraw.
|
||||
*/
|
||||
COGL_TRACE_BEGIN (ClutterStageRelayout, "Layout");
|
||||
|
||||
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
|
||||
|
||||
COGL_TRACE_END (ClutterStageRelayout);
|
||||
|
||||
if (!priv->redraw_pending)
|
||||
return FALSE;
|
||||
|
||||
if (stage_was_relayout)
|
||||
pointers = _clutter_stage_check_updated_pointers (stage);
|
||||
|
||||
clutter_stage_maybe_finish_queue_redraws (stage);
|
||||
COGL_TRACE_BEGIN (ClutterStagePaint, "Paint");
|
||||
|
||||
clutter_stage_maybe_finish_queue_redraws (stage);
|
||||
clutter_stage_do_redraw (stage);
|
||||
|
||||
COGL_TRACE_END (ClutterStagePaint);
|
||||
|
||||
/* reset the guard, so that new redraws are possible */
|
||||
priv->redraw_pending = FALSE;
|
||||
|
||||
@@ -1254,12 +1266,16 @@ _clutter_stage_do_update (ClutterStage *stage)
|
||||
}
|
||||
#endif /* CLUTTER_ENABLE_DEBUG */
|
||||
|
||||
COGL_TRACE_BEGIN (ClutterStagePick, "Pick");
|
||||
|
||||
while (pointers)
|
||||
{
|
||||
_clutter_input_device_update (pointers->data, NULL, TRUE);
|
||||
pointers = g_slist_delete_link (pointers, pointers);
|
||||
}
|
||||
|
||||
COGL_TRACE_END (ClutterStagePick);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -2945,6 +2961,8 @@ clutter_stage_read_pixels (ClutterStage *stage,
|
||||
float pixel_height;
|
||||
uint8_t *pixels;
|
||||
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStageReadPixels, "Read Pixels");
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
|
||||
|
||||
priv = stage->priv;
|
||||
|
@@ -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);
|
||||
|
@@ -46,6 +46,8 @@
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
#include "cogl/cogl-trace.h"
|
||||
|
||||
typedef struct _ClutterStageViewCoglPrivate
|
||||
{
|
||||
/*
|
||||
@@ -905,26 +907,16 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
*/
|
||||
if (use_clipped_redraw)
|
||||
{
|
||||
if (use_clipped_redraw && clip_region_empty)
|
||||
if (clip_region_empty)
|
||||
{
|
||||
do_swap_buffer = FALSE;
|
||||
}
|
||||
else if (use_clipped_redraw)
|
||||
else
|
||||
{
|
||||
swap_region = fb_clip_region;
|
||||
g_assert (swap_region.width > 0);
|
||||
do_swap_buffer = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
swap_region = (cairo_rectangle_int_t) {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = view_rect.width * fb_scale,
|
||||
.height = view_rect.height * fb_scale,
|
||||
};
|
||||
do_swap_buffer = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -934,6 +926,9 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
|
||||
if (do_swap_buffer)
|
||||
{
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStageCoglRedrawViewSwapFramebuffer,
|
||||
"Paint (swap framebuffer)");
|
||||
|
||||
if (clutter_stage_view_get_onscreen (view) !=
|
||||
clutter_stage_view_get_framebuffer (view))
|
||||
{
|
||||
@@ -958,6 +953,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
gboolean swap_event = FALSE;
|
||||
GList *l;
|
||||
|
||||
COGL_TRACE_BEGIN (ClutterStageCoglRedraw, "Paint (Cogl Redraw)");
|
||||
|
||||
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
@@ -981,6 +978,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
stage_cogl->initialized_redraw_clip = FALSE;
|
||||
|
||||
stage_cogl->frame_count++;
|
||||
|
||||
COGL_TRACE_END (ClutterStageCoglRedraw);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -739,31 +739,33 @@ get_button_index (gint button)
|
||||
}
|
||||
|
||||
static void
|
||||
emulate_button_press (ClutterInputDeviceEvdev *device)
|
||||
emulate_button_press (ClutterInputDeviceEvdev *device_evdev)
|
||||
{
|
||||
gint btn = device->mousekeys_btn;
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_evdev);
|
||||
gint btn = device_evdev->mousekeys_btn;
|
||||
|
||||
if (device->mousekeys_btn_states[get_button_index (btn)])
|
||||
if (device_evdev->mousekeys_btn_states[get_button_index (btn)])
|
||||
return;
|
||||
|
||||
clutter_virtual_input_device_notify_button (device->mousekeys_virtual_device,
|
||||
clutter_virtual_input_device_notify_button (device->accessibility_virtual_device,
|
||||
g_get_monotonic_time (), btn,
|
||||
CLUTTER_BUTTON_STATE_PRESSED);
|
||||
device->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_PRESSED;
|
||||
device_evdev->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_PRESSED;
|
||||
}
|
||||
|
||||
static void
|
||||
emulate_button_release (ClutterInputDeviceEvdev *device)
|
||||
emulate_button_release (ClutterInputDeviceEvdev *device_evdev)
|
||||
{
|
||||
gint btn = device->mousekeys_btn;
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_evdev);
|
||||
gint btn = device_evdev->mousekeys_btn;
|
||||
|
||||
if (device->mousekeys_btn_states[get_button_index (btn)] == CLUTTER_BUTTON_STATE_RELEASED)
|
||||
if (device_evdev->mousekeys_btn_states[get_button_index (btn)] == CLUTTER_BUTTON_STATE_RELEASED)
|
||||
return;
|
||||
|
||||
clutter_virtual_input_device_notify_button (device->mousekeys_virtual_device,
|
||||
clutter_virtual_input_device_notify_button (device->accessibility_virtual_device,
|
||||
g_get_monotonic_time (), btn,
|
||||
CLUTTER_BUTTON_STATE_RELEASED);
|
||||
device->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_RELEASED;
|
||||
device_evdev->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_RELEASED;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -830,17 +832,18 @@ mousekeys_get_speed_factor (ClutterInputDeviceEvdev *device,
|
||||
#undef MOUSEKEYS_CURVE
|
||||
|
||||
static void
|
||||
emulate_pointer_motion (ClutterInputDeviceEvdev *device,
|
||||
emulate_pointer_motion (ClutterInputDeviceEvdev *device_evdev,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_evdev);
|
||||
gdouble dx_motion;
|
||||
gdouble dy_motion;
|
||||
gdouble speed;
|
||||
gint64 time_us;
|
||||
|
||||
time_us = g_get_monotonic_time ();
|
||||
speed = mousekeys_get_speed_factor (device, time_us);
|
||||
speed = mousekeys_get_speed_factor (device_evdev, time_us);
|
||||
|
||||
if (dx < 0)
|
||||
dx_motion = floor (((gdouble) dx) * speed);
|
||||
@@ -852,7 +855,7 @@ emulate_pointer_motion (ClutterInputDeviceEvdev *device,
|
||||
else
|
||||
dy_motion = ceil (((gdouble) dy) * speed);
|
||||
|
||||
clutter_virtual_input_device_notify_relative_motion (device->mousekeys_virtual_device,
|
||||
clutter_virtual_input_device_notify_relative_motion (device->accessibility_virtual_device,
|
||||
time_us, dx_motion, dy_motion);
|
||||
}
|
||||
static gboolean
|
||||
@@ -865,51 +868,53 @@ is_numlock_active (ClutterInputDeviceEvdev *device)
|
||||
}
|
||||
|
||||
static void
|
||||
enable_mousekeys (ClutterInputDeviceEvdev *device)
|
||||
enable_mousekeys (ClutterInputDeviceEvdev *device_evdev)
|
||||
{
|
||||
ClutterDeviceManager *manager;
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_evdev);
|
||||
ClutterDeviceManager *manager = device->device_manager;
|
||||
|
||||
device->mousekeys_btn = CLUTTER_BUTTON_PRIMARY;
|
||||
device->move_mousekeys_timer = 0;
|
||||
device->mousekeys_first_motion_time = 0;
|
||||
device->mousekeys_last_motion_time = 0;
|
||||
device->last_mousekeys_key = 0;
|
||||
device_evdev->mousekeys_btn = CLUTTER_BUTTON_PRIMARY;
|
||||
device_evdev->move_mousekeys_timer = 0;
|
||||
device_evdev->mousekeys_first_motion_time = 0;
|
||||
device_evdev->mousekeys_last_motion_time = 0;
|
||||
device_evdev->last_mousekeys_key = 0;
|
||||
|
||||
if (device->mousekeys_virtual_device)
|
||||
if (device->accessibility_virtual_device)
|
||||
return;
|
||||
|
||||
manager = CLUTTER_INPUT_DEVICE (device)->device_manager;
|
||||
device->mousekeys_virtual_device =
|
||||
device->accessibility_virtual_device =
|
||||
clutter_device_manager_create_virtual_device (manager,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_mousekeys (ClutterInputDeviceEvdev *device)
|
||||
disable_mousekeys (ClutterInputDeviceEvdev *device_evdev)
|
||||
{
|
||||
stop_mousekeys_move (device);
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_evdev);
|
||||
|
||||
stop_mousekeys_move (device_evdev);
|
||||
|
||||
/* Make sure we don't leave button pressed behind... */
|
||||
if (device->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_PRIMARY)])
|
||||
if (device_evdev->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_PRIMARY)])
|
||||
{
|
||||
device->mousekeys_btn = CLUTTER_BUTTON_PRIMARY;
|
||||
emulate_button_release (device);
|
||||
device_evdev->mousekeys_btn = CLUTTER_BUTTON_PRIMARY;
|
||||
emulate_button_release (device_evdev);
|
||||
}
|
||||
|
||||
if (device->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_MIDDLE)])
|
||||
if (device_evdev->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_MIDDLE)])
|
||||
{
|
||||
device->mousekeys_btn = CLUTTER_BUTTON_MIDDLE;
|
||||
emulate_button_release (device);
|
||||
device_evdev->mousekeys_btn = CLUTTER_BUTTON_MIDDLE;
|
||||
emulate_button_release (device_evdev);
|
||||
}
|
||||
|
||||
if (device->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_SECONDARY)])
|
||||
if (device_evdev->mousekeys_btn_states[get_button_index (CLUTTER_BUTTON_SECONDARY)])
|
||||
{
|
||||
device->mousekeys_btn = CLUTTER_BUTTON_SECONDARY;
|
||||
emulate_button_release (device);
|
||||
device_evdev->mousekeys_btn = CLUTTER_BUTTON_SECONDARY;
|
||||
emulate_button_release (device_evdev);
|
||||
}
|
||||
|
||||
if (device->mousekeys_virtual_device)
|
||||
g_clear_object (&device->mousekeys_virtual_device);
|
||||
if (device->accessibility_virtual_device)
|
||||
g_clear_object (&device->accessibility_virtual_device);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@@ -94,7 +94,6 @@ struct _ClutterInputDeviceEvdev
|
||||
gdouble mousekeys_curve_factor;
|
||||
guint move_mousekeys_timer;
|
||||
guint16 last_mousekeys_key;
|
||||
ClutterVirtualInputDevice *mousekeys_virtual_device;
|
||||
};
|
||||
|
||||
GType _clutter_input_device_evdev_get_type (void) G_GNUC_CONST;
|
||||
|
@@ -133,6 +133,7 @@ clutter_sources = [
|
||||
'clutter-input-device-tool.c',
|
||||
'clutter-input-focus.c',
|
||||
'clutter-input-method.c',
|
||||
'clutter-input-pointer-a11y.c',
|
||||
'clutter-virtual-input-device.c',
|
||||
'clutter-interval.c',
|
||||
'clutter-keyframe-transition.c',
|
||||
@@ -195,6 +196,7 @@ clutter_private_headers = [
|
||||
'clutter-id-pool.h',
|
||||
'clutter-input-focus-private.h',
|
||||
'clutter-input-method-private.h',
|
||||
'clutter-input-pointer-a11y-private.h',
|
||||
'clutter-master-clock.h',
|
||||
'clutter-master-clock-default.h',
|
||||
'clutter-offscreen-effect-private.h',
|
||||
@@ -504,7 +506,12 @@ libmutter_clutter_dep = declare_dependency(
|
||||
)
|
||||
|
||||
if have_introspection
|
||||
clutter_introspection_args = introspection_args + clutter_c_args
|
||||
clutter_introspection_args = introspection_args + [
|
||||
'-DCLUTTER_SYSCONFDIR="@0@"'.format(join_paths(prefix, sysconfdir)),
|
||||
'-DCLUTTER_COMPILATION=1',
|
||||
'-DCOGL_DISABLE_DEPRECATION_WARNINGS',
|
||||
'-DG_LOG_DOMAIN="Clutter"'
|
||||
]
|
||||
|
||||
libmutter_clutter_gir = gnome.generate_gir(libmutter_clutter,
|
||||
sources: [
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-input-device-xi2.h"
|
||||
#include "clutter-input-device-tool-xi2.h"
|
||||
#include "clutter-input-pointer-a11y-private.h"
|
||||
#include "clutter-virtual-input-device-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
|
||||
@@ -1273,6 +1274,60 @@ translate_pad_event (ClutterEvent *event,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_raw_event (ClutterDeviceManagerXI2 *manager_xi2,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
XGenericEventCookie *cookie;
|
||||
XIEvent *xi_event;
|
||||
XIRawEvent *xev;
|
||||
float x,y;
|
||||
|
||||
cookie = &xevent->xcookie;
|
||||
xi_event = (XIEvent *) cookie->data;
|
||||
xev = (XIRawEvent *) xi_event;
|
||||
|
||||
device = g_hash_table_lookup (manager_xi2->devices_by_id,
|
||||
GINT_TO_POINTER (xev->deviceid));
|
||||
if (device == NULL)
|
||||
return;
|
||||
|
||||
if (!_clutter_is_input_pointer_a11y_enabled (device))
|
||||
return;
|
||||
|
||||
switch (cookie->evtype)
|
||||
{
|
||||
case XI_RawMotion:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"raw motion: device:%d '%s'",
|
||||
device->id,
|
||||
device->device_name);
|
||||
/* We don't get actual pointer location with raw events, and we cannot
|
||||
* rely on `clutter_input_device_get_coords()` either because of
|
||||
* unreparented toplevels (like all client-side decoration windows),
|
||||
* so we need to explicitely query the pointer here...
|
||||
*/
|
||||
if (clutter_input_device_xi2_get_pointer_location (device, &x, &y))
|
||||
_clutter_input_pointer_a11y_on_motion_event (device, x, y);
|
||||
break;
|
||||
case XI_RawButtonPress:
|
||||
case XI_RawButtonRelease:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"raw button %s: device:%d '%s' button %i",
|
||||
cookie->evtype == XI_RawButtonPress
|
||||
? "press "
|
||||
: "release",
|
||||
device->id,
|
||||
device->device_name,
|
||||
xev->detail);
|
||||
_clutter_input_pointer_a11y_on_button_event (device,
|
||||
xev->detail,
|
||||
(cookie->evtype == XI_RawButtonPress));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ClutterTranslateReturn
|
||||
clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
@@ -1303,6 +1358,14 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
|
||||
if (!xi_event)
|
||||
return CLUTTER_TRANSLATE_REMOVE;
|
||||
|
||||
if (cookie->evtype == XI_RawMotion ||
|
||||
cookie->evtype == XI_RawButtonPress ||
|
||||
cookie->evtype == XI_RawButtonRelease)
|
||||
{
|
||||
handle_raw_event (manager_xi2, xevent);
|
||||
return CLUTTER_TRANSLATE_REMOVE;
|
||||
}
|
||||
|
||||
if (!(xi_event->evtype == XI_HierarchyChanged ||
|
||||
xi_event->evtype == XI_DeviceChanged ||
|
||||
xi_event->evtype == XI_PropertyEvent))
|
||||
@@ -2031,7 +2094,7 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
|
||||
GHashTable *masters, *slaves;
|
||||
XIDeviceInfo *info;
|
||||
XIEventMask event_mask;
|
||||
unsigned char mask[2] = { 0, };
|
||||
unsigned char mask[(XI_LASTEVENT + 7) / 8] = { 0, };
|
||||
int n_devices, i;
|
||||
|
||||
backend_x11 =
|
||||
@@ -2083,6 +2146,19 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
|
||||
event_mask.mask_len = sizeof (mask);
|
||||
event_mask.mask = mask;
|
||||
|
||||
clutter_device_manager_xi2_select_events (manager,
|
||||
clutter_x11_get_root_window (),
|
||||
&event_mask);
|
||||
|
||||
memset(mask, 0, sizeof (mask));
|
||||
XISetMask (mask, XI_RawMotion);
|
||||
XISetMask (mask, XI_RawButtonPress);
|
||||
XISetMask (mask, XI_RawButtonRelease);
|
||||
|
||||
event_mask.deviceid = XIAllMasterDevices;
|
||||
event_mask.mask_len = sizeof (mask);
|
||||
event_mask.mask = mask;
|
||||
|
||||
clutter_device_manager_xi2_select_events (manager,
|
||||
clutter_x11_get_root_window (),
|
||||
&event_mask);
|
||||
|
@@ -46,6 +46,11 @@ struct _ClutterInputDeviceXI2
|
||||
gint device_id;
|
||||
ClutterInputDeviceTool *current_tool;
|
||||
|
||||
guint inhibit_pointer_query_timer;
|
||||
gboolean query_status;
|
||||
float current_x;
|
||||
float current_y;
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
WacomDevice *wacom_device;
|
||||
GArray *group_modes;
|
||||
@@ -114,6 +119,9 @@ clutter_input_device_xi2_finalize (GObject *object)
|
||||
g_array_unref (device_xi2->group_modes);
|
||||
#endif
|
||||
|
||||
if (device_xi2->inhibit_pointer_query_timer)
|
||||
g_source_remove (device_xi2->inhibit_pointer_query_timer);
|
||||
|
||||
G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -293,6 +301,75 @@ clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device)
|
||||
return device_xi2->current_tool;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_input_device_xi2_query_pointer_location (ClutterInputDeviceXI2 *device_xi2)
|
||||
{
|
||||
Window xroot_window, xchild_window;
|
||||
double xroot_x, xroot_y, xwin_x, xwin_y;
|
||||
XIButtonState button_state;
|
||||
XIModifierState mod_state;
|
||||
XIGroupState group_state;
|
||||
int result;
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
result = XIQueryPointer (clutter_x11_get_default_display (),
|
||||
device_xi2->device_id,
|
||||
clutter_x11_get_root_window (),
|
||||
&xroot_window,
|
||||
&xchild_window,
|
||||
&xroot_x, &xroot_y,
|
||||
&xwin_x, &xwin_y,
|
||||
&button_state,
|
||||
&mod_state,
|
||||
&group_state);
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
if (!result)
|
||||
return FALSE;
|
||||
|
||||
device_xi2->current_x = (float) xroot_x;
|
||||
device_xi2->current_y = (float) xroot_y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clear_inhibit_pointer_query_cb (gpointer data)
|
||||
{
|
||||
ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (data);
|
||||
|
||||
device_xi2->inhibit_pointer_query_timer = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_input_device_xi2_get_pointer_location (ClutterInputDevice *device,
|
||||
float *x,
|
||||
float *y)
|
||||
|
||||
{
|
||||
ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_XI2 (device_xi2), FALSE);
|
||||
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, FALSE);
|
||||
|
||||
/* Throttle XServer queries and roundtrips using an idle timeout */
|
||||
if (device_xi2->inhibit_pointer_query_timer == 0)
|
||||
{
|
||||
device_xi2->query_status =
|
||||
clutter_input_device_xi2_query_pointer_location (device_xi2);
|
||||
device_xi2->inhibit_pointer_query_timer =
|
||||
clutter_threads_add_idle (clear_inhibit_pointer_query_cb, device_xi2);
|
||||
}
|
||||
|
||||
*x = device_xi2->current_x;
|
||||
*y = device_xi2->current_y;
|
||||
|
||||
return device_xi2->query_status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
void
|
||||
clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device,
|
||||
|
@@ -48,6 +48,9 @@ void _clutter_input_device_xi2_translate_state (ClutterEvent *event,
|
||||
void clutter_input_device_xi2_update_tool (ClutterInputDevice *device,
|
||||
ClutterInputDeviceTool *tool);
|
||||
ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device);
|
||||
gboolean clutter_input_device_xi2_get_pointer_location (ClutterInputDevice *device,
|
||||
float *x,
|
||||
float *y);
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device,
|
||||
|
@@ -12,19 +12,19 @@ clutter_c_args = [
|
||||
]
|
||||
|
||||
clutter_debug_c_args = []
|
||||
if buildtype.startswith('debug')
|
||||
clutter_debug_c_args += '-DG_DISABLE_CAST_CHECKS'
|
||||
if buildtype == 'debug'
|
||||
clutter_debug_c_args += '-DCLUTTER_ENABLE_DEBUG'
|
||||
endif
|
||||
elif buildtype == 'release'
|
||||
if get_option('debug')
|
||||
clutter_debug_c_args += [
|
||||
'-DCLUTTER_ENABLE_DEBUG',
|
||||
'-fno-omit-frame-pointer'
|
||||
]
|
||||
elif buildtype != 'plain'
|
||||
clutter_debug_c_args += [
|
||||
'-DG_DISABLE_ASSERT',
|
||||
'-DG_DISABLE_CHECKS',
|
||||
'-DG_DISABLE_CAST_CHECKS',
|
||||
]
|
||||
endif
|
||||
|
||||
supported_clutter_debug_c_args = cc.get_supported_arguments(clutter_debug_c_args)
|
||||
clutter_c_args += clutter_debug_c_args
|
||||
|
||||
clutter_pkg_deps = [
|
||||
|
@@ -114,11 +114,12 @@ test_destroy_destroy (ClutterActor *self)
|
||||
test->tex = NULL;
|
||||
}
|
||||
|
||||
g_list_free_full (test->children, (GDestroyNotify) clutter_actor_destroy);
|
||||
test->children = NULL;
|
||||
g_assert_nonnull (test->children);
|
||||
|
||||
if (CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy)
|
||||
CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy (self);
|
||||
|
||||
g_assert_null (test->children);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -4,6 +4,9 @@
|
||||
/* Have GLES 2.0 for rendering */
|
||||
#mesondefine HAVE_COGL_GLES2
|
||||
|
||||
/* Building with Sysprof profiling suport */
|
||||
#mesondefine HAVE_TRACING
|
||||
|
||||
/* Enable unit tests */
|
||||
#mesondefine ENABLE_UNIT_TESTS
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -452,9 +452,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_free_full (pipeline->layer_differences, cogl_object_unref);
|
||||
|
||||
@@ -464,6 +461,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);
|
||||
|
258
cogl/cogl/cogl-trace.c
Normal file
258
cogl/cogl/cogl-trace.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cogl-config.h"
|
||||
|
||||
#ifdef HAVE_TRACING
|
||||
|
||||
#include "cogl/cogl-trace.h"
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
#include <syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define COGL_TRACE_OUTPUT_FILE "cogl-trace-sp-capture.syscap"
|
||||
#define BUFFER_LENGTH (4096 * 4)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
char *filename;
|
||||
char *group;
|
||||
} TraceData;
|
||||
|
||||
static void
|
||||
trace_data_free (gpointer user_data)
|
||||
{
|
||||
TraceData *data = user_data;
|
||||
|
||||
data->fd = -1;
|
||||
g_clear_pointer (&data->group, g_free);
|
||||
g_clear_pointer (&data->filename, g_free);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void cogl_trace_thread_context_free (gpointer data);
|
||||
|
||||
GPrivate cogl_trace_thread_data = G_PRIVATE_INIT (cogl_trace_thread_context_free);
|
||||
CoglTraceContext *cogl_trace_context;
|
||||
GMutex cogl_trace_mutex;
|
||||
|
||||
static CoglTraceContext *
|
||||
cogl_trace_context_new (int fd,
|
||||
const char *filename)
|
||||
{
|
||||
CoglTraceContext *context;
|
||||
SysprofCaptureWriter *writer;
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
g_debug ("Initializing trace context with fd=%d", fd);
|
||||
writer = sysprof_capture_writer_new_from_fd (fd, BUFFER_LENGTH);
|
||||
}
|
||||
else if (filename != NULL)
|
||||
{
|
||||
g_debug ("Initializing trace context with filename='%s'", filename);
|
||||
writer = sysprof_capture_writer_new (filename, BUFFER_LENGTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Initializing trace context with default dilename");
|
||||
writer = sysprof_capture_writer_new (COGL_TRACE_OUTPUT_FILE, BUFFER_LENGTH);
|
||||
}
|
||||
|
||||
context = g_new0 (CoglTraceContext, 1);
|
||||
context->writer = writer;
|
||||
return context;
|
||||
}
|
||||
|
||||
static void
|
||||
cogl_trace_context_free (CoglTraceContext *trace_context)
|
||||
{
|
||||
g_clear_pointer (&trace_context->writer, sysprof_capture_writer_unref);
|
||||
g_free (trace_context);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_trace_context (TraceData *data)
|
||||
{
|
||||
g_mutex_lock (&cogl_trace_mutex);
|
||||
if (!cogl_trace_context)
|
||||
cogl_trace_context = cogl_trace_context_new (data->fd, data->filename);
|
||||
g_mutex_unlock (&cogl_trace_mutex);
|
||||
}
|
||||
|
||||
static CoglTraceThreadContext *
|
||||
cogl_trace_thread_context_new (const char *group)
|
||||
{
|
||||
CoglTraceThreadContext *thread_context;
|
||||
pid_t tid;
|
||||
|
||||
tid = (pid_t) syscall (SYS_gettid);
|
||||
|
||||
thread_context = g_new0 (CoglTraceThreadContext, 1);
|
||||
thread_context->cpu_id = -1;
|
||||
thread_context->pid = getpid ();
|
||||
thread_context->group =
|
||||
group ? g_strdup (group) : g_strdup_printf ("t:%d", tid);
|
||||
|
||||
return thread_context;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
enable_tracing_idle_callback (gpointer user_data)
|
||||
{
|
||||
CoglTraceThreadContext *thread_context =
|
||||
g_private_get (&cogl_trace_thread_data);
|
||||
TraceData *data = user_data;
|
||||
|
||||
ensure_trace_context (data);
|
||||
|
||||
if (thread_context)
|
||||
{
|
||||
g_warning ("Tracing already enabled");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
thread_context = cogl_trace_thread_context_new (data->group);
|
||||
g_private_set (&cogl_trace_thread_data, thread_context);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
cogl_trace_thread_context_free (gpointer data)
|
||||
{
|
||||
CoglTraceThreadContext *thread_context = data;
|
||||
|
||||
if (!thread_context)
|
||||
return;
|
||||
|
||||
g_free (thread_context->group);
|
||||
g_free (thread_context);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disable_tracing_idle_callback (gpointer user_data)
|
||||
{
|
||||
CoglTraceThreadContext *thread_context =
|
||||
g_private_get (&cogl_trace_thread_data);
|
||||
CoglTraceContext *trace_context;
|
||||
|
||||
if (!thread_context)
|
||||
{
|
||||
g_warning ("Tracing not enabled");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
g_private_replace (&cogl_trace_thread_data, NULL);
|
||||
|
||||
g_mutex_lock (&cogl_trace_mutex);
|
||||
trace_context = cogl_trace_context;
|
||||
sysprof_capture_writer_flush (trace_context->writer);
|
||||
|
||||
g_clear_pointer (&cogl_trace_context, cogl_trace_context_free);
|
||||
|
||||
g_mutex_unlock (&cogl_trace_mutex);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_tracing_enabled_on_thread (GMainContext *main_context,
|
||||
const char *group,
|
||||
int fd,
|
||||
const char *filename)
|
||||
{
|
||||
TraceData *data;
|
||||
GSource *source;
|
||||
|
||||
data = g_new0 (TraceData, 1);
|
||||
data->fd = fd;
|
||||
data->group = group ? strdup (group) : NULL;
|
||||
data->filename = filename ? strdup (filename) : NULL;
|
||||
|
||||
source = g_idle_source_new ();
|
||||
|
||||
g_source_set_callback (source,
|
||||
enable_tracing_idle_callback,
|
||||
data,
|
||||
trace_data_free);
|
||||
|
||||
g_source_attach (source, main_context);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_set_tracing_enabled_on_thread_with_fd (GMainContext *main_context,
|
||||
const char *group,
|
||||
int fd)
|
||||
{
|
||||
set_tracing_enabled_on_thread (main_context, group, fd, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_set_tracing_enabled_on_thread (GMainContext *main_context,
|
||||
const char *group,
|
||||
const char *filename)
|
||||
{
|
||||
set_tracing_enabled_on_thread (main_context, group, -1, filename);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_set_tracing_disabled_on_thread (GMainContext *main_context)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
source = g_idle_source_new ();
|
||||
|
||||
g_source_set_callback (source, disable_tracing_idle_callback, NULL, NULL);
|
||||
|
||||
g_source_attach (source, main_context);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
cogl_set_tracing_enabled_on_thread_with_fd (void *data,
|
||||
const char *group,
|
||||
int fd)
|
||||
{
|
||||
fprintf (stderr, "Tracing not enabled");
|
||||
}
|
||||
|
||||
void
|
||||
cogl_set_tracing_enabled_on_thread (void *data,
|
||||
const char *group,
|
||||
const char *filename)
|
||||
{
|
||||
fprintf (stderr, "Tracing not enabled");
|
||||
}
|
||||
|
||||
void
|
||||
cogl_set_tracing_disabled_on_thread (void *data)
|
||||
{
|
||||
fprintf (stderr, "Tracing not enabled");
|
||||
}
|
||||
|
||||
#endif /* HAVE_TRACING */
|
147
cogl/cogl/cogl-trace.h
Normal file
147
cogl/cogl/cogl-trace.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COGL_TRACE_H
|
||||
#define COGL_TRACE_H
|
||||
|
||||
#include "cogl-config.h"
|
||||
|
||||
#ifdef HAVE_TRACING
|
||||
|
||||
#include <glib.h>
|
||||
#include <sysprof-capture-writer.h>
|
||||
#include <sysprof-clock.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct _CoglTraceContext
|
||||
{
|
||||
SysprofCaptureWriter *writer;
|
||||
} CoglTraceContext;
|
||||
|
||||
typedef struct _CoglTraceThreadContext
|
||||
{
|
||||
int cpu_id;
|
||||
GPid pid;
|
||||
char *group;
|
||||
} CoglTraceThreadContext;
|
||||
|
||||
typedef struct _CoglTraceHead
|
||||
{
|
||||
SysprofTimeStamp begin_time;
|
||||
const char *name;
|
||||
} CoglTraceHead;
|
||||
|
||||
extern GPrivate cogl_trace_thread_data;
|
||||
extern CoglTraceContext *cogl_trace_context;
|
||||
extern GMutex cogl_trace_mutex;
|
||||
|
||||
void cogl_set_tracing_enabled_on_thread_with_fd (GMainContext *main_context,
|
||||
const char *group,
|
||||
int fd);
|
||||
|
||||
void cogl_set_tracing_enabled_on_thread (GMainContext *main_context,
|
||||
const char *group,
|
||||
const char *filename);
|
||||
|
||||
void cogl_set_tracing_disabled_on_thread (GMainContext *main_context);
|
||||
|
||||
static inline void
|
||||
cogl_trace_begin (CoglTraceHead *head,
|
||||
const char *name)
|
||||
{
|
||||
head->begin_time = g_get_monotonic_time () * 1000;
|
||||
head->name = name;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cogl_trace_end (CoglTraceHead *head)
|
||||
{
|
||||
SysprofTimeStamp end_time;
|
||||
CoglTraceContext *trace_context;
|
||||
CoglTraceThreadContext *trace_thread_context;
|
||||
|
||||
end_time = g_get_monotonic_time () * 1000;
|
||||
trace_context = cogl_trace_context;
|
||||
trace_thread_context = g_private_get (&cogl_trace_thread_data);
|
||||
|
||||
g_mutex_lock (&cogl_trace_mutex);
|
||||
if (!sysprof_capture_writer_add_mark (trace_context->writer,
|
||||
head->begin_time,
|
||||
trace_thread_context->cpu_id,
|
||||
trace_thread_context->pid,
|
||||
(uint64_t) end_time - head->begin_time,
|
||||
trace_thread_context->group,
|
||||
head->name,
|
||||
NULL))
|
||||
{
|
||||
/* XXX: g_main_context_get_thread_default() might be wrong, it probably
|
||||
* needs to store the GMainContext in CoglTraceThreadContext when creating
|
||||
* and use it here.
|
||||
*/
|
||||
if (errno == EPIPE)
|
||||
cogl_set_tracing_disabled_on_thread (g_main_context_get_thread_default ());
|
||||
}
|
||||
g_mutex_unlock (&cogl_trace_mutex);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cogl_auto_trace_end_helper (CoglTraceHead **head)
|
||||
{
|
||||
if (*head)
|
||||
cogl_trace_end (*head);
|
||||
}
|
||||
|
||||
#define COGL_TRACE_BEGIN(Name, description) \
|
||||
CoglTraceHead CoglTrace##Name = { 0 }; \
|
||||
if (g_private_get (&cogl_trace_thread_data)) \
|
||||
cogl_trace_begin (&CoglTrace##Name, description); \
|
||||
|
||||
#define COGL_TRACE_END(Name)\
|
||||
if (g_private_get (&cogl_trace_thread_data)) \
|
||||
cogl_trace_end (&CoglTrace##Name);
|
||||
|
||||
#define COGL_TRACE_BEGIN_SCOPED(Name, description) \
|
||||
CoglTraceHead CoglTrace##Name = { 0 }; \
|
||||
__attribute__((cleanup (cogl_auto_trace_end_helper))) \
|
||||
CoglTraceHead *ScopedCoglTrace##Name = NULL; \
|
||||
if (g_private_get (&cogl_trace_thread_data)) \
|
||||
{ \
|
||||
cogl_trace_begin (&CoglTrace##Name, description); \
|
||||
ScopedCoglTrace##Name = &CoglTrace##Name; \
|
||||
}
|
||||
|
||||
#else /* HAVE_TRACING */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define COGL_TRACE_BEGIN(Name, description) (void) 0
|
||||
#define COGL_TRACE_END(Name) (void) 0
|
||||
#define COGL_TRACE_BEGIN_SCOPED(Name, description) (void) 0
|
||||
|
||||
void cogl_set_tracing_enabled_on_thread_with_fd (void *data,
|
||||
const char *group,
|
||||
int fd);
|
||||
void cogl_set_tracing_enabled_on_thread (void *data,
|
||||
const char *group,
|
||||
const char *filename);
|
||||
void cogl_set_tracing_disabled_on_thread (void *data);
|
||||
|
||||
#endif /* HAVE_TRACING */
|
||||
|
||||
#endif /* COGL_TRACE_H */
|
@@ -54,41 +54,27 @@ static char *_cogl_x11_display_name = NULL;
|
||||
static GList *_cogl_xlib_renderers = NULL;
|
||||
|
||||
static void
|
||||
destroy_xlib_renderer_data (void *user_data)
|
||||
_xlib_renderer_data_free (CoglXlibRenderer *data)
|
||||
{
|
||||
CoglXlibRenderer *data = user_data;
|
||||
|
||||
if (data->xvisinfo)
|
||||
XFree (data->xvisinfo);
|
||||
|
||||
g_slice_free (CoglXlibRenderer, user_data);
|
||||
g_slice_free (CoglXlibRenderer, data);
|
||||
}
|
||||
|
||||
CoglXlibRenderer *
|
||||
_cogl_xlib_renderer_get_data (CoglRenderer *renderer)
|
||||
{
|
||||
static CoglUserDataKey key;
|
||||
CoglXlibRenderer *data;
|
||||
|
||||
/* Constructs a CoglXlibRenderer struct on demand and attaches it to
|
||||
the object using user data. It's done this way instead of using a
|
||||
subclassing hierarchy in the winsys data because all EGL winsys's
|
||||
need the EGL winsys data but only one of them wants the Xlib
|
||||
data. */
|
||||
|
||||
data = cogl_object_get_user_data (COGL_OBJECT (renderer), &key);
|
||||
if (!renderer->custom_winsys_user_data)
|
||||
renderer->custom_winsys_user_data = g_slice_new0 (CoglXlibRenderer);
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
data = g_slice_new0 (CoglXlibRenderer);
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (renderer),
|
||||
&key,
|
||||
data,
|
||||
destroy_xlib_renderer_data);
|
||||
}
|
||||
|
||||
return data;
|
||||
return renderer->custom_winsys_user_data;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -570,6 +556,8 @@ _cogl_xlib_renderer_disconnect (CoglRenderer *renderer)
|
||||
if (!renderer->foreign_xdpy && xlib_renderer->xdpy)
|
||||
XCloseDisplay (xlib_renderer->xdpy);
|
||||
|
||||
g_clear_pointer (&renderer->custom_winsys_user_data, _xlib_renderer_data_free);
|
||||
|
||||
unregister_xlib_renderer (renderer);
|
||||
}
|
||||
|
||||
|
@@ -303,6 +303,8 @@ cogl_sources = [
|
||||
'cogl-blend-string.c',
|
||||
'cogl-blend-string.h',
|
||||
'cogl-debug.c',
|
||||
'cogl-trace.c',
|
||||
'cogl-trace.h',
|
||||
'cogl-sub-texture-private.h',
|
||||
'cogl-texture-private.h',
|
||||
'cogl-texture-2d-private.h',
|
||||
|
@@ -7,6 +7,7 @@ cogl_includepath = include_directories('.', 'cogl')
|
||||
cdata = configuration_data()
|
||||
cdata.set('HAVE_COGL_GL', have_gl)
|
||||
cdata.set('HAVE_COGL_GLES2', have_gles2)
|
||||
cdata.set('HAVE_TRACING', have_profiler)
|
||||
cdata.set('ENABLE_UNIT_TESTS', have_cogl_tests)
|
||||
|
||||
cogl_config_h = configure_file(
|
||||
@@ -26,6 +27,12 @@ cogl_pkg_private_deps = [
|
||||
#uprof_dep,
|
||||
]
|
||||
|
||||
if have_profiler
|
||||
cogl_pkg_private_deps += [
|
||||
sysprof_dep,
|
||||
]
|
||||
endif
|
||||
|
||||
if have_wayland
|
||||
cogl_pkg_deps += [
|
||||
wayland_server_dep,
|
||||
@@ -87,19 +94,21 @@ if have_gles2
|
||||
endif
|
||||
|
||||
cogl_debug_c_args = []
|
||||
if buildtype.startswith('debug')
|
||||
buildtype = get_option('buildtype')
|
||||
if get_option('debug')
|
||||
cogl_debug_c_args += [
|
||||
'-DCOGL_GL_DEBUG',
|
||||
'-DCOGL_OBJECT_DEBUG',
|
||||
'-DCOGL_ENABLE_DEBUG',
|
||||
'-fno-omit-frame-pointer'
|
||||
]
|
||||
elif buildtype == 'release'
|
||||
elif buildtype != 'plain'
|
||||
cogl_debug_c_args += [
|
||||
'-DG_DISABLE_CHECKS',
|
||||
'-DG_DISABLE_CAST_CHECKS',
|
||||
'-DG_DISABLE_CAST_CHECKS'
|
||||
]
|
||||
endif
|
||||
|
||||
supported_cogl_debug_c_args = cc.get_supported_arguments(cogl_debug_c_args)
|
||||
cogl_c_args += cogl_debug_c_args
|
||||
|
||||
if have_cogl_tests
|
||||
|
@@ -49,6 +49,9 @@
|
||||
/* Building with startup notification support */
|
||||
#mesondefine HAVE_STARTUP_NOTIFICATION
|
||||
|
||||
/* Building with Sysprof profiling suport */
|
||||
#mesondefine HAVE_PROFILER
|
||||
|
||||
/* Path to Xwayland executable */
|
||||
#mesondefine XWAYLAND_PATH
|
||||
|
||||
|
@@ -127,6 +127,14 @@
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="locate-pointer-key" type="s">
|
||||
<default>'Control_L'</default>
|
||||
<summary>Modifier to use to locate the pointer</summary>
|
||||
<description>
|
||||
This key will initiate the “locate pointer” action.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<child name="keybindings" schema="org.gnome.mutter.keybindings"/>
|
||||
|
||||
</schema>
|
||||
|
@@ -61,10 +61,17 @@
|
||||
|
||||
<key name="xwayland-allow-grabs" type="b">
|
||||
<default>false</default>
|
||||
<summary>Allow grabs with Xwayland</summary>
|
||||
<summary>Allow X11 grabs to lock keyboard focus with Xwayland</summary>
|
||||
<description>
|
||||
Allow keyboard grabs issued by X11 applications running in Xwayland
|
||||
to be taken into account.
|
||||
Allow all keyboard events to be routed to X11 “override redirect”
|
||||
windows with a grab when running in Xwayland.
|
||||
|
||||
This option is to support X11 clients which map an “override redirect”
|
||||
window (which do not receive keyboard focus) and issue a keyboard
|
||||
grab to force all keyboard events to that window.
|
||||
|
||||
This option is seldom used and has no effect on regular X11 windows
|
||||
which can receive keyboard focus under normal circumstances.
|
||||
|
||||
For a X11 grab to be taken into account under Wayland, the client must
|
||||
also either send a specific X11 ClientMessage to the root window or be
|
||||
|
104
meson.build
104
meson.build
@@ -1,5 +1,5 @@
|
||||
project('mutter', 'c',
|
||||
version: '3.33.1',
|
||||
version: '3.33.2',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
@@ -264,6 +264,11 @@ if have_tests
|
||||
have_installed_tests = get_option('installed_tests')
|
||||
endif
|
||||
|
||||
have_profiler = get_option('profiler')
|
||||
if have_profiler
|
||||
sysprof_dep = dependency('sysprof-capture-3')
|
||||
endif
|
||||
|
||||
required_functions = [
|
||||
'ffs',
|
||||
'clz',
|
||||
@@ -276,54 +281,57 @@ endforeach
|
||||
|
||||
add_project_arguments('-D_GNU_SOURCE', language: 'c')
|
||||
|
||||
all_warnings = [
|
||||
'-fno-strict-aliasing',
|
||||
'-Wpointer-arith',
|
||||
'-Wmissing-declarations',
|
||||
'-Wimplicit-function-declaration',
|
||||
'-Wformat=2',
|
||||
'-Wformat-nonliteral',
|
||||
'-Wformat-security',
|
||||
'-Wstrict-prototypes',
|
||||
'-Wmissing-prototypes',
|
||||
'-Wnested-externs',
|
||||
'-Wold-style-definition',
|
||||
'-Wundef',
|
||||
'-Wunused',
|
||||
'-Wcast-align',
|
||||
'-Wmissing-noreturn',
|
||||
'-Wmissing-format-attribute',
|
||||
'-Wmissing-include-dirs',
|
||||
'-Wlogical-op',
|
||||
'-Wignored-qualifiers',
|
||||
'-Werror=redundant-decls',
|
||||
'-Werror=implicit',
|
||||
'-Werror=nonnull',
|
||||
'-Werror=init-self',
|
||||
'-Werror=main',
|
||||
'-Werror=missing-braces',
|
||||
'-Werror=sequence-point',
|
||||
'-Werror=return-type',
|
||||
'-Werror=trigraphs',
|
||||
'-Werror=array-bounds',
|
||||
'-Werror=write-strings',
|
||||
'-Werror=address',
|
||||
'-Werror=int-to-pointer-cast',
|
||||
'-Werror=pointer-to-int-cast',
|
||||
'-Werror=empty-body',
|
||||
'-Werror=write-strings',
|
||||
]
|
||||
|
||||
supported_warnings = cc.get_supported_arguments(all_warnings)
|
||||
|
||||
add_project_arguments(supported_warnings, language: 'c')
|
||||
|
||||
debug_c_args = []
|
||||
buildtype = get_option('buildtype')
|
||||
if buildtype.startswith('debug')
|
||||
debug_c_args += '-DG_ENABLE_DEBUG'
|
||||
if buildtype != 'plain'
|
||||
all_warnings = [
|
||||
'-fno-strict-aliasing',
|
||||
'-Wpointer-arith',
|
||||
'-Wmissing-declarations',
|
||||
'-Wimplicit-function-declaration',
|
||||
'-Wformat=2',
|
||||
'-Wformat-nonliteral',
|
||||
'-Wformat-security',
|
||||
'-Wstrict-prototypes',
|
||||
'-Wmissing-prototypes',
|
||||
'-Wnested-externs',
|
||||
'-Wold-style-definition',
|
||||
'-Wundef',
|
||||
'-Wunused',
|
||||
'-Wcast-align',
|
||||
'-Wmissing-noreturn',
|
||||
'-Wmissing-format-attribute',
|
||||
'-Wmissing-include-dirs',
|
||||
'-Wlogical-op',
|
||||
'-Wignored-qualifiers',
|
||||
'-Werror=redundant-decls',
|
||||
'-Werror=implicit',
|
||||
'-Werror=nonnull',
|
||||
'-Werror=init-self',
|
||||
'-Werror=main',
|
||||
'-Werror=missing-braces',
|
||||
'-Werror=sequence-point',
|
||||
'-Werror=return-type',
|
||||
'-Werror=trigraphs',
|
||||
'-Werror=array-bounds',
|
||||
'-Werror=write-strings',
|
||||
'-Werror=address',
|
||||
'-Werror=int-to-pointer-cast',
|
||||
'-Werror=pointer-to-int-cast',
|
||||
'-Werror=empty-body',
|
||||
'-Werror=write-strings',
|
||||
]
|
||||
supported_warnings = cc.get_supported_arguments(all_warnings)
|
||||
add_project_arguments(supported_warnings, language: 'c')
|
||||
endif
|
||||
|
||||
if get_option('debug')
|
||||
debug_c_args = [
|
||||
'-DG_ENABLE_DEBUG',
|
||||
'-fno-omit-frame-pointer'
|
||||
]
|
||||
supported_debug_c_args = cc.get_supported_arguments(debug_c_args)
|
||||
add_project_arguments(supported_debug_c_args, language: 'c')
|
||||
endif
|
||||
add_project_arguments(debug_c_args, language: 'c')
|
||||
|
||||
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
|
||||
|
||||
@@ -343,6 +351,7 @@ cdata.set('HAVE_LIBWACOM', have_libwacom)
|
||||
cdata.set('HAVE_SM', have_sm)
|
||||
cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
|
||||
cdata.set('HAVE_INTROSPECTION', have_introspection)
|
||||
cdata.set('HAVE_PROFILER', have_profiler)
|
||||
|
||||
xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base')
|
||||
cdata.set_quoted('XKB_BASE', xkb_base)
|
||||
@@ -408,6 +417,7 @@ output = [
|
||||
' SM....................... ' + have_sm.to_string(),
|
||||
' Startup notification..... ' + have_startup_notification.to_string(),
|
||||
' Introspection............ ' + have_introspection.to_string(),
|
||||
' Profiler................. ' + have_profiler.to_string(),
|
||||
'',
|
||||
' Tests:',
|
||||
'',
|
||||
|
@@ -123,6 +123,12 @@ option('tests',
|
||||
description: 'Enable tests globally. Specific test suites can be controlled with core_tests, clutter_tests, and cogl_tests'
|
||||
)
|
||||
|
||||
option('profiler',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable Sysprof tracing'
|
||||
)
|
||||
|
||||
option('installed_tests',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
|
@@ -9,6 +9,7 @@ data/org.gnome.mutter.gschema.xml.in
|
||||
data/org.gnome.mutter.wayland.gschema.xml.in
|
||||
src/backends/meta-input-settings.c
|
||||
src/backends/meta-monitor-manager.c
|
||||
src/backends/meta-profiler.c
|
||||
src/compositor/compositor.c
|
||||
src/compositor/meta-background.c
|
||||
src/core/bell.c
|
||||
|
77
po/hu.po
77
po/hu.po
@@ -6,20 +6,20 @@
|
||||
# Gabor Sari <saga at externet dot hu>, 2003.
|
||||
# Laszlo Dvornik <dvornik at gnome dot hu>, 2004.
|
||||
# Gabor Kelemen <kelemeng at gnome dot hu>, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013.
|
||||
# Balázs Úr <urbalazs at gmail dot com>, 2013, 2014, 2015, 2016, 2017, 2018, 2019.
|
||||
# Balázs Úr <ur.balazs at fsf dot hu>, 2013, 2014, 2015, 2016, 2017, 2018, 2019.
|
||||
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-05 21:06+0100\n"
|
||||
"Last-Translator: Balázs Úr <urbalazs@gmail.com>\n"
|
||||
"POT-Creation-Date: 2019-05-31 18:48+0000\n"
|
||||
"PO-Revision-Date: 2019-06-01 17:46+0200\n"
|
||||
"Last-Translator: Balázs Úr <ur.balazs at fsf dot hu>\n"
|
||||
"Language-Team: Hungarian <gnome-hu-list at gnome dot org>\n"
|
||||
"Language: hu\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Lokalize 1.2\n"
|
||||
"X-Generator: Lokalize 18.12.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
@@ -395,7 +395,9 @@ msgid ""
|
||||
"proof. Currently possible keywords: • “scale-monitor-framebuffer” — makes "
|
||||
"mutter default to layout logical monitors in a logical pixel coordinate "
|
||||
"space, while scaling monitor framebuffers instead of window content, to "
|
||||
"manage HiDPI monitors. Does not require a restart."
|
||||
"manage HiDPI monitors. Does not require a restart. • “rt-scheduler” — makes "
|
||||
"mutter request a low priority real-time scheduling. The executable or user "
|
||||
"must have CAP_SYS_NICE. Requires a restart."
|
||||
msgstr ""
|
||||
"A kísérleti funkciók engedélyezéséhez adja hozzá a funkció kulcsszavát a "
|
||||
"listához. A funkció a betűszedő újraindítását igényelheti az adott "
|
||||
@@ -406,21 +408,23 @@ msgstr ""
|
||||
"teszi a mutter programot a logikai monitorok elrendezéséhez egy logikai "
|
||||
"képpontkoordináta-térben, miközben átméretezi a monitor keretpufferét az "
|
||||
"ablaktartalom helyett azért, hogy kezelje a HiDPI monitorokat. Nem igényel "
|
||||
"újraindítást."
|
||||
"újraindítást. • „rt-scheduler” — alacsony prioritású, valós idejű ütemezésre "
|
||||
"kéri a mutter programot. A programnak vagy a felhasználónak CAP_SYS_NICE "
|
||||
"értékkel kell rendelkeznie. Újraindítást igényel."
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:141
|
||||
#: data/org.gnome.mutter.gschema.xml.in:145
|
||||
msgid "Select window from tab popup"
|
||||
msgstr "Ablakok kiválasztása tab billentyűre felugró ablakból"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:146
|
||||
#: data/org.gnome.mutter.gschema.xml.in:150
|
||||
msgid "Cancel tab popup"
|
||||
msgstr "Tab felugró kikapcsolása"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:151
|
||||
#: data/org.gnome.mutter.gschema.xml.in:155
|
||||
msgid "Switch monitor configurations"
|
||||
msgstr "Monitorkonfiguráció átváltása"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:156
|
||||
#: data/org.gnome.mutter.gschema.xml.in:160
|
||||
msgid "Rotates the built-in monitor configuration"
|
||||
msgstr "Cserélgeti a beépített monitorkonfigurációkat"
|
||||
|
||||
@@ -525,7 +529,7 @@ msgstr ""
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2423
|
||||
#: src/backends/meta-input-settings.c:2426
|
||||
#, c-format
|
||||
msgid "Mode Switch (Group %d)"
|
||||
msgstr "Módkapcsoló (%d. csoport)"
|
||||
@@ -533,34 +537,34 @@ msgstr "Módkapcsoló (%d. csoport)"
|
||||
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
|
||||
#. * mapping through the available outputs.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2446
|
||||
#: src/backends/meta-input-settings.c:2449
|
||||
msgid "Switch monitor"
|
||||
msgstr "Monitorváltás"
|
||||
|
||||
#: src/backends/meta-input-settings.c:2448
|
||||
#: src/backends/meta-input-settings.c:2451
|
||||
msgid "Show on-screen help"
|
||||
msgstr "Képernyősúgó megjelenítése"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:954
|
||||
#: src/backends/meta-monitor-manager.c:976
|
||||
msgid "Built-in display"
|
||||
msgstr "Beépített kijelző"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:986
|
||||
#: src/backends/meta-monitor-manager.c:1008
|
||||
msgid "Unknown"
|
||||
msgstr "Ismeretlen"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:988
|
||||
#: src/backends/meta-monitor-manager.c:1010
|
||||
msgid "Unknown Display"
|
||||
msgstr "Ismeretlen kijelző"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:996
|
||||
#: src/backends/meta-monitor-manager.c:1018
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:1004
|
||||
#: src/backends/meta-monitor-manager.c:1026
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name followed by product/model name where size in "
|
||||
@@ -568,9 +572,14 @@ msgctxt ""
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#. Translators: this string will appear in Sysprof
|
||||
#: src/backends/meta-profiler.c:82
|
||||
msgid "Compositor"
|
||||
msgstr "Betűszedő"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: src/compositor/compositor.c:482
|
||||
#: src/compositor/compositor.c:510
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display “%s”."
|
||||
@@ -578,7 +587,7 @@ msgstr ""
|
||||
"Már fut egy másik kompozitálás-kezelő a(z) %i. képernyőn a(z) „%s” "
|
||||
"megjelenítőn."
|
||||
|
||||
#: src/core/bell.c:252
|
||||
#: src/core/bell.c:192
|
||||
msgid "Bell event"
|
||||
msgstr "Csengetés esemény"
|
||||
|
||||
@@ -628,16 +637,16 @@ msgid "Run with X11 backend"
|
||||
msgstr "Futtatás X11 háttérprogrammal"
|
||||
|
||||
#. Translators: %s is a window title
|
||||
#: src/core/meta-close-dialog-default.c:150
|
||||
#: src/core/meta-close-dialog-default.c:151
|
||||
#, c-format
|
||||
msgid "“%s” is not responding."
|
||||
msgstr "„%s” nem válaszol."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:152
|
||||
#: src/core/meta-close-dialog-default.c:153
|
||||
msgid "Application is not responding."
|
||||
msgstr "Az alkalmazás nem válaszol."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:157
|
||||
#: src/core/meta-close-dialog-default.c:158
|
||||
msgid ""
|
||||
"You may choose to wait a short while for it to continue or force the "
|
||||
"application to quit entirely."
|
||||
@@ -645,11 +654,11 @@ msgstr ""
|
||||
"Várhat egy kicsit a folytatódására, vagy kikényszerítheti az alkalmazás "
|
||||
"teljes kilépését."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:164
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Force Quit"
|
||||
msgstr "_Erőltetett kilépés"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:164
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Wait"
|
||||
msgstr "Vá_rakozás"
|
||||
|
||||
@@ -690,7 +699,7 @@ msgstr "A Mutter ablakkezelőt a részletes mód támogatása nélkül fordítot
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "Módkapcsoló: %d. mód"
|
||||
|
||||
#: src/x11/meta-x11-display.c:666
|
||||
#: src/x11/meta-x11-display.c:674
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Display “%s” already has a window manager; try using the --replace option to "
|
||||
@@ -699,20 +708,25 @@ msgstr ""
|
||||
"A(z) „%s” kijelző már rendelkezik ablakkezelővel; próbálja a --replace "
|
||||
"kapcsolóval helyettesíteni a jelenlegi ablakkezelőt."
|
||||
|
||||
#: src/x11/meta-x11-display.c:1008
|
||||
#: src/x11/meta-x11-display.c:1016
|
||||
msgid "Failed to initialize GDK\n"
|
||||
msgstr "A GDK előkészítése meghiúsult\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1032
|
||||
#: src/x11/meta-x11-display.c:1040
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "Nem sikerült megnyitni a(z) „%s” X Window rendszer képernyőt\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1115
|
||||
#: src/x11/meta-x11-display.c:1124
|
||||
#, c-format
|
||||
msgid "Screen %d on display “%s” is invalid\n"
|
||||
msgstr "A(z) %d. képernyő a(z) „%s” megjelenítőn érvénytelen\n"
|
||||
|
||||
#: src/x11/meta-x11-selection-input-stream.c:445
|
||||
#, c-format
|
||||
msgid "Format %s not supported"
|
||||
msgstr "A(z) %s formátum nem támogatott"
|
||||
|
||||
#: src/x11/session.c:1821
|
||||
msgid ""
|
||||
"These windows do not support “save current setup” and will have to be "
|
||||
@@ -721,8 +735,7 @@ msgstr ""
|
||||
"Az alábbi ablakok nem támogatják az „aktuális beállítások mentését”, emiatt "
|
||||
"ezeket a legközelebbi bejelentkezéskor manuálisan újra kell indítania."
|
||||
|
||||
#: src/x11/window-props.c:568
|
||||
#: src/x11/window-props.c:569
|
||||
#, c-format
|
||||
msgid "%s (on %s)"
|
||||
msgstr "%s (ezen: %s)"
|
||||
|
||||
|
@@ -66,6 +66,10 @@
|
||||
#include "meta/meta-backend.h"
|
||||
#include "meta/util.h"
|
||||
|
||||
#ifdef HAVE_PROFILER
|
||||
#include "backends/meta-profiler.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
@@ -127,6 +131,10 @@ struct _MetaBackendPrivate
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PROFILER
|
||||
MetaProfiler *profiler;
|
||||
#endif
|
||||
|
||||
ClutterBackend *clutter_backend;
|
||||
ClutterActor *stage;
|
||||
|
||||
@@ -193,6 +201,10 @@ meta_backend_finalize (GObject *object)
|
||||
|
||||
g_clear_object (&priv->settings);
|
||||
|
||||
#ifdef HAVE_PROFILER
|
||||
g_clear_object (&priv->profiler);
|
||||
#endif
|
||||
|
||||
G_OBJECT_CLASS (meta_backend_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -841,6 +853,10 @@ meta_backend_initable_init (GInitable *initable,
|
||||
system_bus_gotten_cb,
|
||||
backend);
|
||||
|
||||
#ifdef HAVE_PROFILER
|
||||
priv->profiler = meta_profiler_new ();
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@@ -353,7 +353,7 @@ find_builtin_output (MetaInputMapper *mapper,
|
||||
return panel != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
guess_candidates (MetaInputMapper *mapper,
|
||||
MetaMapperInputInfo *input,
|
||||
DeviceCandidates *info)
|
||||
@@ -387,15 +387,7 @@ guess_candidates (MetaInputMapper *mapper,
|
||||
find_builtin_output (mapper, &info->candidates[META_MATCH_IS_BUILTIN]);
|
||||
}
|
||||
|
||||
if (best < N_OUTPUT_MATCHES)
|
||||
{
|
||||
info->best = best;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
info->best = best;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -408,8 +400,7 @@ mapping_helper_add (MappingHelper *helper,
|
||||
|
||||
info.input = input;
|
||||
|
||||
if (!guess_candidates (mapper, input, &info))
|
||||
return;
|
||||
guess_candidates (mapper, input, &info);
|
||||
|
||||
for (i = 0; i < helper->device_maps->len; i++)
|
||||
{
|
||||
|
@@ -76,7 +76,8 @@ struct _MetaInputSettingsPrivate
|
||||
GSettings *trackball_settings;
|
||||
GSettings *keyboard_settings;
|
||||
GSettings *gsd_settings;
|
||||
GSettings *a11y_settings;
|
||||
GSettings *keyboard_a11y_settings;
|
||||
GSettings *mouse_a11y_settings;
|
||||
|
||||
GHashTable *mappable_devices;
|
||||
|
||||
@@ -161,7 +162,8 @@ meta_input_settings_dispose (GObject *object)
|
||||
g_clear_object (&priv->trackball_settings);
|
||||
g_clear_object (&priv->keyboard_settings);
|
||||
g_clear_object (&priv->gsd_settings);
|
||||
g_clear_object (&priv->a11y_settings);
|
||||
g_clear_object (&priv->keyboard_a11y_settings);
|
||||
g_clear_object (&priv->mouse_a11y_settings);
|
||||
g_clear_object (&priv->input_mapper);
|
||||
g_clear_pointer (&priv->mappable_devices, g_hash_table_unref);
|
||||
g_clear_pointer (&priv->current_tools, g_hash_table_unref);
|
||||
@@ -300,9 +302,30 @@ update_touchpad_left_handed (MetaInputSettings *input_settings,
|
||||
}
|
||||
else
|
||||
{
|
||||
settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
|
||||
input_settings_class->set_left_handed,
|
||||
enabled);
|
||||
GSList *devices, *l;
|
||||
|
||||
devices = meta_input_settings_get_devices (input_settings,
|
||||
CLUTTER_TOUCHPAD_DEVICE);
|
||||
|
||||
for (l = devices; l; l = l->next)
|
||||
{
|
||||
#ifdef HAVE_LIBWACOM
|
||||
WacomDevice *wacom_device;
|
||||
|
||||
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
|
||||
device);
|
||||
/* "Touchpads" with a wacom description will be rotated along their tablets */
|
||||
if (wacom_device &&
|
||||
(libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
settings_device_set_bool_setting (input_settings, l->data,
|
||||
input_settings_class->set_left_handed,
|
||||
enabled);
|
||||
}
|
||||
|
||||
g_slist_free (devices);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,8 +1089,12 @@ update_tablet_left_handed (MetaInputSettings *input_settings,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaInputSettingsClass *input_settings_class;
|
||||
MetaInputSettingsPrivate *priv;
|
||||
const GSList *devices, *l;
|
||||
gboolean enabled;
|
||||
|
||||
priv = meta_input_settings_get_instance_private (input_settings);
|
||||
|
||||
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
|
||||
clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
|
||||
clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE &&
|
||||
@@ -1089,10 +1116,18 @@ update_tablet_left_handed (MetaInputSettings *input_settings,
|
||||
|
||||
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
|
||||
enabled = g_settings_get_boolean (settings, "left-handed");
|
||||
devices = clutter_device_manager_peek_devices (priv->device_manager);
|
||||
|
||||
settings_device_set_bool_setting (input_settings, device,
|
||||
input_settings_class->set_left_handed,
|
||||
enabled);
|
||||
for (l = devices; l; l = l->next)
|
||||
{
|
||||
if (l->data != device &&
|
||||
!clutter_input_device_is_grouped (device, l->data))
|
||||
continue;
|
||||
|
||||
settings_device_set_bool_setting (input_settings, l->data,
|
||||
input_settings_class->set_left_handed,
|
||||
enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1191,10 +1226,10 @@ apply_mappable_device_settings (MetaInputSettings *input_settings,
|
||||
}
|
||||
}
|
||||
|
||||
struct _a11y_settings_flags_pair {
|
||||
struct _keyboard_a11y_settings_flags_pair {
|
||||
const char *name;
|
||||
ClutterKeyboardA11yFlags flag;
|
||||
} settings_flags_pair[] = {
|
||||
} keyboard_a11y_settings_flags_pair[] = {
|
||||
{ "enable", CLUTTER_A11Y_KEYBOARD_ENABLED },
|
||||
{ "timeout-enable", CLUTTER_A11Y_TIMEOUT_ENABLED },
|
||||
{ "mousekeys-enable", CLUTTER_A11Y_MOUSE_KEYS_ENABLED },
|
||||
@@ -1225,23 +1260,23 @@ load_keyboard_a11y_settings (MetaInputSettings *input_settings,
|
||||
return;
|
||||
|
||||
kbd_a11y_settings.controls = 0;
|
||||
for (i = 0; i < G_N_ELEMENTS (settings_flags_pair); i++)
|
||||
for (i = 0; i < G_N_ELEMENTS (keyboard_a11y_settings_flags_pair); i++)
|
||||
{
|
||||
if (g_settings_get_boolean (priv->a11y_settings, settings_flags_pair[i].name))
|
||||
kbd_a11y_settings.controls |= settings_flags_pair[i].flag;
|
||||
if (g_settings_get_boolean (priv->keyboard_a11y_settings, keyboard_a11y_settings_flags_pair[i].name))
|
||||
kbd_a11y_settings.controls |= keyboard_a11y_settings_flags_pair[i].flag;
|
||||
}
|
||||
|
||||
kbd_a11y_settings.timeout_delay = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.timeout_delay = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"disable-timeout");
|
||||
kbd_a11y_settings.slowkeys_delay = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.slowkeys_delay = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"slowkeys-delay");
|
||||
kbd_a11y_settings.debounce_delay = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.debounce_delay = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"bouncekeys-delay");
|
||||
kbd_a11y_settings.mousekeys_init_delay = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.mousekeys_init_delay = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"mousekeys-init-delay");
|
||||
kbd_a11y_settings.mousekeys_max_speed = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.mousekeys_max_speed = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"mousekeys-max-speed");
|
||||
kbd_a11y_settings.mousekeys_accel_time = g_settings_get_int (priv->a11y_settings,
|
||||
kbd_a11y_settings.mousekeys_accel_time = g_settings_get_int (priv->keyboard_a11y_settings,
|
||||
"mousekeys-accel-time");
|
||||
|
||||
clutter_device_manager_set_kbd_a11y_settings (priv->device_manager, &kbd_a11y_settings);
|
||||
@@ -1256,25 +1291,121 @@ on_keyboard_a11y_settings_changed (ClutterDeviceManager *device_manager,
|
||||
MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (settings_flags_pair); i++)
|
||||
for (i = 0; i < G_N_ELEMENTS (keyboard_a11y_settings_flags_pair); i++)
|
||||
{
|
||||
if (settings_flags_pair[i].flag & what_changed)
|
||||
g_settings_set_boolean (priv->a11y_settings,
|
||||
settings_flags_pair[i].name,
|
||||
(new_flags & settings_flags_pair[i].flag) ? TRUE : FALSE);
|
||||
if (keyboard_a11y_settings_flags_pair[i].flag & what_changed)
|
||||
g_settings_set_boolean (priv->keyboard_a11y_settings,
|
||||
keyboard_a11y_settings_flags_pair[i].name,
|
||||
(new_flags & keyboard_a11y_settings_flags_pair[i].flag) ? TRUE : FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_a11y_settings_changed (GSettings *settings,
|
||||
const char *key,
|
||||
gpointer user_data)
|
||||
meta_input_keyboard_a11y_settings_changed (GSettings *settings,
|
||||
const char *key,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data);
|
||||
|
||||
load_keyboard_a11y_settings (input_settings, NULL);
|
||||
}
|
||||
|
||||
struct _pointer_a11y_settings_flags_pair {
|
||||
const char *name;
|
||||
ClutterPointerA11yFlags flag;
|
||||
} pointer_a11y_settings_flags_pair[] = {
|
||||
{ "secondary-click-enabled", CLUTTER_A11Y_SECONDARY_CLICK_ENABLED },
|
||||
{ "dwell-click-enabled", CLUTTER_A11Y_DWELL_ENABLED },
|
||||
};
|
||||
|
||||
static ClutterPointerA11yDwellDirection
|
||||
pointer_a11y_dwell_direction_from_setting (MetaInputSettings *input_settings,
|
||||
const char *key)
|
||||
{
|
||||
MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
|
||||
GDesktopMouseDwellDirection dwell_gesture_direction;
|
||||
|
||||
dwell_gesture_direction = g_settings_get_enum (priv->mouse_a11y_settings, key);
|
||||
switch (dwell_gesture_direction)
|
||||
{
|
||||
case G_DESKTOP_MOUSE_DWELL_DIRECTION_LEFT:
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_LEFT;
|
||||
break;
|
||||
case G_DESKTOP_MOUSE_DWELL_DIRECTION_RIGHT:
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_RIGHT;
|
||||
break;
|
||||
case G_DESKTOP_MOUSE_DWELL_DIRECTION_UP:
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_UP;
|
||||
break;
|
||||
case G_DESKTOP_MOUSE_DWELL_DIRECTION_DOWN:
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_DOWN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CLUTTER_A11Y_DWELL_DIRECTION_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_pointer_a11y_settings (MetaInputSettings *input_settings,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
|
||||
ClutterPointerA11ySettings pointer_a11y_settings;
|
||||
ClutterInputDevice *core_pointer;
|
||||
GDesktopMouseDwellMode dwell_mode;
|
||||
|
||||
guint i;
|
||||
|
||||
core_pointer = clutter_device_manager_get_core_device (priv->device_manager, CLUTTER_POINTER_DEVICE);
|
||||
if (device && device != core_pointer)
|
||||
return;
|
||||
|
||||
clutter_device_manager_get_pointer_a11y_settings (priv->device_manager, &pointer_a11y_settings);
|
||||
pointer_a11y_settings.controls = 0;
|
||||
for (i = 0; i < G_N_ELEMENTS (pointer_a11y_settings_flags_pair); i++)
|
||||
{
|
||||
if (g_settings_get_boolean (priv->mouse_a11y_settings, pointer_a11y_settings_flags_pair[i].name))
|
||||
pointer_a11y_settings.controls |= pointer_a11y_settings_flags_pair[i].flag;
|
||||
}
|
||||
|
||||
/* "secondary-click-time" is expressed in seconds */
|
||||
pointer_a11y_settings.secondary_click_delay =
|
||||
(1000 * g_settings_get_double (priv->mouse_a11y_settings, "secondary-click-time"));
|
||||
/* "dwell-time" is expressed in seconds */
|
||||
pointer_a11y_settings.dwell_delay =
|
||||
(1000 * g_settings_get_double (priv->mouse_a11y_settings, "dwell-time"));
|
||||
pointer_a11y_settings.dwell_threshold = g_settings_get_int (priv->mouse_a11y_settings,
|
||||
"dwell-threshold");
|
||||
|
||||
dwell_mode = g_settings_get_enum (priv->mouse_a11y_settings, "dwell-mode");
|
||||
if (dwell_mode == G_DESKTOP_MOUSE_DWELL_MODE_WINDOW)
|
||||
pointer_a11y_settings.dwell_mode = CLUTTER_A11Y_DWELL_MODE_WINDOW;
|
||||
else
|
||||
pointer_a11y_settings.dwell_mode = CLUTTER_A11Y_DWELL_MODE_GESTURE;
|
||||
|
||||
pointer_a11y_settings.dwell_gesture_single =
|
||||
pointer_a11y_dwell_direction_from_setting (input_settings, "dwell-gesture-single");
|
||||
pointer_a11y_settings.dwell_gesture_double =
|
||||
pointer_a11y_dwell_direction_from_setting (input_settings, "dwell-gesture-double");
|
||||
pointer_a11y_settings.dwell_gesture_drag =
|
||||
pointer_a11y_dwell_direction_from_setting (input_settings, "dwell-gesture-drag");
|
||||
pointer_a11y_settings.dwell_gesture_secondary =
|
||||
pointer_a11y_dwell_direction_from_setting (input_settings, "dwell-gesture-secondary");
|
||||
|
||||
clutter_device_manager_set_pointer_a11y_settings (priv->device_manager, &pointer_a11y_settings);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_mouse_a11y_settings_changed (GSettings *settings,
|
||||
const char *key,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data);
|
||||
|
||||
load_pointer_a11y_settings (input_settings, NULL);
|
||||
}
|
||||
|
||||
static GSettings *
|
||||
lookup_device_settings (ClutterInputDevice *device)
|
||||
{
|
||||
@@ -1556,6 +1687,7 @@ apply_device_settings (MetaInputSettings *input_settings,
|
||||
priv->trackball_settings,
|
||||
device);
|
||||
load_keyboard_a11y_settings (input_settings, device);
|
||||
load_pointer_a11y_settings (input_settings, device);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1856,12 +1988,16 @@ meta_input_settings_init (MetaInputSettings *settings)
|
||||
clutter_settings_get_default(), "double-click-time",
|
||||
G_SETTINGS_BIND_GET);
|
||||
|
||||
priv->a11y_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard");
|
||||
g_signal_connect (priv->a11y_settings, "changed",
|
||||
G_CALLBACK (meta_input_a11y_settings_changed), settings);
|
||||
priv->keyboard_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard");
|
||||
g_signal_connect (priv->keyboard_a11y_settings, "changed",
|
||||
G_CALLBACK (meta_input_keyboard_a11y_settings_changed), settings);
|
||||
g_signal_connect (priv->device_manager, "kbd-a11y-flags-changed",
|
||||
G_CALLBACK (on_keyboard_a11y_settings_changed), settings);
|
||||
|
||||
priv->mouse_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.mouse");
|
||||
g_signal_connect (priv->mouse_a11y_settings, "changed",
|
||||
G_CALLBACK (meta_input_mouse_a11y_settings_changed), settings);
|
||||
|
||||
priv->mappable_devices =
|
||||
g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) device_mapping_info_free);
|
||||
|
||||
|
206
src/backends/meta-profiler.c
Normal file
206
src/backends/meta-profiler.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Endless, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "src/backends/meta-profiler.h"
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "cogl/cogl-trace.h"
|
||||
|
||||
#define META_SYSPROF_PROFILER_DBUS_PATH "/org/gnome/Sysprof3/Profiler"
|
||||
|
||||
struct _MetaProfiler
|
||||
{
|
||||
MetaDBusSysprof3ProfilerSkeleton parent_instance;
|
||||
|
||||
GDBusConnection *connection;
|
||||
GCancellable *cancellable;
|
||||
|
||||
gboolean running;
|
||||
};
|
||||
|
||||
static void
|
||||
meta_sysprof_capturer_init_iface (MetaDBusSysprof3ProfilerIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaProfiler,
|
||||
meta_profiler,
|
||||
META_DBUS_TYPE_SYSPROF3_PROFILER_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SYSPROF3_PROFILER,
|
||||
meta_sysprof_capturer_init_iface))
|
||||
|
||||
static gboolean
|
||||
handle_start (MetaDBusSysprof3Profiler *dbus_profiler,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *options,
|
||||
GVariant *fd_variant)
|
||||
{
|
||||
MetaProfiler *profiler = META_PROFILER (dbus_profiler);
|
||||
GMainContext *main_context = g_main_context_default ();
|
||||
GDBusMessage *message;
|
||||
GUnixFDList *fd_list;
|
||||
const char *group_name;
|
||||
int position;
|
||||
int fd = -1;
|
||||
|
||||
if (profiler->running)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Profiler already running");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_variant_get (fd_variant, "h", &position);
|
||||
|
||||
message = g_dbus_method_invocation_get_message (invocation);
|
||||
fd_list = g_dbus_message_get_unix_fd_list (message);
|
||||
if (fd_list)
|
||||
fd = g_unix_fd_list_get (fd_list, position, NULL);
|
||||
|
||||
/* Translators: this string will appear in Sysprof */
|
||||
group_name = _("Compositor");
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
cogl_set_tracing_enabled_on_thread_with_fd (main_context,
|
||||
group_name,
|
||||
fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
cogl_set_tracing_enabled_on_thread (main_context,
|
||||
group_name,
|
||||
"mutter-profile.syscap");
|
||||
}
|
||||
|
||||
profiler->running = TRUE;
|
||||
|
||||
g_debug ("Profiler running");
|
||||
|
||||
meta_dbus_sysprof3_profiler_complete_start (dbus_profiler, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_stop (MetaDBusSysprof3Profiler *dbus_profiler,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
MetaProfiler *profiler = META_PROFILER (dbus_profiler);
|
||||
|
||||
if (!profiler->running)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Profiler not running");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cogl_set_tracing_disabled_on_thread (g_main_context_default ());
|
||||
profiler->running = FALSE;
|
||||
|
||||
g_debug ("Stopping profiler");
|
||||
|
||||
meta_dbus_sysprof3_profiler_complete_stop (dbus_profiler, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_sysprof_capturer_init_iface (MetaDBusSysprof3ProfilerIface *iface)
|
||||
{
|
||||
iface->handle_start = handle_start;
|
||||
iface->handle_stop = handle_stop;
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GDBusConnection) connection = NULL;
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
g_autoptr (GError) error = NULL;
|
||||
MetaProfiler *profiler;
|
||||
|
||||
connection = g_bus_get_finish (result, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
g_warning ("Failed to get session bus: %s\n", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
profiler = META_PROFILER (user_data);
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (profiler);
|
||||
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
connection,
|
||||
META_SYSPROF_PROFILER_DBUS_PATH,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Failed to export profiler object: %s\n", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
profiler->connection = g_steal_pointer (&connection);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_profiler_finalize (GObject *object)
|
||||
{
|
||||
MetaProfiler *self = (MetaProfiler *)object;
|
||||
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
|
||||
g_clear_object (&self->cancellable);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
G_OBJECT_CLASS (meta_profiler_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_profiler_class_init (MetaProfilerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_profiler_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_profiler_init (MetaProfiler *self)
|
||||
{
|
||||
self->cancellable = g_cancellable_new ();
|
||||
|
||||
g_bus_get (G_BUS_TYPE_SESSION,
|
||||
self->cancellable,
|
||||
on_bus_acquired_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
MetaProfiler *
|
||||
meta_profiler_new (void)
|
||||
{
|
||||
return g_object_new (META_TYPE_PROFILER, NULL);
|
||||
}
|
41
src/backends/meta-profiler.h
Normal file
41
src/backends/meta-profiler.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Endless, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_PROFILER_H
|
||||
#define META_PROFILER_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta-dbus-sysprof3-profiler.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_PROFILER (meta_profiler_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (MetaProfiler,
|
||||
meta_profiler,
|
||||
META,
|
||||
PROFILER,
|
||||
MetaDBusSysprof3ProfilerSkeleton)
|
||||
|
||||
MetaProfiler * meta_profiler_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_PROFILER_H */
|
@@ -66,6 +66,6 @@ void meta_settings_get_xwayland_grab_patterns (MetaSettings *settings,
|
||||
GPtrArray **whitelist_patterns,
|
||||
GPtrArray **blacklist_patterns);
|
||||
|
||||
gboolean meta_settings_are_xwayland_grabs_allowed (MetaSettings *settings);
|
||||
gboolean meta_settings_are_xwayland_grabs_allowed (MetaSettings *settings);
|
||||
|
||||
#endif /* META_SETTINGS_PRIVATE_H */
|
||||
|
@@ -404,7 +404,7 @@ meta_settings_get_xwayland_grab_patterns (MetaSettings *settings,
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_settings_are_xwayland_grabs_allowed (MetaSettings *settings)
|
||||
meta_settings_are_xwayland_grabs_allowed (MetaSettings *settings)
|
||||
{
|
||||
return (settings->xwayland_allow_grabs);
|
||||
}
|
||||
|
@@ -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 *
|
||||
|
@@ -2126,6 +2126,18 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
|
||||
}
|
||||
}
|
||||
|
||||
static MetaDumbBuffer *
|
||||
secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
||||
{
|
||||
MetaDumbBuffer *current_dumb_fb;
|
||||
|
||||
current_dumb_fb = secondary_gpu_state->cpu.dumb_fb;
|
||||
if (current_dumb_fb == &secondary_gpu_state->cpu.dumb_fbs[0])
|
||||
return &secondary_gpu_state->cpu.dumb_fbs[1];
|
||||
else
|
||||
return &secondary_gpu_state->cpu.dumb_fbs[0];
|
||||
}
|
||||
|
||||
typedef struct _PixelFormatMap {
|
||||
uint32_t drm_format;
|
||||
CoglPixelFormat cogl_format;
|
||||
@@ -2192,47 +2204,28 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *cogl_context = framebuffer->context;
|
||||
int width, height;
|
||||
uint8_t *target_data;
|
||||
int target_stride_bytes;
|
||||
uint32_t target_fb_id;
|
||||
uint32_t target_drm_format;
|
||||
MetaDumbBuffer *next_dumb_fb;
|
||||
MetaDumbBuffer *current_dumb_fb;
|
||||
MetaDumbBuffer *dumb_fb;
|
||||
CoglBitmap *dumb_bitmap;
|
||||
CoglPixelFormat cogl_format;
|
||||
gboolean ret;
|
||||
MetaDrmBufferDumb *buffer_dumb;
|
||||
|
||||
width = cogl_framebuffer_get_width (framebuffer);
|
||||
height = cogl_framebuffer_get_height (framebuffer);
|
||||
dumb_fb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
|
||||
|
||||
current_dumb_fb = secondary_gpu_state->cpu.dumb_fb;
|
||||
if (current_dumb_fb == &secondary_gpu_state->cpu.dumb_fbs[0])
|
||||
next_dumb_fb = &secondary_gpu_state->cpu.dumb_fbs[1];
|
||||
else
|
||||
next_dumb_fb = &secondary_gpu_state->cpu.dumb_fbs[0];
|
||||
secondary_gpu_state->cpu.dumb_fb = next_dumb_fb;
|
||||
g_assert (cogl_framebuffer_get_width (framebuffer) == dumb_fb->width);
|
||||
g_assert (cogl_framebuffer_get_height (framebuffer) == dumb_fb->height);
|
||||
|
||||
g_assert (width == secondary_gpu_state->cpu.dumb_fb->width);
|
||||
g_assert (height == secondary_gpu_state->cpu.dumb_fb->height);
|
||||
|
||||
target_data = secondary_gpu_state->cpu.dumb_fb->map;
|
||||
target_stride_bytes = secondary_gpu_state->cpu.dumb_fb->stride_bytes;
|
||||
target_fb_id = secondary_gpu_state->cpu.dumb_fb->fb_id;
|
||||
target_drm_format = secondary_gpu_state->cpu.dumb_fb->drm_format;
|
||||
|
||||
ret = cogl_pixel_format_from_drm_format (target_drm_format,
|
||||
ret = cogl_pixel_format_from_drm_format (dumb_fb->drm_format,
|
||||
&cogl_format,
|
||||
NULL);
|
||||
g_assert (ret);
|
||||
|
||||
dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
|
||||
width,
|
||||
height,
|
||||
dumb_fb->width,
|
||||
dumb_fb->height,
|
||||
cogl_format,
|
||||
target_stride_bytes,
|
||||
target_data);
|
||||
dumb_fb->stride_bytes,
|
||||
dumb_fb->map);
|
||||
|
||||
if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||
0 /* x */,
|
||||
@@ -2244,8 +2237,9 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
|
||||
cogl_object_unref (dumb_bitmap);
|
||||
|
||||
g_clear_object (&secondary_gpu_state->gbm.next_fb);
|
||||
buffer_dumb = meta_drm_buffer_dumb_new (target_fb_id);
|
||||
buffer_dumb = meta_drm_buffer_dumb_new (dumb_fb->fb_id);
|
||||
secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_dumb);
|
||||
secondary_gpu_state->cpu.dumb_fb = dumb_fb;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -357,7 +357,6 @@ handle_host_xevent (MetaBackend *backend,
|
||||
{
|
||||
switch (xkb_ev->any.xkb_type)
|
||||
{
|
||||
case XkbNewKeyboardNotify:
|
||||
case XkbMapNotify:
|
||||
keymap_changed (backend);
|
||||
break;
|
||||
|
@@ -203,7 +203,7 @@ meta_renderer_x11_nested_create_view (MetaRenderer *renderer,
|
||||
height = logical_monitor->rect.height;
|
||||
}
|
||||
width = roundf (width * view_scale);
|
||||
height = roundf (width * view_scale);
|
||||
height = roundf (height * view_scale);
|
||||
|
||||
fake_onscreen = create_offscreen (cogl_context, width, height);
|
||||
|
||||
|
@@ -71,4 +71,6 @@ MetaCloseDialog * meta_compositor_create_close_dialog (MetaCompositor *composito
|
||||
MetaInhibitShortcutsDialog * meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_compositor_locate_pointer (MetaCompositor *compositor);
|
||||
|
||||
#endif /* META_COMPOSITOR_PRIVATE_H */
|
||||
|
@@ -431,13 +431,11 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
|
||||
{
|
||||
MetaDisplay *display = compositor->display;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaWindow *grab_window = display->grab_window;
|
||||
MetaGrabOp grab_op = display->grab_op;
|
||||
|
||||
g_return_if_fail (is_modal (display));
|
||||
|
||||
g_signal_emit_by_name (display, "grab-op-end",
|
||||
meta_plugin_get_display (plugin),
|
||||
display->grab_window, display->grab_op);
|
||||
|
||||
display->grab_op = META_GRAB_OP_NONE;
|
||||
display->event_route = META_EVENT_ROUTE_NORMAL;
|
||||
display->grab_window = NULL;
|
||||
@@ -454,6 +452,10 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
|
||||
meta_display_sync_wayland_input_focus (display);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_signal_emit_by_name (display, "grab-op-end",
|
||||
meta_plugin_get_display (plugin),
|
||||
grab_window, grab_op);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -692,11 +694,8 @@ meta_compositor_add_window (MetaCompositor *compositor,
|
||||
{
|
||||
MetaWindowActor *window_actor;
|
||||
ClutterActor *window_group;
|
||||
MetaDisplay *display = compositor->display;
|
||||
GType window_actor_type = G_TYPE_INVALID;
|
||||
|
||||
meta_x11_error_trap_push (display->x11_display);
|
||||
|
||||
switch (window->client_type)
|
||||
{
|
||||
case META_WINDOW_CLIENT_TYPE_X11:
|
||||
@@ -724,8 +723,6 @@ meta_compositor_add_window (MetaCompositor *compositor,
|
||||
*/
|
||||
compositor->windows = g_list_append (compositor->windows, window_actor);
|
||||
sync_actor_stacking (compositor);
|
||||
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1556,3 +1553,9 @@ meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor,
|
||||
return meta_plugin_manager_create_inhibit_shortcuts_dialog (compositor->plugin_mgr,
|
||||
window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_locate_pointer (MetaCompositor *compositor)
|
||||
{
|
||||
meta_plugin_manager_locate_pointer (compositor->plugin_mgr);
|
||||
}
|
||||
|
@@ -405,3 +405,13 @@ meta_plugin_manager_create_inhibit_shortcuts_dialog (MetaPluginManager *plugin_m
|
||||
|
||||
return meta_inhibit_shortcuts_dialog_default_new (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_manager_locate_pointer (MetaPluginManager *plugin_mgr)
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
|
||||
if (klass->locate_pointer)
|
||||
klass->locate_pointer (plugin);
|
||||
}
|
||||
|
@@ -100,4 +100,6 @@ MetaInhibitShortcutsDialog *
|
||||
meta_plugin_manager_create_inhibit_shortcuts_dialog (MetaPluginManager *plugin_mgr,
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_plugin_manager_locate_pointer (MetaPluginManager *mgr);
|
||||
|
||||
#endif
|
||||
|
@@ -55,17 +55,8 @@ meta_rectangle_free (MetaRectangle *rect)
|
||||
g_free (rect);
|
||||
}
|
||||
|
||||
GType
|
||||
meta_rectangle_get_type (void)
|
||||
{
|
||||
static GType type_id = 0;
|
||||
|
||||
if (!type_id)
|
||||
type_id = g_boxed_type_register_static (g_intern_static_string ("MetaRectangle"),
|
||||
(GBoxedCopyFunc) meta_rectangle_copy,
|
||||
(GBoxedFreeFunc) meta_rectangle_free);
|
||||
return type_id;
|
||||
}
|
||||
G_DEFINE_BOXED_TYPE (MetaRectangle, meta_rectangle,
|
||||
meta_rectangle_copy, meta_rectangle_free);
|
||||
|
||||
char*
|
||||
meta_rectangle_to_string (const MetaRectangle *rect,
|
||||
@@ -2141,8 +2132,8 @@ meta_rectangle_from_clutter_rect (ClutterRect *rect,
|
||||
*dest = (MetaRectangle) {
|
||||
.x = ceilf (rect->origin.x),
|
||||
.y = ceilf (rect->origin.y),
|
||||
.width = floorf (rect->origin.x + rect->size.width) - dest->x,
|
||||
.height = floorf (rect->origin.y + rect->size.height) - dest->x,
|
||||
.width = floorf (rect->size.width),
|
||||
.height = floorf (rect->size.height),
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
@@ -140,14 +140,6 @@ struct _MetaDisplay
|
||||
*/
|
||||
guint allow_terminal_deactivation : 1;
|
||||
|
||||
/* If true, server->focus_serial refers to us changing the focus; in
|
||||
* this case, we can ignore focus events that have exactly focus_serial,
|
||||
* since we take care to make another request immediately afterwards.
|
||||
* But if focus is being changed by another client, we have to accept
|
||||
* multiple events with the same serial.
|
||||
*/
|
||||
guint focused_by_us : 1;
|
||||
|
||||
/*< private-ish >*/
|
||||
GHashTable *stamps;
|
||||
GHashTable *wayland_windows;
|
||||
@@ -203,10 +195,6 @@ struct _MetaDisplay
|
||||
MetaEdgeResistanceData *grab_edge_resistance_data;
|
||||
unsigned int grab_last_user_action_was_snap;
|
||||
|
||||
/* we use property updates as sentinels for certain window focus events
|
||||
* to avoid some race conditions on EnterNotify events
|
||||
*/
|
||||
int sentinel_counter;
|
||||
int grab_resize_timeout_id;
|
||||
|
||||
MetaKeyBindingManager key_binding_manager;
|
||||
@@ -363,10 +351,6 @@ gboolean meta_grab_op_is_resizing (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_mouse (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
|
||||
|
||||
void meta_display_increment_focus_sentinel (MetaDisplay *display);
|
||||
void meta_display_decrement_focus_sentinel (MetaDisplay *display);
|
||||
gboolean meta_display_focus_sentinel_clear (MetaDisplay *display);
|
||||
|
||||
void meta_display_queue_autoraise_callback (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
void meta_display_remove_autoraise_callback (MetaDisplay *display);
|
||||
@@ -379,10 +363,7 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
||||
|
||||
void meta_display_sync_wayland_input_focus (MetaDisplay *display);
|
||||
void meta_display_update_focus_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
Window xwindow,
|
||||
gulong serial,
|
||||
gboolean focused_by_us);
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_display_sanity_check_timestamps (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
@@ -446,4 +427,8 @@ MetaWindow *meta_display_get_window_from_id (MetaDisplay *display,
|
||||
uint64_t window_id);
|
||||
uint64_t meta_display_generate_window_id (MetaDisplay *display);
|
||||
|
||||
gboolean meta_display_init_x11 (MetaDisplay *display,
|
||||
GError **error);
|
||||
void meta_display_shutdown_x11 (MetaDisplay *display);
|
||||
|
||||
#endif
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/cm/meta-backend-x11-cm.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "core/bell.h"
|
||||
#include "core/boxes-private.h"
|
||||
@@ -630,6 +631,39 @@ on_ui_scaling_factor_changed (MetaSettings *settings,
|
||||
meta_display_reload_cursor (display);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_display_init_x11 (MetaDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
MetaX11Display *x11_display;
|
||||
|
||||
g_assert (display->x11_display == NULL);
|
||||
|
||||
x11_display = meta_x11_display_new (display, error);
|
||||
if (!x11_display)
|
||||
return FALSE;
|
||||
|
||||
display->x11_display = x11_display;
|
||||
g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
|
||||
meta_x11_display_create_guard_window (x11_display);
|
||||
|
||||
if (!display->display_opening)
|
||||
meta_display_manage_all_windows (display);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_shutdown_x11 (MetaDisplay *display)
|
||||
{
|
||||
if (!display->x11_display)
|
||||
return;
|
||||
|
||||
g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0);
|
||||
g_object_run_dispose (G_OBJECT (display->x11_display));
|
||||
g_clear_object (&display->x11_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_display_open:
|
||||
*
|
||||
@@ -645,7 +679,6 @@ meta_display_open (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MetaDisplay *display;
|
||||
MetaX11Display *x11_display;
|
||||
int i;
|
||||
guint32 timestamp;
|
||||
Window old_active_xwindow = None;
|
||||
@@ -683,7 +716,6 @@ meta_display_open (void)
|
||||
}
|
||||
|
||||
display->current_time = META_CURRENT_TIME;
|
||||
display->sentinel_counter = 0;
|
||||
|
||||
display->grab_resize_timeout_id = 0;
|
||||
display->grab_have_keyboard = FALSE;
|
||||
@@ -693,7 +725,7 @@ meta_display_open (void)
|
||||
display->grab_tile_mode = META_TILE_NONE;
|
||||
display->grab_tile_monitor_number = -1;
|
||||
|
||||
display->grab_edge_resistance_data = NULL;
|
||||
meta_display_cleanup_edges (display);
|
||||
|
||||
meta_display_init_keys (display);
|
||||
|
||||
@@ -730,10 +762,8 @@ meta_display_open (void)
|
||||
|
||||
if (meta_should_autostart_x11_display ())
|
||||
{
|
||||
x11_display = meta_x11_display_new (display, &error);
|
||||
g_assert (x11_display != NULL); /* Required, for now */
|
||||
display->x11_display = x11_display;
|
||||
g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
|
||||
if (!meta_display_init_x11 (display, &error))
|
||||
g_error ("Failed to start Xwayland: %s", error->message);
|
||||
|
||||
timestamp = display->x11_display->timestamp;
|
||||
}
|
||||
@@ -779,10 +809,12 @@ meta_display_open (void)
|
||||
if (old_active_window)
|
||||
meta_window_focus (old_active_window, timestamp);
|
||||
else
|
||||
meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp);
|
||||
meta_display_unset_input_focus (display, timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_display_unset_input_focus (display, timestamp);
|
||||
}
|
||||
else if (display->x11_display)
|
||||
meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp);
|
||||
|
||||
meta_idle_monitor_init_dbus ();
|
||||
|
||||
@@ -924,7 +956,7 @@ meta_display_close (MetaDisplay *display,
|
||||
|
||||
g_clear_object (&display->gesture_tracker);
|
||||
|
||||
g_clear_pointer (&display->stack, meta_stack_free);
|
||||
g_clear_object (&display->stack);
|
||||
g_clear_pointer (&display->stack_tracker,
|
||||
meta_stack_tracker_free);
|
||||
|
||||
@@ -953,12 +985,7 @@ meta_display_close (MetaDisplay *display,
|
||||
if (display->compositor)
|
||||
meta_compositor_destroy (display->compositor);
|
||||
|
||||
if (display->x11_display)
|
||||
{
|
||||
g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0);
|
||||
g_object_run_dispose (G_OBJECT (display->x11_display));
|
||||
g_clear_object (&display->x11_display);
|
||||
}
|
||||
meta_display_shutdown_x11 (display);
|
||||
|
||||
meta_display_shutdown_keys (display);
|
||||
|
||||
@@ -1238,16 +1265,9 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display)
|
||||
|
||||
void
|
||||
meta_display_update_focus_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
Window xwindow,
|
||||
gulong serial,
|
||||
gboolean focused_by_us)
|
||||
MetaWindow *window)
|
||||
{
|
||||
display->x11_display->focus_serial = serial;
|
||||
display->focused_by_us = focused_by_us;
|
||||
|
||||
if (display->x11_display->focus_xwindow == xwindow &&
|
||||
display->focus_window == window)
|
||||
if (display->focus_window == window)
|
||||
return;
|
||||
|
||||
if (display->focus_window)
|
||||
@@ -1264,28 +1284,25 @@ meta_display_update_focus_window (MetaDisplay *display,
|
||||
*/
|
||||
previous = display->focus_window;
|
||||
display->focus_window = NULL;
|
||||
display->x11_display->focus_xwindow = None;
|
||||
|
||||
meta_window_set_focused_internal (previous, FALSE);
|
||||
}
|
||||
|
||||
display->focus_window = window;
|
||||
display->x11_display->focus_xwindow = xwindow;
|
||||
|
||||
if (display->focus_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS, "* Focus --> %s with serial %lu\n",
|
||||
display->focus_window->desc, serial);
|
||||
meta_topic (META_DEBUG_FOCUS, "* Focus --> %s\n",
|
||||
display->focus_window->desc);
|
||||
meta_window_set_focused_internal (display->focus_window, TRUE);
|
||||
}
|
||||
else
|
||||
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
|
||||
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL\n");
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_display_sync_wayland_input_focus (display);
|
||||
|
||||
g_object_notify (G_OBJECT (display), "focus-window");
|
||||
meta_x11_display_update_active_window_hint (display->x11_display);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -1317,6 +1334,51 @@ meta_display_timestamp_too_old (MetaDisplay *display,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_set_input_focus (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
gboolean focus_frame,
|
||||
guint32 timestamp)
|
||||
{
|
||||
if (meta_display_timestamp_too_old (display, ×tamp))
|
||||
return;
|
||||
|
||||
if (display->x11_display)
|
||||
{
|
||||
MetaX11Display *x11_display = display->x11_display;
|
||||
Window xwindow;
|
||||
gulong serial;
|
||||
|
||||
meta_x11_error_trap_push (x11_display);
|
||||
|
||||
if (window)
|
||||
xwindow = focus_frame ? window->frame->xwindow : window->xwindow;
|
||||
else
|
||||
xwindow = x11_display->no_focus_window;
|
||||
|
||||
meta_x11_display_set_input_focus (x11_display, xwindow, timestamp);
|
||||
serial = XNextRequest (x11_display->xdisplay);
|
||||
|
||||
meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE);
|
||||
|
||||
meta_x11_error_trap_pop (display->x11_display);
|
||||
}
|
||||
|
||||
meta_display_update_focus_window (display, window);
|
||||
|
||||
display->last_focus_time = timestamp;
|
||||
|
||||
if (window == NULL || window != display->autoraise_window)
|
||||
meta_display_remove_autoraise_callback (display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_unset_input_focus (MetaDisplay *display,
|
||||
guint32 timestamp)
|
||||
{
|
||||
meta_display_set_input_focus (display, NULL, FALSE, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_register_wayland_window (MetaDisplay *display,
|
||||
MetaWindow *window)
|
||||
@@ -1678,14 +1740,17 @@ meta_display_begin_grab_op (MetaDisplay *display,
|
||||
if (pointer_already_grabbed)
|
||||
display->grab_have_pointer = TRUE;
|
||||
|
||||
/* Since grab operations often happen as a result of implicit
|
||||
* pointer operations on the display X11 connection, we need
|
||||
* to ungrab here to ensure that the backend's X11 can take
|
||||
* the device grab. */
|
||||
XIUngrabDevice (display->x11_display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
timestamp);
|
||||
XSync (display->x11_display->xdisplay, False);
|
||||
if (META_IS_BACKEND_X11 (meta_get_backend ()) && display->x11_display)
|
||||
{
|
||||
/* Since grab operations often happen as a result of implicit
|
||||
* pointer operations on the display X11 connection, we need
|
||||
* to ungrab here to ensure that the backend's X11 can take
|
||||
* the device grab. */
|
||||
XIUngrabDevice (display->x11_display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
timestamp);
|
||||
XSync (display->x11_display->xdisplay, False);
|
||||
}
|
||||
|
||||
if (meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp))
|
||||
display->grab_have_pointer = TRUE;
|
||||
@@ -1772,9 +1837,6 @@ meta_display_end_grab_op (MetaDisplay *display,
|
||||
|
||||
g_assert (grab_window != NULL);
|
||||
|
||||
g_signal_emit (display, display_signals[GRAB_OP_END], 0,
|
||||
display, grab_window, grab_op);
|
||||
|
||||
/* We need to reset this early, since the
|
||||
* meta_window_grab_op_ended callback relies on this being
|
||||
* up to date. */
|
||||
@@ -1826,6 +1888,9 @@ meta_display_end_grab_op (MetaDisplay *display,
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_display_sync_wayland_input_focus (display);
|
||||
|
||||
g_signal_emit (display, display_signals[GRAB_OP_END], 0,
|
||||
display, grab_window, grab_op);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2490,37 +2555,6 @@ prefs_changed_callback (MetaPreference pref,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_increment_focus_sentinel (MetaDisplay *display)
|
||||
{
|
||||
unsigned long data[1];
|
||||
|
||||
data[0] = meta_display_get_current_time (display);
|
||||
|
||||
XChangeProperty (display->x11_display->xdisplay,
|
||||
display->x11_display->xroot,
|
||||
display->x11_display->atom__MUTTER_SENTINEL,
|
||||
XA_CARDINAL,
|
||||
32, PropModeReplace, (guchar*) data, 1);
|
||||
|
||||
display->sentinel_counter += 1;
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_decrement_focus_sentinel (MetaDisplay *display)
|
||||
{
|
||||
display->sentinel_counter -= 1;
|
||||
|
||||
if (display->sentinel_counter < 0)
|
||||
display->sentinel_counter = 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_display_focus_sentinel_clear (MetaDisplay *display)
|
||||
{
|
||||
return (display->sentinel_counter == 0);
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_sanity_check_timestamps (MetaDisplay *display,
|
||||
guint32 timestamp)
|
||||
@@ -2626,13 +2660,14 @@ meta_display_supports_extended_barriers (MetaDisplay *display)
|
||||
return TRUE;
|
||||
#endif
|
||||
|
||||
if (META_IS_BACKEND_X11 (meta_get_backend ()))
|
||||
if (META_IS_BACKEND_X11_CM (meta_get_backend ()))
|
||||
{
|
||||
return (META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display) &&
|
||||
!meta_is_wayland_compositor());
|
||||
if (meta_is_wayland_compositor())
|
||||
return FALSE;
|
||||
|
||||
return META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display);
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@@ -113,6 +113,9 @@ typedef struct
|
||||
MetaKeyCombo overlay_key_combo;
|
||||
MetaResolvedKeyCombo overlay_resolved_key_combo;
|
||||
gboolean overlay_key_only_pressed;
|
||||
MetaKeyCombo locate_pointer_key_combo;
|
||||
MetaResolvedKeyCombo locate_pointer_resolved_key_combo;
|
||||
gboolean locate_pointer_key_only_pressed;
|
||||
MetaResolvedKeyCombo iso_next_group_combo[2];
|
||||
int n_iso_next_group_combos;
|
||||
|
||||
@@ -149,6 +152,7 @@ gboolean meta_prefs_remove_keybinding (const char *name);
|
||||
|
||||
GList *meta_prefs_get_keybindings (void);
|
||||
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
|
||||
void meta_prefs_get_locate_pointer_binding (MetaKeyCombo *combo);
|
||||
const char *meta_prefs_get_iso_next_group_option (void);
|
||||
|
||||
void meta_x11_display_grab_keys (MetaX11Display *x11_display);
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "compositor/compositor-private.h"
|
||||
#include "core/edge-resistance.h"
|
||||
#include "core/frame.h"
|
||||
#include "core/keybindings-private.h"
|
||||
@@ -780,6 +781,10 @@ reload_combos (MetaKeyBindingManager *keys)
|
||||
&keys->overlay_key_combo,
|
||||
&keys->overlay_resolved_key_combo);
|
||||
|
||||
resolve_key_combo (keys,
|
||||
&keys->locate_pointer_key_combo,
|
||||
&keys->locate_pointer_resolved_key_combo);
|
||||
|
||||
reload_iso_next_group_combos (keys);
|
||||
|
||||
g_hash_table_foreach (keys->key_bindings, binding_reload_combos_foreach, keys);
|
||||
@@ -871,6 +876,9 @@ rebuild_special_bindings (MetaKeyBindingManager *keys)
|
||||
|
||||
meta_prefs_get_overlay_binding (&combo);
|
||||
keys->overlay_key_combo = combo;
|
||||
|
||||
meta_prefs_get_locate_pointer_binding (&combo);
|
||||
keys->locate_pointer_key_combo = combo;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1062,6 +1070,10 @@ get_keybinding_action (MetaKeyBindingManager *keys,
|
||||
&keys->overlay_resolved_key_combo))
|
||||
return META_KEYBINDING_ACTION_OVERLAY_KEY;
|
||||
|
||||
if (resolved_key_combo_intersect (resolved_combo,
|
||||
&keys->locate_pointer_resolved_key_combo))
|
||||
return META_KEYBINDING_ACTION_LOCATE_POINTER_KEY;
|
||||
|
||||
binding = get_keybinding (keys, resolved_combo);
|
||||
if (binding)
|
||||
{
|
||||
@@ -1487,6 +1499,10 @@ meta_x11_display_change_keygrabs (MetaX11Display *x11_display,
|
||||
meta_change_keygrab (keys, x11_display->xroot,
|
||||
grab, &keys->overlay_resolved_key_combo);
|
||||
|
||||
if (keys->locate_pointer_resolved_key_combo.len != 0)
|
||||
meta_change_keygrab (keys, x11_display->xroot,
|
||||
grab, &keys->locate_pointer_resolved_key_combo);
|
||||
|
||||
for (i = 0; i < keys->n_iso_next_group_combos; i++)
|
||||
meta_change_keygrab (keys, x11_display->xroot,
|
||||
grab, &keys->iso_next_group_combo[i]);
|
||||
@@ -1952,37 +1968,31 @@ process_event (MetaDisplay *display,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_overlay_key (MetaDisplay *display,
|
||||
ClutterKeyEvent *event,
|
||||
MetaWindow *window)
|
||||
process_special_modifier_key (MetaDisplay *display,
|
||||
ClutterKeyEvent *event,
|
||||
MetaWindow *window,
|
||||
gboolean *modifier_press_only,
|
||||
MetaResolvedKeyCombo *resolved_key_combo,
|
||||
GFunc trigger_callback)
|
||||
{
|
||||
MetaKeyBindingManager *keys = &display->key_binding_manager;
|
||||
MetaBackend *backend = keys->backend;
|
||||
Display *xdisplay;
|
||||
|
||||
if (display->focus_window && !keys->overlay_key_only_pressed)
|
||||
{
|
||||
ClutterInputDevice *source;
|
||||
|
||||
source = clutter_event_get_source_device ((ClutterEvent *) event);
|
||||
if (meta_window_shortcuts_inhibited (display->focus_window, source))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (META_IS_BACKEND_X11 (backend))
|
||||
xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
else
|
||||
xdisplay = NULL;
|
||||
|
||||
if (keys->overlay_key_only_pressed)
|
||||
if (*modifier_press_only)
|
||||
{
|
||||
if (! resolved_key_combo_has_keycode (&keys->overlay_resolved_key_combo,
|
||||
if (! resolved_key_combo_has_keycode (resolved_key_combo,
|
||||
event->hardware_keycode))
|
||||
{
|
||||
keys->overlay_key_only_pressed = FALSE;
|
||||
*modifier_press_only = FALSE;
|
||||
|
||||
/* OK, the user hit modifier+key rather than pressing and
|
||||
* releasing the ovelay key. We want to handle the key
|
||||
* releasing the modifier key alone. We want to handle the key
|
||||
* sequence "normally". Unfortunately, using
|
||||
* XAllowEvents(..., ReplayKeyboard, ...) doesn't quite
|
||||
* work, since global keybindings won't be activated ("this
|
||||
@@ -2021,7 +2031,7 @@ process_overlay_key (MetaDisplay *display,
|
||||
{
|
||||
MetaKeyBinding *binding;
|
||||
|
||||
keys->overlay_key_only_pressed = FALSE;
|
||||
*modifier_press_only = FALSE;
|
||||
|
||||
/* We want to unfreeze events, but keep the grab so that if the user
|
||||
* starts typing into the overlay we get all the keys */
|
||||
@@ -2030,11 +2040,11 @@ process_overlay_key (MetaDisplay *display,
|
||||
clutter_input_device_get_device_id (event->device),
|
||||
XIAsyncDevice, event->time);
|
||||
|
||||
binding = get_keybinding (keys, &keys->overlay_resolved_key_combo);
|
||||
binding = get_keybinding (keys, resolved_key_combo);
|
||||
if (binding &&
|
||||
meta_compositor_filter_keybinding (display->compositor, binding))
|
||||
return TRUE;
|
||||
meta_display_overlay_key_activate (display);
|
||||
trigger_callback (display, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2044,7 +2054,7 @@ process_overlay_key (MetaDisplay *display,
|
||||
* while the key is still down
|
||||
* - passive grabs are only activated on KeyPress and not KeyRelease.
|
||||
*
|
||||
* In this case, keys->overlay_key_only_pressed might be wrong.
|
||||
* In this case, modifier_press_only might be wrong.
|
||||
* Mutter still ought to acknowledge events, otherwise the X server
|
||||
* will not send the next events.
|
||||
*
|
||||
@@ -2059,12 +2069,12 @@ process_overlay_key (MetaDisplay *display,
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == CLUTTER_KEY_PRESS &&
|
||||
resolved_key_combo_has_keycode (&keys->overlay_resolved_key_combo,
|
||||
resolved_key_combo_has_keycode (resolved_key_combo,
|
||||
event->hardware_keycode))
|
||||
{
|
||||
keys->overlay_key_only_pressed = TRUE;
|
||||
*modifier_press_only = TRUE;
|
||||
/* We keep the keyboard frozen - this allows us to use ReplayKeyboard
|
||||
* on the next event if it's not the release of the overlay key */
|
||||
* on the next event if it's not the release of the modifier key */
|
||||
if (xdisplay)
|
||||
XIAllowEvents (xdisplay,
|
||||
clutter_input_device_get_device_id (event->device),
|
||||
@@ -2076,6 +2086,43 @@ process_overlay_key (MetaDisplay *display,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
process_overlay_key (MetaDisplay *display,
|
||||
ClutterKeyEvent *event,
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaKeyBindingManager *keys = &display->key_binding_manager;
|
||||
|
||||
return process_special_modifier_key (display,
|
||||
event,
|
||||
window,
|
||||
&keys->overlay_key_only_pressed,
|
||||
&keys->overlay_resolved_key_combo,
|
||||
(GFunc) meta_display_overlay_key_activate);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_locate_pointer (MetaDisplay *display)
|
||||
{
|
||||
meta_compositor_locate_pointer (display->compositor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_locate_pointer_key (MetaDisplay *display,
|
||||
ClutterKeyEvent *event,
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaKeyBindingManager *keys = &display->key_binding_manager;
|
||||
|
||||
return process_special_modifier_key (display,
|
||||
event,
|
||||
window,
|
||||
&keys->locate_pointer_key_only_pressed,
|
||||
&keys->locate_pointer_resolved_key_combo,
|
||||
(GFunc) handle_locate_pointer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_iso_next_group (MetaDisplay *display,
|
||||
ClutterKeyEvent *event)
|
||||
@@ -2129,6 +2176,10 @@ process_key_event (MetaDisplay *display,
|
||||
if (handled)
|
||||
return TRUE;
|
||||
|
||||
handled = process_locate_pointer_key (display, event, window);
|
||||
if (handled) /* Continue with the event even if handled */
|
||||
return FALSE;
|
||||
|
||||
handled = process_iso_next_group (display, event);
|
||||
if (handled)
|
||||
return TRUE;
|
||||
@@ -2217,6 +2268,7 @@ meta_keybindings_process_event (MetaDisplay *display,
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
case CLUTTER_TOUCH_END:
|
||||
keys->overlay_key_only_pressed = FALSE;
|
||||
keys->locate_pointer_key_only_pressed = FALSE;
|
||||
return FALSE;
|
||||
|
||||
case CLUTTER_KEY_PRESS:
|
||||
@@ -4403,20 +4455,26 @@ meta_display_init_keys (MetaDisplay *display)
|
||||
handler->name = g_strdup ("overlay-key");
|
||||
handler->flags = META_KEY_BINDING_BUILTIN;
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
|
||||
g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
|
||||
|
||||
handler = g_new0 (MetaKeyHandler, 1);
|
||||
handler->name = g_strdup ("locate-pointer-key");
|
||||
handler->flags = META_KEY_BINDING_BUILTIN;
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
|
||||
|
||||
handler = g_new0 (MetaKeyHandler, 1);
|
||||
handler->name = g_strdup ("iso-next-group");
|
||||
handler->flags = META_KEY_BINDING_BUILTIN;
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup ("iso-next-group"), handler);
|
||||
g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
|
||||
|
||||
handler = g_new0 (MetaKeyHandler, 1);
|
||||
handler->name = g_strdup ("external-grab");
|
||||
handler->func = handle_external_grab;
|
||||
handler->default_func = handle_external_grab;
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup ("external-grab"), handler);
|
||||
g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
|
||||
|
||||
external_grabs = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL,
|
||||
|
@@ -606,22 +606,6 @@ meta_init (void)
|
||||
meta_fatal ("Can't specify both SM save file and SM client id\n");
|
||||
|
||||
meta_main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/*
|
||||
* We need to make sure the first client connecting to the X server
|
||||
* (e.g. Xwayland started from meta_wayland_init() above) is a permanent one,
|
||||
* so prepare the GDK X11 connection now already. Without doing this, if
|
||||
* there are any functionality that relies on X11 after here before
|
||||
* meta_display_open(), the X server will terminate itself when such a client
|
||||
* disconnects before the permanent GDK client connects.
|
||||
*/
|
||||
if (meta_should_autostart_x11_display ())
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!meta_x11_init_gdk_display (&error))
|
||||
g_error ("Failed to open X11 display: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -600,8 +600,6 @@ meta_workspace_manager_calc_workspace_layout (MetaWorkspaceManager *workspace_ma
|
||||
|
||||
grid = g_new (int, grid_area);
|
||||
|
||||
current_row = -1;
|
||||
current_col = -1;
|
||||
i = 0;
|
||||
|
||||
switch (workspace_manager->starting_corner)
|
||||
|
@@ -81,6 +81,7 @@ static gboolean use_system_font = FALSE;
|
||||
static PangoFontDescription *titlebar_font = NULL;
|
||||
static MetaVirtualModifier mouse_button_mods = Mod1Mask;
|
||||
static MetaKeyCombo overlay_key_combo = { 0, 0, 0 };
|
||||
static MetaKeyCombo locate_pointer_key_combo = { 0, 0, 0 };
|
||||
static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
|
||||
static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
|
||||
static gboolean raise_on_click = TRUE;
|
||||
@@ -145,6 +146,7 @@ static gboolean titlebar_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean locate_pointer_key_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean iso_next_group_handler (GVariant*, gpointer*, gpointer);
|
||||
|
||||
static void init_bindings (void);
|
||||
@@ -427,6 +429,14 @@ static MetaStringPreference preferences_string[] =
|
||||
overlay_key_handler,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
{ "locate-pointer-key",
|
||||
SCHEMA_MUTTER,
|
||||
META_PREF_KEYBINDINGS,
|
||||
},
|
||||
locate_pointer_key_handler,
|
||||
NULL,
|
||||
},
|
||||
{ { NULL, 0, 0 }, NULL },
|
||||
};
|
||||
|
||||
@@ -1475,6 +1485,36 @@ overlay_key_handler (GVariant *value,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
locate_pointer_key_handler (GVariant *value,
|
||||
gpointer *result,
|
||||
gpointer data)
|
||||
{
|
||||
MetaKeyCombo combo;
|
||||
const gchar *string_value;
|
||||
|
||||
*result = NULL; /* ignored */
|
||||
string_value = g_variant_get_string (value, NULL);
|
||||
|
||||
if (!string_value || !meta_parse_accelerator (string_value, &combo))
|
||||
{
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Failed to parse value for locate-pointer-key\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
combo.modifiers = 0;
|
||||
|
||||
if (locate_pointer_key_combo.keysym != combo.keysym ||
|
||||
locate_pointer_key_combo.keycode != combo.keycode)
|
||||
{
|
||||
locate_pointer_key_combo = combo;
|
||||
queue_changed (META_PREF_KEYBINDINGS);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iso_next_group_handler (GVariant *value,
|
||||
gpointer *result,
|
||||
@@ -1688,7 +1728,15 @@ init_bindings (void)
|
||||
pref->combos = g_slist_prepend (pref->combos, &overlay_key_combo);
|
||||
pref->builtin = 1;
|
||||
|
||||
g_hash_table_insert (key_bindings, g_strdup ("overlay-key"), pref);
|
||||
g_hash_table_insert (key_bindings, g_strdup (pref->name), pref);
|
||||
|
||||
pref = g_new0 (MetaKeyPref, 1);
|
||||
pref->name = g_strdup ("locate-pointer-key");
|
||||
pref->action = META_KEYBINDING_ACTION_LOCATE_POINTER_KEY;
|
||||
pref->combos = g_slist_prepend (pref->combos, &locate_pointer_key_combo);
|
||||
pref->builtin = 1;
|
||||
|
||||
g_hash_table_insert (key_bindings, g_strdup (pref->name), pref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1966,6 +2014,12 @@ meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
|
||||
*combo = overlay_key_combo;
|
||||
}
|
||||
|
||||
void
|
||||
meta_prefs_get_locate_pointer_binding (MetaKeyCombo *combo)
|
||||
{
|
||||
*combo = locate_pointer_key_combo;
|
||||
}
|
||||
|
||||
const char *
|
||||
meta_prefs_get_iso_next_group_option (void)
|
||||
{
|
||||
|
409
src/core/stack.c
409
src/core/stack.c
@@ -29,18 +29,13 @@
|
||||
|
||||
#include "core/stack.h"
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "core/frame.h"
|
||||
#include "core/meta-workspace-manager-private.h"
|
||||
#include "core/window-private.h"
|
||||
#include "meta/group.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "meta/prefs.h"
|
||||
#include "meta/workspace.h"
|
||||
#include "x11/group-private.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
|
||||
(w->type == META_WINDOW_DIALOG || \
|
||||
@@ -52,51 +47,141 @@
|
||||
#define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \
|
||||
(WINDOW_HAS_TRANSIENT_TYPE (w) && w->transient_for == NULL)
|
||||
|
||||
static void stack_sync_to_xserver (MetaStack *stack);
|
||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
||||
int position);
|
||||
static void stack_do_window_deletions (MetaStack *stack);
|
||||
static void stack_do_window_additions (MetaStack *stack);
|
||||
static void stack_do_relayer (MetaStack *stack);
|
||||
static void stack_do_constrain (MetaStack *stack);
|
||||
static void stack_do_resort (MetaStack *stack);
|
||||
|
||||
static void stack_ensure_sorted (MetaStack *stack);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_DISPLAY = 1,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGED,
|
||||
WINDOW_ADDED,
|
||||
WINDOW_REMOVED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static GParamSpec *pspecs[N_PROPS] = { 0 };
|
||||
static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_stack_init (MetaStack *stack)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stack_finalize (GObject *object)
|
||||
{
|
||||
MetaStack *stack = META_STACK (object);
|
||||
|
||||
g_list_free (stack->sorted);
|
||||
|
||||
G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stack_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStack *stack = META_STACK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
stack->display = g_value_get_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stack_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStack *stack = META_STACK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
g_value_set_object (value, stack->display);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stack_class_init (MetaStackClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = meta_stack_set_property;
|
||||
object_class->get_property = meta_stack_get_property;
|
||||
object_class->finalize = meta_stack_finalize;
|
||||
|
||||
signals[CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
signals[WINDOW_ADDED] =
|
||||
g_signal_new ("window-added",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, META_TYPE_WINDOW);
|
||||
signals[WINDOW_REMOVED] =
|
||||
g_signal_new ("window-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, META_TYPE_WINDOW);
|
||||
|
||||
pspecs[PROP_DISPLAY] =
|
||||
g_param_spec_object ("display",
|
||||
"Display",
|
||||
"Display",
|
||||
META_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, pspecs);
|
||||
}
|
||||
|
||||
MetaStack *
|
||||
meta_stack_new (MetaDisplay *display)
|
||||
{
|
||||
MetaStack *stack;
|
||||
|
||||
stack = g_new (MetaStack, 1);
|
||||
|
||||
stack->display = display;
|
||||
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
stack->sorted = NULL;
|
||||
stack->added = NULL;
|
||||
stack->removed = NULL;
|
||||
|
||||
stack->freeze_count = 0;
|
||||
stack->n_positions = 0;
|
||||
|
||||
stack->need_resort = FALSE;
|
||||
stack->need_relayer = FALSE;
|
||||
stack->need_constrain = FALSE;
|
||||
|
||||
return stack;
|
||||
return g_object_new (META_TYPE_STACK,
|
||||
"display", display,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_stack_free (MetaStack *stack)
|
||||
static void
|
||||
meta_stack_changed (MetaStack *stack)
|
||||
{
|
||||
g_array_free (stack->xwindows, TRUE);
|
||||
/* Bail out if frozen */
|
||||
if (stack->freeze_count > 0)
|
||||
return;
|
||||
|
||||
g_list_free (stack->sorted);
|
||||
g_list_free (stack->added);
|
||||
g_list_free (stack->removed);
|
||||
|
||||
g_free (stack);
|
||||
stack_ensure_sorted (stack);
|
||||
g_signal_emit (stack, signals[CHANGED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -112,7 +197,12 @@ meta_stack_add (MetaStack *stack,
|
||||
if (meta_window_is_in_stack (window))
|
||||
meta_bug ("Window %s had stack position already\n", window->desc);
|
||||
|
||||
stack->added = g_list_prepend (stack->added, window);
|
||||
stack->sorted = g_list_prepend (stack->sorted, window);
|
||||
stack->need_resort = TRUE; /* may not be needed as we add to top */
|
||||
stack->need_constrain = TRUE;
|
||||
stack->need_relayer = TRUE;
|
||||
|
||||
g_signal_emit (stack, signals[WINDOW_ADDED], 0, window);
|
||||
|
||||
window->stack_position = stack->n_positions;
|
||||
stack->n_positions += 1;
|
||||
@@ -120,7 +210,7 @@ meta_stack_add (MetaStack *stack,
|
||||
"Window %s has stack_position initialized to %d\n",
|
||||
window->desc, window->stack_position);
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -140,25 +230,11 @@ meta_stack_remove (MetaStack *stack,
|
||||
window->stack_position = -1;
|
||||
stack->n_positions -= 1;
|
||||
|
||||
/* We don't know if it's been moved from "added" to "stack" yet */
|
||||
stack->added = g_list_remove (stack->added, window);
|
||||
stack->sorted = g_list_remove (stack->sorted, window);
|
||||
|
||||
/* stack->removed is only used to update stack->xwindows */
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
/* Remember the window ID to remove it from the stack array.
|
||||
* The macro is safe to use: Window is guaranteed to be 32 bits, and
|
||||
* GUINT_TO_POINTER says it only works on 32 bits.
|
||||
*/
|
||||
stack->removed = g_list_prepend (stack->removed,
|
||||
GUINT_TO_POINTER (window->xwindow));
|
||||
if (window->frame)
|
||||
stack->removed = g_list_prepend (stack->removed,
|
||||
GUINT_TO_POINTER (window->frame->xwindow));
|
||||
}
|
||||
g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window);
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -169,7 +245,7 @@ meta_stack_update_layer (MetaStack *stack,
|
||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||
stack->need_relayer = TRUE;
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -180,7 +256,7 @@ meta_stack_update_transient (MetaStack *stack,
|
||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||
stack->need_constrain = TRUE;
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -210,7 +286,7 @@ meta_stack_raise (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -239,7 +315,7 @@ meta_stack_lower (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||
}
|
||||
|
||||
@@ -255,7 +331,7 @@ meta_stack_thaw (MetaStack *stack)
|
||||
g_return_if_fail (stack->freeze_count > 0);
|
||||
|
||||
stack->freeze_count -= 1;
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@@ -771,99 +847,6 @@ apply_constraints (Constraint **constraints,
|
||||
g_slist_free (heads);
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_do_window_deletions:
|
||||
*
|
||||
* Go through "deleted" and take the matching windows
|
||||
* out of "windows".
|
||||
*/
|
||||
static void
|
||||
stack_do_window_deletions (MetaStack *stack)
|
||||
{
|
||||
/* Do removals before adds, with paranoid idea that we might re-add
|
||||
* the same window IDs.
|
||||
*/
|
||||
GList *tmp;
|
||||
int i;
|
||||
|
||||
tmp = stack->removed;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
Window xwindow;
|
||||
xwindow = GPOINTER_TO_UINT (tmp->data);
|
||||
|
||||
/* We go from the end figuring removals are more
|
||||
* likely to be recent.
|
||||
*/
|
||||
i = stack->xwindows->len;
|
||||
while (i > 0)
|
||||
{
|
||||
--i;
|
||||
|
||||
/* there's no guarantee we'll actually find windows to
|
||||
* remove, e.g. the same xwindow could have been
|
||||
* added/removed before we ever synced, and we put
|
||||
* both the window->xwindow and window->frame->xwindow
|
||||
* in the removal list.
|
||||
*/
|
||||
if (xwindow == g_array_index (stack->xwindows, Window, i))
|
||||
{
|
||||
g_array_remove_index (stack->xwindows, i);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_list_free (stack->removed);
|
||||
stack->removed = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
stack_do_window_additions (MetaStack *stack)
|
||||
{
|
||||
GList *tmp;
|
||||
gint n_added;
|
||||
|
||||
n_added = g_list_length (stack->added);
|
||||
if (n_added > 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Adding %d windows to sorted list\n",
|
||||
n_added);
|
||||
|
||||
/* stack->added has the most recent additions at the
|
||||
* front of the list, so we need to reverse it
|
||||
*/
|
||||
stack->added = g_list_reverse (stack->added);
|
||||
|
||||
tmp = stack->added;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w;
|
||||
|
||||
w = tmp->data;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (stack->xwindows, w->xwindow);
|
||||
|
||||
/* add to the main list */
|
||||
stack->sorted = g_list_prepend (stack->sorted, w);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
stack->need_resort = TRUE; /* may not be needed as we add to top */
|
||||
stack->need_constrain = TRUE;
|
||||
stack->need_relayer = TRUE;
|
||||
}
|
||||
|
||||
g_list_free (stack->added);
|
||||
stack->added = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_do_relayer:
|
||||
*
|
||||
@@ -981,131 +964,11 @@ stack_do_resort (MetaStack *stack)
|
||||
static void
|
||||
stack_ensure_sorted (MetaStack *stack)
|
||||
{
|
||||
stack_do_window_deletions (stack);
|
||||
stack_do_window_additions (stack);
|
||||
stack_do_relayer (stack);
|
||||
stack_do_constrain (stack);
|
||||
stack_do_resort (stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_sync_to_server:
|
||||
*
|
||||
* Order the windows on the X server to be the same as in our structure.
|
||||
* We do this using XRestackWindows if we don't know the previous order,
|
||||
* or XConfigureWindow on a few particular windows if we do and can figure
|
||||
* out the minimum set of changes. After that, we set __NET_CLIENT_LIST
|
||||
* and __NET_CLIENT_LIST_STACKING.
|
||||
*
|
||||
* FIXME: Now that we have a good view of the stacking order on the server
|
||||
* with MetaStackTracker it should be possible to do a simpler and better
|
||||
* job of computing the minimal set of stacking requests needed.
|
||||
*/
|
||||
static void
|
||||
stack_sync_to_xserver (MetaStack *stack)
|
||||
{
|
||||
GArray *x11_stacked;
|
||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||
GList *tmp;
|
||||
GArray *hidden_stack_ids;
|
||||
|
||||
/* Bail out if frozen */
|
||||
if (stack->freeze_count > 0)
|
||||
return;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
||||
|
||||
stack_ensure_sorted (stack);
|
||||
|
||||
/* Create stacked xwindow arrays, in bottom-to-top order
|
||||
*/
|
||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||
hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Bottom to top: ");
|
||||
meta_push_no_msg_prefix ();
|
||||
|
||||
for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
guint64 top_level_window;
|
||||
guint64 stack_id;
|
||||
|
||||
if (w->unmanaging)
|
||||
continue;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||
w->layer, w->stack_position, w->desc);
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (x11_stacked, w->xwindow);
|
||||
|
||||
if (w->frame)
|
||||
top_level_window = w->frame->xwindow;
|
||||
else
|
||||
top_level_window = w->xwindow;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
stack_id = top_level_window;
|
||||
else
|
||||
stack_id = w->stamp;
|
||||
|
||||
/* We don't restack hidden windows along with the rest, though they are
|
||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||
* the screens fullscreen guard_window. */
|
||||
if (w->hidden)
|
||||
{
|
||||
g_array_append_val (hidden_stack_ids, stack_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_array_append_val (all_root_children_stacked, stack_id);
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "\n");
|
||||
meta_pop_no_msg_prefix ();
|
||||
|
||||
/* The screen guard window sits above all hidden windows and acts as
|
||||
* a barrier to input reaching these windows. */
|
||||
guint64 guard_window_id = stack->display->x11_display->guard_window;
|
||||
g_array_append_val (hidden_stack_ids, guard_window_id);
|
||||
|
||||
/* Sync to server */
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||
all_root_children_stacked->len);
|
||||
|
||||
meta_stack_tracker_restack_managed (stack->display->stack_tracker,
|
||||
(guint64 *)all_root_children_stacked->data,
|
||||
all_root_children_stacked->len);
|
||||
meta_stack_tracker_restack_at_bottom (stack->display->stack_tracker,
|
||||
(guint64 *)hidden_stack_ids->data,
|
||||
hidden_stack_ids->len);
|
||||
|
||||
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
|
||||
|
||||
XChangeProperty (stack->display->x11_display->xdisplay,
|
||||
stack->display->x11_display->xroot,
|
||||
stack->display->x11_display->atom__NET_CLIENT_LIST,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stack->xwindows->data,
|
||||
stack->xwindows->len);
|
||||
XChangeProperty (stack->display->x11_display->xdisplay,
|
||||
stack->display->x11_display->xroot,
|
||||
stack->display->x11_display->atom__NET_CLIENT_LIST_STACKING,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)x11_stacked->data,
|
||||
x11_stacked->len);
|
||||
|
||||
g_array_free (x11_stacked, TRUE);
|
||||
g_array_free (hidden_stack_ids, TRUE);
|
||||
g_array_free (all_root_children_stacked, TRUE);
|
||||
}
|
||||
|
||||
MetaWindow*
|
||||
meta_stack_get_top (MetaStack *stack)
|
||||
{
|
||||
@@ -1415,7 +1278,7 @@ meta_stack_set_positions (MetaStack *stack,
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Reset the stack positions of (nearly) all windows\n");
|
||||
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_changed (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@@ -1480,7 +1343,7 @@ meta_window_set_stack_position (MetaWindow *window,
|
||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, position);
|
||||
stack_sync_to_xserver (window->display->stack);
|
||||
meta_stack_changed (window->display->stack);
|
||||
meta_stack_update_window_tile_matches (window->display->stack,
|
||||
workspace_manager->active_workspace);
|
||||
}
|
||||
|
@@ -51,38 +51,14 @@
|
||||
*/
|
||||
struct _MetaStack
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
/** The MetaDisplay containing this stack. */
|
||||
MetaDisplay *display;
|
||||
|
||||
/**
|
||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||
*/
|
||||
GArray *xwindows;
|
||||
|
||||
/** The MetaWindows of the windows we manage, sorted in order. */
|
||||
GList *sorted;
|
||||
|
||||
/**
|
||||
* MetaWindows waiting to be added to the "sorted" and "windows" list, after
|
||||
* being added by meta_stack_add() and before being assimilated by
|
||||
* stack_ensure_sorted().
|
||||
*
|
||||
* The order of the elements in this list is not important; what is important
|
||||
* is the stack_position element of each window.
|
||||
*/
|
||||
GList *added;
|
||||
|
||||
/**
|
||||
* Windows (X handles, not MetaWindows) waiting to be removed from the
|
||||
* "windows" list, after being removed by meta_stack_remove() and before
|
||||
* being assimilated by stack_ensure_sorted(). (We already removed them
|
||||
* from the "sorted" list.)
|
||||
*
|
||||
* The order of the elements in this list is not important.
|
||||
*/
|
||||
GList *removed;
|
||||
|
||||
/**
|
||||
* If this is zero, the local stack oughtn't to be brought up to date with
|
||||
* the X server's stack, because it is in the middle of being updated.
|
||||
@@ -121,6 +97,9 @@ struct _MetaStack
|
||||
unsigned int need_constrain : 1;
|
||||
};
|
||||
|
||||
#define META_TYPE_STACK (meta_stack_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaStack, meta_stack, META, STACK, GObject)
|
||||
|
||||
/**
|
||||
* meta_stack_new:
|
||||
* @display: The MetaDisplay which will be the parent of this stack.
|
||||
@@ -131,14 +110,6 @@ struct _MetaStack
|
||||
*/
|
||||
MetaStack *meta_stack_new (MetaDisplay *display);
|
||||
|
||||
/**
|
||||
* meta_stack_free:
|
||||
* @stack: The stack to destroy.
|
||||
*
|
||||
* Destroys and frees a MetaStack.
|
||||
*/
|
||||
void meta_stack_free (MetaStack *stack);
|
||||
|
||||
/**
|
||||
* meta_stack_add:
|
||||
* @stack: The stack to add it to
|
||||
|
@@ -581,6 +581,9 @@ struct _MetaWindowClass
|
||||
gboolean (*is_stackable) (MetaWindow *window);
|
||||
gboolean (*can_ping) (MetaWindow *window);
|
||||
gboolean (*are_updates_frozen) (MetaWindow *window);
|
||||
|
||||
void (* map) (MetaWindow *window);
|
||||
void (* unmap) (MetaWindow *window);
|
||||
};
|
||||
|
||||
/* These differ from window->has_foo_func in that they consider
|
||||
|
@@ -809,17 +809,10 @@ sync_client_window_mapped (MetaWindow *window)
|
||||
|
||||
window->mapped = should_be_mapped;
|
||||
|
||||
meta_x11_error_trap_push (window->display->x11_display);
|
||||
if (should_be_mapped)
|
||||
{
|
||||
XMapWindow (window->display->x11_display->xdisplay, window->xwindow);
|
||||
}
|
||||
if (window->mapped)
|
||||
META_WINDOW_GET_CLASS (window)->map (window);
|
||||
else
|
||||
{
|
||||
XUnmapWindow (window->display->x11_display->xdisplay, window->xwindow);
|
||||
window->unmaps_pending ++;
|
||||
}
|
||||
meta_x11_error_trap_pop (window->display->x11_display);
|
||||
META_WINDOW_GET_CLASS (window)->unmap (window);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1939,9 +1932,10 @@ idle_calc_showing (gpointer data)
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *window = tmp->data;
|
||||
MetaDisplay *display = window->display;
|
||||
|
||||
if (!window->display->mouse_mode)
|
||||
meta_display_increment_focus_sentinel (window->display);
|
||||
if (display->x11_display && !display->mouse_mode)
|
||||
meta_x11_display_increment_focus_sentinel (display->x11_display);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
@@ -2411,6 +2405,7 @@ meta_window_show (MetaWindow *window)
|
||||
gboolean needs_stacking_adjustment;
|
||||
MetaWindow *focus_window;
|
||||
gboolean notify_demands_attention = FALSE;
|
||||
MetaDisplay *display = window->display;
|
||||
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"Showing window %s, shaded: %d iconic: %d placed: %d\n",
|
||||
@@ -2577,7 +2572,7 @@ meta_window_show (MetaWindow *window)
|
||||
|
||||
meta_window_focus (window, timestamp);
|
||||
}
|
||||
else
|
||||
else if (display->x11_display)
|
||||
{
|
||||
/* Prevent EnterNotify events in sloppy/mouse focus from
|
||||
* erroneously focusing the window that had been denied
|
||||
@@ -2585,7 +2580,7 @@ meta_window_show (MetaWindow *window)
|
||||
* ideas for a better way to accomplish the same thing, but
|
||||
* they're more involved so do it this way for now.
|
||||
*/
|
||||
meta_display_increment_focus_sentinel (window->display);
|
||||
meta_x11_display_increment_focus_sentinel (display->x11_display);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3684,6 +3679,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",
|
||||
@@ -3812,13 +3814,13 @@ maybe_move_attached_window (MetaWindow *window,
|
||||
void *data)
|
||||
{
|
||||
if (window->hidden)
|
||||
return FALSE;
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
if (meta_window_is_attached_dialog (window) ||
|
||||
meta_window_get_placement_rule (window))
|
||||
meta_window_reposition (window);
|
||||
|
||||
return FALSE;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5378,50 +5380,6 @@ redraw_icon (MetaWindow *window)
|
||||
meta_frame_queue_draw (window->frame);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
load_default_window_icon (int size)
|
||||
{
|
||||
GtkIconTheme *theme = gtk_icon_theme_get_default ();
|
||||
g_autoptr (GdkPixbuf) pixbuf = NULL;
|
||||
const char *icon_name;
|
||||
|
||||
if (gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME))
|
||||
icon_name = META_DEFAULT_ICON_NAME;
|
||||
else
|
||||
icon_name = "image-missing";
|
||||
|
||||
pixbuf = gtk_icon_theme_load_icon (theme, icon_name, size, 0, NULL);
|
||||
return gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
get_default_window_icon (void)
|
||||
{
|
||||
static cairo_surface_t *default_icon = NULL;
|
||||
|
||||
if (default_icon == NULL)
|
||||
{
|
||||
default_icon = load_default_window_icon (META_ICON_WIDTH);
|
||||
g_assert (default_icon);
|
||||
}
|
||||
|
||||
return cairo_surface_reference (default_icon);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
get_default_mini_icon (void)
|
||||
{
|
||||
static cairo_surface_t *default_icon = NULL;
|
||||
|
||||
if (default_icon == NULL)
|
||||
{
|
||||
default_icon = load_default_window_icon (META_MINI_ICON_WIDTH);
|
||||
g_assert (default_icon);
|
||||
}
|
||||
|
||||
return cairo_surface_reference (default_icon);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_update_icon_now (MetaWindow *window,
|
||||
gboolean force)
|
||||
@@ -5438,17 +5396,11 @@ meta_window_update_icon_now (MetaWindow *window,
|
||||
{
|
||||
if (window->icon)
|
||||
cairo_surface_destroy (window->icon);
|
||||
if (icon)
|
||||
window->icon = icon;
|
||||
else
|
||||
window->icon = get_default_window_icon ();
|
||||
window->icon = icon;
|
||||
|
||||
if (window->mini_icon)
|
||||
cairo_surface_destroy (window->mini_icon);
|
||||
if (mini_icon)
|
||||
window->mini_icon = mini_icon;
|
||||
else
|
||||
window->mini_icon = get_default_mini_icon ();
|
||||
window->mini_icon = mini_icon;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (window));
|
||||
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_ICON]);
|
||||
@@ -5457,9 +5409,6 @@ meta_window_update_icon_now (MetaWindow *window,
|
||||
|
||||
redraw_icon (window);
|
||||
}
|
||||
|
||||
g_assert (window->icon);
|
||||
g_assert (window->mini_icon);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -8146,8 +8095,7 @@ mouse_mode_focus (MetaWindow *window,
|
||||
"Unsetting focus from %s due to mouse entering "
|
||||
"the DESKTOP window\n",
|
||||
display->focus_window->desc);
|
||||
meta_x11_display_focus_the_no_focus_window (display->x11_display,
|
||||
timestamp);
|
||||
meta_display_unset_input_focus (display, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1308,8 +1308,7 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Setting focus to no_focus_window, since no valid "
|
||||
"window to focus found.\n");
|
||||
meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display,
|
||||
timestamp);
|
||||
meta_display_unset_input_focus (workspace->display, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1381,8 +1380,7 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace,
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n");
|
||||
meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display,
|
||||
timestamp);
|
||||
meta_display_unset_input_focus (workspace->display, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -392,6 +392,8 @@ mutter_sources = [
|
||||
'x11/meta-x11-selection-input-stream-private.h',
|
||||
'x11/meta-x11-selection-output-stream.c',
|
||||
'x11/meta-x11-selection-output-stream-private.h',
|
||||
'x11/meta-x11-stack.c',
|
||||
'x11/meta-x11-stack-private.h',
|
||||
'x11/mutter-Xatomtype.h',
|
||||
'x11/session.c',
|
||||
'x11/session.h',
|
||||
@@ -623,6 +625,23 @@ dbus_idle_monitor_built_sources = gnome.gdbus_codegen('meta-dbus-idle-monitor',
|
||||
)
|
||||
mutter_built_sources += dbus_idle_monitor_built_sources
|
||||
|
||||
if have_profiler
|
||||
mutter_sources += [
|
||||
'backends/meta-profiler.c',
|
||||
'backends/meta-profiler.h',
|
||||
]
|
||||
|
||||
dbus_interfaces_dir = join_paths(datadir, 'dbus-1', 'interfaces')
|
||||
sysprof3_dbus_file = join_paths(dbus_interfaces_dir, 'org.gnome.Sysprof3.Profiler.xml')
|
||||
|
||||
dbus_sysprof3_profiler_built_sources = gnome.gdbus_codegen('meta-dbus-sysprof3-profiler',
|
||||
sysprof3_dbus_file,
|
||||
interface_prefix: 'org.gnome.',
|
||||
namespace: 'MetaDBus',
|
||||
)
|
||||
mutter_built_sources += dbus_sysprof3_profiler_built_sources
|
||||
endif
|
||||
|
||||
if have_native_backend
|
||||
cvt = find_program('cvt')
|
||||
|
||||
|
@@ -297,4 +297,13 @@ MetaSoundPlayer * meta_display_get_sound_player (MetaDisplay *display);
|
||||
META_EXPORT
|
||||
MetaSelection * meta_display_get_selection (MetaDisplay *display);
|
||||
|
||||
META_EXPORT
|
||||
void meta_display_set_input_focus (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
gboolean focus_frame,
|
||||
guint32 timestamp);
|
||||
META_EXPORT
|
||||
void meta_display_unset_input_focus (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
|
||||
#endif
|
||||
|
@@ -239,6 +239,16 @@ struct _MetaPluginClass
|
||||
*/
|
||||
MetaInhibitShortcutsDialog * (* create_inhibit_shortcuts_dialog) (MetaPlugin *plugin,
|
||||
MetaWindow *window);
|
||||
|
||||
/**
|
||||
* MetaPluginClass::locate_pointer:
|
||||
*
|
||||
* Virtual function called when the user triggered the "locate-pointer"
|
||||
* mechanism.
|
||||
* The common way to implement this function is to show some animation
|
||||
* on screen to draw user attention on the pointer location.
|
||||
*/
|
||||
void (*locate_pointer) (MetaPlugin *plugin);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -63,27 +63,4 @@ META_EXPORT
|
||||
gboolean meta_x11_display_xwindow_is_a_no_focus_window (MetaX11Display *x11_display,
|
||||
Window xwindow);
|
||||
|
||||
/* meta_x11_display_set_input_focus_window is like XSetInputFocus, except
|
||||
* that (a) it can't detect timestamps later than the current time,
|
||||
* since Mutter isn't part of the XServer, and thus gives erroneous
|
||||
* behavior in this circumstance (so don't do it), (b) it uses
|
||||
* display->last_focus_time since we don't have access to the true
|
||||
* Xserver one, (c) it makes use of display->user_time since checking
|
||||
* whether a window should be allowed to be focused should depend
|
||||
* on user_time events (see bug 167358, comment 15 in particular)
|
||||
*/
|
||||
META_EXPORT
|
||||
void meta_x11_display_set_input_focus_window (MetaX11Display *x11_display,
|
||||
MetaWindow *window,
|
||||
gboolean focus_frame,
|
||||
guint32 timestamp);
|
||||
|
||||
/* meta_x11_display_focus_the_no_focus_window is called when the
|
||||
* designated no_focus_window should be focused, but is otherwise the
|
||||
* same as meta_display_set_input_focus_window
|
||||
*/
|
||||
META_EXPORT
|
||||
void meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display,
|
||||
guint32 timestamp);
|
||||
|
||||
#endif /* META_X11_DISPLAY_H */
|
||||
|
@@ -322,6 +322,7 @@ int meta_prefs_get_drag_threshold (void);
|
||||
* @META_KEYBINDING_ACTION_MOVE_TO_SIDE_W: FILLME
|
||||
* @META_KEYBINDING_ACTION_MOVE_TO_CENTER: FILLME
|
||||
* @META_KEYBINDING_ACTION_OVERLAY_KEY: FILLME
|
||||
* @META_KEYBINDING_ACTION_LOCATE_POINTER_KEY: FILLME
|
||||
* @META_KEYBINDING_ACTION_ALWAYS_ON_TOP: FILLME
|
||||
* @META_KEYBINDING_ACTION_LAST: FILLME
|
||||
*/
|
||||
@@ -419,6 +420,7 @@ typedef enum _MetaKeyBindingAction
|
||||
META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
|
||||
META_KEYBINDING_ACTION_MOVE_TO_CENTER,
|
||||
META_KEYBINDING_ACTION_OVERLAY_KEY,
|
||||
META_KEYBINDING_ACTION_LOCATE_POINTER_KEY,
|
||||
META_KEYBINDING_ACTION_ISO_NEXT_GROUP,
|
||||
META_KEYBINDING_ACTION_ALWAYS_ON_TOP,
|
||||
META_KEYBINDING_ACTION_SWITCH_MONITOR,
|
||||
|
@@ -29,10 +29,9 @@ The tests are installed according to:
|
||||
|
||||
https://wiki.gnome.org/Initiatives/GnomeGoals/InstalledTests
|
||||
|
||||
if --enable-installed-tests is passed to configure. You can run them
|
||||
uninstalled with:
|
||||
if -Dtests=true is passed to `meson configure`. You can run them uninstalled with:
|
||||
|
||||
cd src && make run-tests
|
||||
ninja test
|
||||
|
||||
Command reference
|
||||
=================
|
||||
|
@@ -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 ();
|
||||
|
@@ -385,6 +385,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)
|
||||
|
@@ -31,8 +31,6 @@
|
||||
#include "meta/prefs.h"
|
||||
#include "ui/frames.h"
|
||||
|
||||
#define DEBUG_FILL_STRUCT(s) memset ((s), 0xef, sizeof (*(s)))
|
||||
|
||||
static void scale_border (GtkBorder *border, double factor);
|
||||
|
||||
static MetaFrameLayout *
|
||||
@@ -58,7 +56,6 @@ meta_frame_layout_free (MetaFrameLayout *layout)
|
||||
{
|
||||
g_return_if_fail (layout != NULL);
|
||||
|
||||
DEBUG_FILL_STRUCT (layout);
|
||||
g_free (layout);
|
||||
}
|
||||
|
||||
@@ -967,7 +964,6 @@ meta_theme_free (MetaTheme *theme)
|
||||
if (theme->layouts[i])
|
||||
meta_frame_layout_free (theme->layouts[i]);
|
||||
|
||||
DEBUG_FILL_STRUCT (theme);
|
||||
g_free (theme);
|
||||
}
|
||||
|
||||
|
@@ -188,6 +188,9 @@ meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
|
||||
ClutterPoint point;
|
||||
ClutterRect logical_monitor_rect;
|
||||
|
||||
if (!priv->cursor_renderer)
|
||||
return FALSE;
|
||||
|
||||
logical_monitor_rect =
|
||||
meta_rectangle_to_clutter_rect (&logical_monitor->rect);
|
||||
|
||||
|
@@ -95,6 +95,9 @@ G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
|
||||
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
|
||||
META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
|
||||
|
||||
static void unset_selection_source (MetaWaylandDataDevice *data_device,
|
||||
MetaSelectionType selection_type);
|
||||
|
||||
static MetaWaylandDataSource *
|
||||
meta_wayland_data_source_wayland_new (struct wl_resource *resource);
|
||||
static MetaWaylandDataSource *
|
||||
@@ -567,12 +570,14 @@ destroy_data_offer (struct wl_resource *resource)
|
||||
|
||||
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
|
||||
{
|
||||
if (seat && seat->data_device.dnd_data_source == offer->source &&
|
||||
if (seat->data_device.dnd_data_source == offer->source &&
|
||||
wl_resource_get_version (offer->resource) <
|
||||
WL_DATA_OFFER_ACTION_SINCE_VERSION)
|
||||
meta_wayland_data_source_notify_finish (offer->source);
|
||||
else
|
||||
{
|
||||
if (seat->data_device.dnd_data_source == offer->source)
|
||||
unset_selection_source (&seat->data_device, META_SELECTION_DND);
|
||||
meta_wayland_data_source_cancel (offer->source);
|
||||
meta_wayland_data_source_set_current_offer (offer->source, NULL);
|
||||
}
|
||||
@@ -1038,7 +1043,6 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
|
||||
{
|
||||
/* Detach the data source from the grab, it's meant to live longer */
|
||||
meta_wayland_drag_grab_set_source (drag_grab, NULL);
|
||||
meta_wayland_data_source_set_seat (source, NULL);
|
||||
|
||||
meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus);
|
||||
meta_wayland_data_source_notify_drop_performed (source);
|
||||
|
@@ -172,13 +172,16 @@ gtk_surface_request_focus (struct wl_client *client,
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
uint32_t timestamp;
|
||||
uint32_t timestamp, workspace_idx;
|
||||
|
||||
workspace_idx = meta_startup_sequence_get_workspace (sequence);
|
||||
timestamp = meta_startup_sequence_get_timestamp (sequence);
|
||||
|
||||
meta_startup_sequence_complete (sequence);
|
||||
meta_startup_notification_remove_sequence (display->startup_notification,
|
||||
sequence);
|
||||
if (workspace_idx >= 0)
|
||||
meta_window_change_workspace_by_index (window, workspace_idx, TRUE);
|
||||
|
||||
meta_window_activate_full (window, timestamp,
|
||||
META_CLIENT_TYPE_APPLICATION, NULL);
|
||||
|
@@ -862,6 +862,19 @@ init_pointer_constraint (struct wl_resource *resource,
|
||||
return;
|
||||
}
|
||||
|
||||
switch (lifetime)
|
||||
{
|
||||
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
|
||||
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
wl_resource_post_error (resource,
|
||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
"Invalid constraint lifetime");
|
||||
return;
|
||||
}
|
||||
|
||||
constraint = meta_wayland_pointer_constraint_new (surface, seat,
|
||||
region,
|
||||
lifetime,
|
||||
|
@@ -48,6 +48,7 @@ typedef struct
|
||||
char *lock_file;
|
||||
int abstract_fd;
|
||||
int unix_fd;
|
||||
struct wl_display *wayland_display;
|
||||
struct wl_client *client;
|
||||
struct wl_resource *xserver_resource;
|
||||
char *display_name;
|
||||
|
@@ -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
|
||||
|
@@ -115,13 +115,24 @@ meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool,
|
||||
return;
|
||||
|
||||
if (tool->cursor_surface)
|
||||
wl_list_remove (&tool->cursor_surface_destroy_listener.link);
|
||||
{
|
||||
MetaWaylandCursorSurface *cursor_surface;
|
||||
|
||||
cursor_surface = META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role);
|
||||
meta_wayland_cursor_surface_set_renderer (cursor_surface, NULL);
|
||||
|
||||
meta_wayland_surface_update_outputs (tool->cursor_surface);
|
||||
wl_list_remove (&tool->cursor_surface_destroy_listener.link);
|
||||
}
|
||||
|
||||
tool->cursor_surface = surface;
|
||||
|
||||
if (tool->cursor_surface)
|
||||
wl_resource_add_destroy_listener (tool->cursor_surface->resource,
|
||||
&tool->cursor_surface_destroy_listener);
|
||||
{
|
||||
meta_wayland_surface_update_outputs (tool->cursor_surface);
|
||||
wl_resource_add_destroy_listener (tool->cursor_surface->resource,
|
||||
&tool->cursor_surface_destroy_listener);
|
||||
}
|
||||
|
||||
meta_wayland_tablet_tool_update_cursor_surface (tool);
|
||||
}
|
||||
|
@@ -142,10 +142,12 @@ meta_window_wayland_focus (MetaWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
if (meta_window_is_focusable (window))
|
||||
meta_x11_display_set_input_focus_window (window->display->x11_display,
|
||||
window,
|
||||
FALSE,
|
||||
timestamp);
|
||||
{
|
||||
meta_display_set_input_focus (window->display,
|
||||
window,
|
||||
FALSE,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -611,6 +613,16 @@ meta_window_wayland_are_updates_frozen (MetaWindow *window)
|
||||
return !wl_window->has_been_shown;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_wayland_map (MetaWindow *window)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_wayland_unmap (MetaWindow *window)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
|
||||
{
|
||||
@@ -634,6 +646,8 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
|
||||
window_class->is_stackable = meta_window_wayland_is_stackable;
|
||||
window_class->can_ping = meta_window_wayland_can_ping;
|
||||
window_class->are_updates_frozen = meta_window_wayland_are_updates_frozen;
|
||||
window_class->map = meta_window_wayland_map;
|
||||
window_class->unmap = meta_window_wayland_unmap;
|
||||
}
|
||||
|
||||
MetaWindow *
|
||||
@@ -641,7 +655,6 @@ meta_window_wayland_new (MetaDisplay *display,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
XWindowAttributes attrs = { 0 };
|
||||
MetaWindow *window;
|
||||
|
||||
/*
|
||||
* Set attributes used by _meta_window_shared_new, don't bother trying to fake
|
||||
@@ -656,26 +669,13 @@ meta_window_wayland_new (MetaDisplay *display,
|
||||
attrs.map_state = IsUnmapped;
|
||||
attrs.override_redirect = False;
|
||||
|
||||
/* XXX: Note: In the Wayland case we currently still trap X errors while
|
||||
* creating a MetaWindow because we will still be making various redundant
|
||||
* X requests (passing a window xid of None) until we thoroughly audit all
|
||||
* the code to make sure it knows about non X based clients...
|
||||
*/
|
||||
meta_x11_error_trap_push (display->x11_display); /* Push a trap over all of window
|
||||
* creation, to reduce XSync() calls
|
||||
*/
|
||||
|
||||
window = _meta_window_shared_new (display,
|
||||
META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
surface,
|
||||
None,
|
||||
WithdrawnState,
|
||||
META_COMP_EFFECT_CREATE,
|
||||
&attrs);
|
||||
|
||||
meta_x11_error_trap_pop (display->x11_display); /* pop the XSync()-reducing trap */
|
||||
|
||||
return window;
|
||||
return _meta_window_shared_new (display,
|
||||
META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
surface,
|
||||
None,
|
||||
WithdrawnState,
|
||||
META_COMP_EFFECT_CREATE,
|
||||
&attrs);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@@ -193,8 +193,6 @@ meta_xwayland_grab_is_granted (MetaWindow *window)
|
||||
|
||||
backend = meta_get_backend ();
|
||||
settings = meta_backend_get_settings (backend);
|
||||
if (!meta_settings_are_xwayland_grabs_allowed (settings))
|
||||
return FALSE;
|
||||
|
||||
/* Check whether the window is blacklisted */
|
||||
meta_settings_get_xwayland_grab_patterns (settings, &whitelist, &blacklist);
|
||||
@@ -214,6 +212,22 @@ meta_xwayland_grab_is_granted (MetaWindow *window)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_xwayland_grab_should_lock_focus (MetaWindow *window)
|
||||
{
|
||||
MetaBackend *backend;
|
||||
MetaSettings *settings;
|
||||
|
||||
/* Lock focus applies to O-R windows which never receive keyboard focus otherwise */
|
||||
if (!window->override_redirect)
|
||||
return FALSE;
|
||||
|
||||
backend = meta_get_backend ();
|
||||
settings = meta_backend_get_settings (backend);
|
||||
|
||||
return meta_settings_are_xwayland_grabs_allowed (settings);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_xwayland_keyboard_grab_activate (MetaXwaylandKeyboardActiveGrab *active_grab)
|
||||
{
|
||||
@@ -225,8 +239,8 @@ meta_xwayland_keyboard_grab_activate (MetaXwaylandKeyboardActiveGrab *active_gra
|
||||
{
|
||||
meta_verbose ("XWayland window %s has a grab granted", window->desc);
|
||||
meta_wayland_surface_inhibit_shortcuts (surface, seat);
|
||||
/* Use a grab for O-R windows which never receive keyboard focus otherwise */
|
||||
if (window->override_redirect)
|
||||
|
||||
if (meta_xwayland_grab_should_lock_focus (window))
|
||||
meta_wayland_keyboard_start_grab (seat->keyboard, &active_grab->keyboard_grab);
|
||||
}
|
||||
if (active_grab->window_associate_handler)
|
||||
|
@@ -465,32 +465,27 @@ on_displayfd_ready (int fd,
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_xwayland_start (MetaXWaylandManager *manager,
|
||||
struct wl_display *wl_display)
|
||||
static gboolean
|
||||
meta_xwayland_init_xserver (MetaXWaylandManager *manager)
|
||||
{
|
||||
int xwayland_client_fd[2];
|
||||
int displayfd[2];
|
||||
gboolean started = FALSE;
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
GSubprocessFlags flags;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!choose_xdisplay (manager))
|
||||
goto out;
|
||||
|
||||
/* We want xwayland to be a wayland client so we make a socketpair to setup a
|
||||
* wayland protocol connection. */
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
|
||||
{
|
||||
g_warning ("xwayland_client_fd socketpair failed\n");
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0)
|
||||
{
|
||||
g_warning ("displayfd socketpair failed\n");
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* xwayland, please. */
|
||||
@@ -511,16 +506,10 @@ meta_xwayland_start (MetaXWaylandManager *manager,
|
||||
|
||||
g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE);
|
||||
|
||||
/* Use the -terminate parameter to ensure that Xwayland exits cleanly
|
||||
* after the last client disconnects. Fortunately that includes the window
|
||||
* manager so it won't exit prematurely either. This ensures that Xwayland
|
||||
* won't try to reconnect and crash, leaving uninteresting core dumps. We do
|
||||
* want core dumps from Xwayland but only if a real bug occurs...
|
||||
*/
|
||||
manager->proc = g_subprocess_launcher_spawn (launcher, &error,
|
||||
XWAYLAND_PATH, manager->display_name,
|
||||
"-rootless",
|
||||
"-terminate",
|
||||
"-noreset",
|
||||
"-accessx",
|
||||
"-core",
|
||||
"-listen", "4",
|
||||
@@ -530,14 +519,15 @@ meta_xwayland_start (MetaXWaylandManager *manager,
|
||||
if (!manager->proc)
|
||||
{
|
||||
g_error ("Failed to spawn Xwayland: %s", error->message);
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
manager->xserver_died_cancellable = g_cancellable_new ();
|
||||
g_subprocess_wait_async (manager->proc, manager->xserver_died_cancellable,
|
||||
xserver_died, NULL);
|
||||
g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready, manager);
|
||||
manager->client = wl_client_create (wl_display, xwayland_client_fd[0]);
|
||||
manager->client = wl_client_create (manager->wayland_display,
|
||||
xwayland_client_fd[0]);
|
||||
|
||||
/* We need to run a mainloop until we know xwayland has a binding
|
||||
* for our xserver interface at which point we can assume it's
|
||||
@@ -545,15 +535,18 @@ meta_xwayland_start (MetaXWaylandManager *manager,
|
||||
manager->init_loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (manager->init_loop);
|
||||
|
||||
started = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!started)
|
||||
{
|
||||
unlink (manager->lock_file);
|
||||
g_clear_pointer (&manager->lock_file, g_free);
|
||||
}
|
||||
return started;
|
||||
gboolean
|
||||
meta_xwayland_start (MetaXWaylandManager *manager,
|
||||
struct wl_display *wl_display)
|
||||
{
|
||||
if (!choose_xdisplay (manager))
|
||||
return FALSE;
|
||||
|
||||
manager->wayland_display = wl_display;
|
||||
return meta_xwayland_init_xserver (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -803,14 +803,15 @@ handle_window_focus_event (MetaX11Display *x11_display,
|
||||
* multiple focus events with the same serial.
|
||||
*/
|
||||
if (x11_display->server_focus_serial > x11_display->focus_serial ||
|
||||
(!display->focused_by_us &&
|
||||
(!x11_display->focused_by_us &&
|
||||
x11_display->server_focus_serial == x11_display->focus_serial))
|
||||
{
|
||||
meta_display_update_focus_window (display,
|
||||
focus_window,
|
||||
focus_window ? focus_window->xwindow : None,
|
||||
x11_display->server_focus_serial,
|
||||
FALSE);
|
||||
meta_display_update_focus_window (display, focus_window);
|
||||
meta_x11_display_update_focus_window (x11_display,
|
||||
focus_window ?
|
||||
focus_window->xwindow : None,
|
||||
x11_display->server_focus_serial,
|
||||
FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@@ -882,7 +883,7 @@ handle_input_xevent (MetaX11Display *x11_display,
|
||||
enter_event->mode != XINotifyGrab &&
|
||||
enter_event->mode != XINotifyUngrab &&
|
||||
enter_event->detail != XINotifyInferior &&
|
||||
meta_display_focus_sentinel_clear (display))
|
||||
meta_x11_display_focus_sentinel_clear (x11_display))
|
||||
{
|
||||
meta_window_handle_enter (window,
|
||||
enter_event->time,
|
||||
@@ -1525,7 +1526,7 @@ handle_other_xevent (MetaX11Display *x11_display,
|
||||
if (event->xproperty.atom ==
|
||||
x11_display->atom__MUTTER_SENTINEL)
|
||||
{
|
||||
meta_display_decrement_focus_sentinel (display);
|
||||
meta_x11_display_decrement_focus_sentinel (x11_display);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1792,7 +1793,7 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
||||
if (META_IS_BACKEND_X11 (backend))
|
||||
meta_backend_x11_handle_event (META_BACKEND_X11 (backend), event);
|
||||
|
||||
if (display->focused_by_us &&
|
||||
if (x11_display->focused_by_us &&
|
||||
event->xany.serial > x11_display->focus_serial &&
|
||||
display->focus_window &&
|
||||
!window_has_xwindow (display->focus_window, x11_display->server_focus_window))
|
||||
@@ -1801,10 +1802,11 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
||||
display->focus_window->desc);
|
||||
meta_display_update_focus_window (display,
|
||||
meta_x11_display_lookup_x_window (x11_display,
|
||||
x11_display->server_focus_window),
|
||||
x11_display->server_focus_window,
|
||||
x11_display->server_focus_serial,
|
||||
FALSE);
|
||||
x11_display->server_focus_window));
|
||||
meta_x11_display_update_focus_window (x11_display,
|
||||
x11_display->server_focus_window,
|
||||
x11_display->server_focus_serial,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
if (event->xany.window == x11_display->xroot)
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "meta/types.h"
|
||||
#include "meta/meta-x11-display.h"
|
||||
#include "meta-startup-notification-x11.h"
|
||||
#include "meta-x11-stack-private.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
|
||||
@@ -133,8 +134,21 @@ struct _MetaX11Display
|
||||
GList *output_streams;
|
||||
} selection;
|
||||
|
||||
/* If true, server->focus_serial refers to us changing the focus; in
|
||||
* this case, we can ignore focus events that have exactly focus_serial,
|
||||
* since we take care to make another request immediately afterwards.
|
||||
* But if focus is being changed by another client, we have to accept
|
||||
* multiple events with the same serial.
|
||||
*/
|
||||
guint focused_by_us : 1;
|
||||
|
||||
guint keys_grabbed : 1;
|
||||
|
||||
/* we use property updates as sentinels for certain window focus events
|
||||
* to avoid some race conditions on EnterNotify events
|
||||
*/
|
||||
int sentinel_counter;
|
||||
|
||||
int composite_event_base;
|
||||
int composite_error_base;
|
||||
int composite_major_version;
|
||||
@@ -162,6 +176,7 @@ struct _MetaX11Display
|
||||
#define META_X11_DISPLAY_HAS_XINPUT_23(x11_display) ((x11_display)->have_xinput_23)
|
||||
|
||||
MetaX11StartupNotification *startup_notification;
|
||||
MetaX11Stack *x11_stack;
|
||||
};
|
||||
|
||||
MetaX11Display *meta_x11_display_new (MetaDisplay *display, GError **error);
|
||||
@@ -222,4 +237,16 @@ MetaLogicalMonitor *meta_x11_display_xinerama_index_to_logical_monitor (MetaX11D
|
||||
void meta_x11_display_update_workspace_layout (MetaX11Display *x11_display);
|
||||
void meta_x11_display_update_workspace_names (MetaX11Display *x11_display);
|
||||
|
||||
void meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display);
|
||||
void meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display);
|
||||
gboolean meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display);
|
||||
|
||||
void meta_x11_display_update_focus_window (MetaX11Display *x11_display,
|
||||
Window xwindow,
|
||||
gulong serial,
|
||||
gboolean focused_by_us);
|
||||
void meta_x11_display_set_input_focus (MetaX11Display *x11_display,
|
||||
Window xwindow,
|
||||
guint32 timestamp);
|
||||
|
||||
#endif /* META_X11_DISPLAY_PRIVATE_H */
|
||||
|
@@ -95,6 +95,27 @@ static void unset_wm_check_hint (MetaX11Display *x11_display);
|
||||
static void prefs_changed_callback (MetaPreference pref,
|
||||
void *data);
|
||||
|
||||
static void
|
||||
meta_x11_display_unmanage_windows (MetaX11Display *x11_display)
|
||||
{
|
||||
GList *windows, *l;
|
||||
MetaWindow *window;
|
||||
|
||||
if (!x11_display->xids)
|
||||
return;
|
||||
|
||||
windows = g_hash_table_get_values (x11_display->xids);
|
||||
g_list_foreach (windows, (GFunc) g_object_ref, NULL);
|
||||
|
||||
for (l = windows; l; l = l->next)
|
||||
{
|
||||
window = l->data;
|
||||
if (!window->unmanaging)
|
||||
meta_window_unmanage (window, META_CURRENT_TIME);
|
||||
}
|
||||
g_list_free_full (windows, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_display_dispose (GObject *object)
|
||||
{
|
||||
@@ -107,6 +128,9 @@ meta_x11_display_dispose (GObject *object)
|
||||
meta_x11_display_ungrab_keys (x11_display);
|
||||
|
||||
meta_x11_selection_shutdown (x11_display);
|
||||
meta_x11_display_unmanage_windows (x11_display);
|
||||
|
||||
g_clear_object (&x11_display->x11_stack);
|
||||
|
||||
if (x11_display->ui)
|
||||
{
|
||||
@@ -466,6 +490,13 @@ init_x11_bell (MetaX11Display *x11_display)
|
||||
&mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* We are playing sounds using libcanberra support, we handle the
|
||||
* bell whether its an audible bell or a visible bell */
|
||||
XkbChangeEnabledControls (x11_display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -483,32 +514,6 @@ shutdown_x11_bell (MetaX11Display *x11_display)
|
||||
XkbAudibleBellMask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turns the bell to audible or visual. This tells X what to do, but
|
||||
* not Mutter; you will need to set the "visual bell" pref for that.
|
||||
*/
|
||||
static void
|
||||
set_x11_bell_is_audible (MetaX11Display *x11_display,
|
||||
gboolean is_audible)
|
||||
{
|
||||
/* When we are playing sounds using libcanberra support, we handle the
|
||||
* bell whether its an audible bell or a visible bell */
|
||||
gboolean enable_system_bell = FALSE;
|
||||
|
||||
XkbChangeEnabledControls (x11_display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
enable_system_bell ? XkbAudibleBellMask : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_is_audible_changed (MetaBell *bell,
|
||||
gboolean is_audible,
|
||||
MetaX11Display *x11_display)
|
||||
{
|
||||
set_x11_bell_is_audible (x11_display, is_audible);
|
||||
}
|
||||
|
||||
static void
|
||||
set_desktop_geometry_hint (MetaX11Display *x11_display)
|
||||
{
|
||||
@@ -1086,6 +1091,9 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
|
||||
};
|
||||
Atom atoms[G_N_ELEMENTS(atom_names)];
|
||||
|
||||
if (!meta_x11_init_gdk_display (error))
|
||||
return NULL;
|
||||
|
||||
g_assert (prepared_gdk_display);
|
||||
gdk_display = g_steal_pointer (&prepared_gdk_display);
|
||||
|
||||
@@ -1270,6 +1278,7 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
|
||||
set_desktop_geometry_hint (x11_display);
|
||||
|
||||
x11_display->ui = meta_ui_new (x11_display);
|
||||
x11_display->x11_stack = meta_x11_stack_new (x11_display);
|
||||
|
||||
x11_display->keys_grabbed = FALSE;
|
||||
meta_x11_display_grab_keys (x11_display);
|
||||
@@ -1323,12 +1332,6 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
|
||||
|
||||
init_x11_bell (x11_display);
|
||||
|
||||
g_signal_connect_object (display->bell, "is-audible-changed",
|
||||
G_CALLBACK (on_is_audible_changed),
|
||||
x11_display, 0);
|
||||
|
||||
set_x11_bell_is_audible (x11_display, meta_prefs_bell_is_audible ());
|
||||
|
||||
meta_x11_startup_notification_init (x11_display);
|
||||
meta_x11_selection_init (x11_display);
|
||||
|
||||
@@ -1819,17 +1822,27 @@ meta_x11_display_update_active_window_hint (MetaX11Display *x11_display)
|
||||
meta_x11_error_trap_pop (x11_display);
|
||||
}
|
||||
|
||||
static void
|
||||
request_xserver_input_focus_change (MetaX11Display *x11_display,
|
||||
MetaWindow *meta_window,
|
||||
Window xwindow,
|
||||
guint32 timestamp)
|
||||
void
|
||||
meta_x11_display_update_focus_window (MetaX11Display *x11_display,
|
||||
Window xwindow,
|
||||
gulong serial,
|
||||
gboolean focused_by_us)
|
||||
{
|
||||
gulong serial;
|
||||
x11_display->focus_serial = serial;
|
||||
x11_display->focused_by_us = !!focused_by_us;
|
||||
|
||||
if (meta_display_timestamp_too_old (x11_display->display, ×tamp))
|
||||
if (x11_display->focus_xwindow == xwindow)
|
||||
return;
|
||||
|
||||
x11_display->focus_xwindow = xwindow;
|
||||
meta_x11_display_update_active_window_hint (x11_display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_x11_display_set_input_focus (MetaX11Display *x11_display,
|
||||
Window xwindow,
|
||||
guint32 timestamp)
|
||||
{
|
||||
meta_x11_error_trap_push (x11_display);
|
||||
|
||||
/* In order for mutter to know that the focus request succeeded, we track
|
||||
@@ -1842,8 +1855,6 @@ request_xserver_input_focus_change (MetaX11Display *x11_display,
|
||||
*/
|
||||
XGrabServer (x11_display->xdisplay);
|
||||
|
||||
serial = XNextRequest (x11_display->xdisplay);
|
||||
|
||||
XSetInputFocus (x11_display->xdisplay,
|
||||
xwindow,
|
||||
RevertToPointerRoot,
|
||||
@@ -1857,30 +1868,7 @@ request_xserver_input_focus_change (MetaX11Display *x11_display,
|
||||
XUngrabServer (x11_display->xdisplay);
|
||||
XFlush (x11_display->xdisplay);
|
||||
|
||||
meta_display_update_focus_window (x11_display->display,
|
||||
meta_window,
|
||||
xwindow,
|
||||
serial,
|
||||
TRUE);
|
||||
|
||||
meta_x11_error_trap_pop (x11_display);
|
||||
|
||||
x11_display->display->last_focus_time = timestamp;
|
||||
|
||||
if (meta_window == NULL || meta_window != x11_display->display->autoraise_window)
|
||||
meta_display_remove_autoraise_callback (x11_display->display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_x11_display_set_input_focus_window (MetaX11Display *x11_display,
|
||||
MetaWindow *window,
|
||||
gboolean focus_frame,
|
||||
guint32 timestamp)
|
||||
{
|
||||
request_xserver_input_focus_change (x11_display,
|
||||
window,
|
||||
focus_frame ? window->frame->xwindow : window->xwindow,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1888,20 +1876,12 @@ meta_x11_display_set_input_focus_xwindow (MetaX11Display *x11_display,
|
||||
Window window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
request_xserver_input_focus_change (x11_display,
|
||||
NULL,
|
||||
window,
|
||||
timestamp);
|
||||
}
|
||||
gulong serial;
|
||||
|
||||
void
|
||||
meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display,
|
||||
guint32 timestamp)
|
||||
{
|
||||
request_xserver_input_focus_change (x11_display,
|
||||
NULL,
|
||||
x11_display->no_focus_window,
|
||||
timestamp);
|
||||
meta_display_unset_input_focus (x11_display->display, timestamp);
|
||||
serial = XNextRequest (x11_display->xdisplay);
|
||||
meta_x11_display_set_input_focus (x11_display, window, timestamp);
|
||||
meta_x11_display_update_focus_window (x11_display, window, serial, TRUE);
|
||||
}
|
||||
|
||||
static MetaX11DisplayLogicalMonitorData *
|
||||
@@ -2177,3 +2157,34 @@ prefs_changed_callback (MetaPreference pref,
|
||||
set_workspace_names (x11_display);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display)
|
||||
{
|
||||
unsigned long data[1];
|
||||
|
||||
data[0] = meta_display_get_current_time (x11_display->display);
|
||||
|
||||
XChangeProperty (x11_display->xdisplay,
|
||||
x11_display->xroot,
|
||||
x11_display->atom__MUTTER_SENTINEL,
|
||||
XA_CARDINAL,
|
||||
32, PropModeReplace, (guchar*) data, 1);
|
||||
|
||||
x11_display->sentinel_counter += 1;
|
||||
}
|
||||
|
||||
void
|
||||
meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display)
|
||||
{
|
||||
x11_display->sentinel_counter -= 1;
|
||||
|
||||
if (x11_display->sentinel_counter < 0)
|
||||
x11_display->sentinel_counter = 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display)
|
||||
{
|
||||
return (x11_display->sentinel_counter == 0);
|
||||
}
|
||||
|
33
src/x11/meta-x11-stack-private.h
Normal file
33
src/x11/meta-x11-stack-private.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_X11_STACK_H
|
||||
#define META_X11_STACK_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta/types.h"
|
||||
|
||||
#define META_TYPE_X11_STACK (meta_x11_stack_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaX11Stack, meta_x11_stack, META, X11_STACK, GObject)
|
||||
|
||||
typedef struct _MetaX11Stack MetaX11Stack;
|
||||
|
||||
MetaX11Stack * meta_x11_stack_new (MetaX11Display *x11_display);
|
||||
|
||||
#endif /* META_X11_STACK_H */
|
413
src/x11/meta-x11-stack.c
Normal file
413
src/x11/meta-x11-stack.c
Normal file
@@ -0,0 +1,413 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "core/frame.h"
|
||||
#include "core/stack.h"
|
||||
#include "core/window-private.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
#include "x11/meta-x11-stack-private.h"
|
||||
|
||||
struct _MetaX11Stack
|
||||
{
|
||||
GObject parent;
|
||||
MetaX11Display *x11_display;
|
||||
|
||||
/*
|
||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||
*/
|
||||
GArray *xwindows;
|
||||
|
||||
/*
|
||||
* MetaWindows waiting to be added to the xwindows list, after
|
||||
* being added to the MetaStack.
|
||||
*
|
||||
* The order of the elements in this list is not important; what is important
|
||||
* is the stack_position element of each window.
|
||||
*/
|
||||
GList *added;
|
||||
|
||||
/*
|
||||
* Windows (X handles, not MetaWindows) waiting to be removed from the
|
||||
* xwindows list, after being removed from the MetaStack.
|
||||
*
|
||||
* The order of the elements in this list is not important.
|
||||
*/
|
||||
GList *removed;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_DISPLAY = 1,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *pspecs[N_PROPS] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (MetaX11Stack, meta_x11_stack, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_x11_stack_init (MetaX11Stack *x11_stack)
|
||||
{
|
||||
x11_stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_stack_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
x11_stack->x11_display = g_value_get_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_stack_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
g_value_set_object (value, x11_stack->x11_display);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stack_window_added_cb (MetaStack *stack,
|
||||
MetaWindow *window,
|
||||
MetaX11Stack *x11_stack)
|
||||
{
|
||||
if (window->client_type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
return;
|
||||
|
||||
x11_stack->added = g_list_prepend (x11_stack->added, window);
|
||||
}
|
||||
|
||||
static void
|
||||
stack_window_removed_cb (MetaStack *stack,
|
||||
MetaWindow *window,
|
||||
MetaX11Stack *x11_stack)
|
||||
{
|
||||
if (window->client_type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
return;
|
||||
|
||||
x11_stack->added = g_list_remove (x11_stack->added, window);
|
||||
|
||||
x11_stack->removed = g_list_prepend (x11_stack->removed,
|
||||
GUINT_TO_POINTER (window->xwindow));
|
||||
if (window->frame)
|
||||
{
|
||||
x11_stack->removed = g_list_prepend (x11_stack->removed,
|
||||
GUINT_TO_POINTER (window->frame->xwindow));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_do_window_deletions:
|
||||
*
|
||||
* Go through "deleted" and take the matching windows
|
||||
* out of "windows".
|
||||
*/
|
||||
static void
|
||||
x11_stack_do_window_deletions (MetaX11Stack *x11_stack)
|
||||
{
|
||||
GList *tmp;
|
||||
int i;
|
||||
|
||||
tmp = x11_stack->removed;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
Window xwindow;
|
||||
xwindow = GPOINTER_TO_UINT (tmp->data);
|
||||
|
||||
/* We go from the end figuring removals are more
|
||||
* likely to be recent.
|
||||
*/
|
||||
i = x11_stack->xwindows->len;
|
||||
while (i > 0)
|
||||
{
|
||||
--i;
|
||||
|
||||
/* there's no guarantee we'll actually find windows to
|
||||
* remove, e.g. the same xwindow could have been
|
||||
* added/removed before we ever synced, and we put
|
||||
* both the window->xwindow and window->frame->xwindow
|
||||
* in the removal list.
|
||||
*/
|
||||
if (xwindow == g_array_index (x11_stack->xwindows, Window, i))
|
||||
{
|
||||
g_array_remove_index (x11_stack->xwindows, i);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_clear_pointer (&x11_stack->removed, g_list_free);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_stack_do_window_additions (MetaX11Stack *x11_stack)
|
||||
{
|
||||
GList *tmp;
|
||||
gint n_added;
|
||||
|
||||
n_added = g_list_length (x11_stack->added);
|
||||
if (n_added > 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Adding %d windows to sorted list\n",
|
||||
n_added);
|
||||
|
||||
/* stack->added has the most recent additions at the
|
||||
* front of the list, so we need to reverse it
|
||||
*/
|
||||
x11_stack->added = g_list_reverse (x11_stack->added);
|
||||
|
||||
tmp = x11_stack->added;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w;
|
||||
|
||||
w = tmp->data;
|
||||
g_array_append_val (x11_stack->xwindows, w->xwindow);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_pointer (&x11_stack->added, g_list_free);
|
||||
}
|
||||
|
||||
/**
|
||||
* x11_stack_sync_to_server:
|
||||
*
|
||||
* Order the windows on the X server to be the same as in our structure.
|
||||
* We do this using XRestackWindows if we don't know the previous order,
|
||||
* or XConfigureWindow on a few particular windows if we do and can figure
|
||||
* out the minimum set of changes. After that, we set __NET_CLIENT_LIST
|
||||
* and __NET_CLIENT_LIST_STACKING.
|
||||
*
|
||||
* FIXME: Now that we have a good view of the stacking order on the server
|
||||
* with MetaStackTracker it should be possible to do a simpler and better
|
||||
* job of computing the minimal set of stacking requests needed.
|
||||
*/
|
||||
static void
|
||||
x11_stack_sync_to_xserver (MetaX11Stack *x11_stack)
|
||||
{
|
||||
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||
MetaStack *stack = x11_display->display->stack;
|
||||
GArray *x11_stacked;
|
||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||
GList *tmp;
|
||||
GArray *hidden_stack_ids;
|
||||
uint64_t guard_window_id;
|
||||
GList *sorted;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
||||
|
||||
/* Create stacked xwindow arrays, in bottom-to-top order
|
||||
*/
|
||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||
hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Bottom to top: ");
|
||||
meta_push_no_msg_prefix ();
|
||||
|
||||
sorted = meta_stack_list_windows (stack, NULL);
|
||||
|
||||
for (tmp = sorted; tmp; tmp = tmp->next)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
guint64 top_level_window;
|
||||
guint64 stack_id;
|
||||
|
||||
if (w->unmanaging)
|
||||
continue;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||
w->layer, w->stack_position, w->desc);
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (x11_stacked, w->xwindow);
|
||||
|
||||
if (w->frame)
|
||||
top_level_window = w->frame->xwindow;
|
||||
else
|
||||
top_level_window = w->xwindow;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
stack_id = top_level_window;
|
||||
else
|
||||
stack_id = w->stamp;
|
||||
|
||||
/* We don't restack hidden windows along with the rest, though they are
|
||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||
* the screens fullscreen guard_window. */
|
||||
if (w->hidden)
|
||||
{
|
||||
g_array_append_val (hidden_stack_ids, stack_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_array_append_val (all_root_children_stacked, stack_id);
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "\n");
|
||||
meta_pop_no_msg_prefix ();
|
||||
|
||||
/* The screen guard window sits above all hidden windows and acts as
|
||||
* a barrier to input reaching these windows. */
|
||||
guard_window_id = x11_stack->x11_display->guard_window;
|
||||
g_array_append_val (hidden_stack_ids, guard_window_id);
|
||||
|
||||
/* Sync to server */
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||
all_root_children_stacked->len);
|
||||
|
||||
meta_stack_tracker_restack_managed (x11_display->display->stack_tracker,
|
||||
(guint64 *)all_root_children_stacked->data,
|
||||
all_root_children_stacked->len);
|
||||
meta_stack_tracker_restack_at_bottom (x11_display->display->stack_tracker,
|
||||
(guint64 *)hidden_stack_ids->data,
|
||||
hidden_stack_ids->len);
|
||||
|
||||
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
|
||||
|
||||
XChangeProperty (x11_stack->x11_display->xdisplay,
|
||||
x11_stack->x11_display->xroot,
|
||||
x11_stack->x11_display->atom__NET_CLIENT_LIST,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *) x11_stack->xwindows->data,
|
||||
x11_stack->xwindows->len);
|
||||
XChangeProperty (x11_stack->x11_display->xdisplay,
|
||||
x11_stack->x11_display->xroot,
|
||||
x11_stack->x11_display->atom__NET_CLIENT_LIST_STACKING,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *) x11_stacked->data,
|
||||
x11_stacked->len);
|
||||
|
||||
g_array_free (x11_stacked, TRUE);
|
||||
g_array_free (hidden_stack_ids, TRUE);
|
||||
g_array_free (all_root_children_stacked, TRUE);
|
||||
g_list_free (sorted);
|
||||
}
|
||||
|
||||
static void
|
||||
stack_changed_cb (MetaX11Stack *x11_stack)
|
||||
{
|
||||
/* Do removals before adds, with paranoid idea that we might re-add
|
||||
* the same window IDs.
|
||||
*/
|
||||
x11_stack_do_window_deletions (x11_stack);
|
||||
x11_stack_do_window_additions (x11_stack);
|
||||
x11_stack_sync_to_xserver (x11_stack);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_stack_constructed (GObject *object)
|
||||
{
|
||||
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||
|
||||
G_OBJECT_CLASS (meta_x11_stack_parent_class)->constructed (object);
|
||||
|
||||
g_signal_connect (x11_display->display->stack,
|
||||
"window-added",
|
||||
G_CALLBACK (stack_window_added_cb),
|
||||
x11_stack);
|
||||
g_signal_connect (x11_display->display->stack,
|
||||
"window-removed",
|
||||
G_CALLBACK (stack_window_removed_cb),
|
||||
x11_stack);
|
||||
g_signal_connect_swapped (x11_display->display->stack,
|
||||
"changed",
|
||||
G_CALLBACK (stack_changed_cb),
|
||||
x11_stack);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_stack_finalize (GObject *object)
|
||||
{
|
||||
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||
|
||||
if (x11_display->display && x11_display->display->stack)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_data (x11_display->display->stack,
|
||||
x11_stack);
|
||||
}
|
||||
|
||||
g_array_free (x11_stack->xwindows, TRUE);
|
||||
g_list_free (x11_stack->added);
|
||||
g_list_free (x11_stack->removed);
|
||||
|
||||
G_OBJECT_CLASS (meta_x11_stack_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_stack_class_init (MetaX11StackClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = meta_x11_stack_set_property;
|
||||
object_class->get_property = meta_x11_stack_get_property;
|
||||
object_class->constructed = meta_x11_stack_constructed;
|
||||
object_class->finalize = meta_x11_stack_finalize;
|
||||
|
||||
pspecs[PROP_DISPLAY] =
|
||||
g_param_spec_object ("display",
|
||||
"Display",
|
||||
"Display",
|
||||
META_TYPE_X11_DISPLAY,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, pspecs);
|
||||
}
|
||||
|
||||
MetaX11Stack *
|
||||
meta_x11_stack_new (MetaX11Display *x11_display)
|
||||
{
|
||||
return g_object_new (META_TYPE_X11_STACK,
|
||||
"display", x11_display,
|
||||
NULL);
|
||||
}
|
@@ -794,10 +794,10 @@ meta_window_x11_focus (MetaWindow *window,
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing frame of %s\n", window->desc);
|
||||
meta_x11_display_set_input_focus_window (window->display->x11_display,
|
||||
window,
|
||||
TRUE,
|
||||
timestamp);
|
||||
meta_display_set_input_focus (window->display,
|
||||
window,
|
||||
TRUE,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -806,10 +806,10 @@ meta_window_x11_focus (MetaWindow *window,
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Setting input focus on %s since input = true\n",
|
||||
window->desc);
|
||||
meta_x11_display_set_input_focus_window (window->display->x11_display,
|
||||
window,
|
||||
FALSE,
|
||||
timestamp);
|
||||
meta_display_set_input_focus (window->display,
|
||||
window,
|
||||
FALSE,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
if (priv->wm_take_focus)
|
||||
@@ -832,8 +832,7 @@ meta_window_x11_focus (MetaWindow *window,
|
||||
*/
|
||||
if (window->display->focus_window != NULL &&
|
||||
window->display->focus_window->unmanaging)
|
||||
meta_x11_display_focus_the_no_focus_window (window->display->x11_display,
|
||||
timestamp);
|
||||
meta_display_unset_input_focus (window->display, timestamp);
|
||||
}
|
||||
|
||||
request_take_focus (window, timestamp);
|
||||
@@ -1706,6 +1705,27 @@ meta_window_x11_are_updates_frozen (MetaWindow *window)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_map (MetaWindow *window)
|
||||
{
|
||||
MetaX11Display *x11_display = window->display->x11_display;
|
||||
|
||||
meta_x11_error_trap_push (x11_display);
|
||||
XMapWindow (x11_display->xdisplay, window->xwindow);
|
||||
meta_x11_error_trap_pop (x11_display);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_unmap (MetaWindow *window)
|
||||
{
|
||||
MetaX11Display *x11_display = window->display->x11_display;
|
||||
|
||||
meta_x11_error_trap_push (x11_display);
|
||||
XUnmapWindow (x11_display->xdisplay, window->xwindow);
|
||||
meta_x11_error_trap_pop (x11_display);
|
||||
window->unmaps_pending ++;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_class_init (MetaWindowX11Class *klass)
|
||||
{
|
||||
@@ -1733,6 +1753,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
|
||||
window_class->is_stackable = meta_window_x11_is_stackable;
|
||||
window_class->can_ping = meta_window_x11_can_ping;
|
||||
window_class->are_updates_frozen = meta_window_x11_are_updates_frozen;
|
||||
window_class->map = meta_window_x11_map;
|
||||
window_class->unmap = meta_window_x11_unmap;
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user