Compare commits

..

42 Commits

Author SHA1 Message Date
Carlos Garnacho
f82a0a70c0 backends: Map left-handed in tablet "touchpads" together with the tablet
Avoid those devices when applying the configuration to touchpads, and ensure
the devices grouped with the tablet are all synchronized wrt the left handed
setting.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/562
2019-06-07 12:41:45 +02:00
Olivier Fourdan
a3b86447f7 backends: Add mouse accessibility settings
Add support for mouse accessibility settings to set the click assist
values.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
1d76eace1e clutter: Hook up pointer accessibility
When using evdev (for Wayland), the backend receives all device events
and queue them for clutter.

Hook up the pointer accessibility handlers in clutter's main processing
queue, so that we get better accuracy for pointer location.

We need to avoid doing this on X11 though because X11 relies on the raw
events for this to work reliably, so the same is already done in the
X11 backend when using X11.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
c1303bd642 clutter/x11: Hook up pointer accessibility
Pointer accessibility features requires to receive all pointer events
regardless of X11 grabs.

Add XI2 raw events mask and hook up the pointer accessibility handlers
to the raw motion and button press/release events.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
db11a37a68 clutter: Add pointer accessibility features
Add support for click assist, namely simulated secondary click (on a
long primary button press) and hover click support (simulate a click when
the pointer remains static for some time).

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
0d0b9da6f8 clutter: Add pointer accessibility signals
Add the required signaling in place in clutter device manager to notify
the upper layers (namely, the shell) whenever a click assist delay or
gesture is started or stopped.

This will allow the shell to implement a visual feedback for click
assist operations.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
ab0b407da4 clutter/enums: Add pointer accessibility types
Add the relevant enumeration types to support pointer accessibility
features.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
c33b330799 backends: Rename keyboard accessibility settings
Naming the keyboard accessibility settings `a11y_settings` wrongly
assumes there will never be any other type of accessibility settings.

Rename `a11y_settings` to `keyboard_a11y_settings` to avoid future
confusion.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
144b24bfcc clutter/evdev: Use the accessibility virtual device
Instead of adding one specifically for keyboard accessibility in evdev,
use the one from ClutterInputDevice instead.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Olivier Fourdan
4d21650d6d clutter: Add an accessibility virtual device
For accessibility features, being either keyboard accessibility to
implement mousekeys, or pointer accessibility to implement simulated
secondary click or dwell click, we need to have a virtual device.

Add that virtual device in ClutterInputDevice so it can be used either
for keyboard or pointer accessibility.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/512
2019-06-06 13:04:50 +02:00
Marco Trevisan (Treviño)
a6fc656e91 window: Emit an error and return when trying to activate an unmanaged
If something (i.e. gnome-shell or an extension) tries to activate an unmanaged
window, we should warn about this and avoid to perform further actions as this
could lead to a crash of mutter, since the window has not valid flags (like
workspace) set anymore at this stage.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/580

https://gitlab.gnome.org/GNOME/mutter/merge_requests/564
2019-06-05 17:53:12 +00:00
Douglas R. Reno
a38bae259e docs: Update tests instructions
The documentation still refers to autotools, update it to
use the corresponding meson commands.

https://gitlab.gnome.org/GNOME/mutter/issues/568
2019-06-05 14:49:35 -03:00
Olivier Fourdan
c53aa89098 keybindings: Small code cleanup
Reuse the name we just set to insert in the hash table, that avoids
duplicating the string.

Suggested-by: Carlos Garnacho <carlosg@gnome.org>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/453
2019-06-05 09:34:39 +00:00
Olivier Fourdan
851b7d0639 keybindings: Trigger locate-pointer on key modifier
We trigger the "locate-pointer" mechanism when a special key modifier
(defaults to Control_L) key is pressed and released.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/453
https://gitlab.gnome.org/GNOME/gnome-shell/issues/981
https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/merge_requests/19
https://gitlab.gnome.org/GNOME/gnome-settings-daemon/merge_requests/86
2019-06-05 09:34:39 +00:00
Olivier Fourdan
b4c78726cf compositor: Add "locate_pointer" vmethod
This method is invoked to locate the pointer on screen.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/453
https://gitlab.gnome.org/GNOME/gnome-shell/issues/981
https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/merge_requests/19
https://gitlab.gnome.org/GNOME/gnome-settings-daemon/merge_requests/86
2019-06-05 09:34:39 +00:00
Olivier Fourdan
c9cc07fd3a settings: Slack off “xwayland-allow-grabs” setting
To emulate X11 grabs, mutter as a Wayland compositor would disable its
own keyboard shortcuts and when the X11 window is an override redirect
window (which never receives focus), it also forces keyboard focus onto
that X11 O-R window so that all keyboard events are routed to the
window, just like an X11 server would.

But that's a bit of a “all-or-nothing” approach which prevents
applications that would legitimately grab the keyboard under X11 (like
virtual machine viewers) to work by default.

Change “xwayland-allow-grabs” to control whether the keyboard focus
should be locked onto override redirect windows in case of an X11 grab.

For stringent needs, careful users can still use the blacklisting
feature (i.e. a list containing “!*”) to prevent grabs from any X11
applications to affect other Wayland native applications.

https://gitlab.gnome.org/GNOME/mutter/issues/597
2019-06-03 09:34:31 +02:00
Olivier Fourdan
f6eb2a8cf8 settings: Remove space characters
Small code style cleanup.

https://gitlab.gnome.org/GNOME/mutter/issues/597
2019-06-03 09:34:31 +02:00
Balázs Úr
08e5589836 Update Hungarian translation 2019-06-01 15:48:01 +00:00
Piotr Drąg
4f5a5e84fc Update POTFILES.in 2019-05-31 20:47:46 +02:00
Robert Mader
0786683189 meson: Add no-omit-frame-pointer to clutter debug builds
This will help us getting better stacktraces and sysprof integration.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/601
2019-05-31 16:03:43 +00:00
Robert Mader
4887de533c meson: Do not use clutter_c_args for GIR
Certain arguments like `-fno-omit-frame-pointer` break GIR creation.
Lets handle this like we do for the rest of mutter and duplicate the
relevant arguments from `clutter_c_args`.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/601
2019-05-31 16:03:43 +00:00
Georges Basile Stavracas Neto
57945a730f backend: Conditionally compile MetaProfiler
MetaProfiler is not built when -Dprofiler=false, and that
breaks the build since MetaBackend unconditionally imports
and uses it.

Fix that by wrapping MetaProfiler in compile-time checks.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/603
2019-05-31 12:54:13 -03:00
Georges Basile Stavracas Neto
78254146f3 build: Rename HAVE_TRACING to HAVE_PROFILER in Mutter
It fits better the name of the build flag. Cogl still uses
HAVE_TRACING since profiler is already used by it.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/603
2019-05-31 12:54:10 -03:00
Georges Basile Stavracas Neto
3e2a2cf532 clutter/stage-cogl: Simplify redraw function
Spotted while adding tracing to swap buffers, we only enter
the first part of the if condition when use_clipped_redraw
is TRUE, so it's pretty safe to assume it's TRUE.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:09 -03:00
Georges Basile Stavracas Neto
04b240b50c ci: Add sysprof3 to the Docker image
It is now a dependency that we want to build against,
even if optional.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:09 -03:00
Georges Basile Stavracas Neto
7810f0e276 cogl/trace: Add user-visible group name
This way, it shows up as "Compositor" in Sysprof instead of
"t:XYZ".

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:09 -03:00
Georges Basile Stavracas Neto
9b8f9b65b8 clutter: Add more descriptive profiling sections
The idea here is to be able to visualize and immediately
understand what is happening. Something like:

```
                   [ view1 ] [ view2 ]
 [---- Layout ---][------ Paint ------][ Pick ]
[================== Update =====================]
```

But with colors. A few of the previous profiling data
sections were removed, since they didn't really add to
reading the graph.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:08 -03:00
Georges Basile Stavracas Neto
e741cab3f4 profiler: Support setting output filename
So we can have some control over where the file will
be saved.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:08 -03:00
Georges Basile Stavracas Neto
53748e3da7 cogl-trace: Cleanup context after disabling
This allows running the Capture() method multiple times,
with different arguments each time.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:07 -03:00
Georges Basile Stavracas Neto
17c5436f6e profile: Add a Sysprof-based profiler
This exposes the /org/gnome/Sysprof3/Profiler object
inside Mutter to allow initiating a Sysprof capture.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:07 -03:00
Jonas Ådahl
04fb6f7659 clutter: Add some preliminary tracing to clutter
https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:57:07 -03:00
Jonas Ådahl
e5e58f8075 cogl: Add libsysprof capture based tracing
Add the ability to add tracing instrumentation to the code. When
enabled, trace entries will generate a file with timing information
that will be processable by sysprof for generating visualization of
traces over time.

While enabled by default at compile time, it is possible to disable the
expansion of the macros completely by passing --disable-tracing to
./configure.

Tracing is so far only actually done if actually enabled on explicitly
specified threads.

This will be used by Mutter passing the write end of a pipe, where the
read end is sent to Sysprof itself via the D-Bus method 'Capture()'.

By passing that, we have to detect EPIPE that is sent when Sysprof stops
recording. Fortunately, we already ignore the signal at meta_init(), so
no need to add a custom signal handler.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/197
2019-05-31 11:55:56 -03:00
Carlos Garnacho
1da0355528 wayland: Update tablet cursor outputs across cursor/proximity changes
Make sure those generic surface events are sent early on when setting a
cursor for any tablet tool, so clients can update to output characteristics.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/545
Related: https://gitlab.gnome.org/GNOME/gtk/issues/1675
2019-05-31 09:57:24 +00:00
Carlos Garnacho
e5881156f6 wayland: Handle NULL cursor renderer finding the outputs of a cursor role
Having a cursor role with a NULL renderer is valid state, and even desirable
on tablets (eg. after proximity out). In those cases it should be
interpreted as the cursor surface not being over any output.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/545
2019-05-31 09:57:24 +00:00
Marco Trevisan (Treviño)
60170cff70 compositor: Emit 'grab-op-end' signal after ungrab happened
We're currently emitting the 'grab-op-end' signal when the grab prerequisites
are met, but when display->grab_op is still set to a not-NONE value and thus
meta_display_get_grab_op() would return that in the signal callback.
And more importantly when this is emitted, devices are still grabbed.

Instead, emit this signal as soon as we've unset all the grab properties and
released the devices.

Helps with https://gitlab.gnome.org/GNOME/gnome-shell/issues/1326

https://gitlab.gnome.org/GNOME/mutter/merge_requests/596
2019-05-29 20:09:40 +00:00
Marco Trevisan (Treviño)
e2bea48073 display: Emit 'grab-op-end' signal after ungrab happened
We're currently emitting the 'grab-op-end' signal when the grab prerequisites
are met, but when display->grab_op is still set to a not-NONE value and thus
meta_display_get_grab_op() would return that in the signal callback.
And more importantly when this is emitted, devices are still grabbed.

Instead, emit this signal as soon as we've unset all the grab properties and
released the devices.

Helps with https://gitlab.gnome.org/GNOME/gnome-shell/issues/1326

https://gitlab.gnome.org/GNOME/mutter/merge_requests/596
2019-05-29 20:09:40 +00:00
Carlos Garnacho
bbfaf8204b wayland: Honor startup sequence workspace on .request_focus
We handle this in backend specific code for x11, so do the wayland
bits here. We can only honor this on applications that request focus
on a surface after a startup request, as we do need an explicit
surface to apply the workspace on (and we don't have additional clues
like WMCLASS on X11). Notably, gtk_shell1.notify_startup doesn't suffice.

Another gotcha is that the .request_focus happens when the surface is
already "mapped". Due to the way x11 and the GDK api currently work (first
reply on the startup id, then map a window, then request focus on that
window). This means the surface will ignore at this point
window->initial_workspace, so it must be actively changed.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/544
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/674
2019-05-29 16:21:15 +00:00
Carlos Garnacho
b3e19ee669 wayland: Unset DnD selection on wl_data_offer destruction
On a successful DnD operation we may expect the wl_data_source and
wl_data_offer to live long enough to finish the data transfer, despite the
grab operation (and other supporting data) being gone.

When that happens, the compositor expects a wl_data_offer.finish request to
notify that it finished. However the client may still chose not to send that
and destroy the wl_data_offer instead, resulting in the MetaSelectionSource
owner for the DnD selection not being unset.

When that happens, the DnD MetaSelectionSource still exists but it's
detached from any grab operation, so will not be unset if eg. the drag
source client destroys the wl_data_source. This may result in crashes when
the next drag operation tries to replace the owner DnD MetaSelectionSource.

Check explicitly for this case, in order to ensure the DnD owner is unset
after such operations.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/591
2019-05-29 16:10:57 +00:00
Robert Mader
75e2bfb062 meson: Do not add compiler flags if 'plain' buildtype is used
That is how the 'plain' buildtype is meant in meson.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/497
2019-05-29 15:52:39 +00:00
Robert Mader
a859d76c72 meson: Cleanup debug build handling
Add debug flags based on meson's `debug` option instead of `buildtype`.
This allows custom build configurations to behave like a debug or release build.

Add `-fno-omit-frame-pointer` to Mutter/Cogl. Not to Clutter though, as that would
require more changes to how Clutter's gir is created

Remove `-DG_DISABLE_CAST_CHECKS` from Clutter in debug builds

Add `-DG_DISABLE_CHECKS`, `-DG_DISABLE_ASSERT` and `-DG_DISABLE_CAST_CHECKS` to all
non-debug builds but `plain`, which explicitly should not have any compile flags

Use `cc.get_supported_arguments`, so it becomes more obvious to the user which flags
are set during compilation

https://gitlab.gnome.org/GNOME/mutter/merge_requests/497
2019-05-29 15:52:39 +00:00
Pekka Paalanen
2145333969 renderer/native: Refactor into secondary_gpu_get_next_dumb_buffer
Extract the next buffer -logic into a new function. This allows to
simplify copy_shared_framebuffer_cpu () making it more readable.

This change is a pure refactoring, no functional changes.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/593
2019-05-29 11:53:00 -03:00
Robert Mader
1b61b9cd73 boxes: Fix calculation of rounded rectangles
Since 68fba458 the function is used for more calculations, exposing
a bug when used with fractional scaling.

https://gitlab.gnome.org/GNOME/mutter/issues/609
2019-05-29 00:07:15 +02:00
60 changed files with 2636 additions and 364 deletions

View File

@@ -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 && \

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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__ */

View File

@@ -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

View File

@@ -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);

View 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__ */

View 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));
}

View File

@@ -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:

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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: [

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 = [

View File

@@ -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

View File

@@ -29,7 +29,6 @@
*/
#include "cogl-config.h"
#include "cogl-defines.h"
#include <string.h>
#include <math.h>
@@ -309,66 +308,3 @@ cogl_pixel_format_to_string (CoglPixelFormat format)
g_assert_not_reached ();
}
#ifdef COGL_HAS_LIBDRM
typedef struct _PixelFormatMap {
uint32_t drm_format;
CoglPixelFormat cogl_format;
CoglTextureComponents cogl_components;
} PixelFormatMap;
static const PixelFormatMap pixel_format_map[] = {
/* DRM formats are defined as little-endian, not machine endian. */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
{ DRM_FORMAT_RGB565, COGL_PIXEL_FORMAT_RGB_565, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
#elif G_BYTE_ORDER == G_BIG_ENDIAN
/* DRM_FORMAT_RGB565 cannot be expressed. */
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
#else
#error "unexpected G_BYTE_ORDER"
#endif
};
gboolean
cogl_pixel_format_from_drm_format (uint32_t drm_format,
CoglPixelFormat *out_format,
CoglTextureComponents *out_components)
{
const size_t n = G_N_ELEMENTS (pixel_format_map);
size_t i;
for (i = 0; i < n; i++)
{
if (pixel_format_map[i].drm_format == drm_format)
break;
}
if (i == n)
return FALSE;
if (out_format)
*out_format = pixel_format_map[i].cogl_format;
if (out_components)
*out_components = pixel_format_map[i].cogl_components;
return TRUE;
}
#endif

View File

@@ -38,10 +38,6 @@
#include <stdint.h>
#include <stddef.h>
#ifdef COGL_HAS_LIBDRM
#include <drm_fourcc.h>
#endif
#include <cogl/cogl-defines.h>
#include <glib.h>
@@ -62,9 +58,6 @@ G_BEGIN_DECLS
*
* Other examples of factors that can influence the layout in memory are the
* system's endianness.
*
* This file also contains methods to map Linux DRM 4CC codes to
* CoglPixelFormats.
*/
#define COGL_A_BIT (1 << 4)
@@ -302,34 +295,6 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format);
const char *
cogl_pixel_format_to_string (CoglPixelFormat format);
#ifdef COGL_HAS_LIBDRM
/* added in libdrm 2.4.95 */
#ifndef DRM_FORMAT_INVALID
#define DRM_FORMAT_INVALID 0
#endif
/**
* cogl_pixel_format_from_drm_format:
* @drm_format: The DRM 4CC code (as specified in drm_fourcc.h)
* @out_format: (optional): The corresponding #CoglPixelFormat (if successful)
* @out_components: (optional): The corresponding #CoglTextureComponents (if
* sucessful)
*
* Does an internal lookup to find a #CoglPixelFormat that matches the given
* DRM 4CC code. If no such format could be found, this function will return
* %FALSE and the output parameters will stay untouched.
*
* Returns: %TRUE if a #CoglPixelFormat corresponding to the 4CC code exists,
* %FALSE otherwise.
*/
gboolean
cogl_pixel_format_from_drm_format (uint32_t drm_format,
CoglPixelFormat *out_format,
CoglTextureComponents *out_components);
#endif
G_END_DECLS
#endif /* __COGL_PIXEL_FORMAT_H__ */

258
cogl/cogl/cogl-trace.c Normal file
View 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
View 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 */

View File

@@ -12,9 +12,6 @@ cdata.set('COGL_HAS_X11', have_x11)
cdata.set('COGL_HAS_X11_SUPPORT', have_x11)
cdata.set('COGL_HAS_XLIB', have_x11)
cdata.set('COGL_HAS_XLIB_SUPPORT', have_x11)
if have_native_backend
cdata.set('COGL_HAS_LIBDRM', libdrm_dep.found())
endif
cogl_defines_h = configure_file(
input: 'cogl-defines.h.meson',
@@ -306,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',

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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:',
'',

View File

@@ -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,

View File

@@ -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

View File

@@ -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)"

View File

@@ -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;
}

View File

@@ -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);

View 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);
}

View 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 */

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -73,6 +73,11 @@
#define EGL_DRM_MASTER_FD_EXT 0x333C
#endif
/* added in libdrm 2.4.95 */
#ifndef DRM_FORMAT_INVALID
#define DRM_FORMAT_INVALID 0
#endif
enum
{
PROP_0,
@@ -247,6 +252,11 @@ static void
free_next_secondary_bo (MetaGpuKms *gpu_kms,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state);
static gboolean
cogl_pixel_format_from_drm_format (uint32_t drm_format,
CoglPixelFormat *out_format,
CoglTextureComponents *out_components);
static MetaBackend *
backend_from_renderer_native (MetaRendererNative *renderer_native)
{
@@ -2116,6 +2126,77 @@ 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;
CoglTextureComponents cogl_components;
} PixelFormatMap;
static const PixelFormatMap pixel_format_map[] = {
/* DRM formats are defined as little-endian, not machine endian. */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
{ DRM_FORMAT_RGB565, COGL_PIXEL_FORMAT_RGB_565, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
#elif G_BYTE_ORDER == G_BIG_ENDIAN
/* DRM_FORMAT_RGB565 cannot be expressed. */
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
#else
#error "unexpected G_BYTE_ORDER"
#endif
};
static gboolean
cogl_pixel_format_from_drm_format (uint32_t drm_format,
CoglPixelFormat *out_format,
CoglTextureComponents *out_components)
{
const size_t n = G_N_ELEMENTS (pixel_format_map);
size_t i;
for (i = 0; i < n; i++)
{
if (pixel_format_map[i].drm_format == drm_format)
break;
}
if (i == n)
return FALSE;
if (out_format)
*out_format = pixel_format_map[i].cogl_format;
if (out_components)
*out_components = pixel_format_map[i].cogl_components;
return TRUE;
}
static void
copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
@@ -2123,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 */,
@@ -2175,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

View File

@@ -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 */

View File

@@ -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
@@ -1551,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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -2132,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;

View File

@@ -1837,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. */
@@ -1891,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);
}
/**

View File

@@ -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);

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -3679,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",

View File

@@ -625,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')

View File

@@ -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);
};
/**

View File

@@ -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,

View File

@@ -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
=================

View File

@@ -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);

View File

@@ -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);

View File

@@ -43,6 +43,10 @@
#include "linux-dmabuf-unstable-v1-server-protocol.h"
#ifndef DRM_FORMAT_MOD_INVALID
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
#endif
#define META_WAYLAND_DMA_BUF_MAX_FDS 4
struct _MetaWaylandDmaBufBuffer
@@ -80,15 +84,28 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
if (buffer->dma_buf.texture)
return TRUE;
/*
* NOTE: The cogl_format here is only used for texture color channel
* swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
* for accessing the buffer memory. EGL will access the buffer
* memory according to the DRM fourcc code. Cogl will not mmap
* and access the buffer memory at all.
*/
if (!cogl_pixel_format_from_drm_format (dma_buf->drm_format, &cogl_format, NULL))
switch (dma_buf->drm_format)
{
/*
* NOTE: The cogl_format here is only used for texture color channel
* swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
* for accessing the buffer memory. EGL will access the buffer
* memory according to the DRM fourcc code. Cogl will not mmap
* and access the buffer memory at all.
*/
case DRM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_RGB_888;
break;
case DRM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
break;
case DRM_FORMAT_ARGB2101010:
cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
break;
case DRM_FORMAT_RGB565:
cogl_format = COGL_PIXEL_FORMAT_RGB_565;
break;
default:
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Unsupported buffer format %d", dma_buf->drm_format);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)