Compare commits

..

36 Commits

Author SHA1 Message Date
Florian Müllner
8d51a9db5b Bump version to 3.17.2
Update NEWS.
2015-05-27 10:28:44 +02:00
Rui Matos
b39c00f344 window: Fix meta_window_set_alive() not working if first ping fails
window->is_alive isn't initialized explicitly so it defaults to FALSE
meaning that if the first ping fails we'd short circuit and not show
the delete dialog as we should.

We could initialize the variable to TRUE but in fact we don't even
need the variable at all since our dialog management is enough to
manage all the state we need, i.e. we're only interested in knowing
whether we're already displaying a delete dialog.

This does change our behavior here since previously we wouldn't
display the dialog again if the next ping failed after the dialog is
dismissed but this was arguably a bug too since in that case there
wouldn't be a way to kill the window after waiting for a while and the
window kept being unresponsive.

https://bugzilla.gnome.org/show_bug.cgi?id=749711
2015-05-22 16:53:42 +02:00
Rui Matos
83ce71c3bf backend-native: Reset idle time on lid open events
This makes gnome-settings-daemon turn on the backlight and
gnome-shell's screen shield animate.

Note that on X sessions, gnome-settings-daemon uses the same upower
property to force an innocuous key event into the X server so that the
idle time gets reset since Xorg doesn't do this itself on lid events.

https://bugzilla.gnome.org/show_bug.cgi?id=749076
2015-05-22 16:53:42 +02:00
Rui Matos
f9d869a3dd backend-native: Remove unused variable
https://bugzilla.gnome.org/show_bug.cgi?id=749076
2015-05-22 16:43:44 +02:00
Carlos Garnacho
0b0ce4193f xwayland: Ensure we've got an owner when setting the X selection owner
Otherwise we may end up claiming the X selection when there's no wayland
selection owner.
2015-05-18 20:59:07 +02:00
Carlos Garnacho
719d8bd0c7 xwayland: remove unused struct field 2015-05-18 20:58:57 +02:00
Carlos Garnacho
4fc1811c15 wayland: Add X11/wayland selection interoperation
This piece of code hooks in both wl_data_device and the relevant X
selection events, an X11 Window is set up so it can act as the clipboard
owner when any wayland client owns the selection, reacting to
SelectionRequest events, and returning the data from the wayland client
FD to any X11 requestor through X properties.

In the opposite direction, SelectionNotify messages are received,
which results in the property contents being converted then written
into the wayland requestor's FD.

This code also takes care of the handling incremental transfers through
the INCR property type, reading/writing data chunk by chunk.

https://bugzilla.gnome.org/show_bug.cgi?id=738312
2015-05-15 17:43:53 +02:00
Carlos Garnacho
4b5f5abb4f wayland: refactor MetaWaylandDataSource
Expose it partly (in internal headers anyway), and pass a vtable for the
data source functions, the wayland vfuncs just delegate operations on the
wl_data_source resource. The resource has been also made optional, although
it'll be present on all data sources from wayland clients.

The ownership/lifetime of the DnD data source has also changed a bit,
belonging now to the MetaWaylandDataDevice like the selection one does, as
we can't guarantee how long it will be needed after the grab is finished,
it will be left inert and replaced the next time DnD is started at worst.

This allows the creation of custom/proxy data sources, which will turn out
useful for X11 selection interoperation.

https://bugzilla.gnome.org/show_bug.cgi?id=738312
2015-05-15 17:43:46 +02:00
Jasper St. Pierre
95ad52ba58 xrandr: Fix copy/paste typo in connector type heuristics 2015-05-12 18:17:16 -07:00
Rui Matos
dac30a222e input-settings-x11: Honor default value for click method setting
Now that xf86-input-libinput exposes default values we can honor the
gsettings value.

https://bugzilla.gnome.org/show_bug.cgi?id=746290
2015-05-08 17:44:59 +02:00
Rui Matos
7d1b593fbd input-settings-x11: Factor out a get_property() helper
We'll need to get the value of some properties. Fail if the number of
items returned is less than we expect and warn if it exceeds it so
that we can easily find out if items are added to a property later and
fix it.
2015-05-08 17:44:57 +02:00
Carlos Garnacho
d6a7559750 wayland: Fix c&p typo in wl_listener notify callback
The corresponding wl_notify field for destroy_data_device_icon()
is drag_grab->drag_icon_listener, otherwise we're fetching a pointer
that's slightly off where we want.
2015-05-01 18:50:06 +02:00
Florian Müllner
cff5ef0ec2 Bump version to 3.17.1
Update NEWS.
2015-04-30 17:35:43 +02:00
Rui Matos
d478d8f143 core/events: Invalidate monitor cache when we're a wayland compositor
When running as an X11 compositor we do this for every event we see on
the X event stream. As a wayland compositor we don't go through that
code path but since we see all events we can easily do this on motion
events.

In fact, we don't even need this caching when we're a wayland
compositor since we can always find where the pointer is without a
round trip but we're sharing the current monitor logic with the X
path so let's keep it as is for now.

https://bugzilla.gnome.org/show_bug.cgi?id=748478
2015-04-30 14:01:23 +02:00
Rui Matos
7eca43cec9 monitor-manager-kms: Avoid a couple of potential crashes
The drm API can return NULL and we could end up using uninitialized
memory if the driver private struct isn't cleared.
2015-04-28 18:00:45 +02:00
Rui Matos
9060190555 monitor-manager-kms: Read crtc props after determining the crtc ID
Otherwise we can't read the properties.
2015-04-28 18:00:44 +02:00
Jasper St. Pierre
0de3869656 core: Remove unused function 2015-04-27 18:14:15 -07:00
Jasper St. Pierre
9f13033f15 window-wayland.[ch] => meta-window-wayland.[ch]
This finishes off the meta- prefix for wayland/.
2015-04-27 18:09:16 -07:00
Jasper St. Pierre
48bf807430 monitor-manager-kms: Add support for underscan 2015-04-27 17:58:38 -07:00
Jasper St. Pierre
c68e43a97f monitor-manager-xrandr: Set the underscan border properties, too 2015-04-27 17:23:56 -07:00
Tomeu Vizoso
cc53d48fa8 MonitorManager: Add support for overscan compensation
Some DRM drivers have added a consistent set of properties that
allow compensating for the overscan that some TVs do, without the
user being able to disable.
2015-04-27 17:17:15 -07:00
Jasper St. Pierre
ca6e799b97 Move atomnames.h to x11/
This should *not* be part of the public API.
2015-04-27 16:36:56 -07:00
Jasper St. Pierre
0f8e387dc0 monitor-config: Allow loading from a system file 2015-04-27 16:31:11 -07:00
Rui Matos
d62c595e51 events: Ignore some event types when reseting idle time
These events don't result from actual hardware events so we shouldn't
use them to reset idle time.

https://bugzilla.gnome.org/show_bug.cgi?id=748541
2015-04-27 19:44:58 +02:00
Jasper St. Pierre
dd3cf94744 Properly implement wl_shell_surface's poor surface commit semantics 2015-04-25 11:19:25 -07:00
Ray Strode
eb56e0a3d7 xwayland: plug some leaks in stop function
This commit makes sure the lockfile and display
name are freed in meta_xwayland_stop.

https://bugzilla.gnome.org/show_bug.cgi?id=748380
2015-04-23 13:51:11 -04:00
Ray Strode
8937c32cd5 xwayland: rename lockfile to lock_file
The missing underscore is inconsistent with the
coding style of the surrounding code.

https://bugzilla.gnome.org/show_bug.cgi?id=748380
2015-04-23 13:51:11 -04:00
Ray Strode
a8a5da768a xwayland: don't unlink lock file twice in stop function
The stop function currently manually constructs the lock
filename from the display number and also calls unlink
on the same, already known lock filename from the manager
struct.

This commit gets rid fo the manual construction in favor
of the saved lock filename.

https://bugzilla.gnome.org/show_bug.cgi?id=748380
2015-04-23 13:51:11 -04:00
Ray Strode
33bfcf56ce xwayland: free lockfile in start function on error
Right now we just leak the lockfile.

https://bugzilla.gnome.org/show_bug.cgi?id=748380
2015-04-23 13:51:11 -04:00
Ray Strode
40cccb58a5 xwayland: use out label for cleanup in start function
The start function has a few exit paths that need to
perform clean up of the lock file.

This commit consolidates those exit paths at the end
using an out label and gotos.

https://bugzilla.gnome.org/show_bug.cgi?id=748380
2015-04-23 13:51:11 -04:00
Jonas Ådahl
eb6c70137b wayland: Add and implement set/unset_modal for the gtk_surface interface
Add set_modal ond unset_modal to the gtk_surface interface. When a
surface is modal, the compositor can treat it differently from non-modal
dialogs, for example attach it to the parent window if any. There is
currently no changes to input device focus; it is up to the client to
ignore events to the parent surface that is wanted.

This bumps the gtk_shell version to 2.

https://bugzilla.gnome.org/show_bug.cgi?id=745720
2015-04-23 16:02:37 +08:00
Jonas Ådahl
df3b412a25 wayland: Kill clients who try to bind an incompatible gtk_shell version
gtk_shell is not backward compatible, and clients binding to it should
check whether the advertised version is the same as the client supports.

https://bugzilla.gnome.org/show_bug.cgi?id=745720
2015-04-23 16:02:37 +08:00
Jonas Ådahl
cfba0a5dfc wayland: Sync protocol/gtk-shell.xml from GTK+
Had added a new capability enum value.

https://bugzilla.gnome.org/show_bug.cgi?id=745720
2015-04-23 16:02:37 +08:00
Ondrej Holy
3561b46fc6 backends/x11: Fix set_scroll_button
There is copy&pasted code in set_scroll_button, which is apparently
wrong, because it is trying to set scroll method instead of the scroll
button...

https://bugzilla.gnome.org/show_bug.cgi?id=747967
2015-04-17 10:50:33 +02:00
Carlos Garnacho
8dfb88b669 backend: Apply the right settings to the right input devices
Since 8769b3d55, the checks performed on which update_* function was
called for each device got quite more lax, leading to failed asserts
on code that assumed the previous behavior.

Change update_[mouse|touchpad|trackball]_* to bail out early if the
device received has not the right type, and remove the asserts.

https://bugzilla.gnome.org/show_bug.cgi?id=747886
2015-04-15 13:33:12 +02:00
Florian Müllner
2e3086e2aa screen: Add public method to get neighboring monitor
The existing private get_monitor_neighbor() function returns a
MetaMonitorInfo, which is private as well. Add a public wrapper
that returns a monitor index instead, as we do for other public
monitor-related methods.

https://bugzilla.gnome.org/show_bug.cgi?id=633994
2015-04-14 23:13:19 +02:00
33 changed files with 1634 additions and 186 deletions

23
NEWS
View File

@@ -1,19 +1,24 @@
3.16.2 3.17.2
====== ======
* Fix scroll button setting [Ondrej; #747967]
* Don't reset idle time for non-hardware events [Rui; #748541]
* Honor default value for click method setting [Rui; #746290] * Honor default value for click method setting [Rui; #746290]
* Misc. bug fixes [Rui; #748478] * Add X11/wayland clipboard interoperation [Carlos; #738312]
* Misc. bug fixes [Rui; #749076, #749711]
Contributors: Contributors:
Carlos Garnacho, Ondrej Holy, Rui Matos Carlos Garnacho, Rui Matos, Jasper St. Pierre
3.16.1.1 3.17.1
======== ======
* Prevent a crash when switching VTs or adding input devices [Carlos; #747886] * Add public method to get neighboring monitor [Florian; #633994]
* Apply the right settings to the right input devices [Carlos; #747886]
* Fix scroll button setting [Ondrej; #747967]
* Add support for modal hint on wayland [Jonas; #745720]
* Don't reset idle time for non-hardware events [Rui; #748541]
* Misc. bug fixes [Ray, Rui; #748380, #748478]
Contributors: Contributors:
Carlos Garnacho Jonas Ådahl, Carlos Garnacho, Ondrej Holy, Rui Matos, Florian Müllner,
Jasper St. Pierre, Ray Strode, Tomeu Vizoso
3.16.1 3.16.1
====== ======

View File

@@ -1,7 +1,7 @@
AC_PREREQ(2.62) AC_PREREQ(2.62)
m4_define([mutter_major_version], [3]) m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [16]) m4_define([mutter_minor_version], [17])
m4_define([mutter_micro_version], [2]) m4_define([mutter_micro_version], [2])
m4_define([mutter_version], m4_define([mutter_version],

View File

@@ -210,10 +210,9 @@ libmutter_la_SOURCES = \
meta/theme.h \ meta/theme.h \
ui/theme-private.h \ ui/theme-private.h \
ui/ui.c \ ui/ui.c \
x11/iconcache.c \
x11/iconcache.h \
x11/async-getprop.c \ x11/async-getprop.c \
x11/async-getprop.h \ x11/async-getprop.h \
x11/atomnames.h \
x11/events.c \ x11/events.c \
x11/events.h \ x11/events.h \
x11/group-private.h \ x11/group-private.h \
@@ -221,6 +220,8 @@ libmutter_la_SOURCES = \
x11/group-props.h \ x11/group-props.h \
x11/group.c \ x11/group.c \
meta/group.h \ meta/group.h \
x11/iconcache.c \
x11/iconcache.h \
x11/session.c \ x11/session.c \
x11/session.h \ x11/session.h \
x11/window-props.c \ x11/window-props.c \
@@ -242,6 +243,7 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-private.h \ wayland/meta-wayland-private.h \
wayland/meta-xwayland.c \ wayland/meta-xwayland.c \
wayland/meta-xwayland.h \ wayland/meta-xwayland.h \
wayland/meta-xwayland-selection.c \
wayland/meta-xwayland-private.h \ wayland/meta-xwayland-private.h \
wayland/meta-wayland-buffer.c \ wayland/meta-wayland-buffer.c \
wayland/meta-wayland-buffer.h \ wayland/meta-wayland-buffer.h \
@@ -265,8 +267,8 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-versions.h \ wayland/meta-wayland-versions.h \
wayland/meta-wayland-outputs.c \ wayland/meta-wayland-outputs.c \
wayland/meta-wayland-outputs.h \ wayland/meta-wayland-outputs.h \
wayland/window-wayland.c \ wayland/meta-window-wayland.c \
wayland/window-wayland.h \ wayland/meta-window-wayland.h \
$(NULL) $(NULL)
endif endif
@@ -338,16 +340,10 @@ libmutterinclude_base_headers = \
$(libmutterinclude_headers) \ $(libmutterinclude_headers) \
$(libmutterinclude_built_headers) $(libmutterinclude_built_headers)
# Excluded from scanning for introspection but installed
# atomnames.h: macros cause problems for scanning process
libmutterinclude_extra_headers = \
meta/atomnames.h
libmutterincludedir = $(includedir)/mutter/meta libmutterincludedir = $(includedir)/mutter/meta
libmutterinclude_HEADERS = \ libmutterinclude_HEADERS = \
$(libmutterinclude_headers) \ $(libmutterinclude_headers)
$(libmutterinclude_extra_headers)
nodist_libmutterinclude_HEADERS = \ nodist_libmutterinclude_HEADERS = \
$(libmutterinclude_built_headers) $(libmutterinclude_built_headers)

View File

@@ -65,6 +65,7 @@ typedef struct {
gboolean is_primary; gboolean is_primary;
gboolean is_presentation; gboolean is_presentation;
gboolean is_underscanning;
} MetaOutputConfig; } MetaOutputConfig;
typedef struct { typedef struct {
@@ -82,7 +83,8 @@ struct _MetaMonitorConfig {
gboolean current_is_for_laptop_lid; gboolean current_is_for_laptop_lid;
MetaConfiguration *previous; MetaConfiguration *previous;
GFile *file; GFile *user_file;
GFile *system_file;
GCancellable *save_cancellable; GCancellable *save_cancellable;
UpClient *up_client; UpClient *up_client;
@@ -238,6 +240,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
{ {
const char *filename; const char *filename;
char *path; char *path;
const char * const *system_dirs;
self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref); self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
@@ -246,9 +249,17 @@ meta_monitor_config_init (MetaMonitorConfig *self)
filename = "monitors.xml"; filename = "monitors.xml";
path = g_build_filename (g_get_user_config_dir (), filename, NULL); path = g_build_filename (g_get_user_config_dir (), filename, NULL);
self->file = g_file_new_for_path (path); self->user_file = g_file_new_for_path (path);
g_free (path); g_free (path);
for (system_dirs = g_get_system_config_dirs (); !self->system_file && *system_dirs; system_dirs++)
{
path = g_build_filename (*system_dirs, filename, NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
self->system_file = g_file_new_for_path (path);
g_free (path);
}
self->up_client = up_client_new (); self->up_client = up_client_new ();
self->lid_is_closed = up_client_get_lid_is_closed (self->up_client); self->lid_is_closed = up_client_get_lid_is_closed (self->up_client);
@@ -393,7 +404,8 @@ handle_start_element (GMarkupParseContext *context,
strcmp (element_name, "reflect_x") == 0 || strcmp (element_name, "reflect_x") == 0 ||
strcmp (element_name, "reflect_y") == 0 || strcmp (element_name, "reflect_y") == 0 ||
strcmp (element_name, "primary") == 0 || strcmp (element_name, "primary") == 0 ||
strcmp (element_name, "presentation") == 0) && parser->unknown_count == 0) strcmp (element_name, "presentation") == 0 ||
strcmp (element_name, "underscanning") == 0) && parser->unknown_count == 0)
{ {
parser->state = STATE_OUTPUT_FIELD; parser->state = STATE_OUTPUT_FIELD;
@@ -700,6 +712,8 @@ handle_text (GMarkupParseContext *context,
parser->output.is_primary = read_bool (text, text_len, error); parser->output.is_primary = read_bool (text, text_len, error);
else if (strcmp (parser->output_field, "presentation") == 0) else if (strcmp (parser->output_field, "presentation") == 0)
parser->output.is_presentation = read_bool (text, text_len, error); parser->output.is_presentation = read_bool (text, text_len, error);
else if (strcmp (parser->output_field, "underscanning") == 0)
parser->output.is_underscanning = read_bool (text, text_len, error);
else else
g_assert_not_reached (); g_assert_not_reached ();
return; return;
@@ -717,8 +731,8 @@ static const GMarkupParser config_parser = {
.text = handle_text, .text = handle_text,
}; };
static void static gboolean
meta_monitor_config_load (MetaMonitorConfig *self) load_config_file (MetaMonitorConfig *self, GFile *file)
{ {
char *contents; char *contents;
gsize size; gsize size;
@@ -736,14 +750,12 @@ meta_monitor_config_load (MetaMonitorConfig *self)
*/ */
error = NULL; error = NULL;
ok = g_file_load_contents (self->file, NULL, &contents, &size, NULL, &error); ok = g_file_load_contents (file, NULL, &contents, &size, NULL, &error);
if (!ok) if (!ok)
{ {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
meta_warning ("Failed to load stored monitor configuration: %s\n", error->message);
g_error_free (error); g_error_free (error);
return; return FALSE;
} }
memset (&parser, 0, sizeof (ConfigParser)); memset (&parser, 0, sizeof (ConfigParser));
@@ -772,6 +784,17 @@ meta_monitor_config_load (MetaMonitorConfig *self)
g_markup_parse_context_free (context); g_markup_parse_context_free (context);
g_free (contents); g_free (contents);
return ok;
}
static void
meta_monitor_config_load (MetaMonitorConfig *self)
{
if (self->user_file && load_config_file (self, self->user_file))
return;
if (self->system_file && load_config_file (self, self->system_file))
return;
} }
MetaMonitorConfig * MetaMonitorConfig *
@@ -1408,6 +1431,7 @@ init_config_from_output (MetaOutputConfig *config,
config->transform = output->crtc->transform; config->transform = output->crtc->transform;
config->is_primary = output->is_primary; config->is_primary = output->is_primary;
config->is_presentation = output->is_presentation; config->is_presentation = output->is_presentation;
config->is_underscanning = output->is_underscanning;
} }
void void
@@ -1598,7 +1622,8 @@ meta_monitor_config_save (MetaMonitorConfig *self)
" <reflect_x>%s</reflect_x>\n" " <reflect_x>%s</reflect_x>\n"
" <reflect_y>no</reflect_y>\n" " <reflect_y>no</reflect_y>\n"
" <primary>%s</primary>\n" " <primary>%s</primary>\n"
" <presentation>%s</presentation>\n", " <presentation>%s</presentation>\n"
" <underscanning>%s</underscanning>\n",
output->rect.width, output->rect.width,
output->rect.height, output->rect.height,
refresh_rate, refresh_rate,
@@ -1607,7 +1632,8 @@ meta_monitor_config_save (MetaMonitorConfig *self)
rotation_map[output->transform & 0x3], rotation_map[output->transform & 0x3],
output->transform >= META_MONITOR_TRANSFORM_FLIPPED ? "yes" : "no", output->transform >= META_MONITOR_TRANSFORM_FLIPPED ? "yes" : "no",
output->is_primary ? "yes" : "no", output->is_primary ? "yes" : "no",
output->is_presentation ? "yes" : "no"); output->is_presentation ? "yes" : "no",
output->is_underscanning ? "yes" : "no");
} }
g_string_append (buffer, " </output>\n"); g_string_append (buffer, " </output>\n");
@@ -1622,7 +1648,7 @@ meta_monitor_config_save (MetaMonitorConfig *self)
closure->config = g_object_ref (self); closure->config = g_object_ref (self);
closure->buffer = buffer; closure->buffer = buffer;
g_file_replace_contents_async (self->file, g_file_replace_contents_async (self->user_file,
buffer->str, buffer->len, buffer->str, buffer->len,
NULL, /* etag */ NULL, /* etag */
TRUE, TRUE,
@@ -1941,6 +1967,7 @@ meta_monitor_config_assign_crtcs (MetaConfiguration *config,
&config->keys[i]); &config->keys[i]);
output_info->is_primary = output_config->is_primary; output_info->is_primary = output_config->is_primary;
output_info->is_presentation = output_config->is_presentation; output_info->is_presentation = output_config->is_presentation;
output_info->is_underscanning = output_config->is_underscanning;
g_ptr_array_add (outputs, output_info); g_ptr_array_add (outputs, output_info);
} }

View File

@@ -132,6 +132,7 @@ struct _MetaOutput
*/ */
gboolean is_primary; gboolean is_primary;
gboolean is_presentation; gboolean is_presentation;
gboolean is_underscanning;
gpointer driver_private; gpointer driver_private;
GDestroyNotify driver_notify; GDestroyNotify driver_notify;
@@ -159,6 +160,9 @@ struct _MetaCRTC
gboolean is_dirty; gboolean is_dirty;
MetaCursorReference *cursor; MetaCursorReference *cursor;
gpointer driver_private;
GDestroyNotify driver_notify;
}; };
struct _MetaMonitorMode struct _MetaMonitorMode
@@ -230,6 +234,7 @@ struct _MetaOutputInfo {
MetaOutput *output; MetaOutput *output;
gboolean is_primary; gboolean is_primary;
gboolean is_presentation; gboolean is_presentation;
gboolean is_underscanning;
}; };
#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ()) #define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ())

View File

@@ -264,6 +264,21 @@ meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
g_free (old_modes); g_free (old_modes);
} }
static void
meta_monitor_manager_free_crtc_array (MetaCRTC *old_crtcs,
int n_old_crtcs)
{
int i;
for (i = 0; i < n_old_crtcs; i++)
{
if (old_crtcs[i].driver_notify)
old_crtcs[i].driver_notify (&old_crtcs[i]);
}
g_free (old_crtcs);
}
static void static void
meta_monitor_manager_finalize (GObject *object) meta_monitor_manager_finalize (GObject *object)
{ {
@@ -271,8 +286,8 @@ meta_monitor_manager_finalize (GObject *object)
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs); meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes); meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
meta_monitor_manager_free_crtc_array (manager->crtcs, manager->n_crtcs);
g_free (manager->monitor_infos); g_free (manager->monitor_infos);
g_free (manager->crtcs);
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
} }
@@ -520,6 +535,8 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_new_boolean (output->is_presentation)); g_variant_new_boolean (output->is_presentation));
g_variant_builder_add (&properties, "{sv}", "connector-type", g_variant_builder_add (&properties, "{sv}", "connector-type",
g_variant_new_string (get_connector_type_name (output->connector_type))); g_variant_new_string (get_connector_type_name (output->connector_type)));
g_variant_builder_add (&properties, "{sv}", "underscanning",
g_variant_new_boolean (output->is_underscanning));
edid_file = manager_class->get_edid_file (manager, output); edid_file = manager_class->get_edid_file (manager, output);
if (edid_file) if (edid_file)
@@ -808,7 +825,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_index, &properties)) while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_index, &properties))
{ {
MetaOutputInfo *output_info; MetaOutputInfo *output_info;
gboolean primary, presentation; gboolean primary, presentation, underscanning;
if (output_index >= manager->n_outputs) if (output_index >= manager->n_outputs)
{ {
@@ -827,6 +844,9 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
if (g_variant_lookup (properties, "presentation", "b", &presentation)) if (g_variant_lookup (properties, "presentation", "b", &presentation))
output_info->is_presentation = presentation; output_info->is_presentation = presentation;
if (g_variant_lookup (properties, "underscanning", "b", &underscanning))
output_info->is_underscanning = underscanning;
g_ptr_array_add (output_infos, output_info); g_ptr_array_add (output_infos, output_info);
} }
@@ -1194,23 +1214,24 @@ meta_monitor_manager_read_current_config (MetaMonitorManager *manager)
MetaOutput *old_outputs; MetaOutput *old_outputs;
MetaCRTC *old_crtcs; MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes; MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes; unsigned int n_old_outputs, n_old_crtcs, n_old_modes;
/* Some implementations of read_current use the existing information /* Some implementations of read_current use the existing information
* we have available, so don't free the old configuration until after * we have available, so don't free the old configuration until after
* read_current finishes. */ * read_current finishes. */
old_outputs = manager->outputs; old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs; n_old_outputs = manager->n_outputs;
old_crtcs = manager->crtcs;
n_old_crtcs = manager->n_crtcs;
old_modes = manager->modes; old_modes = manager->modes;
n_old_modes = manager->n_modes; n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
manager->serial++; manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager); META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes); meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs); meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs);
} }
void void

View File

@@ -29,6 +29,7 @@
#include <meta/main.h> #include <meta/main.h>
#include <clutter/evdev/clutter-evdev.h> #include <clutter/evdev/clutter-evdev.h>
#include <libupower-glib/upower.h>
#include "meta-barrier-native.h" #include "meta-barrier-native.h"
#include "meta-idle-monitor-native.h" #include "meta-idle-monitor-native.h"
@@ -39,10 +40,8 @@
struct _MetaBackendNativePrivate struct _MetaBackendNativePrivate
{ {
MetaLauncher *launcher; MetaLauncher *launcher;
MetaBarrierManagerNative *barrier_manager; MetaBarrierManagerNative *barrier_manager;
UpClient *up_client;
GSettings *keyboard_settings;
}; };
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate; typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
@@ -56,9 +55,22 @@ meta_backend_native_finalize (GObject *object)
meta_launcher_free (priv->launcher); meta_launcher_free (priv->launcher);
g_object_unref (priv->up_client);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object); G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
} }
static void
lid_is_closed_changed_cb (UpClient *client,
GParamSpec *pspec,
gpointer user_data)
{
if (up_client_get_lid_is_closed (client))
return;
meta_idle_monitor_native_reset_idletime (meta_idle_monitor_get_core ());
}
static void static void
constrain_to_barriers (ClutterInputDevice *device, constrain_to_barriers (ClutterInputDevice *device,
guint32 time, guint32 time,
@@ -270,6 +282,10 @@ meta_backend_native_init (MetaBackendNative *native)
priv->launcher = meta_launcher_new (); priv->launcher = meta_launcher_new ();
priv->barrier_manager = meta_barrier_manager_native_new (); priv->barrier_manager = meta_barrier_manager_native_new ();
priv->up_client = up_client_new ();
g_signal_connect (priv->up_client, "notify::lid-is-closed",
G_CALLBACK (lid_is_closed_changed_cb), NULL);
} }
gboolean gboolean

View File

@@ -57,6 +57,12 @@ typedef struct {
uint32_t edid_blob_id; uint32_t edid_blob_id;
} MetaOutputKms; } MetaOutputKms;
typedef struct {
uint32_t underscan_prop_id;
uint32_t underscan_hborder_prop_id;
uint32_t underscan_vborder_prop_id;
} MetaCRTCKms;
struct _MetaMonitorManagerKms struct _MetaMonitorManagerKms
{ {
MetaMonitorManager parent_instance; MetaMonitorManager parent_instance;
@@ -137,6 +143,12 @@ meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
g_slice_free (drmModeModeInfo, output->driver_private); g_slice_free (drmModeModeInfo, output->driver_private);
} }
static void
meta_crtc_destroy_notify (MetaCRTC *crtc)
{
g_free (crtc->driver_private);
}
static gboolean static gboolean
drm_mode_equal (gconstpointer one, drm_mode_equal (gconstpointer one,
gconstpointer two) gconstpointer two)
@@ -181,29 +193,57 @@ drm_mode_hash (gconstpointer ptr)
} }
static void static void
find_properties (MetaMonitorManagerKms *manager_kms, find_connector_properties (MetaMonitorManagerKms *manager_kms,
MetaOutputKms *output_kms) MetaOutputKms *output_kms)
{ {
drmModePropertyPtr prop;
int i; int i;
for (i = 0; i < output_kms->connector->count_props; i++) for (i = 0; i < output_kms->connector->count_props; i++)
{ {
prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]); drmModePropertyPtr prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]);
if (!prop) if (!prop)
continue; continue;
if ((prop->flags & DRM_MODE_PROP_ENUM) && if ((prop->flags & DRM_MODE_PROP_ENUM) && strcmp (prop->name, "DPMS") == 0)
strcmp(prop->name, "DPMS") == 0)
output_kms->dpms_prop_id = prop->prop_id; output_kms->dpms_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_BLOB) && else if ((prop->flags & DRM_MODE_PROP_BLOB) && strcmp (prop->name, "EDID") == 0)
strcmp (prop->name, "EDID") == 0)
output_kms->edid_blob_id = output_kms->connector->prop_values[i]; output_kms->edid_blob_id = output_kms->connector->prop_values[i];
drmModeFreeProperty (prop); drmModeFreeProperty (prop);
} }
} }
static void
find_crtc_properties (MetaMonitorManagerKms *manager_kms,
MetaCRTC *meta_crtc)
{
MetaCRTCKms *crtc_kms;
drmModeObjectPropertiesPtr props;
size_t i;
crtc_kms = meta_crtc->driver_private;
props = drmModeObjectGetProperties (manager_kms->fd, meta_crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!props)
return;
for (i = 0; i < props->count_props; i++)
{
drmModePropertyPtr prop = drmModeGetProperty (manager_kms->fd, props->props[i]);
if (!prop)
continue;
if ((prop->flags & DRM_MODE_PROP_ENUM) && strcmp (prop->name, "underscan") == 0)
crtc_kms->underscan_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) && strcmp (prop->name, "underscan hborder") == 0)
crtc_kms->underscan_hborder_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) && strcmp (prop->name, "underscan vborder") == 0)
crtc_kms->underscan_vborder_prop_id = prop->prop_id;
drmModeFreeProperty (prop);
}
}
static GBytes * static GBytes *
read_output_edid (MetaMonitorManagerKms *manager_kms, read_output_edid (MetaMonitorManagerKms *manager_kms,
MetaOutput *output) MetaOutput *output)
@@ -442,6 +482,10 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height); height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
} }
meta_crtc->driver_private = g_new0 (MetaCRTCKms, 1);
meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
find_crtc_properties (manager_kms, meta_crtc);
drmModeFreeCrtc (crtc); drmModeFreeCrtc (crtc);
} }
@@ -567,7 +611,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
meta_output->is_presentation = FALSE; meta_output->is_presentation = FALSE;
} }
find_properties (manager_kms, output_kms); find_connector_properties (manager_kms, output_kms);
edid = read_output_edid (manager_kms, meta_output); edid = read_output_edid (manager_kms, meta_output);
meta_output_parse_edid (meta_output, edid); meta_output_parse_edid (meta_output, edid);
@@ -723,8 +767,9 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
if (output_kms->dpms_prop_id != 0) if (output_kms->dpms_prop_id != 0)
{ {
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->winsys_id, int ok = drmModeObjectSetProperty (manager_kms->fd, meta_output->winsys_id,
output_kms->dpms_prop_id, state); DRM_MODE_OBJECT_CONNECTOR,
output_kms->dpms_prop_id, state);
if (ok < 0) if (ok < 0)
meta_warning ("Failed to set power save mode for output %s: %s\n", meta_warning ("Failed to set power save mode for output %s: %s\n",
@@ -748,6 +793,48 @@ crtc_free (CoglKmsCrtc *crtc)
g_slice_free (CoglKmsCrtc, crtc); g_slice_free (CoglKmsCrtc, crtc);
} }
static void
set_underscan (MetaMonitorManagerKms *manager_kms,
MetaOutput *output)
{
if (!output->crtc)
return;
MetaCRTC *crtc = output->crtc;
MetaCRTCKms *crtc_kms = crtc->driver_private;
if (!crtc_kms->underscan_prop_id)
return;
if (output->is_underscanning)
{
drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id,
DRM_MODE_OBJECT_CRTC,
crtc_kms->underscan_prop_id, (uint64_t) 1);
if (crtc_kms->underscan_hborder_prop_id)
{
uint64_t value = crtc->current_mode->width * 0.05;
drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id,
DRM_MODE_OBJECT_CRTC,
crtc_kms->underscan_hborder_prop_id, value);
}
if (crtc_kms->underscan_vborder_prop_id)
{
uint64_t value = crtc->current_mode->height * 0.05;
drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id,
DRM_MODE_OBJECT_CRTC,
crtc_kms->underscan_vborder_prop_id, value);
}
}
else
{
drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id,
DRM_MODE_OBJECT_CRTC,
crtc_kms->underscan_prop_id, (uint64_t) 0);
}
}
static void static void
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
MetaCRTCInfo **crtcs, MetaCRTCInfo **crtcs,
@@ -755,6 +842,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
MetaOutputInfo **outputs, MetaOutputInfo **outputs,
unsigned int n_outputs) unsigned int n_outputs)
{ {
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
ClutterBackend *backend; ClutterBackend *backend;
CoglContext *cogl_context; CoglContext *cogl_context;
CoglDisplay *cogl_display; CoglDisplay *cogl_display;
@@ -900,6 +988,9 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
output->is_primary = output_info->is_primary; output->is_primary = output_info->is_primary;
output->is_presentation = output_info->is_presentation; output->is_presentation = output_info->is_presentation;
output->is_underscanning = output_info->is_underscanning;
set_underscan (manager_kms, output);
} }
/* Disable outputs not mentioned in the list */ /* Disable outputs not mentioned in the list */

View File

@@ -225,6 +225,38 @@ output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
return output_get_boolean_property (manager_xrandr, output, "_MUTTER_PRESENTATION_OUTPUT"); return output_get_boolean_property (manager_xrandr, output, "_MUTTER_PRESENTATION_OUTPUT");
} }
static gboolean
output_get_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gboolean value = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
char *str;
atom = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
atom,
0, G_MAXLONG, False, False, XA_ATOM,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_ATOM || actual_format != 32 ||
nitems < 1)
goto out;
str = XGetAtomName (manager_xrandr->xdisplay, *(Atom *)buffer);
value = !strcmp(str, "on");
XFree (str);
out:
XFree (buffer);
return value;
}
static int static int
normalize_backlight (MetaOutput *output, normalize_backlight (MetaOutput *output,
int hw_value) int hw_value)
@@ -506,7 +538,7 @@ output_get_connector_type_from_name (MetaMonitorManagerXrandr *manager_xrandr,
if (g_str_has_prefix (name, "Virtual")) if (g_str_has_prefix (name, "Virtual"))
return META_CONNECTOR_TYPE_VIRTUAL; return META_CONNECTOR_TYPE_VIRTUAL;
if (g_str_has_prefix (name, "Composite")) if (g_str_has_prefix (name, "Composite"))
return META_CONNECTOR_TYPE_VGA; return META_CONNECTOR_TYPE_Composite;
if (g_str_has_prefix (name, "S-video")) if (g_str_has_prefix (name, "S-video"))
return META_CONNECTOR_TYPE_SVIDEO; return META_CONNECTOR_TYPE_SVIDEO;
if (g_str_has_prefix (name, "TV")) if (g_str_has_prefix (name, "TV"))
@@ -756,6 +788,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
meta_output->is_primary = ((XID)meta_output->winsys_id == primary_output); meta_output->is_primary = ((XID)meta_output->winsys_id == primary_output);
meta_output->is_presentation = output_get_presentation_xrandr (manager_xrandr, meta_output); meta_output->is_presentation = output_get_presentation_xrandr (manager_xrandr, meta_output);
meta_output->is_underscanning = output_get_underscanning_xrandr (manager_xrandr, meta_output);
output_get_backlight_limits_xrandr (manager_xrandr, meta_output); output_get_backlight_limits_xrandr (manager_xrandr, meta_output);
if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0)) if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0))
@@ -876,6 +909,49 @@ output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
(unsigned char*) &value, 1); (unsigned char*) &value, 1);
} }
static void
output_set_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output,
gboolean underscanning)
{
Atom prop, valueatom;
const char *value;
prop = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
value = underscanning ? "on" : "off";
valueatom = XInternAtom (manager_xrandr->xdisplay, value, False);
XRRChangeOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
prop,
XA_ATOM, 32, PropModeReplace,
(unsigned char*) &valueatom, 1);
/* Configure the border at the same time. Currently, we use a
* 5% of the width/height of the mode. In the future, we should
* make the border configurable. */
if (underscanning)
{
uint32_t border_value;
prop = XInternAtom (manager_xrandr->xdisplay, "underscan hborder", False);
border_value = output->crtc->current_mode->width * 0.05;
XRRChangeOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
prop,
XA_INTEGER, 32, PropModeReplace,
(unsigned char *) &border_value, 1);
prop = XInternAtom (manager_xrandr->xdisplay, "underscan vborder", False);
border_value = output->crtc->current_mode->height * 0.05;
XRRChangeOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
prop,
XA_INTEGER, 32, PropModeReplace,
(unsigned char *) &border_value, 1);
}
}
static void static void
meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager, meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
MetaCRTCInfo **crtcs, MetaCRTCInfo **crtcs,
@@ -1071,8 +1147,13 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
output_info->output, output_info->output,
output_info->is_presentation); output_info->is_presentation);
output_set_underscanning_xrandr (manager_xrandr,
output_info->output,
output_info->is_underscanning);
output->is_primary = output_info->is_primary; output->is_primary = output_info->is_primary;
output->is_presentation = output_info->is_presentation; output->is_presentation = output_info->is_presentation;
output->is_underscanning = output_info->is_underscanning;
} }
/* Disable outputs not mentioned in the list */ /* Disable outputs not mentioned in the list */

View File

@@ -217,19 +217,6 @@ meta_core_show_window_menu_for_rect (Display *xdisplay,
meta_window_show_menu_for_rect (window, menu, rect); meta_window_show_menu_for_rect (window, menu, rect);
} }
const char*
meta_core_get_workspace_name_with_index (Display *xdisplay,
Window xroot,
int index)
{
MetaDisplay *display;
MetaWorkspace *workspace;
display = meta_display_for_x_display (xdisplay);
workspace = meta_screen_get_workspace_by_index (display->screen, index);
return workspace ? meta_workspace_get_name (workspace) : NULL;
}
gboolean gboolean
meta_core_begin_grab_op (Display *xdisplay, meta_core_begin_grab_op (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,

View File

@@ -47,9 +47,6 @@ void meta_core_change_workspace (Display *xdisplay,
int meta_core_get_frame_workspace (Display *xdisplay, int meta_core_get_frame_workspace (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);
const char* meta_core_get_workspace_name_with_index (Display *xdisplay,
Window xroot,
int index);
void meta_core_show_window_menu (Display *xdisplay, void meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,

View File

@@ -160,12 +160,7 @@ void
meta_window_set_alive (MetaWindow *window, meta_window_set_alive (MetaWindow *window,
gboolean is_alive) gboolean is_alive)
{ {
if (window->is_alive == is_alive) if (is_alive)
return;
window->is_alive = is_alive;
if (window->is_alive)
kill_delete_dialog (window); kill_delete_dialog (window);
else else
show_delete_dialog (window, CurrentTime); show_delete_dialog (window, CurrentTime);

View File

@@ -121,7 +121,7 @@ struct _MetaDisplay
* class is constructed. * class is constructed.
*/ */
#define item(x) Atom atom_##x; #define item(x) Atom atom_##x;
#include <meta/atomnames.h> #include <x11/atomnames.h>
#undef item #undef item
/* The window and serial of the most recent FocusIn event. */ /* The window and serial of the most recent FocusIn event. */

View File

@@ -549,7 +549,7 @@ meta_display_open (void)
/* A list of all atom names, so that we can intern them in one go. */ /* A list of all atom names, so that we can intern them in one go. */
char *atom_names[] = { char *atom_names[] = {
#define item(x) #x, #define item(x) #x,
#include <meta/atomnames.h> #include <x11/atomnames.h>
#undef item #undef item
}; };
Atom atoms[G_N_ELEMENTS(atom_names)]; Atom atoms[G_N_ELEMENTS(atom_names)];
@@ -610,7 +610,7 @@ meta_display_open (void)
{ {
int i = 0; int i = 0;
#define item(x) display->atom_##x = atoms[i++]; #define item(x) display->atom_##x = atoms[i++];
#include <meta/atomnames.h> #include <x11/atomnames.h>
#undef item #undef item
} }

View File

@@ -41,14 +41,6 @@
typedef void (* MetaScreenWindowFunc) (MetaWindow *window, typedef void (* MetaScreenWindowFunc) (MetaWindow *window,
gpointer user_data); gpointer user_data);
typedef enum
{
META_SCREEN_UP,
META_SCREEN_DOWN,
META_SCREEN_LEFT,
META_SCREEN_RIGHT
} MetaScreenDirection;
#define META_WIREFRAME_XOR_LINE_WIDTH 2 #define META_WIREFRAME_XOR_LINE_WIDTH 2
struct _MetaScreen struct _MetaScreen

View File

@@ -294,7 +294,7 @@ set_supported_hint (MetaScreen *screen)
Atom atoms[] = { Atom atoms[] = {
#define EWMH_ATOMS_ONLY #define EWMH_ATOMS_ONLY
#define item(x) screen->display->atom_##x, #define item(x) screen->display->atom_##x,
#include <meta/atomnames.h> #include <x11/atomnames.h>
#undef item #undef item
#undef EWMH_ATOMS_ONLY #undef EWMH_ATOMS_ONLY
@@ -1490,6 +1490,16 @@ meta_screen_get_monitor_neighbor (MetaScreen *screen,
return NULL; return NULL;
} }
int
meta_screen_get_monitor_neighbor_index (MetaScreen *screen,
int which_monitor,
MetaScreenDirection direction)
{
const MetaMonitorInfo *monitor;
monitor = meta_screen_get_monitor_neighbor (screen, which_monitor, direction);
return monitor ? monitor->number : -1;
}
void void
meta_screen_get_natural_monitor_list (MetaScreen *screen, meta_screen_get_natural_monitor_list (MetaScreen *screen,
int** monitors_list, int** monitors_list,

View File

@@ -434,7 +434,6 @@ struct _MetaWindow
/* Managed by delete.c */ /* Managed by delete.c */
int dialog_pid; int dialog_pid;
guint is_alive : 1;
/* maintained by group.c */ /* maintained by group.c */
MetaGroup *group; MetaGroup *group;

View File

@@ -57,7 +57,7 @@
#include "x11/xprops.h" #include "x11/xprops.h"
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND
#include "wayland/window-wayland.h" #include "wayland/meta-window-wayland.h"
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
#endif #endif

View File

@@ -66,6 +66,21 @@ int meta_screen_get_active_workspace_index (MetaScreen *screen);
MetaWorkspace * meta_screen_get_active_workspace (MetaScreen *screen); MetaWorkspace * meta_screen_get_active_workspace (MetaScreen *screen);
/**
* MetaScreenDirection:
* @META_SCREEN_UP: up
* @META_SCREEN_DOWN: down
* @META_SCREEN_LEFT: left
* @META_SCREEN_RIGHT: right
*/
typedef enum
{
META_SCREEN_UP,
META_SCREEN_DOWN,
META_SCREEN_LEFT,
META_SCREEN_RIGHT
} MetaScreenDirection;
int meta_screen_get_n_monitors (MetaScreen *screen); int meta_screen_get_n_monitors (MetaScreen *screen);
int meta_screen_get_primary_monitor (MetaScreen *screen); int meta_screen_get_primary_monitor (MetaScreen *screen);
int meta_screen_get_current_monitor (MetaScreen *screen); int meta_screen_get_current_monitor (MetaScreen *screen);
@@ -82,6 +97,10 @@ gboolean meta_screen_get_monitor_in_fullscreen (MetaScreen *screen,
int meta_screen_get_monitor_index_for_rect (MetaScreen *screen, int meta_screen_get_monitor_index_for_rect (MetaScreen *screen,
MetaRectangle *rect); MetaRectangle *rect);
int meta_screen_get_monitor_neighbor_index (MetaScreen *screen,
int which_monitor,
MetaScreenDirection dir);
void meta_screen_focus_default_window (MetaScreen *screen, void meta_screen_focus_default_window (MetaScreen *screen,
guint32 timestamp); guint32 timestamp);

View File

@@ -43,13 +43,6 @@ typedef struct
struct wl_listener source_destroy_listener; struct wl_listener source_destroy_listener;
} MetaWaylandDataOffer; } MetaWaylandDataOffer;
struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
gboolean has_target;
};
static void static void
unbind_resource (struct wl_resource *resource) unbind_resource (struct wl_resource *resource)
{ {
@@ -70,7 +63,7 @@ data_offer_accept (struct wl_client *client,
if (offer->source) if (offer->source)
{ {
wl_data_source_send_target (offer->source->resource, mime_type); offer->source->funcs.target (offer->source, mime_type);
offer->source->has_target = mime_type != NULL; offer->source->has_target = mime_type != NULL;
} }
} }
@@ -82,9 +75,9 @@ data_offer_receive (struct wl_client *client, struct wl_resource *resource,
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source) if (offer->source)
wl_data_source_send_send (offer->source->resource, mime_type, fd); meta_wayland_data_source_send (offer->source, mime_type, fd);
else
close (fd); close (fd);
} }
static void static void
@@ -104,7 +97,7 @@ destroy_data_offer (struct wl_resource *resource)
{ {
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source) if (offer->source && offer->source->resource)
wl_list_remove (&offer->source_destroy_listener.link); wl_list_remove (&offer->source_destroy_listener.link);
g_slice_free (MetaWaylandDataOffer, offer); g_slice_free (MetaWaylandDataOffer, offer);
@@ -116,7 +109,6 @@ destroy_offer_data_source (struct wl_listener *listener, void *data)
MetaWaylandDataOffer *offer; MetaWaylandDataOffer *offer;
offer = wl_container_of (listener, offer, source_destroy_listener); offer = wl_container_of (listener, offer, source_destroy_listener);
offer->source = NULL; offer->source = NULL;
} }
@@ -128,11 +120,14 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
char **p; char **p;
offer->source = source; offer->source = source;
offer->source_destroy_listener.notify = destroy_offer_data_source;
offer->resource = wl_resource_create (wl_resource_get_client (target), &wl_data_offer_interface, wl_resource_get_version (target), 0); offer->resource = wl_resource_create (wl_resource_get_client (target), &wl_data_offer_interface, wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource, &data_offer_interface, offer, destroy_data_offer); wl_resource_set_implementation (offer->resource, &data_offer_interface, offer, destroy_data_offer);
wl_resource_add_destroy_listener (source->resource, &offer->source_destroy_listener);
if (source->resource)
{
offer->source_destroy_listener.notify = destroy_offer_data_source;
wl_resource_add_destroy_listener (source->resource, &offer->source_destroy_listener);
}
wl_data_device_send_data_offer (target, offer->resource); wl_data_device_send_data_offer (target, offer->resource);
@@ -147,12 +142,8 @@ data_source_offer (struct wl_client *client,
struct wl_resource *resource, const char *type) struct wl_resource *resource, const char *type)
{ {
MetaWaylandDataSource *source = wl_resource_get_user_data (resource); MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
char **p;
p = wl_array_add (&source->mime_types, sizeof *p); if (!meta_wayland_data_source_add_mime_type (source, type))
if (p)
*p = strdup (type);
if (!p || !*p)
wl_resource_post_no_memory (resource); wl_resource_post_no_memory (resource);
} }
@@ -291,10 +282,7 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
} }
if (drag_grab->drag_data_source) if (drag_grab->drag_data_source)
{ wl_list_remove (&drag_grab->drag_data_source_listener.link);
drag_grab->drag_data_source->has_target = FALSE;
wl_list_remove (&drag_grab->drag_data_source_listener.link);
}
if (drag_grab->feedback_actor) if (drag_grab->feedback_actor)
{ {
@@ -355,6 +343,7 @@ destroy_data_device_origin (struct wl_listener *listener, void *data)
drag_grab->drag_origin = NULL; drag_grab->drag_origin = NULL;
data_device_end_drag_grab (drag_grab); data_device_end_drag_grab (drag_grab);
meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL);
} }
static void static void
@@ -365,6 +354,7 @@ destroy_data_device_source (struct wl_listener *listener, void *data)
drag_grab->drag_data_source = NULL; drag_grab->drag_data_source = NULL;
data_device_end_drag_grab (drag_grab); data_device_end_drag_grab (drag_grab);
meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL);
} }
static void static void
@@ -442,6 +432,9 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_data_source_listener.notify = destroy_data_device_source; drag_grab->drag_data_source_listener.notify = destroy_data_device_source;
wl_resource_add_destroy_listener (source_resource, wl_resource_add_destroy_listener (source_resource,
&drag_grab->drag_data_source_listener); &drag_grab->drag_data_source_listener);
meta_wayland_data_device_set_dnd_source (data_device,
drag_grab->drag_data_source);
} }
if (icon_resource) if (icon_resource)
@@ -489,6 +482,48 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
} }
static void static void
meta_wayland_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
wl_data_source_send_send (source->resource, mime_type, fd);
close (fd);
}
static void
meta_wayland_source_target (MetaWaylandDataSource *source,
const gchar *mime_type)
{
wl_data_source_send_target (source->resource, mime_type);
}
static void
meta_wayland_source_cancel (MetaWaylandDataSource *source)
{
wl_data_source_send_cancelled (source->resource);
}
static const MetaWaylandDataSourceFuncs meta_wayland_source_funcs = {
meta_wayland_source_send,
meta_wayland_source_target,
meta_wayland_source_cancel
};
void
meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source)
{
if (data_device->dnd_data_source == source)
return;
if (data_device->dnd_data_source)
meta_wayland_data_source_free (data_device->dnd_data_source);
data_device->dnd_data_source = source;
wl_signal_emit (&data_device->dnd_ownership_signal, source);
}
void
meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device, meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source, MetaWaylandDataSource *source,
guint32 serial) guint32 serial)
@@ -503,8 +538,15 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
if (data_device->selection_data_source) if (data_device->selection_data_source)
{ {
wl_data_source_send_cancelled (data_device->selection_data_source->resource); data_device->selection_data_source->funcs.cancel (data_device->selection_data_source);
wl_list_remove (&data_device->selection_data_source_listener.link);
if (data_device->selection_data_source->resource)
{
wl_list_remove (&data_device->selection_data_source_listener.link);
data_device->selection_data_source->resource = NULL;
}
meta_wayland_data_source_free (data_device->selection_data_source);
data_device->selection_data_source = NULL; data_device->selection_data_source = NULL;
} }
@@ -531,8 +573,13 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
if (source) if (source)
{ {
data_device->selection_data_source_listener.notify = destroy_selection_data_source; if (source->resource)
wl_resource_add_destroy_listener (source->resource, &data_device->selection_data_source_listener); {
data_device->selection_data_source_listener.notify = destroy_selection_data_source;
wl_resource_add_destroy_listener (source->resource, &data_device->selection_data_source_listener);
}
wl_signal_emit (&data_device->selection_ownership_signal, source);
} }
} }
@@ -570,25 +617,23 @@ static void
destroy_data_source (struct wl_resource *resource) destroy_data_source (struct wl_resource *resource)
{ {
MetaWaylandDataSource *source = wl_resource_get_user_data (resource); MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
char **p;
wl_array_for_each (p, &source->mime_types) free (*p); source->resource = NULL;
wl_array_release (&source->mime_types);
g_slice_free (MetaWaylandDataSource, source);
} }
static void static void
create_data_source (struct wl_client *client, create_data_source (struct wl_client *client,
struct wl_resource *resource, guint32 id) struct wl_resource *resource, guint32 id)
{ {
MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource); MetaWaylandDataSource *source;
struct wl_resource *source_resource;
source->resource = wl_resource_create (client, &wl_data_source_interface, wl_resource_get_version (resource), id); source_resource = wl_resource_create (client, &wl_data_source_interface,
wl_resource_set_implementation (source->resource, &data_source_interface, source, destroy_data_source); wl_resource_get_version (resource), id);
source = meta_wayland_data_source_new (&meta_wayland_source_funcs,
wl_array_init (&source->mime_types); source_resource, NULL);
wl_resource_set_implementation (source_resource, &data_source_interface,
source, destroy_data_source);
} }
static void static void
@@ -632,6 +677,8 @@ void
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device) meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
{ {
wl_list_init (&data_device->resource_list); wl_list_init (&data_device->resource_list);
wl_signal_init (&data_device->selection_ownership_signal);
wl_signal_init (&data_device->dnd_ownership_signal);
} }
void void
@@ -683,3 +730,75 @@ meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
-drag_grab->drag_surface->offset_x, -drag_grab->drag_surface->offset_x,
-drag_grab->drag_surface->offset_y); -drag_grab->drag_surface->offset_y);
} }
void
meta_wayland_data_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
source->funcs.send (source, mime_type, fd);
}
gboolean
meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
const gchar *mime_type)
{
gchar **p;
wl_array_for_each (p, &source->mime_types)
{
if (g_strcmp0 (mime_type, *p) == 0)
return TRUE;
}
return FALSE;
}
MetaWaylandDataSource *
meta_wayland_data_source_new (const MetaWaylandDataSourceFuncs *funcs,
struct wl_resource *wl_resource,
gpointer user_data)
{
MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource);
source->funcs = *funcs;
source->resource = wl_resource;
source->user_data = user_data;
wl_array_init (&source->mime_types);
return source;
}
void
meta_wayland_data_source_free (MetaWaylandDataSource *source)
{
char **pos;
if (source->resource)
wl_resource_destroy (source->resource);
wl_array_for_each (pos, &source->mime_types)
{
g_free (*pos);
}
wl_array_release (&source->mime_types);
g_slice_free (MetaWaylandDataSource, source);
}
gboolean
meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type)
{
gchar **pos;
pos = wl_array_add (&source->mime_types, sizeof (*pos));
if (pos)
{
*pos = g_strdup (mime_type);
return *pos != NULL;
}
return FALSE;
}

View File

@@ -28,14 +28,38 @@
#include "meta-wayland-types.h" #include "meta-wayland-types.h"
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab; typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
typedef struct _MetaWaylandDataSourceFuncs MetaWaylandDataSourceFuncs;
struct _MetaWaylandDataDevice struct _MetaWaylandDataDevice
{ {
uint32_t selection_serial; uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source; MetaWaylandDataSource *selection_data_source;
MetaWaylandDataSource *dnd_data_source;
struct wl_listener selection_data_source_listener; struct wl_listener selection_data_source_listener;
struct wl_list resource_list; struct wl_list resource_list;
MetaWaylandDragGrab *current_grab; MetaWaylandDragGrab *current_grab;
struct wl_signal selection_ownership_signal;
struct wl_signal dnd_ownership_signal;
};
struct _MetaWaylandDataSourceFuncs
{
void (* send) (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
void (* target) (MetaWaylandDataSource *source,
const gchar *mime_type);
void (* cancel) (MetaWaylandDataSource *source);
};
struct _MetaWaylandDataSource
{
MetaWaylandDataSourceFuncs funcs;
struct wl_resource *resource;
struct wl_array mime_types;
gpointer user_data;
gboolean has_target;
}; };
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor); void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -48,4 +72,25 @@ gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_de
MetaWaylandSurface *surface); MetaWaylandSurface *surface);
void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device); void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device);
void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source);
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source,
guint32 serial);
MetaWaylandDataSource *
meta_wayland_data_source_new (const MetaWaylandDataSourceFuncs *funcs,
struct wl_resource *resource,
gpointer user_data);
void meta_wayland_data_source_free (MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type);
gboolean meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
const gchar *mime_type);
void meta_wayland_data_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
#endif /* META_WAYLAND_DATA_DEVICE_H */ #endif /* META_WAYLAND_DATA_DEVICE_H */

View File

@@ -33,6 +33,8 @@
#include "meta-wayland-surface.h" #include "meta-wayland-surface.h"
#include "meta-wayland-seat.h" #include "meta-wayland-seat.h"
typedef struct _MetaXWaylandSelection MetaXWaylandSelection;
typedef struct typedef struct
{ {
struct wl_list link; struct wl_list link;
@@ -43,7 +45,7 @@ typedef struct
typedef struct typedef struct
{ {
int display_index; int display_index;
char *lockfile; char *lock_file;
int abstract_fd; int abstract_fd;
int unix_fd; int unix_fd;
pid_t pid; pid_t pid;
@@ -52,6 +54,8 @@ typedef struct
char *display_name; char *display_name;
GMainLoop *init_loop; GMainLoop *init_loop;
MetaXWaylandSelection *selection_data;
} MetaXWaylandManager; } MetaXWaylandManager;
struct _MetaWaylandCompositor struct _MetaWaylandCompositor

View File

@@ -46,7 +46,7 @@
#include "meta-cursor-tracker-private.h" #include "meta-cursor-tracker-private.h"
#include "display-private.h" #include "display-private.h"
#include "window-private.h" #include "window-private.h"
#include "window-wayland.h" #include "meta-window-wayland.h"
#include "compositor/region-utils.h" #include "compositor/region-utils.h"
@@ -215,19 +215,52 @@ calculate_surface_window_geometry (MetaWaylandSurface *surface,
} }
} }
static void
destroy_window (MetaWaylandSurface *surface)
{
if (surface->window)
{
MetaDisplay *display = meta_get_display ();
guint32 timestamp = meta_display_get_current_time_roundtrip (display);
meta_window_unmanage (surface->window, timestamp);
}
g_assert (surface->window == NULL);
}
static void static void
toplevel_surface_commit (MetaWaylandSurface *surface, toplevel_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending) MetaWaylandPendingState *pending)
{ {
MetaWindow *window = surface->window; MetaWindow *window = surface->window;
/* Sanity check. */ if (surface->role == META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE)
if (surface->buffer == NULL)
{ {
wl_resource_post_error (surface->resource, /* For wl_shell, it's equivalent to an unmap. Semantics
WL_DISPLAY_ERROR_INVALID_OBJECT, * are poorly defined, so we can choose some that are
"Cannot commit a NULL buffer to an xdg_surface"); * convenient for us. */
return; if (surface->buffer && !window)
{
window = meta_window_wayland_new (meta_get_display (), surface);
meta_wayland_surface_set_window (surface, window);
}
else if (surface->buffer == NULL && window)
{
destroy_window (surface);
return;
}
}
else
{
if (surface->buffer == NULL)
{
/* XDG surfaces can't commit NULL buffers */
wl_resource_post_error (surface->resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Cannot commit a NULL buffer to an xdg_surface");
return;
}
} }
/* We resize X based surfaces according to X events */ /* We resize X based surfaces according to X events */
@@ -723,20 +756,6 @@ meta_wayland_surface_set_window (MetaWaylandSurface *surface,
sync_reactive (surface); sync_reactive (surface);
} }
static void
destroy_window (MetaWaylandSurface *surface)
{
if (surface->window)
{
MetaDisplay *display = meta_get_display ();
guint32 timestamp = meta_display_get_current_time_roundtrip (display);
meta_window_unmanage (surface->window, timestamp);
}
g_assert (surface->window == NULL);
}
static void static void
wl_surface_destructor (struct wl_resource *resource) wl_surface_destructor (struct wl_resource *resource)
{ {
@@ -1506,7 +1525,6 @@ wl_shell_get_shell_surface (struct wl_client *client,
struct wl_resource *surface_resource) struct wl_resource *surface_resource)
{ {
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWindow *window;
if (surface->wl_shell_surface != NULL) if (surface->wl_shell_surface != NULL)
{ {
@@ -1524,9 +1542,6 @@ wl_shell_get_shell_surface (struct wl_client *client,
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id); surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor); wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
window = meta_window_wayland_new (meta_get_display (), surface);
meta_wayland_surface_set_window (surface, window);
} }
static const struct wl_shell_interface meta_wayland_wl_shell_interface = { static const struct wl_shell_interface meta_wayland_wl_shell_interface = {
@@ -1554,14 +1569,14 @@ gtk_surface_destructor (struct wl_resource *resource)
} }
static void static void
set_dbus_properties (struct wl_client *client, gtk_surface_set_dbus_properties (struct wl_client *client,
struct wl_resource *resource, struct wl_resource *resource,
const char *application_id, const char *application_id,
const char *app_menu_path, const char *app_menu_path,
const char *menubar_path, const char *menubar_path,
const char *window_object_path, const char *window_object_path,
const char *application_object_path, const char *application_object_path,
const char *unique_bus_name) const char *unique_bus_name)
{ {
MetaWaylandSurface *surface = wl_resource_get_user_data (resource); MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
@@ -1581,8 +1596,36 @@ set_dbus_properties (struct wl_client *client,
window_object_path); window_object_path);
} }
static void
gtk_surface_set_modal (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
if (surface->is_modal)
return;
surface->is_modal = TRUE;
meta_window_set_type (surface->window, META_WINDOW_MODAL_DIALOG);
}
static void
gtk_surface_unset_modal (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
if (!surface->is_modal)
return;
surface->is_modal = FALSE;
meta_window_set_type (surface->window, META_WINDOW_NORMAL);
}
static const struct gtk_surface_interface meta_wayland_gtk_surface_interface = { static const struct gtk_surface_interface meta_wayland_gtk_surface_interface = {
set_dbus_properties gtk_surface_set_dbus_properties,
gtk_surface_set_modal,
gtk_surface_unset_modal,
}; };
static void static void
@@ -1619,6 +1662,17 @@ bind_gtk_shell (struct wl_client *client,
uint32_t capabilities = 0; uint32_t capabilities = 0;
resource = wl_resource_create (client, &gtk_shell_interface, version, id); resource = wl_resource_create (client, &gtk_shell_interface, version, id);
if (version != META_GTK_SHELL_VERSION)
{
wl_resource_post_error (resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Incompatible gtk-shell version "
"(supported version: %d)",
META_GTK_SHELL_VERSION);
return;
}
wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL); wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL);
if (!meta_prefs_get_show_fallback_app_menu ()) if (!meta_prefs_get_show_fallback_app_menu ())

View File

@@ -101,6 +101,7 @@ struct _MetaWaylandSurface
struct wl_resource *xdg_shell_resource; struct wl_resource *xdg_shell_resource;
MetaWaylandSerial acked_configure_serial; MetaWaylandSerial acked_configure_serial;
gboolean has_set_geometry; gboolean has_set_geometry;
gboolean is_modal;
/* xdg_popup */ /* xdg_popup */
struct { struct {

View File

@@ -42,7 +42,7 @@
#define META_WL_SEAT_VERSION 4 #define META_WL_SEAT_VERSION 4
#define META_WL_OUTPUT_VERSION 2 #define META_WL_OUTPUT_VERSION 2
#define META_XSERVER_VERSION 1 #define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 1 #define META_GTK_SHELL_VERSION 2
#define META_WL_SUBCOMPOSITOR_VERSION 1 #define META_WL_SUBCOMPOSITOR_VERSION 1
#endif #endif

View File

@@ -24,7 +24,7 @@
#include "config.h" #include "config.h"
#include "window-wayland.h" #include "meta-window-wayland.h"
#include <meta/errors.h> #include <meta/errors.h>
#include "window-private.h" #include "window-private.h"

View File

@@ -34,4 +34,9 @@ meta_xwayland_complete_init (void);
void void
meta_xwayland_stop (MetaXWaylandManager *manager); meta_xwayland_stop (MetaXWaylandManager *manager);
/* wl_data_device/X11 selection interoperation */
void meta_xwayland_init_selection (void);
void meta_xwayland_shutdown_selection (void);
gboolean meta_xwayland_selection_handle_event (XEvent *xevent);
#endif /* META_XWAYLAND_PRIVATE_H */ #endif /* META_XWAYLAND_PRIVATE_H */

View File

@@ -0,0 +1,943 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* The file is loosely based on xwayland/selection.c from Weston */
#include "config.h"
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <glib-unix.h>
#include <gio/gunixoutputstream.h>
#include <gio/gunixinputstream.h>
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#include <meta/errors.h>
#include "meta-xwayland-private.h"
#include "meta-wayland-data-device.h"
#define INCR_CHUNK_SIZE (128 * 1024)
typedef struct {
MetaXWaylandSelection *selection_data;
GInputStream *stream;
GCancellable *cancellable;
MetaWindow *window;
XSelectionRequestEvent request_event;
guchar buffer[INCR_CHUNK_SIZE];
gsize buffer_len;
guint incr : 1;
} WaylandSelectionData;
typedef struct {
MetaXWaylandSelection *selection_data;
GOutputStream *stream;
GCancellable *cancellable;
gchar *mime_type;
guint incr : 1;
} X11SelectionData;
typedef struct {
Atom selection_atom;
Window window;
Window owner;
Time timestamp;
const MetaWaylandDataSource *source;
WaylandSelectionData *wayland_selection;
X11SelectionData *x11_selection;
struct wl_listener ownership_listener;
} MetaSelectionBridge;
struct _MetaXWaylandSelection {
MetaSelectionBridge clipboard;
};
static MetaSelectionBridge *
atom_to_selection_bridge (MetaWaylandCompositor *compositor,
Atom selection_atom)
{
MetaXWaylandSelection *selection_data = compositor->xwayland_manager.selection_data;
if (selection_atom == selection_data->clipboard.selection_atom)
return &selection_data->clipboard;
else
return NULL;
}
static X11SelectionData *
x11_selection_data_new (MetaXWaylandSelection *selection_data,
int fd,
const char *mime_type)
{
X11SelectionData *data;
data = g_slice_new0 (X11SelectionData);
data->selection_data = selection_data;
data->stream = g_unix_output_stream_new (fd, TRUE);
data->cancellable = g_cancellable_new ();
data->mime_type = g_strdup (mime_type);
return data;
}
static void
x11_selection_data_free (X11SelectionData *data)
{
g_cancellable_cancel (data->cancellable);
g_object_unref (data->cancellable);
g_object_unref (data->stream);
g_free (data->mime_type);
g_slice_free (X11SelectionData, data);
}
static void
x11_data_write_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
MetaSelectionBridge *selection = user_data;
X11SelectionData *data = selection->x11_selection;
GError *error = NULL;
g_output_stream_write_finish (G_OUTPUT_STREAM (object), res, &error);
if (data->incr)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XDeleteProperty (xdisplay, selection->window,
gdk_x11_get_xatom_by_name ("_META_SELECTION"));
}
if (error)
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("Error writing from X11 selection: %s\n", error->message);
g_error_free (error);
}
if (!data->incr)
{
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
}
}
static void
x11_selection_data_write (MetaSelectionBridge *selection,
guchar *buffer,
gulong len)
{
X11SelectionData *data = selection->x11_selection;
g_output_stream_write_async (data->stream, buffer, len,
G_PRIORITY_DEFAULT, data->cancellable,
x11_data_write_cb, selection);
}
static MetaWaylandDataSource *
data_device_get_active_source_for_atom (MetaWaylandDataDevice *data_device,
Atom selection_atom)
{
if (selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
return data_device->selection_data_source;
else
return NULL;
}
static WaylandSelectionData *
wayland_selection_data_new (XSelectionRequestEvent *request_event,
MetaWaylandCompositor *compositor)
{
MetaWaylandDataDevice *data_device;
MetaWaylandDataSource *wayland_source;
MetaSelectionBridge *selection;
WaylandSelectionData *data;
const gchar *mime_type;
GError *error = NULL;
int p[2];
selection = atom_to_selection_bridge (compositor, request_event->selection);
if (!selection)
return NULL;
if (!g_unix_open_pipe (p, FD_CLOEXEC, &error))
{
g_critical ("Failed to open pipe: %s\n", error->message);
g_error_free (error);
return NULL;
}
data_device = &compositor->seat->data_device;
mime_type = gdk_x11_get_xatom_name (request_event->target);
if (!g_unix_set_fd_nonblocking (p[0], TRUE, &error) ||
!g_unix_set_fd_nonblocking (p[1], TRUE, &error))
{
if (error)
{
g_critical ("Failed to make fds non-blocking: %s\n", error->message);
g_error_free (error);
}
close (p[0]);
close (p[1]);
return NULL;
}
wayland_source = data_device_get_active_source_for_atom (data_device,
selection->selection_atom),
meta_wayland_data_source_send (wayland_source, mime_type, p[1]);
data = g_slice_new0 (WaylandSelectionData);
data->request_event = *request_event;
data->cancellable = g_cancellable_new ();
data->stream = g_unix_input_stream_new (p[0], TRUE);
data->window = meta_display_lookup_x_window (meta_get_display (),
data->request_event.requestor);
if (!data->window)
{
/* Not a managed window, set the PropertyChangeMask
* for INCR deletion notifications.
*/
XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
data->request_event.requestor, PropertyChangeMask);
}
return data;
}
static void
reply_selection_request (XSelectionRequestEvent *request_event,
gboolean accepted)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XSelectionEvent event;
memset(&event, 0, sizeof (XSelectionEvent));
event.type = SelectionNotify;
event.time = request_event->time;
event.requestor = request_event->requestor;
event.selection = request_event->selection;
event.target = request_event->target;
event.property = accepted ? request_event->property : None;
XSendEvent (xdisplay, request_event->requestor,
False, NoEventMask, (XEvent *) &event);
}
static void
wayland_selection_data_free (WaylandSelectionData *data)
{
if (!data->window)
{
MetaDisplay *display = meta_get_display ();
meta_error_trap_push (display);
XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
data->request_event.requestor, NoEventMask);
meta_error_trap_pop (display);
}
g_cancellable_cancel (data->cancellable);
g_object_unref (data->cancellable);
g_object_unref (data->stream);
g_slice_free (WaylandSelectionData, data);
}
static void
wayland_selection_update_x11_property (WaylandSelectionData *data)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XChangeProperty (xdisplay,
data->request_event.requestor,
data->request_event.property,
data->request_event.target,
8, PropModeReplace,
data->buffer, data->buffer_len);
data->buffer_len = 0;
}
static void
wayland_data_read_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
MetaSelectionBridge *selection = user_data;
WaylandSelectionData *data = selection->wayland_selection;
GError *error = NULL;
gsize bytes_read;
bytes_read = g_input_stream_read_finish (G_INPUT_STREAM (object),
res, &error);
if (error)
{
g_warning ("Error transfering wayland clipboard to X11: %s\n",
error->message);
g_error_free (error);
if (data)
{
reply_selection_request (&data->request_event, FALSE);
g_clear_pointer (&selection->wayland_selection,
(GDestroyNotify) wayland_selection_data_free);
}
return;
}
data->buffer_len = bytes_read;
if (bytes_read == INCR_CHUNK_SIZE)
{
if (!data->incr)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
guint32 incr_chunk_size = INCR_CHUNK_SIZE;
/* Not yet in incr */
data->incr = TRUE;
XChangeProperty (xdisplay,
data->request_event.requestor,
data->request_event.property,
gdk_x11_get_xatom_by_name ("INCR"),
32, PropModeReplace,
(guchar *) &incr_chunk_size, 1);
reply_selection_request (&data->request_event, TRUE);
}
else
wayland_selection_update_x11_property (data);
}
else
{
if (!data->incr)
{
/* Non-incr transfer finished */
wayland_selection_update_x11_property (data);
reply_selection_request (&data->request_event, TRUE);
}
else if (data->incr)
{
/* Incr transfer complete, setting a new property */
wayland_selection_update_x11_property (data);
if (bytes_read > 0)
return;
}
g_clear_pointer (&selection->wayland_selection,
(GDestroyNotify) wayland_selection_data_free);
}
}
static void
wayland_selection_data_read (MetaSelectionBridge *selection)
{
WaylandSelectionData *data = selection->wayland_selection;
g_input_stream_read_async (data->stream, data->buffer,
INCR_CHUNK_SIZE, G_PRIORITY_DEFAULT,
data->cancellable,
wayland_data_read_cb, selection);
}
static void
meta_xwayland_selection_get_incr_chunk (MetaWaylandCompositor *compositor,
MetaSelectionBridge *selection)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
gulong nitems_ret, bytes_after_ret;
guchar *prop_ret;
int format_ret;
Atom type_ret;
XGetWindowProperty (xdisplay,
selection->window,
gdk_x11_get_xatom_by_name ("_META_SELECTION"),
0, /* offset */
0x1fffffff, /* length */
False, /* delete */
AnyPropertyType,
&type_ret,
&format_ret,
&nitems_ret,
&bytes_after_ret,
&prop_ret);
if (nitems_ret > 0)
{
x11_selection_data_write (selection, prop_ret, nitems_ret);
}
else
{
/* Transfer has completed */
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
}
XFree (prop_ret);
}
static void
meta_x11_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
MetaSelectionBridge *selection = source->user_data;
Atom type_atom;
if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
type_atom = gdk_x11_get_xatom_by_name ("UTF8_STRING");
else
type_atom = gdk_x11_get_xatom_by_name (mime_type);
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
/* Takes ownership of fd */
selection->x11_selection =
x11_selection_data_new (compositor->xwayland_manager.selection_data,
fd, mime_type);
XConvertSelection (xdisplay,
selection->selection_atom, type_atom,
gdk_x11_get_xatom_by_name ("_META_SELECTION"),
selection->window,
CurrentTime);
XFlush (xdisplay);
}
static void
meta_x11_source_target (MetaWaylandDataSource *source,
const gchar *mime_type)
{
}
static void
meta_x11_source_cancel (MetaWaylandDataSource *source)
{
MetaSelectionBridge *selection = source->user_data;
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
}
static const MetaWaylandDataSourceFuncs meta_x11_source_funcs = {
meta_x11_source_send,
meta_x11_source_target,
meta_x11_source_cancel
};
static gboolean
meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source,
Window window,
Atom prop)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
gulong nitems_ret, bytes_after_ret, i;
Atom *atoms, type_ret, utf8_string;
int format_ret;
utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING");
XGetWindowProperty (xdisplay, window, prop,
0, /* offset */
0x1fffffff, /* length */
True, /* delete */
AnyPropertyType,
&type_ret,
&format_ret,
&nitems_ret,
&bytes_after_ret,
(guchar **) &atoms);
if (nitems_ret == 0 || type_ret != XA_ATOM)
{
XFree (atoms);
return FALSE;
}
for (i = 0; i < nitems_ret; i++)
{
const gchar *mime_type;
if (atoms[i] == utf8_string)
mime_type = "text/plain;charset=utf-8";
else
mime_type = gdk_x11_get_xatom_name (atoms[i]);
meta_wayland_data_source_add_mime_type (source, mime_type);
}
XFree (atoms);
return TRUE;
}
static void
meta_xwayland_selection_get_x11_targets (MetaWaylandCompositor *compositor,
MetaSelectionBridge *selection)
{
MetaWaylandDataSource *data_source;
data_source = meta_wayland_data_source_new (&meta_x11_source_funcs,
NULL, selection);
if (meta_xwayland_data_source_fetch_mimetype_list (data_source,
selection->window,
gdk_x11_get_xatom_by_name ("_META_SELECTION")))
{
selection->source = data_source;
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
{
meta_wayland_data_device_set_selection (&compositor->seat->data_device, data_source,
wl_display_next_serial (compositor->wayland_display));
}
}
else
{
meta_wayland_data_source_free (data_source);
}
}
static void
meta_xwayland_selection_get_x11_data (MetaWaylandCompositor *compositor,
MetaSelectionBridge *selection)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
gulong nitems_ret, bytes_after_ret;
guchar *prop_ret;
int format_ret;
Atom type_ret;
if (!selection->x11_selection)
return;
XGetWindowProperty (xdisplay,
selection->window,
gdk_x11_get_xatom_by_name ("_META_SELECTION"),
0, /* offset */
0x1fffffff, /* length */
True, /* delete */
AnyPropertyType,
&type_ret,
&format_ret,
&nitems_ret,
&bytes_after_ret,
&prop_ret);
selection->x11_selection->incr = (type_ret == gdk_x11_get_xatom_by_name ("INCR"));
if (selection->x11_selection->incr)
return;
if (type_ret == gdk_x11_get_xatom_by_name (selection->x11_selection->mime_type))
x11_selection_data_write (selection, prop_ret, nitems_ret);
XFree (prop_ret);
}
static gboolean
meta_xwayland_selection_handle_selection_notify (MetaWaylandCompositor *compositor,
XEvent *xevent)
{
XSelectionEvent *event = (XSelectionEvent *) xevent;
MetaSelectionBridge *selection;
selection = atom_to_selection_bridge (compositor, event->selection);
if (!selection)
return FALSE;
/* convert selection failed */
if (event->property == None)
{
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
return FALSE;
}
if (event->target == gdk_x11_get_xatom_by_name ("TARGETS"))
meta_xwayland_selection_get_x11_targets (compositor, selection);
else
meta_xwayland_selection_get_x11_data (compositor, selection);
return TRUE;
}
static void
meta_xwayland_selection_send_targets (MetaWaylandCompositor *compositor,
const MetaWaylandDataSource *data_source,
Window requestor,
Atom property)
{
Atom *targets;
gchar **p;
int i = 0;
if (!data_source)
return;
if (data_source->mime_types.size == 0)
return;
/* Make extra room for TIMESTAMP/TARGETS */
targets = g_new (Atom, data_source->mime_types.size + 2);
wl_array_for_each (p, &data_source->mime_types)
{
targets[i++] = gdk_x11_get_xatom_by_name (*p);
}
targets[i++] = gdk_x11_get_xatom_by_name ("TIMESTAMP");
targets[i++] = gdk_x11_get_xatom_by_name ("TARGETS");
XChangeProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
requestor, property,
XA_ATOM, 32, PropModeReplace,
(guchar *) targets, i);
g_free (targets);
}
static void
meta_xwayland_selection_send_timestamp (MetaWaylandCompositor *compositor,
Window requestor,
Atom property,
Time timestamp)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XChangeProperty (xdisplay, requestor, property,
XA_INTEGER, 32,
PropModeReplace,
(guchar *) &timestamp, 1);
}
static void
meta_xwayland_selection_send_incr_chunk (MetaWaylandCompositor *compositor,
MetaSelectionBridge *selection)
{
if (!selection->wayland_selection)
return;
if (selection->wayland_selection->buffer_len > 0)
wayland_selection_update_x11_property (selection->wayland_selection);
else
wayland_selection_data_read (selection);
}
static gboolean
handle_incr_chunk (MetaWaylandCompositor *compositor,
MetaSelectionBridge *selection,
XPropertyEvent *event)
{
if (selection->x11_selection &&
selection->x11_selection->incr &&
event->window == selection->owner &&
event->state == PropertyNewValue &&
event->atom == gdk_x11_get_xatom_by_name ("_META_SELECTION"))
{
/* X11 to Wayland */
meta_xwayland_selection_get_incr_chunk (compositor, selection);
return TRUE;
}
else if (selection->wayland_selection &&
selection->wayland_selection->incr &&
event->window == selection->window &&
event->state == PropertyDelete &&
event->atom == selection->wayland_selection->request_event.property)
{
/* Wayland to X11 */
meta_xwayland_selection_send_incr_chunk (compositor, selection);
return TRUE;
}
return FALSE;
}
static gboolean
meta_xwayland_selection_handle_property_notify (MetaWaylandCompositor *compositor,
XEvent *xevent)
{
MetaXWaylandSelection *selection_data = compositor->xwayland_manager.selection_data;
XPropertyEvent *event = (XPropertyEvent *) xevent;
return handle_incr_chunk (compositor, &selection_data->clipboard, event);
}
static gboolean
meta_xwayland_selection_handle_selection_request (MetaWaylandCompositor *compositor,
XEvent *xevent)
{
XSelectionRequestEvent *event = (XSelectionRequestEvent *) xevent;
MetaWaylandDataSource *data_source;
MetaSelectionBridge *selection;
selection = atom_to_selection_bridge (compositor, event->selection);
if (!selection)
return FALSE;
/* We must fetch from the currently active source, not the Xwayland one */
data_source = data_device_get_active_source_for_atom (&compositor->seat->data_device,
selection->selection_atom);
if (!data_source)
return FALSE;
g_clear_pointer (&selection->wayland_selection,
(GDestroyNotify) wayland_selection_data_free);
if (event->target == gdk_x11_get_xatom_by_name ("TARGETS"))
{
meta_xwayland_selection_send_targets (compositor,
data_source,
event->requestor,
event->property);
reply_selection_request (event, TRUE);
}
else if (event->target == gdk_x11_get_xatom_by_name ("TIMESTAMP"))
{
meta_xwayland_selection_send_timestamp (compositor,
event->requestor, event->property,
selection->timestamp);
reply_selection_request (event, TRUE);
}
else
{
if (data_source &&
meta_wayland_data_source_has_mime_type (data_source,
gdk_x11_get_xatom_name (event->target)))
{
selection->wayland_selection = wayland_selection_data_new (event,
compositor);
if (selection->wayland_selection)
wayland_selection_data_read (selection);
}
if (!selection->wayland_selection)
reply_selection_request (event, FALSE);
}
return TRUE;
}
static gboolean
meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *compositor,
XEvent *xevent)
{
XFixesSelectionNotifyEvent *event = (XFixesSelectionNotifyEvent *) xevent;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
MetaSelectionBridge *selection;
selection = atom_to_selection_bridge (compositor, event->selection);
if (!selection)
return FALSE;
if (event->owner == None)
{
if (selection->source && selection->owner != selection->window)
{
/* An X client went away, clear the selection */
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
{
meta_wayland_data_device_set_selection (&compositor->seat->data_device, NULL,
wl_display_next_serial (compositor->wayland_display));
}
selection->source = NULL;
}
selection->owner = None;
}
else
{
selection->owner = event->owner;
if (selection->owner == selection->window)
{
/* This our own selection window */
selection->timestamp = event->timestamp;
return TRUE;
}
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
XConvertSelection (xdisplay,
event->selection,
gdk_x11_get_xatom_by_name ("TARGETS"),
gdk_x11_get_xatom_by_name ("_META_SELECTION"),
selection->window,
selection->timestamp);
XFlush (xdisplay);
}
return TRUE;
}
gboolean
meta_xwayland_selection_handle_event (XEvent *xevent)
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
if (!compositor->xwayland_manager.selection_data)
return FALSE;
switch (xevent->type)
{
case SelectionNotify:
return meta_xwayland_selection_handle_selection_notify (compositor, xevent);
case PropertyNotify:
return meta_xwayland_selection_handle_property_notify (compositor, xevent);
case SelectionRequest:
return meta_xwayland_selection_handle_selection_request (compositor, xevent);
default:
{
MetaDisplay *display = meta_get_display ();
if (xevent->type - display->xfixes_event_base == XFixesSelectionNotify)
return meta_xwayland_selection_handle_xfixes_selection_notify (compositor, xevent);
return FALSE;
}
}
}
static void
meta_selection_bridge_ownership_notify (struct wl_listener *listener,
void *data)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
MetaSelectionBridge *selection =
wl_container_of (listener, selection, ownership_listener);
MetaWaylandDataSource *owner = data;
if (!owner && selection->window == selection->owner)
{
XSetSelectionOwner (xdisplay, selection->selection_atom,
None, selection->timestamp);
}
else if (owner && selection->source != owner)
{
XSetSelectionOwner (xdisplay,
selection->selection_atom,
selection->window,
CurrentTime);
}
}
static void
init_selection_bridge (MetaSelectionBridge *selection,
Atom selection_atom,
struct wl_signal *signal)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XSetWindowAttributes attributes;
guint mask;
attributes.event_mask = PropertyChangeMask;
selection->ownership_listener.notify = meta_selection_bridge_ownership_notify;
wl_signal_add (signal, &selection->ownership_listener);
selection->selection_atom = selection_atom;
selection->window =
XCreateWindow (xdisplay,
gdk_x11_window_get_xid (gdk_get_default_root_window ()),
-1, -1, 1, 1, /* position */
0, /* border width */
0, /* depth */
InputOnly, /* class */
CopyFromParent, /* visual */
CWEventMask,
&attributes);
mask = XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask;
XFixesSelectSelectionInput (xdisplay, selection->window,
selection_atom, mask);
}
static void
shutdown_selection_bridge (MetaSelectionBridge *selection)
{
wl_list_remove (&selection->ownership_listener.link);
XDestroyWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
selection->window);
g_clear_pointer (&selection->wayland_selection,
(GDestroyNotify) wayland_selection_data_free);
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
}
void
meta_xwayland_init_selection (void)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaXWaylandManager *manager = &compositor->xwayland_manager;
g_assert (manager->selection_data == NULL);
manager->selection_data = g_slice_new0 (MetaXWaylandSelection);
init_selection_bridge (&manager->selection_data->clipboard,
gdk_x11_get_xatom_by_name ("CLIPBOARD"),
&compositor->seat->data_device.selection_ownership_signal);
}
void
meta_xwayland_shutdown_selection (void)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaXWaylandManager *manager = &compositor->xwayland_manager;
MetaXWaylandSelection *selection = manager->selection_data;
g_assert (selection != NULL);
if (selection->clipboard.source)
{
meta_wayland_data_device_set_selection (&compositor->seat->data_device, NULL,
wl_display_next_serial (compositor->wayland_display));
}
shutdown_selection_bridge (&selection->clipboard);
g_slice_free (MetaXWaylandSelection, selection);
manager->selection_data = NULL;
}

View File

@@ -182,7 +182,7 @@ try_display (int display,
if (kill (other, 0) < 0 && errno == ESRCH) if (kill (other, 0) < 0 && errno == ESRCH)
{ {
/* Process is dead. Try unlinking the lockfile and trying again. */ /* Process is dead. Try unlinking the lock file and trying again. */
if (unlink (filename) < 0) if (unlink (filename) < 0)
{ {
g_warning ("failed to unlink stale lock file %s: %m", filename); g_warning ("failed to unlink stale lock file %s: %m", filename);
@@ -221,7 +221,7 @@ try_display (int display,
} }
static char * static char *
create_lockfile (int display, int *display_out) create_lock_file (int display, int *display_out)
{ {
char *filename; char *filename;
int fd; int fd;
@@ -354,7 +354,7 @@ static gboolean
choose_xdisplay (MetaXWaylandManager *manager) choose_xdisplay (MetaXWaylandManager *manager)
{ {
int display = 0; int display = 0;
char *lockfile = NULL; char *lock_file = NULL;
/* Hack to keep the unused Xwayland instance on /* Hack to keep the unused Xwayland instance on
* the login screen from taking the prime :0 display * the login screen from taking the prime :0 display
@@ -365,8 +365,8 @@ choose_xdisplay (MetaXWaylandManager *manager)
do do
{ {
lockfile = create_lockfile (display, &display); lock_file = create_lock_file (display, &display);
if (!lockfile) if (!lock_file)
{ {
g_warning ("Failed to create an X lock file"); g_warning ("Failed to create an X lock file");
return FALSE; return FALSE;
@@ -375,7 +375,7 @@ choose_xdisplay (MetaXWaylandManager *manager)
manager->abstract_fd = bind_to_abstract_socket (display); manager->abstract_fd = bind_to_abstract_socket (display);
if (manager->abstract_fd < 0) if (manager->abstract_fd < 0)
{ {
unlink (lockfile); unlink (lock_file);
if (errno == EADDRINUSE) if (errno == EADDRINUSE)
{ {
@@ -389,7 +389,7 @@ choose_xdisplay (MetaXWaylandManager *manager)
manager->unix_fd = bind_to_unix_socket (display); manager->unix_fd = bind_to_unix_socket (display);
if (manager->abstract_fd < 0) if (manager->abstract_fd < 0)
{ {
unlink (lockfile); unlink (lock_file);
close (manager->abstract_fd); close (manager->abstract_fd);
return FALSE; return FALSE;
} }
@@ -400,7 +400,7 @@ choose_xdisplay (MetaXWaylandManager *manager)
manager->display_index = display; manager->display_index = display;
manager->display_name = g_strdup_printf (":%d", manager->display_index); manager->display_name = g_strdup_printf (":%d", manager->display_index);
manager->lockfile = lockfile; manager->lock_file = lock_file;
return TRUE; return TRUE;
} }
@@ -438,28 +438,27 @@ meta_xwayland_start (MetaXWaylandManager *manager,
{ {
int xwayland_client_fd[2]; int xwayland_client_fd[2];
int displayfd[2]; int displayfd[2];
gboolean started = FALSE;
g_autoptr(GSubprocessLauncher) launcher = NULL; g_autoptr(GSubprocessLauncher) launcher = NULL;
GSubprocessFlags flags; GSubprocessFlags flags;
GSubprocess *proc; GSubprocess *proc;
GError *error = NULL; GError *error = NULL;
if (!choose_xdisplay (manager)) if (!choose_xdisplay (manager))
return FALSE; goto out;
/* We want xwayland to be a wayland client so we make a socketpair to setup a /* We want xwayland to be a wayland client so we make a socketpair to setup a
* wayland protocol connection. */ * wayland protocol connection. */
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0) if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
{ {
g_warning ("xwayland_client_fd socketpair failed\n"); g_warning ("xwayland_client_fd socketpair failed\n");
unlink (manager->lockfile); goto out;
return FALSE;
} }
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0) if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0)
{ {
g_warning ("displayfd socketpair failed\n"); g_warning ("displayfd socketpair failed\n");
unlink (manager->lockfile); goto out;
return FALSE;
} }
/* xwayland, please. */ /* xwayland, please. */
@@ -489,7 +488,7 @@ meta_xwayland_start (MetaXWaylandManager *manager,
if (!proc) if (!proc)
{ {
g_error ("Failed to spawn Xwayland: %s", error->message); g_error ("Failed to spawn Xwayland: %s", error->message);
return FALSE; goto out;
} }
g_subprocess_wait_async (proc, NULL, xserver_died, NULL); g_subprocess_wait_async (proc, NULL, xserver_died, NULL);
@@ -502,7 +501,15 @@ meta_xwayland_start (MetaXWaylandManager *manager,
manager->init_loop = g_main_loop_new (NULL, FALSE); manager->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (manager->init_loop); g_main_loop_run (manager->init_loop);
return TRUE; started = TRUE;
out:
if (!started)
{
unlink (manager->lock_file);
g_clear_pointer (&manager->lock_file, g_free);
}
return started;
} }
/* To be called right after connecting */ /* To be called right after connecting */
@@ -515,6 +522,8 @@ meta_xwayland_complete_init (void)
we won't reset the tty). we won't reset the tty).
*/ */
XSetIOErrorHandler (x_io_error); XSetIOErrorHandler (x_io_error);
meta_xwayland_init_selection ();
} }
void void
@@ -522,10 +531,15 @@ meta_xwayland_stop (MetaXWaylandManager *manager)
{ {
char path[256]; char path[256];
snprintf (path, sizeof path, "/tmp/.X%d-lock", manager->display_index); meta_xwayland_shutdown_selection ();
unlink (path);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index); snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index);
unlink (path); unlink (path);
unlink (manager->lockfile); g_clear_pointer (&manager->display_name, g_free);
if (manager->lock_file)
{
unlink (manager->lock_file);
g_clear_pointer (&manager->lock_file, g_free);
}
} }

View File

@@ -1,9 +1,18 @@
<protocol name="gtk"> <protocol name="gtk">
<interface name="gtk_shell" version="1"> <interface name="gtk_shell" version="2">
<description summary="gtk specific extensions">
gtk_shell is a protocol extension providing additional features for
clients implementing it. It is not backward compatible, and a client must
always only bind to the specific version it implements. If a client binds
to a version different from the version the server provides, an error will
be raised.
</description>
<enum name="capability"> <enum name="capability">
<entry name="global_app_menu" value="1"/> <entry name="global_app_menu" value="1"/>
<entry name="global_menu_bar" value="2"/> <entry name="global_menu_bar" value="2"/>
<entry name="desktop_icons" value="3"/>
</enum> </enum>
<event name="capabilities"> <event name="capabilities">
@@ -16,7 +25,7 @@
</request> </request>
</interface> </interface>
<interface name="gtk_surface" version="1"> <interface name="gtk_surface" version="2">
<request name="set_dbus_properties"> <request name="set_dbus_properties">
<arg name="application_id" type="string" allow-null="true"/> <arg name="application_id" type="string" allow-null="true"/>
<arg name="app_menu_path" type="string" allow-null="true"/> <arg name="app_menu_path" type="string" allow-null="true"/>
@@ -25,6 +34,9 @@
<arg name="application_object_path" type="string" allow-null="true"/> <arg name="application_object_path" type="string" allow-null="true"/>
<arg name="unique_bus_name" type="string" allow-null="true"/> <arg name="unique_bus_name" type="string" allow-null="true"/>
</request> </request>
<request name="set_modal"/>
<request name="unset_modal"/>
</interface> </interface>
</protocol> </protocol>

View File

@@ -39,6 +39,7 @@
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND
#include "wayland/meta-xwayland.h" #include "wayland/meta-xwayland.h"
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
#include "wayland/meta-xwayland-private.h"
#endif #endif
static XIEvent * static XIEvent *
@@ -1676,6 +1677,15 @@ meta_display_handle_xevent (MetaDisplay *display,
} }
#endif #endif
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () &&
meta_xwayland_selection_handle_event (event))
{
bypass_gtk = bypass_compositor = TRUE;
goto out;
}
#endif
display->current_time = event_get_time (display, event); display->current_time = event_get_time (display, event);
display->monitor_cache_invalidated = TRUE; display->monitor_cache_invalidated = TRUE;