Compare commits

...

58 Commits

Author SHA1 Message Date
27bec68c67 wayland: Add support for show_window_menu 2014-03-14 10:22:13 -04:00
8ce4407a9f x11: Add support for a new _GTK_SHOW_WINDOW_MENU request
To show the window menu from a client-side decoration.
2014-03-14 10:22:13 -04:00
cebb6b2779 window: Remove unused and unnecessary parameters from meta_window_window_menu 2014-03-14 10:22:11 -04:00
d7771a30ee Convert window menus to a compositor implementation 2014-03-13 19:36:33 -04:00
10fb5e527f window: Export a bunch of state flags as accessor methods
This is necessary to reimplement window menus in gnome-shell.
2014-03-13 19:33:28 -04:00
7116786ad3 Add a META_MAXIMIZE_BOTH
Which has the value of META_MAXIMIZE_VERTICAL |
META_MAXIMIZE_HORIZONTAL.

This is an obvious code cleanup.
2014-03-13 18:33:17 -04:00
d294fa45d1 wayland: Add support for set_surface_type 2014-03-13 17:14:28 -04:00
e278d65f05 constraints 2014-03-13 17:14:28 -04:00
42408c1c38 hack to get things working for demo
have to figure out something better to put here
2014-03-13 17:14:28 -04:00
9ac086a613 Replace mutter-launch with logind integration
This uses David Herrmann's new logind sessions interface to retrieve
fds for input devices, rather than using a custom setuid helper to do
the management. This vastly simplifies the interface.

This requires systemd v210, at least.

https://bugzilla.gnome.org/show_bug.cgi?id=724604
2014-03-13 17:14:28 -04:00
de06346766 meta-weston-launch: Pause Clutter during VT switches 2014-03-13 17:14:28 -04:00
c22d6ad69c meta-weston-launch: Remove the "VT-switched lock"
We'll replace it by pausing the Clutter master clock.
2014-03-13 17:14:28 -04:00
64be6cf4f0 weston-launch: Pass the DRM device to Cogl
Open the device from weston-launch, and pass it to Cogl/Clutter.
This is a preliminary cleanup for our login1 integration.
2014-03-13 17:14:28 -04:00
a9d8107c3d window: Replace meta_window_type_changed with meta_window_set_type
Which does the equality checking for us.
2014-03-13 17:14:28 -04:00
a5d2c51392 window: Move recalc_type to window-x11.c
It's only used by the X11 codepath.
2014-03-13 17:14:28 -04:00
d1ea17e6a4 meta-weston-launch: Adapt to Clutter's new evdev open callback 2014-03-13 12:47:11 -04:00
b37ad66e9d xdg-shell: Update for new state change mechanism
We're still not properly going through the request system. This
will require a dense investigation of the code, but it will happen
soon...
2014-03-12 23:42:55 -04:00
c1f15348a5 Revert "weston-launch: Pass the DRM device to Cogl"
This reverts commit 857561baed.

This broke the build, and was pushed prematurely.
2014-03-12 14:48:46 -04:00
857561baed weston-launch: Pass the DRM device to Cogl
Open the device from weston-launch, and pass it to Cogl/Clutter.
This is a preliminary cleanup for our login1 integration.
2014-03-11 18:01:21 -04:00
a44cc9ef47 wayland: Fix build 2014-03-11 18:01:17 -04:00
d47b7ba038 Add meta_activate_session
This will be used on startup to switch to the newly activated session.
2014-03-11 17:25:40 -04:00
f21312e2fd meta-weston-launch: Redraw and update the cursor when switching back 2014-03-11 17:25:40 -04:00
394af33607 weston-launch: Allow activating our own VT by passing a negative value
This will be used to implement activate_session.
2014-03-11 17:25:40 -04:00
7314cdac94 weston-launch: Always use sd_session_get_vt 2014-03-11 17:25:40 -04:00
81025e37ea weston-launch: Stat the path before opening it 2014-03-11 17:25:39 -04:00
1bb9f1e333 weston-launch: Remove unused prototypes 2014-03-11 17:25:39 -04:00
b11c75c1c9 weston-launch: Rearrange code slightly
We need to initialize the main loops before our callback is called, so
this makes it make a slight bit of more sense.
2014-03-11 17:25:39 -04:00
757b626aee wayland: Add a few comments, rename some strings 2014-03-11 17:25:02 -04:00
fb3df5243f main: Add a --display-server option
This is an explicit option to launch mutter as a display server,
rather than relying on weston-launch.
2014-03-11 16:33:42 -04:00
e34792d9f0 wayland: Remove needless indirection 2014-03-11 16:00:43 -04:00
f397c32192 wayland: Make set_selection private
It's unused outside of us.
2014-03-11 15:42:37 -04:00
f79314d7b5 wayland: Fix destroying data sources
The resource is not embedded in the source, it's separate. We need
to get the user data here to not crash.
2014-03-11 15:30:17 -04:00
55c61259d8 wayland: Use g_slice_new0
And fix a leak.
2014-03-11 15:30:17 -04:00
5298cf0a3a wayland: Pull in a fix for a FIXME from Weston 2014-03-11 15:30:17 -04:00
f1dc1a0cbc wayland: Fix drag grabs
We need to have the seat here. This makes weston-dnd not crash when
clicking on an item.
2014-03-11 15:30:16 -04:00
2cf80bc647 Fix identification of CSD windows when checking whether to force fullscreen
We try to exempt CSD windows from being forced fullscreen if they are
undecorated and the size of the screen; however, we also catch almost
all windows that *do* need to be forced fullscreen in this check, since
they also have decorations turned off.

Identify actual CSD windows by checking whether _GTK_FRAME_EXTENTS is set -
GTK+ will always set this on CSD windows even if they have no invisible
borders or shadows at the current time.

We explicitly turn off the legacy-fullscreen check for native wayland windows
so we don't start legacy-fullscreening them if the new
meta_window_is_client_decorated() is later made more accurate.

https://bugzilla.gnome.org/show_bug.cgi?id=723029
2014-03-11 13:02:19 -04:00
40c15f6e2a Fix meta_window_titlebar_is_onscreen() for titlebar-less windows
Make the code correspond to the comment - the titlebar can't be
offscreen if there's no titlebar.

https://bugzilla.gnome.org/show_bug.cgi?id=723580
2014-03-11 13:02:19 -04:00
a8849621c9 window: Always save the user_rect when resizing Wayland windows
The user_rect represents the unconstrainted window size, and lots
of code in mutter assumes it can resize to the user_rect at any
time. If we wait for an attach to ACK and save the user rect, we'll
see lots of flickering as code is resizing to the old user_rect
at any time.
2014-03-11 12:29:11 -04:00
49c0be11d6 display: Rework event spewing
Make it a compile-time flag rather than a run-time flag, because
practically any time you're going to be debugging event spewing,
you're going to have to recompile anyway. Remove the WITH_VERBOSE_MODE
checks, too.
2014-03-11 10:24:13 -04:00
9df8e831be xwayland: Make sure to clear an existing surface if we have one
This fixes an assert fail when redecorating an X11 client.
2014-03-11 10:24:13 -04:00
84c6b2a3fa wayland: Remove an extra reset
We already reset the double-buffered state when we commit it, so this
is just superfluous.
2014-03-11 10:24:13 -04:00
06cd669ccb wayland: Fix bad copy-paste error in unset_fullscreen
This was causing memory corruption and a bad crasher with simple-egl.
2014-03-10 16:45:05 -04:00
81eb7d9537 Add META_GRAB_OP_WAYLAND_CLIENT
Which is used for Wayland popup grabs.

The issue here is that we don't want the code that raises or focuses
windows based on mouse ops to run while a client has a grab.

We still keep the "old" grab infrastructure in place for now, but
ideally we'd replace it eventually with a better grab-op infrastructure.
2014-03-10 15:11:03 -04:00
dd8d8e436d wayland: Remove special code for modal grabs
Since we never pass any Clutter events to Wayland, it's not needed.
2014-03-10 15:10:44 -04:00
d6b6b363ad seat: Add support for smooth scrolling 2014-03-10 11:36:36 -04:00
254e2e993c seat: Redo scroll handling
To make way for smooth scrolling
2014-03-10 11:36:36 -04:00
c595a9c29f seat: Reduce indentation 2014-03-10 11:36:36 -04:00
dfc7f7222b wayland-keyboard: Remove unused modifier indexes
This was copied from weston where they're used for compositor
keybindings. Mutter has its own keybindings code which doesn't need
this.

https://bugzilla.gnome.org/show_bug.cgi?id=722847
2014-03-07 15:00:04 +01:00
ef278eb547 meta-cursor-tracker: Initialize our position from MetaWaylandPointer's
Clutter's input device initial position defaults to (-1, -1) on most
backends but for the evdev backend we changed it to be inside the
stage to prevent the pointer from wandering outside the stage until it
first enters, after which our constraining callback won't let it go
out.

This makes us be in sync with the real position from the start.
2014-03-07 14:54:51 +01:00
38e26e5cc3 keybindings: Plug a GSettings instance leak 2014-03-06 19:22:39 +01:00
9773a879c3 cursor-tracker: Include gdk/gdkx.h
Needed for the call to gdk_x11_device_manager_lookup() introduced in
abd2abcde6 .
2014-03-06 19:22:39 +01:00
abd2abcde6 cursor-tracker: Avoid unnecessary round trip 2014-03-06 17:31:08 +01:00
a8f4651c72 MetaCursorTracker: fix uninitialized screen variable
We must call gdk_device_get_pointer() unconditionally, because
that sets the GdkScreen argument we use to obtain the root window.
2014-03-06 17:27:11 +01:00
54df7934ea Bump version to 3.11.91
Update NEWS.
2014-03-05 23:48:33 +01:00
9052efb0d9 build: Use non-deprecated feature test macros
_SVID_SOURCE has been deprecated in newer versions of glibc breaking
-WError; the recommended replacement of _DEFAULT_SOURCE is fairly
new, so switch to _XOPEN_SOURCE instead.
2014-03-05 23:48:33 +01:00
b346f98eb0 Fix positioning error for manually positioned windows
The "original coordinates" passed into meta_window_place() were the
coordinates of the client rectangle not the frame rectangle. When
meta_window_place() didn't place because the window was manually
positioned (e.g., 'xterm -geometry +x+y') that resulted in a window
being offset by the frame dimensions.

https://bugzilla.gnome.org/show_bug.cgi?id=724049
2014-03-05 17:22:56 -05:00
365af53797 Fix handling of dynamic updates to colors/font/etc.
Since the introduction of frame sync in GTK+, updates to titlebar font and
colors haven't been working because GTK+ counts on the frame clock to
do style updates, and the frame clock doesn't run for an unmapped
GdkWindow. (It's possible that GtkStyleContext changes subsequent to
the introduction of the frame clock were also needed to fully break
things.)

We actually need to map the MetaFrames GdkWindow and let the
compositor code send out the frame sync messages in order to pick up
style changes.

Hopefully no bad side effects will occur from this - we make the window
override-redirect, 1x1, and outside the bounds of the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=725751
2014-03-05 17:22:48 -05:00
bee59ec0e1 Use MetaCursorTracker to query the pointer position
Functionally equivalent in the X11 case, but also correct for
Wayland (where the X server doesn't have the updated pointer
position).

https://bugzilla.gnome.org/show_bug.cgi?id=725525
2014-03-05 23:09:48 +01:00
61 changed files with 1375 additions and 3939 deletions

2
.gitignore vendored
View File

@ -48,7 +48,6 @@ po/*.pot
50-metacity-key.xml
libmutter-wayland.pc
mutter-wayland
mutter-launch
org.gnome.mutter.gschema.valid
org.gnome.mutter.gschema.xml
org.gnome.mutter.wayland.gschema.valid
@ -77,6 +76,7 @@ src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/meta-dbus-xrandr.[ch]
src/meta-dbus-idle-monitor.[ch]
src/meta-dbus-login1.[ch]
src/mutter-plugins.pc
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-server-protocol.h

14
NEWS
View File

@ -1,3 +1,17 @@
3.11.91
=======
* Don't use keysym to match keybindings [Rui; #678001]
* Fix message tray icons showing up blank (again) [Adel; #725180]
* Improve keybinding lookups [Rui; #725588]
* Fix dynamic updates of titlebar style properties [Owen; #725751]
* Fix positioning of manually positioned windows [Owen; #724049]
* Misc bug fixes and cleanups [Jasper, Carlos, Adel, Giovanni, Florian; #720631,
#724969, #725216, #724402, #722266, #725338, #725525]
Contributors:
Giovanni Campagna, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre, Owen W. Taylor
3.11.90
=======
* Fix double-scaling on high DPI resolutions [Adel; #723931]

View File

@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [11])
m4_define([mutter_micro_version], [90])
m4_define([mutter_micro_version], [91])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -140,12 +140,6 @@ AM_GLIB_GNU_GETTEXT
## here we get the flags we'll actually use
# GRegex requires Glib-2.14.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
saved_LIBS="$LIBS"
LIBS="$LIBS $MUTTER_LAUNCH"
AC_CHECK_FUNCS([sd_session_get_vt])
LIBS="$saved_LIBS"
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
@ -218,7 +212,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_SUBST([WAYLAND_SCANNER])
AC_SUBST(XWAYLAND_PATH)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm libsystemd"
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_EXISTS([xi >= 1.6.99.1],

View File

@ -40,19 +40,22 @@
<enum name="version">
<description summary="latest protocol version">
Use this enum to check the protocol version, and it will be updated
automatically.
The 'current' member of this enum gives the version of the
protocol. Implementations can compare this to the version
they implement using static_assert to ensure the protocol and
implementation versions match.
</description>
<entry name="current" value="2" summary="Always the latest version"/>
<entry name="current" value="3" 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.
Negotiate the unstable version of the interface. This
mechanism is in place to ensure client and server agree on the
unstable versions of the protocol that they speak or exit
cleanly if they don't agree. This request will go away once
the xdg-shell protocol is stable.
</description>
<arg name="version" type="int"/>
</request>
@ -198,6 +201,37 @@
<arg name="app_id" type="string"/>
</request>
<enum name="surface_type">
<description summary="surface types">
Surface
</description>
<entry name="normal" value="0" summary="A normal window. This is the default type."/>
<entry name="modal_dialog" value="1" summary="A modal dialog."/>
</enum>
<request name="set_surface_type">
<description summary="set the surface type">
Sets the type of the surface. These are high-level "roles" of
surfaces designed to give the compositor more heuristics about
how to place and manage the window.
</description>
<arg name="surface_type" type="uint" summary="a surface type from surface_type"/>
</request>
<request name="show_window_menu">
<description summary="show the window menu">
Clients implementing client-side decorations might want to show
a context menu when right-clicking on the decorations, giving the
user a menu that they can use to maximize or minimize the window.
The seat passed must have either pointer or keyboard focus to pop
up the window menu for a surface.
</description>
<arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/>
<arg name="serial" type="uint" summary="serial of the event to pop up the window for"/>
</request>
<request name="move">
<description summary="start an interactive move">
Start a pointer-driven move of the surface.
@ -275,113 +309,87 @@
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<event name="request_set_fullscreen">
<description summary="server requests that the client set fullscreen">
Event sent from the compositor to the client requesting that the client
goes to a fullscreen state. It's the client job to call set_fullscreen
and really trigger the fullscreen state.
<enum name="state">
<description summary="types of state on the surface">
The different state values used on the surface. This is designed for
state values like maximized, fullscreen. It is paired with the
request_change_state event to ensure that both the client and the
compositor setting the state can be synchronized.
States set in this way are double-buffered. They will get applied on
the next commit.
Desktop environments may extend this enum by taking up a range of
values and documenting the range they chose in this description.
They are not required to document the values for the range that they
chose. Ideally, any good extensions from a desktop environment should
make its way into standardization into this enum.
The current reserved ranges are:
0x0000 - 0x0FFF: xdg-shell core values, documented below.
0x1000 - 0x1FFF: GNOME
</description>
</event>
<entry name="maximized" value="1" summary="the surface is maximized">
A non-zero value indicates the surface is maximized. Otherwise,
the surface is unmaximized.
</entry>
<entry name="fullscreen" value="2" summary="the surface is fullscreen">
A non-zero value indicates the surface is fullscreen. Otherwise,
the surface is not fullscreen.
</entry>
</enum>
<event name="request_unset_fullscreen">
<description summary="server requests that the client unset fullscreen">
Event sent from the compositor to the client requesting that the client
leaves the fullscreen state. It's the client job to call
unset_fullscreen and really leave the fullscreen state.
</description>
</event>
<request name="set_fullscreen">
<description summary="set the surface state as fullscreen">
Set the surface as fullscreen.
After this request, the compositor should send a configure event
informing the output size.
This request informs the compositor that the next attached buffer
committed will be in a fullscreen state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_fullscreen
request. When the sync callback returns, the last configure event
received just before it will be the correct one, and should contain the
right size for the surface to maximize.
Setting one state won't unset another state. Use
xdg_surface.unset_fullscreen for unsetting it.
<request name="request_change_state">
<description summary="client requests to change a surface's state">
This asks the compositor to change the state. If the compositor wants
to change the state, it will send a change_state event with the same
state_type, value, and serial, and the event flow continues as if it
it was initiated by the compositor.
If the compositor does not want to change the state, it will send a
change_state to the client with the old value of the state.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="an event serial">
This serial is so the client can know which change_state event corresponds
to which request_change_state request it sent out.
</arg>
</request>
<request name="unset_fullscreen">
<description summary="unset the surface state as fullscreen">
Unset the surface fullscreen state.
Same negotiation as set_fullscreen must be used.
<event name="change_state">
<description summary="compositor wants to change a surface's state">
This event tells the client to change a surface's state. The client
should respond with an ack_change_state request to the compositor to
guarantee that the compositor knows that the client has seen it.
</description>
</request>
<event name="request_set_maximized">
<description summary="server requests that the client set maximized">
Event sent from the compositor to the client requesting that the client
goes to a maximized state. It's the client job to call set_maximized
and really trigger the maximized state.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/>
</event>
<event name="request_unset_maximized">
<description summary="server requests that the client unset maximized">
Event sent from the compositor to the client requesting that the client
leaves the maximized state. It's the client job to call unset_maximized
and really leave the maximized state.
</description>
</event>
<request name="set_maximized">
<description summary="set the surface state as maximized">
Set the surface as maximized.
After this request, the compositor will send a configure event
informing the output size minus panel and other MW decorations.
This request informs the compositor that the next attached buffer
committed will be in a maximized state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_maximized request.
When the sync callback returns, the last configure event received just
before it will be the correct one, and should contain the right size
for the surface to maximize.
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.
Same negotiation as set_maximized must be used.
<request name="ack_change_state">
<description summary="ack a change_state event">
When a change_state event is received, a client should then ack it
using the ack_change_state request to ensure that the compositor
knows the client has seen the event.
By this point, the state is confirmed, and the next attach should
contain the buffer drawn for the new state value.
The values here need to be the same as the values in the cooresponding
change_state event.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial to pass to change_state"/>
</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 summary="minimize the surface">
Minimize the surface.
</description>
</request>

View File

@ -39,6 +39,7 @@ INCLUDES += \
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_xrandr_built_sources) \
$(dbus_login1_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
wayland/gtk-shell-protocol.c \
@ -177,10 +178,6 @@ libmutter_wayland_la_SOURCES = \
ui/ui.h \
ui/frames.c \
ui/frames.h \
ui/menu.c \
ui/menu.h \
ui/metaaccellabel.c \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
ui/theme-parser.c \
@ -207,8 +204,8 @@ libmutter_wayland_la_SOURCES = \
wayland/meta-wayland-surface.h \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
wayland/meta-login1.c \
wayland/meta-login1.h
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
@ -263,17 +260,6 @@ bin_PROGRAMS=mutter-wayland
mutter_wayland_SOURCES = core/mutter.c
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
bin_PROGRAMS+=mutter-launch
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
install-exec-hook:
-chown root $(DESTDIR)$(bindir)/mutter-launch
-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
@ -409,6 +395,15 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
--c-generate-object-manager \
$(srcdir)/idle-monitor.xml
dbus_login1_built_sources = meta-dbus-login1.c meta-dbus-login1.h
$(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
$(AM_V_GEN)gdbus-codegen \
--interface-prefix org.freedesktop.login1 \
--c-namespace Login1 \
--generate-c-code meta-dbus-login1 \
$(srcdir)/org.freedesktop.login1.xml
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@

View File

@ -436,45 +436,6 @@ begin_modal_x11 (MetaScreen *screen,
return FALSE;
}
static gboolean
begin_modal_wayland (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaWaylandCompositor *compositor;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
compositor = meta_wayland_compositor_get_default ();
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
goto fail;
pointer_grabbed = TRUE;
}
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
timestamp))
goto fail;
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
if (keyboard_grabbed)
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
return FALSE;
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
@ -493,7 +454,7 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
return FALSE;
if (meta_is_wayland_compositor ())
ok = begin_modal_wayland (screen, plugin, options, timestamp);
ok = TRUE;
else
ok = begin_modal_x11 (screen, plugin, options, timestamp);
if (!ok)
@ -521,15 +482,7 @@ meta_end_modal_for_plugin (MetaScreen *screen,
g_return_if_fail (compositor->modal_plugin == plugin);
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
timestamp);
}
else
if (!meta_is_wayland_compositor ())
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
@ -1770,3 +1723,15 @@ meta_compositor_hide_tile_preview (MetaCompositor *compositor,
meta_plugin_manager_hide_tile_preview (info->plugin_mgr);
}
void
meta_compositor_show_window_menu (MetaCompositor *compositor,
MetaWindow *window)
{
MetaCompScreen *info = meta_screen_get_compositor_data (window->screen);
if (!info->plugin_mgr)
return;
meta_plugin_manager_show_window_menu (info->plugin_mgr, window);
}

View File

@ -365,3 +365,18 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
return FALSE;
}
void
meta_plugin_manager_show_window_menu (MetaPluginManager *plugin_mgr,
MetaWindow *window)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return;
if (klass->show_window_menu)
klass->show_window_menu (plugin, window);
}

View File

@ -80,4 +80,8 @@ gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
MetaRectangle *tile_rect,
int tile_monitor_number);
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
void meta_plugin_manager_show_window_menu (MetaPluginManager *mgr,
MetaWindow *window);
#endif

View File

@ -714,7 +714,7 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
/* Leaving out shadows for maximized and fullscreen windows is an effeciency
* win and also prevents the unsightly effect of the shadow of maximized
* window appearing on an adjacent window */
if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
if ((meta_window_get_maximized (priv->window) == META_MAXIMIZE_BOTH) ||
meta_window_is_fullscreen (priv->window))
return FALSE;

View File

@ -425,8 +425,9 @@ setup_constraint_info (ConstraintInfo *info,
* the monitor.
*/
if (meta_prefs_get_force_fullscreen() &&
window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
!window->hide_titlebar_when_maximized &&
window->decorated &&
(window->decorated || !meta_window_is_client_decorated (window)) &&
meta_rectangle_equal (new, &monitor_info->rect) &&
window->has_fullscreen_func &&
!window->fullscreen)
@ -491,12 +492,17 @@ place_window_if_needed(MetaWindow *window,
!window->minimized &&
!window->fullscreen)
{
MetaRectangle orig_rect;
MetaRectangle placed_rect;
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,
orig_rect = info->orig;
extend_by_frame (window, &orig_rect);
meta_window_place (window, orig_rect.x, orig_rect.y,
&placed_rect.x, &placed_rect.y);
did_placement = TRUE;
@ -811,7 +817,7 @@ constrain_maximization (MetaWindow *window,
active_workspace_struts);
}
/* Now make target_size = maximized size of client window */
unextend_by_frame (window, &target_size);
/* unextend_by_frame (window, &target_size); */
/* Check min size constraints; max size constraints are ignored for maximized
* windows, as per bug 327543.

View File

@ -328,8 +328,7 @@ meta_core_maximize (Display *xdisplay,
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
}
void
@ -342,11 +341,9 @@ meta_core_toggle_maximize_vertically (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED_VERTICALLY (window))
meta_window_unmaximize (window,
META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
else
meta_window_maximize (window,
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
}
void
@ -359,11 +356,9 @@ meta_core_toggle_maximize_horizontally (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED_HORIZONTALLY (window))
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL);
meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
else
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL);
meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
}
void
@ -376,11 +371,9 @@ meta_core_toggle_maximize (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
else
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
}
void
@ -392,8 +385,7 @@ meta_core_unmaximize (Display *xdisplay,
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
}
void
@ -477,9 +469,6 @@ meta_core_change_workspace (Display *xdisplay,
void
meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
@ -488,121 +477,7 @@ meta_core_show_window_menu (Display *xdisplay,
meta_window_raise (window);
meta_window_focus (window, timestamp);
meta_window_show_menu (window, root_x, root_y, button, timestamp);
}
void
meta_core_get_menu_accelerator (MetaMenuOp menu_op,
int workspace,
unsigned int *keysym,
MetaVirtualModifier *modifiers)
{
const char *name;
name = NULL;
switch (menu_op)
{
case META_MENU_OP_NONE:
/* No keybinding for this one */
break;
case META_MENU_OP_DELETE:
name = "close";
break;
case META_MENU_OP_MINIMIZE:
name = "minimize";
break;
case META_MENU_OP_UNMAXIMIZE:
name = "unmaximize";
break;
case META_MENU_OP_MAXIMIZE:
name = "maximize";
break;
case META_MENU_OP_UNSHADE:
case META_MENU_OP_SHADE:
name = "toggle_shaded";
break;
case META_MENU_OP_UNSTICK:
case META_MENU_OP_STICK:
name = "toggle-on-all-workspaces";
break;
case META_MENU_OP_ABOVE:
case META_MENU_OP_UNABOVE:
name = "toggle-above";
break;
case META_MENU_OP_WORKSPACES:
switch (workspace)
{
case 1:
name = "move-to-workspace-1";
break;
case 2:
name = "move-to-workspace-2";
break;
case 3:
name = "move-to-workspace-3";
break;
case 4:
name = "move-to-workspace-4";
break;
case 5:
name = "move-to-workspace-5";
break;
case 6:
name = "move-to-workspace-6";
break;
case 7:
name = "move-to-workspace-7";
break;
case 8:
name = "move-to-workspace-8";
break;
case 9:
name = "move-to-workspace-9";
break;
case 10:
name = "move-to-workspace-10";
break;
case 11:
name = "move-to-workspace-11";
break;
case 12:
name = "move-to-workspace-12";
break;
}
break;
case META_MENU_OP_MOVE:
name = "begin-move";
break;
case META_MENU_OP_RESIZE:
name = "begin-resize";
break;
case META_MENU_OP_MOVE_LEFT:
name = "move-to-workspace-left";
break;
case META_MENU_OP_MOVE_RIGHT:
name = "move-to-workspace-right";
break;
case META_MENU_OP_MOVE_UP:
name = "move-to-workspace-up";
break;
case META_MENU_OP_MOVE_DOWN:
name = "move-to-workspace-down";
break;
case META_MENU_OP_RECOVER:
/* No keybinding for this one */
break;
}
if (name)
{
meta_prefs_get_window_binding (name, keysym, modifiers);
}
else
{
*keysym = 0;
*modifiers = 0;
}
meta_window_show_menu (window);
}
const char*

View File

@ -159,15 +159,8 @@ const char* meta_core_get_workspace_name_with_index (Display *xdisplay,
void meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_core_get_menu_accelerator (MetaMenuOp menu_op,
int workspace,
unsigned int *keysym,
MetaVirtualModifier *modifiers);
gboolean meta_core_begin_grab_op (Display *xdisplay,
Window frame_xwindow,

View File

@ -263,10 +263,6 @@ struct _MetaDisplay
/* Managed by group.c */
GHashTable *groups_by_leader;
/* currently-active window menu if any */
MetaWindowMenu *window_menu;
MetaWindow *window_with_menu;
/* Managed by window-props.c */
MetaWindowPropHooks *prop_hooks_table;
GHashTable *prop_hooks;

View File

@ -564,9 +564,6 @@ meta_display_open (void)
the_display->monitor_cache_invalidated = TRUE;
the_display->groups_by_leader = NULL;
the_display->window_with_menu = NULL;
the_display->window_menu = NULL;
the_display->screens = NULL;
the_display->active_screen = NULL;
@ -1295,10 +1292,6 @@ meta_get_display (void)
return the_display;
}
#ifdef WITH_VERBOSE_MODE
static gboolean dump_events = TRUE;
#endif
static gboolean
grab_op_is_mouse_only (MetaGrabOp op)
{
@ -1418,6 +1411,20 @@ meta_grab_op_is_moving (MetaGrabOp op)
}
}
static gboolean
grab_op_should_block_mouse_events (MetaGrabOp op)
{
switch (op)
{
case META_GRAB_OP_WAYLAND_CLIENT:
case META_GRAB_OP_COMPOSITOR:
return TRUE;
default:
return FALSE;
}
}
/**
* meta_display_xserver_time_is_before:
* @display: a #MetaDisplay
@ -2054,7 +2061,7 @@ meta_display_handle_event (MetaDisplay *display,
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
if (grab_op_should_block_mouse_events (display->grab_op))
break;
display->overlay_key_only_pressed = FALSE;
@ -2196,11 +2203,7 @@ meta_display_handle_event (MetaDisplay *display,
{
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_show_menu (window,
event->button.x,
event->button.y,
event->button.button,
event->any.time);
meta_window_show_menu (window);
bypass_clutter = TRUE;
bypass_wayland = TRUE;
}
@ -2226,7 +2229,7 @@ meta_display_handle_event (MetaDisplay *display,
}
break;
case CLUTTER_BUTTON_RELEASE:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
if (grab_op_should_block_mouse_events (display->grab_op))
break;
display->overlay_key_only_pressed = FALSE;
@ -2240,7 +2243,7 @@ meta_display_handle_event (MetaDisplay *display,
}
break;
case CLUTTER_MOTION:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
if (grab_op_should_block_mouse_events (display->grab_op))
break;
if (display->grab_window == window &&
@ -2274,6 +2277,10 @@ meta_display_handle_event (MetaDisplay *display,
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
bypass_wayland = TRUE;
/* If a Wayland client has a grab, don't pass that through to Clutter */
if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT)
bypass_clutter = TRUE;
if (compositor && !bypass_wayland)
{
if (meta_wayland_compositor_handle_event (compositor, event))
@ -2974,9 +2981,8 @@ meta_display_handle_xevent (MetaDisplay *display,
MetaMonitorManager *monitor;
MetaScreen *screen;
#ifdef WITH_VERBOSE_MODE
if (dump_events)
meta_spew_event (display, event);
#if 0
meta_spew_event (display, event);
#endif
#ifdef HAVE_STARTUP_NOTIFICATION
@ -3252,8 +3258,7 @@ event_get_time (MetaDisplay *display,
}
}
#ifdef WITH_VERBOSE_MODE
const char*
G_GNUC_UNUSED const char*
meta_event_detail_to_string (int d)
{
const char *detail = "???";
@ -3289,10 +3294,8 @@ meta_event_detail_to_string (int d)
return detail;
}
#endif /* WITH_VERBOSE_MODE */
#ifdef WITH_VERBOSE_MODE
const char*
G_GNUC_UNUSED const char*
meta_event_mode_to_string (int m)
{
const char *mode = "???";
@ -3314,10 +3317,8 @@ meta_event_mode_to_string (int m)
return mode;
}
#endif /* WITH_VERBOSE_MODE */
#ifdef WITH_VERBOSE_MODE
static const char*
G_GNUC_UNUSED static const char*
stack_mode_to_string (int mode)
{
switch (mode)
@ -3336,11 +3337,9 @@ stack_mode_to_string (int mode)
return "Unknown";
}
#endif /* WITH_VERBOSE_MODE */
#ifdef HAVE_XSYNC
#ifdef WITH_VERBOSE_MODE
static gint64
G_GNUC_UNUSED static gint64
sync_value_to_64 (const XSyncValue *value)
{
gint64 v;
@ -3350,10 +3349,8 @@ sync_value_to_64 (const XSyncValue *value)
return v;
}
#endif /* WITH_VERBOSE_MODE */
#ifdef WITH_VERBOSE_MODE
static const char*
G_GNUC_UNUSED static const char*
alarm_state_to_string (XSyncAlarmState state)
{
switch (state)
@ -3368,12 +3365,9 @@ alarm_state_to_string (XSyncAlarmState state)
return "(unknown)";
}
}
#endif /* WITH_VERBOSE_MODE */
#endif /* HAVE_XSYNC */
#ifdef WITH_VERBOSE_MODE
static void
G_GNUC_UNUSED static void
meta_spew_xi2_event (MetaDisplay *display,
XIEvent *input_event,
const char **name_p,
@ -3433,7 +3427,7 @@ meta_spew_xi2_event (MetaDisplay *display,
*extra_p = extra;
}
static void
G_GNUC_UNUSED static void
meta_spew_core_event (MetaDisplay *display,
XEvent *event,
const char **name_p,
@ -3657,7 +3651,7 @@ meta_spew_core_event (MetaDisplay *display,
*extra_p = extra;
}
static void
G_GNUC_UNUSED static void
meta_spew_event (MetaDisplay *display,
XEvent *event)
{
@ -3666,9 +3660,6 @@ meta_spew_event (MetaDisplay *display,
char *winname;
MetaScreen *screen;
XIEvent *input_event;
if (!meta_is_verbose())
return;
/* filter overnumerous events */
if (event->type == Expose || event->type == MotionNotify ||
@ -3698,18 +3689,16 @@ meta_spew_event (MetaDisplay *display,
else
winname = g_strdup_printf ("0x%lx", event->xany.window);
meta_topic (META_DEBUG_EVENTS,
"%s on %s%s %s %sserial %lu\n", name, winname,
extra ? ":" : "", extra ? extra : "",
event->xany.send_event ? "SEND " : "",
event->xany.serial);
g_print ("%s on %s%s %s %sserial %lu\n", name, winname,
extra ? ":" : "", extra ? extra : "",
event->xany.send_event ? "SEND " : "",
event->xany.serial);
g_free (winname);
if (extra)
g_free (extra);
}
#endif /* WITH_VERBOSE_MODE */
MetaWindow*
meta_display_lookup_x_window (MetaDisplay *display,

View File

@ -1975,9 +1975,7 @@ process_mouse_move_resize_grab (MetaDisplay *display,
* moveresize now to get the position back to the original.
*/
if (window->shaken_loose || window->tile_mode == META_TILE_MAXIMIZED)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
else if (window->tile_mode != META_TILE_NONE)
meta_window_tile (window);
else
@ -2038,9 +2036,7 @@ process_keyboard_move_grab (MetaDisplay *display,
* now to get the position back to the original.
*/
if (window->shaken_loose)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
else
meta_window_move_resize (display->grab_window,
TRUE,
@ -2786,20 +2782,7 @@ handle_activate_window_menu (MetaDisplay *display,
gpointer dummy)
{
if (display->focus_window)
{
int x, y;
meta_window_get_position (display->focus_window,
&x, &y);
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
x += display->focus_window->rect.width;
meta_window_show_menu (display->focus_window,
x, y,
0,
event->time);
}
meta_window_show_menu (display->focus_window);
}
static void
@ -2901,11 +2884,9 @@ handle_toggle_tiled (MetaDisplay *display,
: META_TILE_NONE;
if (window->saved_maximize)
meta_window_maximize (window, META_MAXIMIZE_VERTICAL |
META_MAXIMIZE_HORIZONTAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
else
meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL |
META_MAXIMIZE_HORIZONTAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
}
else if (meta_window_can_tile_side_by_side (window))
{
@ -2931,13 +2912,9 @@ handle_toggle_maximized (MetaDisplay *display,
gpointer dummy)
{
if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
else if (window->has_maximize_func)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
}
static void
@ -2949,9 +2926,7 @@ handle_maximize (MetaDisplay *display,
gpointer dummy)
{
if (window->has_maximize_func)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
}
static void
@ -2963,9 +2938,7 @@ handle_unmaximize (MetaDisplay *display,
gpointer dummy)
{
if (window->maximized_vertically || window->maximized_horizontally)
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
}
static void
@ -3916,6 +3889,7 @@ init_builtin_key_bindings (MetaDisplay *display)
g_object_unref (common_keybindings);
g_object_unref (mutter_keybindings);
g_object_unref (mutter_wayland_keybindings);
}
void

View File

@ -42,7 +42,7 @@
*/
#define _GNU_SOURCE
#define _SVID_SOURCE /* for putenv() and some signal-related functions */
#define _XOPEN_SOURCE /* for putenv() and some signal-related functions */
#include <config.h>
#include <meta/main.h>
@ -190,6 +190,7 @@ static gboolean opt_replace_wm;
static gboolean opt_disable_sm;
static gboolean opt_sync;
static gboolean opt_wayland;
static gboolean opt_display_server;
static GOptionEntry meta_options[] = {
{
@ -233,6 +234,11 @@ static GOptionEntry meta_options[] = {
N_("Run as a wayland compositor"),
NULL
},
{
"display-server", 0, 0, G_OPTION_ARG_NONE,
&opt_display_server,
N_("Run as a full display server, rather than nested")
},
{NULL}
};
@ -401,8 +407,7 @@ meta_init (void)
if (g_getenv ("MUTTER_DEBUG"))
meta_set_debugging (TRUE);
/* We consider running from mutter-launch equivalent to running from bare metal. */
if (getenv ("WESTON_LAUNCHER_SOCK"))
if (opt_display_server)
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
meta_set_is_wayland_compositor (opt_wayland);
@ -497,6 +502,32 @@ meta_register_with_session (void)
g_free (opt_client_id);
}
/**
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* Wayland compositor, this tells logind to switch over to
* the new session.
*/
gboolean
meta_activate_session (void)
{
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
GError *error = NULL;
if (!meta_wayland_compositor_activate_session (compositor, &error))
{
g_warning ("Could not activate session: %s\n", error->message);
g_error_free (error);
return FALSE;
}
}
return TRUE;
}
/**
* meta_run: (skip)
*

View File

@ -43,4 +43,7 @@ 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_force_update (MetaCursorTracker *tracker);
#endif

View File

@ -39,6 +39,7 @@
#include <gbm.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
@ -569,6 +570,9 @@ make_wayland_cursor_tracker (MetaScreen *screen)
compositor = meta_wayland_compositor_get_default ();
compositor->seat->cursor_tracker = self;
meta_cursor_tracker_update_position (self,
wl_fixed_to_int (compositor->seat->pointer.x),
wl_fixed_to_int (compositor->seat->pointer.y));
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
@ -1074,12 +1078,13 @@ get_pointer_position_gdk (int *x,
GdkScreen *gscreen;
gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
gdevice = gdk_device_manager_get_client_pointer (gmanager);
gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
gdk_device_get_position (gdevice, &gscreen, x, y);
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
if (mods)
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
@ -1095,9 +1100,12 @@ get_pointer_position_clutter (int *x,
cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE);
clutter_input_device_get_coords (cdevice, NULL, &point);
*x = point.x;
*y = point.y;
*mods = clutter_input_device_get_modifier_state (cdevice);
if (x)
*x = point.x;
if (y)
*y = point.y;
if (mods)
*mods = clutter_input_device_get_modifier_state (cdevice);
}
void
@ -1139,3 +1147,12 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
tracker->screen->xroot);
}
}
void
meta_cursor_tracker_force_update (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
update_hw_cursor (tracker);
sync_cursor (tracker);
}

View File

@ -2241,43 +2241,6 @@ meta_prefs_get_keybinding_action (const char *name)
: META_KEYBINDING_ACTION_NONE;
}
/* This is used by the menu system to decide what key binding
* to display next to an option. We return the first non-disabled
* binding, if any.
*/
void
meta_prefs_get_window_binding (const char *name,
unsigned int *keysym,
MetaVirtualModifier *modifiers)
{
MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
if (pref->per_window)
{
GSList *s = pref->combos;
while (s)
{
MetaKeyCombo *c = s->data;
if (c->keysym != 0 || c->modifiers != 0)
{
*keysym = c->keysym;
*modifiers = c->modifiers;
return;
}
s = s->next;
}
/* Not found; return the disabled value */
*keysym = *modifiers = 0;
return;
}
g_assert_not_reached ();
}
gint
meta_prefs_get_mouse_button_resize (void)
{

View File

@ -310,6 +310,7 @@ set_supported_hint (MetaScreen *screen)
#undef EWMH_ATOMS_ONLY
screen->display->atom__GTK_FRAME_EXTENTS,
screen->display->atom__GTK_SHOW_WINDOW_MENU,
};
XChangeProperty (screen->display->xdisplay, screen->xroot,
@ -1514,38 +1515,19 @@ meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one)
{
MetaWindow *window;
Window root_return, child_return;
double root_x_return, root_y_return;
double win_x_return, win_y_return;
XIButtonState buttons;
XIModifierState mods;
XIGroupState group;
int x, y;
if (not_this_one)
meta_topic (META_DEBUG_FOCUS,
"Focusing mouse window excluding %s\n", not_this_one->desc);
meta_error_trap_push (screen->display);
XIQueryPointer (screen->display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
screen->xroot,
&root_return,
&child_return,
&root_x_return,
&root_y_return,
&win_x_return,
&win_y_return,
&buttons,
&mods,
&group);
meta_error_trap_pop (screen->display);
free (buttons.mask);
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
&x, &y, NULL);
window = meta_stack_get_default_focus_window_at_point (screen->stack,
screen->active_workspace,
not_this_one,
root_x_return,
root_y_return);
x, y);
return window;
}
@ -1827,28 +1809,11 @@ meta_screen_get_current_monitor (MetaScreen *screen)
if (screen->display->monitor_cache_invalidated)
{
Window root_return, child_return;
double win_x_return, win_y_return;
double root_x_return, root_y_return;
XIButtonState buttons;
XIModifierState mods;
XIGroupState group;
int x, y;
XIQueryPointer (screen->display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
screen->xroot,
&root_return,
&child_return,
&root_x_return,
&root_y_return,
&win_x_return,
&win_y_return,
&buttons,
&mods,
&group);
free (buttons.mask);
meta_screen_get_current_monitor_for_pos (screen, root_x_return, root_y_return);
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
&x, &y, NULL);
meta_screen_get_current_monitor_for_pos (screen, x, y);
}
return screen->last_monitor_index;

View File

@ -628,11 +628,7 @@ void meta_window_set_current_workspace_hint (MetaWindow *window);
unsigned long meta_window_get_net_wm_desktop (MetaWindow *window);
void meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_window_show_menu (MetaWindow *window);
gboolean meta_window_titlebar_is_onscreen (MetaWindow *window);
void meta_window_shove_titlebar_onscreen (MetaWindow *window);
@ -684,9 +680,8 @@ void meta_window_update_layer (MetaWindow *window);
void meta_window_recalc_features (MetaWindow *window);
/* recalc_window_type is x11 only, wayland does its thing and then calls type_changed */
void meta_window_recalc_window_type (MetaWindow *window);
void meta_window_type_changed (MetaWindow *window);
void meta_window_set_type (MetaWindow *window,
MetaWindowType type);
void meta_window_frame_size_changed (MetaWindow *window);
@ -751,4 +746,6 @@ void meta_window_activate_full (MetaWindow *window,
MetaClientType source_indication,
MetaWorkspace *workspace);
gboolean meta_window_is_client_decorated (MetaWindow *window);
#endif

View File

@ -35,7 +35,7 @@
*/
#define _GNU_SOURCE
#define _SVID_SOURCE /* for gethostname() */
#define _XOPEN_SOURCE 500 /* for gethostname() */
#include <config.h>
#include "window-props.h"
@ -727,7 +727,7 @@ reload_net_wm_state (MetaWindow *window,
meta_verbose ("Reloaded _NET_WM_STATE for %s\n",
window->desc);
meta_window_recalc_window_type (window);
meta_window_x11_recalc_window_type (window);
meta_window_recalc_features (window);
}

View File

@ -38,6 +38,7 @@
#include <meta/common.h>
#include <meta/errors.h>
#include <meta/prefs.h>
#include <meta/meta-cursor-tracker.h>
#include "window-private.h"
#include "window-props.h"
@ -225,7 +226,7 @@ meta_window_x11_update_net_wm_type (MetaWindow *window)
meta_XFree (str);
}
meta_window_recalc_window_type (window);
meta_window_x11_recalc_window_type (window);
}
void
@ -673,35 +674,19 @@ meta_window_x11_property_notify (MetaWindow *window,
static int
query_pressed_buttons (MetaWindow *window)
{
double x, y, query_root_x, query_root_y;
Window root, child;
XIButtonState buttons;
XIModifierState mods;
XIGroupState group;
ClutterModifierType mods;
int button = 0;
meta_error_trap_push (window->display);
XIQueryPointer (window->display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
window->xwindow,
&root, &child,
&query_root_x, &query_root_y,
&x, &y,
&buttons, &mods, &group);
meta_cursor_tracker_get_pointer (window->screen->cursor_tracker,
NULL, NULL, &mods);
if (meta_error_trap_pop_with_return (window->display) != Success)
goto out;
if (XIMaskIsSet (buttons.mask, Button1))
if (mods & CLUTTER_BUTTON1_MASK)
button |= 1 << 1;
if (XIMaskIsSet (buttons.mask, Button2))
if (mods & CLUTTER_BUTTON2_MASK)
button |= 1 << 2;
if (XIMaskIsSet (buttons.mask, Button3))
if (mods & CLUTTER_BUTTON3_MASK)
button |= 1 << 3;
free (buttons.mask);
out:
return button;
}
@ -887,7 +872,7 @@ meta_window_x11_client_message (MetaWindow *window,
(action == _NET_WM_STATE_ADD) ||
(action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal);
meta_window_recalc_window_type (window);
meta_window_x11_recalc_window_type (window);
meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
}
@ -1180,6 +1165,11 @@ meta_window_x11_client_message (MetaWindow *window,
meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
}
else if (event->xclient.message_type ==
display->atom__GTK_SHOW_WINDOW_MENU)
{
meta_window_show_menu (window);
}
return FALSE;
}
@ -1521,3 +1511,114 @@ error:
meta_error_trap_pop (display);
return NULL;
}
void
meta_window_x11_recalc_window_type (MetaWindow *window)
{
MetaWindowType type;
if (window->type_atom != None)
{
if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
type = META_WINDOW_DESKTOP;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
type = META_WINDOW_DOCK;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
type = META_WINDOW_TOOLBAR;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
type = META_WINDOW_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
type = META_WINDOW_UTILITY;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
type = META_WINDOW_SPLASHSCREEN;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
type = META_WINDOW_DIALOG;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
type = META_WINDOW_NORMAL;
/* The below are *typically* override-redirect windows, but the spec does
* not disallow using them for managed windows.
*/
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
type = META_WINDOW_DROPDOWN_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU)
type = META_WINDOW_POPUP_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP)
type = META_WINDOW_TOOLTIP;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION)
type = META_WINDOW_NOTIFICATION;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO)
type = META_WINDOW_COMBO;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND)
type = META_WINDOW_DND;
else
{
char *atom_name;
/*
* Fallback on a normal type, and print warning. Don't abort.
*/
type = META_WINDOW_NORMAL;
meta_error_trap_push (window->display);
atom_name = XGetAtomName (window->display->xdisplay,
window->type_atom);
meta_error_trap_pop (window->display);
meta_warning ("Unrecognized type atom [%s] set for %s \n",
atom_name ? atom_name : "unknown",
window->desc);
if (atom_name)
XFree (atom_name);
}
}
else if (window->transient_for != NULL)
{
type = META_WINDOW_DIALOG;
}
else
{
type = META_WINDOW_NORMAL;
}
if (type == META_WINDOW_DIALOG &&
window->wm_state_modal)
type = META_WINDOW_MODAL_DIALOG;
/* We don't want to allow override-redirect windows to have decorated-window
* types since that's just confusing.
*/
if (window->override_redirect)
{
switch (window->type)
{
/* Decorated types */
case META_WINDOW_NORMAL:
case META_WINDOW_DIALOG:
case META_WINDOW_MODAL_DIALOG:
case META_WINDOW_MENU:
case META_WINDOW_UTILITY:
type = META_WINDOW_OVERRIDE_OTHER;
break;
/* Undecorated types, normally not override-redirect */
case META_WINDOW_DESKTOP:
case META_WINDOW_DOCK:
case META_WINDOW_TOOLBAR:
case META_WINDOW_SPLASHSCREEN:
/* Undecorated types, normally override-redirect types */
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_COMBO:
case META_WINDOW_DND:
/* To complete enum */
case META_WINDOW_OVERRIDE_OTHER:
break;
}
}
meta_verbose ("Calculated type %u for %s, old type %u\n",
type, window->desc, type);
meta_window_set_type (window, type);
}

View File

@ -35,6 +35,8 @@ void meta_window_x11_update_opaque_region (MetaWindow *window);
void meta_window_x11_update_input_region (MetaWindow *window);
void meta_window_x11_update_shape_region (MetaWindow *window);
void meta_window_x11_recalc_window_type (MetaWindow *window);
gboolean meta_window_x11_configure_request (MetaWindow *window,
XEvent *event);
gboolean meta_window_x11_property_notify (MetaWindow *window,

View File

@ -1368,9 +1368,7 @@ meta_window_apply_session_info (MetaWindow *window,
if (window->has_maximize_func && info->maximized)
{
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
if (info->saved_rect_set)
{
@ -1524,13 +1522,6 @@ meta_window_unmanage (MetaWindow *window,
meta_compositor_remove_window (window->display->compositor, window);
}
if (window->display->window_with_menu == window)
{
meta_ui_window_menu_free (window->display->window_menu);
window->display->window_menu = NULL;
window->display->window_with_menu = NULL;
}
if (destroying_windows_disallowed > 0)
meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
window->desc);
@ -3120,6 +3111,9 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (window->surface && window->maximized_horizontally && window->maximized_vertically)
meta_wayland_surface_send_maximized (window->surface);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
@ -3367,7 +3361,7 @@ meta_window_tile (MetaWindow *window)
return;
if (window->tile_mode == META_TILE_MAXIMIZED)
directions = META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL;
directions = META_MAXIMIZE_BOTH;
else
directions = META_MAXIMIZE_VERTICAL;
@ -3605,10 +3599,13 @@ meta_window_unmaximize_internal (MetaWindow *window,
set_net_wm_state (window);
}
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
g_object_thaw_notify (G_OBJECT (window));
if (window->surface && !window->maximized_horizontally && !window->maximized_vertically)
meta_wayland_surface_send_unmaximized (window->surface);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "maximized-horizontally");
g_object_notify (G_OBJECT (window), "maximized-vertically");
g_object_thaw_notify (G_OBJECT (window));
}
void
@ -3711,6 +3708,9 @@ meta_window_make_fullscreen_internal (MetaWindow *window)
/* For the auto-minimize feature, if we fail to get focus */
meta_screen_queue_check_fullscreen (window->screen);
if (window->surface)
meta_wayland_surface_send_fullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen");
}
}
@ -3767,6 +3767,9 @@ meta_window_unmake_fullscreen (MetaWindow *window)
meta_window_update_layer (window);
if (window->surface)
meta_wayland_surface_send_unfullscreened (window->surface);
g_object_notify (G_OBJECT (window), "fullscreen");
}
}
@ -5082,6 +5085,7 @@ meta_window_move_resize_wayland (MetaWindow *window,
meta_window_move_resize_internal (window, flags, NorthWestGravity,
x, y, width, height);
save_user_window_placement (window);
}
/**
@ -7051,122 +7055,7 @@ meta_window_update_struts (MetaWindow *window)
}
}
void
meta_window_recalc_window_type (MetaWindow *window)
{
MetaWindowType old_type;
old_type = window->type;
if (window->type_atom != None)
{
if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
window->type = META_WINDOW_DESKTOP;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
window->type = META_WINDOW_DOCK;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
window->type = META_WINDOW_TOOLBAR;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
window->type = META_WINDOW_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
window->type = META_WINDOW_UTILITY;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
window->type = META_WINDOW_SPLASHSCREEN;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
window->type = META_WINDOW_DIALOG;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
window->type = META_WINDOW_NORMAL;
/* The below are *typically* override-redirect windows, but the spec does
* not disallow using them for managed windows.
*/
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
window->type = META_WINDOW_DROPDOWN_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU)
window->type = META_WINDOW_POPUP_MENU;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP)
window->type = META_WINDOW_TOOLTIP;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION)
window->type = META_WINDOW_NOTIFICATION;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO)
window->type = META_WINDOW_COMBO;
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND)
window->type = META_WINDOW_DND;
else
{
char *atom_name;
/*
* Fallback on a normal type, and print warning. Don't abort.
*/
window->type = META_WINDOW_NORMAL;
meta_error_trap_push (window->display);
atom_name = XGetAtomName (window->display->xdisplay,
window->type_atom);
meta_error_trap_pop (window->display);
meta_warning ("Unrecognized type atom [%s] set for %s \n",
atom_name ? atom_name : "unknown",
window->desc);
if (atom_name)
XFree (atom_name);
}
}
else if (window->transient_for != NULL)
{
window->type = META_WINDOW_DIALOG;
}
else
{
window->type = META_WINDOW_NORMAL;
}
if (window->type == META_WINDOW_DIALOG &&
window->wm_state_modal)
window->type = META_WINDOW_MODAL_DIALOG;
/* We don't want to allow override-redirect windows to have decorated-window
* types since that's just confusing.
*/
if (window->override_redirect)
{
switch (window->type)
{
/* Decorated types */
case META_WINDOW_NORMAL:
case META_WINDOW_DIALOG:
case META_WINDOW_MODAL_DIALOG:
case META_WINDOW_MENU:
case META_WINDOW_UTILITY:
window->type = META_WINDOW_OVERRIDE_OTHER;
break;
/* Undecorated types, normally not override-redirect */
case META_WINDOW_DESKTOP:
case META_WINDOW_DOCK:
case META_WINDOW_TOOLBAR:
case META_WINDOW_SPLASHSCREEN:
/* Undecorated types, normally override-redirect types */
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_COMBO:
case META_WINDOW_DND:
/* To complete enum */
case META_WINDOW_OVERRIDE_OTHER:
break;
}
}
meta_verbose ("Calculated type %u for %s, old type %u\n",
window->type, window->desc, old_type);
if (old_type != window->type)
meta_window_type_changed (window);
}
void
static void
meta_window_type_changed (MetaWindow *window)
{
gboolean old_decorated = window->decorated;
@ -7199,6 +7088,17 @@ meta_window_type_changed (MetaWindow *window)
g_object_thaw_notify (object);
}
void
meta_window_set_type (MetaWindow *window,
MetaWindowType type)
{
if (window->type == type)
return;
window->type = type;
meta_window_type_changed (window);
}
void
meta_window_frame_size_changed (MetaWindow *window)
{
@ -7511,272 +7411,11 @@ meta_window_recalc_features (MetaWindow *window)
*/
}
static void
menu_callback (MetaWindowMenu *menu,
Display *xdisplay,
Window client_xwindow,
guint32 timestamp,
MetaMenuOp op,
int workspace_index,
gpointer data)
{
MetaDisplay *display;
MetaWindow *window;
MetaWorkspace *workspace;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, client_xwindow);
workspace = NULL;
if (window != NULL) /* window can be NULL */
{
meta_verbose ("Menu op %u on %s\n", op, window->desc);
switch (op)
{
case META_MENU_OP_NONE:
/* nothing */
break;
case META_MENU_OP_DELETE:
meta_window_delete (window, timestamp);
break;
case META_MENU_OP_MINIMIZE:
meta_window_minimize (window);
break;
case META_MENU_OP_UNMAXIMIZE:
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
break;
case META_MENU_OP_MAXIMIZE:
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
break;
case META_MENU_OP_UNSHADE:
meta_window_unshade (window, timestamp);
break;
case META_MENU_OP_SHADE:
meta_window_shade (window, timestamp);
break;
case META_MENU_OP_MOVE_LEFT:
workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
META_MOTION_LEFT);
break;
case META_MENU_OP_MOVE_RIGHT:
workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
META_MOTION_RIGHT);
break;
case META_MENU_OP_MOVE_UP:
workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
META_MOTION_UP);
break;
case META_MENU_OP_MOVE_DOWN:
workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
META_MOTION_DOWN);
break;
case META_MENU_OP_WORKSPACES:
workspace = meta_screen_get_workspace_by_index (window->screen,
workspace_index);
break;
case META_MENU_OP_STICK:
meta_window_stick (window);
break;
case META_MENU_OP_UNSTICK:
meta_window_unstick (window);
break;
case META_MENU_OP_ABOVE:
case META_MENU_OP_UNABOVE:
if (window->wm_state_above == FALSE)
meta_window_make_above (window);
else
meta_window_unmake_above (window);
break;
case META_MENU_OP_MOVE:
meta_window_begin_grab_op (window,
META_GRAB_OP_KEYBOARD_MOVING,
TRUE,
timestamp);
break;
case META_MENU_OP_RESIZE:
meta_window_begin_grab_op (window,
META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
TRUE,
timestamp);
break;
case META_MENU_OP_RECOVER:
meta_window_shove_titlebar_onscreen (window);
break;
default:
meta_warning (G_STRLOC": Unknown window op\n");
break;
}
if (workspace)
{
meta_window_change_workspace (window,
workspace);
}
}
else
{
meta_verbose ("Menu callback on nonexistent window\n");
}
if (display->window_menu == menu)
{
display->window_menu = NULL;
display->window_with_menu = NULL;
}
meta_ui_window_menu_free (menu);
}
void
meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
guint32 timestamp)
meta_window_show_menu (MetaWindow *window)
{
MetaMenuOp ops;
MetaMenuOp insensitive;
MetaWindowMenu *menu;
MetaWorkspaceLayout layout;
int n_workspaces;
gboolean ltr;
g_return_if_fail (!window->override_redirect);
if (window->display->window_menu)
{
meta_ui_window_menu_free (window->display->window_menu);
window->display->window_menu = NULL;
window->display->window_with_menu = NULL;
}
ops = META_MENU_OP_NONE;
insensitive = META_MENU_OP_NONE;
ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE);
if (!meta_window_titlebar_is_onscreen (window) &&
window->type != META_WINDOW_DOCK &&
window->type != META_WINDOW_DESKTOP)
ops |= META_MENU_OP_RECOVER;
if (!meta_prefs_get_workspaces_only_on_primary () ||
meta_window_is_on_primary_monitor (window))
{
n_workspaces = meta_screen_get_n_workspaces (window->screen);
if (n_workspaces > 1)
ops |= META_MENU_OP_WORKSPACES;
meta_screen_calc_workspace_layout (window->screen,
n_workspaces,
meta_workspace_index ( window->screen->active_workspace),
&layout);
if (!window->on_all_workspaces)
{
ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
if (layout.current_col > 0)
ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
if ((layout.current_col < layout.cols - 1) &&
(layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
if (layout.current_row > 0)
ops |= META_MENU_OP_MOVE_UP;
if ((layout.current_row < layout.rows - 1) &&
((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
ops |= META_MENU_OP_MOVE_DOWN;
}
meta_screen_free_workspace_layout (&layout);
ops |= META_MENU_OP_UNSTICK;
ops |= META_MENU_OP_STICK;
}
if (META_WINDOW_MAXIMIZED (window))
ops |= META_MENU_OP_UNMAXIMIZE;
else
ops |= META_MENU_OP_MAXIMIZE;
if (window->wm_state_above)
ops |= META_MENU_OP_UNABOVE;
else
ops |= META_MENU_OP_ABOVE;
if (!window->has_maximize_func)
insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE;
if (!window->has_minimize_func)
insensitive |= META_MENU_OP_MINIMIZE;
if (!window->has_close_func)
insensitive |= META_MENU_OP_DELETE;
if (!window->has_shade_func)
insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE;
if (!META_WINDOW_ALLOWS_MOVE (window))
insensitive |= META_MENU_OP_MOVE;
if (!META_WINDOW_ALLOWS_RESIZE (window))
insensitive |= META_MENU_OP_RESIZE;
if (window->always_sticky)
insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES;
if ((window->type == META_WINDOW_DESKTOP) ||
(window->type == META_WINDOW_DOCK) ||
(window->type == META_WINDOW_SPLASHSCREEN ||
META_WINDOW_MAXIMIZED (window)))
insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE;
/* If all operations are disabled, just quit without showing the menu.
* This is the case, for example, with META_WINDOW_DESKTOP windows.
*/
if ((ops & ~insensitive) == 0)
return;
menu =
meta_ui_window_menu_new (window->screen->ui,
window->xwindow,
ops,
insensitive,
meta_window_get_net_wm_desktop (window),
meta_screen_get_n_workspaces (window->screen),
menu_callback,
NULL);
window->display->window_menu = menu;
window->display->window_with_menu = window;
meta_verbose ("Popping up window menu for %s\n", window->desc);
meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp);
meta_compositor_show_window_menu (window->display->compositor, window);
}
void
@ -7840,7 +7479,7 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
/* Titlebar can't be offscreen if there is no titlebar... */
if (!window->frame)
return FALSE;
return TRUE;
/* Get the rectangle corresponding to the titlebar */
meta_window_get_frame_rect (window, &titlebar_rect);
@ -8072,10 +7711,7 @@ update_move (MetaWindow *window,
display->grab_anchor_root_x = x;
display->grab_anchor_root_y = y;
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
return;
}
@ -8119,9 +7755,7 @@ update_move (MetaWindow *window,
window->user_rect.x = window->saved_rect.x;
window->user_rect.y = window->saved_rect.y;
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
}
display->grab_initial_window_pos = work_area;
@ -8129,10 +7763,7 @@ update_move (MetaWindow *window,
display->grab_anchor_root_y = y;
window->shaken_loose = FALSE;
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
return;
}
}
@ -8855,6 +8486,34 @@ meta_window_same_application (MetaWindow *window,
group==other_group;
}
/**
* meta_window_is_client_decorated:
*
* Check if if the window has decorations drawn by the client.
* (window->decorated refers only to whether we should add decorations)
*/
gboolean
meta_window_is_client_decorated (MetaWindow *window)
{
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
/* Assume all Wayland clients draw decorations - not strictly
* true but good enough for current purposes.
*/
return TRUE;
}
else
{
/* Currently the implementation here is hackish -
* has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set
* to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for
* client-side-decorated window, even if the value is 0 because
* the window is maxized and has no invisible borders or shadows.
*/
return window->has_custom_frame_extents;
}
}
void
meta_window_refresh_resize_popup (MetaWindow *window)
{
@ -10128,12 +9787,6 @@ meta_window_compute_tile_match (MetaWindow *window)
}
}
gboolean
meta_window_can_close (MetaWindow *window)
{
return window->has_close_func;
}
void
meta_window_set_title (MetaWindow *window,
const char *title)
@ -10217,7 +9870,8 @@ meta_window_set_transient_for (MetaWindow *window,
meta_window_propagate_focus_appearance (window, FALSE);
/* may now be a dialog */
meta_window_recalc_window_type (window);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_x11_recalc_window_type (window);
if (!window->constructing)
{
@ -10343,25 +9997,15 @@ window_focus_on_pointer_rest_callback (gpointer data)
MetaWindow *window = focus_data->window;
MetaDisplay *display = window->display;
MetaScreen *screen = window->screen;
Window root, child;
double root_x, root_y, x, y;
int root_x, root_y;
guint32 timestamp;
XIButtonState buttons;
XIModifierState mods;
XIGroupState group;
ClutterActor *child;
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);
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
&root_x, &root_y, NULL);
if (root_x != focus_data->pointer_x ||
root_y != focus_data->pointer_y)
@ -10371,17 +10015,15 @@ window_focus_on_pointer_rest_callback (gpointer data)
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))
child = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (clutter_stage_get_default ()),
CLUTTER_PICK_REACTIVE, root_x, root_y);
if (!META_IS_SURFACE_ACTOR (child))
goto out;
window =
meta_stack_get_default_focus_window_at_point (screen->stack,
screen->active_workspace,
None, root_x, root_y);
NULL, root_x, root_y);
if (window == NULL)
goto out;
@ -10486,3 +10128,51 @@ meta_window_set_custom_frame_extents (MetaWindow *window,
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}
gboolean
meta_window_can_maximize (MetaWindow *window)
{
return window->has_maximize_func;
}
gboolean
meta_window_can_minimize (MetaWindow *window)
{
return window->has_minimize_func;
}
gboolean
meta_window_can_shade (MetaWindow *window)
{
return window->has_shade_func;
}
gboolean
meta_window_can_close (MetaWindow *window)
{
return window->has_close_func;
}
gboolean
meta_window_is_always_on_all_workspaces (MetaWindow *window)
{
return window->always_sticky;
}
gboolean
meta_window_is_above (MetaWindow *window)
{
return window->wm_state_above;
}
gboolean
meta_window_allows_move (MetaWindow *window)
{
return META_WINDOW_ALLOWS_MOVE (window);
}
gboolean
meta_window_allows_resize (MetaWindow *window)
{
return META_WINDOW_ALLOWS_RESIZE (window);
}

View File

@ -62,6 +62,7 @@ item(_GTK_WINDOW_OBJECT_PATH)
item(_GTK_APP_MENU_OBJECT_PATH)
item(_GTK_MENUBAR_OBJECT_PATH)
item(_GTK_FRAME_EXTENTS)
item(_GTK_SHOW_WINDOW_MENU)
item(_GNOME_WM_KEYBINDINGS)
item(_GNOME_PANEL_ACTION)
item(_GNOME_PANEL_ACTION_MAIN_MENU)

View File

@ -86,61 +86,6 @@ typedef enum
META_FRAME_TILED_RIGHT = 1 << 16
} MetaFrameFlags;
/**
* MetaMenuOp:
* @META_MENU_OP_NONE: No menu operation
* @META_MENU_OP_DELETE: Menu operation delete
* @META_MENU_OP_MINIMIZE: Menu operation minimize
* @META_MENU_OP_UNMAXIMIZE: Menu operation unmaximize
* @META_MENU_OP_MAXIMIZE: Menu operation maximize
* @META_MENU_OP_UNSHADE: Menu operation unshade
* @META_MENU_OP_SHADE: Menu operation shade
* @META_MENU_OP_UNSTICK: Menu operation unstick
* @META_MENU_OP_STICK: Menu operation stick
* @META_MENU_OP_WORKSPACES: Menu operation workspaces
* @META_MENU_OP_MOVE: Menu operation move
* @META_MENU_OP_RESIZE: Menu operation resize
* @META_MENU_OP_ABOVE: Menu operation above
* @META_MENU_OP_UNABOVE: Menu operation unabove
* @META_MENU_OP_MOVE_LEFT: Menu operation left
* @META_MENU_OP_MOVE_RIGHT: Menu operation right
* @META_MENU_OP_MOVE_UP: Menu operation up
* @META_MENU_OP_MOVE_DOWN: Menu operation down
* @META_MENU_OP_RECOVER: Menu operation recover
*/
typedef enum
{
META_MENU_OP_NONE = 0,
META_MENU_OP_DELETE = 1 << 0,
META_MENU_OP_MINIMIZE = 1 << 1,
META_MENU_OP_UNMAXIMIZE = 1 << 2,
META_MENU_OP_MAXIMIZE = 1 << 3,
META_MENU_OP_UNSHADE = 1 << 4,
META_MENU_OP_SHADE = 1 << 5,
META_MENU_OP_UNSTICK = 1 << 6,
META_MENU_OP_STICK = 1 << 7,
META_MENU_OP_WORKSPACES = 1 << 8,
META_MENU_OP_MOVE = 1 << 9,
META_MENU_OP_RESIZE = 1 << 10,
META_MENU_OP_ABOVE = 1 << 11,
META_MENU_OP_UNABOVE = 1 << 12,
META_MENU_OP_MOVE_LEFT = 1 << 13,
META_MENU_OP_MOVE_RIGHT = 1 << 14,
META_MENU_OP_MOVE_UP = 1 << 15,
META_MENU_OP_MOVE_DOWN = 1 << 16,
META_MENU_OP_RECOVER = 1 << 17
} MetaMenuOp;
typedef struct _MetaWindowMenu MetaWindowMenu;
typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
Display *xdisplay,
Window client_xwindow,
guint32 timestamp,
MetaMenuOp op,
int workspace,
gpointer user_data);
/**
* MetaGrabOp:
* @META_GRAB_OP_NONE: None
@ -228,7 +173,10 @@ typedef enum
META_GRAB_OP_CLICKING_UNSTICK,
/* Special grab op when the compositor asked for a grab */
META_GRAB_OP_COMPOSITOR
META_GRAB_OP_COMPOSITOR,
/* For when a client takes a popup grab */
META_GRAB_OP_WAYLAND_CLIENT,
} MetaGrabOp;
/**

View File

@ -130,5 +130,7 @@ void meta_compositor_show_tile_preview (MetaCompositor *compositor,
int tile_monitor_number);
void meta_compositor_hide_tile_preview (MetaCompositor *compositor,
MetaScreen *screen);
void meta_compositor_show_window_menu (MetaCompositor *compositor,
MetaWindow *window);
#endif /* META_COMPOSITOR_H */

View File

@ -28,6 +28,7 @@ GOptionContext *meta_get_option_context (void);
void meta_init (void);
int meta_run (void);
void meta_register_with_session (void);
gboolean meta_activate_session (void);
gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */
void meta_set_wm_name (const char *wm_name);

View File

@ -164,6 +164,9 @@ struct _MetaPluginClass
int tile_monitor_number);
void (*hide_tile_preview) (MetaPlugin *plugin);
void (*show_window_menu) (MetaPlugin *plugin,
MetaWindow *window);
/**
* MetaPluginClass::kill_window_effects:
* @actor: a #MetaWindowActor

View File

@ -392,10 +392,6 @@ GType meta_key_binding_get_type (void);
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
void meta_prefs_get_window_binding (const char *name,
unsigned int *keysym,
MetaVirtualModifier *modifiers);
gboolean meta_prefs_get_visual_bell (void);
gboolean meta_prefs_bell_is_audible (void);
GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);

View File

@ -72,11 +72,13 @@ typedef enum
* MetaMaximizeFlags:
* @META_MAXIMIZE_HORIZONTAL: Horizontal
* @META_MAXIMIZE_VERTICAL: Vertical
* @META_MAXIMIZE_BOTH: Both
*/
typedef enum
{
META_MAXIMIZE_HORIZONTAL = 1 << 0,
META_MAXIMIZE_VERTICAL = 1 << 1
META_MAXIMIZE_VERTICAL = 1 << 1,
META_MAXIMIZE_BOTH = (1 << 0 | 1 << 1),
} MetaMaximizeFlags;
/**
@ -252,6 +254,13 @@ void meta_window_begin_grab_op (MetaWindow *window,
gboolean frame_action,
guint32 timestamp);
gboolean meta_window_can_maximize (MetaWindow *window);
gboolean meta_window_can_minimize (MetaWindow *window);
gboolean meta_window_can_shade (MetaWindow *window);
gboolean meta_window_can_close (MetaWindow *window);
gboolean meta_window_is_always_on_all_workspaces (MetaWindow *window);
gboolean meta_window_is_above (MetaWindow *window);
gboolean meta_window_allows_move (MetaWindow *window);
gboolean meta_window_allows_resize (MetaWindow *window);
#endif

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
_Name=Mutter (wayland compositor)
Exec=mutter-launch -- mutter --wayland
Exec=mutter --wayland --display-server
NoDisplay=true
# name of loadable control center module
X-GNOME-WMSettingsModule=metacity

View File

@ -0,0 +1,44 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.login1.Session">
<property name="Active" type="b" access="read" />
<method name="Activate">
</method>
<method name="TakeControl">
<arg name="force" type="b"/>
</method>
<method name="TakeDevice">
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
<arg name="major" type="u" direction="in"/>
<arg name="minor" type="u" direction="in"/>
<arg name="fd" type="h" direction="out"/>
<arg name="paused" type="b" direction="out"/>
</method>
<method name="ReleaseDevice">
<arg name="major" type="u"/>
<arg name="minor" type="u"/>
</method>
<method name="PauseDeviceComplete">
<arg name="major" type="u"/>
<arg name="minor" type="u"/>
</method>
<signal name="PauseDevice">
<arg name="major" type="u"/>
<arg name="minor" type="u"/>
<arg name="type" type="s"/>
</signal>
<signal name="ResumeDevice">
<arg name="major" type="u"/>
<arg name="minor" type="u"/>
<arg name="fd" type="h"/>
</signal>
</interface>
<interface name="org.freedesktop.login1.Seat">
<method name="SwitchTo">
<arg name="vt" type="u"/>
</method>
</interface>
</node>

View File

@ -44,8 +44,6 @@
static void meta_frames_destroy (GtkWidget *object);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_updated (GtkWidget *widget);
static void meta_frames_map (GtkWidget *widget);
static void meta_frames_unmap (GtkWidget *widget);
static void meta_frames_update_prelit_control (MetaFrames *frames,
MetaUIFrame *frame,
@ -134,9 +132,6 @@ meta_frames_class_init (MetaFramesClass *class)
widget_class->style_updated = meta_frames_style_updated;
widget_class->map = meta_frames_map;
widget_class->unmap = meta_frames_unmap;
widget_class->draw = meta_frames_draw;
widget_class->destroy_event = meta_frames_destroy_event;
widget_class->button_press_event = meta_frames_button_press_event;
@ -231,6 +226,7 @@ meta_frames_init (MetaFrames *frames)
frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
update_style_contexts (frames);
gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
@ -522,13 +518,26 @@ MetaFrames*
meta_frames_new (int screen_number)
{
GdkScreen *screen;
MetaFrames *frames;
screen = gdk_display_get_screen (gdk_display_get_default (),
screen_number);
return g_object_new (META_TYPE_FRAMES,
"screen", screen,
NULL);
frames = g_object_new (META_TYPE_FRAMES,
"screen", screen,
"type", GTK_WINDOW_POPUP,
NULL);
/* Put the window at an arbitrary offscreen location; the one place
* it can't be is at -100x-100, since the meta_window_new() will
* mistake it for a window created via meta_create_offscreen_window()
* and ignore it, and we need this window to get frame-synchronization
* messages so that GTK+'s style change handling works.
*/
gtk_window_move (GTK_WINDOW (frames), -200, -200);
gtk_window_resize (GTK_WINDOW (frames), 1, 1);
return frames;
}
/* In order to use a style with a window it has to be attached to that
@ -635,22 +644,6 @@ meta_frames_unmanage_window (MetaFrames *frames,
meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
}
static void
meta_frames_map (GtkWidget *widget)
{
/* We override the parent map function to a no-op because we don't
* want to actually show the GDK window. But GTK needs to think that
* the widget is mapped or it won't deliver the events we care about.
*/
gtk_widget_set_mapped (widget, TRUE);
}
static void
meta_frames_unmap (GtkWidget *widget)
{
gtk_widget_set_mapped (widget, FALSE);
}
static MetaUIFrame*
meta_frames_lookup_window (MetaFrames *frames,
Window xwindow)
@ -1113,9 +1106,6 @@ meta_frame_titlebar_event (MetaUIFrame *frame,
case G_DESKTOP_TITLEBAR_ACTION_MENU:
meta_core_show_window_menu (display,
frame->xwindow,
event->x_root,
event->y_root,
event->button,
event->time);
break;
}
@ -1275,30 +1265,9 @@ meta_frames_button_press_event (GtkWidget *widget,
redraw_control (frames, frame, control);
if (op == META_GRAB_OP_CLICKING_MENU)
{
MetaFrameGeometry fgeom;
GdkRectangle *rect;
int dx, dy;
meta_frames_calc_geometry (frames, frame, &fgeom);
rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
/* get delta to convert to root coords */
dx = event->x_root - event->x;
dy = event->y_root - event->y;
/* Align to the right end of the menu rectangle if RTL */
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
dx += rect->width;
meta_core_show_window_menu (display,
frame->xwindow,
rect->x + dx,
rect->y + rect->height + dy,
event->button,
event->time);
}
meta_core_show_window_menu (display,
frame->xwindow,
event->time);
}
else if (event->button == 1 &&
(control == META_FRAME_CONTROL_RESIZE_SE ||

View File

@ -1,518 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter window menu */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2004 Rob Adams
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include "menu.h"
#include <meta/main.h>
#include "util-private.h"
#include "core.h"
#include "metaaccellabel.h"
#include "ui.h"
typedef struct _MenuItem MenuItem;
typedef struct _MenuData MenuData;
typedef enum
{
MENU_ITEM_SEPARATOR = 0,
MENU_ITEM_NORMAL,
MENU_ITEM_CHECKBOX,
MENU_ITEM_RADIOBUTTON,
MENU_ITEM_WORKSPACE_LIST,
} MetaMenuItemType;
struct _MenuItem
{
MetaMenuOp op;
MetaMenuItemType type;
const gboolean checked;
const char *label;
};
struct _MenuData
{
MetaWindowMenu *menu;
MetaMenuOp op;
};
static void activate_cb (GtkWidget *menuitem, gpointer data);
static MenuItem menuitems[] = {
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MINIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Mi_nimize") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Ma_ximize") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_UNMAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Unma_ximize") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_SHADE, MENU_ITEM_NORMAL, FALSE, N_("Roll _Up") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_UNSHADE, MENU_ITEM_NORMAL, FALSE, N_("_Unroll") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MOVE, MENU_ITEM_NORMAL, FALSE, N_("_Move") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_RESIZE, MENU_ITEM_NORMAL, FALSE, N_("_Resize") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_RECOVER, MENU_ITEM_NORMAL, FALSE, N_("Move Titlebar On_screen") },
{ META_MENU_OP_WORKSPACES, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_ABOVE, MENU_ITEM_CHECKBOX, FALSE, N_("Always on _Top") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_UNABOVE, MENU_ITEM_CHECKBOX, TRUE, N_("Always on _Top") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_STICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Always on Visible Workspace") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_UNSTICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Only on This Workspace") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MOVE_LEFT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Left") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MOVE_RIGHT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace R_ight") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MOVE_UP, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Up") },
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_MOVE_DOWN, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Down") },
{ 0, MENU_ITEM_WORKSPACE_LIST, FALSE, NULL },
{ 0, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
/* Translators: Translate this string the same way as you do in libwnck! */
{ META_MENU_OP_DELETE, MENU_ITEM_NORMAL, FALSE, N_("_Close") }
};
static void
popup_position_func (GtkMenu *menu,
gint *x,
gint *y,
gboolean *push_in,
gpointer user_data)
{
GtkRequisition req;
GdkPoint *pos;
pos = user_data;
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
*x = pos->x;
*y = pos->y;
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
*x = MAX (0, *x - req.width);
/* Ensure onscreen */
*x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
}
static void
menu_closed (GtkMenu *widget,
gpointer data)
{
MetaWindowMenu *menu;
menu = data;
meta_frames_notify_menu_hide (menu->frames);
(* menu->func) (menu,
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
menu->client_xwindow,
gtk_get_current_event_time (),
0, 0,
menu->data);
/* menu may now be freed */
}
static void
activate_cb (GtkWidget *menuitem, gpointer data)
{
MenuData *md;
g_return_if_fail (GTK_IS_WIDGET (menuitem));
md = data;
meta_frames_notify_menu_hide (md->menu->frames);
(* md->menu->func) (md->menu,
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
md->menu->client_xwindow,
gtk_get_current_event_time (),
md->op,
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
"workspace")),
md->menu->data);
/* menu may now be freed */
}
/*
* Given a Display and an index, get the workspace name and add any
* accelerators. At the moment this means adding a _ if the name is of
* the form "Workspace n" where n is less than 10, and escaping any
* other '_'s so they do not create inadvertant accelerators.
*
* The calling code owns the string, and is reponsible to free the
* memory after use.
*
* See also http://mail.gnome.org/archives/gnome-i18n/2008-March/msg00380.html
* which discusses possible i18n concerns.
*/
static char*
get_workspace_name_with_accel (Display *display,
Window xroot,
int index)
{
const char *name;
int number;
int charcount=0;
name = meta_core_get_workspace_name_with_index (display, xroot, index);
g_assert (name != NULL);
/*
* If the name is of the form "Workspace x" where x is an unsigned
* integer, insert a '_' before the number if it is less than 10 and
* return it
*/
number = 0;
if (sscanf (name, _("Workspace %d%n"), &number, &charcount) != 0 &&
*(name + charcount)=='\0')
{
char *new_name;
/*
* Above name is a pointer into the Workspace struct. Here we make
* a copy copy so we can have our wicked way with it.
*/
if (number == 10)
new_name = g_strdup_printf (_("Workspace 1_0"));
else
new_name = g_strdup_printf (_("Workspace %s%d"),
number < 10 ? "_" : "",
number);
return new_name;
}
else
{
/*
* Otherwise this is just a normal name. Escape any _ characters so that
* the user's workspace names do not get mangled. If the number is less
* than 10 we provide an accelerator.
*/
char *new_name;
const char *source;
char *dest;
/*
* Assume the worst case, that every character is a _. We also
* provide memory for " (_#)"
*/
new_name = g_malloc0 (strlen (name) * 2 + 6 + 1);
/*
* Now iterate down the strings, adding '_' to escape as we go
*/
dest = new_name;
source = name;
while (*source != '\0')
{
if (*source == '_')
*dest++ = '_';
*dest++ = *source++;
}
/* People don't start at workspace 0, but workspace 1 */
if (index < 9)
{
g_snprintf (dest, 6, " (_%d)", index + 1);
}
else if (index == 9)
{
g_snprintf (dest, 6, " (_0)");
}
return new_name;
}
}
static GtkWidget *
menu_item_new (MenuItem *menuitem, int workspace_id)
{
unsigned int key;
MetaVirtualModifier mods;
const char *i18n_label;
GtkWidget *mi;
GtkWidget *accel_label;
if (menuitem->type == MENU_ITEM_NORMAL)
{
mi = gtk_menu_item_new ();
}
else if (menuitem->type == MENU_ITEM_CHECKBOX)
{
mi = gtk_check_menu_item_new ();
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
menuitem->checked);
}
else if (menuitem->type == MENU_ITEM_RADIOBUTTON)
{
mi = gtk_check_menu_item_new ();
gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (mi),
TRUE);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
menuitem->checked);
}
else if (menuitem->type == MENU_ITEM_WORKSPACE_LIST)
return NULL;
else
return gtk_separator_menu_item_new ();
i18n_label = _(menuitem->label);
meta_core_get_menu_accelerator (menuitem->op, workspace_id, &key, &mods);
accel_label = meta_accel_label_new_with_mnemonic (i18n_label);
gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
gtk_container_add (GTK_CONTAINER (mi), accel_label);
gtk_widget_show (accel_label);
meta_accel_label_set_accelerator (META_ACCEL_LABEL (accel_label),
key, mods);
return mi;
}
MetaWindowMenu*
meta_window_menu_new (MetaFrames *frames,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
int i;
MetaWindowMenu *menu;
/* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */
if (n_workspaces < 2)
ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES);
else if (n_workspaces == 2)
/* #151183: If we only have two workspaces, disable the menu listing them. */
ops &= ~(META_MENU_OP_WORKSPACES);
menu = g_new (MetaWindowMenu, 1);
menu->frames = frames;
menu->client_xwindow = client_xwindow;
menu->func = func;
menu->data = data;
menu->ops = ops;
menu->insensitive = insensitive;
menu->menu = gtk_menu_new ();
gtk_menu_set_screen (GTK_MENU (menu->menu),
gtk_widget_get_screen (GTK_WIDGET (frames)));
for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++)
{
MenuItem menuitem = menuitems[i];
if (ops & menuitem.op || menuitem.op == 0)
{
GtkWidget *mi;
MenuData *md;
unsigned int key;
MetaVirtualModifier mods;
mi = menu_item_new (&menuitem, -1);
/* Set the activeness of radiobuttons. */
switch (menuitem.op)
{
case META_MENU_OP_STICK:
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
active_workspace == 0xFFFFFFFF);
break;
case META_MENU_OP_UNSTICK:
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
active_workspace != 0xFFFFFFFF);
break;
default:
break;
}
if (menuitem.type == MENU_ITEM_WORKSPACE_LIST)
{
if (ops & META_MENU_OP_WORKSPACES)
{
Display *display;
Window xroot;
GdkScreen *screen;
GdkWindow *window;
GtkWidget *submenu;
int j;
MenuItem to_another_workspace = {
0, MENU_ITEM_NORMAL, FALSE,
N_("Move to Another _Workspace")
};
meta_verbose ("Creating %d-workspace menu current space %lu\n",
n_workspaces, active_workspace);
window = gtk_widget_get_window (GTK_WIDGET (frames));
display = GDK_WINDOW_XDISPLAY (window);
screen = gdk_window_get_screen (window);
xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
submenu = gtk_menu_new ();
g_assert (mi==NULL);
mi = menu_item_new (&to_another_workspace, -1);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);
for (j = 0; j < n_workspaces; j++)
{
char *label;
MenuData *md;
unsigned int key;
MetaVirtualModifier mods;
MenuItem moveitem;
GtkWidget *submi;
meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES,
j + 1,
&key, &mods);
label = get_workspace_name_with_accel (display, xroot, j);
moveitem.type = MENU_ITEM_NORMAL;
moveitem.op = META_MENU_OP_WORKSPACES;
moveitem.label = label;
submi = menu_item_new (&moveitem, j + 1);
g_free (label);
if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK))
gtk_widget_set_sensitive (submi, FALSE);
md = g_new (MenuData, 1);
md->menu = menu;
md->op = META_MENU_OP_WORKSPACES;
g_object_set_data (G_OBJECT (submi),
"workspace",
GINT_TO_POINTER (j));
g_signal_connect_data (G_OBJECT (submi),
"activate",
G_CALLBACK (activate_cb),
md,
(GClosureNotify) g_free, 0);
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi);
gtk_widget_show (submi);
}
}
else
meta_verbose ("not creating workspace menu\n");
}
else if (menuitem.type != MENU_ITEM_SEPARATOR)
{
meta_core_get_menu_accelerator (menuitems[i].op, -1,
&key, &mods);
if (insensitive & menuitem.op)
gtk_widget_set_sensitive (mi, FALSE);
md = g_new (MenuData, 1);
md->menu = menu;
md->op = menuitem.op;
g_signal_connect_data (G_OBJECT (mi),
"activate",
G_CALLBACK (activate_cb),
md,
(GClosureNotify) g_free, 0);
}
if (mi)
{
gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi);
gtk_widget_show (mi);
}
}
}
g_signal_connect (menu->menu, "selection_done",
G_CALLBACK (menu_closed), menu);
return menu;
}
void
meta_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
GdkPoint *pt;
pt = g_new (GdkPoint, 1);
g_object_set_data_full (G_OBJECT (menu->menu),
"destroy-point",
pt,
g_free);
pt->x = root_x;
pt->y = root_y;
gtk_menu_popup (GTK_MENU (menu->menu),
NULL, NULL,
popup_position_func, pt,
button,
timestamp);
if (!gtk_widget_get_visible (menu->menu))
meta_warning ("GtkMenu failed to grab the pointer\n");
}
void
meta_window_menu_free (MetaWindowMenu *menu)
{
gtk_widget_destroy (menu->menu);
g_free (menu);
}

View File

@ -1,55 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter window menu */
/*
* Copyright (C) 2001 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_MENU_H
#define META_MENU_H
#include <gtk/gtk.h>
#include "frames.h"
struct _MetaWindowMenu
{
MetaFrames *frames;
Window client_xwindow;
GtkWidget *menu;
MetaWindowMenuFunc func;
gpointer data;
MetaMenuOp ops;
MetaMenuOp insensitive;
};
MetaWindowMenu* meta_window_menu_new (MetaFrames *frames,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data);
void meta_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_window_menu_free (MetaWindowMenu *menu);
#endif

View File

@ -1,451 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity hacked-up GtkAccelLabel */
/* Copyright (C) 2002 Red Hat, Inc. */
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
* Copyright (C) 1998 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <config.h>
#include "metaaccellabel.h"
#include <gtk/gtk.h>
#include <string.h>
#include "util-private.h"
static void meta_accel_label_destroy (GtkWidget *object);
static void meta_accel_label_finalize (GObject *object);
static void meta_accel_label_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural);
static void meta_accel_label_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
static gboolean meta_accel_label_draw (GtkWidget *widget,
cairo_t *cr);
static void meta_accel_label_update (MetaAccelLabel *accel_label);
static int meta_accel_label_get_accel_width (MetaAccelLabel *accel_label);
G_DEFINE_TYPE (MetaAccelLabel, meta_accel_label, GTK_TYPE_LABEL);
static void
meta_accel_label_class_init (MetaAccelLabelClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
gobject_class->finalize = meta_accel_label_finalize;
widget_class->destroy = meta_accel_label_destroy;
widget_class->get_preferred_width = meta_accel_label_get_preferred_width;
widget_class->get_preferred_height = meta_accel_label_get_preferred_height;
widget_class->draw = meta_accel_label_draw;
class->signal_quote1 = g_strdup ("<:");
class->signal_quote2 = g_strdup (":>");
/* This is the text that should appear next to menu accelerators
* that use the shift key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_shift = g_strdup (_("Shift"));
/* This is the text that should appear next to menu accelerators
* that use the control key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_control = g_strdup (_("Ctrl"));
/* This is the text that should appear next to menu accelerators
* that use the alt key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_alt = g_strdup (_("Alt"));
/* This is the text that should appear next to menu accelerators
* that use the meta key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_meta = g_strdup (_("Meta"));
/* This is the text that should appear next to menu accelerators
* that use the super key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_super = g_strdup (_("Super"));
/* This is the text that should appear next to menu accelerators
* that use the hyper key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_hyper = g_strdup (_("Hyper"));
/* This is the text that should appear next to menu accelerators
* that use the mod2 key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_mod2 = g_strdup (_("Mod2"));
/* This is the text that should appear next to menu accelerators
* that use the mod3 key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_mod3 = g_strdup (_("Mod3"));
/* This is the text that should appear next to menu accelerators
* that use the mod4 key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_mod4 = g_strdup (_("Mod4"));
/* This is the text that should appear next to menu accelerators
* that use the mod5 key. If the text on this key isn't typically
* translated on keyboards used for your language, don't translate
* this.
*/
class->mod_name_mod5 = g_strdup (_("Mod5"));
class->mod_separator = g_strdup ("+");
class->accel_seperator = g_strdup (" / ");
class->latin1_to_char = TRUE;
}
static void
meta_accel_label_init (MetaAccelLabel *accel_label)
{
accel_label->accel_padding = 3;
accel_label->accel_string = NULL;
meta_accel_label_update (accel_label);
}
GtkWidget*
meta_accel_label_new_with_mnemonic (const gchar *string)
{
MetaAccelLabel *accel_label;
g_return_val_if_fail (string != NULL, NULL);
accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL);
gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string);
return GTK_WIDGET (accel_label);
}
static void
meta_accel_label_destroy (GtkWidget *object)
{
MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
g_free (accel_label->accel_string);
accel_label->accel_string = NULL;
accel_label->accel_mods = 0;
accel_label->accel_key = 0;
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->destroy (object);
}
static void
meta_accel_label_finalize (GObject *object)
{
MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
g_free (accel_label->accel_string);
G_OBJECT_CLASS (meta_accel_label_parent_class)->finalize (object);
}
void
meta_accel_label_set_accelerator (MetaAccelLabel *accel_label,
guint accelerator_key,
MetaVirtualModifier accelerator_mods)
{
g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
if (accelerator_key != accel_label->accel_key ||
accelerator_mods != accel_label->accel_mods)
{
accel_label->accel_mods = accelerator_mods;
accel_label->accel_key = accelerator_key;
meta_accel_label_update (accel_label);
}
}
static int
meta_accel_label_get_accel_width (MetaAccelLabel *accel_label)
{
g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0);
return (accel_label->accel_string_width +
(accel_label->accel_string_width ? accel_label->accel_padding : 0));
}
static void
meta_accel_label_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
PangoLayout *layout;
gint width;
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_width (widget, minimum, natural);
layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
pango_layout_get_pixel_size (layout, &width, NULL);
accel_label->accel_string_width = width;
g_object_unref (G_OBJECT (layout));
}
static void
meta_accel_label_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_height (widget, minimum, natural);
}
/* Mostly taken from GTK3. */
static gboolean
meta_accel_label_draw (GtkWidget *widget,
cairo_t *cr)
{
MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
GtkMisc *misc = GTK_MISC (accel_label);
GtkTextDirection direction;
int ac_width;
GtkAllocation allocation;
GtkRequisition requisition;
direction = gtk_widget_get_direction (widget);
ac_width = meta_accel_label_get_accel_width (accel_label);
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_get_preferred_size (widget,
&requisition, NULL);
if (allocation.width >= requisition.width + ac_width)
{
GtkStyleContext *style;
PangoLayout *label_layout;
PangoLayout *accel_layout;
GtkLabel *label = GTK_LABEL (widget);
gint x, y, xpad, ypad;
gfloat xalign, yalign;
label_layout = gtk_label_get_layout (GTK_LABEL (accel_label));
gtk_misc_get_alignment (misc, &xalign, &yalign);
cairo_save (cr);
/* XXX: Mad hack: We modify the label's width so it renders
* properly in its draw function that we chain to. */
if (direction == GTK_TEXT_DIR_RTL)
cairo_translate (cr, ac_width, 0);
if (gtk_label_get_ellipsize (label))
pango_layout_set_width (label_layout,
pango_layout_get_width (label_layout)
- ac_width * PANGO_SCALE);
allocation.width -= ac_width;
gtk_widget_set_allocation (widget, &allocation);
if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget,
cr);
allocation.width += ac_width;
gtk_widget_set_allocation (widget, &allocation);
if (gtk_label_get_ellipsize (label))
pango_layout_set_width (label_layout,
pango_layout_get_width (label_layout)
+ ac_width * PANGO_SCALE);
cairo_restore (cr);
gtk_misc_get_padding (misc, &xpad, &ypad);
if (direction == GTK_TEXT_DIR_RTL)
x = xpad;
else
x = gtk_widget_get_allocated_width (widget) - xpad - ac_width;
gtk_label_get_layout_offsets (GTK_LABEL (accel_label), NULL, &y);
accel_layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 1.5;
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style,
gtk_widget_get_state_flags (widget));
gtk_render_layout (gtk_widget_get_style_context (widget),
cr,
x, y,
accel_layout);
gtk_style_context_restore (style);
g_object_unref (accel_layout);
}
else
{
if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget, cr);
}
return FALSE;
}
static void
meta_accel_label_update (MetaAccelLabel *accel_label)
{
MetaAccelLabelClass *class;
GString *gstring;
gboolean seen_mod = FALSE;
gunichar ch;
g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
class = META_ACCEL_LABEL_GET_CLASS (accel_label);
g_free (accel_label->accel_string);
accel_label->accel_string = NULL;
gstring = g_string_new (accel_label->accel_string);
g_string_append (gstring, gstring->len ? class->accel_seperator : " ");
if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK)
{
g_string_append (gstring, class->mod_name_shift);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_control);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_alt);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_META_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_meta);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_super);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_hyper);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_mod2);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_mod3);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_mod4);
seen_mod = TRUE;
}
if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK)
{
if (seen_mod)
g_string_append (gstring, class->mod_separator);
g_string_append (gstring, class->mod_name_mod5);
seen_mod = TRUE;
}
if (seen_mod)
g_string_append (gstring, class->mod_separator);
ch = gdk_keyval_to_unicode (accel_label->accel_key);
if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
(ch < 0x80 || class->latin1_to_char))
{
switch (ch)
{
case ' ':
g_string_append (gstring, "Space");
break;
case '\\':
g_string_append (gstring, "Backslash");
break;
default:
g_string_append_unichar (gstring, g_unichar_toupper (ch));
break;
}
}
else
{
gchar *tmp;
tmp = gtk_accelerator_name (accel_label->accel_key, 0);
if (tmp[0] != 0 && tmp[1] == 0)
tmp[0] = g_ascii_toupper (tmp[0]);
g_string_append (gstring, tmp);
g_free (tmp);
}
g_free (accel_label->accel_string);
accel_label->accel_string = gstring->str;
g_string_free (gstring, FALSE);
g_assert (accel_label->accel_string);
/* accel_label->accel_string = g_strdup ("-/-"); */
gtk_widget_queue_resize (GTK_WIDGET (accel_label));
}

View File

@ -1,104 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity hacked-up GtkAccelLabel */
/* Copyright (C) 2002 Red Hat, Inc. */
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
* Copyright (C) 1998 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __META_ACCEL_LABEL_H__
#define __META_ACCEL_LABEL_H__
#include <gtk/gtk.h>
#include <meta/common.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define META_TYPE_ACCEL_LABEL (meta_accel_label_get_type ())
#define META_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabel))
#define META_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
#define META_IS_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_ACCEL_LABEL))
#define META_IS_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_ACCEL_LABEL))
#define META_ACCEL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
typedef struct _MetaAccelLabel MetaAccelLabel;
typedef struct _MetaAccelLabelClass MetaAccelLabelClass;
struct _MetaAccelLabel
{
GtkLabel label;
MetaVirtualModifier accel_mods;
guint accel_key;
guint accel_padding;
gchar *accel_string;
guint16 accel_string_width;
};
struct _MetaAccelLabelClass
{
GtkLabelClass parent_class;
gchar *signal_quote1;
gchar *signal_quote2;
gchar *mod_name_shift;
gchar *mod_name_control;
gchar *mod_name_alt;
gchar *mod_name_meta;
gchar *mod_name_super;
gchar *mod_name_hyper;
gchar *mod_name_mod2;
gchar *mod_name_mod3;
gchar *mod_name_mod4;
gchar *mod_name_mod5;
gchar *mod_separator;
gchar *accel_seperator;
guint latin1_to_char : 1;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
GType meta_accel_label_get_type (void) G_GNUC_CONST;
GtkWidget* meta_accel_label_new_with_mnemonic (const gchar *string);
void meta_accel_label_set_accelerator (MetaAccelLabel *accel_label,
guint accelerator_key,
MetaVirtualModifier accelerator_mods);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __META_ACCEL_LABEL_H__ */

View File

@ -295,9 +295,12 @@ meta_ui_new (Display *xdisplay,
g_assert (gdisplay == gdk_display_get_default ());
ui->frames = meta_frames_new (XScreenNumberOfScreen (screen));
/* This does not actually show any widget. MetaFrames has been hacked so
* that showing it doesn't actually do anything. But we need the flags
* set for GTK to deliver events properly. */
/* GTK+ needs the frame-sync protocol to work in order to properly
* handle style changes. This means that the dummy widget we create
* to get the style for title bars actually needs to be mapped
* and fully tracked as a MetaWindow. Horrible, but mostly harmless -
* the window is a 1x1 overide redirect window positioned offscreen.
*/
gtk_widget_show (GTK_WIDGET (ui->frames));
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui);
@ -511,40 +514,6 @@ meta_ui_set_frame_title (MetaUI *ui,
meta_frames_set_title (ui->frames, xwindow, title);
}
MetaWindowMenu*
meta_ui_window_menu_new (MetaUI *ui,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
return meta_window_menu_new (ui->frames,
ops, insensitive,
client_xwindow,
active_workspace,
n_workspaces,
func, data);
}
void
meta_ui_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
meta_window_menu_popup (menu, root_x, root_y, button, timestamp);
}
void
meta_ui_window_menu_free (MetaWindowMenu *menu)
{
meta_window_menu_free (menu);
}
GdkPixbuf*
meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,
int src_x,

View File

@ -120,21 +120,6 @@ void meta_ui_update_frame_style (MetaUI *ui,
void meta_ui_repaint_frame (MetaUI *ui,
Window xwindow);
MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data);
void meta_ui_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_ui_window_menu_free (MetaWindowMenu *menu);
/* FIXME these lack a display arg */
GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,

441
src/wayland/meta-login1.c Normal file
View File

@ -0,0 +1,441 @@
/*
* Copyright (C) 2014 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.
*/
#include "config.h"
#include "meta-login1.h"
#include "meta-dbus-login1.h"
#include "meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
#include <gio/gunixfdlist.h>
#include <clutter/clutter.h>
#include <clutter/evdev/clutter-evdev.h>
#include <clutter/egl/clutter-egl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>
#include <fcntl.h>
#include <unistd.h>
#include <systemd/sd-login.h>
struct _MetaLogin1
{
Login1Session *session_proxy;
Login1Seat *seat_proxy;
gboolean session_active;
};
/* Stolen from tp_escape_as_identifier, from tp-glib,
* which follows the same escaping convention as systemd.
*/
static inline gboolean
_esc_ident_bad (gchar c, gboolean is_first)
{
return ((c < 'a' || c > 'z') &&
(c < 'A' || c > 'Z') &&
(c < '0' || c > '9' || is_first));
}
static gchar *
escape_dbus_component (const gchar *name)
{
gboolean bad = FALSE;
size_t len = 0;
GString *op;
const gchar *ptr, *first_ok;
g_return_val_if_fail (name != NULL, NULL);
/* fast path for empty name */
if (name[0] == '\0')
return g_strdup ("_");
for (ptr = name; *ptr; ptr++)
{
if (_esc_ident_bad (*ptr, ptr == name))
{
bad = TRUE;
len += 3;
}
else
len++;
}
/* fast path if it's clean */
if (!bad)
return g_strdup (name);
/* If strictly less than ptr, first_ok is the first uncopied safe character.
*/
first_ok = name;
op = g_string_sized_new (len);
for (ptr = name; *ptr; ptr++)
{
if (_esc_ident_bad (*ptr, ptr == name))
{
/* copy preceding safe characters if any */
if (first_ok < ptr)
{
g_string_append_len (op, first_ok, ptr - first_ok);
}
/* escape the unsafe character */
g_string_append_printf (op, "_%02x", (unsigned char)(*ptr));
/* restart after it */
first_ok = ptr + 1;
}
}
/* copy trailing safe characters if any */
if (first_ok < ptr)
{
g_string_append_len (op, first_ok, ptr - first_ok);
}
return g_string_free (op, FALSE);
}
static char *
get_escaped_dbus_path (const char *prefix,
const char *component)
{
char *escaped_component = escape_dbus_component (component);
char *path = g_strconcat (prefix, "/", component, NULL);
g_free (escaped_component);
return path;
}
static Login1Session *
get_session_proxy (GCancellable *cancellable)
{
char *proxy_path;
char *session_id;
Login1Session *session_proxy;
if (sd_pid_get_session (getpid (), &session_id) < 0)
return NULL;
proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.freedesktop.login1",
proxy_path,
cancellable, NULL);
free (proxy_path);
return session_proxy;
}
static Login1Seat *
get_seat_proxy (GCancellable *cancellable)
{
return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.freedesktop.login1",
"/org/freedesktop/login1/seat/self",
cancellable, NULL);
}
static void
session_unpause (void)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_kms_display_queue_modes_reset (cogl_display);
clutter_set_paused (FALSE);
/* clutter_evdev_reclaim_devices (); */
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
/* When we mode-switch back, we need to immediately queue a redraw
* in case nothing else quueed one for us, and force the cursor to
* update. */
clutter_actor_queue_redraw (compositor->stage);
meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
}
}
static void
session_pause (void)
{
clutter_set_paused (TRUE);
/* clutter_evdev_release_devices (); */
}
static void
sync_active (MetaLogin1 *self)
{
gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
if (active == self->session_active)
return;
self->session_active = active;
if (active)
session_unpause ();
else
session_pause ();
}
static void
on_active_changed (Login1Session *session,
GParamSpec *pspec,
gpointer user_data)
{
MetaLogin1 *self = user_data;
sync_active (self);
}
static gboolean
take_device (Login1Session *session_proxy,
int dev_major,
int dev_minor,
int *out_fd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GVariant *fd_variant = NULL;
int fd = -1;
GUnixFDList *fd_list;
if (!login1_session_call_take_device_sync (session_proxy,
dev_major,
dev_minor,
NULL,
&fd_variant,
NULL, /* paused */
&fd_list,
cancellable,
error))
goto out;
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
if (fd == -1)
goto out;
*out_fd = fd;
ret = TRUE;
out:
if (fd_variant)
g_variant_unref (fd_variant);
if (fd_list)
g_object_unref (fd_list);
return ret;
}
static gboolean
get_device_info_from_path (const char *path,
int *out_major,
int *out_minor)
{
gboolean ret = FALSE;
int r;
struct stat st;
r = stat (path, &st);
if (r < 0)
goto out;
if (!S_ISCHR (st.st_mode))
goto out;
*out_major = major (st.st_rdev);
*out_minor = minor (st.st_rdev);
ret = TRUE;
out:
return ret;
}
static gboolean
get_device_info_from_fd (int fd,
int *out_major,
int *out_minor)
{
gboolean ret = FALSE;
int r;
struct stat st;
r = fstat (fd, &st);
if (r < 0)
goto out;
if (!S_ISCHR (st.st_mode))
goto out;
*out_major = major (st.st_rdev);
*out_minor = minor (st.st_rdev);
ret = TRUE;
out:
return ret;
}
static int
open_evdev_device (const char *path,
int flags,
gpointer user_data,
GError **error)
{
MetaLogin1 *self = user_data;
int fd;
int major, minor;
if (!get_device_info_from_path (path, &major, &minor))
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
"Could not get device info for path %s: %m", path);
return -1;
}
if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
return -1;
return fd;
}
static void
close_evdev_device (int fd,
gpointer user_data)
{
MetaLogin1 *self = user_data;
int major, minor;
GError *error = NULL;
if (!get_device_info_from_fd (fd, &major, &minor))
{
g_warning ("Could not get device info for fd %d: %m", fd);
return;
}
if (!login1_session_call_release_device_sync (self->session_proxy,
major, minor,
NULL, &error))
{
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
}
}
static gboolean
get_kms_fd (Login1Session *session_proxy,
int *fd_out)
{
int major, minor;
int fd;
GError *error = NULL;
/* XXX -- use udev to find the DRM master device */
if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
{
g_warning ("Could not stat /dev/dri/card0: %m");
return FALSE;
}
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
{
g_warning ("Could not open DRM device: %s\n", error->message);
g_error_free (error);
return FALSE;
}
*fd_out = fd;
return TRUE;
}
MetaLogin1 *
meta_login1_new (void)
{
MetaLogin1 *self;
Login1Session *session_proxy;
GError *error = NULL;
int kms_fd;
session_proxy = get_session_proxy (NULL);
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
{
g_warning ("Could not take control: %s", error->message);
g_error_free (error);
return NULL;
}
if (!get_kms_fd (session_proxy, &kms_fd))
return NULL;
self = g_slice_new0 (MetaLogin1);
self->session_proxy = session_proxy;
self->seat_proxy = get_seat_proxy (NULL);
/* Clutter/Cogl start out in a state that assumes the session is active */
self->session_active = TRUE;
clutter_egl_set_kms_fd (kms_fd);
clutter_evdev_set_device_callbacks (open_evdev_device,
close_evdev_device,
self);
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
sync_active (self);
return self;
}
void
meta_login1_free (MetaLogin1 *self)
{
g_object_unref (self->seat_proxy);
g_object_unref (self->session_proxy);
g_slice_free (MetaLogin1, self);
}
gboolean
meta_login1_activate_session (MetaLogin1 *self,
GError **error)
{
if (!login1_session_call_activate_sync (self->session_proxy, NULL, error))
return FALSE;
sync_active (self);
return TRUE;
}
gboolean
meta_login1_activate_vt (MetaLogin1 *self,
int vt,
GError **error)
{
return login1_seat_call_switch_to_sync (self->seat_proxy, vt, NULL, error);
}

35
src/wayland/meta-login1.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef META_LOGIN1_H
#define META_LOGIN1_H
#include <glib-object.h>
typedef struct _MetaLogin1 MetaLogin1;
MetaLogin1 *meta_login1_new (void);
void meta_login1_free (MetaLogin1 *self);
gboolean meta_login1_activate_session (MetaLogin1 *self,
GError **error);
gboolean meta_login1_activate_vt (MetaLogin1 *self,
int vt,
GError **error);
#endif

View File

@ -48,7 +48,7 @@ data_offer_accept (struct wl_client *client,
* this be a wl_data_device request? */
if (offer->source)
offer->source->accept (offer->source, serial, mime_type);
wl_data_source_send_target (offer->source->resource, mime_type);
}
static void
@ -58,9 +58,9 @@ data_offer_receive (struct wl_client *client, struct wl_resource *resource,
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source)
offer->source->send (offer->source, mime_type, fd);
else
close (fd);
wl_data_source_send_send (offer->source->resource, mime_type, fd);
close (fd);
}
static void
@ -82,7 +82,8 @@ destroy_data_offer (struct wl_resource *resource)
if (offer->source)
wl_list_remove (&offer->source_destroy_listener.link);
free (offer);
g_slice_free (MetaWaylandDataOffer, offer);
}
static void
@ -99,13 +100,9 @@ static struct wl_resource *
meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
char **p;
offer = malloc (sizeof *offer);
if (offer == NULL)
return NULL;
offer->source = source;
offer->source_destroy_listener.notify = destroy_offer_data_source;
@ -318,8 +315,12 @@ data_device_start_drag (struct wl_client *client,
{
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
MetaWaylandDragGrab *drag_grab;
/* FIXME: Check that client has implicit grab on the origin
* surface that matches the given time. */
if ((seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
return;
/* FIXME: Check that the data source type array isn't empty. */
@ -332,6 +333,7 @@ data_device_start_drag (struct wl_client *client,
drag_grab->generic.pointer = &seat->pointer;
drag_grab->drag_client = client;
drag_grab->seat = seat;
if (source_resource)
{
@ -375,7 +377,7 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
}
}
void
static void
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
MetaWaylandDataSource *source,
guint32 serial)
@ -389,7 +391,7 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
if (seat->selection_data_source)
{
seat->selection_data_source->cancel (seat->selection_data_source);
wl_data_source_send_cancelled (seat->selection_data_source->resource);
wl_list_remove (&seat->selection_data_source_listener.link);
seat->selection_data_source = NULL;
}
@ -449,47 +451,21 @@ static const struct wl_data_device_interface data_device_interface = {
static void
destroy_data_source (struct wl_resource *resource)
{
MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
char **p;
wl_array_for_each (p, &source->mime_types) free (*p);
wl_array_release (&source->mime_types);
}
static void
client_source_accept (MetaWaylandDataSource *source,
guint32 time, const char *mime_type)
{
wl_data_source_send_target (source->resource, mime_type);
}
static void
client_source_send (MetaWaylandDataSource *source,
const char *mime_type, int32_t fd)
{
wl_data_source_send_send (source->resource, mime_type, fd);
close (fd);
}
static void
client_source_cancel (MetaWaylandDataSource *source)
{
wl_data_source_send_cancelled (source->resource);
g_slice_free (MetaWaylandDataSource, source);
}
static void
create_data_source (struct wl_client *client,
struct wl_resource *resource, guint32 id)
{
MetaWaylandDataSource *source;
source = malloc (sizeof *source);
if (source == NULL)
{
wl_resource_post_no_memory (resource);
return;
}
MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource);
source->resource = wl_resource_create (client, &wl_data_source_interface,
MIN (META_WL_DATA_SOURCE_VERSION,
@ -497,10 +473,6 @@ create_data_source (struct wl_client *client,
wl_resource_set_implementation (source->resource, &data_source_interface,
source, destroy_data_source);
source->accept = client_source_accept;
source->send = client_source_send;
source->cancel = client_source_cancel;
wl_array_init (&source->mime_types);
}

View File

@ -33,10 +33,4 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat);
int
meta_wayland_data_device_manager_init (struct wl_display *display);
void
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
MetaWaylandDataSource *source,
uint32_t serial);
#endif /* __META_WAYLAND_DATA_DEVICE_H__ */

View File

@ -142,20 +142,6 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
xkb_keymap_unref (xkb_info->keymap);
xkb_info->keymap = keymap;
xkb_info->shift_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
xkb_info->caps_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
xkb_info->ctrl_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
xkb_info->alt_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
xkb_info->super_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
if (keymap_str == NULL)
{
@ -295,31 +281,6 @@ static const MetaWaylandKeyboardGrabInterface
default_grab_modifiers,
};
static gboolean
modal_key (MetaWaylandKeyboardGrab *grab,
uint32_t time,
uint32_t key,
uint32_t state)
{
/* FALSE means: let the event through to clutter */
return FALSE;
}
static void
modal_modifiers (MetaWaylandKeyboardGrab *grab,
uint32_t serial,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group)
{
}
static MetaWaylandKeyboardGrabInterface modal_grab = {
modal_key,
modal_modifiers,
};
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display)
@ -535,26 +496,13 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
/* If we're in a modal grab, the client is focused but doesn't see
modifiers or pressed keys (and fix that up when we exit the modal) */
if (keyboard->grab->interface == &modal_grab)
{
struct wl_array empty;
wl_array_init (&empty);
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, 0, 0, 0, 0);
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, &empty);
}
else
{
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
&keyboard->keys);
}
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
&keyboard->keys);
wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener);
keyboard->focus_serial = serial;
@ -588,85 +536,6 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
wl_array_release (&keyboard->keys);
}
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp);
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
if (keyboard->focus_surface)
{
/* Fake key release events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
0, 0, 0, 0);
for (k = keyboard->keys.data; k < end; k++)
{
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 0);
}
}
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
grab->interface = &modal_grab;
meta_wayland_keyboard_start_grab (keyboard, grab);
meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp);
return TRUE;
}
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
grab = keyboard->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
if (keyboard->focus_surface)
{
/* Fake key press events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
for (k = keyboard->keys.data; k < end; k++)
{
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 1);
}
}
meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
}
void
meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
const char *rules,

View File

@ -72,14 +72,6 @@ typedef struct
int keymap_fd;
size_t keymap_size;
char *keymap_area;
xkb_mod_index_t shift_mod;
xkb_mod_index_t caps_mod;
xkb_mod_index_t ctrl_mod;
xkb_mod_index_t alt_mod;
xkb_mod_index_t mod2_mod;
xkb_mod_index_t mod3_mod;
xkb_mod_index_t super_mod;
xkb_mod_index_t mod5_mod;
} MetaWaylandXkbInfo;
typedef struct
@ -150,13 +142,6 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
void
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);

View File

@ -398,61 +398,6 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
interface->focus (pointer->grab, pointer->current, NULL);
}
static void
modal_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
}
static void
modal_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
}
static void
modal_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
}
static MetaWaylandPointerGrabInterface modal_grab = {
modal_focus,
modal_motion,
modal_button
};
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
if (pointer->grab != &pointer->default_grab)
return FALSE;
meta_wayland_pointer_set_focus (pointer, NULL);
grab = g_slice_new0 (MetaWaylandPointerGrab);
grab->interface = &modal_grab;
meta_wayland_pointer_start_grab (pointer, grab);
return TRUE;
}
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
grab = pointer->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPointerGrab, grab);
}
typedef struct {
MetaWaylandPointerGrab generic;
@ -533,6 +478,12 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
g_slice_free (MetaWaylandPopup, popup);
}
{
MetaDisplay *display = meta_get_display ();
meta_display_end_grab_op (display,
meta_display_get_current_time_roundtrip (display));
}
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPopupGrab, popup_grab);
}
@ -572,6 +523,8 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
if (pointer->grab == &pointer->default_grab)
{
MetaWindow *window = surface->window;
grab = g_slice_new0 (MetaWaylandPopupGrab);
grab->generic.interface = &popup_grab_interface;
grab->generic.pointer = pointer;
@ -579,6 +532,19 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
wl_list_init (&grab->all_popups);
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
meta_display_begin_grab_op (window->display,
window->screen,
window,
META_GRAB_OP_WAYLAND_CLIENT,
FALSE, /* pointer_already_grabbed */
FALSE, /* frame_action */
1, /* button. XXX? */
0, /* modmask */
meta_display_get_current_time_roundtrip (window->display),
wl_fixed_to_int (pointer->grab_x),
wl_fixed_to_int (pointer->grab_y));
}
else
grab = (MetaWaylandPopupGrab*)pointer->grab;
@ -593,7 +559,6 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener);
wl_list_insert (&grab->all_popups, &popup->link);
return TRUE;
}

View File

@ -85,11 +85,6 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
gboolean
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *popup);

View File

@ -27,7 +27,7 @@
#include <cairo.h>
#include "window-private.h"
#include "meta-weston-launch.h"
#include "meta-login1.h"
#include <meta/meta-cursor-tracker.h>
#include "meta-wayland.h"
@ -85,7 +85,7 @@ struct _MetaWaylandCompositor
MetaXWaylandManager xwayland_manager;
MetaLauncher *launcher;
MetaLogin1 *login1;
MetaWaylandSeat *seat;
};

View File

@ -276,42 +276,53 @@ static void
handle_scroll_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
enum wl_pointer_axis axis;
wl_fixed_t value;
wl_fixed_t x_value = 0, y_value = 0;
notify_motion (seat, event);
if (!seat->pointer.focus_resource)
return;
if (clutter_event_is_pointer_emulated (event))
return;
switch (clutter_event_get_scroll_direction (event))
{
case CLUTTER_SCROLL_UP:
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
value = -DEFAULT_AXIS_STEP_DISTANCE;
y_value = -DEFAULT_AXIS_STEP_DISTANCE;
break;
case CLUTTER_SCROLL_DOWN:
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
value = DEFAULT_AXIS_STEP_DISTANCE;
y_value = DEFAULT_AXIS_STEP_DISTANCE;
break;
case CLUTTER_SCROLL_LEFT:
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
value = -DEFAULT_AXIS_STEP_DISTANCE;
x_value = -DEFAULT_AXIS_STEP_DISTANCE;
break;
case CLUTTER_SCROLL_RIGHT:
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
value = DEFAULT_AXIS_STEP_DISTANCE;
x_value = DEFAULT_AXIS_STEP_DISTANCE;
break;
case CLUTTER_SCROLL_SMOOTH:
{
double dx, dy;
clutter_event_get_scroll_delta (event, &dx, &dy);
x_value = wl_fixed_from_double (dx);
y_value = wl_fixed_from_double (dy);
}
break;
default:
return;
}
if (seat->pointer.focus_resource)
wl_pointer_send_axis (seat->pointer.focus_resource,
clutter_event_get_time (event),
axis,
value);
if (x_value)
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event),
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
if (y_value)
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event),
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
}
static int

View File

@ -43,12 +43,6 @@ struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
void (*accept) (MetaWaylandDataSource * source,
uint32_t serial, const char *mime_type);
void (*send) (MetaWaylandDataSource * source,
const char *mime_type, int32_t fd);
void (*cancel) (MetaWaylandDataSource * source);
};
struct _MetaWaylandSeat

View File

@ -336,22 +336,6 @@ toplevel_surface_commit (MetaWaylandSurface *surface,
if (pending->frame_extents_changed)
meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents);
if (pending->maximized.changed)
{
if (pending->maximized.value)
meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
else
meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
if (pending->fullscreen.changed)
{
if (pending->fullscreen.value)
meta_window_make_fullscreen (surface->window);
else
meta_window_unmake_fullscreen (surface->window);
}
}
static void
@ -377,8 +361,6 @@ double_buffered_state_init (MetaWaylandDoubleBufferedState *state)
wl_list_init (&state->frame_callback_list);
state->frame_extents_changed = FALSE;
state->maximized.changed = FALSE;
state->fullscreen.changed = FALSE;
}
static void
@ -767,6 +749,49 @@ xdg_surface_set_app_id (struct wl_client *client,
meta_window_set_wm_class (surface->window, app_id, app_id);
}
static MetaWindowType
window_type_from_surface_type (uint32_t surface_type)
{
switch (surface_type)
{
case XDG_SURFACE_SURFACE_TYPE_NORMAL:
return META_WINDOW_NORMAL;
case XDG_SURFACE_SURFACE_TYPE_MODAL_DIALOG:
return META_WINDOW_MODAL_DIALOG;
default:
g_warning ("Unknown surface type: %d\n", surface_type);
return META_WINDOW_NORMAL;
}
}
static void
xdg_surface_set_surface_type (struct wl_client *client,
struct wl_resource *resource,
uint32_t surface_type)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
meta_window_set_type (surface->window,
window_type_from_surface_type (surface_type));
}
static void
xdg_surface_show_window_menu (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
seat->pointer.focus_surface != surface)
return;
meta_window_show_menu (surface->window);
}
static gboolean
begin_grab_op_on_surface (MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
@ -861,44 +886,44 @@ xdg_surface_set_output (struct wl_client *client,
}
static void
xdg_surface_set_fullscreen (struct wl_client *client,
struct wl_resource *resource)
xdg_surface_request_change_state (struct wl_client *client,
struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.fullscreen.changed = TRUE;
surface->pending.fullscreen.value = TRUE;
surface->state_changed_serial = serial;
switch (state_type)
{
case XDG_SURFACE_STATE_MAXIMIZED:
if (value)
meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
else
meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
break;
case XDG_SURFACE_STATE_FULLSCREEN:
if (value)
meta_window_make_fullscreen (surface->window);
else
meta_window_unmake_fullscreen (surface->window);
}
}
static void
xdg_surface_unset_fullscreen (struct wl_client *client,
struct wl_resource *resource)
xdg_surface_ack_change_state (struct wl_client *client,
struct wl_resource *resource,
uint32_t state_type,
uint32_t value,
uint32_t serial)
{
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
surface->pending.fullscreen.changed = TRUE;
surface->pending.fullscreen.value = FALSE;
}
static void
xdg_surface_set_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.maximized.changed = TRUE;
surface->pending.maximized.value = TRUE;
}
static void
xdg_surface_unset_maximized (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
surface->pending.maximized.changed = TRUE;
surface->pending.maximized.value = FALSE;
/* Do nothing for now. In the future, we'd imagine that
* we'd ignore attaches when we have a state pending that
* we haven't had the client ACK'd, to prevent a race
* condition when we have an in-flight attach when the
* client gets the new state. */
}
static void
@ -916,13 +941,13 @@ static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
xdg_surface_set_margin,
xdg_surface_set_title,
xdg_surface_set_app_id,
xdg_surface_set_surface_type,
xdg_surface_show_window_menu,
xdg_surface_move,
xdg_surface_resize,
xdg_surface_set_output,
xdg_surface_set_fullscreen,
xdg_surface_unset_fullscreen,
xdg_surface_set_maximized,
xdg_surface_unset_maximized,
xdg_surface_request_change_state,
xdg_surface_ack_change_state,
xdg_surface_set_minimized,
};
@ -1011,8 +1036,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
surface->window->placed = TRUE;
meta_window_set_transient_for (surface->window, parent_surf->window);
surface->window->type = META_WINDOW_DROPDOWN_MENU;
meta_window_type_changed (surface->window);
meta_window_set_type (surface->window, META_WINDOW_DROPDOWN_MENU);
meta_wayland_pointer_start_popup_grab (&seat->pointer, surface);
}
@ -1174,9 +1198,9 @@ wl_shell_surface_set_state (MetaWaylandSurface *surface,
meta_window_unmake_fullscreen (surface->window);
if (state == SURFACE_STATE_MAXIMIZED)
meta_window_maximize (surface->window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL);
meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
else
meta_window_unmaximize (surface->window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL);
meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
}
static void
@ -1465,8 +1489,6 @@ subsurface_parent_surface_committed (MetaWaylandSurface *surface)
if (surface->sub.synchronous)
commit_double_buffered_state (surface, pending_surface_state);
double_buffered_state_reset (pending_surface_state);
}
static void
@ -1738,6 +1760,55 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
0, new_width, new_height);
}
static void
send_change_state (MetaWaylandSurface *surface,
uint32_t state_type,
uint32_t value)
{
if (surface->xdg_surface.resource)
{
uint32_t serial;
if (surface->state_changed_serial != 0)
{
serial = surface->state_changed_serial;
surface->state_changed_serial = 0;
}
else
{
struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource);
struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
}
xdg_surface_send_change_state (surface->xdg_surface.resource, state_type, value, serial);
}
}
void
meta_wayland_surface_send_maximized (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, TRUE);
}
void
meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, FALSE);
}
void
meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, TRUE);
}
void
meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface)
{
send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, FALSE);
}
void
meta_wayland_surface_activated (MetaWaylandSurface *surface)
{

View File

@ -41,12 +41,6 @@ struct _MetaWaylandBuffer
uint32_t ref_count;
};
typedef struct
{
guint changed : 1;
guint value : 1;
} MetaWaylandStateFlag;
typedef struct
{
/* wl_surface.attach */
@ -67,9 +61,6 @@ typedef struct
gboolean frame_extents_changed;
GtkBorder frame_extents;
MetaWaylandStateFlag fullscreen;
MetaWaylandStateFlag maximized;
} MetaWaylandDoubleBufferedState;
typedef struct
@ -107,6 +98,8 @@ struct _MetaWaylandSurface
GSList *pending_placement_ops;
} sub;
uint32_t state_changed_serial;
/* All the pending state, that wl_surface.commit will apply. */
MetaWaylandDoubleBufferedState pending;
};
@ -124,6 +117,10 @@ void meta_wayland_surface_window_unmanaged (MetaWaylandSurface *s
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width,
int height);
void meta_wayland_surface_send_maximized (MetaWaylandSurface *surface);
void meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface);
void meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface);
void meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface);
void meta_wayland_surface_activated (MetaWaylandSurface *surface);
void meta_wayland_surface_deactivated (MetaWaylandSurface *surface);

View File

@ -52,7 +52,7 @@
#include <meta/main.h>
#include "frame.h"
#include "meta-idle-monitor-private.h"
#include "meta-weston-launch.h"
#include "meta-login1.h"
#include "monitor-private.h"
static MetaWaylandCompositor _meta_wayland_compositor;
@ -643,25 +643,16 @@ meta_wayland_init (void)
clutter_wayland_set_compositor_display (compositor->wayland_display);
/* If we're running on bare metal, we're a display server,
* so start talking to logind. */
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
compositor->launcher = meta_launcher_new ();
compositor->login1 = meta_login1_new ();
#endif
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Failed to initialize Clutter");
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
int drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
meta_launcher_set_drm_fd (compositor->launcher, drm_fd, NULL);
}
#endif
meta_monitor_manager_initialize ();
monitors = meta_monitor_manager_get ();
g_signal_connect (monitors, "monitors-changed",
@ -713,8 +704,8 @@ meta_wayland_finalize (void)
meta_xwayland_stop (&compositor->xwayland_manager);
if (compositor->launcher)
meta_launcher_free (compositor->launcher);
if (compositor->login1)
meta_login1_free (compositor->login1);
}
gboolean
@ -722,13 +713,28 @@ meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
int vt,
GError **error)
{
if (compositor->launcher)
if (compositor->login1)
{
return meta_launcher_activate_vt (compositor->launcher, vt, error);
return meta_login1_activate_vt (compositor->login1, vt, error);
}
else
{
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
g_debug ("Ignoring VT switch keybinding, not running as display server");
return TRUE;
}
}
gboolean
meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
GError **error)
{
if (compositor->login1)
{
return meta_login1_activate_session (compositor->login1, error);
}
else
{
g_debug ("Ignoring activate_session, not running as display server");
return TRUE;
}
}

View File

@ -46,6 +46,8 @@ void meta_wayland_compositor_paint_finished (MetaWaylandComp
gboolean meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
int vt,
GError **error);
gboolean meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
GError **error);
#endif

View File

@ -1,401 +0,0 @@
/*
* Copyright (C) 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.
*/
#include <config.h>
#include <gio/gio.h>
#include <gio/gunixfdmessage.h>
#include <clutter/clutter.h>
#include <clutter/evdev/clutter-evdev.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "meta-weston-launch.h"
struct _MetaLauncher
{
GSocket *weston_launch;
gboolean vt_switched;
GMainContext *nested_context;
GMainLoop *nested_loop;
GSource *inner_source;
GSource *outer_source;
};
static void handle_request_vt_switch (MetaLauncher *self);
static gboolean
request_vt_switch_idle (gpointer user_data)
{
handle_request_vt_switch (user_data);
return FALSE;
}
static gboolean
send_message_to_wl (MetaLauncher *self,
void *message,
gsize size,
GSocketControlMessage *out_cmsg,
GSocketControlMessage **in_cmsg,
GError **error)
{
struct weston_launcher_reply reply;
GInputVector in_iov = { &reply, sizeof (reply) };
GOutputVector out_iov = { message, size };
GSocketControlMessage *out_all_cmsg[2];
GSocketControlMessage **in_all_cmsg;
int flags = 0;
int i;
out_all_cmsg[0] = out_cmsg;
out_all_cmsg[1] = NULL;
if (g_socket_send_message (self->weston_launch, NULL,
&out_iov, 1,
out_all_cmsg, -1,
flags, NULL, error) != (gssize)size)
return FALSE;
if (g_socket_receive_message (self->weston_launch, NULL,
&in_iov, 1,
&in_all_cmsg, NULL,
&flags, NULL, error) != sizeof (reply))
return FALSE;
while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
{
/* There were events queued */
g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
/* This can never happen, because the only time mutter-launch can queue
this event is after confirming a VT switch, and we don't make requests
during that time.
Note that getting this event would be really bad, because we would be
in the wrong loop/context.
*/
g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
switch (reply.header.opcode)
{
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
g_idle_add (request_vt_switch_idle, self);
break;
default:
g_assert_not_reached ();
}
if (g_socket_receive_message (self->weston_launch, NULL,
&in_iov, 1,
NULL, NULL,
&flags, NULL, error) != sizeof (reply))
return FALSE;
}
if (reply.ret != 0)
{
if (reply.ret == -1)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Got failure from weston-launch");
else
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
"Got failure from weston-launch: %s", strerror (-reply.ret));
for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
g_object_unref (in_all_cmsg[i]);
g_free (in_all_cmsg);
return FALSE;
}
if (in_all_cmsg && in_all_cmsg[0])
{
for (i = 1; in_all_cmsg[i]; i++)
g_object_unref (in_all_cmsg[i]);
*in_cmsg = in_all_cmsg[0];
}
g_free (in_all_cmsg);
return TRUE;
}
gboolean
meta_launcher_set_drm_fd (MetaLauncher *self,
int drm_fd,
GError **error)
{
struct weston_launcher_message message;
GSocketControlMessage *cmsg;
gboolean ok;
message.opcode = WESTON_LAUNCHER_DRM_SET_FD;
cmsg = g_unix_fd_message_new ();
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
drm_fd, error) == FALSE)
{
g_object_unref (cmsg);
return FALSE;
}
ok = send_message_to_wl (self, &message, sizeof message, cmsg, NULL, error);
g_object_unref (cmsg);
return ok;
}
int
meta_launcher_open_input_device (MetaLauncher *self,
const char *name,
int flags,
GError **error)
{
struct weston_launcher_open *message;
GSocketControlMessage *cmsg;
gboolean ok;
gsize size;
int *fds, n_fd;
int ret;
size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
message = g_malloc (size);
message->header.opcode = WESTON_LAUNCHER_OPEN;
message->flags = flags;
strcpy (message->path, name);
message->path[strlen(name)] = 0;
ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
if (ok)
{
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
g_assert (n_fd == 1);
ret = fds[0];
g_free (fds);
g_object_unref (cmsg);
}
else
ret = -1;
g_free (message);
return ret;
}
static void
meta_launcher_enter (MetaLauncher *launcher)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_kms_display_queue_modes_reset (cogl_display);
clutter_evdev_reclaim_devices ();
}
static void
meta_launcher_leave (MetaLauncher *launcher)
{
clutter_evdev_release_devices ();
}
static int
on_evdev_device_open (const char *path,
int flags,
gpointer user_data,
GError **error)
{
MetaLauncher *launcher = user_data;
return meta_launcher_open_input_device (launcher, path, flags, error);
}
static void
handle_vt_enter (MetaLauncher *launcher)
{
g_assert (launcher->vt_switched);
g_main_loop_quit (launcher->nested_loop);
}
static void
handle_request_vt_switch (MetaLauncher *launcher)
{
struct weston_launcher_message message;
GError *error;
gboolean ok;
meta_launcher_leave (launcher);
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
error = NULL;
ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
if (!ok) {
g_warning ("Failed to acknowledge VT switch: %s", error->message);
g_error_free (error);
return;
}
g_assert (!launcher->vt_switched);
launcher->vt_switched = TRUE;
/* We can't do anything at this point, because we don't
have input devices and we don't have the DRM master,
so let's run a nested busy loop until the VT is reentered */
g_main_loop_run (launcher->nested_loop);
g_assert (launcher->vt_switched);
launcher->vt_switched = FALSE;
meta_launcher_enter (launcher);
}
static gboolean
on_socket_readable (GSocket *socket,
GIOCondition condition,
gpointer user_data)
{
MetaLauncher *launcher = user_data;
struct weston_launcher_event event;
gssize read;
GError *error;
if ((condition & G_IO_IN) == 0)
return TRUE;
error = NULL;
read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
if (read < (gssize)sizeof(event))
{
g_warning ("Error reading from weston-launcher socket: %s", error->message);
g_error_free (error);
return TRUE;
}
switch (event.header.opcode)
{
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
handle_request_vt_switch (launcher);
break;
case WESTON_LAUNCHER_SERVER_VT_ENTER:
handle_vt_enter (launcher);
break;
}
return TRUE;
}
static int
env_get_fd (const char *env)
{
const char *value;
value = g_getenv (env);
if (value == NULL)
return -1;
else
return g_ascii_strtoll (value, NULL, 10);
}
MetaLauncher *
meta_launcher_new (void)
{
MetaLauncher *self = g_slice_new0 (MetaLauncher);
int launch_fd;
launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
if (launch_fd < 0)
g_error ("Invalid mutter-launch socket");
self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
clutter_evdev_set_open_callback (on_evdev_device_open, self);
self->nested_context = g_main_context_new ();
self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
g_source_attach (self->outer_source, NULL);
g_source_unref (self->outer_source);
self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
g_source_attach (self->inner_source, self->nested_context);
g_source_unref (self->inner_source);
return self;
}
void
meta_launcher_free (MetaLauncher *launcher)
{
g_source_destroy (launcher->outer_source);
g_source_destroy (launcher->inner_source);
g_main_loop_unref (launcher->nested_loop);
g_main_context_unref (launcher->nested_context);
g_object_unref (launcher->weston_launch);
g_slice_free (MetaLauncher, launcher);
}
gboolean
meta_launcher_activate_vt (MetaLauncher *launcher,
int vt,
GError **error)
{
struct weston_launcher_activate_vt message;
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
message.vt = vt;
return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 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.
*/
#ifndef META_WESTON_LAUNCH_H
#define META_WESTON_LAUNCH_H
#include <glib-object.h>
#include "weston-launch.h"
typedef struct _MetaLauncher MetaLauncher;
MetaLauncher *meta_launcher_new (void);
void meta_launcher_free (MetaLauncher *self);
gboolean meta_launcher_activate_vt (MetaLauncher *self,
int number,
GError **error);
gboolean meta_launcher_set_drm_fd (MetaLauncher *self,
int drm_fd,
GError **error);
gboolean meta_launcher_set_master (MetaLauncher *self,
gboolean master,
GError **error);
int meta_launcher_open_input_device (MetaLauncher *self,
const char *name,
int flags,
GError **error);
#endif

View File

@ -47,6 +47,13 @@ xserver_set_window_id (struct wl_client *client,
if (!window)
return;
/* If the window has an existing surface, like if we're
* undecorating or decorating the window, then we need
* to detach the window from its old surface.
*/
if (window->surface)
window->surface->window = NULL;
meta_wayland_surface_make_toplevel (surface);
surface->window = window;

View File

@ -1,788 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <error.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <termios.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <linux/kd.h>
#include <pwd.h>
#include <grp.h>
#include <xf86drm.h>
#include <systemd/sd-login.h>
#include "weston-launch.h"
#define MAX_ARGV_SIZE 256
#define DRM_MAJOR 226
enum vt_state {
VT_HAS_VT,
VT_PENDING_CONFIRM,
VT_NOT_HAVE_VT,
};
struct weston_launch {
int tty;
int ttynr;
int sock[2];
struct passwd *pw;
int signalfd;
pid_t child;
int verbose;
struct termios terminal_attributes;
int kb_mode;
enum vt_state vt_state;
int drm_fd;
};
union cmsg_data { unsigned char b[4]; int fd; };
static void quit (struct weston_launch *wl, int status);
static int
weston_launch_allowed(struct weston_launch *wl)
{
char *session, *seat;
int err;
if (getuid() == 0)
return 1;
err = sd_pid_get_session(getpid(), &session);
if (err == 0 && session) {
if (sd_session_is_active(session) &&
sd_session_get_seat(session, &seat) == 0) {
free(seat);
free(session);
return 1;
}
free(session);
}
return 0;
}
static int
setup_launcher_socket(struct weston_launch *wl)
{
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
error(1, errno, "socketpair failed");
fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
return 0;
}
static int
setup_signals(struct weston_launch *wl)
{
int ret;
sigset_t mask;
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
ret = sigaction(SIGCHLD, &sa, NULL);
assert(ret == 0);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction(SIGHUP, &sa, NULL);
ret = sigemptyset(&mask);
assert(ret == 0);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(ret == 0);
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (wl->signalfd < 0)
return -errno;
return 0;
}
static void
setenv_fd(const char *env, int fd)
{
char buf[32];
snprintf(buf, sizeof buf, "%d", fd);
setenv(env, buf, 1);
}
static int
handle_setdrmfd(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
struct cmsghdr *cmsg;
union cmsg_data *data;
struct stat s;
reply.header.opcode = WESTON_LAUNCHER_DRM_SET_FD;
reply.ret = -1;
if (wl->drm_fd != -1) {
error(0, 0, "DRM FD already set");
reply.ret = -EINVAL;
goto out;
}
cmsg = CMSG_FIRSTHDR(msg);
if (!cmsg ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
error(0, 0, "invalid control message");
reply.ret = -EINVAL;
goto out;
}
data = (union cmsg_data *) CMSG_DATA(cmsg);
if (data->fd < 0) {
error(0, 0, "missing drm fd in socket request");
reply.ret = -EINVAL;
goto out;
}
if (fstat(data->fd, &s) < 0) {
reply.ret = -errno;
goto out;
}
if (major(s.st_rdev) != DRM_MAJOR) {
fprintf(stderr, "FD is not for DRM\n");
reply.ret = -EPERM;
goto out;
}
wl->drm_fd = data->fd;
reply.ret = drmSetMaster(data->fd);
if (reply.ret < 0)
reply.ret = -errno;
if (wl->verbose)
fprintf(stderr, "mutter-launch: set drm FD, ret: %d, fd: %d\n",
reply.ret, data->fd);
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
reply.ret = -1;
if (wl->vt_state != VT_PENDING_CONFIRM) {
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
goto out;
}
if (wl->drm_fd != -1) {
int ret;
ret = drmDropMaster(wl->drm_fd);
if (ret < 0) {
fprintf(stderr, "failed to drop DRM master: %m\n");
} else if (wl->verbose) {
fprintf(stderr, "dropped DRM master for VT switch\n");
}
}
wl->vt_state = VT_NOT_HAVE_VT;
ioctl(wl->tty, VT_RELDISP, 1);
if (wl->verbose)
fprintf(stderr, "mutter-launcher: confirmed VT switch\n");
reply.ret = 0;
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
struct weston_launcher_activate_vt *message;
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
reply.ret = -1;
if (len != sizeof(*message)) {
error(0, 0, "missing value in activate_vt request");
goto out;
}
message = msg->msg_iov->iov_base;
reply.ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
if (reply.ret < 0)
reply.ret = -errno;
if (wl->verbose)
fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
int fd = -1;
char control[CMSG_SPACE(sizeof(fd))];
struct cmsghdr *cmsg;
struct stat s;
struct msghdr nmsg;
struct iovec iov;
struct weston_launcher_open *message;
union cmsg_data *data;
reply.header.opcode = WESTON_LAUNCHER_OPEN;
reply.ret = -1;
message = msg->msg_iov->iov_base;
if ((size_t)len < sizeof(*message))
goto err0;
/* Ensure path is null-terminated */
((char *) message)[len-1] = '\0';
if (stat(message->path, &s) < 0) {
reply.ret = -errno;
goto err0;
}
fd = open(message->path, message->flags);
if (fd < 0) {
fprintf(stderr, "Error opening device %s: %m\n",
message->path);
reply.ret = -errno;
goto err0;
}
if (major(s.st_rdev) != INPUT_MAJOR) {
close(fd);
fd = -1;
fprintf(stderr, "Device %s is not an input device\n",
message->path);
reply.ret = -EPERM;
goto err0;
}
err0:
memset(&nmsg, 0, sizeof nmsg);
nmsg.msg_iov = &iov;
nmsg.msg_iovlen = 1;
if (fd != -1) {
nmsg.msg_control = control;
nmsg.msg_controllen = sizeof control;
cmsg = CMSG_FIRSTHDR(&nmsg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
data = (union cmsg_data *) CMSG_DATA(cmsg);
data->fd = fd;
nmsg.msg_controllen = cmsg->cmsg_len;
reply.ret = 0;
}
iov.iov_base = &reply;
iov.iov_len = sizeof reply;
if (wl->verbose)
fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n",
message->path, reply.ret, fd);
do {
len = sendmsg(wl->sock[0], &nmsg, 0);
} while (len < 0 && errno == EINTR);
close(fd);
if (len < 0)
return -1;
return 0;
}
static int
handle_socket_msg(struct weston_launch *wl)
{
char control[CMSG_SPACE(sizeof(int))];
char buf[BUFSIZ];
struct msghdr msg;
struct iovec iov;
int ret = -1;
ssize_t len;
struct weston_launcher_message *message;
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf;
iov.iov_len = sizeof buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof control;
do {
len = recvmsg(wl->sock[0], &msg, 0);
} while (len < 0 && errno == EINTR);
if (len < 1)
return -1;
message = (void *) buf;
switch (message->opcode) {
case WESTON_LAUNCHER_OPEN:
ret = handle_open(wl, &msg, len);
break;
case WESTON_LAUNCHER_DRM_SET_FD:
ret = handle_setdrmfd(wl, &msg, len);
break;
case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
ret = handle_confirm_vt_switch(wl, &msg, len);
break;
case WESTON_LAUNCHER_ACTIVATE_VT:
ret = handle_activate_vt(wl, &msg, len);
break;
}
return ret;
}
static void
tty_reset(struct weston_launch *wl)
{
struct vt_mode mode = { 0 };
if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
fprintf(stderr, "failed to restore keyboard mode: %m\n");
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
fprintf(stderr, "could not restore terminal to canonical mode\n");
mode.mode = VT_AUTO;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
fprintf(stderr, "could not reset vt handling\n");
}
static void
quit(struct weston_launch *wl, int status)
{
if (wl->child > 0)
kill(wl->child, SIGKILL);
close(wl->signalfd);
close(wl->sock[0]);
if (wl->drm_fd > 0)
close(wl->drm_fd);
tty_reset(wl);
exit(status);
}
static int
handle_vt_switch(struct weston_launch *wl)
{
struct weston_launcher_event message;
ssize_t len;
if (wl->vt_state == VT_HAS_VT) {
wl->vt_state = VT_PENDING_CONFIRM;
message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
wl->vt_state = VT_HAS_VT;
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
if (wl->drm_fd != -1) {
int ret;
ret = drmSetMaster(wl->drm_fd);
if (ret < 0) {
fprintf(stderr, "failed to become DRM master: %m\n");
/* This is very, very bad, and the compositor will crash soon,
but oh well... */
} else if (wl->verbose) {
fprintf(stderr, "became DRM master after VT switch\n");
}
}
message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
} else
return -1;
message.detail = 0;
do {
len = send(wl->sock[0], &message, sizeof(message), 0);
} while (len < 0 && errno == EINTR);
return 0;
}
static int
handle_signal(struct weston_launch *wl)
{
struct signalfd_siginfo sig;
int pid, status, ret;
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
error(0, errno, "reading signalfd failed");
return -1;
}
switch (sig.ssi_signo) {
case SIGCHLD:
pid = waitpid(-1, &status, 0);
if (pid == wl->child) {
wl->child = 0;
if (WIFEXITED(status))
ret = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
/*
* If weston dies because of signal N, we
* return 10+N. This is distinct from
* weston-launch dying because of a signal
* (128+N).
*/
ret = 10 + WTERMSIG(status);
else
ret = 0;
quit(wl, ret);
}
break;
case SIGTERM:
case SIGINT:
if (wl->child)
kill(wl->child, sig.ssi_signo);
break;
case SIGUSR1:
return handle_vt_switch(wl);
default:
return -1;
}
return 0;
}
static int
setup_tty(struct weston_launch *wl)
{
struct stat buf;
struct termios raw_attributes;
struct vt_mode mode = { 0 };
char *session, *tty;
char path[PATH_MAX];
int ok;
ok = sd_pid_get_session(getpid(), &session);
if (ok < 0)
error(1, -ok, "could not determine current session");
ok = sd_session_get_tty(session, &tty);
if (ok == 0) {
/* Old systemd only has the tty name in the TTY
field, new one has the full char device path.
Check what we have and fix it properly.
*/
if (strncmp(tty, "/dev", strlen("/dev")) == 0) {
strncpy(path, tty, PATH_MAX);
path[PATH_MAX-1] = 0;
} else {
snprintf(path, PATH_MAX, "/dev/%s", tty);
}
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
free(tty);
#ifdef HAVE_SD_SESSION_GET_VT
} else if (ok == -ENOENT) {
unsigned vt;
/* Negative errnos are cool, right?
So cool that we can't distinguish "session not found"
from "key does not exist in the session file"!
Let's assume the latter, as we got the value
from sd_pid_get_session()...
*/
ok = sd_session_get_vt(session, &vt);
if (ok < 0)
error(1, -ok, "could not determine current TTY");
snprintf(path, PATH_MAX, "/dev/tty%u", vt);
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
free(tty);
#endif
} else
error(1, -ok, "could not determine current TTY");
if (wl->tty < 0)
error(1, errno, "failed to open tty");
if (fstat(wl->tty, &buf) < 0)
error(1, errno, "stat %s failed", path);
if (major(buf.st_rdev) != TTY_MAJOR)
error(1, 0, "invalid tty device: %s", path);
wl->ttynr = minor(buf.st_rdev);
if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
error(1, errno, "could not get terminal attributes");
/* Ignore control characters and disable echo */
raw_attributes = wl->terminal_attributes;
cfmakeraw(&raw_attributes);
/* Fix up line endings to be normal (cfmakeraw hoses them) */
raw_attributes.c_oflag |= OPOST | OCRNL;
/* Don't generate ttou signals */
raw_attributes.c_oflag &= ~TOSTOP;
if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
error(1, errno, "could not put terminal into raw mode");
ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
if (ok < 0) {
ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
if (ok < 0)
error(1, errno, "failed to set keyboard mode on tty");
}
ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
if (ok < 0)
error(1, errno, "failed to set KD_GRAPHICS mode on tty");
wl->vt_state = VT_HAS_VT;
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR1;
ok = ioctl(wl->tty, VT_SETMODE, &mode);
if (ok < 0)
error(1, errno, "failed to take control of vt handling");
return 0;
}
static void
drop_privileges(struct weston_launch *wl)
{
if (setgid(wl->pw->pw_gid) < 0 ||
#ifdef HAVE_INITGROUPS
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
#endif
setuid(wl->pw->pw_uid) < 0)
error(1, errno, "dropping privileges failed");
}
static void
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
{
char command[PATH_MAX];
char *child_argv[MAX_ARGV_SIZE];
sigset_t mask;
int i;
if (wl->verbose)
printf("weston-launch: spawned weston with pid: %d\n", getpid());
drop_privileges(wl);
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
setenv("LD_LIBRARY_PATH", LIBDIR, 1);
unsetenv("DISPLAY");
/* Do not give our signal mask to the new process. */
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
child_argv[0] = wl->pw->pw_shell;
child_argv[1] = "-l";
child_argv[2] = "-c";
child_argv[3] = command;
for (i = 0; i < argc; ++i)
child_argv[4 + i] = argv[i];
child_argv[4 + i] = NULL;
execv(child_argv[0], child_argv);
error(1, errno, "exec failed");
}
static void
help(const char *name)
{
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
fprintf(stderr, " -u, --user Start session as specified username\n");
fprintf(stderr, " -v, --verbose Be verbose\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
int
main(int argc, char *argv[])
{
struct weston_launch wl;
int i, c;
struct option opts[] = {
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
memset(&wl, 0, sizeof wl);
wl.drm_fd = -1;
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
switch (c) {
case 'v':
wl.verbose = 1;
break;
case 'h':
help("mutter-launch");
exit(EXIT_FAILURE);
}
}
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
error(1, E2BIG, "Too many arguments to pass to weston");
if (optind >= argc)
error(1, 0, "Expected program argument");
wl.pw = getpwuid(getuid());
if (wl.pw == NULL)
error(1, errno, "failed to get username");
if (!weston_launch_allowed(&wl))
error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
if (setup_tty(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_launcher_socket(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_signals(&wl) < 0)
exit(EXIT_FAILURE);
wl.child = fork();
if (wl.child == -1) {
error(1, errno, "fork failed");
exit(EXIT_FAILURE);
}
if (wl.child == 0)
launch_compositor(&wl, argc - optind, argv + optind);
close(wl.sock[1]);
while (1) {
struct pollfd fds[2];
int n;
fds[0].fd = wl.sock[0];
fds[0].events = POLLIN;
fds[1].fd = wl.signalfd;
fds[1].events = POLLIN;
n = poll(fds, 2, -1);
if (n < 0)
error(0, errno, "poll failed");
if (fds[0].revents & POLLIN)
handle_socket_msg(&wl);
if (fds[1].revents)
handle_signal(&wl);
}
return 0;
}

View File

@ -1,69 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
* 2013 Red Hat, Inc.
*
* 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.
*/
#ifndef _WESTON_LAUNCH_H_
#define _WESTON_LAUNCH_H_
enum weston_launcher_message_type {
WESTON_LAUNCHER_REQUEST,
WESTON_LAUNCHER_EVENT,
};
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_DRM_SET_FD = (2 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_ACTIVATE_VT = (3 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (4 << 1 | WESTON_LAUNCHER_REQUEST),
};
enum weston_launcher_server_opcode {
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT),
};
struct weston_launcher_message {
int opcode;
};
struct weston_launcher_open {
struct weston_launcher_message header;
int flags;
char path[0];
};
struct weston_launcher_activate_vt {
struct weston_launcher_message header;
int vt;
};
struct weston_launcher_reply {
struct weston_launcher_message header;
int ret;
};
struct weston_launcher_event {
struct weston_launcher_message header;
int detail; /* unused, but makes sure replies and events are serialized the same */
};
#endif