Compare commits

..

6 Commits

Author SHA1 Message Date
Giovanni Campagna
34398b273c wayland: add support for pointer barriers
Use the clutter pointer constrain callback and a lot of copypasted
code from Xorg to implement reactive pointer barriers and pointer
barrier events.

https://bugzilla.gnome.org/show_bug.cgi?id=706655
2013-10-03 21:11:13 +02:00
Giovanni Campagna
00a73c5bdc display: shortcut get_time_roundtrip() when running as a wayland compositor
In wayland, we can make some assumptions about the behavior and
configuration of the X server (which is Xwayland), including on
the time it uses, and that way avoiding a roundtrip (potentially deadly, if
by chance the X server is also blocking on us or needs us to flush
the wayland socket buffer).
Note that we bypass get_current_time() entirely, as it is assumed
the function is called always to translated CurrentTime into a real
value.

https://bugzilla.gnome.org/show_bug.cgi?id=707466
2013-10-03 21:11:12 +02:00
Giovanni Campagna
20cd02f086 wayland: use the timestamps from events
Clutter has learned to use monotonic times for the events, and
so does X (at least Xwayland, which is an implementation we know
and we can rely upon), so the values are directly comparable.

https://bugzilla.gnome.org/show_bug.cgi?id=707466
2013-10-03 21:11:12 +02:00
Giovanni Campagna
0cb9392686 wayland: sync the keymap from X to wayland
When X clients change the keyboard map, the also update a property
on the root window. We can notice that and rebuild our data structures
with the new values, as well as inform the wayland clients.

This is a terrible hack, and it's not how we want to implement things
in 3.12, but it's enough to have the same keyboard layout in the
shell, in X clients and in wayland clients in 3.10, until we decide
on the fate of the keyboard g-s-d plugin.

https://bugzilla.gnome.org/show_bug.cgi?id=707446
2013-10-03 21:11:12 +02:00
Giovanni Campagna
57f0b1d46d wayland: implement global and window keybindings
Synthetize XInput events from ClutterEvents in MetaWaylandKeyboard,
and pass them to the keybindings infrastructure for early handling,
so that we can activate them even if the currently focused window
is not an X11 one (or if there is no focused window, or we're
modal)

https://bugzilla.gnome.org/show_bug.cgi?id=706963
2013-10-03 21:11:12 +02:00
Giovanni Campagna
e2d8d886a8 [NOT FOR REVIEW] Add the ability to attach a debugger at init 2013-10-03 21:11:12 +02:00
61 changed files with 4495 additions and 3862 deletions

3
.gitignore vendored
View File

@@ -81,9 +81,6 @@ src/mutter-plugins.pc
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-client-protocol.h
src/wayland/gtk-shell-server-protocol.h
src/wayland/xdg-shell-protocol.c
src/wayland/xdg-shell-client-protocol.h
src/wayland/xdg-shell-server-protocol.h
src/wayland/xserver-protocol.c
src/wayland/xserver-client-protocol.h
src/wayland/xserver-server-protocol.h

View File

@@ -6,5 +6,3 @@ EXTRA_DIST = HACKING MAINTAINERS rationales.txt
DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

38
NEWS
View File

@@ -1,41 +1,3 @@
3.11.2
======
* Support setting a NULL opaque region [Andreas; #711518]
* Sync keymap from X to wayland [Giovanni; #707446]
* Implement support for subsurfaces [Jonas; #705502]
* Don't focus the no-focus-window for globally active windows [Jasper; #710296]
* Support "hotplug_mode_update" property [Marc-André; #711216]
* Fix resize operations using mouse-button-modifier [Lionel; #710251]
* Fix position of attached modals for CSD windows [Giovanni, Owen; #707194]
* Misc. bug fixes [Rui, Jasper, Neil, Florian; #712247, #711731]
Contributors:
Giovanni Campagna, Andreas Heider, Lionel Landwerlin, Marc-André Lureau,
Rui Matos, Florian Müllner, Neil Roberts, Sindhu S, Jasper St. Pierre,
Rico Tzschichholz, Owen W. Taylor, Jonas Ådahl
3.11.1
======
* Fix tile previews getting stuck on right click during drags [Lionel; #704759]
* Use new UPower API [Bastien]
* Set hot spot when cursor set from wl_buffer [Jonas; #709593]
* Expose min-backlight-step [Asad; #710380]
* Misc. bug fixes and cleanups [Jasper, Olav, Magdalen; #709776]
Contributors:
Magdalen Berns, Lionel Landwerlin, Asad Mehmood, Bastien Nocera,
Jasper St. Pierre, Olav Vitters, Jonas Ådahl
3.10.1
======
* Don't apply fullscreen workarounds to CSD windows [Giovanni; #708718]
* Fix hangs during DND operations [Adel; #709340]
* Misc bug fixes [Dan, Giovanni, Jasper; #708813, #708420]
Contributors:
Giovanni Campagna, Adel Gadllah, Dan Horák, Hans Petter Jansson,
Jasper St. Pierre
3.10.0.1
========
* Fix bug when a window changed size twice in a single frame - this

View File

@@ -1,9 +1,8 @@
AC_PREREQ(2.50)
AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [11])
m4_define([mutter_micro_version], [2])
m4_define([mutter_minor_version], [10])
m4_define([mutter_micro_version], [0.1])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -78,9 +77,9 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.17.1
$CLUTTER_PACKAGE >= 1.15.94
cogl-1.0 >= 1.13.3
upower-glib >= 0.99.0
upower-glib > 0.9.11
gnome-desktop-3.0
"

View File

@@ -49,8 +49,8 @@ FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=$(top_srcdir)/src/*/*.h
CFILE_GLOB=$(top_srcdir)/src/*/*.c
HFILE_GLOB=$(top_srcdir)/src/*.h
CFILE_GLOB=$(top_srcdir)/src/*.c
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h

View File

@@ -207,6 +207,7 @@ meta_key_binding_get_modifiers
meta_key_binding_get_mask
meta_key_binding_is_builtin
meta_keybindings_set_custom_handler
meta_keybindings_switch_window
meta_screen_ungrab_all_keys
meta_screen_grab_all_keys
</SECTION>
@@ -541,10 +542,7 @@ meta_window_is_override_redirect
meta_window_is_skip_taskbar
meta_window_get_rect
meta_window_get_input_rect
meta_window_get_frame_rect
meta_window_get_outer_rect
meta_window_client_rect_to_frame_rect
meta_window_frame_rect_to_client_rect
meta_window_get_screen
meta_window_get_display
meta_window_get_xwindow

View File

@@ -21,7 +21,6 @@ environment.</description>
-->
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
<download-page rdf:resource="http://download.gnome.org/sources/mutter/" />
<download-page rdf:resource="http://download.gnome.org/sources/mutter-wayland/" />
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=mutter" />
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />

View File

@@ -1,7 +1 @@
NULL =
EXTRA_DIST = \
gtk-shell.xml \
xdg-shell.xml \
xserver.xml \
$(NULL)
EXTRA_DIST = xserver.xml

View File

@@ -1,385 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="xdg_surface">
<copyright>
Copyright © 2008-2013 Kristian Høgsberg
Copyright © 2013 Rafael Antognolli
Copyright © 2013 Jasper St. Pierre
Copyright © 2010-2013 Intel Corporation
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="xdg_shell" version="1">
<description summary="create desktop-style surfaces">
This interface is implemented by servers that provide
desktop-style user interfaces.
It allows clients to associate a xdg_surface with
a basic surface.
</description>
<enum name="version">
<description summary="latest protocol version">
Use this enum to check the protocol version, and it will be updated
automatically.
</description>
<entry name="current" value="1" summary="Always the latest version"/>
</enum>
<request name="use_unstable_version">
<description summary="enable use of this unstable version">
Use this request in order to enable use of this interface.
Understand and agree that one is using an unstable interface,
that will likely change in the future, breaking the API.
</description>
<arg name="version" type="int"/>
</request>
<request name="get_xdg_surface">
<description summary="create a shell surface from a surface">
Create a shell surface for an existing surface.
Only one shell or popup surface can be associated with a given
surface.
</description>
<arg name="id" type="new_id" interface="xdg_surface"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="get_xdg_popup">
<description summary="create a shell surface from a surface">
Create a popup surface for an existing surface.
Only one shell or popup surface can be associated with a given
surface.
</description>
<arg name="id" type="new_id" interface="xdg_popup"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="parent" type="object" interface="wl_surface"/>
<arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
<arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="flags" type="uint"/>
</request>
</interface>
<interface name="xdg_surface" version="1">
<description summary="desktop-style metadata interface">
An interface that may be implemented by a wl_surface, for
implementations that provide a desktop-style user interface.
It provides requests to treat surfaces like windows, allowing to set
properties like maximized, fullscreen, minimized, and to move and resize
them, and associate metadata like title and app id.
On the server side the object is automatically destroyed when
the related wl_surface is destroyed. On client side,
xdg_surface.destroy() must be called before destroying
the wl_surface object.
</description>
<request name="destroy" type="destructor">
<description summary="remove xdg_surface interface">
The xdg_surface interface is removed from the wl_surface object
that was turned into a xdg_surface with
xdg_shell.get_xdg_surface request. The xdg_surface properties,
like maximized and fullscreen, are lost. The wl_surface loses
its role as a xdg_surface. The wl_surface is unmapped.
</description>
</request>
<request name="set_transient_for">
<description summary="surface is a child of another surface">
Setting a surface as transient of another means that it is child
of another surface.
Child surfaces are stacked above their parents, and will be
unmapped if the parent is unmapped too. They should not appear
on task bars and alt+tab.
</description>
<arg name="parent" type="object" interface="wl_surface"/>
</request>
<request name="set_title">
<description summary="set surface title">
Set a short title for the surface.
This string may be used to identify the surface in a task bar,
window list, or other user interface elements provided by the
compositor.
The string must be encoded in UTF-8.
</description>
<arg name="title" type="string"/>
</request>
<request name="set_app_id">
<description summary="set surface class">
Set an id for the surface.
The app id identifies the general class of applications to which
the surface belongs.
It should be the ID that appears in the new desktop entry
specification, the interface name.
</description>
<arg name="app_id" type="string"/>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<request name="move">
<description summary="start an interactive move">
Start a pointer-driven move of the surface.
This request must be used in response to a button press event.
The server may ignore move requests depending on the state of
the surface (e.g. fullscreen or maximized).
</description>
<arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
<arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
</request>
<enum name="resize_edge">
<description summary="edge values for resizing">
These values are used to indicate which edge of a surface
is being dragged in a resize operation. The server may
use this information to adapt its behavior, e.g. choose
an appropriate cursor image.
</description>
<entry name="none" value="0"/>
<entry name="top" value="1"/>
<entry name="bottom" value="2"/>
<entry name="left" value="4"/>
<entry name="top_left" value="5"/>
<entry name="bottom_left" value="6"/>
<entry name="right" value="8"/>
<entry name="top_right" value="9"/>
<entry name="bottom_right" value="10"/>
</enum>
<request name="resize">
<description summary="start an interactive resize">
Start a pointer-driven resizing of the surface.
This request must be used in response to a button press event.
The server may ignore resize requests depending on the state of
the surface (e.g. fullscreen or maximized).
</description>
<arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
<arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
<arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
</request>
<event name="configure">
<description summary="suggest resize">
The configure event asks the client to resize its surface.
The size is a hint, in the sense that the client is free to
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
The edges parameter provides a hint about how the surface
was resized. The client may use this information to decide
how to adjust its content to the new size (e.g. a scrolling
area might adjust its content position to leave the viewable
content unmoved). Valid edge values are from resize_edge enum.
The maximized parameter informs if the surface is in a maximized
state. Same for the fullscreen parameter.
The client is free to dismiss all but the last configure
event it received.
The width and height arguments specify the size of the window
in surface local coordinates.
</description>
<arg name="edges" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="maximized" type="uint"/>
<arg name="fullscreen" type="uint"/>
</event>
<request name="set_output">
<description summary="set the default output used by this surface">
Set the default output used by this surface when it is first mapped.
If this value is NULL (default), it's up to the compositor to choose
which display will be used to map this surface.
When fullscreen or maximized state are set on this surface, and it
wasn't mapped yet, the output set with this method will be used.
Otherwise, the output where the surface is currently mapped will be
used.
</description>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<request name="set_fullscreen">
<description summary="set the surface state as fullscreen">
Set the surface as fullscreen.
The compositor must reply to this request with a configure event
with the dimensions for the output on which the surface will be
made fullscreen.
Once the fullscreen state is set, a "fullscreen_set" event will
be sent to the client.
Setting one state won't unset another state. Use
xdg_surface.unset_fullscreen for unsetting it.
</description>
</request>
<request name="unset_fullscreen">
<description summary="unset the surface state as fullscreen">
Unset the surface fullscreen state.
</description>
</request>
<request name="set_maximized">
<description summary="set the surface state as maximized">
Set the surface as maximized.
The compositor must reply to this request with a configure event
with the dimensions for the output on which the surface will be
made maximized.
Once the maximized state is set, a "maximized_set" event will be
sent to the client.
Setting one state won't unset another state. Use
xdg_surface.unset_maximized for unsetting it.
</description>
</request>
<request name="unset_maximized">
<description summary="unset the surface state as maximized">
Unset the surface maximized state.
</description>
</request>
<request name="set_minimized">
<description summary="set the surface state as minimized">
Set the surface minimized state.
Setting one state won't unset another state.
</description>
</request>
<event name="focused_set">
<description summary="surface was focused">
The focused_set event is sent when this surface has been
activated. Window decorations should be updated accordingly.
</description>
</event>
<event name="focused_unset">
<description summary="surface was unfocused">
The focused_unset event is sent when this surface has been
deactivated, because another surface has been activated. Window
decorations should be updated accordingly.
</description>
</event>
</interface>
<interface name="xdg_popup" version="1">
<description summary="desktop-style metadata interface">
An interface that may be implemented by a wl_surface, for
implementations that provide a desktop-style popups/menus. A popup
surface is a transient surface with an added pointer grab.
An existing implicit grab will be changed to owner-events mode,
and the popup grab will continue after the implicit grab ends
(i.e. releasing the mouse button does not cause the popup to be
unmapped).
The popup grab continues until the window is destroyed or a mouse
button is pressed in any other clients window. A click in any of
the clients surfaces is reported as normal, however, clicks in
other clients surfaces will be discarded and trigger the callback.
The x and y arguments specify the locations of the upper left
corner of the surface relative to the upper left corner of the
parent surface, in surface local coordinates.
xdg_popup surfaces are always transient for another surface.
</description>
<request name="destroy" type="destructor">
<description summary="remove xdg_surface interface">
The xdg_surface interface is removed from the wl_surface object
that was turned into a xdg_surface with
xdg_shell.get_xdg_surface request. The xdg_surface properties,
like maximized and fullscreen, are lost. The wl_surface loses
its role as a xdg_surface. The wl_surface is unmapped.
</description>
</request>
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
the client may be deemed unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
<event name="ping">
<description summary="ping client">
Ping a client to check if it is receiving events and sending
requests. A client is expected to reply with a pong request.
</description>
<arg name="serial" type="uint"/>
</event>
<event name="popup_done">
<description summary="popup interaction is done">
The popup_done event is sent out when a popup grab is broken,
that is, when the users clicks a surface that doesn't belong
to the client owning the popup surface.
</description>
<arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
</event>
</interface>
</protocol>

View File

@@ -43,9 +43,6 @@ mutter_built_sources = \
wayland/gtk-shell-protocol.c \
wayland/gtk-shell-server-protocol.h \
wayland/gtk-shell-client-protocol.h \
wayland/xdg-shell-protocol.c \
wayland/xdg-shell-server-protocol.h \
wayland/xdg-shell-client-protocol.h \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h \
wayland/xserver-client-protocol.h
@@ -55,6 +52,7 @@ libmutter_wayland_la_SOURCES = \
core/async-getprop.h \
core/barrier.c \
meta/barrier.h \
core/barrier-private.h \
core/bell.c \
core/bell.h \
core/boxes.c \
@@ -80,8 +78,6 @@ libmutter_wayland_la_SOURCES = \
compositor/meta-shadow-factory-private.h \
compositor/meta-shaped-texture.c \
compositor/meta-shaped-texture-private.h \
compositor/meta-surface-actor.c \
compositor/meta-surface-actor.h \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \
@@ -188,9 +184,7 @@ libmutter_wayland_la_SOURCES = \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
ui/ui.c
nodist_libmutter_wayland_la_SOURCES = \
ui/ui.c \
$(mutter_built_sources)
libmutter_wayland_la_SOURCES += \
@@ -304,7 +298,7 @@ Meta-$(api_version).gir: libmutter-wayland.la
@META_GIR@_FILES = \
mutter-enum-types.h \
$(libmutterinclude_base_headers) \
$(filter %.c,$(libmutter_wayland_la_SOURCES) $(nodist_libmutter_wayland_la_SOURCES))
$(filter %.c,$(libmutter_wayland_la_SOURCES))
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
endif
@@ -402,6 +396,7 @@ $(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
--generate-c-code meta-dbus-xrandr \
$(srcdir)/xrandr.xml
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
$(AM_V_GEN)gdbus-codegen \

View File

@@ -650,6 +650,11 @@ redirect_windows (MetaCompositor *compositor,
guint n_retries;
guint max_retries;
/* If we're running with wayland, connected to a headless xwayland
* server then all the windows are implicitly redirected offscreen
* already and it would generate an error to try and explicitly
* redirect them via XCompositeRedirectSubwindows() */
if (meta_get_replace_current_wm ())
max_retries = 5;
else
@@ -787,6 +792,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
clutter_actor_add_child (info->stage, info->window_group);
clutter_actor_add_child (info->stage, info->top_window_group);
info->plugin_mgr = meta_plugin_manager_new (screen);
if (meta_is_wayland_compositor ())
{
/* NB: When running as a wayland compositor we don't need an X
@@ -796,6 +803,13 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
}
else
{
/*
* Delay the creation of the overlay window as long as we can, to avoid
* blanking out the screen. This means that during the plugin loading, the
* overlay window is not accessible; if the plugin needs to access it
* directly, it should hook into the "show" signal on stage, and do
* its stuff there.
*/
info->output = get_output_window (screen);
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
@@ -816,8 +830,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
info->pending_input_region = None;
}
info->plugin_mgr = meta_plugin_manager_new (screen);
/* Map overlay window before redirecting windows offscreen so we catch their
* contents until we show the stage.
*/
@@ -864,7 +876,7 @@ meta_shape_cow_for_window (MetaScreen *screen,
int width, height;
MetaRectangle rect;
meta_window_get_frame_rect (metaWindow, &rect);
meta_window_get_outer_rect (metaWindow, &rect);
window_bounds.x = rect.x;
window_bounds.y = rect.y;

View File

@@ -28,9 +28,17 @@
#define __META_SHAPED_TEXTURE_PRIVATE_H__
#include <meta/meta-shaped-texture.h>
#include "meta-wayland-private.h"
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
ClutterActor *meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface);
void meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
MetaWaylandSurface *surface);
MetaWaylandSurface *meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex);
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
Pixmap pixmap);
void meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
MetaWaylandBuffer *buffer);
#endif

View File

@@ -31,13 +31,15 @@
#include <meta/meta-shaped-texture.h>
#include <meta/util.h>
#include "clutter-utils.h"
#include "meta-texture-tower.h"
#include "meta-shaped-texture-private.h"
#include "meta-wayland-private.h"
#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
static void meta_shaped_texture_dispose (GObject *object);
@@ -58,7 +60,15 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_ACTOR);
typedef enum _MetaShapedTextureType
{
META_SHAPED_TEXTURE_TYPE_X11_PIXMAP,
META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE,
} MetaShapedTextureType;
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
CLUTTER_TYPE_ACTOR);
#define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
@@ -68,7 +78,18 @@ struct _MetaShapedTexturePrivate
{
MetaTextureTower *paint_tower;
MetaShapedTextureType type;
union {
struct {
Pixmap pixmap;
} x11;
struct {
MetaWaylandSurface *surface;
} wayland;
};
CoglTexture *texture;
CoglTexture *mask_texture;
cairo_region_t *clip_region;
@@ -106,7 +127,9 @@ meta_shaped_texture_init (MetaShapedTexture *self)
priv->paint_tower = meta_texture_tower_new ();
priv->type = META_SHAPED_TEXTURE_TYPE_X11_PIXMAP;
priv->texture = NULL;
priv->mask_texture = NULL;
priv->create_mipmaps = TRUE;
}
@@ -196,8 +219,10 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
x1, y1, x2, y2,
&coords[0], 8);
}
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
@@ -240,9 +265,6 @@ set_cogl_texture (MetaShapedTexture *stex,
* know how much of the buffer has changed with respect to the
* previous buffer. We only queue a redraw in response to surface
* damage. */
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
}
static void
@@ -258,7 +280,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
CoglTexture *paint_tex;
ClutterActorBox alloc;
cairo_region_t *blended_region = NULL;
CoglPipelineFilter filter;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
@@ -295,22 +316,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
/* Use nearest-pixel interpolation if the texture is unscaled. This
* improves performance, especially with software rendering.
*/
filter = COGL_PIPELINE_FILTER_LINEAR;
if (!clutter_actor_is_in_clone_paint (actor))
{
int x_origin, y_origin;
if (meta_actor_is_untransformed (actor,
&x_origin,
&y_origin))
filter = COGL_PIPELINE_FILTER_NEAREST;
}
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
@@ -339,7 +344,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
opaque_pipeline = get_unblended_pipeline (ctx);
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
n_rects = cairo_region_num_rectangles (region);
for (i = 0; i < n_rects; i++)
@@ -381,11 +385,9 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
pipeline = get_masked_pipeline (ctx);
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
cogl_pipeline_set_layer_filters (pipeline, 1, filter, filter);
}
cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (pipeline, 0, filter, filter);
{
CoglColor color;
@@ -545,6 +547,48 @@ meta_shaped_texture_get_paint_volume (ClutterActor *self,
return clutter_paint_volume_set_from_allocation (volume, self);
}
ClutterActor *
meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface)
{
ClutterActor *actor = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (actor)->priv;
/* XXX: it could probably be better to have a "type" construct-only
* property or create wayland/x11 subclasses */
priv->type = META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE;
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (actor),
surface);
return actor;
}
void
meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
MetaWaylandSurface *surface)
{
MetaShapedTexturePrivate *priv = stex->priv;
priv->wayland.surface = surface;
if (surface && surface->buffer_ref.buffer)
meta_shaped_texture_attach_wayland_buffer (stex,
surface->buffer_ref.buffer);
}
MetaWaylandSurface *
meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
return priv->wayland.surface;
}
ClutterActor *
meta_shaped_texture_new_with_xwindow (Window xwindow)
{
return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
}
void
meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps)
@@ -587,6 +631,66 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
static void
wayland_surface_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height)
{
MetaShapedTexturePrivate *priv;
MetaWaylandBuffer *buffer;
priv = stex->priv;
g_return_if_fail (priv->type == META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE);
g_return_if_fail (priv->texture != NULL);
buffer = priv->wayland.surface->buffer_ref.buffer;
if (buffer)
{
struct wl_resource *resource = buffer->resource;
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
if (shm_buffer)
{
CoglPixelFormat format;
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888;
break;
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888;
break;
#endif
default:
g_warn_if_reached ();
format = COGL_PIXEL_FORMAT_ARGB_8888;
}
cogl_texture_set_region (priv->texture,
x, y,
x, y,
width, height,
width, height,
format,
wl_shm_buffer_get_stride (shm_buffer),
wl_shm_buffer_get_data (shm_buffer));
}
}
}
static gboolean
get_clip (MetaShapedTexture *stex,
int x,
@@ -645,8 +749,8 @@ get_clip (MetaShapedTexture *stex,
* has a mapped clone)
*
* Repairs the damaged area indicated by @x, @y, @width and @height
* and queues a redraw for the intersection @unobscured_region and
* the damage area. If @unobscured_region is %NULL a redraw will always
* and queues a redraw for the intersection @visibible_region and
* the damage area. If @visibible_region is %NULL a redraw will always
* get queued.
*
* Return value: Whether a redraw have been queued or not
@@ -668,6 +772,17 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
if (priv->texture == NULL)
return FALSE;
switch (priv->type)
{
case META_SHAPED_TEXTURE_TYPE_X11_PIXMAP:
cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
x, y, width, height);
break;
case META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE:
wayland_surface_update_area (stex, x, y, width, height);
break;
}
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
has_clip = get_clip (stex, x, y, width, height, &clip);
@@ -707,17 +822,66 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
}
/**
* meta_shaped_texture_set_texture:
* meta_shaped_texture_set_pixmap:
* @stex: The #MetaShapedTexture
* @pixmap: The #CoglTexture to display
* @pixmap: The pixmap you want the stex to assume
*/
void
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture)
meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
Pixmap pixmap)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
set_cogl_texture (stex, texture);
priv = stex->priv;
if (priv->x11.pixmap == pixmap)
return;
priv->x11.pixmap = pixmap;
if (pixmap != None)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglTexture *texture =
COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
set_cogl_texture (stex, texture);
}
else
set_cogl_texture (stex, NULL);
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower,
COGL_TEXTURE (priv->texture));
}
void
meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
MetaWaylandBuffer *buffer)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
/* TODO: we should change this api to be something like
* meta_shaped_texture_notify_buffer_attach() since we now maintain
* a reference to the MetaWaylandSurface where we can access the
* buffer without it being explicitly passed as an argument.
*/
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
if (buffer)
set_cogl_texture (stex, buffer->texture);
else
set_cogl_texture (stex, NULL);
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower,
COGL_TEXTURE (priv->texture));
}
/**
@@ -928,9 +1092,3 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
return surface;
}
ClutterActor *
meta_shaped_texture_new (void)
{
return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
}

View File

@@ -1,149 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:meta-surface-actor
* @title: MetaSurfaceActor
* @short_description: An actor representing a surface in the scene graph
*
* A surface can be either a shaped texture, or a group of shaped texture,
* used to draw the content of a window.
*/
#include <config.h>
#include <clutter/clutter.h>
#include <cogl/cogl-wayland-server.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <meta/meta-shaped-texture.h>
#include "meta-surface-actor.h"
#include "meta-shaped-texture-private.h"
struct _MetaSurfaceActorPrivate
{
MetaShapedTexture *texture;
MetaWaylandBuffer *buffer;
Pixmap pixmap;
};
G_DEFINE_TYPE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR);
static void
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
{
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
}
static void
meta_surface_actor_init (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv;
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_SURFACE_ACTOR,
MetaSurfaceActorPrivate);
priv->texture = NULL;
}
MetaSurfaceActor *
meta_surface_actor_new (void)
{
MetaSurfaceActor *self = g_object_new (META_TYPE_SURFACE_ACTOR, NULL);
MetaShapedTexture *stex;
stex = META_SHAPED_TEXTURE (meta_shaped_texture_new ());
self->priv->texture = stex;
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (stex));
return self;
}
cairo_surface_t *
meta_surface_actor_get_image (MetaSurfaceActor *self,
cairo_rectangle_int_t *clip)
{
return meta_shaped_texture_get_image (self->priv->texture, clip);
}
MetaShapedTexture *
meta_surface_actor_get_texture (MetaSurfaceActor *self)
{
return self->priv->texture;
}
void
meta_surface_actor_set_clip_region (MetaSurfaceActor *self,
cairo_region_t *clip_region)
{
meta_shaped_texture_set_clip_region (self->priv->texture, clip_region);
}
static void
update_area (MetaSurfaceActor *self,
int x, int y, int width, int height)
{
MetaSurfaceActorPrivate *priv = self->priv;
if (meta_is_wayland_compositor ())
{
struct wl_resource *resource = priv->buffer->resource;
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
if (shm_buffer)
{
CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
cogl_wayland_texture_2d_update_area (texture, shm_buffer, x, y, width, height);
}
}
else
{
CoglTexturePixmapX11 *texture = COGL_TEXTURE_PIXMAP_X11 (meta_shaped_texture_get_texture (priv->texture));
cogl_texture_pixmap_x11_update_area (texture, x, y, width, height);
}
}
gboolean
meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region)
{
MetaSurfaceActorPrivate *priv = self->priv;
CoglTexture *texture = meta_shaped_texture_get_texture (priv->texture);
update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
return meta_shaped_texture_update_area (self->priv->texture,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture),
unobscured_region);
}
gboolean
meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region)
{
update_area (self, x, y, width, height);
return meta_shaped_texture_update_area (self->priv->texture,
x, y, width, height,
unobscured_region);
}
void
meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self,
MetaWaylandBuffer *buffer)
{
MetaSurfaceActorPrivate *priv = self->priv;
priv->buffer = buffer;
meta_shaped_texture_set_texture (self->priv->texture, buffer->texture);
}
void
meta_surface_actor_set_texture (MetaSurfaceActor *self,
CoglTexture *texture)
{
meta_shaped_texture_set_texture (self->priv->texture, texture);
}

View File

@@ -1,66 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_SURFACE_ACTOR_PRIVATE_H
#define META_SURFACE_ACTOR_PRIVATE_H
#include <config.h>
#include <meta/meta-shaped-texture.h>
#include "meta-wayland-private.h"
G_BEGIN_DECLS
#define META_TYPE_SURFACE_ACTOR (meta_surface_actor_get_type())
#define META_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActor))
#define META_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass))
#define META_IS_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR))
#define META_IS_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR))
#define META_SURFACE_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass))
typedef struct _MetaSurfaceActor MetaSurfaceActor;
typedef struct _MetaSurfaceActorClass MetaSurfaceActorClass;
typedef struct _MetaSurfaceActorPrivate MetaSurfaceActorPrivate;
struct _MetaSurfaceActorClass
{
/*< private >*/
ClutterActorClass parent_class;
};
struct _MetaSurfaceActor
{
ClutterActor parent;
MetaSurfaceActorPrivate *priv;
};
GType meta_surface_actor_get_type (void);
MetaSurfaceActor *meta_surface_actor_new (void);
cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self,
cairo_rectangle_int_t *clip);
MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
void meta_surface_actor_set_clip_region (MetaSurfaceActor *self,
cairo_region_t *clip_region);
gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self,
cairo_region_t *unobscured_region);
gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region);
void meta_surface_actor_set_texture (MetaSurfaceActor *self,
CoglTexture *texture);
void meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self,
MetaWaylandBuffer *buffer);
G_END_DECLS
#endif /* META_SURFACE_ACTOR_PRIVATE_H */

View File

@@ -10,7 +10,6 @@
#include <X11/extensions/Xdamage.h>
#include <meta/compositor-mutter.h>
#include "meta-surface-actor.h"
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
@@ -36,6 +35,8 @@ void meta_window_actor_process_wayland_damage (MetaWindowActor *self,
int y,
int width,
int height);
void meta_window_actor_set_wayland_surface (MetaWindowActor *self,
MetaWaylandSurface *surface);
void meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
MetaWaylandBuffer *buffer);
@@ -81,6 +82,4 @@ void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

View File

@@ -30,7 +30,6 @@
#include "meta-shaped-texture-private.h"
#include "meta-shadow-factory-private.h"
#include "meta-window-actor-private.h"
#include "meta-surface-actor.h"
#include "meta-texture-rectangle.h"
#include "region-utils.h"
#include "meta-wayland-private.h"
@@ -51,9 +50,7 @@ struct _MetaWindowActorPrivate
Window xwindow;
MetaScreen *screen;
MetaSurfaceActor *surface;
guint surface_allocation_changed_id;
ClutterActor *actor;
/* MetaShadowFactory only caches shadows that are actually in use;
* to avoid unnecessary recomputation we do two things: 1) we store
@@ -301,8 +298,6 @@ meta_window_actor_init (MetaWindowActor *self)
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_WINDOW_ACTOR,
MetaWindowActorPrivate);
priv->surface_allocation_changed_id = 0;
priv->opacity = 0xff;
priv->shadow_class = NULL;
}
@@ -364,17 +359,6 @@ window_appears_focused_notify (MetaWindow *mw,
clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
}
static void
surface_allocation_changed_notify (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
MetaWindowActor *self)
{
meta_window_actor_sync_actor_geometry (self, FALSE);
g_signal_emit (self, signals[SIZE_CHANGED], 0);
}
static void
meta_window_actor_constructed (GObject *object)
{
@@ -405,18 +389,17 @@ meta_window_actor_constructed (GObject *object)
priv->argb32 = TRUE;
}
if (!priv->surface)
if (!priv->actor)
{
priv->surface = meta_surface_actor_new ();
if (meta_is_wayland_compositor ())
priv->actor = meta_shaped_texture_new_with_wayland_surface (window->surface);
else
priv->actor = meta_shaped_texture_new_with_xwindow (xwindow);
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
priv->surface_allocation_changed_id =
g_signal_connect (CLUTTER_ACTOR (priv->surface),
"allocation-changed",
G_CALLBACK (surface_allocation_changed_notify),
self);
if (meta_is_wayland_compositor ())
clutter_actor_set_reactive (priv->actor, TRUE);
/*
* Since we are holding a pointer to this actor independently of the
@@ -425,7 +408,7 @@ meta_window_actor_constructed (GObject *object)
* via the container interface, we do not end up with a dangling pointer.
* We will release it in dispose().
*/
g_object_ref (priv->surface);
g_object_ref (priv->actor);
g_signal_connect_object (window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
@@ -438,7 +421,7 @@ meta_window_actor_constructed (GObject *object)
* This is the case where existing window is gaining/loosing frame.
* Just ensure the actor is top most (i.e., above shadow).
*/
clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface), NULL);
clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (self), priv->actor, NULL);
}
meta_window_actor_update_opacity (self);
@@ -503,15 +486,10 @@ meta_window_actor_dispose (GObject *object)
g_clear_object (&priv->window);
if (priv->surface != NULL && priv->surface_allocation_changed_id != 0)
g_signal_handler_disconnect (priv->surface,
priv->surface_allocation_changed_id);
priv->surface_allocation_changed_id = 0;
/*
* Release the extra reference we took on the actor.
*/
g_clear_object (&priv->surface);
g_clear_object (&priv->actor);
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
}
@@ -907,21 +885,7 @@ meta_window_actor_get_meta_window (MetaWindowActor *self)
ClutterActor *
meta_window_actor_get_texture (MetaWindowActor *self)
{
return CLUTTER_ACTOR (meta_surface_actor_get_texture (self->priv->surface));
}
/**
* meta_window_actor_get_surface:
* @self: a #MetaWindowActor
*
* Gets the MetaSurfaceActor that draws the content of this window
*
* Return value: (transfer none): the #MetaSurfaceActor for the contents
*/
MetaSurfaceActor *
meta_window_actor_get_surface (MetaWindowActor *self)
{
return self->priv->surface;
return self->priv->actor;
}
/**
@@ -998,8 +962,8 @@ meta_window_actor_freeze (MetaWindowActor *self)
self->priv->freeze_count++;
}
static gboolean
send_frame_messages_timeout (gpointer data)
static
gboolean send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
@@ -1043,7 +1007,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
}
interval = (int)(1000000 / refresh_rate) * 6;
offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000;
offset = MAX (0, current_time - priv->frame_drawn_time + interval) / 1000;
/* The clutter master clock source has already been added with META_PRIORITY_REDRAW,
* so the timer will run *after* the clutter frame handling, if a frame is ready
@@ -1056,22 +1020,26 @@ static void
meta_window_actor_damage_all (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *unobscured_region;
CoglTexture *texture;
gboolean redraw_queued;
if (!priv->needs_damage_all)
return;
texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
if (!priv->mapped || priv->needs_pixmap)
return;
unobscured_region =
clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
? NULL : priv->unobscured_region;
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture),
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
redraw_queued = meta_surface_actor_damage_all (priv->surface, unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
priv->needs_damage_all = FALSE;
}
@@ -1155,7 +1123,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
else if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
{
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
priv->repaint_scheduled = TRUE;
}
}
@@ -1198,7 +1166,7 @@ meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self)
*
* The compositor paint function repairs all windows.
*/
clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
clutter_actor_queue_redraw (priv->actor);
}
static gboolean
@@ -1288,7 +1256,7 @@ meta_window_actor_after_effects (MetaWindowActor *self)
meta_window_actor_detach_x11_pixmap (self);
if (priv->needs_pixmap)
clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
clutter_actor_queue_redraw (priv->actor);
}
}
@@ -1384,7 +1352,8 @@ meta_window_actor_detach_x11_pixmap (MetaWindowActor *self)
* you are supposed to be able to free a GLXPixmap after freeing the underlying
* pixmap, but it certainly doesn't work with current DRI/Mesa
*/
meta_surface_actor_set_texture (priv->surface, NULL);
meta_shaped_texture_set_pixmap (META_SHAPED_TEXTURE (priv->actor),
None);
cogl_flush();
XFreePixmap (xdisplay, priv->back_pixmap);
@@ -1462,6 +1431,9 @@ meta_window_actor_destroy (MetaWindowActor *self)
priv = self->priv;
if (meta_is_wayland_compositor ())
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor), NULL);
window = priv->window;
window_type = meta_window_get_window_type (window);
meta_window_set_compositor_private (window, NULL);
@@ -1916,7 +1888,8 @@ meta_window_actor_set_clip_region (MetaWindowActor *self,
{
MetaWindowActorPrivate *priv = self->priv;
meta_surface_actor_set_clip_region (priv->surface, clip_region);
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
clip_region);
}
/**
@@ -1963,7 +1936,8 @@ meta_window_actor_reset_clip_regions (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
meta_surface_actor_set_clip_region (priv->surface, NULL);
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
NULL);
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
}
@@ -1978,6 +1952,7 @@ check_needs_x11_pixmap (MetaWindowActor *self)
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaCompositor *compositor;
Window xwindow = priv->xwindow;
if (!priv->needs_pixmap)
@@ -1990,6 +1965,8 @@ check_needs_x11_pixmap (MetaWindowActor *self)
xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)))
return;
compositor = meta_display_get_compositor (display);
if (priv->x11_size_changed)
{
meta_window_actor_detach_x11_pixmap (self);
@@ -2000,7 +1977,6 @@ check_needs_x11_pixmap (MetaWindowActor *self)
if (priv->back_pixmap == None)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglTexture *texture;
meta_error_trap_push (display);
@@ -2025,13 +2001,24 @@ check_needs_x11_pixmap (MetaWindowActor *self)
goto out;
}
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
if (compositor->no_mipmaps)
meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor),
FALSE);
meta_shaped_texture_set_pixmap (META_SHAPED_TEXTURE (priv->actor),
priv->back_pixmap);
texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
/*
* This only works *after* actually setting the pixmap, so we have to
* do it here.
* See: http://bugzilla.clutter-project.org/show_bug.cgi?id=2236
*/
if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
g_warning ("NOTE: Not using GLX TFP!\n");
meta_surface_actor_set_texture (META_SURFACE_ACTOR (priv->surface), texture);
/* ::size-changed is supposed to refer to meta_window_get_frame_rect().
/* ::size-changed is supposed to refer to meta_window_get_outer_rect().
* Emitting it here works pretty much OK because a new value of the
* *input* rect (which is the outer rect with the addition of invisible
* borders) forces a new pixmap and we get here. In the rare case where
@@ -2121,14 +2108,13 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
gboolean redraw_queued;
cairo_region_t *unobscured_region;
priv->received_x11_damage = TRUE;
if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected)
{
MetaRectangle window_rect;
meta_window_get_frame_rect (priv->window, &window_rect);
meta_window_get_outer_rect (priv->window, &window_rect);
if (window_rect.x == event->area.x &&
window_rect.y == event->area.y &&
@@ -2169,15 +2155,13 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
if (!priv->mapped || priv->needs_pixmap)
return;
unobscured_region =
clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
? NULL : priv->unobscured_region;
redraw_queued = meta_surface_actor_damage_area (priv->surface,
event->area.x,
event->area.y,
event->area.width,
event->area.height,
unobscured_region);
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
event->area.x,
event->area.y,
event->area.width,
event->area.height,
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
@@ -2191,18 +2175,15 @@ meta_window_actor_process_wayland_damage (MetaWindowActor *self,
int height)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *unobscured_region;
gboolean redraw_queued;
if (!priv->mapped)
return;
unobscured_region =
clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
? NULL : priv->unobscured_region;
redraw_queued = meta_surface_actor_damage_area (priv->surface,
x, y, width, height,
unobscured_region);
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
x, y, width, height,
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
}
@@ -2266,18 +2247,12 @@ build_and_scan_frame_mask (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
guchar *mask_data;
guint tex_width, tex_height;
MetaShapedTexture *stex;
CoglTexture *paint_tex, *mask_texture;
int stride;
cairo_t *cr;
cairo_surface_t *surface;
stex = meta_surface_actor_get_texture (priv->surface);
g_return_if_fail (stex);
meta_shaped_texture_set_mask_texture (stex, NULL);
paint_tex = meta_shaped_texture_get_texture (stex);
paint_tex = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
if (paint_tex == NULL)
return;
@@ -2345,7 +2320,8 @@ build_and_scan_frame_mask (MetaWindowActor *self,
mask_data);
}
meta_shaped_texture_set_mask_texture (stex, mask_texture);
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor),
mask_texture);
cogl_object_unref (mask_texture);
g_free (mask_data);
@@ -2375,6 +2351,7 @@ meta_window_actor_update_shape_region (MetaWindowActor *self,
region = cairo_region_create_rectangle (client_area);
}
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
build_and_scan_frame_mask (self, client_area, region);
@@ -2391,12 +2368,9 @@ meta_window_actor_update_input_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShapedTexture *stex = meta_surface_actor_get_texture (priv->surface);
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
cairo_region_t *region = NULL;
if (!stex)
return;
if (priv->window->frame != NULL && priv->window->input_region != NULL)
{
region = meta_frame_get_frame_bounds (priv->window->frame);
@@ -2429,11 +2403,6 @@ static void
meta_window_actor_update_opaque_region (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShapedTexture *stex;
stex = meta_surface_actor_get_texture (priv->surface);
if (!stex)
return;
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
@@ -2462,7 +2431,8 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
else
priv->opaque_region = cairo_region_reference (priv->shape_region);
meta_shaped_texture_set_opaque_region (stex, priv->opaque_region);
meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
priv->opaque_region);
}
static void
@@ -2505,7 +2475,52 @@ meta_window_actor_update_shape (MetaWindowActor *self)
if (is_frozen (self))
return;
clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
clutter_actor_queue_redraw (priv->actor);
}
static void
maybe_emit_size_changed (MetaWindowActor *self,
MetaWaylandBuffer *new_buffer)
{
MetaWindowActorPrivate *priv = self->priv;
int width = 0, height = 0;
if (new_buffer)
{
width = new_buffer->width;
height = new_buffer->height;
}
if (priv->last_width != width || priv->last_height != height)
{
meta_window_actor_update_shape (self);
/* ::size-changed is supposed to refer to meta_window_get_outer_rect()
* but here we are only looking at buffer size changes.
*
* Emitting it here works pretty much OK because a new buffer size (which
* will correspond to the outer rect with the addition of invisible
* borders) also normally implies a change to the outer rect. In the rare
* case where a change to the window size was exactly balanced by a
* change to the invisible borders, we would miss emitting the signal.
*/
g_signal_emit (self, signals[SIZE_CHANGED], 0);
priv->last_width = width;
priv->last_height = height;
}
}
void
meta_window_actor_set_wayland_surface (MetaWindowActor *self,
MetaWaylandSurface *surface)
{
MetaWindowActorPrivate *priv = self->priv;
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor),
surface);
if (surface && surface->buffer_ref.buffer)
maybe_emit_size_changed (self, surface->buffer_ref.buffer);
}
void
@@ -2513,7 +2528,15 @@ meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
MetaWaylandBuffer *buffer)
{
MetaWindowActorPrivate *priv = self->priv;
meta_surface_actor_attach_wayland_buffer (priv->surface, buffer);
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
CoglTexture *prev_tex = meta_shaped_texture_get_texture (stex);
meta_shaped_texture_attach_wayland_buffer (stex, buffer);
if (!prev_tex)
meta_window_actor_sync_actor_geometry (self, FALSE);
maybe_emit_size_changed (self, buffer);
}
static void
@@ -2765,7 +2788,7 @@ meta_window_actor_update_opacity (MetaWindowActor *self)
opacity = 255;
self->priv->opacity = opacity;
clutter_actor_set_opacity (CLUTTER_ACTOR (self->priv->surface), opacity);
clutter_actor_set_opacity (self->priv->actor, opacity);
}
void

View File

@@ -163,7 +163,7 @@ meta_window_group_paint (ClutterActor *actor)
cairo_rectangle_int_t unredirected_rect;
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
meta_window_get_frame_rect (window, (MetaRectangle *)&unredirected_rect);
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
}

View File

@@ -0,0 +1,39 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/*
* Copyright 2012, 2013 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Authors: Jaster St. Pierre <jstpierr@redhat.com>
* Giovanni Campagna <gcampagn@redhat.com>
*/
#ifndef BARRIER_PRIVATE_H
#define BARRIER_PRIVATE_H
typedef struct _MetaBarrierManager MetaBarrierManager;
MetaBarrierManager *meta_barrier_manager_get (void);
void meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager,
guint32 time,
float current_x,
float current_y,
float *new_x,
float *new_y);
#endif

View File

@@ -1,5 +1,27 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/*
* Copyright 2012, 2013 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Authors: Jaster St. Pierre <jstpierr@redhat.com>
* Giovanni Campagna <gcampagn@redhat.com>
*/
/**
* SECTION:barrier
* @Title: MetaBarrier
@@ -9,6 +31,7 @@
#include "config.h"
#include <glib-object.h>
#include <math.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xfixes.h>
@@ -16,6 +39,7 @@
#include <meta/barrier.h>
#include "display-private.h"
#include "mutter-enum-types.h"
#include "barrier-private.h"
#include "core.h"
G_DEFINE_TYPE (MetaBarrier, meta_barrier, G_TYPE_OBJECT)
@@ -56,9 +80,23 @@ struct _MetaBarrierPrivate
MetaBarrierDirection directions;
/* x11 */
PointerBarrier xbarrier;
/* wayland */
gboolean active;
gboolean seen, hit;
int barrier_event_id;
int release_event_id;
guint32 last_timestamp;
};
struct _MetaBarrierManager
{
GList *barriers;
} *global_barrier_manager;
static void meta_barrier_event_unref (MetaBarrierEvent *event);
static void
@@ -148,7 +186,10 @@ meta_barrier_dispose (GObject *object)
gboolean
meta_barrier_is_active (MetaBarrier *barrier)
{
return barrier->priv->xbarrier != 0;
if (meta_is_wayland_compositor ())
return barrier->priv->active;
else
return barrier->priv->xbarrier != 0;
}
/**
@@ -165,15 +206,25 @@ void
meta_barrier_release (MetaBarrier *barrier,
MetaBarrierEvent *event)
{
#ifdef HAVE_XI23
MetaBarrierPrivate *priv = barrier->priv;
if (META_DISPLAY_HAS_XINPUT_23 (priv->display))
MetaBarrierPrivate *priv;
priv = barrier->priv;
if (meta_is_wayland_compositor ())
{
XIBarrierReleasePointer (priv->display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
priv->xbarrier, event->event_id);
priv->release_event_id = event->event_id;
}
else
{
#ifdef HAVE_XI23
if (META_DISPLAY_HAS_XINPUT_23 (priv->display))
{
XIBarrierReleasePointer (priv->display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
priv->xbarrier, event->event_id);
}
#endif /* HAVE_XI23 */
}
}
static void
@@ -192,19 +243,29 @@ meta_barrier_constructed (GObject *object)
return;
}
dpy = priv->display->xdisplay;
root = DefaultRootWindow (dpy);
if (meta_is_wayland_compositor ())
{
MetaBarrierManager *manager = meta_barrier_manager_get ();
priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
priv->x1, priv->y1,
priv->x2, priv->y2,
priv->directions, 0, NULL);
manager->barriers = g_list_prepend (manager->barriers, g_object_ref (barrier));
priv->active = TRUE;
}
else
{
dpy = priv->display->xdisplay;
root = DefaultRootWindow (dpy);
/* Take a ref that we'll release when the XID dies inside destroy(),
* so that the object stays alive and doesn't get GC'd. */
g_object_ref (barrier);
priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
priv->x1, priv->y1,
priv->x2, priv->y2,
priv->directions, 0, NULL);
g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier);
/* Take a ref that we'll release when the XID dies inside destroy(),
* so that the object stays alive and doesn't get GC'd. */
g_object_ref (barrier);
g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier);
}
G_OBJECT_CLASS (meta_barrier_parent_class)->constructed (object);
}
@@ -312,16 +373,26 @@ meta_barrier_destroy (MetaBarrier *barrier)
if (priv->display == NULL)
return;
dpy = priv->display->xdisplay;
if (meta_is_wayland_compositor ())
{
MetaBarrierManager *manager = meta_barrier_manager_get ();
if (!meta_barrier_is_active (barrier))
return;
manager->barriers = g_list_remove (manager->barriers, barrier);
g_object_unref (barrier);
}
else
{
dpy = priv->display->xdisplay;
XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
g_hash_table_remove (priv->display->xids, &priv->xbarrier);
priv->xbarrier = 0;
if (!meta_barrier_is_active (barrier))
return;
g_object_unref (barrier);
XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
g_hash_table_remove (priv->display->xids, &priv->xbarrier);
priv->xbarrier = 0;
g_object_unref (barrier);
}
}
static void
@@ -366,25 +437,14 @@ meta_barrier_fire_event (MetaBarrier *barrier,
}
gboolean
meta_display_process_barrier_event (MetaDisplay *display,
XIEvent *event)
meta_display_process_barrier_event (MetaDisplay *display,
XIBarrierEvent *xev)
{
MetaBarrier *barrier;
XIBarrierEvent *xev;
if (event == NULL)
if (meta_is_wayland_compositor ())
return FALSE;
switch (event->evtype)
{
case XI_BarrierHit:
case XI_BarrierLeave:
break;
default:
return FALSE;
}
xev = (XIBarrierEvent *) event;
barrier = g_hash_table_lookup (display->xids, &xev->barrier);
if (barrier != NULL)
{
@@ -396,6 +456,405 @@ meta_display_process_barrier_event (MetaDisplay *display,
}
#endif /* HAVE_XI23 */
/*
* The following code was copied and adapted from the X server (Xi/xibarriers.c)
*
* Copyright 2012 Red Hat, Inc.
* Copyright © 2002 Keith Packard
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
static gboolean
barrier_is_horizontal(MetaBarrier *barrier)
{
return barrier->priv->y1 == barrier->priv->y2;
}
static gboolean
barrier_is_vertical(MetaBarrier *barrier)
{
return barrier->priv->x1 == barrier->priv->x2;
}
/*
* @return The set of barrier movement directions the movement vector
* x1/y1 → x2/y2 represents.
*/
static int
barrier_get_direction(int x1, int y1, int x2, int y2)
{
int direction = 0;
/* which way are we trying to go */
if (x2 > x1)
direction |= META_BARRIER_DIRECTION_POSITIVE_X;
if (x2 < x1)
direction |= META_BARRIER_DIRECTION_NEGATIVE_X;
if (y2 > y1)
direction |= META_BARRIER_DIRECTION_POSITIVE_Y;
if (y2 < y1)
direction |= META_BARRIER_DIRECTION_NEGATIVE_Y;
return direction;
}
/*
* Test if the barrier may block movement in the direction defined by
* x1/y1 → x2/y2. This function only tests whether the directions could be
* blocked, it does not test if the barrier actually blocks the movement.
*
* @return TRUE if the barrier blocks the direction of movement or FALSE
* otherwise.
*/
static gboolean
barrier_is_blocking_direction(MetaBarrier *barrier,
MetaBarrierDirection direction)
{
/* Barriers define which way is ok, not which way is blocking */
return (barrier->priv->directions & direction) != direction;
}
static gboolean
inside_segment(int v, int v1, int v2)
{
if (v1 < 0 && v2 < 0) /* line */
return TRUE;
else if (v1 < 0) /* ray */
return v <= v2;
else if (v2 < 0) /* ray */
return v >= v1;
else /* line segment */
return v >= v1 && v <= v2;
}
#define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
#define F(t, a, b) ((t) * ((a) - (b)) + (a))
/*
* Test if the movement vector x1/y1 → x2/y2 is intersecting with the
* barrier. A movement vector with the startpoint or endpoint adjacent to
* the barrier itself counts as intersecting.
*
* @param x1 X start coordinate of movement vector
* @param y1 Y start coordinate of movement vector
* @param x2 X end coordinate of movement vector
* @param y2 Y end coordinate of movement vector
* @param[out] distance The distance between the start point and the
* intersection with the barrier (if applicable).
* @return TRUE if the barrier intersects with the given vector
*/
static gboolean
barrier_is_blocking(MetaBarrier *barrier,
int x1, int y1, int x2, int y2, double *distance)
{
if (barrier_is_vertical (barrier))
{
float t, y;
t = T (barrier->priv->x1, x1, x2);
if (t < 0 || t > 1)
return FALSE;
/* Edge case: moving away from barrier. */
if (x2 > x1 && t == 0)
return FALSE;
y = F (t, y1, y2);
if (!inside_segment (y, barrier->priv->y1, barrier->priv->y2))
return FALSE;
*distance = sqrt ((y - y1) * (y - y1) + (barrier->priv->x1 - x1) * (barrier->priv->x1 - x1));
return TRUE;
}
else
{
float t, x;
t = T (barrier->priv->y1, y1, y2);
if (t < 0 || t > 1)
return FALSE;
/* Edge case: moving away from barrier. */
if (y2 > y1 && t == 0)
return FALSE;
x = F(t, x1, x2);
if (!inside_segment (x, barrier->priv->x1, barrier->priv->x2))
return FALSE;
*distance = sqrt ((x - x1) * (x - x1) + (barrier->priv->y1 - y1) * (barrier->priv->y1 - y1));
return TRUE;
}
}
#define HIT_EDGE_EXTENTS 2
static gboolean
barrier_inside_hit_box(MetaBarrier *barrier, int x, int y)
{
int x1, x2, y1, y2;
int dir;
x1 = barrier->priv->x1;
x2 = barrier->priv->x2;
y1 = barrier->priv->y1;
y2 = barrier->priv->y2;
dir = ~(barrier->priv->directions);
if (barrier_is_vertical (barrier))
{
if (dir & META_BARRIER_DIRECTION_POSITIVE_X)
x1 -= HIT_EDGE_EXTENTS;
if (dir & META_BARRIER_DIRECTION_NEGATIVE_X)
x2 += HIT_EDGE_EXTENTS;
}
if (barrier_is_horizontal (barrier))
{
if (dir & META_BARRIER_DIRECTION_POSITIVE_Y)
y1 -= HIT_EDGE_EXTENTS;
if (dir & META_BARRIER_DIRECTION_NEGATIVE_Y)
y2 += HIT_EDGE_EXTENTS;
}
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}
/*
* Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
*
* @param dir Only barriers blocking movement in direction dir are checked
* @param x1 X start coordinate of movement vector
* @param y1 Y start coordinate of movement vector
* @param x2 X end coordinate of movement vector
* @param y2 Y end coordinate of movement vector
* @return The barrier nearest to the movement origin that blocks this movement.
*/
static MetaBarrier *
barrier_find_nearest(MetaBarrierManager *manager,
int dir,
int x1,
int y1,
int x2,
int y2)
{
GList *iter;
MetaBarrier *nearest = NULL;
double min_distance = INT_MAX; /* can't get higher than that in X anyway */
for (iter = manager->barriers; iter; iter = iter->next)
{
MetaBarrier *b = iter->data;
double distance;
if (b->priv->seen || !b->priv->active)
continue;
if (!barrier_is_blocking_direction (b, dir))
continue;
if (barrier_is_blocking (b, x1, y1, x2, y2, &distance))
{
if (min_distance > distance)
{
min_distance = distance;
nearest = b;
}
}
}
return nearest;
}
/*
* Clamp to the given barrier given the movement direction specified in dir.
*
* @param barrier The barrier to clamp to
* @param dir The movement direction
* @param[out] x The clamped x coordinate.
* @param[out] y The clamped x coordinate.
*/
static void
barrier_clamp_to_barrier(MetaBarrier *barrier,
int dir,
float *x,
float *y)
{
if (barrier_is_vertical (barrier))
{
if ((dir & META_BARRIER_DIRECTION_NEGATIVE_X) & ~barrier->priv->directions)
*x = barrier->priv->x1;
if ((dir & META_BARRIER_DIRECTION_POSITIVE_X) & ~barrier->priv->directions)
*x = barrier->priv->x1 - 1;
}
if (barrier_is_horizontal (barrier))
{
if ((dir & META_BARRIER_DIRECTION_NEGATIVE_Y) & ~barrier->priv->directions)
*y = barrier->priv->y1;
if ((dir & META_BARRIER_DIRECTION_POSITIVE_Y) & ~barrier->priv->directions)
*y = barrier->priv->y1 - 1;
}
}
static gboolean
emit_hit_event (gpointer data)
{
MetaBarrierEvent *event = data;
g_signal_emit (event->barrier, obj_signals[HIT], 0, event);
meta_barrier_event_unref (event);
return FALSE;
}
static gboolean
emit_left_event (gpointer data)
{
MetaBarrierEvent *event = data;
g_signal_emit (event->barrier, obj_signals[LEFT], 0, event);
meta_barrier_event_unref (event);
return FALSE;
}
void
meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager,
guint32 time,
float current_x,
float current_y,
float *new_x,
float *new_y)
{
float x = *new_x;
float y = *new_y;
int dir;
MetaBarrier *nearest = NULL;
GList *iter;
float dx = x - current_x;
float dy = y - current_y;
/* How this works:
* Given the origin and the movement vector, get the nearest barrier
* to the origin that is blocking the movement.
* Clamp to that barrier.
* Then, check from the clamped intersection to the original
* destination, again finding the nearest barrier and clamping.
*/
dir = barrier_get_direction (current_x, current_y, x, y);
while (dir != 0)
{
MetaBarrierEvent *event;
gboolean new_sequence;
nearest = barrier_find_nearest (manager, dir, current_x, current_y, x, y);
if (!nearest)
break;
new_sequence = !nearest->priv->hit;
nearest->priv->seen = TRUE;
nearest->priv->hit = TRUE;
if (nearest->priv->barrier_event_id == nearest->priv->release_event_id)
continue;
barrier_clamp_to_barrier (nearest, dir, &x, &y);
if (barrier_is_vertical (nearest))
{
dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_X | META_BARRIER_DIRECTION_POSITIVE_X);
current_x = x;
}
else if (barrier_is_horizontal (nearest))
{
dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_Y | META_BARRIER_DIRECTION_POSITIVE_Y);
current_y = y;
}
event = g_slice_new0 (MetaBarrierEvent);
event->ref_count = 1;
event->barrier = g_object_ref (nearest);
event->event_id = nearest->priv->barrier_event_id;
event->time = time;
event->dt = new_sequence ? 0 : time - nearest->priv->last_timestamp;
event->x = current_x;
event->y = current_y;
event->dx = dx;
event->dy = dy;
event->released = FALSE;
event->grabbed = FALSE;
g_idle_add (emit_hit_event, event);
}
for (iter = manager->barriers; iter; iter = iter->next)
{
MetaBarrierEvent *event;
MetaBarrier *barrier = iter->data;
if (!barrier->priv->active)
continue;
barrier->priv->seen = FALSE;
if (!barrier->priv->hit)
continue;
if (barrier_inside_hit_box (barrier, x, y))
continue;
barrier->priv->hit = FALSE;
event = g_slice_new0 (MetaBarrierEvent);
event->ref_count = 1;
event->barrier = g_object_ref (barrier);
event->event_id = barrier->priv->barrier_event_id;
event->time = time;
event->dt = time - barrier->priv->last_timestamp;
event->x = current_x;
event->y = current_y;
event->dx = dx;
event->dy = dy;
event->released = barrier->priv->barrier_event_id == barrier->priv->release_event_id;
event->grabbed = FALSE;
g_idle_add (emit_left_event, event);
/* If we've left the hit box, this is the
* start of a new event ID. */
barrier->priv->barrier_event_id++;
}
*new_x = x;
*new_y = y;
}
MetaBarrierManager *
meta_barrier_manager_get (void)
{
if (!global_barrier_manager)
global_barrier_manager = g_new0 (MetaBarrierManager, 1);
return global_barrier_manager;
}
static MetaBarrierEvent *
meta_barrier_event_ref (MetaBarrierEvent *event)
{
@@ -413,7 +872,12 @@ meta_barrier_event_unref (MetaBarrierEvent *event)
g_return_if_fail (event->ref_count > 0);
if (g_atomic_int_dec_and_test ((volatile int *)&event->ref_count))
g_slice_free (MetaBarrierEvent, event);
{
if (event->barrier)
g_object_unref (event->barrier);
g_slice_free (MetaBarrierEvent, event);
}
}
G_DEFINE_BOXED_TYPE (MetaBarrierEvent,

View File

@@ -118,6 +118,8 @@ typedef struct
{
MetaRectangle orig;
MetaRectangle current;
MetaFrameBorders *borders;
gboolean must_free_borders;
ActionType action_type;
gboolean is_user_action;
@@ -193,6 +195,7 @@ static gboolean constrain_partially_onscreen (MetaWindow *window,
static void setup_constraint_info (ConstraintInfo *info,
MetaWindow *window,
MetaFrameBorders *orig_borders,
MetaMoveResizeFlags flags,
int resize_gravity,
const MetaRectangle *orig,
@@ -201,12 +204,13 @@ static void place_window_if_needed (MetaWindow *window,
ConstraintInfo *info);
static void update_onscreen_requirements (MetaWindow *window,
ConstraintInfo *info);
static void extend_by_frame (MetaWindow *window,
MetaRectangle *rect);
static void unextend_by_frame (MetaWindow *window,
MetaRectangle *rect);
static inline void get_size_limits (MetaWindow *window,
gboolean include_frame,
static void extend_by_frame (MetaRectangle *rect,
const MetaFrameBorders *borders);
static void unextend_by_frame (MetaRectangle *rect,
const MetaFrameBorders *borders);
static inline void get_size_limits (const MetaWindow *window,
const MetaFrameBorders *borders,
gboolean include_frame,
MetaRectangle *min_size,
MetaRectangle *max_size);
@@ -276,6 +280,7 @@ do_all_constraints (MetaWindow *window,
void
meta_window_constrain (MetaWindow *window,
MetaFrameBorders *orig_borders,
MetaMoveResizeFlags flags,
int resize_gravity,
const MetaRectangle *orig,
@@ -298,6 +303,7 @@ meta_window_constrain (MetaWindow *window,
setup_constraint_info (&info,
window,
orig_borders,
flags,
resize_gravity,
orig,
@@ -327,11 +333,19 @@ meta_window_constrain (MetaWindow *window,
* if this was a user move or user move-and-resize operation.
*/
update_onscreen_requirements (window, &info);
/* Ew, what an ugly way to do things. Destructors (in a real OOP language,
* not gobject-style--gobject would be more pain than it's worth) or
* smart pointers would be so much nicer here. *shrug*
*/
if (info.must_free_borders)
g_free (info.borders);
}
static void
setup_constraint_info (ConstraintInfo *info,
MetaWindow *window,
MetaFrameBorders *orig_borders,
MetaMoveResizeFlags flags,
int resize_gravity,
const MetaRectangle *orig,
@@ -343,6 +357,18 @@ setup_constraint_info (ConstraintInfo *info,
info->orig = *orig;
info->current = *new;
/* Create a fake frame geometry if none really exists */
if (orig_borders && !window->fullscreen)
{
info->borders = orig_borders;
info->must_free_borders = FALSE;
}
else
{
info->borders = g_new0 (MetaFrameBorders, 1);
info->must_free_borders = TRUE;
}
if (flags & META_IS_MOVE_ACTION && flags & META_IS_RESIZE_ACTION)
info->action_type = ACTION_MOVE_AND_RESIZE;
else if (flags & META_IS_RESIZE_ACTION)
@@ -493,12 +519,11 @@ place_window_if_needed(MetaWindow *window,
!window->minimized &&
!window->fullscreen)
{
MetaRectangle placed_rect;
MetaRectangle placed_rect = info->orig;
MetaWorkspace *cur_workspace;
const MetaMonitorInfo *monitor_info;
meta_window_get_frame_rect (window, &placed_rect);
meta_window_place (window, info->orig.x, info->orig.y,
meta_window_place (window, info->borders, info->orig.x, info->orig.y,
&placed_rect.x, &placed_rect.y);
did_placement = TRUE;
@@ -516,7 +541,6 @@ place_window_if_needed(MetaWindow *window,
meta_workspace_get_onmonitor_region (cur_workspace,
monitor_info->number);
meta_window_frame_rect_to_client_rect (window, &placed_rect, &placed_rect);
info->current.x = placed_rect.x;
info->current.y = placed_rect.y;
@@ -562,6 +586,10 @@ place_window_if_needed(MetaWindow *window,
(window->maximize_vertically_after_placement ?
META_MAXIMIZE_VERTICAL : 0), &info->current);
/* maximization may have changed frame geometry */
if (!window->fullscreen)
meta_frame_calc_borders (window->frame, info->borders);
if (window->fullscreen_after_placement)
{
window->saved_rect = info->current;
@@ -621,7 +649,7 @@ update_onscreen_requirements (MetaWindow *window,
/* The require onscreen/on-single-monitor and titlebar_visible
* stuff is relative to the outer window, not the inner
*/
extend_by_frame (window, &info->current);
extend_by_frame (&info->current, info->borders);
/* Update whether we want future constraint runs to require the
* window to be on fully onscreen.
@@ -654,13 +682,10 @@ update_onscreen_requirements (MetaWindow *window,
*/
if (window->frame && window->decorated)
{
MetaFrameBorders borders;
MetaRectangle titlebar_rect;
meta_frame_calc_borders (window->frame, &borders);
titlebar_rect = info->current;
titlebar_rect.height = borders.visible.top;
titlebar_rect.height = info->borders->visible.top;
old = window->require_titlebar_visible;
window->require_titlebar_visible =
meta_rectangle_overlaps_with_region (info->usable_screen_region,
@@ -673,33 +698,39 @@ update_onscreen_requirements (MetaWindow *window,
}
/* Don't forget to restore the position of the window */
unextend_by_frame (window, &info->current);
unextend_by_frame (&info->current, info->borders);
}
static void
extend_by_frame (MetaWindow *window,
MetaRectangle *rect)
extend_by_frame (MetaRectangle *rect,
const MetaFrameBorders *borders)
{
meta_window_client_rect_to_frame_rect (window, rect, rect);
rect->x -= borders->visible.left;
rect->y -= borders->visible.top;
rect->width += borders->visible.left + borders->visible.right;
rect->height += borders->visible.top + borders->visible.bottom;
}
static void
unextend_by_frame (MetaWindow *window,
MetaRectangle *rect)
unextend_by_frame (MetaRectangle *rect,
const MetaFrameBorders *borders)
{
meta_window_frame_rect_to_client_rect (window, rect, rect);
rect->x += borders->visible.left;
rect->y += borders->visible.top;
rect->width -= borders->visible.left + borders->visible.right;
rect->height -= borders->visible.top + borders->visible.bottom;
}
static inline void
get_size_limits (MetaWindow *window,
gboolean include_frame,
get_size_limits (const MetaWindow *window,
const MetaFrameBorders *borders,
gboolean include_frame,
MetaRectangle *min_size,
MetaRectangle *max_size)
{
/* We pack the results into MetaRectangle structs just for convienience; we
* don't actually use the position of those rects.
*/
min_size->x = min_size->y = max_size->x = max_size->y = 0;
min_size->width = window->size_hints.min_width;
min_size->height = window->size_hints.min_height;
max_size->width = window->size_hints.max_width;
@@ -707,8 +738,22 @@ get_size_limits (MetaWindow *window,
if (include_frame)
{
meta_window_client_rect_to_frame_rect (window, min_size, min_size);
meta_window_client_rect_to_frame_rect (window, max_size, max_size);
int fw = borders->visible.left + borders->visible.right;
int fh = borders->visible.top + borders->visible.bottom;
min_size->width += fw;
min_size->height += fh;
/* Do check to avoid overflow (e.g. max_size->width & max_size->height
* may be set to G_MAXINT by meta_set_normal_hints()).
*/
if (max_size->width < (G_MAXINT - fw))
max_size->width += fw;
else
max_size->width = G_MAXINT;
if (max_size->height < (G_MAXINT - fh))
max_size->height += fh;
else
max_size->height = G_MAXINT;
}
}
@@ -720,28 +765,18 @@ constrain_modal_dialog (MetaWindow *window,
{
int x, y;
MetaWindow *parent = meta_window_get_transient_for (window);
MetaRectangle child_rect, parent_rect;
gboolean constraint_already_satisfied;
if (!meta_window_is_attached_dialog (window))
return TRUE;
/* We want to center the dialog on the parent, including the decorations
for both of them. info->current is in client X window coordinates, so we need
to convert them to frame coordinates, apply the centering and then
convert back to client.
*/
child_rect = info->current;
extend_by_frame (window, &child_rect);
meta_window_get_frame_rect (parent, &parent_rect);
child_rect.x = parent_rect.x + (parent_rect.width / 2 - child_rect.width / 2);
child_rect.y = parent_rect.y + (parent_rect.height / 2 - child_rect.height / 2);
unextend_by_frame (window, &child_rect);
x = child_rect.x;
y = child_rect.y;
x = parent->rect.x + (parent->rect.width / 2 - info->current.width / 2);
y = parent->rect.y + (parent->rect.height / 2 - info->current.height / 2);
if (parent->frame)
{
x += parent->frame->rect.x;
y += parent->frame->rect.y;
}
constraint_already_satisfied = (x == info->current.x) && (y == info->current.y);
@@ -806,19 +841,19 @@ constrain_maximization (MetaWindow *window,
active_workspace_struts = window->screen->active_workspace->all_struts;
target_size = info->current;
extend_by_frame (window, &target_size);
extend_by_frame (&target_size, info->borders);
meta_rectangle_expand_to_avoiding_struts (&target_size,
&info->entire_monitor,
direction,
active_workspace_struts);
}
/* Now make target_size = maximized size of client window */
unextend_by_frame (window, &target_size);
unextend_by_frame (&target_size, info->borders);
/* Check min size constraints; max size constraints are ignored for maximized
* windows, as per bug 327543.
*/
get_size_limits (window, FALSE, &min_size, &max_size);
get_size_limits (window, info->borders, FALSE, &min_size, &max_size);
hminbad = target_size.width < min_size.width && window->maximized_horizontally;
vminbad = target_size.height < min_size.height && window->maximized_vertically;
if (hminbad || vminbad)
@@ -872,12 +907,12 @@ constrain_tiling (MetaWindow *window,
* use an external function for the actual calculation
*/
meta_window_get_current_tile_area (window, &target_size);
unextend_by_frame (window, &target_size);
unextend_by_frame (&target_size, info->borders);
/* Check min size constraints; max size constraints are ignored as for
* maximized windows.
*/
get_size_limits (window, FALSE, &min_size, &max_size);
get_size_limits (window, info->borders, FALSE, &min_size, &max_size);
hminbad = target_size.width < min_size.width;
vminbad = target_size.height < min_size.height;
if (hminbad || vminbad)
@@ -920,7 +955,7 @@ constrain_fullscreen (MetaWindow *window,
monitor = info->entire_monitor;
get_size_limits (window, FALSE, &min_size, &max_size);
get_size_limits (window, info->borders, FALSE, &min_size, &max_size);
too_big = !meta_rectangle_could_fit_rect (&monitor, &min_size);
too_small = !meta_rectangle_could_fit_rect (&max_size, &monitor);
if (too_big || too_small)
@@ -1029,7 +1064,7 @@ constrain_size_limits (MetaWindow *window,
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
get_size_limits (window, FALSE, &min_size, &max_size);
get_size_limits (window, info->borders, FALSE, &min_size, &max_size);
/* We ignore max-size limits for maximized windows; see #327543 */
if (window->maximized_horizontally)
max_size.width = MAX (max_size.width, info->current.width);
@@ -1221,8 +1256,8 @@ do_screen_and_monitor_relative_constraints (
/* Determine whether constraint applies; exit if it doesn't */
how_far_it_can_be_smushed = info->current;
get_size_limits (window, TRUE, &min_size, &max_size);
extend_by_frame (window, &info->current);
get_size_limits (window, info->borders, TRUE, &min_size, &max_size);
extend_by_frame (&info->current, info->borders);
if (info->action_type != ACTION_MOVE)
{
@@ -1242,7 +1277,7 @@ do_screen_and_monitor_relative_constraints (
&info->current);
if (exit_early || constraint_satisfied || check_only)
{
unextend_by_frame (window, &info->current);
unextend_by_frame (&info->current, info->borders);
return constraint_satisfied;
}
@@ -1266,7 +1301,7 @@ do_screen_and_monitor_relative_constraints (
info->fixed_directions,
&info->current);
unextend_by_frame (window, &info->current);
unextend_by_frame (&info->current, info->borders);
return TRUE;
}
@@ -1379,11 +1414,8 @@ constrain_titlebar_visible (MetaWindow *window,
*/
if (window->frame)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
bottom_amount = info->current.height + borders.visible.bottom;
vert_amount_onscreen = borders.visible.top;
bottom_amount = info->current.height + info->borders->visible.bottom;
vert_amount_onscreen = info->borders->visible.top;
}
else
bottom_amount = vert_amount_offscreen;
@@ -1457,11 +1489,8 @@ constrain_partially_onscreen (MetaWindow *window,
*/
if (window->frame)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
bottom_amount = info->current.height + borders.visible.bottom;
vert_amount_onscreen = borders.visible.top;
bottom_amount = info->current.height + info->borders->visible.bottom;
vert_amount_onscreen = info->borders->visible.top;
}
else
bottom_amount = vert_amount_offscreen;

View File

@@ -40,6 +40,7 @@ typedef enum
} MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window,
MetaFrameBorders *orig_borders,
MetaMoveResizeFlags flags,
int resize_gravity,
const MetaRectangle *orig,

View File

@@ -172,7 +172,6 @@ meta_core_queue_frame_resize (Display *xdisplay,
MetaWindow *window = get_window (xdisplay, frame_xwindow);
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
meta_window_frame_size_changed (window);
}
void
@@ -477,6 +476,26 @@ meta_core_change_workspace (Display *xdisplay,
new_workspace));
}
int
meta_core_get_num_workspaces (Screen *xscreen)
{
MetaScreen *screen;
screen = meta_screen_for_x_screen (xscreen);
return meta_screen_get_n_workspaces (screen);
}
int
meta_core_get_active_workspace (Screen *xscreen)
{
MetaScreen *screen;
screen = meta_screen_for_x_screen (xscreen);
return meta_workspace_index (screen->active_workspace);
}
void
meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,

View File

@@ -153,6 +153,8 @@ void meta_core_change_workspace (Display *xdisplay,
Window frame_xwindow,
int new_workspace);
int meta_core_get_num_workspaces (Screen *xscreen);
int meta_core_get_active_workspace (Screen *xscreen);
int meta_core_get_frame_workspace (Display *xdisplay,
Window frame_xwindow);
const char* meta_core_get_workspace_name_with_index (Display *xdisplay,

View File

@@ -39,7 +39,6 @@
#include "keybindings-private.h"
#include <meta/prefs.h>
#include <meta/barrier.h>
#include <clutter/clutter.h>
#ifdef HAVE_STARTUP_NOTIFICATION
#include <libsn/sn.h>
@@ -102,8 +101,6 @@ struct _MetaDisplay
char *name;
Display *xdisplay;
int clutter_event_filter;
Window leader_window;
Window timestamp_pinging_window;
@@ -192,7 +189,7 @@ struct _MetaDisplay
MetaWindow* autoraise_window;
/* Alt+click button grabs */
ClutterModifierType window_grab_modifiers;
unsigned int window_grab_modifiers;
/* current window operation */
MetaGrabOp grab_op;
@@ -476,17 +473,21 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display,
void meta_display_remove_autoraise_callback (MetaDisplay *display);
void meta_display_overlay_key_activate (MetaDisplay *display);
void meta_display_accelerator_activate (MetaDisplay *display,
guint action,
ClutterKeyEvent *event);
void meta_display_accelerator_activate (MetaDisplay *display,
guint action,
guint deviceid,
guint timestamp);
gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
gboolean meta_display_handle_event (MetaDisplay *display,
XEvent *event);
#ifdef HAVE_XI23
gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIEvent *event);
gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIBarrierEvent *event);
#endif /* HAVE_XI23 */
void meta_display_set_input_focus_xwindow (MetaDisplay *display,

File diff suppressed because it is too large Load Diff

View File

@@ -985,7 +985,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
{
MetaRectangle *new_rect;
new_rect = g_new (MetaRectangle, 1);
meta_window_get_frame_rect (cur_window, new_rect);
meta_window_get_outer_rect (cur_window, new_rect);
obscuring_windows = g_slist_prepend (obscuring_windows, new_rect);
window_stacking =
g_slist_prepend (window_stacking, GINT_TO_POINTER (stack_position));
@@ -1010,7 +1010,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
{
MetaRectangle cur_rect;
MetaWindow *cur_window = cur_window_iter->data;
meta_window_get_frame_rect (cur_window, &cur_rect);
meta_window_get_outer_rect (cur_window, &cur_rect);
/* Check if we want to use this window's edges for edge
* resistance (note that dock edges are considered screen edges
@@ -1151,7 +1151,7 @@ meta_window_edge_resistance_for_move (MetaWindow *window,
MetaRectangle old_outer, proposed_outer, new_outer;
gboolean is_resize;
meta_window_get_frame_rect (window, &old_outer);
meta_window_get_outer_rect (window, &old_outer);
proposed_outer = old_outer;
proposed_outer.x += (*new_x - old_x);
@@ -1237,7 +1237,7 @@ meta_window_edge_resistance_for_resize (MetaWindow *window,
int proposed_outer_width, proposed_outer_height;
gboolean is_resize;
meta_window_get_frame_rect (window, &old_outer);
meta_window_get_outer_rect (window, &old_outer);
proposed_outer_width = old_outer.width + (*new_width - old_width);
proposed_outer_height = old_outer.height + (*new_height - old_height);
meta_rectangle_resize_with_gravity (&old_outer,

View File

@@ -69,7 +69,6 @@ meta_window_ensure_frame (MetaWindow *window)
frame->mapped = FALSE;
frame->is_flashing = FALSE;
frame->borders_cached = FALSE;
meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n",
window->desc,
@@ -335,23 +334,9 @@ meta_frame_calc_borders (MetaFrame *frame,
if (frame == NULL)
meta_frame_borders_clear (borders);
else
{
if (!frame->borders_cached)
{
meta_ui_get_frame_borders (frame->window->screen->ui,
frame->xwindow,
&frame->cached_borders);
frame->borders_cached = TRUE;
}
*borders = frame->cached_borders;
}
}
void
meta_frame_clear_cached_borders (MetaFrame *frame)
{
frame->borders_cached = FALSE;
meta_ui_get_frame_borders (frame->window->screen->ui,
frame->xwindow,
borders);
}
gboolean

View File

@@ -41,8 +41,6 @@ struct _MetaFrame
*/
MetaRectangle rect;
MetaFrameBorders cached_borders; /* valid if borders_cached is set */
/* position of client, size of frame */
int child_x;
int child_y;
@@ -52,7 +50,6 @@ struct _MetaFrame
guint mapped : 1;
guint need_reapply_frame_shape : 1;
guint is_flashing : 1; /* used by the visual bell flash */
guint borders_cached : 1;
};
void meta_window_ensure_frame (MetaWindow *window);
@@ -71,8 +68,6 @@ gboolean meta_frame_sync_to_window (MetaFrame *frame,
gboolean need_move,
gboolean need_resize);
void meta_frame_clear_cached_borders (MetaFrame *frame);
cairo_region_t *meta_frame_get_frame_bounds (MetaFrame *frame);
void meta_frame_get_mask (MetaFrame *frame,

View File

@@ -66,9 +66,9 @@ gboolean meta_window_grab_all_keys (MetaWindow *window,
guint32 timestamp);
void meta_window_ungrab_all_keys (MetaWindow *window,
guint32 timestamp);
gboolean meta_display_process_key_event (MetaDisplay *display,
MetaWindow *window,
ClutterKeyEvent *event);
gboolean meta_display_process_key_event (MetaDisplay *display,
MetaWindow *window,
XIDeviceEvent *event);
void meta_display_process_mapping_event (MetaDisplay *display,
XEvent *event);
@@ -81,3 +81,7 @@ gboolean meta_prefs_remove_keybinding (const char *name);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -401,6 +401,9 @@ meta_init (void)
g_strerror (errno));
#endif
if (getenv ("MUTTER_SLEEP_INIT"))
sleep (60);
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
if (g_getenv ("MUTTER_VERBOSE"))

View File

@@ -31,18 +31,18 @@
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent);
void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y);
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
void meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
ClutterActor *stage);
#endif

View File

@@ -42,7 +42,6 @@
#include <gdk/gdk.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
@@ -68,34 +67,11 @@ struct _MetaCursorTracker {
MetaScreen *screen;
gboolean is_showing;
gboolean has_cursor;
gboolean has_hw_cursor;
/* The cursor tracker stores the cursor for the current grab
* operation, the cursor for the window with pointer focus, and
* the cursor for the root window, which contains either the
* default arrow cursor or the 'busy' hourglass if we're launching
* an app.
*
* We choose the first one available -- if there's a grab cursor,
* we choose that cursor, if there's window cursor, we choose that,
* otherwise we choose the root cursor.
*
* The displayed_cursor contains the chosen cursor.
*/
MetaCursorReference *displayed_cursor;
MetaCursorReference *grab_cursor;
/* Wayland clients can set a NULL buffer as their cursor
* explicitly, which means that we shouldn't display anything.
* So, we can't simply store a NULL in window_cursor to
* determine an unset window cursor; we need an extra boolean.
*/
gboolean has_window_cursor;
MetaCursorReference *window_cursor;
MetaCursorReference *sprite;
MetaCursorReference *root_cursor;
MetaCursorReference *default_cursors[META_CURSOR_LAST];
int current_x, current_y;
@@ -121,6 +97,9 @@ enum {
static guint signals[LAST_SIGNAL];
static void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
MetaCursorReference *sprite);
static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
MetaCRTC *crtc,
gboolean has_hw_cursor);
@@ -149,130 +128,76 @@ meta_cursor_reference_unref (MetaCursorReference *self)
}
}
static void
translate_meta_cursor (MetaCursor cursor,
guint *glyph_out,
const char **name_out)
static const char *
get_cursor_filename (MetaCursor cursor)
{
guint glyph = XC_num_glyphs;
const char *name = NULL;
switch (cursor)
{
case META_CURSOR_DEFAULT:
glyph = XC_left_ptr;
return "left_ptr";
break;
case META_CURSOR_NORTH_RESIZE:
glyph = XC_top_side;
return "top_side";
break;
case META_CURSOR_SOUTH_RESIZE:
glyph = XC_bottom_side;
return "bottom_side";
break;
case META_CURSOR_WEST_RESIZE:
glyph = XC_left_side;
return "left_side";
break;
case META_CURSOR_EAST_RESIZE:
glyph = XC_right_side;
return "right_side";
break;
case META_CURSOR_SE_RESIZE:
glyph = XC_bottom_right_corner;
return "bottom_right_corner";
break;
case META_CURSOR_SW_RESIZE:
glyph = XC_bottom_left_corner;
return "bottom_left_corner";
break;
case META_CURSOR_NE_RESIZE:
glyph = XC_top_right_corner;
return "top_right_corner";
break;
case META_CURSOR_NW_RESIZE:
glyph = XC_top_left_corner;
return "top_left_corner";
break;
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
glyph = XC_fleur;
return "fleur";
break;
case META_CURSOR_BUSY:
glyph = XC_watch;
return "watch";
break;
case META_CURSOR_DND_IN_DRAG:
name = "dnd-none";
return "dnd-in-drag";
break;
case META_CURSOR_DND_MOVE:
name = "dnd-move";
break;
case META_CURSOR_DND_COPY:
name = "dnd-copy";
return "dnd-copy";
break;
case META_CURSOR_DND_UNSUPPORTED_TARGET:
name = "dnd-none";
return "dnd-none";
break;
case META_CURSOR_POINTING_HAND:
glyph = XC_hand2;
return "hand";
break;
case META_CURSOR_CROSSHAIR:
glyph = XC_crosshair;
return "crosshair";
break;
case META_CURSOR_IBEAM:
glyph = XC_xterm;
return "xterm";
break;
default:
g_assert_not_reached ();
glyph = 0; /* silence compiler */
break;
return NULL;
}
*glyph_out = glyph;
*name_out = name;
}
static Cursor
load_cursor_on_server (MetaDisplay *display,
MetaCursor cursor)
{
Cursor xcursor;
guint glyph;
const char *name;
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
xcursor = XcursorLibraryLoadCursor (display->xdisplay, name);
else
xcursor = XCreateFontCursor (display->xdisplay, glyph);
return xcursor;
}
Cursor
meta_display_create_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
return load_cursor_on_server (display, cursor);
}
static XcursorImage *
load_cursor_on_client (MetaDisplay *display,
MetaCursor cursor)
{
XcursorImage *image;
guint glyph;
const char *name;
const char *theme = XcursorGetTheme (display->xdisplay);
int size = XcursorGetDefaultSize (display->xdisplay);
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
image = XcursorLibraryLoadImage (name, theme, size);
else
image = XcursorShapeLoadImage (glyph, theme, size);
return image;
}
static MetaCursorReference *
meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
MetaCursor cursor)
{
const char *theme;
const char *filename;
int size;
XcursorImage *image;
int width, height, rowstride;
CoglPixelFormat cogl_format;
@@ -281,7 +206,11 @@ meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
CoglContext *cogl_context;
MetaCursorReference *self;
image = load_cursor_on_client (tracker->screen->display, cursor);
filename = get_cursor_filename (cursor);
theme = XcursorGetTheme (tracker->screen->display->xdisplay);
size = XcursorGetDefaultSize (tracker->screen->display->xdisplay);
image = XcursorLibraryLoadImage (filename, theme, size);
if (!image)
return NULL;
@@ -372,9 +301,7 @@ meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->hot_x = hot_x;
self->hot_y = hot_y;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
@@ -540,8 +467,8 @@ meta_cursor_tracker_finalize (GObject *object)
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
int i;
if (self->displayed_cursor)
meta_cursor_reference_unref (self->displayed_cursor);
if (self->sprite)
meta_cursor_reference_unref (self->sprite);
if (self->root_cursor)
meta_cursor_reference_unref (self->root_cursor);
@@ -666,17 +593,6 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen)
return self;
}
static void
set_window_cursor (MetaCursorTracker *tracker,
gboolean has_cursor,
MetaCursorReference *cursor)
{
g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->window_cursor = meta_cursor_reference_ref (cursor);
tracker->has_window_cursor = has_cursor;
}
gboolean
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent)
@@ -693,7 +609,7 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
if (notify_event->subtype != XFixesDisplayCursorNotify)
return FALSE;
set_window_cursor (tracker, FALSE, NULL);
g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
return TRUE;
@@ -708,7 +624,7 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
gboolean free_cursor_data;
CoglContext *ctx;
if (tracker->has_window_cursor)
if (tracker->sprite)
return;
cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
@@ -756,11 +672,9 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
if (sprite != NULL)
{
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite);
cursor->hot_x = cursor_image->xhot;
cursor->hot_y = cursor_image->yhot;
set_window_cursor (tracker, TRUE, cursor);
tracker->sprite = meta_cursor_reference_take_texture (sprite);
tracker->sprite->hot_x = cursor_image->xhot;
tracker->sprite->hot_y = cursor_image->yhot;
}
XFree (cursor_image);
}
@@ -778,8 +692,8 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
if (tracker->displayed_cursor)
return COGL_TEXTURE (tracker->displayed_cursor->texture);
if (tracker->sprite)
return COGL_TEXTURE (tracker->sprite->texture);
else
return NULL;
}
@@ -801,13 +715,12 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
if (tracker->displayed_cursor)
if (tracker->sprite)
{
MetaCursorReference *displayed_cursor = tracker->displayed_cursor;
if (x)
*x = displayed_cursor->hot_x;
*x = tracker->sprite->hot_x;
if (y)
*y = displayed_cursor->hot_y;
*y = tracker->sprite->hot_y;
}
else
{
@@ -822,45 +735,14 @@ static MetaCursorReference *
ensure_wayland_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
if (tracker->default_cursors[cursor])
return tracker->default_cursors[cursor];
tracker->default_cursors[cursor] = meta_cursor_reference_from_theme (tracker, cursor);
if (!tracker->default_cursors[cursor])
{
tracker->default_cursors[cursor] = meta_cursor_reference_from_theme (tracker, cursor);
if (!tracker->default_cursors[cursor])
meta_warning ("Failed to load cursor from theme\n");
}
meta_warning ("Failed to load cursor from theme\n");
return meta_cursor_reference_ref (tracker->default_cursors[cursor]);
}
void
meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
g_clear_pointer (&tracker->grab_cursor, meta_cursor_reference_unref);
if (cursor != META_CURSOR_DEFAULT)
tracker->grab_cursor = ensure_wayland_cursor (tracker, cursor);
}
void
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorReference *cursor;
if (buffer)
cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y);
else
cursor = NULL;
set_window_cursor (tracker, TRUE, cursor);
}
void
meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker)
{
set_window_cursor (tracker, FALSE, NULL);
return tracker->default_cursors[cursor];
}
void
@@ -880,11 +762,21 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
/* Now update the real root cursor */
if (meta_is_wayland_compositor ())
{
MetaCursorReference *ref;
ref = ensure_wayland_cursor (tracker, cursor);
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
tracker->root_cursor = ensure_wayland_cursor (tracker, cursor);
tracker->root_cursor = meta_cursor_reference_ref (ref);
}
}
void
meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
{
meta_cursor_tracker_set_sprite (tracker, tracker->root_cursor);
}
static void
update_hw_cursor (MetaCursorTracker *tracker)
{
@@ -893,7 +785,7 @@ update_hw_cursor (MetaCursorTracker *tracker)
unsigned int i, n_crtcs;
gboolean enabled;
enabled = tracker->displayed_cursor && tracker->displayed_cursor->bo != NULL;
enabled = tracker->has_cursor && tracker->sprite->bo != NULL;
tracker->has_hw_cursor = enabled;
monitors = meta_monitor_manager_get ();
@@ -939,48 +831,105 @@ move_hw_cursor (MetaCursorTracker *tracker)
}
}
static MetaCursorReference *
get_displayed_cursor (MetaCursorTracker *tracker)
void
meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
if (!tracker->is_showing)
return NULL;
MetaCursorReference *new_cursor;
if (tracker->grab_cursor)
return tracker->grab_cursor;
if (tracker->has_window_cursor)
return tracker->window_cursor;
return tracker->root_cursor;
if (buffer)
{
new_cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y);
meta_cursor_tracker_set_sprite (tracker, new_cursor);
meta_cursor_reference_unref (new_cursor);
}
else
meta_cursor_tracker_set_sprite (tracker, NULL);
}
static void
sync_displayed_cursor (MetaCursorTracker *tracker)
meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
MetaCursorReference *sprite)
{
MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker);
g_assert (meta_is_wayland_compositor ());
if (tracker->displayed_cursor == displayed_cursor)
if (sprite == tracker->sprite)
return;
g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref);
if (displayed_cursor)
tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor);
g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
if (displayed_cursor)
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (displayed_cursor->texture));
if (sprite)
{
tracker->sprite = meta_cursor_reference_ref (sprite);
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite->texture));
}
else
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
tracker->has_cursor = tracker->sprite != NULL && tracker->is_showing;
update_hw_cursor (tracker);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
}
static void
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker)
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
{
g_assert (meta_is_wayland_compositor ());
tracker->current_x = new_x;
tracker->current_y = new_y;
if (tracker->sprite)
{
tracker->current_rect.x = tracker->current_x - tracker->sprite->hot_x;
tracker->current_rect.y = tracker->current_y - tracker->sprite->hot_y;
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite->texture));
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite->texture));
}
else
{
tracker->current_rect.x = 0;
tracker->current_rect.y = 0;
tracker->current_rect.width = 0;
tracker->current_rect.height = 0;
}
if (tracker->has_hw_cursor)
move_hw_cursor (tracker);
}
void
meta_cursor_tracker_paint (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
tracker->pipeline,
tracker->current_rect.x,
tracker->current_rect.y,
tracker->current_rect.x +
tracker->current_rect.width,
tracker->current_rect.y +
tracker->current_rect.height);
tracker->previous_rect = tracker->current_rect;
tracker->previous_is_valid = TRUE;
}
void
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
ClutterActor *stage)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
ClutterActor *stage = compositor->stage;
cairo_rectangle_int_t clip;
g_assert (meta_is_wayland_compositor ());
@@ -997,7 +946,7 @@ meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker)
tracker->previous_is_valid = FALSE;
}
if (tracker->has_hw_cursor || !tracker->displayed_cursor)
if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
clip.x = tracker->current_rect.x;
@@ -1007,69 +956,6 @@ meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker)
clutter_actor_queue_redraw_with_clip (stage, &clip);
}
static void
sync_cursor (MetaCursorTracker *tracker)
{
MetaCursorReference *displayed_cursor;
sync_displayed_cursor (tracker);
displayed_cursor = tracker->displayed_cursor;
if (displayed_cursor)
{
tracker->current_rect.x = tracker->current_x - displayed_cursor->hot_x;
tracker->current_rect.y = tracker->current_y - displayed_cursor->hot_y;
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (displayed_cursor->texture));
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (displayed_cursor->texture));
}
else
{
tracker->current_rect.x = 0;
tracker->current_rect.y = 0;
tracker->current_rect.width = 0;
tracker->current_rect.height = 0;
}
if (tracker->has_hw_cursor)
move_hw_cursor (tracker);
else
meta_cursor_tracker_queue_redraw (tracker);
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
{
g_assert (meta_is_wayland_compositor ());
tracker->current_x = new_x;
tracker->current_y = new_y;
sync_cursor (tracker);
}
void
meta_cursor_tracker_paint (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
if (tracker->has_hw_cursor || !tracker->displayed_cursor)
return;
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
tracker->pipeline,
tracker->current_rect.x,
tracker->current_rect.y,
tracker->current_rect.x +
tracker->current_rect.width,
tracker->current_rect.y +
tracker->current_rect.height);
tracker->previous_rect = tracker->current_rect;
tracker->previous_is_valid = TRUE;
}
static void
meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
MetaCRTC *crtc,
@@ -1077,16 +963,15 @@ meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
{
if (has)
{
MetaCursorReference *displayed_cursor = tracker->displayed_cursor;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
handle = gbm_bo_get_handle (displayed_cursor->bo);
width = gbm_bo_get_width (displayed_cursor->bo);
height = gbm_bo_get_height (displayed_cursor->bo);
hot_x = displayed_cursor->hot_x;
hot_y = displayed_cursor->hot_y;
handle = gbm_bo_get_handle (tracker->sprite->bo);
width = gbm_bo_get_width (tracker->sprite->bo);
height = gbm_bo_get_height (tracker->sprite->bo);
hot_x = tracker->sprite->hot_x;
hot_y = tracker->sprite->hot_y;
drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
@@ -1162,7 +1047,13 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
if (meta_is_wayland_compositor ())
{
sync_cursor (tracker);
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
tracker->has_cursor = tracker->sprite != NULL && visible;
update_hw_cursor (tracker);
meta_cursor_tracker_queue_redraw (tracker, compositor->stage);
}
else
{

View File

@@ -99,9 +99,8 @@ static gboolean meta_monitor_config_assign_crtcs (MetaConfiguration *config,
GPtrArray *crtcs,
GPtrArray *outputs);
static void power_client_changed_cb (UpClient *client,
GParamSpec *pspec,
gpointer user_data);
static void power_client_changed_cb (UpClient *client,
gpointer user_data);
static void
free_output_key (MetaOutputKey *key)
@@ -233,7 +232,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
self->up_client = up_client_new ();
self->lid_is_closed = up_client_get_lid_is_closed (self->up_client);
g_signal_connect_object (self->up_client, "notify::lid-is-closed",
g_signal_connect_object (self->up_client, "changed",
G_CALLBACK (power_client_changed_cb), self, 0);
}
@@ -817,22 +816,6 @@ meta_monitor_config_match_current (MetaMonitorConfig *self,
return ok;
}
gboolean
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
{
MetaOutput *outputs;
unsigned n_outputs;
unsigned int i;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
for (i = 0; i < n_outputs; i++)
if (outputs[i].hotplug_mode_update)
return TRUE;
return FALSE;
}
static MetaConfiguration *
meta_monitor_config_get_stored (MetaMonitorConfig *self,
MetaOutput *outputs,
@@ -1352,9 +1335,8 @@ turn_off_laptop_display (MetaMonitorConfig *self,
}
static void
power_client_changed_cb (UpClient *client,
GParamSpec *pspec,
gpointer user_data)
power_client_changed_cb (UpClient *client,
gpointer user_data)
{
MetaMonitorManager *manager = meta_monitor_manager_get ();
MetaMonitorConfig *self = user_data;

View File

@@ -119,9 +119,6 @@ struct _MetaOutput
gpointer driver_private;
GDestroyNotify driver_notify;
/* get a new preferred mode on hotplug events, to handle dynamic guest resizing */
gboolean hotplug_mode_update;
};
struct _MetaCRTC
@@ -410,7 +407,6 @@ void meta_monitor_manager_free_output_array (MetaOutput *old_outpu
int n_old_outputs);
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */

View File

@@ -311,29 +311,6 @@ read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
return NULL;
}
static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
XID output_id)
{
MetaDisplay *display = meta_get_display ();
XRRPropertyInfo *info;
gboolean result = FALSE;
meta_error_trap_push (display);
info = XRRQueryOutputProperty (manager_xrandr->xdisplay, output_id,
display->atom_hotplug_mode_update);
meta_error_trap_pop (display);
if (info)
{
result = TRUE;
XFree (info);
}
return result;
}
static void
meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
{
@@ -507,8 +484,6 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
meta_output->width_mm = output->mm_width;
meta_output->height_mm = output->mm_height;
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
meta_output->hotplug_mode_update =
output_get_hotplug_mode_update (manager_xrandr, meta_output->output_id);
meta_output->n_modes = output->nmode;
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
@@ -994,16 +969,6 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
XRRFreeGamma (gamma);
}
static void
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
static gboolean
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
XEvent *event)
@@ -1013,7 +978,6 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
gboolean new_config;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
@@ -1030,36 +994,31 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
new_config = manager_xrandr->resources->timestamp >=
manager_xrandr->resources->configTimestamp;
if (meta_monitor_manager_has_hotplug_mode_update (manager))
/* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, we can go straight to rebuild the logical config and tell
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with
new configTimestamps (bug 702804), and the driver may have
changed the EDID for some other reason (old broken qxl and vbox
drivers...).
*/
if (manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp ||
meta_monitor_config_match_current (manager->config, manager))
{
/* Check if the current intended configuration is a result of an
XRandR call. Otherwise, hotplug_mode_update tells us to get
a new preferred mode on hotplug events to handle dynamic
guest resizing. */
if (new_config)
meta_monitor_manager_xrandr_rebuild_derived (manager);
else
meta_monitor_config_make_default (manager->config, manager);
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
else
{
/* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, we can go straight to rebuild the logical config and tell
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with new
configTimestamps (bug 702804), and the driver may have changed
the EDID for some other reason (old qxl and vbox drivers). */
if (new_config || meta_monitor_config_match_current (manager->config, manager))
meta_monitor_manager_xrandr_rebuild_derived (manager);
else if (!meta_monitor_config_apply_stored (manager->config, manager))
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
}

View File

@@ -729,9 +729,6 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_new_take_string (make_display_name (manager, output)));
g_variant_builder_add (&properties, "{sv}", "backlight",
g_variant_new_int32 (output->backlight));
g_variant_builder_add (&properties, "{sv}", "min-backlight-step",
g_variant_new_int32 ((output->backlight_max - output->backlight_min) ?
100 / (output->backlight_max - output->backlight_min) : -1));
g_variant_builder_add (&properties, "{sv}", "primary",
g_variant_new_boolean (output->is_primary));
g_variant_builder_add (&properties, "{sv}", "presentation",

View File

@@ -47,18 +47,34 @@ northwestcmp (gconstpointer a, gconstpointer b)
{
MetaWindow *aw = (gpointer) a;
MetaWindow *bw = (gpointer) b;
MetaRectangle a_frame;
MetaRectangle b_frame;
int from_origin_a;
int from_origin_b;
int ax, ay, bx, by;
meta_window_get_frame_rect (aw, &a_frame);
meta_window_get_frame_rect (bw, &b_frame);
ax = a_frame.x;
ay = a_frame.y;
bx = b_frame.x;
by = b_frame.y;
/* we're interested in the frame position for cascading,
* not meta_window_get_position()
*/
if (aw->frame)
{
ax = aw->frame->rect.x;
ay = aw->frame->rect.y;
}
else
{
ax = aw->rect.x;
ay = aw->rect.y;
}
if (bw->frame)
{
bx = bw->frame->rect.x;
by = bw->frame->rect.y;
}
else
{
bx = bw->rect.x;
by = bw->rect.y;
}
/* probably there's a fast good-enough-guess we could use here. */
from_origin_a = sqrt (ax * ax + ay * ay);
@@ -74,6 +90,7 @@ northwestcmp (gconstpointer a, gconstpointer b)
static void
find_next_cascade (MetaWindow *window,
MetaFrameBorders *borders,
/* visible windows on relevant workspaces */
GList *windows,
int x,
@@ -85,7 +102,6 @@ find_next_cascade (MetaWindow *window,
GList *sorted;
int cascade_x, cascade_y;
int x_threshold, y_threshold;
MetaRectangle frame_rect;
int window_width, window_height;
int cascade_stage;
MetaRectangle work_area;
@@ -104,13 +120,10 @@ find_next_cascade (MetaWindow *window,
* manually cascade.
*/
#define CASCADE_FUZZ 15
if (window->frame)
if (borders)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
x_threshold = MAX (borders.visible.left, CASCADE_FUZZ);
y_threshold = MAX (borders.visible.top, CASCADE_FUZZ);
x_threshold = MAX (borders->visible.left, CASCADE_FUZZ);
y_threshold = MAX (borders->visible.top, CASCADE_FUZZ);
}
else
{
@@ -130,25 +143,30 @@ find_next_cascade (MetaWindow *window,
cascade_y = MAX (0, work_area.y);
/* Find first cascade position that's not used. */
meta_window_get_frame_rect (window, &frame_rect);
window_width = frame_rect.width;
window_height = frame_rect.height;
window_width = window->frame ? window->frame->rect.width : window->rect.width;
window_height = window->frame ? window->frame->rect.height : window->rect.height;
cascade_stage = 0;
tmp = sorted;
while (tmp != NULL)
{
MetaWindow *w;
MetaRectangle w_frame_rect;
int wx, wy;
w = tmp->data;
/* we want frame position, not window position */
meta_window_get_frame_rect (w, &w_frame_rect);
wx = w_frame_rect.x;
wy = w_frame_rect.y;
if (w->frame)
{
wx = w->frame->rect.x;
wy = w->frame->rect.y;
}
else
{
wx = w->rect.x;
wy = w->rect.y;
}
if (ABS (wx - cascade_x) < x_threshold &&
ABS (wy - cascade_y) < y_threshold)
@@ -205,12 +223,22 @@ find_next_cascade (MetaWindow *window,
g_list_free (sorted);
*new_x = cascade_x;
*new_y = cascade_y;
/* Convert coords to position of window, not position of frame. */
if (borders == NULL)
{
*new_x = cascade_x;
*new_y = cascade_y;
}
else
{
*new_x = cascade_x + borders->visible.left;
*new_y = cascade_y + borders->visible.top;
}
}
static void
find_most_freespace (MetaWindow *window,
MetaFrameBorders *borders,
/* visible windows on relevant workspaces */
MetaWindow *focus_window,
int x,
@@ -222,25 +250,29 @@ find_most_freespace (MetaWindow *window,
int max_area;
int max_width, max_height, left, right, top, bottom;
int left_space, right_space, top_space, bottom_space;
int frame_size_left, frame_size_top;
MetaRectangle work_area;
MetaRectangle avoid;
MetaRectangle frame_rect;
MetaRectangle outer;
frame_size_left = borders ? borders->visible.left : 0;
frame_size_top = borders ? borders->visible.top : 0;
meta_window_get_work_area_current_monitor (focus_window, &work_area);
meta_window_get_frame_rect (focus_window, &avoid);
meta_window_get_frame_rect (window, &frame_rect);
meta_window_get_outer_rect (focus_window, &avoid);
meta_window_get_outer_rect (window, &outer);
/* Find the areas of choosing the various sides of the focus window */
max_width = MIN (avoid.width, frame_rect.width);
max_height = MIN (avoid.height, frame_rect.height);
max_width = MIN (avoid.width, outer.width);
max_height = MIN (avoid.height, outer.height);
left_space = avoid.x - work_area.x;
right_space = work_area.width - (avoid.x + avoid.width - work_area.x);
top_space = avoid.y - work_area.y;
bottom_space = work_area.height - (avoid.y + avoid.height - work_area.y);
left = MIN (left_space, frame_rect.width);
right = MIN (right_space, frame_rect.width);
top = MIN (top_space, frame_rect.height);
bottom = MIN (bottom_space, frame_rect.height);
left = MIN (left_space, outer.width);
right = MIN (right_space, outer.width);
top = MIN (top_space, outer.height);
bottom = MIN (bottom_space, outer.height);
/* Find out which side of the focus_window can show the most of the window */
side = META_LEFT;
@@ -272,56 +304,39 @@ find_most_freespace (MetaWindow *window,
switch (side)
{
case META_LEFT:
*new_y = avoid.y;
if (left_space > frame_rect.width)
*new_x = avoid.x - frame_rect.width;
*new_y = avoid.y + frame_size_top;
if (left_space > outer.width)
*new_x = avoid.x - outer.width + frame_size_left;
else
*new_x = work_area.x;
*new_x = work_area.x + frame_size_left;
break;
case META_RIGHT:
*new_y = avoid.y;
if (right_space > frame_rect.width)
*new_x = avoid.x + avoid.width;
*new_y = avoid.y + frame_size_top;
if (right_space > outer.width)
*new_x = avoid.x + avoid.width + frame_size_left;
else
*new_x = work_area.x + work_area.width - frame_rect.width;
*new_x = work_area.x + work_area.width - outer.width + frame_size_left;
break;
case META_TOP:
*new_x = avoid.x;
if (top_space > frame_rect.height)
*new_y = avoid.y - frame_rect.height;
*new_x = avoid.x + frame_size_left;
if (top_space > outer.height)
*new_y = avoid.y - outer.height + frame_size_top;
else
*new_y = work_area.y;
*new_y = work_area.y + frame_size_top;
break;
case META_BOTTOM:
*new_x = avoid.x;
if (bottom_space > frame_rect.height)
*new_y = avoid.y + avoid.height;
*new_x = avoid.x + frame_size_left;
if (bottom_space > outer.height)
*new_y = avoid.y + avoid.height + frame_size_top;
else
*new_y = work_area.y + work_area.height - frame_rect.height;
*new_y = work_area.y + work_area.height - outer.height + frame_size_top;
break;
}
}
static gboolean
window_overlaps_focus_window (MetaWindow *window)
{
MetaWindow *focus_window;
MetaRectangle window_frame, focus_frame, overlap;
focus_window = window->display->focus_window;
if (focus_window == NULL)
return FALSE;
meta_window_get_frame_rect (window, &window_frame);
meta_window_get_frame_rect (focus_window, &focus_frame);
return meta_rectangle_intersect (&window_frame,
&focus_frame,
&overlap);
}
static void
avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
MetaFrameBorders *borders,
int *x,
int *y)
{
@@ -340,17 +355,18 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
*/
MetaWindow *focus_window;
MetaRectangle overlap;
focus_window = window->display->focus_window;
/* denied_focus_and_not_transient is only set when focus_window != NULL */
if (window->denied_focus_and_not_transient &&
window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
meta_window_same_application (window, focus_window) &&
window_overlaps_focus_window (window))
meta_rectangle_intersect (&window->rect,
&focus_window->rect,
&overlap))
{
find_most_freespace (window, focus_window, *x, *y, x, y);
find_most_freespace (window, borders, focus_window, *x, *y, x, y);
meta_topic (META_DEBUG_PLACEMENT,
"Dialog window %s was denied focus but may be modal "
"to the focus window; had to move it to avoid the "
@@ -393,7 +409,7 @@ rectangle_overlaps_some_window (MetaRectangle *rect,
case META_WINDOW_UTILITY:
case META_WINDOW_TOOLBAR:
case META_WINDOW_MENU:
meta_window_get_frame_rect (other, &other_rect);
meta_window_get_outer_rect (other, &other_rect);
if (meta_rectangle_intersect (rect, &other_rect, &dest))
return TRUE;
@@ -411,14 +427,20 @@ leftmost_cmp (gconstpointer a, gconstpointer b)
{
MetaWindow *aw = (gpointer) a;
MetaWindow *bw = (gpointer) b;
MetaRectangle a_frame;
MetaRectangle b_frame;
int ax, bx;
meta_window_get_frame_rect (aw, &a_frame);
meta_window_get_frame_rect (bw, &b_frame);
ax = a_frame.x;
bx = b_frame.x;
/* we're interested in the frame position for cascading,
* not meta_window_get_position()
*/
if (aw->frame)
ax = aw->frame->rect.x;
else
ax = aw->rect.x;
if (bw->frame)
bx = bw->frame->rect.x;
else
bx = bw->rect.x;
if (ax < bx)
return -1;
@@ -433,14 +455,20 @@ topmost_cmp (gconstpointer a, gconstpointer b)
{
MetaWindow *aw = (gpointer) a;
MetaWindow *bw = (gpointer) b;
MetaRectangle a_frame;
MetaRectangle b_frame;
int ay, by;
meta_window_get_frame_rect (aw, &a_frame);
meta_window_get_frame_rect (bw, &b_frame);
ay = a_frame.y;
by = b_frame.y;
/* we're interested in the frame position for cascading,
* not meta_window_get_position()
*/
if (aw->frame)
ay = aw->frame->rect.y;
else
ay = aw->rect.y;
if (bw->frame)
by = bw->frame->rect.y;
else
by = bw->rect.y;
if (ay < by)
return -1;
@@ -478,6 +506,7 @@ center_tile_rect_in_area (MetaRectangle *rect,
*/
static gboolean
find_first_fit (MetaWindow *window,
MetaFrameBorders *borders,
/* visible windows on relevant workspaces */
GList *windows,
int monitor,
@@ -511,8 +540,15 @@ find_first_fit (MetaWindow *window,
right_sorted = g_list_copy (windows);
right_sorted = g_list_sort (right_sorted, topmost_cmp);
right_sorted = g_list_sort (right_sorted, leftmost_cmp);
meta_window_get_frame_rect (window, &rect);
rect.width = window->rect.width;
rect.height = window->rect.height;
if (borders)
{
rect.width += borders->visible.left + borders->visible.right;
rect.height += borders->visible.top + borders->visible.bottom;
}
#ifdef WITH_VERBOSE_MODE
{
@@ -534,6 +570,11 @@ find_first_fit (MetaWindow *window,
{
*new_x = rect.x;
*new_y = rect.y;
if (borders)
{
*new_x += borders->visible.left;
*new_y += borders->visible.top;
}
retval = TRUE;
@@ -545,18 +586,23 @@ find_first_fit (MetaWindow *window,
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
MetaRectangle frame_rect;
MetaRectangle outer_rect;
meta_window_get_frame_rect (w, &frame_rect);
meta_window_get_outer_rect (w, &outer_rect);
rect.x = frame_rect.x;
rect.y = frame_rect.y + frame_rect.height;
rect.x = outer_rect.x;
rect.y = outer_rect.y + outer_rect.height;
if (meta_rectangle_contains_rect (&work_area, &rect) &&
!rectangle_overlaps_some_window (&rect, below_sorted))
{
*new_x = rect.x;
*new_y = rect.y;
if (borders)
{
*new_x += borders->visible.left;
*new_y += borders->visible.top;
}
retval = TRUE;
@@ -571,18 +617,23 @@ find_first_fit (MetaWindow *window,
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
MetaRectangle frame_rect;
MetaRectangle outer_rect;
meta_window_get_frame_rect (w, &frame_rect);
meta_window_get_outer_rect (w, &outer_rect);
rect.x = frame_rect.x + frame_rect.width;
rect.y = frame_rect.y;
rect.x = outer_rect.x + outer_rect.width;
rect.y = outer_rect.y;
if (meta_rectangle_contains_rect (&work_area, &rect) &&
!rectangle_overlaps_some_window (&rect, right_sorted))
{
*new_x = rect.x;
*new_y = rect.y;
if (borders)
{
*new_x += borders->visible.left;
*new_y += borders->visible.top;
}
retval = TRUE;
@@ -601,6 +652,7 @@ find_first_fit (MetaWindow *window,
void
meta_window_place (MetaWindow *window,
MetaFrameBorders *borders,
int x,
int y,
int *new_x,
@@ -609,6 +661,13 @@ meta_window_place (MetaWindow *window,
GList *windows;
const MetaMonitorInfo *xi;
/* frame member variables should NEVER be used in here, only
* MetaFrameBorders. But remember borders == NULL
* for undecorated windows. Also, this function should
* NEVER have side effects other than computing the
* placement coordinates.
*/
meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc);
windows = NULL;
@@ -697,7 +756,7 @@ meta_window_place (MetaWindow *window,
{
meta_topic (META_DEBUG_PLACEMENT,
"Not placing window with PPosition or USPosition set\n");
avoid_being_obscured_as_second_modal_dialog (window, &x, &y);
avoid_being_obscured_as_second_modal_dialog (window, borders, &x, &y);
goto done_no_constraints;
}
}
@@ -716,27 +775,29 @@ meta_window_place (MetaWindow *window,
if (parent)
{
MetaRectangle frame_rect, parent_frame_rect;
int w;
meta_window_get_frame_rect (window, &frame_rect);
meta_window_get_frame_rect (parent, &parent_frame_rect);
y = parent_frame_rect.y;
meta_window_get_position (parent, &x, &y);
w = parent->rect.width;
/* center of parent */
x = parent_frame_rect.x + parent_frame_rect.width / 2;
x = x + w / 2;
/* center of child over center of parent */
x -= frame_rect.width / 2;
x -= window->rect.width / 2;
/* "visually" center window over parent, leaving twice as
* much space below as on top.
*/
y += (parent_frame_rect.height - frame_rect.height)/3;
y += (parent->rect.height - window->rect.height)/3;
/* put top of child's frame, not top of child's client */
if (borders)
y += borders->visible.top;
meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n",
window->desc);
avoid_being_obscured_as_second_modal_dialog (window, &x, &y);
avoid_being_obscured_as_second_modal_dialog (window, borders, &x, &y);
goto done;
}
@@ -752,9 +813,6 @@ meta_window_place (MetaWindow *window,
{
/* Center on current monitor */
int w, h;
MetaRectangle frame_rect;
meta_window_get_frame_rect (window, &frame_rect);
/* Warning, this function is a round trip! */
xi = meta_screen_get_current_monitor_info (window->screen);
@@ -762,8 +820,8 @@ meta_window_place (MetaWindow *window,
w = xi->rect.width;
h = xi->rect.height;
x = (w - frame_rect.width) / 2;
y = (h - frame_rect.height) / 2;
x = (w - window->rect.width) / 2;
y = (h - window->rect.height) / 2;
x += xi->rect.x;
y += xi->rect.y;
@@ -807,7 +865,7 @@ meta_window_place (MetaWindow *window,
x = xi->rect.x;
y = xi->rect.y;
if (find_first_fit (window, windows,
if (find_first_fit (window, borders, windows,
xi->number,
x, y, &x, &y))
goto done_check_denied_focus;
@@ -820,17 +878,17 @@ meta_window_place (MetaWindow *window,
!window->fullscreen)
{
MetaRectangle workarea;
MetaRectangle frame_rect;
MetaRectangle outer;
meta_window_get_work_area_for_monitor (window,
xi->number,
&workarea);
meta_window_get_frame_rect (window, &frame_rect);
meta_window_get_outer_rect (window, &outer);
/* If the window is bigger than the screen, then automaximize. Do NOT
* auto-maximize the directions independently. See #419810.
*/
if (frame_rect.width >= workarea.width && frame_rect.height >= workarea.height)
if (outer.width >= workarea.width && outer.height >= workarea.height)
{
window->maximize_horizontally_after_placement = TRUE;
window->maximize_vertically_after_placement = TRUE;
@@ -841,7 +899,7 @@ meta_window_place (MetaWindow *window,
* fully overlapping window (e.g. starting multiple terminals)
* */
if (x == xi->rect.x && y == xi->rect.y)
find_next_cascade (window, windows, x, y, &x, &y);
find_next_cascade (window, borders, windows, x, y, &x, &y);
done_check_denied_focus:
/* If the window is being denied focus and isn't a transient of the
@@ -851,14 +909,17 @@ meta_window_place (MetaWindow *window,
*/
if (window->denied_focus_and_not_transient)
{
MetaWindow *focus_window;
gboolean found_fit;
MetaWindow *focus_window;
MetaRectangle overlap;
focus_window = window->display->focus_window;
g_assert (focus_window != NULL);
/* No need to do anything if the window doesn't overlap at all */
found_fit = !window_overlaps_focus_window (window);
found_fit = !meta_rectangle_intersect (&window->rect,
&focus_window->rect,
&overlap);
/* Try to do a first fit again, this time only taking into account the
* focus window.
@@ -872,7 +933,7 @@ meta_window_place (MetaWindow *window,
x = xi->rect.x;
y = xi->rect.y;
found_fit = find_first_fit (window, focus_window_list,
found_fit = find_first_fit (window, borders, focus_window_list,
xi->number,
x, y, &x, &y);
g_list_free (focus_window_list);
@@ -882,7 +943,7 @@ meta_window_place (MetaWindow *window,
* as possible.
*/
if (!found_fit)
find_most_freespace (window, focus_window, x, y, &x, &y);
find_most_freespace (window, borders, focus_window, x, y, &x, &y);
}
done:

View File

@@ -28,6 +28,7 @@
#include "frame.h"
void meta_window_place (MetaWindow *window,
MetaFrameBorders *borders,
int x,
int y,
int *new_x,

View File

@@ -859,9 +859,9 @@ meta_screen_free (MetaScreen *screen,
screen->wm_sn_selection_window);
if (screen->work_area_later != 0)
meta_later_remove (screen->work_area_later);
g_source_remove (screen->work_area_later);
if (screen->check_fullscreen_later != 0)
meta_later_remove (screen->check_fullscreen_later);
g_source_remove (screen->check_fullscreen_later);
if (screen->monitor_infos)
g_free (screen->monitor_infos);
@@ -1528,7 +1528,7 @@ meta_screen_tab_popup_create (MetaScreen *screen,
if (show_type == META_TAB_SHOW_INSTANTLY ||
!entries[i].hidden ||
!meta_window_get_icon_geometry (window, &r))
meta_window_get_frame_rect (window, &r);
meta_window_get_outer_rect (window, &r);
entries[i].rect = r;
@@ -1914,7 +1914,7 @@ meta_screen_get_monitor_for_window (MetaScreen *screen,
{
MetaRectangle window_rect;
meta_window_get_frame_rect (window, &window_rect);
meta_window_get_outer_rect (window, &window_rect);
return meta_screen_get_monitor_for_rect (screen, &window_rect);
}

View File

@@ -92,6 +92,16 @@ meta_stack_new (MetaScreen *screen)
static void
free_last_all_root_children_stacked_cache (MetaStack *stack)
{
unsigned int i;
for (i = 0; i < stack->last_all_root_children_stacked->len; i++)
{
MetaStackWindow *window = &g_array_index (stack->last_all_root_children_stacked, MetaStackWindow, i);
if (window->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND)
g_object_remove_weak_pointer (G_OBJECT (window->wayland.meta_window),
(gpointer *)&window->wayland.meta_window);
}
g_array_free (stack->last_all_root_children_stacked, TRUE);
stack->last_all_root_children_stacked = NULL;
}
@@ -1327,6 +1337,17 @@ stack_sync_to_xserver (MetaStack *stack)
/* build XRestackWindows() array from top to bottom */
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
g_array_append_val (x11_root_children_stacked, top_level_window);
else
{
MetaStackWindow *new;
/* So we can determine later if a cached stack window is
* stale because the corresponding window has been freed we
* associate a weak pointer with the new window. */
new = &g_array_index (all_root_children_stacked, MetaStackWindow, all_root_children_stacked->len - 1);
g_object_add_weak_pointer (G_OBJECT (new->wayland.meta_window),
(gpointer *)&new->wayland.meta_window);
}
}
meta_topic (META_DEBUG_STACK, "\n");
@@ -1684,7 +1705,7 @@ window_contains_point (MetaWindow *window,
{
MetaRectangle rect;
meta_window_get_frame_rect (window, &rect);
meta_window_get_outer_rect (window, &rect);
return POINT_IN_RECT (root_x, root_y, rect);
}
@@ -1703,12 +1724,14 @@ get_default_focus_window (MetaStack *stack,
* or top window in same group as not_this_one.
*/
MetaWindow *topmost_dock;
MetaWindow *transient_parent;
MetaWindow *topmost_in_group;
MetaWindow *topmost_overall;
MetaGroup *not_this_one_group;
GList *link;
topmost_dock = NULL;
transient_parent = NULL;
topmost_in_group = NULL;
topmost_overall = NULL;
@@ -1734,6 +1757,10 @@ get_default_focus_window (MetaStack *stack,
(workspace == NULL ||
meta_window_located_on_workspace (window, workspace)))
{
if (topmost_dock == NULL &&
window->type == META_WINDOW_DOCK)
topmost_dock = window;
if (not_this_one != NULL)
{
if (transient_parent == NULL &&
@@ -1751,6 +1778,10 @@ get_default_focus_window (MetaStack *stack,
topmost_in_group = window;
}
/* Note that DESKTOP windows can be topmost_overall so
* we prefer focusing desktop or other windows over
* focusing dock, even though docks are stacked higher.
*/
if (topmost_overall == NULL &&
window->type != META_WINDOW_DOCK &&
(!must_be_at_point ||
@@ -1772,7 +1803,7 @@ get_default_focus_window (MetaStack *stack,
else if (topmost_overall)
return topmost_overall;
else
return NULL;
return topmost_dock;
}
MetaWindow*

View File

@@ -44,7 +44,6 @@
#include <X11/Xutil.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include "meta-wayland-types.h"
typedef struct _MetaWindowQueue MetaWindowQueue;
@@ -533,7 +532,6 @@ void meta_window_update_fullscreen_monitors (MetaWindow *window,
unsigned long left,
unsigned long right);
/* args to move are window pos, not frame pos */
void meta_window_move (MetaWindow *window,
gboolean user_op,
@@ -644,8 +642,8 @@ void meta_window_update_sync_request_counter (MetaWindow *window,
gint64 new_counter_value);
#endif /* HAVE_XSYNC */
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
const ClutterEvent *event);
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
XIDeviceEvent *xev);
GList* meta_window_get_workspaces (MetaWindow *window);
@@ -684,8 +682,6 @@ void meta_window_recalc_features (MetaWindow *window);
void meta_window_recalc_window_type (MetaWindow *window);
void meta_window_type_changed (MetaWindow *window);
void meta_window_frame_size_changed (MetaWindow *window);
void meta_window_stack_just_below (MetaWindow *window,
MetaWindow *below_this_one);
@@ -737,9 +733,4 @@ void meta_window_set_gtk_dbus_properties (MetaWindow *window,
void meta_window_set_transient_for (MetaWindow *window,
MetaWindow *parent);
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,
guint root_y);
#endif

View File

@@ -63,7 +63,6 @@
#include <X11/extensions/Xcomposite.h>
#include "meta-wayland-private.h"
#include "meta/compositor-mutter.h"
/* Windows that unmaximize to a size bigger than that fraction of the workarea
* will be scaled down to that size (while maintaining aspect ratio).
@@ -1065,6 +1064,8 @@ meta_window_new_shared (MetaDisplay *display,
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_load_initial_properties (window);
else
meta_wayland_surface_set_initial_state (window->surface, window);
if (window->override_redirect)
{
@@ -2000,8 +2001,6 @@ meta_window_unmanage (MetaWindow *window,
meta_window_ungrab_keys (window);
meta_display_ungrab_window_buttons (window->display, window->xwindow);
meta_display_ungrab_focus_window_button (window->display, window);
if (window->display->autoraise_window == window)
meta_display_remove_autoraise_callback (window->display);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
@@ -2931,8 +2930,8 @@ static gboolean
windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
{
MetaRectangle w1rect, w2rect;
meta_window_get_frame_rect (w1, &w1rect);
meta_window_get_frame_rect (w2, &w2rect);
meta_window_get_outer_rect (w1, &w1rect);
meta_window_get_outer_rect (w2, &w2rect);
return meta_rectangle_overlap (&w1rect, &w2rect);
}
@@ -3733,11 +3732,11 @@ meta_window_maximize (MetaWindow *window,
MetaRectangle old_rect;
MetaRectangle new_rect;
meta_window_get_frame_rect (window, &old_rect);
meta_window_get_outer_rect (window, &old_rect);
meta_window_move_resize_now (window);
meta_window_get_frame_rect (window, &new_rect);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_maximize_window (window->display->compositor,
window,
&old_rect,
@@ -3796,7 +3795,7 @@ meta_window_get_all_monitors (MetaWindow *window, gsize *length)
int i;
monitors = g_array_new (FALSE, FALSE, sizeof (int));
meta_window_get_frame_rect (window, &window_rect);
meta_window_get_outer_rect (window, &window_rect);
for (i = 0; i < window->screen->n_monitor_infos; i++)
{
@@ -3829,7 +3828,7 @@ meta_window_is_screen_sized (MetaWindow *window)
int screen_width, screen_height;
meta_screen_get_size (window->screen, &screen_width, &screen_height);
meta_window_get_frame_rect (window, &window_rect);
meta_window_get_outer_rect (window, &window_rect);
if (window_rect.x == 0 && window_rect.y == 0 &&
window_rect.width == screen_width && window_rect.height == screen_height)
@@ -3858,7 +3857,7 @@ meta_window_is_monitor_sized (MetaWindow *window)
{
MetaRectangle window_rect, monitor_rect;
meta_window_get_frame_rect (window, &window_rect);
meta_window_get_outer_rect (window, &window_rect);
meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
if (meta_rectangle_equal (&window_rect, &monitor_rect))
@@ -3926,11 +3925,11 @@ meta_window_tile (MetaWindow *window)
MetaRectangle old_rect;
MetaRectangle new_rect;
meta_window_get_frame_rect (window, &old_rect);
meta_window_get_outer_rect (window, &old_rect);
meta_window_move_resize_now (window);
meta_window_get_frame_rect (window, &new_rect);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_maximize_window (window->display->compositor,
window,
&old_rect,
@@ -3959,7 +3958,7 @@ meta_window_can_tile_side_by_side (MetaWindow *window)
{
int monitor;
MetaRectangle tile_area;
MetaRectangle client_rect;
MetaFrameBorders borders;
if (!meta_window_can_tile_maximized (window))
return FALSE;
@@ -3973,10 +3972,13 @@ meta_window_can_tile_side_by_side (MetaWindow *window)
tile_area.width /= 2;
meta_window_frame_rect_to_client_rect (window, &tile_area, &client_rect);
meta_frame_calc_borders (window->frame, &borders);
return client_rect.width >= window->size_hints.min_width &&
client_rect.height >= window->size_hints.min_height;
tile_area.width -= (borders.visible.left + borders.visible.right);
tile_area.height -= (borders.visible.top + borders.visible.bottom);
return tile_area.width >= window->size_hints.min_width &&
tile_area.height >= window->size_hints.min_height;
}
static void
@@ -4098,7 +4100,7 @@ meta_window_unmaximize_internal (MetaWindow *window,
{
MetaRectangle old_rect, new_rect;
meta_window_get_frame_rect (window, &old_rect);
meta_window_get_outer_rect (window, &old_rect);
meta_window_move_resize_internal (window,
META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
@@ -4108,7 +4110,7 @@ meta_window_unmaximize_internal (MetaWindow *window,
target_rect.width,
target_rect.height);
meta_window_get_frame_rect (window, &new_rect);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_unmaximize_window (window->display->compositor,
window,
&old_rect,
@@ -4213,7 +4215,6 @@ meta_window_set_above (MetaWindow *window,
window->wm_state_above = new_value;
meta_window_update_layer (window);
set_net_wm_state (window);
meta_window_frame_size_changed (window);
g_object_notify (G_OBJECT (window), "above");
}
@@ -4353,7 +4354,6 @@ meta_window_shade (MetaWindow *window,
window->shaded = TRUE;
meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
meta_window_frame_size_changed (window);
/* After queuing the calc showing, since _focus flushes it,
* and we need to focus the frame
@@ -4379,7 +4379,6 @@ meta_window_unshade (MetaWindow *window,
{
window->shaded = FALSE;
meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
meta_window_frame_size_changed (window);
/* focus the window */
meta_topic (META_DEBUG_FOCUS,
@@ -5118,6 +5117,7 @@ meta_window_move_resize_internal (MetaWindow *window,
if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
{
meta_window_constrain (window,
window->frame ? &borders : NULL,
flags,
gravity,
&old_rect,
@@ -5669,10 +5669,23 @@ meta_window_move_frame (MetaWindow *window,
int root_x_nw,
int root_y_nw)
{
MetaRectangle rect = { root_x_nw, root_y_nw, 0, 0 };
int x = root_x_nw;
int y = root_y_nw;
meta_window_frame_rect_to_client_rect (window, &rect, &rect);
meta_window_move (window, user_op, rect.x, rect.y);
if (window->frame)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
/* root_x_nw and root_y_nw correspond to where the top of
* the visible frame should be. Offset by the distance between
* the origin of the window and the origin of the enclosing
* window decorations.
*/
x += window->frame->child_x - borders.invisible.left;
y += window->frame->child_y - borders.invisible.top;
}
meta_window_move (window, user_op, x, y);
}
static void
@@ -5720,10 +5733,18 @@ meta_window_move_resize_frame (MetaWindow *window,
int w,
int h)
{
MetaRectangle rect = { root_x_nw, root_y_nw, w, h };
meta_window_frame_rect_to_client_rect (window, &rect, &rect);
MetaFrameBorders borders;
meta_window_move_resize (window, user_op, rect.x, rect.y, rect.width, rect.height);
meta_frame_calc_borders (window->frame, &borders);
/* offset by the distance between the origin of the window
* and the origin of the enclosing window decorations ( + border)
*/
root_x_nw += borders.visible.left;
root_y_nw += borders.visible.top;
w -= borders.visible.left + borders.visible.right;
h -= borders.visible.top + borders.visible.bottom;
meta_window_move_resize (window, user_op, root_x_nw, root_y_nw, w, h);
}
/**
@@ -6036,110 +6057,16 @@ meta_window_get_input_rect (const MetaWindow *window,
}
/**
* meta_window_client_rect_to_frame_rect:
* @window: a #MetaWindow
* @frame_rect: client rectangle in root coordinates
* @client_rect: (out): location to store the computed corresponding frame bounds.
*
* Converts a desired bounds of the client window - what is passed to meta_window_move_resize() -
* into the corresponding bounds of the window frame (excluding invisible borders
* and client side shadows.)
*/
void
meta_window_client_rect_to_frame_rect (MetaWindow *window,
MetaRectangle *frame_rect,
MetaRectangle *client_rect)
{
if (!client_rect)
return;
*client_rect = *frame_rect;
/* The support for G_MAXINT here to mean infinity is a convenience for
* constraints.c:get_size_limits() and not something that we provide
* in other locations or document.
*/
if (window->frame)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
client_rect->x -= borders.visible.left;
client_rect->y -= borders.visible.top;
if (client_rect->width != G_MAXINT)
client_rect->width += borders.visible.left + borders.visible.right;
if (client_rect->height != G_MAXINT)
client_rect->height += borders.visible.top + borders.visible.bottom;
}
else
{
if (window->has_custom_frame_extents)
{
const GtkBorder *extents = &window->custom_frame_extents;
client_rect->x += extents->left;
client_rect->y += extents->top;
if (client_rect->width != G_MAXINT)
client_rect->width -= extents->left + extents->right;
if (client_rect->height != G_MAXINT)
client_rect->height -= extents->top + extents->bottom;
}
}
}
/**
* meta_window_frame_rect_to_client_rect:
* @window: a #MetaWindow
* @frame_rect: desired frame bounds for the window
* @client_rect: (out): location to store the computed corresponding client rectangle.
*
* Converts a desired frame bounds for a window into the bounds of the client
* window - what is passed to meta_window_move_resize().
*/
void
meta_window_frame_rect_to_client_rect (MetaWindow *window,
MetaRectangle *frame_rect,
MetaRectangle *client_rect)
{
if (!client_rect)
return;
*client_rect = *frame_rect;
if (window->frame)
{
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
client_rect->x += borders.visible.left;
client_rect->y += borders.visible.top;
client_rect->width -= borders.visible.left + borders.visible.right;
client_rect->height -= borders.visible.top + borders.visible.bottom;
}
else
{
if (window->has_custom_frame_extents)
{
const GtkBorder *extents = &window->custom_frame_extents;
client_rect->x -= extents->left;
client_rect->y -= extents->top;
client_rect->width += extents->left + extents->right;
client_rect->height += extents->top + extents->bottom;
}
}
}
/**
* meta_window_get_frame_rect:
* meta_window_get_outer_rect:
* @window: a #MetaWindow
* @rect: (out): pointer to an allocated #MetaRectangle
*
* Gets the rectangle that bounds @window that is what the user thinks of
* as the edge of the window. This doesn't include any extra reactive
* area that we or the client adds to the window, or any area that the
* client adds to draw a client-side shadow.
* Gets the rectangle that bounds @window that is responsive to mouse events.
* This includes only what is visible; it doesn't include any extra reactive
* area we add to the edges of windows.
*/
void
meta_window_get_frame_rect (const MetaWindow *window,
meta_window_get_outer_rect (const MetaWindow *window,
MetaRectangle *rect)
{
if (window->frame)
@@ -6168,25 +6095,6 @@ meta_window_get_frame_rect (const MetaWindow *window,
}
}
/**
* meta_window_get_outer_rect:
* @window: a #MetaWindow
* @rect: (out): pointer to an allocated #MetaRectangle
*
* Gets the rectangle that bounds @window that is what the user thinks of
* as the edge of the window. This doesn't include any extra reactive
* area that we or the client adds to the window, or any area that the
* client adds to draw a client-side shadow.
*
* Deprecated: 3.10: Use meta_window_get_frame_rect() instead.
*/
void
meta_window_get_outer_rect (const MetaWindow *window,
MetaRectangle *rect)
{
meta_window_get_frame_rect (window, rect);
}
const char*
meta_window_get_startup_id (MetaWindow *window)
{
@@ -6408,7 +6316,6 @@ window_stick_impl (MetaWindow *window)
* toggled back off.
*/
window->on_all_workspaces_requested = TRUE;
meta_window_frame_size_changed (window);
meta_window_update_on_all_workspaces (window);
meta_window_queue(window, META_QUEUE_CALC_SHOWING);
@@ -6423,7 +6330,6 @@ window_unstick_impl (MetaWindow *window)
/* Revert to window->workspaces */
window->on_all_workspaces_requested = FALSE;
meta_window_frame_size_changed (window);
meta_window_update_on_all_workspaces (window);
/* We change ourselves to the active workspace, since otherwise you'd get
@@ -6930,7 +6836,8 @@ meta_window_property_notify (MetaWindow *window,
void
meta_window_change_workspace_by_index (MetaWindow *window,
gint space_index,
gboolean append)
gboolean append,
guint32 timestamp)
{
MetaWorkspace *workspace;
MetaScreen *screen;
@@ -6949,7 +6856,11 @@ meta_window_change_workspace_by_index (MetaWindow *window,
meta_screen_get_workspace_by_index (screen, space_index);
if (!workspace && append)
workspace = meta_screen_append_new_workspace (screen, FALSE, CurrentTime);
{
if (timestamp == CurrentTime)
timestamp = meta_display_get_current_time_roundtrip (window->display);
workspace = meta_screen_append_new_workspace (screen, FALSE, timestamp);
}
if (workspace)
{
@@ -7499,7 +7410,6 @@ static void
meta_window_appears_focused_changed (MetaWindow *window)
{
set_net_wm_state (window);
meta_window_frame_size_changed (window);
g_object_notify (G_OBJECT (window), "appears-focused");
@@ -8676,13 +8586,6 @@ meta_window_type_changed (MetaWindow *window)
g_object_thaw_notify (object);
}
void
meta_window_frame_size_changed (MetaWindow *window)
{
if (window->frame)
meta_frame_clear_cached_borders (window->frame);
}
static void
set_allowed_actions_hint (MetaWindow *window)
{
@@ -8885,13 +8788,18 @@ recalc_window_features (MetaWindow *window)
if (window->has_maximize_func)
{
MetaRectangle work_area, client_rect;
MetaRectangle work_area;
MetaFrameBorders borders;
int min_frame_width, min_frame_height;
meta_window_get_work_area_current_monitor (window, &work_area);
meta_window_frame_rect_to_client_rect (window, &work_area, &client_rect);
meta_frame_calc_borders (window->frame, &borders);
if (window->size_hints.min_width >= client_rect.width ||
window->size_hints.min_height >= client_rect.height)
min_frame_width = window->size_hints.min_width + borders.visible.left + borders.visible.right;
min_frame_height = window->size_hints.min_height + borders.visible.top + borders.visible.bottom;
if (min_frame_width >= work_area.width ||
min_frame_height >= work_area.height)
window->has_maximize_func = FALSE;
}
@@ -8983,8 +8891,6 @@ recalc_window_features (MetaWindow *window)
if (window->has_resize_func != old_has_resize_func)
g_object_notify (G_OBJECT (window), "resizeable");
meta_window_frame_size_changed (window);
/* FIXME perhaps should ensure if we don't have a shade func,
* we aren't shaded, etc.
*/
@@ -9261,7 +9167,7 @@ meta_window_show_menu (MetaWindow *window,
void
meta_window_shove_titlebar_onscreen (MetaWindow *window)
{
MetaRectangle frame_rect;
MetaRectangle outer_rect;
GList *onscreen_region;
int horiz_amount, vert_amount;
int newx, newy;
@@ -9273,15 +9179,15 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
return;
/* Get the basic info we need */
meta_window_get_frame_rect (window, &frame_rect);
meta_window_get_outer_rect (window, &outer_rect);
onscreen_region = window->screen->active_workspace->screen_region;
/* Extend the region (just in case the window is too big to fit on the
* screen), then shove the window on screen, then return the region to
* normal.
*/
horiz_amount = frame_rect.width;
vert_amount = frame_rect.height;
horiz_amount = outer_rect.width;
vert_amount = outer_rect.height;
meta_rectangle_expand_region (onscreen_region,
horiz_amount,
horiz_amount,
@@ -9289,15 +9195,15 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
vert_amount);
meta_rectangle_shove_into_region(onscreen_region,
FIXED_DIRECTION_X,
&frame_rect);
&outer_rect);
meta_rectangle_expand_region (onscreen_region,
-horiz_amount,
-horiz_amount,
0,
-vert_amount);
newx = frame_rect.x + window->frame->child_x;
newy = frame_rect.y + window->frame->child_y;
newx = outer_rect.x + window->frame->child_x;
newy = outer_rect.y + window->frame->child_y;
meta_window_move_resize (window,
FALSE,
newx,
@@ -9322,7 +9228,7 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
return FALSE;
/* Get the rectangle corresponding to the titlebar */
meta_window_get_frame_rect (window, &titlebar_rect);
meta_window_get_outer_rect (window, &titlebar_rect);
titlebar_rect.height = window->frame->child_y;
/* Run through the spanning rectangles for the screen and see if one of
@@ -10000,20 +9906,96 @@ update_resize (MetaWindow *window,
g_get_current_time (&window->display->grab_last_moveresize_time);
}
static gboolean
check_use_this_motion_notify (MetaWindow *window,
const ClutterEvent *event)
typedef struct
{
/* XXX: Previously this code would walk through the X event queue
and filter out motion events that are followed by a later motion
event. There currently isn't any API to do the equivalent
procedure with the Clutter event queue so this function does
nothing. Clutter does its own motion event squashing so it may be
the case that this function isn't necessary. If it turns out that
we do need additional motion event squashing we could add some
extra API to the Clutter event queue and implement this function
properly. */
return TRUE;
Window window;
int count;
guint32 last_time;
} EventScannerData;
static Bool
find_last_time_predicate (Display *display,
XEvent *ev,
XPointer arg)
{
EventScannerData *esd = (void*) arg;
XIEvent *xev;
if (ev->type != GenericEvent)
return False;
/* We are peeking into events not yet handled by GDK,
* Allocate cookie events here so we can handle XI2.
*
* GDK will handle later these events, and eventually
* free the cookie data itself.
*/
XGetEventData (display, &ev->xcookie);
xev = (XIEvent *) ev->xcookie.data;
if (xev->evtype != XI_Motion)
return False;
if (esd->window != ((XIDeviceEvent *) xev)->event)
return False;
esd->count += 1;
esd->last_time = xev->time;
return False;
}
static gboolean
check_use_this_motion_notify (MetaWindow *window,
XIDeviceEvent *xev)
{
EventScannerData esd;
XEvent useless;
/* This code is copied from Owen's GDK code. */
if (window->display->grab_motion_notify_time != 0)
{
/* == is really the right test, but I'm all for paranoia */
if (window->display->grab_motion_notify_time <=
xev->time)
{
meta_topic (META_DEBUG_RESIZING,
"Arrived at event with time %u (waiting for %u), using it\n",
(unsigned int)xev->time,
window->display->grab_motion_notify_time);
window->display->grab_motion_notify_time = 0;
return TRUE;
}
else
return FALSE; /* haven't reached the saved timestamp yet */
}
esd.window = xev->event;
esd.count = 0;
esd.last_time = 0;
/* "useless" isn't filled in because the predicate never returns True */
XCheckIfEvent (window->display->xdisplay,
&useless,
find_last_time_predicate,
(XPointer) &esd);
if (esd.count > 0)
meta_topic (META_DEBUG_RESIZING,
"Will skip %d motion events and use the event with time %u\n",
esd.count, (unsigned int) esd.last_time);
if (esd.last_time == 0)
return TRUE;
else
{
/* Save this timestamp, and ignore all motion notify
* until we get to the one with this stamp.
*/
window->display->grab_motion_notify_time = esd.last_time;
return FALSE;
}
}
static void
@@ -10087,90 +10069,81 @@ meta_window_update_sync_request_counter (MetaWindow *window,
#endif /* HAVE_XSYNC */
void
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
const ClutterEvent *event)
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
XIDeviceEvent *xev)
{
gboolean is_window_root = (event->any.stage != NULL &&
window &&
window->screen &&
CLUTTER_ACTOR (event->any.stage) ==
meta_get_stage_for_screen (window->screen));
switch (event->type)
switch (xev->evtype)
{
case CLUTTER_BUTTON_RELEASE:
if (event->button.button == 1 ||
event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ())
case XI_ButtonRelease:
meta_display_check_threshold_reached (window->display,
xev->root_x,
xev->root_y);
/* If the user was snap moving then ignore the button release
* because they may have let go of shift before releasing the
* mouse button and they almost certainly do not want a
* non-snapped movement to occur from the button release.
*/
if (!window->display->grab_last_user_action_was_snap)
{
meta_display_check_threshold_reached (window->display,
event->button.x,
event->button.y);
/* If the user was snap moving then ignore the button
* release because they may have let go of shift before
* releasing the mouse button and they almost certainly do
* not want a non-snapped movement to occur from the button
* release.
*/
if (!window->display->grab_last_user_action_was_snap)
if (meta_grab_op_is_moving (window->display->grab_op))
{
if (meta_grab_op_is_moving (window->display->grab_op))
{
if (window->tile_mode != META_TILE_NONE)
meta_window_tile (window);
else if (is_window_root)
update_move (window,
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->button.x,
event->button.y);
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (is_window_root)
update_resize (window,
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->button.x,
event->button.y,
TRUE);
if (window->tile_mode != META_TILE_NONE)
meta_window_tile (window);
else if (xev->root == window->screen->xroot)
update_move (window,
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y);
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (xev->root == window->screen->xroot)
update_resize (window,
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y,
TRUE);
/* If a tiled window has been dragged free with a
* mouse resize without snapping back to the tiled
* state, it will end up with an inconsistent tile
* mode on mouse release; cleaning the mode earlier
* would break the ability to snap back to the tiled
* state, so we wait until mouse release.
*/
update_tile_mode (window);
}
meta_display_end_grab_op (window->display, event->any.time);
/* If a tiled window has been dragged free with a
* mouse resize without snapping back to the tiled
* state, it will end up with an inconsistent tile
* mode on mouse release; cleaning the mode earlier
* would break the ability to snap back to the tiled
* state, so we wait until mouse release.
*/
update_tile_mode (window);
}
}
meta_display_end_grab_op (window->display, xev->time);
break;
case CLUTTER_MOTION:
case XI_Motion:
meta_display_check_threshold_reached (window->display,
event->motion.x,
event->motion.y);
xev->root_x,
xev->root_y);
if (meta_grab_op_is_moving (window->display->grab_op))
{
if (is_window_root)
if (xev->root == window->screen->xroot)
{
if (check_use_this_motion_notify (window, event))
if (check_use_this_motion_notify (window,
xev))
update_move (window,
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->motion.x,
event->motion.y);
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y);
}
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (is_window_root)
if (xev->root == window->screen->xroot)
{
if (check_use_this_motion_notify (window, event))
if (check_use_this_motion_notify (window,
xev))
update_resize (window,
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->motion.x,
event->motion.y,
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y,
FALSE);
}
}
@@ -10552,7 +10525,7 @@ warp_grab_pointer (MetaWindow *window,
/* We may not have done begin_grab_op yet, i.e. may not be in a grab
*/
meta_window_get_frame_rect (window, &rect);
meta_window_get_outer_rect (window, &rect);
switch (grab_op)
{
@@ -10891,7 +10864,7 @@ meta_window_set_demands_attention (MetaWindow *window)
}
else
{
meta_window_get_frame_rect (window, &candidate_rect);
meta_window_get_outer_rect (window, &candidate_rect);
/* The stack is sorted with the top windows first. */
@@ -10902,7 +10875,7 @@ meta_window_set_demands_attention (MetaWindow *window)
if (meta_window_located_on_workspace (other_window, window->workspace))
{
meta_window_get_frame_rect (other_window, &other_rect);
meta_window_get_outer_rect (other_window, &other_rect);
if (meta_rectangle_overlap (&candidate_rect, &other_rect))
{
@@ -11608,8 +11581,8 @@ meta_window_compute_tile_match (MetaWindow *window)
bottommost = match;
}
meta_window_get_frame_rect (bottommost, &bottommost_rect);
meta_window_get_frame_rect (topmost, &topmost_rect);
meta_window_get_outer_rect (bottommost, &bottommost_rect);
meta_window_get_outer_rect (topmost, &topmost_rect);
/*
* If there's a window stacked in between which is partially visible
* behind the topmost tile we don't consider the tiles to match.
@@ -11623,7 +11596,7 @@ meta_window_compute_tile_match (MetaWindow *window)
meta_window_get_workspace (above) != meta_window_get_workspace (window))
continue;
meta_window_get_frame_rect (above, &above_rect);
meta_window_get_outer_rect (above, &above_rect);
if (meta_rectangle_overlap (&above_rect, &bottommost_rect) &&
meta_rectangle_overlap (&above_rect, &topmost_rect))
@@ -11766,185 +11739,3 @@ meta_window_set_transient_for (MetaWindow *window,
if (meta_window_appears_focused (window) && window->transient_for != None)
meta_window_propagate_focus_appearance (window, TRUE);
}
static void
reset_ignored_crossing_serials (MetaDisplay *display)
{
int i;
i = 0;
while (i < N_IGNORED_CROSSING_SERIALS)
{
display->ignored_crossing_serials[i] = 0;
++i;
}
display->ungrab_should_not_cause_focus_window = None;
}
typedef struct
{
MetaWindow *window;
int pointer_x;
int pointer_y;
} MetaFocusData;
static void
mouse_mode_focus (MetaWindow *window,
guint32 timestamp)
{
MetaDisplay *display = window->display;
if (window->type != META_WINDOW_DESKTOP)
{
meta_topic (META_DEBUG_FOCUS,
"Focusing %s at time %u.\n", window->desc, timestamp);
meta_window_focus (window, timestamp);
if (meta_prefs_get_auto_raise ())
meta_display_queue_autoraise_callback (display, window);
else
meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n");
}
else
{
/* In mouse focus mode, we defocus when the mouse *enters*
* the DESKTOP window, instead of defocusing on LeaveNotify.
* This is because having the mouse enter override-redirect
* child windows unfortunately causes LeaveNotify events that
* we can't distinguish from the mouse actually leaving the
* toplevel window as we expect. But, since we filter out
* EnterNotify events on override-redirect windows, this
* alternative mechanism works great.
*/
if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE &&
display->focus_window != NULL)
{
meta_topic (META_DEBUG_FOCUS,
"Unsetting focus from %s due to mouse entering "
"the DESKTOP window\n",
display->focus_window->desc);
meta_display_focus_the_no_focus_window (display,
window->screen,
timestamp);
}
}
}
static gboolean
window_focus_on_pointer_rest_callback (gpointer data)
{
MetaFocusData *focus_data = data;
MetaWindow *window = focus_data->window;
MetaDisplay *display = window->display;
MetaScreen *screen = window->screen;
Window root, child;
double root_x, root_y, x, y;
guint32 timestamp;
XIButtonState buttons;
XIModifierState mods;
XIGroupState group;
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
goto out;
meta_error_trap_push (display);
XIQueryPointer (display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
screen->xroot,
&root, &child,
&root_x, &root_y, &x, &y,
&buttons, &mods, &group);
meta_error_trap_pop (display);
free (buttons.mask);
if (root_x != focus_data->pointer_x ||
root_y != focus_data->pointer_y)
{
focus_data->pointer_x = root_x;
focus_data->pointer_y = root_y;
return TRUE;
}
/* Explicitly check for the overlay window, as get_focus_window_at_point()
* may return windows that extend underneath the chrome (like
* override-redirect or DESKTOP windows)
*/
if (child == meta_get_overlay_window (screen))
goto out;
window =
meta_stack_get_default_focus_window_at_point (screen->stack,
screen->active_workspace,
None, root_x, root_y);
if (window == NULL)
goto out;
timestamp = meta_display_get_current_time_roundtrip (display);
mouse_mode_focus (window, timestamp);
out:
display->focus_timeout_id = 0;
return FALSE;
}
/* The interval, in milliseconds, we use in focus-follows-mouse
* mode to check whether the pointer has stopped moving after a
* crossing event.
*/
#define FOCUS_TIMEOUT_DELAY 25
static void
queue_focus_callback (MetaDisplay *display,
MetaWindow *window,
int pointer_x,
int pointer_y)
{
MetaFocusData *focus_data;
focus_data = g_new (MetaFocusData, 1);
focus_data->window = window;
focus_data->pointer_x = pointer_x;
focus_data->pointer_y = pointer_y;
if (display->focus_timeout_id != 0)
g_source_remove (display->focus_timeout_id);
display->focus_timeout_id =
g_timeout_add_full (G_PRIORITY_DEFAULT,
FOCUS_TIMEOUT_DELAY,
window_focus_on_pointer_rest_callback,
focus_data,
g_free);
}
void
meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,
guint root_y)
{
MetaDisplay *display = window->display;
switch (meta_prefs_get_focus_mode ())
{
case G_DESKTOP_FOCUS_MODE_SLOPPY:
case G_DESKTOP_FOCUS_MODE_MOUSE:
display->mouse_mode = TRUE;
if (window->type != META_WINDOW_DOCK)
{
if (meta_prefs_get_focus_change_on_pointer_rest())
queue_focus_callback (display, window, root_x, root_y);
else
mouse_mode_focus (window, timestamp);
/* stop ignoring stuff */
reset_ignored_crossing_serials (display);
}
break;
case G_DESKTOP_FOCUS_MODE_CLICK:
break;
}
}

View File

@@ -82,7 +82,6 @@ item(VERSION)
item(ATOM_PAIR)
item(BACKLIGHT)
item(_XKB_RULES_NAMES)
item(hotplug_mode_update)
/* Oddities: These are used, and we need atoms for them,
* but when we need all _NET_WM hints (i.e. when we're making

View File

@@ -94,6 +94,7 @@ typedef enum {
struct _MetaBarrierEvent {
/* < private > */
volatile guint ref_count;
MetaBarrier *barrier;
/* < public > */
int event_id;

View File

@@ -31,7 +31,6 @@
#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include <clutter/clutter.h>
#include <glib.h>
#include <gtk/gtk.h>

View File

@@ -35,6 +35,13 @@ gboolean meta_keybindings_set_custom_handler (const gchar *name,
gpointer user_data,
GDestroyNotify free_data);
void meta_keybindings_switch_window (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *event_window,
XIDeviceEvent *event,
MetaKeyBinding *binding);
void meta_screen_ungrab_all_keys (MetaScreen *screen, guint32 timestamp);
gboolean meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp);
#endif

View File

@@ -248,7 +248,6 @@ void meta_prefs_set_ignore_request_hide_titlebar (gboolean whether);
* @META_KEYBINDING_ACTION_LOWER: FILLME
* @META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY: FILLME
* @META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY: FILLME
* @META_KEYBINDING_ACTION_ALWAYS_ON_TOP: FILLME
* @META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW: FILLME
* @META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE: FILLME
* @META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW: FILLME
@@ -340,7 +339,6 @@ typedef enum _MetaKeyBindingAction
META_KEYBINDING_ACTION_RAISE,
META_KEYBINDING_ACTION_LOWER,
META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY,
META_KEYBINDING_ACTION_ALWAYS_ON_TOP,
META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY,
META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW,
META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE,
@@ -393,17 +391,17 @@ struct _MetaKeyCombo
* @display: a #MetaDisplay
* @screen: a #MetaScreen
* @window: a #MetaWindow
* @event: a #ClutterKeyEvent
* @event: (type gpointer): a #XIDeviceEvent
* @binding: a #MetaKeyBinding
* @user_data: data passed to the function
*
*/
typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
ClutterKeyEvent *event,
MetaKeyBinding *binding,
gpointer user_data);
typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XIDeviceEvent *event,
MetaKeyBinding *binding,
gpointer user_data);
typedef struct _MetaKeyHandler MetaKeyHandler;
@@ -421,13 +419,13 @@ typedef struct
*/
GSList *bindings;
/* for keybindings that can have shift or not like Alt+Tab */
/** for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift:1;
/* for keybindings that apply only to a window */
/** for keybindings that apply only to a window */
gboolean per_window:1;
/* for keybindings not added with meta_display_add_keybinding() */
/** for keybindings not added with meta_display_add_keybinding() */
gboolean builtin:1;
} MetaKeyPref;

View File

@@ -110,17 +110,7 @@ gboolean meta_window_is_override_redirect (MetaWindow *window);
gboolean meta_window_is_skip_taskbar (MetaWindow *window);
MetaRectangle *meta_window_get_rect (MetaWindow *window);
void meta_window_get_input_rect (const MetaWindow *window, MetaRectangle *rect);
void meta_window_get_frame_rect (const MetaWindow *window, MetaRectangle *rect);
void meta_window_get_outer_rect (const MetaWindow *window, MetaRectangle *rect) G_GNUC_DEPRECATED;
void meta_window_client_rect_to_frame_rect (MetaWindow *window,
MetaRectangle *frame_rect,
MetaRectangle *client_rect);
void meta_window_frame_rect_to_client_rect (MetaWindow *window,
MetaRectangle *frame_rect,
MetaRectangle *client_rect);
void meta_window_get_outer_rect (const MetaWindow *window, MetaRectangle *rect);
MetaScreen *meta_window_get_screen (MetaWindow *window);
MetaDisplay *meta_window_get_display (MetaWindow *window);
Window meta_window_get_xwindow (MetaWindow *window);
@@ -160,7 +150,8 @@ void meta_window_unset_demands_attention (MetaWindow *window);
const char* meta_window_get_startup_id (MetaWindow *window);
void meta_window_change_workspace_by_index (MetaWindow *window,
gint space_index,
gboolean append);
gboolean append,
guint32 timestamp);
void meta_window_change_workspace (MetaWindow *window,
MetaWorkspace *workspace);
GObject *meta_window_get_compositor_private (MetaWindow *window);

View File

@@ -412,6 +412,81 @@ set_modifiers (MetaWaylandKeyboard *keyboard,
new_state.group);
}
#define N_BUTTONS 5
static gboolean
process_keybinding (MetaWaylandKeyboard *keyboard,
const ClutterEvent *event)
{
MetaWaylandSurface *surface;
XGenericEventCookie generic_event;
XIDeviceEvent device_event;
unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
MetaDisplay *display = meta_get_display ();
ClutterModifierType button_state;
int i;
if (!display) /* not initialized yet */
return FALSE;
generic_event.type = GenericEvent;
generic_event.serial = 0;
generic_event.send_event = False;
generic_event.display = display->xdisplay;
generic_event.extension = display->xinput_opcode;
if (clutter_event_type (event) == CLUTTER_KEY_PRESS)
generic_event.evtype = XI_KeyPress;
else
generic_event.evtype = XI_KeyRelease;
/* Mutter assumes the data for the event is already retrieved by GDK
* so we don't need the cookie */
generic_event.cookie = 0;
generic_event.data = &device_event;
memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
device_event.time = clutter_event_get_time (event);
device_event.deviceid = clutter_event_get_device_id (event);
device_event.sourceid = 0; /* not used, not sure what this should be */
device_event.detail = clutter_event_get_key_code (event);
device_event.root = DefaultRootWindow (display->xdisplay);
device_event.flags = 0;
surface = keyboard->focus;
if (surface)
device_event.event = surface->window ? surface->window->xwindow : device_event.root;
else
device_event.event = device_event.root;
/* Mutter doesn't really know about the sub-windows. This assumes it
doesn't care either */
device_event.child = device_event.event;
device_event.root_x = 0;
device_event.root_y = 0;
clutter_event_get_state_full (event,
&button_state,
(ClutterModifierType*)&device_event.mods.base,
(ClutterModifierType*)&device_event.mods.latched,
(ClutterModifierType*)&device_event.mods.locked,
(ClutterModifierType*)&device_event.mods.effective);
device_event.mods.effective &= ~button_state;
memset (&device_event.group, 0, sizeof (device_event.group));
device_event.group.effective = (device_event.mods.effective >> 13) & 0x3;
for (i = 0; i < N_BUTTONS; i++)
if ((button_state & (CLUTTER_BUTTON1_MASK << i)))
XISetMask (button_mask, i + 1);
device_event.buttons.mask_len = N_BUTTONS + 1;
device_event.buttons.mask = button_mask;
device_event.valuators.mask_len = 0;
device_event.valuators.mask = NULL;
device_event.valuators.values = NULL;
return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event);
}
static gboolean
update_pressed_keys (MetaWaylandKeyboard *keyboard,
uint32_t evdev_code,
@@ -484,6 +559,10 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
autorepeat ? " (autorepeat)" : "",
xkb_keycode);
/* Give a chance to process keybindings */
if (process_keybinding (keyboard, (ClutterEvent*) event))
return TRUE;
if (autorepeat)
return FALSE;
@@ -522,8 +601,6 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
serial = wl_display_next_serial (display);
wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
wl_list_remove (&keyboard->focus_listener.link);
meta_wayland_surface_focused_unset (keyboard->focus);
}
resource = find_resource_for_surface (&keyboard->resource_list, surface);
@@ -560,8 +637,6 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
}
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
keyboard->focus_serial = serial;
meta_wayland_surface_focused_set (surface);
}
keyboard->focus_resource = resource;

View File

@@ -49,7 +49,7 @@
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "xdg-shell-server-protocol.h"
#include "barrier-private.h"
#include <string.h>
@@ -166,10 +166,10 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
*/
static gboolean
check_all_screen_monitors(MetaMonitorInfo *monitors,
unsigned n_monitors,
float x,
float y)
check_all_screen_monitors (MetaMonitorInfo *monitors,
unsigned n_monitors,
float x,
float y)
{
unsigned int i;
@@ -194,14 +194,13 @@ static void
constrain_all_screen_monitors (ClutterInputDevice *device,
MetaMonitorInfo *monitors,
unsigned n_monitors,
float current_x,
float current_y,
float *x,
float *y)
{
ClutterPoint current;
unsigned int i;
clutter_input_device_get_coords (device, NULL, &current);
/* if we're trying to escape, clamp to the CRTC we're coming from */
for (i = 0; i < n_monitors; i++)
{
@@ -214,8 +213,8 @@ constrain_all_screen_monitors (ClutterInputDevice *device,
top = monitor->rect.y;
bottom = left + monitor->rect.height;
nx = current.x;
ny = current.y;
nx = current_x;
ny = current_y;
if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom))
{
@@ -240,21 +239,32 @@ pointer_constrain_callback (ClutterInputDevice *device,
float *new_y,
gpointer user_data)
{
MetaBarrierManager *barrier_manager;
MetaMonitorManager *monitor_manager;
MetaMonitorInfo *monitors;
unsigned int n_monitors;
gboolean ret;
ClutterPoint current;
clutter_input_device_get_coords (device, NULL, &current);
barrier_manager = meta_barrier_manager_get ();
monitor_manager = meta_monitor_manager_get ();
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
meta_barrier_manager_constrain_cursor (barrier_manager, time,
current.x, current.y,
new_x, new_y);
/* if we're moving inside a monitor, we're fine */
ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y);
if (ret == TRUE)
if (ret)
return;
/* if we're trying to escape, clamp to the CRTC we're coming from */
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
constrain_all_screen_monitors(device, monitors, n_monitors,
current.x, current.y,
new_x, new_y);
}
void
@@ -353,11 +363,6 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
}
meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
meta_window_handle_enter (surface->window,
/* XXX -- can we reliably get a timestamp for setting focus? */
clutter_get_current_event_time (),
wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y));
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
pointer->focus_serial = serial;
@@ -391,6 +396,32 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
interface->focus (pointer->grab, pointer->current, NULL);
}
static void
current_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer =
wl_container_of (listener, pointer, current_listener);
pointer->current = NULL;
}
void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
if (pointer->current)
wl_list_remove (&pointer->current_listener.link);
pointer->current = surface;
if (!surface)
return;
wl_resource_add_destroy_listener (surface->resource,
&pointer->current_listener);
pointer->current_listener.notify = current_surface_destroy;
}
static void
modal_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
@@ -538,14 +569,9 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link)
{
MetaWaylandSurfaceExtension *shell_surface = popup->surface->xdg_surface;
struct wl_client *client = wl_resource_get_client (shell_surface->resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial;
MetaWaylandSurfaceExtension *shell_surface = popup->surface->shell_surface;
serial = wl_display_next_serial (display);
xdg_popup_send_popup_done (shell_surface->resource, serial);
wl_shell_surface_send_popup_done (shell_surface->resource);
wl_list_remove (&popup->surface_destroy_listener.link);
wl_list_remove (&popup->link);
g_slice_free (MetaWaylandPopup, popup);

View File

@@ -62,6 +62,8 @@ struct _MetaWaylandPointer
wl_fixed_t x, y; /* TODO: remove, use ClutterInputDevice instead */
MetaWaylandSurface *current;
struct wl_listener current_listener;
wl_fixed_t current_x, current_y;
guint32 button_count;
};
@@ -95,6 +97,10 @@ gboolean
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *popup);
void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
void
meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,

View File

@@ -83,6 +83,14 @@ struct _MetaWaylandCompositor
int drm_fd;
MetaWaylandSeat *seat;
/* This surface is only used to keep drag of the implicit grab when
synthesizing XEvents for Mutter */
MetaWaylandSurface *implicit_grab_surface;
/* Button that was pressed to initiate an implicit grab. The
implicit grab will only be released when this button is
released */
guint32 implicit_grab_button;
};
void meta_wayland_init (void);
@@ -96,8 +104,6 @@ void meta_wayland_compositor_repick (MetaWaylandComp
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window);
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
@@ -107,7 +113,5 @@ MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resou
void meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
MetaWaylandBuffer *buffer);
void meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
#endif /* META_WAYLAND_PRIVATE_H */

View File

@@ -51,7 +51,14 @@ static void
pointer_unmap_sprite (MetaWaylandSeat *seat)
{
if (seat->cursor_tracker)
meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, NULL, 0, 0);
{
meta_cursor_tracker_set_buffer (seat->cursor_tracker,
NULL, 0, 0);
if (seat->current_stage)
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
CLUTTER_ACTOR (seat->current_stage));
}
if (seat->sprite)
{
@@ -69,10 +76,14 @@ meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
return;
buffer = seat->sprite->buffer_ref.buffer->resource;
meta_cursor_tracker_set_window_cursor (seat->cursor_tracker,
buffer,
seat->hotspot_x,
seat->hotspot_y);
meta_cursor_tracker_set_buffer (seat->cursor_tracker,
buffer,
seat->hotspot_x,
seat->hotspot_y);
if (seat->current_stage)
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
CLUTTER_ACTOR (seat->current_stage));
}
static void
@@ -246,6 +257,11 @@ notify_motion (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
float x, y;
clutter_event_get_coords (event, &x, &y);
pointer->x = wl_fixed_from_double (x);
pointer->y = wl_fixed_from_double (y);
meta_wayland_seat_repick (seat, event);
@@ -264,22 +280,34 @@ handle_button_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
gboolean implicit_grab;
gboolean state = event->type == CLUTTER_BUTTON_PRESS;
uint32_t button;
MetaWaylandSurface *surface;
notify_motion (seat, event);
implicit_grab = (event->type == CLUTTER_BUTTON_PRESS) && (pointer->button_count == 1);
if (implicit_grab)
if (state && pointer->button_count == 1)
{
pointer->grab_button = clutter_event_get_button (event);
button = clutter_event_get_button (event);
pointer->grab_button = button;
pointer->grab_time = clutter_event_get_time (event);
pointer->grab_x = pointer->x;
pointer->grab_y = pointer->y;
/* FIXME: synth a XI2 event and handle in display.c */
surface = pointer->current;
if (button == CLUTTER_BUTTON_PRIMARY &&
surface &&
surface->window &&
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
meta_window_raise (surface->window);
}
}
pointer->grab->interface->button (pointer->grab, event);
if (implicit_grab)
if (pointer->button_count == 1)
pointer->grab_serial = wl_display_get_serial (seat->display);
}
@@ -347,33 +375,12 @@ count_buttons (const ClutterEvent *event)
return count;
}
void
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
float x, y;
clutter_event_get_coords (event, &x, &y);
seat->pointer.x = wl_fixed_from_double (x);
seat->pointer.y = wl_fixed_from_double (y);
seat->pointer.button_count = count_buttons (event);
if (seat->cursor_tracker)
{
meta_cursor_tracker_update_position (seat->cursor_tracker,
wl_fixed_to_int (seat->pointer.x),
wl_fixed_to_int (seat->pointer.y));
if (seat->pointer.current == NULL)
meta_cursor_tracker_unset_window_cursor (seat->cursor_tracker);
}
}
gboolean
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
seat->pointer.button_count = count_buttons (event);
switch (event->type)
{
case CLUTTER_MOTION:
@@ -401,6 +408,20 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
return FALSE;
}
static void
update_pointer_position_for_actor (MetaWaylandPointer *pointer,
ClutterActor *actor)
{
float ax, ay;
clutter_actor_transform_stage_point (actor,
wl_fixed_to_double (pointer->x),
wl_fixed_to_double (pointer->y),
&ax, &ay);
pointer->current_x = wl_fixed_from_double (ax);
pointer->current_y = wl_fixed_from_double (ay);
}
/* The actor argument can be NULL in which case a Clutter pick will be
performed to determine the right actor. An actor should only be
passed if the repick is being performed due to an event in which
@@ -437,8 +458,18 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
MetaWindow *window =
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
update_pointer_position_for_actor (pointer, actor);
surface = window->surface;
}
else if (META_IS_SHAPED_TEXTURE (actor))
{
MetaShapedTexture *shaped_texture = META_SHAPED_TEXTURE (actor);
update_pointer_position_for_actor (pointer, actor);
surface = meta_shaped_texture_get_wayland_surface (shaped_texture);
}
pointer->current = surface;
if (surface != pointer->focus)

View File

@@ -77,10 +77,6 @@ MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native);
void
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
const ClutterEvent *event);
gboolean
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
const ClutterEvent *event);

File diff suppressed because it is too large Load Diff

View File

@@ -64,19 +64,31 @@ typedef struct
/* wl_surface.frame */
struct wl_list frame_callback_list;
} MetaWaylandDoubleBufferedState;
typedef enum {
META_WAYLAND_SURFACE_TOPLEVEL = 0,
META_WAYLAND_SURFACE_MAXIMIZED,
META_WAYLAND_SURFACE_FULLSCREEN,
META_WAYLAND_SURFACE_POPUP,
} MetaWaylandSurfaceType;
typedef struct
{
MetaWaylandSurfaceType initial_type;
struct wl_resource *transient_for;
int x, y;
/* xdg_surface */
char *title;
char *app_id;
char *wm_class;
/* gtk_surface */
char *gtk_application_id;
char *gtk_unique_bus_name;
char *gtk_app_menu_path;
char *gtk_menubar_path;
char *gtk_application_object_path;
char *gtk_window_object_path;
} MetaWaylandDoubleBufferedState;
} MetaWaylandSurfaceInitialState;
typedef struct
{
@@ -91,11 +103,15 @@ struct _MetaWaylandSurface
MetaWaylandCompositor *compositor;
MetaWaylandBufferReference buffer_ref;
MetaWindow *window;
MetaWaylandSurfaceExtension *xdg_surface;
MetaWaylandSurfaceExtension *shell_surface;
MetaWaylandSurfaceExtension *gtk_surface;
/* All the pending state, that wl_surface.commit will apply. */
MetaWaylandDoubleBufferedState pending;
/* All the initial state, that wl_shell_surface.set_* will apply
(through meta_window_new_for_wayland) */
MetaWaylandSurfaceInitialState *initial_state;
};
void meta_wayland_init_shell (MetaWaylandCompositor *compositor);
@@ -106,12 +122,12 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
guint32 version);
void meta_wayland_surface_free (MetaWaylandSurface *surface);
void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
MetaWindow *window);
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width,
int height,
int edges);
void meta_wayland_surface_focused_set (MetaWaylandSurface *surface);
void meta_wayland_surface_focused_unset (MetaWaylandSurface *surface);
#endif

View File

@@ -37,23 +37,23 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 3
#define META_WL_DATA_DEVICE_MANAGER_VERSION 1
#define META_WL_SHELL_VERSION 1
#define META_WL_SEAT_VERSION 2 /* 3 not implemented yet */
#define META_WL_OUTPUT_VERSION 2
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1
#define META_XDG_SHELL_VERSION 1
/* Slave objects (version inherited from a master object) */
#define META_WL_DATA_OFFER_VERSION 1 /* from wl_data_device */
#define META_WL_DATA_SOURCE_VERSION 1 /* from wl_data_device */
#define META_WL_DATA_DEVICE_VERSION 1 /* from wl_data_device_manager */
#define META_WL_SHELL_SURFACE_VERSION 1 /* from wl_shell */
#define META_WL_SURFACE_VERSION 3 /* from wl_compositor */
#define META_WL_POINTER_VERSION 2 /* from wl_seat; 3 not implemented yet */
#define META_WL_KEYBOARD_VERSION 2 /* from wl_seat; 3 not implemented yet */
#define META_WL_TOUCH_VERSION 0 /* from wl_seat; wl_touch not supported */
#define META_WL_REGION_VERSION 1 /* from wl_compositor */
#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */
#define META_XDG_SURFACE_VERSION 1 /* from xdg_shell */
/* The first version to implement a specific event */
#define META_WL_SEAT_HAS_NAME 2

View File

@@ -533,18 +533,127 @@ stage_destroy_cb (void)
meta_quit (META_EXIT_SUCCESS);
}
void
meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
const ClutterEvent *event)
#define N_BUTTONS 5
static void
synthesize_motion_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event)
{
/* We want to synthesize X events for mouse motion events so that we
don't have to rely on the X server's window position being
synched with the surface position. See the comment in
event_callback() in display.c */
MetaWaylandSeat *seat = compositor->seat;
MetaWaylandPointer *pointer = &seat->pointer;
MetaWaylandSurface *surface;
XGenericEventCookie generic_event;
XIDeviceEvent device_event;
unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
MetaDisplay *display = meta_get_display ();
ClutterModifierType button_state;
int i;
generic_event.type = GenericEvent;
generic_event.serial = 0;
generic_event.send_event = False;
generic_event.display = display->xdisplay;
generic_event.extension = display->xinput_opcode;
generic_event.evtype = XI_Motion;
/* Mutter assumes the data for the event is already retrieved by GDK
* so we don't need the cookie */
generic_event.cookie = 0;
generic_event.data = &device_event;
memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
device_event.time = clutter_event_get_time (event);
device_event.deviceid = clutter_event_get_device_id (event);
device_event.sourceid = 0; /* not used, not sure what this should be */
device_event.detail = 0;
device_event.root = DefaultRootWindow (display->xdisplay);
device_event.flags = 0 /* not used for motion events */;
if (compositor->implicit_grab_surface)
surface = compositor->implicit_grab_surface;
else
surface = pointer->current;
if (surface == pointer->current)
{
device_event.event_x = wl_fixed_to_int (pointer->current_x);
device_event.event_y = wl_fixed_to_int (pointer->current_y);
}
else if (surface && surface->window)
{
ClutterActor *window_actor =
CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
if (window_actor)
{
float ax, ay;
clutter_actor_transform_stage_point (window_actor,
wl_fixed_to_double (pointer->x),
wl_fixed_to_double (pointer->y),
&ax, &ay);
device_event.event_x = ax;
device_event.event_y = ay;
}
else
{
device_event.event_x = wl_fixed_to_double (pointer->x);
device_event.event_y = wl_fixed_to_double (pointer->y);
}
}
else
{
device_event.event_x = wl_fixed_to_double (pointer->x);
device_event.event_y = wl_fixed_to_double (pointer->y);
}
if (surface && surface->window != NULL)
device_event.event = surface->window->xwindow;
else
device_event.event = device_event.root;
/* Mutter doesn't really know about the sub-windows. This assumes it
doesn't care either */
device_event.child = device_event.event;
device_event.root_x = wl_fixed_to_double (pointer->x);
device_event.root_y = wl_fixed_to_double (pointer->y);
clutter_event_get_state_full (event,
&button_state,
(ClutterModifierType*)&device_event.mods.base,
(ClutterModifierType*)&device_event.mods.latched,
(ClutterModifierType*)&device_event.mods.locked,
(ClutterModifierType*)&device_event.mods.effective);
device_event.mods.effective &= ~button_state;
memset (&device_event.group, 0, sizeof (device_event.group));
device_event.group.effective = (device_event.mods.effective >> 13) & 0x3;
for (i = 0; i < N_BUTTONS; i++)
if ((button_state & (CLUTTER_BUTTON1_MASK << i)))
XISetMask (button_mask, i + 1);
device_event.buttons.mask_len = N_BUTTONS + 1;
device_event.buttons.mask = button_mask;
device_event.valuators.mask_len = 0;
device_event.valuators.mask = NULL;
device_event.valuators.values = NULL;
meta_display_handle_event (display, (XEvent *) &generic_event);
}
static void
reset_idletimes (const ClutterEvent *event)
{
ClutterInputDevice *device, *source_device;
MetaIdleMonitor *core_monitor, *device_monitor;
int device_id;
device = clutter_event_get_device (event);
if (device == NULL)
return;
device_id = clutter_input_device_get_device_id (device);
core_monitor = meta_idle_monitor_get_core ();
@@ -560,24 +669,129 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
device_monitor = meta_idle_monitor_get_for_device (device_id);
meta_idle_monitor_reset_idletime (device_monitor);
}
}
static gboolean
event_cb (ClutterActor *stage,
const ClutterEvent *event,
MetaWaylandCompositor *compositor)
{
MetaWaylandSeat *seat = compositor->seat;
MetaWaylandPointer *pointer = &seat->pointer;
MetaWaylandSurface *surface;
MetaDisplay *display;
reset_idletimes (event);
if (meta_wayland_seat_handle_event (compositor->seat, event))
return TRUE;
/* HACK: for now, the surfaces from Wayland clients aren't
integrated into Mutter's event handling and Mutter won't give them
focus on mouse clicks. As a hack to work around this we can just
give them input focus on mouse clicks so we can at least test the
keyboard support */
if (event->type == CLUTTER_BUTTON_PRESS)
{
surface = pointer->current;
if (surface && surface->window &&
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
meta_window_focus (surface->window, clutter_event_get_time (event));
}
if (seat->cursor_tracker)
{
meta_cursor_tracker_update_position (seat->cursor_tracker,
wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y));
if (pointer->current == NULL)
meta_cursor_tracker_revert_root (seat->cursor_tracker);
meta_cursor_tracker_queue_redraw (seat->cursor_tracker, stage);
}
display = meta_get_display ();
if (!display)
return FALSE;
switch (event->type)
{
case CLUTTER_MOTION:
case CLUTTER_BUTTON_PRESS:
if (compositor->implicit_grab_surface == NULL)
{
compositor->implicit_grab_button = event->button.button;
compositor->implicit_grab_surface = pointer->current;
}
return FALSE;
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL:
meta_wayland_seat_update_pointer (compositor->seat, event);
if (event->type == CLUTTER_BUTTON_RELEASE &&
compositor->implicit_grab_surface &&
event->button.button == compositor->implicit_grab_button)
compositor->implicit_grab_surface = NULL;
return FALSE;
case CLUTTER_MOTION:
synthesize_motion_event (compositor, event);
return FALSE;
default:
break;
return FALSE;
}
}
gboolean
meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event)
static gboolean
event_emission_hook_cb (GSignalInvocationHint *ihint,
guint n_param_values,
const GValue *param_values,
gpointer data)
{
return meta_wayland_seat_handle_event (compositor->seat, event);
MetaWaylandCompositor *compositor = data;
ClutterActor *actor;
ClutterEvent *event;
g_return_val_if_fail (n_param_values == 2, FALSE);
actor = g_value_get_object (param_values + 0);
event = g_value_get_boxed (param_values + 1);
if (actor == NULL)
return TRUE /* stay connected */;
/* If this event belongs to the corresponding grab for this event
* type then the captured-event signal won't be emitted so we have
* to manually forward it on */
switch (event->type)
{
/* Pointer events */
case CLUTTER_MOTION:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL:
if (actor == clutter_get_pointer_grab ())
event_cb (clutter_actor_get_stage (actor),
event,
compositor);
break;
/* Keyboard events */
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
if (actor == clutter_get_keyboard_grab ())
event_cb (clutter_actor_get_stage (actor),
event,
compositor);
default:
break;
}
return TRUE /* stay connected */;
}
static void
@@ -620,6 +834,7 @@ void
meta_wayland_init (void)
{
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
guint event_signal;
MetaMonitorManager *monitors;
ClutterBackend *backend;
CoglContext *cogl_context;
@@ -708,6 +923,21 @@ meta_wayland_init (void)
compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
compositor->drm_fd >= 0);
g_signal_connect (compositor->stage,
"captured-event",
G_CALLBACK (event_cb),
compositor);
/* If something sets a grab on an actor then the captured event
* signal won't get emitted but we still want to see these events so
* we can update the cursor position. To make sure we see all events
* we also install an emission hook on the event signal */
event_signal = g_signal_lookup ("event", CLUTTER_TYPE_STAGE);
g_signal_add_emission_hook (event_signal,
0 /* detail */,
event_emission_hook_cb,
compositor, /* hook_data */
NULL /* data_destroy */);
meta_wayland_init_shell (compositor);
clutter_actor_show (compositor->stage);

View File

@@ -48,6 +48,11 @@ xserver_set_window_id (struct wl_client *client,
window = meta_display_lookup_x_window (display, xid);
if (window)
{
MetaWindowActor *window_actor =
META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
meta_window_actor_set_wayland_surface (window_actor, surface);
surface->window = window;
window->surface = surface;