Compare commits
58 Commits
wip/resize
...
wip/compos
Author | SHA1 | Date | |
---|---|---|---|
27bec68c67 | |||
8ce4407a9f | |||
cebb6b2779 | |||
d7771a30ee | |||
10fb5e527f | |||
7116786ad3 | |||
d294fa45d1 | |||
e278d65f05 | |||
42408c1c38 | |||
9ac086a613 | |||
de06346766 | |||
c22d6ad69c | |||
64be6cf4f0 | |||
a9d8107c3d | |||
a5d2c51392 | |||
d1ea17e6a4 | |||
b37ad66e9d | |||
c1f15348a5 | |||
857561baed | |||
a44cc9ef47 | |||
d47b7ba038 | |||
f21312e2fd | |||
394af33607 | |||
7314cdac94 | |||
81025e37ea | |||
1bb9f1e333 | |||
b11c75c1c9 | |||
757b626aee | |||
fb3df5243f | |||
e34792d9f0 | |||
f397c32192 | |||
f79314d7b5 | |||
55c61259d8 | |||
5298cf0a3a | |||
f1dc1a0cbc | |||
2cf80bc647 | |||
40c15f6e2a | |||
a8849621c9 | |||
49c0be11d6 | |||
9df8e831be | |||
84c6b2a3fa | |||
06cd669ccb | |||
81eb7d9537 | |||
dd8d8e436d | |||
d6b6b363ad | |||
254e2e993c | |||
c595a9c29f | |||
dfc7f7222b | |||
ef278eb547 | |||
38e26e5cc3 | |||
9773a879c3 | |||
abd2abcde6 | |||
a8f4651c72 | |||
54df7934ea | |||
9052efb0d9 | |||
b346f98eb0 | |||
365af53797 | |||
bee59ec0e1 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
14
NEWS
@ -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]
|
||||
|
10
configure.ac
10
configure.ac
@ -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],
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 < $< > $@
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
143
src/core/core.c
143
src/core/core.c
@ -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*
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
44
src/org.freedesktop.login1.xml
Normal file
44
src/org.freedesktop.login1.xml
Normal 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>
|
@ -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 ||
|
||||
|
518
src/ui/menu.c
518
src/ui/menu.c
@ -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);
|
||||
}
|
@ -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
|
@ -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));
|
||||
}
|
@ -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__ */
|
43
src/ui/ui.c
43
src/ui/ui.c
@ -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,
|
||||
|
15
src/ui/ui.h
15
src/ui/ui.h
@ -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
441
src/wayland/meta-login1.c
Normal 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
35
src/wayland/meta-login1.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
Reference in New Issue
Block a user