Compare commits

...

8 Commits

Author SHA1 Message Date
Carlos Garnacho
297d11b323 WIP: Implement the primary selection protocol 2016-02-20 01:37:01 +01:00
Carlos Garnacho
3f60a2e48a wayland: Implement gtk-shell v3
Implement the gtk_shell.set_startup_id request, so that the ID is
removed from the sequences list, and feedback updated accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Carlos Garnacho
3729e592a6 wayland: Update gtk-shell protocol file to v3
Add a gtk_shell.set_startup_id request, so the application can communicate
to the compositor the startup id that it received through the
DESKTOP_STARTUP_ID envvar, or other means.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Carlos Garnacho
56beedf9f2 core: Refactor startup notification into a separate object
This is kind of in a middle ground at the moment. Even though it
handles sequences not coming from libsn, they're added nowhere at
the moment, we'll rely on the app launch context being in the x11
side at the moment.

Also, even though we do create internal sequence objects, we keep
exposing SnStartupSequences to make gnome-shell happy, we could
consider making this object "public" (and the sequence objects with
it), things stay private at the moment.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Ray Strode
bed82427c6 wayland: change accessible boolean to use_count counter
Since a buffer can be used by multiple surfaces at once,
we need to release the buffer only after all surfaces
are finished with it.  Currently we track whether or
not to release the buffer based on the accessible boolean.
This commit changes it to a counter to accomodate multiple
users.

Also, each surface needs to know whether not it is done with
the buffer, so this commit adds a buffer_used boolean to the
surface state.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-19 08:57:56 -05:00
Ray Strode
e097bc8353 wayland: get rid of buffer->copied_data boolean
We currently track whether or not a buffer can be released early
by looking at the copied_data boolean on the buffer.  This boolean
is, practically speaking, always set to TRUE for shm buffers and is
always false otherwise.

We can just as easily check if the buffer is a shm buffer to decide
whether or not to do an early release.  That's better from a
theoretical point of view since copied_data assumes a 1-to-1
relationship between surface and buffer, which may not actually hold.

This commit drops copied_data and changes the check to instead see
if the buffer is shm.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-19 08:57:56 -05:00
Olivier Fourdan
4e82a751fb window: check for possible loop in transients
If a broken or naughty application tries set up its windows to create
a loop in the transient relationship, mutter will hang, looping forever
in meta_window_foreach_ancestor()

To avoid looping infinitely at various point in the code, check for a
possible loop when setting the transient relationship and deny the
request to set a window transient for another if that would create a
loop.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=759299
2016-02-18 09:03:56 +01:00
Ray Strode
acd50508dc wayland: return from toplevel commit early if no new buffer
meta_wayland_surface_toplevel_commit has a lot of logic to handle
a new buffer getting attached as part of the commit.  None of
that code needs to run if there is no new buffer attached.

This commit short-circuits that case.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-17 16:16:07 -05:00
20 changed files with 1269 additions and 328 deletions

View File

@@ -45,6 +45,8 @@ mutter_built_sources = \
if HAVE_WAYLAND
mutter_built_sources += \
primary-selection-unstable-v1-protocol.c \
primary-selection-unstable-v1-server-protocol.h \
pointer-gestures-unstable-v1-protocol.c \
pointer-gestures-unstable-v1-server-protocol.h \
gtk-shell-protocol.c \
@@ -198,6 +200,8 @@ libmutter_la_SOURCES = \
core/screen.c \
core/screen-private.h \
meta/screen.h \
core/startup-notification.c \
core/startup-notification-private.h \
meta/types.h \
core/restart.c \
core/stack.c \

View File

@@ -35,6 +35,7 @@
#include <meta/boxes.h>
#include <meta/display.h>
#include "keybindings-private.h"
#include "startup-notification-private.h"
#include "meta-gesture-tracker-private.h"
#include <meta/prefs.h>
#include <meta/barrier.h>
@@ -276,9 +277,8 @@ struct _MetaDisplay
int xinput_event_base;
int xinput_opcode;
#ifdef HAVE_STARTUP_NOTIFICATION
SnDisplay *sn_display;
#endif
MetaStartupNotification *startup_notification;
int xsync_event_base;
int xsync_error_base;
int shape_event_base;

View File

@@ -400,28 +400,6 @@ meta_display_remove_pending_pings_for_window (MetaDisplay *display,
}
#ifdef HAVE_STARTUP_NOTIFICATION
static void
sn_error_trap_push (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_error_trap_push (display);
}
static void
sn_error_trap_pop (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_error_trap_pop (display);
}
#endif
static void
enable_compositor (MetaDisplay *display)
{
@@ -527,6 +505,20 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
}
}
static void
on_startup_notification_changed (MetaStartupNotification *sn,
gpointer sequence,
MetaDisplay *display)
{
if (!display->screen)
return;
g_slist_free (display->screen->startup_sequences);
display->screen->startup_sequences =
meta_startup_notification_get_sequences (display->startup_notification);
g_signal_emit_by_name (display->screen, "startup-sequence-changed", sequence);
}
/**
* meta_display_open:
*
@@ -630,12 +622,6 @@ meta_display_open (void)
display->screen = NULL;
#ifdef HAVE_STARTUP_NOTIFICATION
display->sn_display = sn_display_new (display->xdisplay,
sn_error_trap_push,
sn_error_trap_pop);
#endif
/* Get events */
meta_display_init_events (display);
meta_display_init_events_x11 (display);
@@ -916,6 +902,10 @@ meta_display_open (void)
display->screen = screen;
display->startup_notification = meta_startup_notification_get (display);
g_signal_connect (display->startup_notification, "changed",
G_CALLBACK (on_startup_notification_changed), display);
meta_screen_init_workspaces (screen);
enable_compositor (display);
@@ -1100,6 +1090,7 @@ meta_display_close (MetaDisplay *display,
meta_display_remove_autoraise_callback (display);
g_clear_object (&display->startup_notification);
g_clear_object (&display->gesture_tracker);
if (display->focus_timeout_id)
@@ -1112,14 +1103,6 @@ meta_display_close (MetaDisplay *display,
meta_screen_free (display->screen, timestamp);
#ifdef HAVE_STARTUP_NOTIFICATION
if (display->sn_display)
{
sn_display_unref (display->sn_display);
display->sn_display = NULL;
}
#endif
/* Must be after all calls to meta_window_unmanage() since they
* unregister windows
*/

View File

@@ -85,11 +85,7 @@ struct _MetaScreen
/* Cache the current monitor */
int last_monitor_index;
#ifdef HAVE_STARTUP_NOTIFICATION
SnMonitorContext *sn_context;
GSList *startup_sequences;
guint startup_sequence_timeout;
#endif
Window wm_cm_selection_window;
guint work_area_later;

View File

@@ -71,11 +71,6 @@ static void prefs_changed_callback (MetaPreference pref,
static void set_desktop_geometry_hint (MetaScreen *screen);
static void set_desktop_viewport_hint (MetaScreen *screen);
#ifdef HAVE_STARTUP_NOTIFICATION
static void meta_screen_sn_event (SnMonitorEvent *event,
void *user_data);
#endif
static void on_monitors_changed (MetaMonitorManager *manager,
MetaScreen *screen);
@@ -730,17 +725,6 @@ meta_screen_new (MetaDisplay *display,
meta_prefs_add_listener (prefs_changed_callback, screen);
#ifdef HAVE_STARTUP_NOTIFICATION
screen->sn_context =
sn_monitor_context_new (screen->display->sn_display,
screen->number,
meta_screen_sn_event,
screen,
NULL);
screen->startup_sequences = NULL;
screen->startup_sequence_timeout = 0;
#endif
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
screen->number, screen->screen_name, screen->xroot);
@@ -800,24 +784,6 @@ meta_screen_free (MetaScreen *screen,
meta_screen_ungrab_keys (screen);
#ifdef HAVE_STARTUP_NOTIFICATION
g_slist_foreach (screen->startup_sequences,
(GFunc) sn_startup_sequence_unref, NULL);
g_slist_free (screen->startup_sequences);
screen->startup_sequences = NULL;
if (screen->startup_sequence_timeout != 0)
{
g_source_remove (screen->startup_sequence_timeout);
screen->startup_sequence_timeout = 0;
}
if (screen->sn_context)
{
sn_monitor_context_unref (screen->sn_context);
screen->sn_context = NULL;
}
#endif
meta_ui_free (screen->ui);
meta_stack_free (screen->stack);
@@ -2538,208 +2504,6 @@ meta_screen_unshow_desktop (MetaScreen *screen)
meta_screen_update_showing_desktop_hint (screen);
}
#ifdef HAVE_STARTUP_NOTIFICATION
static gboolean startup_sequence_timeout (void *data);
static void
update_startup_feedback (MetaScreen *screen)
{
if (screen->startup_sequences != NULL)
{
meta_topic (META_DEBUG_STARTUP,
"Setting busy cursor\n");
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
}
else
{
meta_topic (META_DEBUG_STARTUP,
"Setting default cursor\n");
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
}
}
static void
add_sequence (MetaScreen *screen,
SnStartupSequence *sequence)
{
meta_topic (META_DEBUG_STARTUP,
"Adding sequence %s\n",
sn_startup_sequence_get_id (sequence));
sn_startup_sequence_ref (sequence);
screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
sequence);
/* our timeout just polls every second, instead of bothering
* to compute exactly when we may next time out
*/
if (screen->startup_sequence_timeout == 0)
{
screen->startup_sequence_timeout = g_timeout_add_seconds (1,
startup_sequence_timeout,
screen);
g_source_set_name_by_id (screen->startup_sequence_timeout,
"[mutter] startup_sequence_timeout");
}
update_startup_feedback (screen);
}
static void
remove_sequence (MetaScreen *screen,
SnStartupSequence *sequence)
{
meta_topic (META_DEBUG_STARTUP,
"Removing sequence %s\n",
sn_startup_sequence_get_id (sequence));
screen->startup_sequences = g_slist_remove (screen->startup_sequences,
sequence);
if (screen->startup_sequences == NULL &&
screen->startup_sequence_timeout != 0)
{
g_source_remove (screen->startup_sequence_timeout);
screen->startup_sequence_timeout = 0;
}
update_startup_feedback (screen);
sn_startup_sequence_unref (sequence);
}
typedef struct
{
GSList *list;
GTimeVal now;
} CollectTimedOutData;
/* This should be fairly long, as it should never be required unless
* apps or .desktop files are buggy, and it's confusing if
* OpenOffice or whatever seems to stop launching - people
* might decide they need to launch it again.
*/
#define STARTUP_TIMEOUT 15000
static void
collect_timed_out_foreach (void *element,
void *data)
{
CollectTimedOutData *ctod = data;
SnStartupSequence *sequence = element;
long tv_sec, tv_usec;
double elapsed;
sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
elapsed =
((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
(ctod->now.tv_usec - tv_usec))) / 1000.0;
meta_topic (META_DEBUG_STARTUP,
"Sequence used %g seconds vs. %g max: %s\n",
elapsed, (double) STARTUP_TIMEOUT,
sn_startup_sequence_get_id (sequence));
if (elapsed > STARTUP_TIMEOUT)
ctod->list = g_slist_prepend (ctod->list, sequence);
}
static gboolean
startup_sequence_timeout (void *data)
{
MetaScreen *screen = data;
CollectTimedOutData ctod;
GSList *l;
ctod.list = NULL;
g_get_current_time (&ctod.now);
g_slist_foreach (screen->startup_sequences,
collect_timed_out_foreach,
&ctod);
for (l = ctod.list; l != NULL; l = l->next)
{
SnStartupSequence *sequence = l->data;
meta_topic (META_DEBUG_STARTUP,
"Timed out sequence %s\n",
sn_startup_sequence_get_id (sequence));
sn_startup_sequence_complete (sequence);
}
g_slist_free (ctod.list);
if (screen->startup_sequences != NULL)
{
return TRUE;
}
else
{
/* remove */
screen->startup_sequence_timeout = 0;
return FALSE;
}
}
static void
meta_screen_sn_event (SnMonitorEvent *event,
void *user_data)
{
MetaScreen *screen;
SnStartupSequence *sequence;
screen = user_data;
sequence = sn_monitor_event_get_startup_sequence (event);
sn_startup_sequence_ref (sequence);
switch (sn_monitor_event_get_type (event))
{
case SN_MONITOR_EVENT_INITIATED:
{
const char *wmclass;
wmclass = sn_startup_sequence_get_wmclass (sequence);
meta_topic (META_DEBUG_STARTUP,
"Received startup initiated for %s wmclass %s\n",
sn_startup_sequence_get_id (sequence),
wmclass ? wmclass : "(unset)");
add_sequence (screen, sequence);
}
break;
case SN_MONITOR_EVENT_COMPLETED:
{
meta_topic (META_DEBUG_STARTUP,
"Received startup completed for %s\n",
sn_startup_sequence_get_id (sequence));
remove_sequence (screen,
sn_monitor_event_get_startup_sequence (event));
}
break;
case SN_MONITOR_EVENT_CHANGED:
meta_topic (META_DEBUG_STARTUP,
"Received startup changed for %s\n",
sn_startup_sequence_get_id (sequence));
break;
case SN_MONITOR_EVENT_CANCELED:
meta_topic (META_DEBUG_STARTUP,
"Received startup canceled for %s\n",
sn_startup_sequence_get_id (sequence));
break;
}
g_signal_emit (G_OBJECT (screen), screen_signals[STARTUP_SEQUENCE_CHANGED], 0, sequence);
sn_startup_sequence_unref (sequence);
}
/**
* meta_screen_get_startup_sequences: (skip)
* @screen:
@@ -2751,7 +2515,6 @@ meta_screen_get_startup_sequences (MetaScreen *screen)
{
return screen->startup_sequences;
}
#endif
/* Sets the initial_timestamp and initial_workspace properties
* of a window according to information given us by the

View File

@@ -0,0 +1,48 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_STARTUP_NOTIFICATION_PRIVATE_H
#define META_STARTUP_NOTIFICATION_PRIVATE_H
#include "display-private.h"
#define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ())
G_DECLARE_FINAL_TYPE (MetaStartupNotification,
meta_startup_notification,
META, STARTUP_NOTIFICATION,
GObject)
MetaStartupNotification *
meta_startup_notification_get (MetaDisplay *display);
gboolean meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
XEvent *xevent);
void meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
const gchar *id);
GSList * meta_startup_notification_get_sequences (MetaStartupNotification *sn);
#endif /* META_STARTUP_NOTIFICATION_PRIVATE_H */

View File

@@ -0,0 +1,767 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib-object.h>
#include <meta/errors.h>
#include "display-private.h"
#include "screen-private.h"
#include "startup-notification-private.h"
/* This should be fairly long, as it should never be required unless
* apps or .desktop files are buggy, and it's confusing if
* OpenOffice or whatever seems to stop launching - people
* might decide they need to launch it again.
*/
#define STARTUP_TIMEOUT 15000000
typedef struct _MetaStartupNotificationSequence MetaStartupNotificationSequence;
typedef struct _MetaStartupNotificationSequenceClass MetaStartupNotificationSequenceClass;
enum {
PROP_SN_0,
PROP_SN_DISPLAY,
N_SN_PROPS
};
enum {
PROP_SEQ_0,
PROP_SEQ_ID,
PROP_SEQ_TIMESTAMP,
N_SEQ_PROPS
};
enum {
SN_CHANGED,
N_SN_SIGNALS
};
static guint sn_signals[N_SN_SIGNALS];
static GParamSpec *sn_props[N_SN_PROPS];
static GParamSpec *seq_props[N_SEQ_PROPS];
typedef struct
{
GSList *list;
gint64 now;
} CollectTimedOutData;
struct _MetaStartupNotification
{
GObject parent_instance;
MetaDisplay *display;
#ifdef HAVE_STARTUP_NOTIFICATION
SnDisplay *sn_display;
SnMonitorContext *sn_context;
#endif
GSList *startup_sequences;
guint startup_sequence_timeout;
};
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE \
(meta_startup_notification_sequence_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaStartupNotificationSequence,
meta_startup_notification_sequence,
META, STARTUP_NOTIFICATION_SEQUENCE,
GObject)
typedef struct {
gchar *id;
time_t timestamp;
} MetaStartupNotificationSequencePrivate;
struct _MetaStartupNotificationSequenceClass {
GObjectClass parent_class;
void (* complete) (MetaStartupNotificationSequence *sequence);
};
G_DEFINE_TYPE (MetaStartupNotification,
meta_startup_notification,
G_TYPE_OBJECT)
G_DEFINE_TYPE_WITH_PRIVATE (MetaStartupNotificationSequence,
meta_startup_notification_sequence,
G_TYPE_OBJECT)
#ifdef HAVE_STARTUP_NOTIFICATION
enum {
PROP_SEQ_X11_0,
PROP_SEQ_X11_SEQ,
N_SEQ_X11_PROPS
};
struct _MetaStartupNotificationSequenceX11 {
MetaStartupNotificationSequence parent_instance;
SnStartupSequence *seq;
};
static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS];
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11 \
(meta_startup_notification_sequence_x11_get_type ())
G_DECLARE_FINAL_TYPE (MetaStartupNotificationSequenceX11,
meta_startup_notification_sequence_x11,
META, STARTUP_NOTIFICATION_SEQUENCE_X11,
MetaStartupNotificationSequence)
G_DEFINE_TYPE (MetaStartupNotificationSequenceX11,
meta_startup_notification_sequence_x11,
META_TYPE_STARTUP_NOTIFICATION_SEQUENCE)
static void meta_startup_notification_ensure_timeout (MetaStartupNotification *sn);
#endif
static void
meta_startup_notification_update_feedback (MetaStartupNotification *sn)
{
MetaScreen *screen = sn->display->screen;
if (sn->startup_sequences != NULL)
{
meta_topic (META_DEBUG_STARTUP,
"Setting busy cursor\n");
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
}
else
{
meta_topic (META_DEBUG_STARTUP,
"Setting default cursor\n");
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
}
}
static void
meta_startup_notification_sequence_init (MetaStartupNotificationSequence *seq)
{
}
static void
meta_startup_notification_sequence_finalize (GObject *object)
{
MetaStartupNotificationSequence *seq;
MetaStartupNotificationSequencePrivate *priv;
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
priv = meta_startup_notification_sequence_get_instance_private (seq);
g_free (priv->id);
G_OBJECT_CLASS (meta_startup_notification_sequence_parent_class)->finalize (object);
}
static void
meta_startup_notification_sequence_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaStartupNotificationSequence *seq;
MetaStartupNotificationSequencePrivate *priv;
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
priv = meta_startup_notification_sequence_get_instance_private (seq);
switch (prop_id)
{
case PROP_SEQ_ID:
priv->id = g_value_dup_string (value);
break;
case PROP_SEQ_TIMESTAMP:
priv->timestamp = g_value_get_int64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_notification_sequence_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaStartupNotificationSequence *seq;
MetaStartupNotificationSequencePrivate *priv;
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
priv = meta_startup_notification_sequence_get_instance_private (seq);
switch (prop_id)
{
case PROP_SEQ_ID:
g_value_set_string (value, priv->id);
break;
case PROP_SEQ_TIMESTAMP:
g_value_set_int64 (value, priv->timestamp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_notification_sequence_class_init (MetaStartupNotificationSequenceClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_startup_notification_sequence_finalize;
object_class->set_property = meta_startup_notification_sequence_set_property;
object_class->get_property = meta_startup_notification_sequence_get_property;
seq_props[PROP_SEQ_ID] =
g_param_spec_string ("id",
"ID",
"ID",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
seq_props[PROP_SEQ_TIMESTAMP] =
g_param_spec_int64 ("timestamp",
"Timestamp",
"Timestamp",
G_MININT64, G_MAXINT64, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_SEQ_PROPS, seq_props);
}
static const gchar *
meta_startup_notification_sequence_get_id (MetaStartupNotificationSequence *seq)
{
MetaStartupNotificationSequencePrivate *priv;
priv = meta_startup_notification_sequence_get_instance_private (seq);
return priv->id;
}
#ifdef HAVE_STARTUP_NOTIFICATION
static gint64
meta_startup_notification_sequence_get_timestamp (MetaStartupNotificationSequence *seq)
{
MetaStartupNotificationSequencePrivate *priv;
priv = meta_startup_notification_sequence_get_instance_private (seq);
return priv->timestamp;
}
static void
meta_startup_notification_sequence_complete (MetaStartupNotificationSequence *seq)
{
MetaStartupNotificationSequenceClass *klass;
klass = META_STARTUP_NOTIFICATION_SEQUENCE_GET_CLASS (seq);
if (klass->complete)
klass->complete (seq);
}
#endif
#ifdef HAVE_STARTUP_NOTIFICATION
static void
meta_startup_notification_sequence_x11_complete (MetaStartupNotificationSequence *seq)
{
MetaStartupNotificationSequenceX11 *seq_x11;
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (seq);
sn_startup_sequence_complete (seq_x11->seq);
}
static void
meta_startup_notification_sequence_x11_finalize (GObject *object)
{
MetaStartupNotificationSequenceX11 *seq;
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
sn_startup_sequence_unref (seq->seq);
G_OBJECT_CLASS (meta_startup_notification_sequence_x11_parent_class)->finalize (object);
}
static void
meta_startup_notification_sequence_x11_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaStartupNotificationSequenceX11 *seq;
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
switch (prop_id)
{
case PROP_SEQ_X11_SEQ:
seq->seq = g_value_get_pointer (value);
sn_startup_sequence_ref (seq->seq);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_notification_sequence_x11_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaStartupNotificationSequenceX11 *seq;
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
switch (prop_id)
{
case PROP_SEQ_X11_SEQ:
g_value_set_pointer (value, seq->seq);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_notification_sequence_x11_init (MetaStartupNotificationSequenceX11 *seq)
{
}
static void
meta_startup_notification_sequence_x11_class_init (MetaStartupNotificationSequenceX11Class *klass)
{
MetaStartupNotificationSequenceClass *seq_class;
GObjectClass *object_class;
seq_class = META_STARTUP_NOTIFICATION_SEQUENCE_CLASS (klass);
seq_class->complete = meta_startup_notification_sequence_x11_complete;
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_startup_notification_sequence_x11_finalize;
object_class->set_property = meta_startup_notification_sequence_x11_set_property;
object_class->get_property = meta_startup_notification_sequence_x11_get_property;
seq_x11_props[PROP_SEQ_X11_SEQ] =
g_param_spec_pointer ("seq",
"Sequence",
"Sequence",
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_SEQ_X11_PROPS,
seq_x11_props);
}
static MetaStartupNotificationSequence *
meta_startup_notification_sequence_x11_new (SnStartupSequence *seq)
{
return g_object_new (META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11,
"id", sn_startup_sequence_get_id (seq),
"timestamp", sn_startup_sequence_get_timestamp (seq) * 1000,
"seq", seq,
NULL);
}
static void
meta_startup_notification_add_sequence_internal (MetaStartupNotification *sn,
MetaStartupNotificationSequence *seq)
{
sn->startup_sequences = g_slist_prepend (sn->startup_sequences,
g_object_ref (seq));
meta_startup_notification_ensure_timeout (sn);
meta_startup_notification_update_feedback (sn);
}
static void
collect_timed_out_foreach (void *element,
void *data)
{
MetaStartupNotificationSequence *sequence = element;
CollectTimedOutData *ctod = data;
gint64 elapsed, timestamp;
timestamp = meta_startup_notification_sequence_get_timestamp (sequence);
elapsed = ctod->now - timestamp;
meta_topic (META_DEBUG_STARTUP,
"Sequence used %ld ms vs. %d max: %s\n",
elapsed, STARTUP_TIMEOUT,
meta_startup_notification_sequence_get_id (sequence));
if (elapsed > STARTUP_TIMEOUT)
ctod->list = g_slist_prepend (ctod->list, sequence);
}
static gboolean
startup_sequence_timeout (void *data)
{
MetaStartupNotification *sn = data;
CollectTimedOutData ctod;
GSList *l;
ctod.list = NULL;
ctod.now = g_get_monotonic_time ();
g_slist_foreach (sn->startup_sequences,
collect_timed_out_foreach,
&ctod);
for (l = ctod.list; l != NULL; l = l->next)
{
MetaStartupNotificationSequence *sequence = l->data;
meta_topic (META_DEBUG_STARTUP,
"Timed out sequence %s\n",
meta_startup_notification_sequence_get_id (sequence));
meta_startup_notification_sequence_complete (sequence);
}
g_slist_free (ctod.list);
if (sn->startup_sequences != NULL)
{
return TRUE;
}
else
{
/* remove */
sn->startup_sequence_timeout = 0;
return FALSE;
}
}
static void
meta_startup_notification_ensure_timeout (MetaStartupNotification *sn)
{
if (sn->startup_sequence_timeout != 0)
return;
/* our timeout just polls every second, instead of bothering
* to compute exactly when we may next time out
*/
sn->startup_sequence_timeout = g_timeout_add_seconds (1,
startup_sequence_timeout,
sn);
g_source_set_name_by_id (sn->startup_sequence_timeout,
"[mutter] startup_sequence_timeout");
}
#endif
static void
meta_startup_notification_remove_sequence_internal (MetaStartupNotification *sn,
MetaStartupNotificationSequence *seq)
{
sn->startup_sequences = g_slist_remove (sn->startup_sequences, seq);
meta_startup_notification_update_feedback (sn);
if (sn->startup_sequences == NULL &&
sn->startup_sequence_timeout != 0)
{
g_source_remove (sn->startup_sequence_timeout);
sn->startup_sequence_timeout = 0;
}
g_object_unref (seq);
}
static MetaStartupNotificationSequence *
meta_startup_notification_lookup_sequence (MetaStartupNotification *sn,
const gchar *id)
{
MetaStartupNotificationSequence *seq;
const gchar *seq_id;
GSList *l;
for (l = sn->startup_sequences; l; l = l->next)
{
seq = l->data;
seq_id = meta_startup_notification_sequence_get_id (seq);
if (g_str_equal (seq_id, id))
return l->data;
}
return NULL;
}
static void
meta_startup_notification_init (MetaStartupNotification *sn)
{
}
static void
meta_startup_notification_finalize (GObject *object)
{
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
#ifdef HAVE_STARTUP_NOTIFICATION
sn_monitor_context_unref (sn->sn_context);
sn_display_unref (sn->sn_display);
#endif
if (sn->startup_sequence_timeout)
g_source_remove (sn->startup_sequence_timeout);
g_slist_foreach (sn->startup_sequences, (GFunc) g_object_unref, NULL);
g_slist_free (sn->startup_sequences);
sn->startup_sequences = NULL;
G_OBJECT_CLASS (meta_startup_notification_parent_class)->finalize (object);
}
static void
meta_startup_notification_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
switch (prop_id)
{
case PROP_SN_DISPLAY:
sn->display = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_notification_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
switch (prop_id)
{
case PROP_SN_DISPLAY:
g_value_set_object (value, sn->display);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
#ifdef HAVE_STARTUP_NOTIFICATION
static void
sn_error_trap_push (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_error_trap_push (display);
}
static void
sn_error_trap_pop (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_error_trap_pop (display);
}
static void
meta_startup_notification_sn_event (SnMonitorEvent *event,
void *user_data)
{
MetaStartupNotification *sn = user_data;
MetaStartupNotificationSequence *seq;
SnStartupSequence *sequence;
sequence = sn_monitor_event_get_startup_sequence (event);
sn_startup_sequence_ref (sequence);
switch (sn_monitor_event_get_type (event))
{
case SN_MONITOR_EVENT_INITIATED:
{
const char *wmclass;
wmclass = sn_startup_sequence_get_wmclass (sequence);
meta_topic (META_DEBUG_STARTUP,
"Received startup initiated for %s wmclass %s\n",
sn_startup_sequence_get_id (sequence),
wmclass ? wmclass : "(unset)");
seq = meta_startup_notification_sequence_x11_new (sequence);
meta_startup_notification_add_sequence_internal (sn, seq);
g_object_unref (seq);
}
break;
case SN_MONITOR_EVENT_COMPLETED:
{
meta_topic (META_DEBUG_STARTUP,
"Received startup completed for %s\n",
sn_startup_sequence_get_id (sequence));
meta_startup_notification_remove_sequence (sn, sn_startup_sequence_get_id (sequence));
}
break;
case SN_MONITOR_EVENT_CHANGED:
meta_topic (META_DEBUG_STARTUP,
"Received startup changed for %s\n",
sn_startup_sequence_get_id (sequence));
break;
case SN_MONITOR_EVENT_CANCELED:
meta_topic (META_DEBUG_STARTUP,
"Received startup canceled for %s\n",
sn_startup_sequence_get_id (sequence));
break;
}
g_signal_emit (sn, sn_signals[SN_CHANGED], 0, sequence);
sn_startup_sequence_unref (sequence);
}
#endif
static void
meta_startup_notification_constructed (GObject *object)
{
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
g_assert (sn->display != NULL);
#ifdef HAVE_STARTUP_NOTIFICATION
sn->sn_display = sn_display_new (sn->display->xdisplay,
sn_error_trap_push,
sn_error_trap_pop);
sn->sn_context =
sn_monitor_context_new (sn->sn_display,
sn->display->screen->number,
meta_startup_notification_sn_event,
sn,
NULL);
#endif
sn->startup_sequences = NULL;
sn->startup_sequence_timeout = 0;
}
static void
meta_startup_notification_class_init (MetaStartupNotificationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = meta_startup_notification_constructed;
object_class->finalize = meta_startup_notification_finalize;
object_class->set_property = meta_startup_notification_set_property;
object_class->get_property = meta_startup_notification_get_property;
sn_props[PROP_SN_DISPLAY] =
g_param_spec_object ("display",
"Display",
"Display",
META_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
sn_signals[SN_CHANGED] =
g_signal_new ("changed",
META_TYPE_STARTUP_NOTIFICATION,
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_POINTER);
g_object_class_install_properties (object_class, N_SN_PROPS, sn_props);
}
MetaStartupNotification *
meta_startup_notification_get (MetaDisplay *display)
{
static MetaStartupNotification *notification = NULL;
if (!notification)
notification = g_object_new (META_TYPE_STARTUP_NOTIFICATION,
"display", display,
NULL);
return notification;
}
void
meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
const gchar *id)
{
MetaStartupNotificationSequence *seq;
seq = meta_startup_notification_lookup_sequence (sn, id);
if (seq)
meta_startup_notification_remove_sequence_internal (sn, seq);
}
gboolean
meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
XEvent *xevent)
{
#ifdef HAVE_STARTUP_NOTIFICATION
return sn_display_process_event (sn->sn_display, xevent);
#endif
return FALSE;
}
GSList *
meta_startup_notification_get_sequences (MetaStartupNotification *sn)
{
GSList *sequences = NULL;
#ifdef HAVE_STARTUP_NOTIFICATION
GSList *l;
/* We return a list of SnStartupSequences here */
for (l = sn->startup_sequences; l; l = l->next)
{
MetaStartupNotificationSequenceX11 *seq_x11;
if (!META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data))
continue;
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data);
sequences = g_slist_prepend (sequences, seq_x11->seq);
}
#endif
return sequences;
}

View File

@@ -7388,10 +7388,31 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
g_object_thaw_notify (G_OBJECT (window));
}
static gboolean
check_transient_for_loop (MetaWindow *window,
MetaWindow *parent)
{
while (parent)
{
if (parent->transient_for == window)
return TRUE;
parent = parent->transient_for;
}
return FALSE;
}
void
meta_window_set_transient_for (MetaWindow *window,
MetaWindow *parent)
{
if (check_transient_for_loop (window, parent))
{
meta_warning ("Setting %s transient for %s would create a loop.\n",
window->desc, parent->desc);
return;
}
if (meta_window_appears_focused (window) && window->transient_for != NULL)
meta_window_propagate_focus_appearance (window, FALSE);

View File

@@ -51,32 +51,30 @@ void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_clear_pointer (&buffer->texture, cogl_object_unref);
g_warn_if_fail (buffer->use_count == 0);
if (buffer->accessible)
meta_wayland_buffer_release_control (buffer);
g_clear_pointer (&buffer->texture, cogl_object_unref);
}
}
void
meta_wayland_buffer_take_control (MetaWaylandBuffer *buffer)
meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer)
{
if (buffer->accessible)
meta_fatal ("buffer control taken twice");
buffer->accessible = TRUE;
buffer->use_count++;
}
void
meta_wayland_buffer_release_control (MetaWaylandBuffer *buffer)
meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer)
{
if (!buffer->accessible)
meta_fatal ("buffer released when not in control");
g_return_if_fail (buffer->use_count != 0);
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
buffer->accessible = FALSE;
buffer->use_count--;
if (buffer->use_count == 0)
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
MetaWaylandBuffer *
@@ -114,8 +112,7 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
CoglTexture *texture;
struct wl_shm_buffer *shm_buffer;
if (!buffer->accessible)
meta_warning ("attempted to process damage on uncommitted buffer");
g_return_val_if_fail (buffer->use_count != 0, NULL);
if (buffer->texture)
goto out;
@@ -140,9 +137,6 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
buffer->texture = texture;
if (shm_buffer)
buffer->copied_data = TRUE;
out:
return buffer->texture;
}
@@ -153,8 +147,7 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
{
struct wl_shm_buffer *shm_buffer;
if (!buffer->accessible)
meta_warning ("attempted to process damage on uncommitted buffer");
g_return_if_fail (buffer->use_count != 0);
shm_buffer = wl_shm_buffer_get (buffer->resource);

View File

@@ -39,16 +39,14 @@ struct _MetaWaylandBuffer
CoglTexture *texture;
uint32_t ref_count;
uint32_t accessible : 1;
uint32_t copied_data : 1;
uint32_t use_count;
};
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_take_control (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_release_control (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer);
CoglTexture * meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region);

View File

@@ -31,4 +31,10 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDataSourceWayland,
META, WAYLAND_DATA_SOURCE_WAYLAND,
MetaWaylandDataSource);
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
meta_wayland_data_source_primary,
META, WAYLAND_DATA_SOURCE_PRIMARY,
MetaWaylandDataSourceWayland);
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */

View File

@@ -37,6 +37,8 @@
#include "meta-wayland-private.h"
#include "meta-dnd-actor-private.h"
#include "primary-selection-unstable-v1-server-protocol.h"
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
@@ -70,13 +72,22 @@ typedef struct _MetaWaylandDataSourceWayland
struct wl_resource *resource;
} MetaWaylandDataSourceWayland;
typedef struct _MetaWaylandDataSourcePrimary
{
MetaWaylandDataSourceWayland parent;
} MetaWaylandDataSourcePrimary;
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
G_TYPE_OBJECT);
G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
META_TYPE_WAYLAND_DATA_SOURCE);
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
static MetaWaylandDataSource *
meta_wayland_data_source_wayland_new (struct wl_resource *resource);
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource);
static void
drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
@@ -160,7 +171,8 @@ static void
meta_wayland_data_source_target (MetaWaylandDataSource *source,
const char *mime_type)
{
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
}
void
@@ -430,6 +442,32 @@ static const struct wl_data_offer_interface data_offer_interface = {
data_offer_set_actions,
};
static void
primary_offer_receive (struct wl_client *client, struct wl_resource *resource,
const char *mime_type, int32_t fd, uint32_t serial)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source = offer->source;
MetaWaylandSeat *seat;
if (!source)
{
close (fd);
return;
}
seat = meta_wayland_data_source_get_seat (source);
if (serial == seat->keyboard.key_serial ||
serial == seat->pointer.click_serial)
meta_wayland_data_source_send (source, mime_type, fd);
}
static const struct zwp_primary_selection_offer_v1_interface primary_offer_interface = {
primary_offer_receive,
data_offer_destroy,
};
static void
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
{
@@ -500,6 +538,35 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
return offer->resource;
}
static struct wl_resource *
meta_wayland_data_source_send_primary_offer (MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
char **p;
offer->source = source;
g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)&offer->source);
offer->resource = wl_resource_create (wl_resource_get_client (target),
&zwp_primary_selection_offer_v1_interface,
wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource,
&primary_offer_interface,
offer,
destroy_data_offer);
zwp_primary_selection_device_v1_send_data_offer (target, offer->resource);
wl_array_for_each (p, &priv->mime_types)
zwp_primary_selection_offer_v1_send_offer (offer->resource, *p);
meta_wayland_data_source_set_current_offer (source, offer);
return offer->resource;
}
static void
data_source_offer (struct wl_client *client,
struct wl_resource *resource, const char *type)
@@ -561,6 +628,11 @@ static struct wl_data_source_interface data_source_interface = {
data_source_set_actions
};
static struct zwp_primary_selection_source_v1_interface primary_source_interface = {
data_source_offer,
data_source_destroy,
};
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
@@ -1108,6 +1180,43 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
data_source_class->drag_finished = meta_wayland_source_drag_finished;
}
static void
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = (MetaWaylandDataSourceWayland *) source;
zwp_primary_selection_source_v1_send_send (source_wayland->resource,
mime_type, fd);
}
static void
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = (MetaWaylandDataSourceWayland *) source;
zwp_primary_selection_source_v1_send_cancelled (source_wayland->resource);
}
static void
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
{
}
static void
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_send;
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
data_source_class->target = NULL;
}
static void
meta_wayland_data_source_finalize (GObject *object)
{
@@ -1299,6 +1408,7 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
selection_data_source_destroyed,
data_device);
@@ -1351,6 +1461,93 @@ static const struct wl_data_device_interface data_device_interface = {
data_device_release,
};
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevice *data_device = data;
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_client *focus_client = NULL;
data_device->primary_data_source = NULL;
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
if (focus_client)
{
struct wl_resource *data_device_resource;
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
void
meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource, *offer;
struct wl_client *focus_client;
if (data_device->primary_data_source)
{
meta_wayland_data_source_cancel (data_device->primary_data_source);
g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
primary_source_destroyed,
data_device);
data_device->primary_data_source = NULL;
}
data_device->primary_data_source = source;
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
if (focus_client)
{
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
{
if (data_device->primary_data_source)
{
offer = meta_wayland_data_source_send_primary_offer (data_device->primary_data_source,
data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
else
{
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
}
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
}
wl_signal_emit (&data_device->primary_ownership_signal, source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource)
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source;
source = wl_resource_get_user_data (source_resource);
meta_wayland_data_device_set_primary (data_device, source);
}
static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
primary_device_set_selection,
data_device_release,
};
static void
destroy_data_source (struct wl_resource *resource)
{
@@ -1389,6 +1586,48 @@ static const struct wl_data_device_manager_interface manager_interface = {
get_data_device
};
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->data_device, unbind_resource);
wl_list_insert (&seat->data_device.primary_resource_list, wl_resource_get_link (cr));
}
static void
primary_device_manager_destroy (struct wl_client *client,
struct wl_resource *manager_resource)
{
}
static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
primary_device_manager_destroy
};
static void
bind_manager (struct wl_client *client,
void *data, guint32 version, guint32 id)
@@ -1398,6 +1637,19 @@ bind_manager (struct wl_client *client,
wl_resource_set_implementation (resource, &manager_interface, NULL, NULL);
}
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
{
@@ -1406,13 +1658,20 @@ meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
META_WL_DATA_DEVICE_MANAGER_VERSION,
NULL, bind_manager) == NULL)
g_error ("Could not create data_device");
if (wl_global_create (compositor->wayland_display,
&zwp_primary_selection_device_manager_v1_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->primary_resource_list);
wl_signal_init (&data_device->selection_ownership_signal);
wl_signal_init (&data_device->primary_ownership_signal);
wl_signal_init (&data_device->dnd_ownership_signal);
}
@@ -1435,17 +1694,32 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
return;
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (!data_device_resource)
return;
source = data_device->selection_data_source;
if (source)
if (data_device_resource)
{
offer = meta_wayland_data_source_send_offer (source, data_device_resource);
wl_data_device_send_selection (data_device_resource, offer);
source = data_device->selection_data_source;
if (source)
{
offer = meta_wayland_data_source_send_offer (source, data_device_resource);
wl_data_device_send_selection (data_device_resource, offer);
}
else
wl_data_device_send_selection (data_device_resource, NULL);
}
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
{
source = data_device->primary_data_source;
if (source)
{
offer = meta_wayland_data_source_send_primary_offer (source, data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
else
{
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
else
wl_data_device_send_selection (data_device_resource, NULL);
}
gboolean
@@ -1486,6 +1760,19 @@ meta_wayland_data_source_wayland_new (struct wl_resource *resource)
return META_WAYLAND_DATA_SOURCE (source_wayland);
}
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source_wayland =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
source_wayland->resource = resource;
wl_resource_set_implementation (resource, &primary_source_interface,
source_wayland, destroy_data_source);
return META_WAYLAND_DATA_SOURCE (source_wayland);
}
gboolean
meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type)

View File

@@ -57,13 +57,16 @@ struct _MetaWaylandDataDevice
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
MetaWaylandDataSource *dnd_data_source;
MetaWaylandDataSource *primary_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
struct wl_list primary_resource_list;
MetaWaylandDragGrab *current_grab;
struct wl_client *focus_client;
struct wl_signal selection_ownership_signal;
struct wl_signal dnd_ownership_signal;
struct wl_signal primary_ownership_signal;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -80,6 +83,8 @@ void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_de
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source,
guint32 serial);
void meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type);

View File

@@ -400,6 +400,9 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
time = clutter_event_get_time (event);
serial = wl_display_next_serial (display);
if (event->type == CLUTTER_BUTTON_PRESS)
pointer->click_serial = serial;
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
{
wl_pointer_send_button (resource, serial,

View File

@@ -174,6 +174,25 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
}
}
static void
surface_use_buffer (MetaWaylandSurface *surface)
{
g_return_if_fail (!surface->using_buffer);
meta_wayland_buffer_ref_use_count (surface->buffer);
surface->using_buffer = TRUE;
}
static void
surface_stop_using_buffer (MetaWaylandSurface *surface)
{
if (!surface->using_buffer)
return;
meta_wayland_buffer_unref_use_count (surface->buffer);
surface->using_buffer = FALSE;
}
static void
surface_set_buffer (MetaWaylandSurface *surface,
MetaWaylandBuffer *buffer)
@@ -184,6 +203,8 @@ surface_set_buffer (MetaWaylandSurface *surface,
if (surface->buffer)
{
wl_list_remove (&surface->buffer_destroy_listener.link);
surface_stop_using_buffer (surface);
meta_wayland_buffer_unref (surface->buffer);
}
@@ -345,6 +366,12 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
queue_surface_actor_frame_callbacks (surface, pending);
/* If there's no new buffer pending, then there's nothing else to
* do
*/
if (!pending->newly_attached)
return;
if (META_IS_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (surface->role))
{
/* For wl_shell, it's equivalent to an unmap. Semantics
@@ -642,6 +669,8 @@ static void
apply_pending_state (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
gboolean release_new_buffer = FALSE;
if (pending->newly_attached)
{
if (!surface->buffer && surface->window)
@@ -649,11 +678,18 @@ apply_pending_state (MetaWaylandSurface *surface,
surface_set_buffer (surface, pending->buffer);
if (pending->buffer)
if (pending->buffer && !surface->using_buffer)
{
meta_wayland_buffer_take_control (pending->buffer);
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (pending->buffer->resource);
surface_use_buffer (surface);
CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
/* Release the buffer as soon as possible, so the client can reuse it
*/
if (shm_buffer)
release_new_buffer = TRUE;
}
}
@@ -663,8 +699,8 @@ apply_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage);
if (pending->buffer && pending->buffer->copied_data)
meta_wayland_buffer_release_control (pending->buffer);
if (release_new_buffer)
surface_stop_using_buffer (surface);
surface->offset_x += pending->dx;
surface->offset_y += pending->dy;
@@ -2029,8 +2065,21 @@ get_gtk_surface (struct wl_client *client,
wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
}
static void
set_startup_id (struct wl_client *client,
struct wl_resource *resource,
const char *startup_id)
{
MetaDisplay *display;
display = meta_get_display ();
meta_startup_notification_remove_sequence (display->startup_notification,
startup_id);
}
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
get_gtk_surface
get_gtk_surface,
set_startup_id
};
static void
@@ -2044,7 +2093,7 @@ bind_gtk_shell (struct wl_client *client,
resource = wl_resource_create (client, &gtk_shell_interface, version, id);
if (version != META_GTK_SHELL_VERSION)
if (version < 2)
{
wl_resource_post_error (resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,

View File

@@ -152,6 +152,7 @@ struct _MetaWaylandSurface
MetaWaylandSurfaceRole *role;
MetaWindow *window;
MetaWaylandBuffer *buffer;
gboolean using_buffer;
struct wl_listener buffer_destroy_listener;
cairo_region_t *input_region;
cairo_region_t *opaque_region;

View File

@@ -42,7 +42,7 @@
#define META_WL_SEAT_VERSION 5
#define META_WL_OUTPUT_VERSION 2
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL_VERSION 2
#define META_GTK_SHELL_VERSION 3
#define META_WL_SUBCOMPOSITOR_VERSION 1
#define META_ZWP_POINTER_GESTURES_V1_VERSION 1

View File

@@ -91,6 +91,7 @@ struct _MetaWaylandDataSourceXWayland
struct _MetaXWaylandSelection {
MetaSelectionBridge clipboard;
MetaSelectionBridge primary;
MetaDndBridge dnd;
};
@@ -396,6 +397,8 @@ atom_to_selection_bridge (MetaWaylandCompositor *compositor,
if (selection_atom == selection_data->clipboard.selection_atom)
return &selection_data->clipboard;
else if (selection_atom == selection_data->primary.selection_atom)
return &selection_data->primary;
else if (selection_atom == selection_data->dnd.selection.selection_atom)
return &selection_data->dnd.selection;
else
@@ -530,6 +533,8 @@ data_device_get_active_source_for_atom (MetaWaylandDataDevice *data_device,
{
if (selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
return data_device->selection_data_source;
else if (selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
return data_device->primary_data_source;
else if (selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
return data_device->dnd_data_source;
else
@@ -1058,6 +1063,10 @@ meta_xwayland_selection_get_x11_targets (MetaWaylandCompositor *compositor,
meta_wayland_data_device_set_selection (&compositor->seat->data_device, data_source,
wl_display_next_serial (compositor->wayland_display));
}
else if (selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
{
meta_wayland_data_device_set_primary (&compositor->seat->data_device, data_source);
}
}
else
g_object_unref (data_source);
@@ -1529,7 +1538,8 @@ meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *c
if (!selection)
return FALSE;
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD") ||
selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
{
if (event->owner == None)
{
@@ -1712,6 +1722,9 @@ meta_xwayland_init_selection (void)
init_selection_bridge (&manager->selection_data->clipboard,
gdk_x11_get_xatom_by_name ("CLIPBOARD"),
&compositor->seat->data_device.selection_ownership_signal);
init_selection_bridge (&manager->selection_data->primary,
gdk_x11_get_xatom_by_name ("PRIMARY"),
&compositor->seat->data_device.primary_ownership_signal);
init_selection_bridge (&manager->selection_data->dnd.selection,
xdnd_atoms[ATOM_DND_SELECTION],
&compositor->seat->data_device.dnd_ownership_signal);
@@ -1730,6 +1743,7 @@ meta_xwayland_shutdown_selection (void)
meta_xwayland_shutdown_dnd (manager);
shutdown_selection_bridge (&selection->clipboard);
shutdown_selection_bridge (&selection->primary);
shutdown_selection_bridge (&selection->dnd.selection);
g_slice_free (MetaXWaylandSelection, selection);

View File

@@ -1,6 +1,6 @@
<protocol name="gtk">
<interface name="gtk_shell" version="2">
<interface name="gtk_shell" version="3">
<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
@@ -23,9 +23,13 @@
<arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="set_startup_id" since="3">
<arg name="startup_id" type="string" allow-null="true"/>
</request>
</interface>
<interface name="gtk_surface" version="2">
<interface name="gtk_surface" version="3">
<request name="set_dbus_properties">
<arg name="application_id" type="string" allow-null="true"/>
<arg name="app_menu_path" type="string" allow-null="true"/>

View File

@@ -1671,13 +1671,12 @@ meta_display_handle_xevent (MetaDisplay *display,
meta_spew_event_print (display, event);
#endif
#ifdef HAVE_STARTUP_NOTIFICATION
if (sn_display_process_event (display->sn_display, event))
if (meta_startup_notification_handle_xevent (display->startup_notification,
event))
{
bypass_gtk = bypass_compositor = TRUE;
goto out;
}
#endif
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () &&