[Spice-commits] 8 commits - gtk/channel-inputs.c gtk/channel-main.c gtk/channel-record.c gtk/channel-smartcard.c gtk/channel-usbredir.c gtk/Makefile.am gtk/map-file gtk/smartcard-manager.c gtk/spice-channel.c gtk/spice-channel-priv.h gtk/spice-gtk-session.c gtk/spice-gtk-session-priv.h gtk/spice-session.c gtk/spice-session.h gtk/spice-session-priv.h gtk/spice-util.c gtk/spice-util.h gtk/spice-util-priv.h gtk/spice-widget.c gtk/spice-widget-priv.h gtk/spicy.c

Marc-André Lureau elmarco at kemper.freedesktop.org
Thu Nov 24 04:29:35 PST 2011


 gtk/Makefile.am              |    6 +-
 gtk/channel-inputs.c         |   22 +++++++-
 gtk/channel-main.c           |    5 +
 gtk/channel-record.c         |    5 +
 gtk/channel-smartcard.c      |    3 +
 gtk/channel-usbredir.c       |    3 +
 gtk/map-file                 |   24 ++++----
 gtk/smartcard-manager.c      |    2 
 gtk/spice-channel-priv.h     |    2 
 gtk/spice-channel.c          |   41 ++++++++++++++-
 gtk/spice-gtk-session-priv.h |    1 
 gtk/spice-gtk-session.c      |   17 +++++-
 gtk/spice-session-priv.h     |    1 
 gtk/spice-session.c          |   37 +++++++++++++
 gtk/spice-session.h          |    1 
 gtk/spice-util-priv.h        |    5 -
 gtk/spice-util.c             |   14 ++++-
 gtk/spice-util.h             |    5 +
 gtk/spice-widget-priv.h      |    1 
 gtk/spice-widget.c           |  117 +++++++++++++++++++++++++++++++------------
 gtk/spicy.c                  |    6 ++
 21 files changed, 261 insertions(+), 57 deletions(-)

New commits:
commit b6b41fdbc37d5a83d4f89922933ae56dd867e890
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 23 01:41:57 2011 +0100

    Do not send specific messages in read-only

diff --git a/gtk/channel-inputs.c b/gtk/channel-inputs.c
index f6c4a3e..bacbba3 100644
--- a/gtk/channel-inputs.c
+++ b/gtk/channel-inputs.c
@@ -215,6 +215,9 @@ static void send_position(SpiceInputsChannel *channel)
 {
     SpiceMsgOut *msg;
 
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
+
     msg = mouse_position(channel);
     if (!msg) /* if no motion */
         return;
@@ -228,6 +231,9 @@ static void send_motion(SpiceInputsChannel *channel)
 {
     SpiceMsgOut *msg;
 
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
+
     msg = mouse_motion(channel);
     if (!msg) /* if no motion */
         return;
@@ -382,6 +388,8 @@ void spice_inputs_button_press(SpiceInputsChannel *channel, gint button,
 
     if (SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_READY)
         return;
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     c = channel->priv;
     switch (button) {
@@ -428,6 +436,8 @@ void spice_inputs_button_release(SpiceInputsChannel *channel, gint button,
 
     if (SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_READY)
         return;
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     c = channel->priv;
     switch (button) {
@@ -442,7 +452,7 @@ void spice_inputs_button_release(SpiceInputsChannel *channel, gint button,
         break;
     }
 
-    c->bs  = button_state;
+    c->bs = button_state;
     send_motion(channel);
     send_position(channel);
 
@@ -471,6 +481,8 @@ void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode)
     g_return_if_fail(SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_UNCONNECTED);
     if (SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_READY)
         return;
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     SPICE_DEBUG("%s: scancode %d", __FUNCTION__, scancode);
     if (scancode < 0x100) {
@@ -502,6 +514,8 @@ void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode)
     g_return_if_fail(SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_UNCONNECTED);
     if (SPICE_CHANNEL(channel)->priv->state != SPICE_CHANNEL_STATE_READY)
         return;
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     SPICE_DEBUG("%s: scancode %d", __FUNCTION__, scancode);
     if (scancode < 0x100) {
@@ -552,6 +566,9 @@ void spice_inputs_set_key_locks(SpiceInputsChannel *channel, guint locks)
 {
     SpiceMsgOut *msg;
 
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
+
     msg = set_key_locks(channel, locks);
     if (!msg) /* you can set_key_locks() even if the channel is not ready */
         return;
@@ -566,6 +583,9 @@ static void spice_inputs_channel_up(SpiceChannel *channel)
     SpiceInputsChannelPrivate *c = SPICE_INPUTS_CHANNEL(channel)->priv;
     SpiceMsgOut *msg;
 
+    if (spice_channel_get_read_only(channel))
+        return;
+
     msg = set_key_locks(SPICE_INPUTS_CHANNEL(channel), c->locks);
     spice_msg_out_send_internal(msg);
     spice_msg_out_unref(msg);
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 90eb0fd..b2d44b6 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -1054,11 +1054,14 @@ static void set_mouse_mode(SpiceMainChannel *channel, uint32_t supported, uint32
     }
 
     /* switch to client mode if possible */
-    if ((supported & SPICE_MOUSE_MODE_CLIENT) && (current != SPICE_MOUSE_MODE_CLIENT)) {
+    if (!spice_channel_get_read_only(SPICE_CHANNEL(channel)) &&
+        supported & SPICE_MOUSE_MODE_CLIENT &&
+        current != SPICE_MOUSE_MODE_CLIENT) {
         SpiceMsgcMainMouseModeRequest req = {
             .mode = SPICE_MOUSE_MODE_CLIENT,
         };
         SpiceMsgOut *out;
+
         out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST);
         out->marshallers->msgc_main_mouse_mode_request(out->marshaller, &req);
         spice_msg_out_send_internal(out);
diff --git a/gtk/channel-record.c b/gtk/channel-record.c
index 443337c..bb66c3b 100644
--- a/gtk/channel-record.c
+++ b/gtk/channel-record.c
@@ -277,6 +277,8 @@ static void spice_record_mode(SpiceRecordChannel *channel, uint32_t time,
     SpiceMsgOut *msg;
 
     g_return_if_fail(channel != NULL);
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     m.mode = mode;
     m.time = time;
@@ -309,6 +311,8 @@ static void spice_record_start_mark(SpiceRecordChannel *channel, uint32_t time)
     SpiceMsgOut *msg;
 
     g_return_if_fail(channel != NULL);
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
 
     m.time = time;
 
@@ -336,6 +340,7 @@ void spice_record_send_data(SpiceRecordChannel *channel, gpointer data,
     uint8_t *celt_buf = NULL;
 
     g_return_if_fail(channel != NULL);
+    g_return_if_fail(spice_channel_get_read_only(SPICE_CHANNEL(channel)) == FALSE);
 
     rc = channel->priv;
 
diff --git a/gtk/channel-smartcard.c b/gtk/channel-smartcard.c
index 5fec217..c5aa17b 100644
--- a/gtk/channel-smartcard.c
+++ b/gtk/channel-smartcard.c
@@ -281,6 +281,9 @@ static void smartcard_message_send(SpiceSmartcardChannel *channel,
 {
     SpiceSmartcardChannelMessage *message;
 
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
+
     SPICE_DEBUG("smartcard: send message %d, %s",
                 msg_type, queue ? "queued" : "now");
     if (!queue) {
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 9479b6b..00647b6 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -350,6 +350,9 @@ void spice_usbredir_channel_do_write(SpiceUsbredirChannel *channel)
 {
     SpiceUsbredirChannelPrivate *priv = channel->priv;
 
+    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
+        return;
+
     /* No recursion allowed! */
     g_return_if_fail(priv->msg_out == NULL);
 
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index df661f8..83e7e25 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -167,6 +167,7 @@ gint spice_channel_get_channel_id(SpiceChannel *channel);
 gint spice_channel_get_channel_type(SpiceChannel *channel);
 void spice_channel_swap(SpiceChannel *channel, SpiceChannel *swap);
 void spice_channel_set_common_capability(SpiceChannel *channel, guint32 cap);
+gboolean spice_channel_get_read_only(SpiceChannel *channel);
 
 /* coroutine context */
 #define emit_main_context(object, event, args...)                       \
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index c2133ab..c9af0ba 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -1561,6 +1561,12 @@ void spice_channel_wakeup(SpiceChannel *channel)
     g_io_wakeup(&c->wait);
 }
 
+G_GNUC_INTERNAL
+gboolean spice_channel_get_read_only(SpiceChannel *channel)
+{
+    return spice_session_get_read_only(channel->priv->session);
+}
+
 /* coroutine context if @buffered is FALSE,
    system context if @buffered is TRUE */
 static void spice_channel_send_msg(SpiceChannel *channel, SpiceMsgOut *out, gboolean buffered)
@@ -1573,7 +1579,7 @@ static void spice_channel_send_msg(SpiceChannel *channel, SpiceMsgOut *out, gboo
     g_return_if_fail(out != NULL);
 
     if (out->ro_check &&
-        spice_session_get_read_only(channel->priv->session)) {
+        spice_channel_get_read_only(channel)) {
         g_warning("Try to send message while read-only. Please report a bug.");
         return;
     }
commit 1711687df25b02074097d8308b801bb35fd8dafd
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 23 00:32:36 2011 +0100

    Check if msg are permitted to be sent in read-only

diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 86b22e1..df661f8 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -46,6 +46,7 @@ struct _SpiceMsgOut {
     SpiceMessageMarshallers *marshallers;
     SpiceMarshaller       *marshaller;
     SpiceDataHeader       *header;
+    gboolean              ro_check;
 };
 
 struct _SpiceMsgIn {
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 99af206..c2133ab 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -465,6 +465,30 @@ void spice_msg_out_hexdump(SpiceMsgOut *out, unsigned char *data, int len)
     hexdump(">> msg", data, len);
 }
 
+static gboolean msg_check_read_only (int channel_type, int msg_type)
+{
+    if (msg_type < 100) // those are the common messages
+        return FALSE;
+
+    switch (channel_type) {
+    /* messages allowed to be sent in read-only mode */
+    case SPICE_CHANNEL_MAIN:
+        switch (msg_type) {
+        case SPICE_MSGC_MAIN_CLIENT_INFO:
+        case SPICE_MSGC_MAIN_MIGRATE_CONNECTED:
+        case SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR:
+        case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
+        case SPICE_MSGC_MAIN_MIGRATE_END:
+            return FALSE;
+        }
+        break;
+    case SPICE_CHANNEL_DISPLAY:
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 G_GNUC_INTERNAL
 SpiceMsgOut *spice_msg_out_new(SpiceChannel *channel, int type)
 {
@@ -476,6 +500,7 @@ SpiceMsgOut *spice_msg_out_new(SpiceChannel *channel, int type)
     out = spice_new0(SpiceMsgOut, 1);
     out->refcount = 1;
     out->channel  = channel;
+    out->ro_check = msg_check_read_only(c->channel_type, type);
 
     out->marshallers = c->marshallers;
     out->marshaller = spice_marshaller_new();
@@ -1547,6 +1572,12 @@ static void spice_channel_send_msg(SpiceChannel *channel, SpiceMsgOut *out, gboo
     g_return_if_fail(channel != NULL);
     g_return_if_fail(out != NULL);
 
+    if (out->ro_check &&
+        spice_session_get_read_only(channel->priv->session)) {
+        g_warning("Try to send message while read-only. Please report a bug.");
+        return;
+    }
+
     data = spice_marshaller_linearize(out->marshaller, 0,
                                       &len, &free_data);
     /* spice_msg_out_hexdump(out, data, len); */
@@ -1554,9 +1585,9 @@ static void spice_channel_send_msg(SpiceChannel *channel, SpiceMsgOut *out, gboo
         spice_channel_buffered_write(channel, data, len);
     else
         spice_channel_write(channel, data, len);
-    if (free_data) {
+
+    if (free_data)
         free(data);
-    }
 }
 
 /* coroutine context */
commit 222e25a02928172fa4620e94c84ba9e01b06bfbd
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Nov 22 20:55:38 2011 +0100

    Add read-only property on sessions
    
    It is useful to have a way to prevent sending commands in read-only
    sessions (think of multi-client)
    
    No clipboard sharing allowed in this case in gtk-session.

diff --git a/gtk/map-file b/gtk/map-file
index 1d7a934..4b470bb 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -67,6 +67,7 @@ spice_record_send_data;
 spice_session_connect;
 spice_session_disconnect;
 spice_session_get_channels;
+spice_session_get_read_only;
 spice_session_get_type;
 spice_session_has_channel_type;
 spice_session_migration_get_type;
diff --git a/gtk/spice-gtk-session-priv.h b/gtk/spice-gtk-session-priv.h
index 19692af..21a4251 100644
--- a/gtk/spice-gtk-session-priv.h
+++ b/gtk/spice-gtk-session-priv.h
@@ -24,6 +24,7 @@ G_BEGIN_DECLS
 
 void spice_gtk_session_update_keyboard_focus(SpiceGtkSession *self,
                                              gboolean state);
+gboolean spice_gtk_session_get_read_only(SpiceGtkSession *self);
 
 G_END_DECLS
 
diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
index 116eead..afabe8e 100644
--- a/gtk/spice-gtk-session.c
+++ b/gtk/spice-gtk-session.c
@@ -77,6 +77,7 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,
                         gpointer user_data);
 static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
                             gpointer user_data);
+static gboolean read_only(SpiceGtkSession *self);
 
 /* ------------------------------------------------------------------ */
 /* gobject glue                                                       */
@@ -477,7 +478,7 @@ static void clipboard_owner_change(GtkClipboard        *clipboard,
         }
         s->clipboard_by_guest[selection] = FALSE;
         s->clip_hasdata[selection] = TRUE;
-        if (s->auto_clipboard_enable)
+        if (s->auto_clipboard_enable && !read_only(self))
             gtk_clipboard_request_targets(clipboard, clipboard_get_targets,
                                           self);
         break;
@@ -620,7 +621,9 @@ static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,
     /* Receiving a grab implies we've released our own grab */
     s->clip_grabbed[selection] = FALSE;
 
-    if (!s->auto_clipboard_enable || s->nclip_targets[selection] == 0)
+    if (read_only(self) ||
+        !s->auto_clipboard_enable ||
+        s->nclip_targets[selection] == 0)
         goto skip_grab_clipboard;
 
     if (!gtk_clipboard_set_with_data(cb, targets, i, clipboard_get,
@@ -692,6 +695,9 @@ static gboolean clipboard_request(SpiceMainChannel *main, guint selection,
     GtkClipboard* cb;
     int m;
 
+    if (read_only(self))
+        return FALSE;
+
     cb = get_clipboard_from_selection(s, selection);
     g_return_val_if_fail(cb != NULL, FALSE);
 
@@ -771,6 +777,11 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
     }
 }
 
+static gboolean read_only(SpiceGtkSession *self)
+{
+    return spice_session_get_read_only(self->priv->session);
+}
+
 /* ---------------------------------------------------------------- */
 /* private functions (usbredir related)                             */
 G_GNUC_INTERNAL
@@ -841,6 +852,7 @@ SpiceGtkSession *spice_gtk_session_get(SpiceSession *session)
 void spice_gtk_session_copy_to_guest(SpiceGtkSession *self)
 {
     g_return_if_fail(SPICE_IS_GTK_SESSION(self));
+    g_return_if_fail(read_only(self) == FALSE);
 
     SpiceGtkSessionPrivate *s = self->priv;
     int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
@@ -862,6 +874,7 @@ void spice_gtk_session_copy_to_guest(SpiceGtkSession *self)
 void spice_gtk_session_paste_from_guest(SpiceGtkSession *self)
 {
     g_return_if_fail(SPICE_IS_GTK_SESSION(self));
+    g_return_if_fail(read_only(self) == FALSE);
 
     SpiceGtkSessionPrivate *s = self->priv;
     int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h
index 963735b..0851c39 100644
--- a/gtk/spice-session-priv.h
+++ b/gtk/spice-session-priv.h
@@ -37,6 +37,7 @@ struct _SpiceSessionPrivate {
     GByteArray        *pubkey;
     char              *cert_subject;
     guint             verify;
+    gboolean          read_only;
 
     /* whether to enable audio */
     gboolean          audio;
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 3366b58..4405fd2 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -99,6 +99,7 @@ enum {
     PROP_INHIBIT_KEYBOARD_GRAB,
     PROP_DISABLE_EFFECTS,
     PROP_COLOR_DEPTH,
+    PROP_READ_ONLY,
 };
 
 /* signals */
@@ -373,6 +374,9 @@ static void spice_session_get_property(GObject    *gobject,
     case PROP_AUDIO:
         g_value_set_boolean(value, s->audio);
         break;
+    case PROP_READ_ONLY:
+        g_value_set_boolean(value, s->read_only);
+	break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
 	break;
@@ -469,6 +473,10 @@ static void spice_session_set_property(GObject      *gobject,
     case PROP_AUDIO:
         s->audio = g_value_get_boolean(value);
         break;
+    case PROP_READ_ONLY:
+        s->read_only = g_value_get_boolean(value);
+        g_object_notify(gobject, "read-only");
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
         break;
@@ -858,6 +866,22 @@ static void spice_session_class_init(SpiceSessionClass *klass)
                      1,
                      SPICE_TYPE_CHANNEL);
 
+    /**
+     * SpiceSession:read-only:
+     *
+     * Whether this connection is read-only mode.
+     *
+     * Since: 0.8
+     **/
+    g_object_class_install_property
+        (gobject_class, PROP_READ_ONLY,
+         g_param_spec_boolean("read-only", "Read-only",
+                              "Whether this connection is read-only mode",
+                              FALSE,
+                              G_PARAM_READWRITE |
+                              G_PARAM_CONSTRUCT |
+                              G_PARAM_STATIC_STRINGS));
+
     g_type_class_add_private(klass, sizeof(SpiceSessionPrivate));
 }
 
@@ -1123,6 +1147,19 @@ void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel)
 }
 
 /**
+ * spice_session_get_read_only:
+ * @session: a #SpiceSession
+ *
+ * Returns: wether the @session is in read-only mode.
+ **/
+gboolean spice_session_get_read_only(SpiceSession *self)
+{
+    g_return_val_if_fail(SPICE_IS_SESSION(self), FALSE);
+
+    return self->priv->read_only;
+}
+
+/**
  * spice_session_disconnect:
  * @session:
  *
diff --git a/gtk/spice-session.h b/gtk/spice-session.h
index 72effce..4895288 100644
--- a/gtk/spice-session.h
+++ b/gtk/spice-session.h
@@ -93,6 +93,7 @@ gboolean spice_session_open_fd(SpiceSession *session, int fd);
 void spice_session_disconnect(SpiceSession *session);
 GList *spice_session_get_channels(SpiceSession *session);
 gboolean spice_session_has_channel_type(SpiceSession *session, gint type);
+gboolean spice_session_get_read_only(SpiceSession *session);
 
 G_END_DECLS
 
commit 1de356faf5797e8098cb4cac1894122485d3c426
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 23 02:28:25 2011 +0100

    Add disable-inputs on Spice widget

diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
index a86168d..bd5eec6 100644
--- a/gtk/spice-widget-priv.h
+++ b/gtk/spice-widget-priv.h
@@ -62,6 +62,7 @@ struct _SpiceDisplayPrivate {
     bool                    convert;
     bool                    have_mitshm;
     gboolean                allow_scaling;
+    gboolean                disable_inputs;
 
     /* TODO: make a display object instead? */
 #ifdef WITH_X11
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index 0edc70f..816a3e2 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -86,6 +86,7 @@ enum {
     PROP_RESIZE_GUEST,
     PROP_AUTO_CLIPBOARD,
     PROP_SCALING,
+    PROP_DISABLE_INPUTS,
 };
 
 /* Signals */
@@ -102,8 +103,10 @@ static guint signals[SPICE_DISPLAY_LAST_SIGNAL];
 static HWND focus_window = NULL;
 #endif
 
+static void update_keyboard_grab(SpiceDisplay *display);
 static void try_keyboard_grab(SpiceDisplay *display);
 static void try_keyboard_ungrab(SpiceDisplay *display);
+static void update_mouse_grab(SpiceDisplay *display);
 static void try_mouse_grab(SpiceDisplay *display);
 static void try_mouse_ungrab(SpiceDisplay *display);
 static void recalc_geometry(GtkWidget *widget, gboolean set_display);
@@ -148,6 +151,9 @@ static void spice_display_get_property(GObject    *object,
     case PROP_SCALING:
         g_value_set_boolean(value, d->allow_scaling);
 	break;
+    case PROP_DISABLE_INPUTS:
+        g_value_set_boolean(value, d->disable_inputs);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -172,17 +178,11 @@ static void spice_display_set_property(GObject      *object,
         break;
     case PROP_KEYBOARD_GRAB:
         d->keyboard_grab_enable = g_value_get_boolean(value);
-        if (d->keyboard_grab_enable) {
-            try_keyboard_grab(display);
-        } else {
-            try_keyboard_ungrab(display);
-        }
+        update_keyboard_grab(display);
         break;
     case PROP_MOUSE_GRAB:
         d->mouse_grab_enable = g_value_get_boolean(value);
-        if (!d->mouse_grab_enable) {
-            try_mouse_ungrab(display);
-        }
+        update_mouse_grab(display);
         break;
     case PROP_RESIZE_GUEST:
         d->resize_guest_enable = g_value_get_boolean(value);
@@ -207,6 +207,12 @@ static void spice_display_set_property(GObject      *object,
         g_object_set(d->gtk_session, "auto-clipboard",
                      g_value_get_boolean(value), NULL);
         break;
+    case PROP_DISABLE_INPUTS:
+        d->disable_inputs = g_value_get_boolean(value);
+        gtk_widget_set_can_focus(GTK_WIDGET(display), !d->disable_inputs);
+        update_keyboard_grab(display);
+        update_mouse_grab(display);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -231,11 +237,7 @@ static void session_inhibit_keyboard_grab_changed(GObject    *gobject,
 
     g_object_get(d->session, "inhibit-keyboard-grab",
                  &d->keyboard_grab_inhibit, NULL);
-    if (d->keyboard_grab_inhibit) {
-        try_keyboard_ungrab(display);
-    } else {
-        try_keyboard_grab(display);
-    }
+    update_keyboard_grab(display);
 }
 
 static void spice_display_dispose(GObject *obj)
@@ -430,14 +432,15 @@ static void try_keyboard_grab(SpiceDisplay *display)
 
     if (g_getenv("SPICE_NOGRAB"))
         return;
-
-    if (d->keyboard_grab_active)
+    if (d->disable_inputs)
         return;
 
     if (d->keyboard_grab_inhibit)
         return;
     if (!d->keyboard_grab_enable)
         return;
+    if (d->keyboard_grab_active)
+        return;
     if (!d->keyboard_have_focus)
         return;
     if (!d->mouse_have_pointer)
@@ -463,7 +466,6 @@ static void try_keyboard_grab(SpiceDisplay *display)
     }
 }
 
-
 static void try_keyboard_ungrab(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
@@ -482,6 +484,18 @@ static void try_keyboard_ungrab(SpiceDisplay *display)
     g_signal_emit(widget, signals[SPICE_DISPLAY_KEYBOARD_GRAB], 0, false);
 }
 
+static void update_keyboard_grab(SpiceDisplay *display)
+{
+    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+
+    if (d->keyboard_grab_enable &&
+        !d->keyboard_grab_inhibit &&
+        !d->disable_inputs)
+        try_keyboard_grab(display);
+    else
+        try_keyboard_ungrab(display);
+}
+
 static GdkGrabStatus do_pointer_grab(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
@@ -553,6 +567,8 @@ static void try_mouse_grab(SpiceDisplay *display)
 
     if (g_getenv("SPICE_NOGRAB"))
         return;
+    if (d->disable_inputs)
+        return;
 
     if (!d->mouse_grab_enable)
         return;
@@ -614,6 +630,16 @@ static void try_mouse_ungrab(SpiceDisplay *display)
     g_signal_emit(display, signals[SPICE_DISPLAY_MOUSE_GRAB], 0, false);
 }
 
+static void update_mouse_grab(SpiceDisplay *display)
+{
+    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
+
+    if (d->mouse_grab_enable && !d->disable_inputs)
+        update_mouse_pointer(display);
+    else
+        try_mouse_ungrab(display);
+}
+
 static void recalc_geometry(GtkWidget *widget, gboolean set_display)
 {
     SpiceDisplay *display = SPICE_DISPLAY(widget);
@@ -746,6 +772,9 @@ static void send_key(SpiceDisplay *display, int scancode, int down)
     if (!d->inputs)
         return;
 
+    if (d->disable_inputs)
+        return;
+
     i = scancode / 32;
     b = scancode % 32;
     m = (1 << b);
@@ -991,6 +1020,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 
     if (!d->inputs)
         return true;
+    if (d->disable_inputs)
+        return true;
 
     gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
     if (spicex_is_scaled(display)) {
@@ -1051,6 +1082,8 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *scroll)
 
     if (!d->inputs)
         return true;
+    if (d->disable_inputs)
+        return true;
 
     if (scroll->direction == GDK_SCROLL_UP)
         button = SPICE_MOUSE_BUTTON_UP;
@@ -1077,6 +1110,9 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
             button->type == GDK_BUTTON_PRESS ? "press" : "release",
             button->button, button->state);
 
+    if (d->disable_inputs)
+        return true;
+
     if (!spicex_is_scaled(display)) {
         gint x, y;
 
@@ -1248,6 +1284,23 @@ static void spice_display_class_init(SpiceDisplayClass *klass)
                               G_PARAM_READWRITE |
                               G_PARAM_CONSTRUCT |
                               G_PARAM_STATIC_STRINGS));
+
+    /**
+     * SpiceDisplay:disable-inputs:
+     *
+     * Disable all keyboard & mouse inputs.
+     *
+     * Since: 0.8
+     **/
+    g_object_class_install_property
+        (gobject_class, PROP_DISABLE_INPUTS,
+         g_param_spec_boolean("disable-inputs", "Disable inputs",
+                              "Whether inputs should be disabled",
+                              FALSE,
+                              G_PARAM_READWRITE |
+                              G_PARAM_CONSTRUCT |
+                              G_PARAM_STATIC_STRINGS));
+
     /**
      * SpiceDisplay::mouse-grab:
      * @display: the #SpiceDisplay that emitted the signal
@@ -1774,6 +1827,9 @@ static void sync_keyboard_lock_modifiers(SpiceDisplay *display)
     guint32 modifiers;
     GdkWindow *w;
 
+    if (d->disable_inputs)
+        return;
+
     w = gtk_widget_get_parent_window(GTK_WIDGET(display));
     if (w == NULL) /* it can happen if the display is not yet shown */
         return;
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 6c05b1e..427b8d1 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -721,6 +721,7 @@ static const char *spice_display_properties[] = {
     "grab-mouse",
     "resize-guest",
     "scaling",
+    "disable-inputs",
 };
 
 static const char *spice_gtk_session_properties[] = {
@@ -748,6 +749,10 @@ static const GtkToggleActionEntry tentries[] = {
         .label       = N_("Scale display"),
         .callback    = G_CALLBACK(menu_cb_bool_prop),
     },{
+        .name        = "disable-inputs",
+        .label       = N_("Disable inputs"),
+        .callback    = G_CALLBACK(menu_cb_bool_prop),
+    },{
         .name        = "auto-clipboard",
         .label       = N_("Automagic clipboard sharing between host and guest"),
         .callback    = G_CALLBACK(menu_cb_bool_prop),
@@ -798,6 +803,7 @@ static char ui_xml[] =
 "      <menuitem action='grab-mouse'/>\n"
 "      <menuitem action='resize-guest'/>\n"
 "      <menuitem action='scaling'/>\n"
+"      <menuitem action='disable-inputs'/>\n"
 "      <menuitem action='auto-clipboard'/>\n"
 #ifdef USE_USBREDIR
 "      <menuitem action='auto-usbredir'/>\n"
commit 92722df56cd9fb52a0fcdd0ddac4a3676eb8de32
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 23 16:23:03 2011 +0100

    cleanup: the try_grab() functions should take a SpiceDisplay

diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index f095130..0edc70f 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -104,8 +104,8 @@ static HWND focus_window = NULL;
 
 static void try_keyboard_grab(SpiceDisplay *display);
 static void try_keyboard_ungrab(SpiceDisplay *display);
-static void try_mouse_grab(GtkWidget *widget);
-static void try_mouse_ungrab(GtkWidget *widget);
+static void try_mouse_grab(SpiceDisplay *display);
+static void try_mouse_ungrab(SpiceDisplay *display);
 static void recalc_geometry(GtkWidget *widget, gboolean set_display);
 static void disconnect_main(SpiceDisplay *display);
 static void disconnect_cursor(SpiceDisplay *display);
@@ -181,7 +181,7 @@ static void spice_display_set_property(GObject      *object,
     case PROP_MOUSE_GRAB:
         d->mouse_grab_enable = g_value_get_boolean(value);
         if (!d->mouse_grab_enable) {
-            try_mouse_ungrab(GTK_WIDGET(display));
+            try_mouse_ungrab(display);
         }
         break;
     case PROP_RESIZE_GUEST:
@@ -343,8 +343,8 @@ spice_display_constructor(GType                  gtype,
     }
     g_list_free(list);
 
-    g_signal_connect(d->gtk_session, "notify::auto-clipboard",
-                     G_CALLBACK(gtk_session_property_changed), display);
+    spice_g_signal_connect_object(d->gtk_session, "notify::auto-clipboard",
+                                  G_CALLBACK(gtk_session_property_changed), display, 0);
 
     g_signal_connect(d->session, "notify::inhibit-keyboard-grab",
                      G_CALLBACK(session_inhibit_keyboard_grab_changed),
@@ -536,8 +536,9 @@ static void update_mouse_pointer(SpiceDisplay *display)
         if (!d->mouse_grab_active) {
             gdk_window_set_cursor(window, NULL);
         } else {
+            // FIXME: should it be transparent instead?
             gdk_window_set_cursor(window, d->mouse_cursor);
-            try_mouse_grab(GTK_WIDGET(display));
+            try_mouse_grab(display);
         }
         break;
     default:
@@ -546,9 +547,8 @@ static void update_mouse_pointer(SpiceDisplay *display)
     }
 }
 
-static void try_mouse_grab(GtkWidget *widget)
+static void try_mouse_grab(SpiceDisplay *display)
 {
-    SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
 
     if (g_getenv("SPICE_NOGRAB"))
@@ -601,9 +601,8 @@ static void mouse_check_edges(GtkWidget *widget, GdkEventMotion *motion)
     }
 }
 
-static void try_mouse_ungrab(GtkWidget *widget)
+static void try_mouse_ungrab(SpiceDisplay *display)
 {
-    SpiceDisplay *display = SPICE_DISPLAY(widget);
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
 
     if (!d->mouse_grab_active)
@@ -612,7 +611,7 @@ static void try_mouse_ungrab(GtkWidget *widget)
     gdk_pointer_ungrab(GDK_CURRENT_TIME);
     d->mouse_grab_active = false;
     update_mouse_pointer(display);
-    g_signal_emit(widget, signals[SPICE_DISPLAY_MOUSE_GRAB], 0, false);
+    g_signal_emit(display, signals[SPICE_DISPLAY_MOUSE_GRAB], 0, false);
 }
 
 static void recalc_geometry(GtkWidget *widget, gboolean set_display)
@@ -836,11 +835,11 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
     if (check_for_grab_key(display, key->type, key->keyval)) {
         g_signal_emit(widget, signals[SPICE_DISPLAY_GRAB_KEY_PRESSED], 0);
         if (d->mouse_grab_active)
-            try_mouse_ungrab(widget);
+            try_mouse_ungrab(display);
         else
             /* TODO: gtk-vnc has a weird condition here
                if (!d->grab_keyboard || !d->absolute) */
-            try_mouse_grab(widget);
+            try_mouse_grab(display);
     }
 
 
@@ -1091,7 +1090,7 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
 
     gtk_widget_grab_focus(widget);
     if (d->mouse_mode == SPICE_MOUSE_MODE_SERVER)
-        try_mouse_grab(widget);
+        try_mouse_grab(display);
     else /* allow to drag and drop between windows/displays:
             FIXME: should be multiple widget grab, but how?
             or should now the position of the other widgets?..
@@ -1317,7 +1316,7 @@ static void mouse_update(SpiceChannel *channel, gpointer data)
     d->mouse_guest_x = -1;
     d->mouse_guest_y = -1;
     if (d->mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
-        try_mouse_ungrab(GTK_WIDGET(display));
+        try_mouse_ungrab(display);
     }
     update_mouse_pointer(display);
 }
@@ -1668,7 +1667,7 @@ SpiceDisplay *spice_display_new(SpiceSession *session, int id)
  **/
 void spice_display_mouse_ungrab(SpiceDisplay *display)
 {
-    try_mouse_ungrab(GTK_WIDGET(display));
+    try_mouse_ungrab(display);
 }
 
 /**
commit ac2b9e1e39e0f459c61a6762b3154cb3ffd9d2ff
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Nov 22 22:22:24 2011 +0100

    Fix a few g-ir-scanner warnings

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 8a353dc..ebf908d 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -590,6 +590,7 @@ glib_introspection_files =			\
 	spice-channel.c				\
 	spice-glib-enums.c			\
 	spice-option.c				\
+	spice-util.c				\
 	channel-cursor.c			\
 	channel-display.c			\
 	channel-inputs.c			\
@@ -598,6 +599,7 @@ glib_introspection_files =			\
 	channel-record.c			\
 	channel-smartcard.c			\
 	channel-usbredir.c			\
+	smartcard-manager.c			\
 	usb-device-manager.c            	\
 	$(NULL)
 
diff --git a/gtk/smartcard-manager.c b/gtk/smartcard-manager.c
index df29088..d814ac3 100644
--- a/gtk/smartcard-manager.c
+++ b/gtk/smartcard-manager.c
@@ -246,7 +246,7 @@ static SpiceSmartcardManager *spice_smartcard_manager_new(void)
  * to it. A new SpiceSmartcardManager instance will be created the first
  * time this function is called
  *
- * Returns: a pointer to the #SpiceSmartcardManager singleton
+ * Returns: (transfer none): a weak reference to the #SpiceSmartcardManager
  */
 SpiceSmartcardManager *spice_smartcard_manager_get(void)
 {
diff --git a/gtk/spice-util.c b/gtk/spice-util.c
index b634bf3..f2f30e8 100644
--- a/gtk/spice-util.c
+++ b/gtk/spice-util.c
@@ -148,6 +148,19 @@ closure_invalidated_cb (gpointer ctx_,
 }
 
 /* Copied from tp_g_signal_connect_object. See documentation. */
+/**
+  * spice_g_signal_connect_object: (skip)
+  * @instance: the instance to connect to.
+  * @detailed_signal: a string of the form "signal-name::detail".
+  * @c_handler: the #GCallback to connect.
+  * @gobject: the object to pass as data to @c_handler.
+  * @connect_flags: a combination of #GConnectFlags.
+  *
+  * Similar to g_signal_connect_object() but will delete connection
+  * when any of the objects is destroyed.
+  *
+  * Returns: the handler id.
+  */
 gulong spice_g_signal_connect_object (gpointer instance,
                                       const gchar *detailed_signal,
                                       GCallback c_handler,
commit ff98834d9af6913ce1de3b6a317c614f3e1799e4
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Nov 22 20:50:54 2011 +0100

    Export spice_g_signal_connect_object
    
    The helper needs to be accessible from spice-client-gtk too.

diff --git a/gtk/map-file b/gtk/map-file
index f3a6e22..1d7a934 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -34,6 +34,7 @@ spice_grab_sequence_free;
 spice_grab_sequence_get_type;
 spice_grab_sequence_new;
 spice_grab_sequence_new_from_string;
+spice_g_signal_connect_object;
 spice_gtk_session_copy_to_guest;
 spice_gtk_session_get;
 spice_gtk_session_get_type;
diff --git a/gtk/spice-util-priv.h b/gtk/spice-util-priv.h
index 1f9778c..90b437c 100644
--- a/gtk/spice-util-priv.h
+++ b/gtk/spice-util-priv.h
@@ -23,11 +23,6 @@
 G_BEGIN_DECLS
 
 gboolean spice_strv_contains(const GStrv strv, const gchar *str);
-gulong spice_g_signal_connect_object(gpointer instance,
-                                     const gchar *detailed_signal,
-                                     GCallback c_handler,
-                                     gpointer gobject,
-                                     GConnectFlags connect_flags);
 
 G_END_DECLS
 
diff --git a/gtk/spice-util.c b/gtk/spice-util.c
index fb5767b..b634bf3 100644
--- a/gtk/spice-util.c
+++ b/gtk/spice-util.c
@@ -148,7 +148,6 @@ closure_invalidated_cb (gpointer ctx_,
 }
 
 /* Copied from tp_g_signal_connect_object. See documentation. */
-G_GNUC_INTERNAL
 gulong spice_g_signal_connect_object (gpointer instance,
                                       const gchar *detailed_signal,
                                       GCallback c_handler,
diff --git a/gtk/spice-util.h b/gtk/spice-util.h
index a052ca8..5029bc1 100644
--- a/gtk/spice-util.h
+++ b/gtk/spice-util.h
@@ -25,6 +25,11 @@ G_BEGIN_DECLS
 void spice_util_set_debug(gboolean enabled);
 gboolean spice_util_get_debug(void);
 const gchar *spice_util_get_version_string(void);
+gulong spice_g_signal_connect_object(gpointer instance,
+                                     const gchar *detailed_signal,
+                                     GCallback c_handler,
+                                     gpointer gobject,
+                                     GConnectFlags connect_flags);
 
 #define SPICE_DEBUG(fmt, ...)                                   \
     do {                                                        \
commit e6feb40fc7f37e4d29d9e564ad75c0cf7502bcc4
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Nov 22 20:48:07 2011 +0100

    Regenerate map-file correctly
    
    We should use update-map-file instead of modifying it manually

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 5dfa9f3..8a353dc 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -232,7 +232,6 @@ libspice_client_glib_2_0_la_SOURCES =	\
 	channel-usbredir.c		\
 	channel-usbredir-priv.h		\
 	smartcard-manager.c		\
-	smartcard-manager.h		\
 	smartcard-manager-priv.h	\
 	usb-device-manager.c		\
 	$(GUSB_SRCS)			\
@@ -295,6 +294,7 @@ libspice_client_glibinclude_HEADERS =	\
 	channel-smartcard.h		\
 	channel-usbredir.h		\
 	usb-device-manager.h		\
+	smartcard-manager.h		\
 	$(NULL)
 
 nodist_libspice_client_glibinclude_HEADERS =	\
@@ -577,7 +577,7 @@ PREFIX_ARGS = --strip-prefix=Spice
 endif
 
 INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = --warn-all --add-include-path=$(builddir) $(PREFIX_ARGS)
+INTROSPECTION_SCANNER_ARGS = --warn-all --accept-unprefixed --add-include-path=$(builddir) $(PREFIX_ARGS)
 INTROSPECTION_COMPILER_ARGS = --includedir=$(builddir)
 
 if HAVE_INTROSPECTION
diff --git a/gtk/map-file b/gtk/map-file
index b6b84f1..f3a6e22 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -1,8 +1,8 @@
 SPICEGTK_1 {
 global:
+spice_audio_get;
 spice_audio_get_type;
 spice_audio_new;
-spice_audio_get;
 spice_channel_connect;
 spice_channel_destroy;
 spice_channel_disconnect;
@@ -34,6 +34,10 @@ spice_grab_sequence_free;
 spice_grab_sequence_get_type;
 spice_grab_sequence_new;
 spice_grab_sequence_new_from_string;
+spice_gtk_session_copy_to_guest;
+spice_gtk_session_get;
+spice_gtk_session_get_type;
+spice_gtk_session_paste_from_guest;
 spice_inputs_button_press;
 spice_inputs_button_release;
 spice_inputs_channel_get_type;
@@ -68,10 +72,6 @@ spice_session_migration_get_type;
 spice_session_new;
 spice_session_open_fd;
 spice_session_verify_get_type;
-spice_gtk_session_get;
-spice_gtk_session_get_type;
-spice_gtk_session_copy_to_guest;
-spice_gtk_session_paste_from_guest;
 spice_set_session_option;
 spice_smartcard_channel_get_type;
 spice_smartcard_manager_get;
@@ -80,16 +80,16 @@ spice_smartcard_manager_insert_card;
 spice_smartcard_manager_remove_card;
 spice_smartcard_reader_get_type;
 spice_smartcard_reader_is_software;
-spice_usbredir_channel_get_type;
-spice_usb_device_get_type;
 spice_usb_device_get_description;
-spice_usb_device_manager_get_type;
-spice_usb_device_manager_get;
-spice_usb_device_manager_get_devices;
-spice_usb_device_manager_is_device_connected;
+spice_usb_device_get_type;
 spice_usb_device_manager_connect_device_async;
 spice_usb_device_manager_connect_device_finish;
 spice_usb_device_manager_disconnect_device;
+spice_usb_device_manager_get;
+spice_usb_device_manager_get_devices;
+spice_usb_device_manager_get_type;
+spice_usb_device_manager_is_device_connected;
+spice_usbredir_channel_get_type;
 spice_util_get_debug;
 spice_util_get_version_string;
 spice_util_set_debug;


More information about the Spice-commits mailing list