Compare commits

...

67 Commits

Author SHA1 Message Date
Carlos Garnacho
410b37bc53 wayland: Update focus window during DnD motion
But don't emit crossing events, since the DnD grab is in effect.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
Carlos Garnacho
6dfdc6d6ec wayland: Add emit_crossing argument to meta_wayland_pointer_set_focus()
This is TRUE in every place it was previously called.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
Carlos Garnacho
869d12c36d wayland: Trigger the DnD failed animation if no DnD is to happen
If there is no focus window, focus data_source or target selected,
DnD will fail and show the fancy animation.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
827e0c23c5 wayland: Store whether the wl_data_source has a target selected
It will be useful to check whether DnD is going to fail or not.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
9efd96be7b wayland: Unset local DnD surface if destroyed early during DnD 2014-09-30 17:30:54 +02:00
Carlos Garnacho
102d1e62a2 wayland: Keep track of the origin surface and drag point on DnD
Keeping track of the surface will be necessary in case it is destroyed
during DnD, and the coordinates will be useful when figuring out the
snap back coordinates.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
aba81603b9 backend: Add "DnD failed" plumbing to the MetaCursorTracker 2014-09-30 17:30:54 +02:00
Carlos Garnacho
10c6056ce0 backend: Add "DnD failed" animation plumbing on MetaCursorRenderer
The MetaCursorRenderer is the object aware of the offsets applying to
the DnD surface, so translate the given coordinates by that.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
79fdbbfe1a backend: Add "DnD failed" animation
This is currently handled by the MetaStage, when DnD is hinted to be
failed, the current overlay will be copied and used on the snap back/
fade out animation, after the animation is finished, the extra overlay
will be freed.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
572727e6e8 backend: Add meta_overlay_copy()
This function will be useful to transfer an overlay so it can be
temporarily rendered differently. Will be mainly useful for DnD
animations.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
1dbc9e868f detach dnd surface and pointer 2014-09-30 17:30:54 +02:00
Carlos Garnacho
a181ea3cde surface: honor wl_surface_commit()s on the DnD surface
And update the surface when this happens.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
78477dd56a data-device: Update the DnD surface on drag grab updates 2014-09-30 17:30:54 +02:00
Carlos Garnacho
30cc4e1d0a data-device: Store the current drag grab
And bail out if any further start_drag() is attempted.
2014-09-30 17:30:54 +02:00
Carlos Garnacho
4b83b031bc cursor-tracker: Wrap cursor renderer's DnD surface setter 2014-09-30 17:30:54 +02:00
Jasper St. Pierre
40a85e0e99 cursor-renderer: Add setter for the DnD surface
The DnD surface will be always updated/redrawn when the cursor position
changes, and it will never go through backend-specific handling of hw
cursors, so the stage will always need updating when a drag is in effect.
2014-09-30 17:30:54 +02:00
Jasper St. Pierre
dfde1ff327 stage: Add overlay for the DnD surface
This will be rendered similarly to the pointer cursor.
2014-09-30 17:30:54 +02:00
Jasper St. Pierre
92b7daab61 wayland: Record the offset position
This is needed for DND surfaces. We should probably test to see if it's
used for cursor surfaces at all.
2014-09-30 17:30:54 +02:00
Owen W. Taylor
b735571688 MetaBackgroundImage: free the GdkPixbuf after creating a texture
The GdkPixbuf used to load a texture was never freed.
2014-09-29 21:32:48 -04:00
Jasper St. Pierre
5e249ad5eb prefs: Don't leak the variant value for unknown properties 2014-09-29 17:54:20 -06:00
Jasper St. Pierre
21bffe4aef monitor-manager-xrandr: Fix small leak for invalid properties
If the property is invalid, then we leak the allocated buffer. Make sure
to free it in this case.
2014-09-29 17:54:20 -06:00
Florian Müllner
68283df4d9 workspace: Don't relocate sticky windows
Windows are relocated before their workspace is removed, however this
is only necessary for windows that are *only* on that workspace; for
windows on all workspaces, that step is annoying as it will unset the
sticky state requested by the user.

https://bugzilla.gnome.org/show_bug.cgi?id=737625
2014-09-30 00:41:25 +02:00
Florian Müllner
4f3de2ce39 workspace: Correctly initialize MRU list
The workspace MRU lists are updated when windows are managed/unmanaged
or change workspaces. However those updates obviously only apply to
existing workspaces - new workspaces will always start out with an empty
MRU list, despite sticky windows already being "on" that workspace.
As we now assert that the list contains all windows located on the
workspace, we need to initialize it correctly to avoid a crash.

https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
Florian Müllner
9f8b641472 display: Optionally sort window list
https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
Rico Tzschichholz
a9a21c801c configure: Require gbm >= 10.3
Needed for 488dd0b402
2014-09-29 23:13:59 +02:00
Florian Müllner
482a97466d window: Fix typo 2014-09-27 07:41:10 +02:00
Florian Müllner
4e14bb9df3 window: Fix corner case in set_demands_attention()
We only grant requests to set the demands-attention hint if the window
is at least partially obscured; so for non-minimized windows on the
active workspace, we check if any other window on the same workspace
that is higher in the stack overlaps.
However in the case of a sticky window, window->workspace is NULL, so
we end up considering any non-sticky window on a different workspace.

At this point we have already established that the window is showing
on the active workspace, so use that to filter for windows that may
overlap.
2014-09-27 06:43:16 +02:00
Florian Müllner
df90545258 window: Fix crash when mapping sticky window
Since the introduction of set_workspace_state(), window->workspace
will always be NULL when on_all_workspaces is set - passing that
to a workspace function that does not validate its input will then
result in a crash.
Use the get_workspace() function instead, which will always return
a valid workspace.
2014-09-27 06:41:35 +02:00
Florian Müllner
c954f9cc24 workspace: Fix typo in META_IS_WORKSPACE macro 2014-09-27 06:37:38 +02:00
Florian Müllner
d06b39d13c window: Fix another case of uninitialized workspace state
Since commit 2eec11b445, windows without a __NET_WM_DESKTOP property
that should be on all workspaces are not added to the active workspace;
this is correct, however not adding them to any workspace is not ...
2014-09-26 11:48:11 +01:00
Jasper St. Pierre
f3595ebd08 monitor-manager: Make sure to emit PropertiesChanged for PowerSaveMode
We overrode the property for PowerSaveMode, which meant that gdbus's
auto-generated PropertiesChanged code wasn't being run.

This really confused gnome-rr and gnome-settings-daemon's power plugin
about the current DPMS state of the display, since they used their
cached PowerSaveMode properties, and never saw a PropertiesChanged being
emitted.

If a display was on, they set it to off, and then set it back on, the
setting back on would never fire, since they thought the display was
already off.

To fix this, remove our custom property override and just respond to
notifications on the object.

Namely, this fixes the DPMS management when receiving notifications so
that it now properly times out.
2014-09-25 20:17:53 -06:00
Florian Müllner
1e1ca47ec1 window: Always set workspace state while constructing
set_workspace_state () returns early when the desired sticky state
and workspace match the current property values, assuming that the
corresponding MRU lists are already correct in that case.
However that might not be the case when we are setting the initial
state, so don't take the shortcut in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
Florian Müllner
2eec11b445 window: Be more careful when setting initial workspace state
A window may either be sticky because it has been requested as such,
or because it is placed on a non-primary monitor (and the corresponding
preference is set). While we do take the latter into account, we
currently override the sticky state later during initialization;
be a bit more careful there to get the initial state right.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
Saibal Ray
8ff4597201 Updated Bengali (India) translation 2014-09-25 08:26:38 +00:00
Alexander Shopov
d5f2468d88 Updated Bulgarian translation 2014-09-25 06:28:04 +03:00
Jasper St. Pierre
488dd0b402 Support for hardware cursor sizes other than 64x64 on wayland
Use the new DRM capabilities to figure out the correct cursor size, and
make sure that matches instead of hardcoding 64x64. This fixes incorrect
rendering on some newer AMD cards that support 256x256 cursors.

Based heavily on a patch by:
Alvaro Fernando García <alvarofernandogarcia@gmail.com>
2014-09-24 15:42:17 -06:00
Jasper St. Pierre
6565bca210 wayland: Send accurate capabilities
mutter now knows whether the app menu should be shown, so expose this
properly under Wayland as well.
2014-09-24 15:42:17 -06:00
Rui Matos
60c22b6236 keybindings: Do a breadth first search in our keysym to keycode code
Commit 1af0033368 made a subtle change
regarding how XKeysymToKeycode behaves. It does a depth first search
while XKeysymToKeycode is documented to do a breadth first search:

"this function looks in each column of the core keyboard mapping in
turn and returns the lowest numbered key that matches in the lowest
numbered group" - from the XKB library documentation

Looping over all keycodes for each layout and level index makes us go
back to the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=737134
2014-09-24 23:20:42 +02:00
Owen W. Taylor
d3111a9f07 Fix stacking of the guard window
With the change to how hidden windows are stacked, the position
of the guard window with respect to the hidden windows got flipped
and the guard window was at the bottom of everything; fix it to
be on top of the hidden windows.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
Owen W. Taylor
cdfb301200 Add a test for stacking vs. minimization
Test that the guard window is in the right place.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
Owen W. Taylor
371560c2b6 tests: Add minimize/unminimize commands
Add commands to request the client to minimize or unminimize the window;
unminimize doesn't currently work for GTK+ because it expects XMapRequest
to be received by the window manager, but the window is already mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Owen W. Taylor
7616881afa test-runner: represent the guard window as '|' for assert_stacking
Allow putting '|' into the list of windows for assert_stacking to
represent the position of the guard window. Not present is the same
as at the beginning (bottom) of the list.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Owen W. Taylor
74c37d49c4 test-runner: make test_case_wait() wait for queued-work
Sometimes (for example with minimization) a request from the client
causes queued work rather than immediate work; so make the test client
'wait' command wait for a full frame cycle.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
Мирослав Николић
d3142b92f0 Updated Serbian translation 2014-09-24 11:10:30 +02:00
Krishnababu Krothapalli
ae2afa7c5e Updated Telugu translation 2014-09-23 14:48:16 +00:00
Florian Müllner
4a71621fbc keybindings: Fix indentation 2014-09-22 22:01:37 +02:00
Florian Müllner
565b9d73d5 keybindings: Do not depend on linux headers for above-tab key
Commit 2f229c3928 removed the code to compute the above-tab
keycode and replaced it with a simple constant from linux/input.h.
We obviously cannot depend on linux headers on non-linux systems,
so provide a fallback definition in that case (which is expected
to work assuming the system is using the Xorg xf86-input-keyboard
driver).

https://bugzilla.gnome.org/show_bug.cgi?id=737135
2014-09-22 21:54:48 +02:00
Florian Müllner
90bd02ff4d constraints: Fix update_onscreen_requirements()
Another missing translation into screen coordinates ...

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
Florian Müllner
73ca0efaeb window: Fix titlebar_is_onscreen() test
The titlebar rect is in window coordinates, while screen regions are
obviously not. Fix by translating into screen coordinates before
testing for overlaps.

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
Florian Müllner
790269db95 Bump version to 3.14.0
Update NEWS.
2014-09-22 20:12:08 +02:00
Rajesh Ranjan
cb82bd8afa Updated Hindi translation 2014-09-22 13:23:07 +00:00
Petr Kovar
b1e06ed110 Update Czech translation 2014-09-22 15:02:04 +02:00
Shankar Prasad
fabe66e65f Updated Kannada translation 2014-09-22 05:14:51 +00:00
Bernd Homuth
4a965a37d1 Updated German translation 2014-09-21 19:20:16 +00:00
YunQiang Su
302ff7b95a update zh_CN translation 2014-09-21 10:15:01 +08:00
Ask H. Larsen
e2e241340c Updated Danish translation 2014-09-20 17:22:51 +02:00
Jasper St. Pierre
461aea47dd window: Adjust the frame rect when _GTK_FRAME_EXTENTS is set on map 2014-09-19 17:35:38 -06:00
Jasper St. Pierre
d87093fe29 window: Don't queue move/resizes if the extents are the same
GTK+ sets the frame extents on every allocation, so don't bother doing
any extra work if things are the same.
2014-09-19 17:35:38 -06:00
Jasper St. Pierre
0cde7879d6 window: Move set_custom_frame_extents to be X11-only
Wayland doesn't use custom frame extents anymore -- it uses a full
geometry description.
2014-09-19 17:35:38 -06:00
Owen W. Taylor
89ffcee7ca Fix computation of window positions for StaticGravity
When adjust_for_gravity() was simplified (01b6445708), the correct
handling of StaticGravity dropped out - fix adjust_for_gravity() to do
nothing in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=736719
2014-09-19 15:41:22 -04:00
Owen W. Taylor
1250afef7b Revert "window-x11: Fix the coordinates we use in the synthetic ConfigureNotify"
The coordinates in ConfigureNotify *should* be the coordinates of the
client window; using the coordinates of the frame window compensated for
a problem with the interpretation of StaticGravity for some clients but
broke other clients.

This reverts commit f4f70afe31.

https://bugzilla.gnome.org/show_bug.cgi?id=736719
2014-09-19 15:41:22 -04:00
Christian Kirbach
3a577edaa7 Updated German translation 2014-09-18 21:55:42 +00:00
Jasper St. Pierre
48dfde2073 keyboard/pointer: Calculate the serial once per event
Some applications, like totem, create keyboard/pointer objects from the
same client, and expect it to work. We made this work a while ago, but
due to an oversight in the code, we increment the serial on button press
for every resource that we need to send events to.

Since operations like move/resize use the grab serial of the devices to
determine whether the operation is exact, we need to make sure the same
serial goes to all devices.

Restructure the code so that all that's in the resource loop is the
sending of the event -- all the calculation that's needed happens
outside.

This fixes moving / resizing the Totem window not working sometimes.

https://bugzilla.gnome.org/show_bug.cgi?id=736840
2014-09-18 09:15:13 -06:00
Jasper St. Pierre
4a41d415f8 wayland: Fix the placement of popup windows
The fix in d61dde1 regressed the position of popup windows, since the
size was 0x0 when we wanted to do a sole move. Only fizzle out in the
path where we actually *do* resize.

https://bugzilla.gnome.org/show_bug.cgi?id=736812
2014-09-17 17:42:37 +02:00
Manoj Kumar Giri
1fb7ca398d Updated Oriya translation 2014-09-17 11:27:43 +00:00
Dušan Kazik
2b79935fd8 Updated Slovak translation 2014-09-17 09:10:51 +00:00
Saibal Ray
e3c915350e Updated Bengali (India) translation 2014-09-17 06:30:41 +00:00
54 changed files with 9995 additions and 11534 deletions

14
NEWS
View File

@@ -1,3 +1,17 @@
3.14.0
======
* Fix placement of popup windows on wayland [Jasper; #736812]
* Only increment serial once per event [Jasper; #736840]
* Fix window positioning regression with non-GTK+ toolkits [Owen; #736719]
Contributors:
Jasper St. Pierre, Owen W. Taylor
Translations:
Saibal Ray [bn_IN], Dušan Kazik [sk], Manoj Kumar Giri [or],
Christian Kirbach [de], Ask H. Larsen [da], YunQiang Su [zh_CN],
Bernd Homuth [de], Shankar Prasad [kn], Petr Kovar [cs], Rajesh Ranjan [hi]
3.13.92
=======
* Rewrite background code [Owen; #735637, #736568]

View File

@@ -1,8 +1,8 @@
AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [13])
m4_define([mutter_micro_version], [92])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [0])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -79,7 +79,7 @@ MUTTER_PC_MODULES="
$CLUTTER_PACKAGE >= 1.19.5
clutter-egl-1.0
cogl-1.0 >= 1.17.1
gbm
gbm >= 10.3
upower-glib >= 0.99.0
gnome-desktop-3.0
xcomposite >= 0.2

1503
po/bg.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1284
po/cs.po

File diff suppressed because it is too large Load Diff

1298
po/da.po

File diff suppressed because it is too large Load Diff

1530
po/de.po

File diff suppressed because it is too large Load Diff

1942
po/hi.po

File diff suppressed because it is too large Load Diff

1966
po/kn.po

File diff suppressed because it is too large Load Diff

1800
po/or.po

File diff suppressed because it is too large Load Diff

502
po/sk.po

File diff suppressed because it is too large Load Diff

1300
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1865
po/te.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ stackingdir = $(pkgdatadir)/tests/stacking
dist_stacking_DATA = \
tests/stacking/basic-x11.metatest \
tests/stacking/basic-wayland.metatest \
tests/stacking/minimized.metatest \
tests/stacking/mixed-windows.metatest \
tests/stacking/override-redirect.metatest

View File

@@ -35,13 +35,21 @@
#include "meta-stage.h"
typedef struct
{
CoglTexture *texture;
MetaRectangle current_rect;
int current_x, current_y;
} MetaCursorLayer;
struct _MetaCursorRendererPrivate
{
int current_x, current_y;
MetaRectangle current_rect;
MetaCursorLayer core_layer;
MetaCursorLayer dnd_layer;
MetaCursorReference *displayed_cursor;
gboolean handled_by_backend;
int dnd_surface_offset_x, dnd_surface_offset_y;
gboolean cursor_handled_by_backend;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@@ -59,12 +67,19 @@ queue_redraw (MetaCursorRenderer *renderer)
if (!stage)
return;
if (priv->displayed_cursor && !priv->handled_by_backend)
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, NULL, NULL);
/* Pointer cursor */
if (!priv->cursor_handled_by_backend)
texture = priv->core_layer.texture;
else
texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
meta_stage_set_cursor (META_STAGE (stage), texture,
&priv->core_layer.current_rect);
/* DnD surface */
meta_stage_set_dnd_surface (META_STAGE (stage),
priv->dnd_layer.texture,
&priv->dnd_layer.current_rect);
}
static gboolean
@@ -85,46 +100,76 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
}
static void
update_cursor (MetaCursorRenderer *renderer)
update_layer (MetaCursorRenderer *renderer,
MetaCursorLayer *layer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend;
gboolean should_redraw = FALSE;
layer->texture = texture;
if (priv->displayed_cursor)
if (layer->texture)
{
CoglTexture *texture;
int hot_x, hot_y;
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, &hot_x, &hot_y);
priv->current_rect.x = priv->current_x - hot_x;
priv->current_rect.y = priv->current_y - hot_y;
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
layer->current_rect.x = layer->current_x + offset_x;
layer->current_rect.y = layer->current_y + offset_y;
layer->current_rect.width = cogl_texture_get_width (layer->texture);
layer->current_rect.height = cogl_texture_get_height (layer->texture);
}
else
{
priv->current_rect.x = 0;
priv->current_rect.y = 0;
priv->current_rect.width = 0;
priv->current_rect.height = 0;
layer->current_rect.x = 0;
layer->current_rect.y = 0;
layer->current_rect.width = 0;
layer->current_rect.height = 0;
}
}
static void
emit_update_cursor (MetaCursorRenderer *renderer,
gboolean force)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend, should_redraw = FALSE;
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
if (handled_by_backend != priv->handled_by_backend)
if (handled_by_backend != priv->cursor_handled_by_backend)
{
priv->handled_by_backend = handled_by_backend;
priv->cursor_handled_by_backend = handled_by_backend;
should_redraw = TRUE;
}
if (!handled_by_backend)
if (force || !handled_by_backend || priv->dnd_layer.texture)
should_redraw = TRUE;
if (should_redraw)
queue_redraw (renderer);
}
static void
update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
CoglTexture *texture;
int hot_x, hot_y;
/* Cursor layer */
if (priv->displayed_cursor)
{
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor,
&hot_x, &hot_y);
}
else
{
texture = NULL;
hot_x = 0;
hot_y = 0;
}
update_layer (renderer, &priv->core_layer, texture, -hot_x, -hot_y);
emit_update_cursor (renderer, FALSE);
}
MetaCursorRenderer *
meta_cursor_renderer_new (void)
{
@@ -144,6 +189,23 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_surface_offset_x = offset_x;
priv->dnd_surface_offset_y = offset_y;
update_layer (renderer, &priv->dnd_layer, texture, offset_x, offset_y);
emit_update_cursor (renderer, TRUE);
}
void
meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
int x, int y)
@@ -152,12 +214,46 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
g_assert (meta_is_wayland_compositor ());
priv->current_x = x;
priv->current_y = y;
priv->core_layer.current_x = x;
priv->core_layer.current_y = y;
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x,
int y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_layer.current_x = x;
priv->dnd_layer.current_y = y;
update_layer (renderer, &priv->dnd_layer, priv->dnd_layer.texture,
priv->dnd_surface_offset_x, priv->dnd_surface_offset_y);
emit_update_cursor (renderer, FALSE);
}
void
meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x,
int dest_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
g_assert (meta_is_wayland_compositor ());
if (priv->dnd_layer.texture)
meta_stage_dnd_failed (META_STAGE (stage),
dest_x + priv->dnd_surface_offset_x,
dest_y + priv->dnd_surface_offset_y);
}
MetaCursorReference *
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
{
@@ -171,5 +267,5 @@ meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return &priv->current_rect;
return &priv->core_layer.current_rect;
}

View File

@@ -67,4 +67,14 @@ void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
MetaCursorReference * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
void meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x, int y);
void meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x, int dest_y);
#endif /* META_CURSOR_RENDERER_H */

View File

@@ -62,10 +62,20 @@ void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y);
MetaCursorReference * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);

View File

@@ -358,6 +358,28 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
sync_cursor (tracker);
}
void
meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface (tracker->renderer, texture,
offset_x, offset_y);
}
void
meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_dnd_failed (tracker->renderer, dest_x, dest_y);
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
@@ -368,6 +390,17 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
meta_cursor_renderer_set_position (tracker->renderer, new_x, new_y);
}
void
meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface_position (tracker->renderer,
new_x, new_y);
}
static void
get_pointer_position_gdk (int *x,
int *y,

View File

@@ -139,35 +139,56 @@ load_cursor_on_client (MetaCursor cursor)
meta_prefs_get_cursor_size ());
}
static void
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
{
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
return;
}
#endif
g_assert_not_reached ();
}
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
uint8_t *pixels,
int width,
int height,
uint width,
uint height,
int rowstride,
uint32_t gbm_format)
{
if (width > 64 || height > 64)
uint64_t cursor_width, cursor_height;
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width > cursor_width || height > cursor_height)
{
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
(unsigned int)cursor_width, (unsigned int)cursor_height);
return;
}
if (gbm_device_is_format_supported (gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
uint8_t buf[4 * 64 * 64];
int i;
uint8_t buf[4 * cursor_width * cursor_height];
uint i;
image->bo = gbm_bo_create (gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
image->bo = gbm_bo_create (gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4);
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
gbm_bo_write (image->bo, buf, 64 * 64 * 4);
gbm_bo_write (image->bo, buf, cursor_width * cursor_height * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
@@ -191,7 +212,7 @@ static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
{
int width, height, rowstride;
uint width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
@@ -262,7 +283,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
CoglContext *cogl_context;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
int width, height;
uint64_t cursor_width, cursor_height;
uint width, height;
image->hot_x = hot_x;
image->hot_y = hot_y;
@@ -313,22 +335,23 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
}
else
{
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
if (gbm)
{
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
size, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width != cursor_width || height != cursor_height)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, buffer, GBM_BO_USE_CURSOR);
if (!image->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}

View File

@@ -44,12 +44,6 @@ enum {
SIGNALS_LAST
};
enum {
PROP_0,
PROP_POWER_SAVE_MODE,
PROP_LAST
};
static int signals[SIGNALS_LAST];
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
@@ -167,11 +161,39 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
}
static void
power_save_mode_changed (MetaMonitorManager *manager,
GParamSpec *pspec,
gpointer user_data)
{
MetaMonitorManagerClass *klass;
int mode = meta_dbus_display_config_get_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager));
if (mode == META_POWER_SAVE_UNSUPPORTED)
return;
/* If DPMS is unsupported, force the property back. */
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
{
meta_dbus_display_config_set_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager), META_POWER_SAVE_UNSUPPORTED);
return;
}
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
static void
meta_monitor_manager_constructed (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
g_signal_connect_object (manager, "notify::power-save-mode",
G_CALLBACK (power_save_mode_changed), manager, 0);
manager->in_init = TRUE;
manager->config = meta_monitor_config_new ();
@@ -214,23 +236,6 @@ meta_monitor_manager_constructed (GObject *object)
manager->in_init = FALSE;
}
static void
meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
MetaPowerSave mode)
{
MetaMonitorManagerClass *klass;
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED ||
mode == META_POWER_SAVE_UNSUPPORTED)
return;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
@@ -298,44 +303,6 @@ meta_monitor_manager_dispose (GObject *object)
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
}
static void
meta_monitor_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
meta_monitor_manager_set_power_save_mode (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_monitor_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
g_value_set_int (value, self->power_save_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GBytes *
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
MetaOutput *output)
@@ -356,8 +323,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = meta_monitor_manager_constructed;
object_class->get_property = meta_monitor_manager_get_property;
object_class->set_property = meta_monitor_manager_set_property;
object_class->dispose = meta_monitor_manager_dispose;
object_class->finalize = meta_monitor_manager_finalize;
@@ -371,8 +336,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_object_class_override_property (object_class, PROP_POWER_SAVE_MODE, "power-save-mode");
}
static const double known_diagonals[] = {

View File

@@ -28,6 +28,8 @@
#include <meta/meta-backend.h>
#include <meta/util.h>
#define DRAG_FAILED_MSECS 500
typedef struct {
gboolean enabled;
@@ -39,8 +41,20 @@ typedef struct {
gboolean previous_is_valid;
} MetaOverlay;
typedef struct {
MetaStage *stage;
MetaOverlay overlay;
ClutterTimeline *timeline;
int orig_x;
int orig_y;
int dest_x;
int dest_y;
} MetaDragFailedAnimation;
struct _MetaStagePrivate {
MetaOverlay dnd_overlay;
MetaOverlay cursor_overlay;
GList *drag_failed_animations;
};
typedef struct _MetaStagePrivate MetaStagePrivate;
@@ -54,6 +68,15 @@ meta_overlay_init (MetaOverlay *overlay)
overlay->pipeline = cogl_pipeline_new (ctx);
}
static void
meta_overlay_copy (MetaOverlay *src,
MetaOverlay *dst)
{
*dst = *src;
dst->pipeline = cogl_pipeline_copy (src->pipeline);
dst->texture = src->texture;
}
static void
meta_overlay_free (MetaOverlay *overlay)
{
@@ -112,6 +135,7 @@ meta_stage_finalize (GObject *object)
MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_free (&priv->dnd_overlay);
meta_overlay_free (&priv->cursor_overlay);
}
@@ -120,9 +144,18 @@ meta_stage_paint (ClutterActor *actor)
{
MetaStage *stage = META_STAGE (actor);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *animation;
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
for (l = priv->drag_failed_animations; l; l = l->next)
{
animation = l->data;
meta_overlay_paint (&animation->overlay);
}
meta_overlay_paint (&priv->dnd_overlay);
meta_overlay_paint (&priv->cursor_overlay);
}
@@ -142,6 +175,7 @@ meta_stage_init (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_init (&priv->dnd_overlay);
meta_overlay_init (&priv->cursor_overlay);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
@@ -183,6 +217,19 @@ queue_redraw_for_overlay (MetaStage *stage,
}
}
void
meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
g_assert (meta_is_wayland_compositor ());
meta_overlay_set (&priv->dnd_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->dnd_overlay);
}
void
meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
@@ -195,3 +242,84 @@ meta_stage_set_cursor (MetaStage *stage,
meta_overlay_set (&priv->cursor_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->cursor_overlay);
}
static void
drag_failed_animation_frame_cb (ClutterTimeline *timeline,
guint pos,
gpointer user_data)
{
MetaDragFailedAnimation *data = user_data;
gdouble progress = clutter_timeline_get_progress (timeline);
CoglColor color;
cogl_color_init_from_4f (&color, 0, 0, 0, 1 - progress);
cogl_pipeline_set_layer_combine_constant (data->overlay.pipeline, 0, &color);
data->overlay.current_rect.x = data->orig_x + ((data->dest_x - data->orig_x) * progress);
data->overlay.current_rect.y = data->orig_y + ((data->dest_y - data->orig_y) * progress);
queue_redraw_for_overlay (data->stage, &data->overlay);
}
static void
meta_drag_failed_animation_free (MetaDragFailedAnimation *data)
{
MetaStage *stage = data->stage;
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
priv->drag_failed_animations =
g_list_remove (priv->drag_failed_animations, data);
g_object_unref (data->timeline);
meta_overlay_free (&data->overlay);
g_slice_free (MetaDragFailedAnimation, data);
}
static MetaDragFailedAnimation *
meta_drag_failed_animation_new (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
data = g_slice_new0 (MetaDragFailedAnimation);
data->stage = stage;
data->orig_x = priv->dnd_overlay.current_rect.x;
data->orig_y = priv->dnd_overlay.current_rect.y;
data->dest_x = dest_x;
data->dest_y = dest_y;
meta_overlay_copy (&priv->dnd_overlay, &data->overlay);
data->timeline = clutter_timeline_new (DRAG_FAILED_MSECS);
clutter_timeline_set_progress_mode (data->timeline, CLUTTER_EASE_OUT_CUBIC);
g_signal_connect (data->timeline, "new-frame",
G_CALLBACK (drag_failed_animation_frame_cb), data);
g_signal_connect_swapped (data->timeline, "completed",
G_CALLBACK (meta_drag_failed_animation_free), data);
priv->drag_failed_animations =
g_list_prepend (priv->drag_failed_animations, data);
cogl_pipeline_set_layer_combine (data->overlay.pipeline, 0,
"RGBA = MODULATE (TEXTURE, CONSTANT[A])",
NULL);
return data;
}
void
meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
g_assert (meta_is_wayland_compositor ());
if (!priv->dnd_overlay.enabled)
return;
data = meta_drag_failed_animation_new (stage, dest_x, dest_y);
clutter_timeline_start (data->timeline);
}

View File

@@ -51,9 +51,18 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void);
void meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y);
G_END_DECLS
#endif /* META_STAGE_H */

View File

@@ -27,16 +27,27 @@
#include "meta-cursor-renderer-native.h"
#include <gbm.h>
#include <xf86drm.h>
#include "meta-cursor-private.h"
#include "meta-monitor-manager.h"
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
#endif
#ifndef DRM_CAP_CURSOR_HEIGHT
#define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
struct _MetaCursorRendererNativePrivate
{
gboolean has_hw_cursor;
int drm_fd;
struct gbm_device *gbm;
uint64_t cursor_width;
uint64_t cursor_height;
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
@@ -71,17 +82,13 @@ set_crtc_cursor (MetaCursorRendererNative *native,
{
struct gbm_bo *bo;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
bo = meta_cursor_reference_get_gbm_bo (cursor, &hot_x, &hot_y);
handle = gbm_bo_get_handle (bo);
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
}
else
{
@@ -186,6 +193,19 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
priv->gbm = gbm_create_device (priv->drm_fd);
uint64_t width, height;
if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
priv->cursor_width = width;
priv->cursor_height = height;
}
else
{
priv->cursor_width = 64;
priv->cursor_height = 64;
}
}
#endif
}
@@ -198,6 +218,16 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
return priv->gbm;
}
void
meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native,
uint64_t *width, uint64_t *height)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width;
*height = priv->cursor_height;
}
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{

View File

@@ -50,6 +50,7 @@ struct _MetaCursorRendererNativeClass
GType meta_cursor_renderer_native_get_type (void) G_GNUC_CONST;
struct gbm_device * meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *renderer);
void meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native, uint64_t *width, uint64_t *height);
void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
#endif /* META_CURSOR_RENDERER_NATIVE_H */

View File

@@ -144,7 +144,7 @@ static gboolean
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean value;
gboolean value = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@@ -158,12 +158,12 @@ output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_CARDINAL || actual_format != 32 ||
nitems < 1)
return FALSE;
if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return value;
}
@@ -187,7 +187,7 @@ static int
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gboolean value;
int value = -1;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@@ -201,14 +201,17 @@ output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_INTEGER || actual_format != 32 ||
nitems < 1)
return -1;
if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return normalize_backlight (output, value);
if (value > 0)
return normalize_backlight (output, value);
else
return -1;
}
static void

View File

@@ -185,6 +185,9 @@ file_loaded (GObject *source_object,
image->texture = texture;
out:
if (pixbuf != NULL)
g_object_unref (pixbuf);
image->loaded = TRUE;
g_signal_emit (image, signals[LOADED], 0);
}

View File

@@ -612,9 +612,14 @@ update_onscreen_requirements (MetaWindow *window,
*/
if (window->frame && window->decorated)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
meta_window_get_titlebar_rect (window, &titlebar_rect);
meta_window_get_frame_rect (window, &frame_rect);
/* translate into screen coordinates */
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
old = window->require_titlebar_visible;
window->require_titlebar_visible =

View File

@@ -57,6 +57,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
META_LIST_SORTED = 1 << 1, /* sort list by mru */
} MetaListWindowsFlags;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */

View File

@@ -150,6 +150,9 @@ static void update_cursor_theme (void);
static void prefs_changed_callback (MetaPreference pref,
void *data);
static int mru_cmp (gconstpointer a,
gconstpointer b);
static void
meta_display_get_property(GObject *object,
guint prop_id,
@@ -1061,6 +1064,9 @@ meta_display_list_windows (MetaDisplay *display,
tmp = next;
}
if (flags & META_LIST_SORTED)
winlist = g_slist_sort (winlist, mru_cmp);
return winlist;
}

View File

@@ -101,6 +101,8 @@ typedef struct
MetaKeyCombo *iso_next_group_combos;
int n_iso_next_group_combos;
xkb_level_index_t keymap_num_levels;
/* Alt+click button grabs */
ClutterModifierType window_grab_modifiers;
} MetaKeyBindingManager;

View File

@@ -40,7 +40,11 @@
#include <meta/prefs.h>
#include "meta-accel-parse.h"
#ifdef __linux__
#include <linux/input.h>
#elif !defined KEY_GRAVE
#define KEY_GRAVE 0x29 /* assume the use of xf86-input-keyboard */
#endif
#include "backends/x11/meta-backend-x11.h"
#include "x11/window-x11.h"
@@ -236,29 +240,19 @@ reload_modmap (MetaKeyBindingManager *keys)
static gboolean
is_keycode_for_keysym (struct xkb_keymap *keymap,
xkb_layout_index_t layout,
xkb_level_index_t level,
xkb_keycode_t keycode,
xkb_keysym_t keysym)
{
xkb_layout_index_t num_layouts, i;
const xkb_keysym_t *syms;
int num_syms, k;
num_layouts = xkb_keymap_num_layouts_for_key (keymap, keycode);
for (i = 0; i < num_layouts; i++)
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, layout, level, &syms);
for (k = 0; k < num_syms; k++)
{
xkb_level_index_t num_levels, j;
num_levels = xkb_keymap_num_levels_for_key (keymap, keycode, i);
for (j = 0; j < num_levels; j++)
{
const xkb_keysym_t *syms;
int num_syms, k;
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, i, j, &syms);
for (k = 0; k < num_syms; k++)
{
if (syms[k] == keysym)
return TRUE;
}
}
if (syms[k] == keysym)
return TRUE;
}
return FALSE;
@@ -268,6 +262,8 @@ typedef struct
{
GArray *keycodes;
xkb_keysym_t keysym;
xkb_layout_index_t layout;
xkb_level_index_t level;
} FindKeysymData;
static void
@@ -278,8 +274,10 @@ get_keycodes_for_keysym_iter (struct xkb_keymap *keymap,
FindKeysymData *search_data = data;
GArray *keycodes = search_data->keycodes;
xkb_keysym_t keysym = search_data->keysym;
xkb_layout_index_t layout = search_data->layout;
xkb_level_index_t level = search_data->level;
if (is_keycode_for_keysym (keymap, keycode, keysym))
if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym))
g_array_append_val (keycodes, keycode);
}
@@ -307,8 +305,15 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
FindKeysymData search_data = { retval, keysym };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
xkb_layout_index_t i;
xkb_level_index_t j;
for (i = 0; i < xkb_keymap_num_layouts (keymap); i++)
for (j = 0; j < keys->keymap_num_levels; j++)
{
FindKeysymData search_data = { retval, keysym, i, j };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
}
}
out:
@@ -319,7 +324,7 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
static guint
get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
guint keysym)
guint keysym)
{
int *keycodes;
int n_keycodes;
@@ -336,6 +341,32 @@ get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
return keycode;
}
static void
determine_keymap_num_levels_iter (struct xkb_keymap *keymap,
xkb_keycode_t keycode,
void *data)
{
xkb_level_index_t *num_levels = data;
xkb_layout_index_t i;
for (i = 0; i < xkb_keymap_num_layouts_for_key (keymap, keycode); i++)
{
xkb_level_index_t level = xkb_keymap_num_levels_for_key (keymap, keycode, i);
if (level > *num_levels)
*num_levels = level;
}
}
static void
determine_keymap_num_levels (MetaKeyBindingManager *keys)
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
keys->keymap_num_levels = 0;
xkb_keymap_key_for_each (keymap, determine_keymap_num_levels_iter, &keys->keymap_num_levels);
}
static void
reload_iso_next_group_combos (MetaKeyBindingManager *keys)
{
@@ -484,6 +515,8 @@ reload_keycodes (MetaKeyBindingManager *keys)
meta_topic (META_DEBUG_KEYBINDINGS,
"Reloading keycodes for binding tables\n");
determine_keymap_num_levels (keys);
if (keys->overlay_key_combo.keysym != 0)
{
keys->overlay_key_combo.keycode =

View File

@@ -1187,7 +1187,6 @@ settings_changed (GSettings *settings,
{
/* Unknown preference type. This quite likely simply isn't
* a preference we track changes to. */
return;
}
g_variant_unref (value);

View File

@@ -1056,10 +1056,6 @@ stack_sync_to_xserver (MetaStack *stack)
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
x11_hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window);
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
meta_push_no_msg_prefix ();
@@ -1107,6 +1103,10 @@ stack_sync_to_xserver (MetaStack *stack)
meta_topic (META_DEBUG_STACK, "\n");
meta_pop_no_msg_prefix ();
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window);
/* Sync to server */
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",

View File

@@ -653,9 +653,6 @@ void meta_window_set_transient_for (MetaWindow *window,
void meta_window_set_opacity (MetaWindow *window,
guint8 opacity);
void meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents);
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,

View File

@@ -1062,8 +1062,8 @@ _meta_window_shared_new (MetaDisplay *display,
if (window->initial_workspace_set)
{
gboolean on_all_workspaces;
MetaWorkspace *workspace;
gboolean on_all_workspaces = window->on_all_workspaces;
MetaWorkspace *workspace = NULL;
if (window->initial_workspace == (int) 0xFFFFFFFF)
{
@@ -1077,15 +1077,13 @@ _meta_window_shared_new (MetaDisplay *display,
window->on_all_workspaces_requested = TRUE;
on_all_workspaces = TRUE;
workspace = NULL;
}
else
else if (!on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Window %s is initially on space %d\n",
window->desc, window->initial_workspace);
on_all_workspaces = FALSE;
workspace = meta_screen_get_workspace_by_index (window->screen,
window->initial_workspace);
}
@@ -1099,9 +1097,9 @@ _meta_window_shared_new (MetaDisplay *display,
* but appear on other workspaces. override-redirect windows are part
* of no workspace.
*/
if (!window->override_redirect)
if (!window->override_redirect && window->workspace == NULL)
{
if (window->workspace == NULL && window->transient_for != NULL)
if (window->transient_for != NULL)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on same workspace as parent %s\n",
@@ -1112,7 +1110,15 @@ _meta_window_shared_new (MetaDisplay *display,
window->transient_for->workspace);
}
if (window->workspace == NULL)
if (window->on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on all workspaces\n",
window->desc);
set_workspace_state (window, TRUE, NULL);
}
else
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace\n",
@@ -2089,7 +2095,7 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
static gboolean
window_would_be_covered (const MetaWindow *newbie)
{
MetaWorkspace *workspace = newbie->workspace;
MetaWorkspace *workspace = meta_window_get_workspace ((MetaWindow *)newbie);
GList *tmp, *windows;
windows = meta_workspace_list_windows (workspace);
@@ -4291,7 +4297,7 @@ meta_window_focus (MetaWindow *window,
* - workspace->windows is a list of windows that is located on
* that workspace.
*
* - If the window is on_all_workspaces, then then
* - If the window is on_all_workspaces, then
* window->workspace == NULL, but workspace->windows contains
* the window.
*/
@@ -4313,7 +4319,8 @@ set_workspace_state (MetaWindow *window,
g_return_if_fail ((window->constructing && on_all_workspaces) || window->unmanaging);
if (on_all_workspaces == window->on_all_workspaces &&
workspace == window->workspace)
workspace == window->workspace &&
!window->constructing)
return;
if (window->workspace)
@@ -5385,7 +5392,7 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
gboolean
meta_window_titlebar_is_onscreen (MetaWindow *window)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
GList *onscreen_region;
gboolean is_onscreen;
@@ -5400,6 +5407,11 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
/* Get the rectangle corresponding to the titlebar */
meta_window_get_titlebar_rect (window, &titlebar_rect);
/* Translate into screen coordinates */
meta_window_get_frame_rect (window, &frame_rect);
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
/* Run through the spanning rectangles for the screen and see if one of
* them overlaps with the titlebar sufficiently to consider it onscreen.
*/
@@ -6719,7 +6731,7 @@ meta_window_set_demands_attention (MetaWindow *window)
other_window = stack->data;
stack = stack->next;
if (meta_window_located_on_workspace (other_window, window->workspace))
if (meta_window_located_on_workspace (other_window, workspace))
{
meta_window_get_frame_rect (other_window, &other_rect);
@@ -7887,24 +7899,6 @@ meta_window_handle_ungrabbed_event (MetaWindow *window,
}
}
void
meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents)
{
if (extents)
{
window->has_custom_frame_extents = TRUE;
window->custom_frame_extents = *extents;
}
else
{
window->has_custom_frame_extents = FALSE;
memset (&window->custom_frame_extents, 0, sizeof (window->custom_frame_extents));
}
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}
gboolean
meta_window_can_maximize (MetaWindow *window)
{

View File

@@ -170,6 +170,7 @@ MetaWorkspace*
meta_workspace_new (MetaScreen *screen)
{
MetaWorkspace *workspace;
GSList *windows, *l;
workspace = g_object_new (META_TYPE_WORKSPACE, NULL);
@@ -179,6 +180,13 @@ meta_workspace_new (MetaScreen *screen)
workspace->windows = NULL;
workspace->mru_list = NULL;
/* make sure sticky windows are in our mru_list */
windows = meta_display_list_windows (screen->display, META_LIST_SORTED);
for (l = windows; l; l = l->next)
if (meta_window_located_on_workspace (l->data, workspace))
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
workspace->work_areas_invalid = TRUE;
workspace->work_area_monitor = NULL;
workspace->work_area_screen.x = 0;
@@ -358,7 +366,7 @@ meta_workspace_relocate_windows (MetaWorkspace *workspace,
{
MetaWindow *window = l->data;
if (!window->override_redirect)
if (!window->on_all_workspaces)
meta_window_change_workspace (window, new_home);
}

View File

@@ -28,7 +28,7 @@
#define META_TYPE_WORKSPACE (meta_workspace_get_type ())
#define META_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WORKSPACE, MetaWorkspace))
#define META_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WORKSPACE, MetaWorkspaceClass))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_WORKSPACE_TYPE))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WORKSPACE))
#define META_IS_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WORKSPACE))
#define META_WORKSPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WORKSPACE, MetaWorkspaceClass))

View File

@@ -71,6 +71,11 @@ lower <client-id>/<window-id>
for Wayland clients. (It's also considered discouraged, but supported, for
non-override-redirect X11 clients.)
minimize <client-id>/<window-id>
unminimize <client-id>/<window-id>
Ask the client to minimize or unminimize the given window ID. This older
term for this operation is "iconify".
destroy <client-id>/<window-id>
Destroy the given window
@@ -80,7 +85,10 @@ wait
assert_stacking <client-id>/<window-id> <client-id>/<window-id> ...
Assert that the list of client windows known to Mutter is as given and in
the given order, bottom to top.
the given order, bottom to top. The character '|' can be present in the
list of windows to indicate the guard window that separates hidden and
visible windows. If '|' isn't present, the guard window is asserted to
be below all client windows.
This function also queries the X server stack and verifies that Mutter's
expectation of the X server stack matches reality.

View File

@@ -0,0 +1,18 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2
show 1/2
wait
assert_stacking 1/1 1/2
minimize 1/2
wait
assert_stacking 1/2 | 1/1
# unminimize doesn't work for GTK+ currently, because GTK+ expects
# to be able to de-iconify with MapWindow, but the window is already
# mapped.
activate 1/2
wait
assert_stacking 1/1 1/2

View File

@@ -12,7 +12,7 @@ assert_stacking 1/1 1/2
lower 1/2
wait
assert_stacking 1/2 1/1
assert_stacking 1/2 | 1/1
raise 1/2
wait

View File

@@ -263,6 +263,34 @@ process_line (const char *line)
XSyncSetCounter (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
counter, sync_value);
}
else if (strcmp (argv[0], "minimize") == 0)
{
if (argc != 2)
{
g_print ("usage: minimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_iconify (GTK_WINDOW (window));
}
else if (strcmp (argv[0], "unminimize") == 0)
{
if (argc != 2)
{
g_print ("usage: unminimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_deiconify (GTK_WINDOW (window));
}
else
{
g_print ("Unknown command %s", argv[0]);

View File

@@ -413,6 +413,7 @@ typedef struct {
AsyncWaiter *waiter;
guint log_handler_id;
GString *warning_messages;
GMainLoop *loop;
} TestCase;
static gboolean
@@ -483,10 +484,21 @@ test_case_new (void)
test->clients = g_hash_table_new (g_str_hash, g_str_equal);
test->waiter = async_waiter_new ();
test->loop = g_main_loop_new (NULL, FALSE);
return test;
}
static gboolean
test_case_before_redraw (gpointer data)
{
TestCase *test = data;
g_main_loop_quit (test->loop);
return FALSE;
}
static gboolean
test_case_wait (TestCase *test,
GError **error)
@@ -494,11 +506,30 @@ test_case_wait (TestCase *test,
GHashTableIter iter;
gpointer key, value;
/* First have each client set a XSync counter, and wait until
* we receive the resulting event - so we know we've received
* everything that the client have sent us.
*/
g_hash_table_iter_init (&iter, test->clients);
while (g_hash_table_iter_next (&iter, &key, &value))
if (!test_client_wait (value, error))
return FALSE;
/* Then wait until we've done any outstanding queued up work.
* Though we add this as BEFORE_REDRAW, the iteration that runs the
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
* waiting until after *all* frame processing.
*/
meta_later_add (META_LATER_BEFORE_REDRAW,
test_case_before_redraw,
test,
NULL);
g_main_loop_run (test->loop);
/* Then set an XSync counter ourselves and and wait until
* we receive the resulting event - this makes sure that we've
* received back any X events we generated.
*/
async_waiter_set_and_wait (test->waiter);
return TRUE;
}
@@ -579,6 +610,13 @@ test_case_assert_stacking (TestCase *test,
else
g_string_append_printf (stack_string, "(%s)", window->title);
}
else if (windows[i] == display->screen->guard_window)
{
if (stack_string->len > 0)
g_string_append_c (stack_string, ' ');
g_string_append_c (stack_string, '|');
}
}
for (i = 0; i < n_expected_windows; i++)
@@ -589,6 +627,16 @@ test_case_assert_stacking (TestCase *test,
g_string_append (expected_string, expected_windows[i]);
}
/* Don't require '| ' as a prefix if there are no hidden windows - we
* remove the prefix from the actual string instead of adding it to the
* expected string for clarity of the error message
*/
if (index (expected_string->str, '|') == NULL && stack_string->str[0] == '|')
{
g_string_erase (stack_string,
0, stack_string->str[1] == ' ' ? 2 : 1);
}
if (strcmp (expected_string->str, stack_string->str) != 0)
{
g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED,
@@ -725,6 +773,8 @@ test_case_do (TestCase *test,
strcmp (argv[0], "activate") == 0 ||
strcmp (argv[0], "raise") == 0 ||
strcmp (argv[0], "lower") == 0 ||
strcmp (argv[0], "minimize") == 0 ||
strcmp (argv[0], "unminimize") == 0 ||
strcmp (argv[0], "destroy") == 0)
{
if (argc != 2)
@@ -766,6 +816,7 @@ test_case_do (TestCase *test,
{
if (!test_case_assert_stacking (test, argv + 1, argc - 1, error))
return FALSE;
if (!test_case_check_xserver_stacking (test, error))
return FALSE;
}

View File

@@ -34,6 +34,7 @@
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
typedef struct
{
@@ -46,6 +47,7 @@ struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
gboolean has_target;
};
static void
@@ -67,7 +69,10 @@ data_offer_accept (struct wl_client *client,
* this be a wl_data_device request? */
if (offer->source)
wl_data_source_send_target (offer->source->resource, mime_type);
{
wl_data_source_send_target (offer->source->resource, mime_type);
offer->source->has_target = mime_type != NULL;
}
}
static void
@@ -162,7 +167,7 @@ static struct wl_data_source_interface data_source_interface = {
data_source_destroy
};
typedef struct {
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
MetaWaylandSeat *seat;
@@ -177,7 +182,12 @@ typedef struct {
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
} MetaWaylandDragGrab;
MetaWaylandSurface *drag_origin;
struct wl_listener drag_origin_listener;
int drag_start_x, drag_start_y;
};
static void
destroy_drag_focus (struct wl_listener *listener, void *data)
@@ -202,6 +212,8 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
if (drag_grab->drag_focus == surface)
return;
meta_wayland_pointer_set_focus (&seat->pointer, surface, FALSE);
if (drag_grab->drag_focus_data_device)
{
wl_data_device_send_leave (drag_grab->drag_focus_data_device);
@@ -241,6 +253,40 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
wl_resource_add_destroy_listener (data_device_resource, &drag_grab->drag_focus_listener);
}
static void
drag_grab_update_dnd_surface_position (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint pos;
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
meta_cursor_tracker_update_dnd_surface_position (seat->pointer.cursor_tracker,
(int) pos.x, (int) pos.y);
}
static void
drag_grab_update_dnd_surface (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_surface;
MetaWaylandSeat *seat = drag_grab->seat;
CoglTexture *texture = NULL;
int offset_x, offset_y;
if (surface)
{
if (surface->buffer)
texture = surface->buffer->texture;
offset_x = surface->offset_x;
offset_y = surface->offset_y;
}
else
offset_x = offset_y = 0;
meta_cursor_tracker_set_dnd_surface (seat->pointer.cursor_tracker,
texture, offset_x, offset_y);
}
static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
@@ -248,6 +294,8 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
wl_fixed_t sx, sy;
drag_grab_update_dnd_surface_position (drag_grab);
if (drag_grab->drag_focus_data_device)
{
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
@@ -259,9 +307,38 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
}
}
static void
data_device_dnd_failed (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_origin;
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint dest;
if (drag_grab->drag_origin &&
!meta_window_is_hidden (surface->window))
{
/* Find out the snap back position */
clutter_actor_get_transformed_position (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
&dest.x, &dest.y);
dest.x += drag_grab->drag_start_x;
dest.y += drag_grab->drag_start_y;
}
else
clutter_input_device_get_coords (seat->pointer.device, NULL, &dest);
meta_cursor_tracker_dnd_failed (seat->pointer.cursor_tracker,
dest.x, dest.y);
}
static void
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
{
if (drag_grab->drag_origin)
{
drag_grab->drag_origin = NULL;
wl_list_remove (&drag_grab->drag_origin_listener.link);
}
if (drag_grab->drag_surface)
{
drag_grab->drag_surface = NULL;
@@ -269,9 +346,15 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
}
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
{
drag_grab->drag_data_source->has_target = FALSE;
wl_list_remove (&drag_grab->drag_data_source_listener.link);
}
drag_grab->seat->data_device.current_grab = NULL;
drag_grab_focus (&drag_grab->generic, NULL);
drag_grab_update_dnd_surface (drag_grab);
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
@@ -285,10 +368,15 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
MetaWaylandSeat *seat = drag_grab->seat;
ClutterEventType event_type = clutter_event_type (event);
if (drag_grab->drag_focus_data_device &&
drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
{
if (drag_grab->drag_focus_data_device &&
drag_grab->drag_data_source->has_target)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
else
data_device_dnd_failed (drag_grab);
}
if (seat->pointer.button_count == 0 &&
event_type == CLUTTER_BUTTON_RELEASE)
@@ -301,6 +389,16 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
drag_grab_button,
};
static void
destroy_data_device_origin (struct wl_listener *listener, void *data)
{
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_origin_listener);
drag_grab->drag_origin = NULL;
data_device_end_drag_grab (drag_grab);
}
static void
destroy_data_device_source (struct wl_listener *listener, void *data)
{
@@ -318,6 +416,7 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
wl_container_of (listener, drag_grab, drag_data_source_listener);
drag_grab->drag_surface = NULL;
drag_grab_update_dnd_surface (drag_grab);
}
static void
@@ -329,20 +428,29 @@ data_device_start_drag (struct wl_client *client,
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandSurface *surface = NULL;
MetaWaylandDragGrab *drag_grab;
ClutterPoint pos;
if ((seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
if (origin_resource)
surface = wl_resource_get_user_data (origin_resource);
if (!surface)
return;
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != surface)
return;
/* FIXME: Check that the data source type array isn't empty. */
if (seat->pointer.grab != &seat->pointer.default_grab)
if (data_device->current_grab ||
seat->pointer.grab != &seat->pointer.default_grab)
return;
drag_grab = g_slice_new0 (MetaWaylandDragGrab);
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
drag_grab->generic.interface = &drag_grab_interface;
drag_grab->generic.pointer = &seat->pointer;
@@ -350,6 +458,17 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_client = client;
drag_grab->seat = seat;
drag_grab->drag_origin = surface;
drag_grab->drag_origin_listener.notify = destroy_data_device_origin;
wl_resource_add_destroy_listener (origin_resource,
&drag_grab->drag_origin_listener);
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
pos.x, pos.y, &pos.x, &pos.y);
drag_grab->drag_start_x = pos.x;
drag_grab->drag_start_y = pos.y;
if (source_resource)
{
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
@@ -366,8 +485,10 @@ data_device_start_drag (struct wl_client *client,
&drag_grab->drag_icon_listener);
}
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
meta_wayland_pointer_set_focus (&seat->pointer, NULL, TRUE);
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
drag_grab_update_dnd_surface_position (drag_grab);
drag_grab_update_dnd_surface (drag_grab);
}
static void
@@ -551,3 +672,18 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
wl_data_device_send_selection (data_device_resource, offer);
}
}
gboolean
meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface)
{
return data_device->current_grab &&
data_device->current_grab->drag_surface == surface;
}
void
meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
{
if (data_device->current_grab)
drag_grab_update_dnd_surface (data_device->current_grab);
}

View File

@@ -27,12 +27,15 @@
#include "meta-wayland-types.h"
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
struct _MetaWaylandDataDevice
{
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
MetaWaylandDragGrab *current_grab;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -41,4 +44,8 @@ void meta_wayland_data_device_init (MetaWaylandDataDevice *data_device);
void meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device);
gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface);
void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_H */

View File

@@ -273,14 +273,19 @@ notify_modifiers (MetaWaylandKeyboard *keyboard)
state = keyboard->xkb_info.state;
l = &keyboard->focus_resource_list;
wl_resource_for_each (resource, l)
if (!wl_list_empty (l))
{
wl_keyboard_send_modifiers (resource,
wl_display_next_serial (keyboard->display),
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
uint32_t serial = wl_display_next_serial (keyboard->display);
wl_resource_for_each (resource, l)
{
wl_keyboard_send_modifiers (resource,
serial,
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
}
}
}

View File

@@ -95,7 +95,7 @@ pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
}
static void
@@ -107,7 +107,7 @@ default_grab_focus (MetaWaylandPointerGrab *grab,
if (pointer->button_count > 0)
return;
meta_wayland_pointer_set_focus (pointer, surface);
meta_wayland_pointer_set_focus (pointer, surface, TRUE);
}
static void
@@ -142,7 +142,7 @@ default_grab_button (MetaWaylandPointerGrab *grab,
event_type = clutter_event_type (event);
l = &grab->pointer->focus_resource_list;
wl_resource_for_each(resource, l)
if (!wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
@@ -168,13 +168,17 @@ default_grab_button (MetaWaylandPointerGrab *grab,
}
serial = wl_display_next_serial (display);
wl_pointer_send_button (resource, serial,
clutter_event_get_time (event), button,
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
wl_resource_for_each(resource, l)
{
wl_pointer_send_button (resource, serial,
clutter_event_get_time (event), button,
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
}
}
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
meta_wayland_pointer_set_focus (pointer, pointer->current);
meta_wayland_pointer_set_focus (pointer, pointer->current, TRUE);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@@ -214,7 +218,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
set_cursor_surface (pointer, NULL);
pointer->display = NULL;
@@ -476,7 +480,8 @@ broadcast_focus (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
MetaWaylandSurface *surface,
gboolean emit_crossing)
{
if (pointer->display == NULL)
return;
@@ -496,9 +501,12 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
if (emit_crossing)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
wl_resource_for_each (resource, l)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
}
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
@@ -529,7 +537,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
wl_resource_get_client (pointer->focus_surface->resource));
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
if (emit_crossing && !wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
@@ -591,9 +599,9 @@ popup_grab_focus (MetaWaylandPointerGrab *grab,
/* Popup grabs are in owner-events mode (ie, events for the same client
are reported as normal) */
if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client)
meta_wayland_pointer_set_focus (grab->pointer, surface);
meta_wayland_pointer_set_focus (grab->pointer, surface, TRUE);
else
meta_wayland_pointer_set_focus (grab->pointer, NULL);
meta_wayland_pointer_set_focus (grab->pointer, NULL, TRUE);
}
static void

View File

@@ -86,7 +86,8 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
const ClutterEvent *event);
void meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
MetaWaylandSurface *surface,
gboolean emit_crossing);
void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
MetaWaylandPointerGrab *grab);

View File

@@ -175,6 +175,13 @@ cursor_surface_commit (MetaWaylandSurface *surface,
meta_wayland_seat_update_cursor_surface (surface->compositor->seat);
}
static void
dnd_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
}
static void
calculate_surface_window_geometry (MetaWaylandSurface *surface,
MetaRectangle *total_geometry,
@@ -429,6 +436,9 @@ commit_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage);
surface->offset_x += pending->dx;
surface->offset_y += pending->dy;
if (pending->opaque_region)
{
pending->opaque_region = scale_region (pending->opaque_region, surface->scale);
@@ -442,6 +452,8 @@ commit_pending_state (MetaWaylandSurface *surface,
if (surface == compositor->seat->pointer.cursor_surface)
cursor_surface_commit (surface, pending);
else if (meta_wayland_data_device_is_dnd_surface (&compositor->seat->data_device, surface))
dnd_surface_commit (surface, pending);
else if (surface->window)
toplevel_surface_commit (surface, pending);
else if (surface->subsurface.resource)
@@ -1441,12 +1453,15 @@ bind_gtk_shell (struct wl_client *client,
guint32 id)
{
struct wl_resource *resource;
uint32_t capabilities = 0;
resource = wl_resource_create (client, &gtk_shell_interface, version, id);
wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL);
/* FIXME: ask the plugin */
gtk_shell_send_capabilities (resource, GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU);
if (!meta_prefs_get_show_fallback_app_menu ())
capabilities = GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU;
gtk_shell_send_capabilities (resource, capabilities);
}
static void

View File

@@ -115,6 +115,8 @@ struct _MetaWaylandSurface
GSList *pending_placement_ops;
} sub;
int32_t offset_x, offset_y;
gboolean has_set_geometry;
/* All the pending state that wl_surface.commit will apply. */

View File

@@ -188,21 +188,20 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
}
else
{
/* If we get a 0x0 size, this means that we're trying to resize
* a surface that doesn't have any buffer attached. This can happen
* when a client requests an xdg surface before bringing it up.
* The constrained_rect will be 1x1 because of how our constraints
* code works, and sending that to the window would cause it to
* redraw itself, so just don't send anything. Pretend like this
* move_resize never happened.
*/
if (unconstrained_rect.width == 0 &&
unconstrained_rect.height == 0)
return;
if (constrained_rect.width != window->rect.width ||
constrained_rect.height != window->rect.height)
{
/* If we get a 0x0 size, this means that we're trying to resize
* a surface that doesn't have any buffer attached. This can happen
* when a client requests an xdg surface before bringing it up.
* The constrained_rect will be 1x1 because of how our constraints
* code works, and sending that to the window would cause it to
* redraw itself, so just don't send anything.
*/
if (unconstrained_rect.width == 0 &&
unconstrained_rect.height == 0)
return;
meta_wayland_surface_configure_notify (window->surface,
constrained_rect.width,
constrained_rect.height,

View File

@@ -338,6 +338,52 @@ reload_icon_geometry (MetaWindow *window,
}
}
static gboolean
gtk_border_equal (GtkBorder *a,
GtkBorder *b)
{
return (a->left == b->left &&
a->right == b->right &&
a->top == b->top &&
a->bottom == b->bottom);
}
static void
meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents,
gboolean is_initial)
{
if (extents)
{
if (window->has_custom_frame_extents && gtk_border_equal (&window->custom_frame_extents, extents))
return;
window->has_custom_frame_extents = TRUE;
window->custom_frame_extents = *extents;
/* If we're setting the frame extents on map, then this is telling
* us to adjust our understanding of the frame rect to match what
* GTK+ thinks it is. Future changes to the frame extents should
* trigger a resize and send a ConfigureRequest to the application.
*/
if (is_initial)
{
meta_window_client_rect_to_frame_rect (window, &window->rect, &window->rect);
meta_window_client_rect_to_frame_rect (window, &window->unconstrained_rect, &window->unconstrained_rect);
}
}
else
{
if (!window->has_custom_frame_extents)
return;
window->has_custom_frame_extents = FALSE;
memset (&window->custom_frame_extents, 0, sizeof (window->custom_frame_extents));
}
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}
static void
reload_gtk_frame_extents (MetaWindow *window,
MetaPropValue *value,
@@ -357,16 +403,13 @@ reload_gtk_frame_extents (MetaWindow *window,
extents.right = (int)value->v.cardinal_list.cardinals[1];
extents.top = (int)value->v.cardinal_list.cardinals[2];
extents.bottom = (int)value->v.cardinal_list.cardinals[3];
meta_window_set_custom_frame_extents (window, &extents);
meta_window_set_custom_frame_extents (window, &extents, initial);
}
}
else
{
meta_window_set_custom_frame_extents (window, NULL);
meta_window_set_custom_frame_extents (window, NULL, initial);
}
if (!initial)
meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
}
static void

View File

@@ -214,8 +214,29 @@ send_configure_notify (MetaWindow *window)
event.xconfigure.display = window->display->xdisplay;
event.xconfigure.event = window->xwindow;
event.xconfigure.window = window->xwindow;
event.xconfigure.x = window->rect.x - priv->border_width;
event.xconfigure.y = window->rect.y - priv->border_width;
event.xconfigure.x = priv->client_rect.x - priv->border_width;
event.xconfigure.y = priv->client_rect.y - priv->border_width;
if (window->frame)
{
if (window->withdrawn)
{
MetaFrameBorders borders;
/* We reparent the client window and put it to the position
* where the visible top-left of the frame window currently is.
*/
meta_frame_calc_borders (window->frame, &borders);
event.xconfigure.x = window->frame->rect.x + borders.invisible.left;
event.xconfigure.y = window->frame->rect.y + borders.invisible.top;
}
else
{
/* Need to be in root window coordinates */
event.xconfigure.x += window->frame->rect.x;
event.xconfigure.y += window->frame->rect.y;
}
}
event.xconfigure.width = priv->client_rect.width;
event.xconfigure.height = priv->client_rect.height;
event.xconfigure.border_width = priv->border_width; /* requested not actual */
@@ -249,6 +270,17 @@ adjust_for_gravity (MetaWindow *window,
int frame_width, frame_height;
MetaFrameBorders borders;
/* We're computing position to pass to window_move, which is
* the position of the client window (StaticGravity basically)
*
* (see WM spec description of gravity computation, but note that
* their formulas assume we're honoring the border width, rather
* than compensating for having turned it off)
*/
if (gravity == StaticGravity)
return;
if (coords_assume_border)
bw = priv->border_width;
else
@@ -261,14 +293,6 @@ adjust_for_gravity (MetaWindow *window,
frame_width = child_x + rect->width + borders.visible.right;
frame_height = child_y + rect->height + borders.visible.bottom;
/* We're computing position to pass to window_move, which is
* the position of the client window (StaticGravity basically)
*
* (see WM spec description of gravity computation, but note that
* their formulas assume we're honoring the border width, rather
* than compensating for having turned it off)
*/
/* Calculate the the reference point, which is the corner of the
* outer window specified by the gravity. So, NorthEastGravity
* would have the reference point as the top-right corner of the