[Spice-devel] [PATCH spice-gtk 18/25] spicy: learn to deal with monitors

Marc-André Lureau marcandre.lureau at gmail.com
Thu Jul 12 15:29:15 PDT 2012


---
 gtk/spicy.c |   98 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 84 insertions(+), 14 deletions(-)

diff --git a/gtk/spicy.c b/gtk/spicy.c
index 5ffe3b7..ac2088e 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -62,7 +62,8 @@ typedef struct _SpiceWindowClass SpiceWindowClass;
 struct _SpiceWindow {
     GObject          object;
     spice_connection *conn;
-    int              id;
+    gint             id;
+    gint             monitor_id;
     GtkWidget        *toplevel, *spice;
     GtkWidget        *menubar, *toolbar;
     GtkWidget        *ritem, *rmenu;
@@ -87,10 +88,15 @@ struct _SpiceWindowClass
 
 G_DEFINE_TYPE (SpiceWindow, spice_window, G_TYPE_OBJECT);
 
+#define CHANNELID_MAX 4
+#define MONITORID_MAX 4
+
+// FIXME: turn this into an object, get rid of fixed wins array, use
+// signals to replace the various callback that iterate over wins array
 struct spice_connection {
     SpiceSession     *session;
     SpiceGtkSession  *gtk_session;
-    SpiceWindow     *wins[4];
+    SpiceWindow     *wins[CHANNELID_MAX * MONITORID_MAX];
     SpiceAudio       *audio;
     const char       *mouse_state;
     const char       *agent_state;
@@ -1141,7 +1147,7 @@ spice_window_init (SpiceWindow *self)
 {
 }
 
-static SpiceWindow *create_spice_window(spice_connection *conn, int id, SpiceChannel *channel)
+static SpiceWindow *create_spice_window(spice_connection *conn, SpiceChannel *channel, int id, gint monitor_id)
 {
     char title[32];
     SpiceWindow *win;
@@ -1154,12 +1160,13 @@ static SpiceWindow *create_spice_window(spice_connection *conn, int id, SpiceCha
 
     win = g_object_new(SPICE_TYPE_WINDOW, NULL);
     win->id = id;
+    win->monitor_id = monitor_id;
     win->conn = conn;
     win->display_channel = channel;
 
     /* toplevel */
     win->toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    snprintf(title, sizeof(title), _("spice display %d"), id);
+    snprintf(title, sizeof(title), _("spice display %d:%d"), id, monitor_id);
     gtk_window_set_title(GTK_WINDOW(win->toplevel), title);
     g_signal_connect(G_OBJECT(win->toplevel), "window-state-event",
                      G_CALLBACK(window_state_cb), win);
@@ -1204,7 +1211,7 @@ static SpiceWindow *create_spice_window(spice_connection *conn, int id, SpiceCha
 #endif
 
     /* spice display */
-    win->spice = GTK_WIDGET(spice_display_new(conn->session, id));
+    win->spice = GTK_WIDGET(spice_display_new_with_monitor(conn->session, id, monitor_id));
     g_signal_connect(win->spice, "configure-event", G_CALLBACK(configure_event_cb), win);
     seq = spice_grab_sequence_new_from_string("Shift_L+F12");
     spice_display_set_grab_keys(SPICE_DISPLAY(win->spice), seq);
@@ -1324,7 +1331,10 @@ static SpiceWindow *create_spice_window(spice_connection *conn, int id, SpiceCha
 
 static void destroy_spice_window(SpiceWindow *win)
 {
-    SPICE_DEBUG("destroy window (#%d)", win->id);
+    if (win == NULL)
+        return;
+
+    SPICE_DEBUG("destroy window (#%d:%d)", win->id, win->monitor_id);
     g_object_unref(win->ag);
     g_object_unref(win->ui);
     gtk_widget_destroy(win->toplevel);
@@ -1490,6 +1500,70 @@ static void update_auto_usbredir_sensitive(spice_connection *conn)
 #endif
 }
 
+static SpiceWindow* get_window(spice_connection *conn, int channel_id, int monitor_id)
+{
+    g_return_val_if_fail(channel_id < CHANNELID_MAX, NULL);
+    g_return_val_if_fail(monitor_id < MONITORID_MAX, NULL);
+
+    return conn->wins[channel_id * CHANNELID_MAX + monitor_id];
+}
+
+static void add_window(spice_connection *conn, SpiceWindow *win)
+{
+    g_return_if_fail(win != NULL);
+    g_return_if_fail(win->id < CHANNELID_MAX);
+    g_return_if_fail(win->monitor_id < MONITORID_MAX);
+    g_return_if_fail(conn->wins[win->id * CHANNELID_MAX + win->monitor_id] == NULL);
+
+    SPICE_DEBUG("add display monitor %d:%d", win->id, win->monitor_id);
+    conn->wins[win->id * CHANNELID_MAX + win->monitor_id] = win;
+}
+
+static void del_window(spice_connection *conn, SpiceWindow *win)
+{
+    if (win == NULL)
+        return;
+
+    g_return_if_fail(win->id < CHANNELID_MAX);
+    g_return_if_fail(win->monitor_id < MONITORID_MAX);
+
+    g_debug("del display monitor %d:%d", win->id, win->monitor_id);
+    conn->wins[win->id * CHANNELID_MAX + win->monitor_id] = NULL;
+    destroy_spice_window(win);
+}
+
+static void display_monitors(SpiceChannel *display, GParamSpec *pspec,
+                             spice_connection *conn)
+{
+    GArray *monitors = NULL;
+    int id;
+    guint i;
+
+    g_object_get(display,
+                 "channel-id", &id,
+                 "monitors", &monitors,
+                 NULL);
+    g_return_if_fail(monitors != NULL);
+
+    for (i = 0; i < monitors->len; i++) {
+        SpiceWindow *w;
+
+        if (!get_window(conn, id, i)) {
+            w = create_spice_window(conn, display, id, i);
+            add_window(conn, w);
+            spice_g_signal_connect_object(display, "display-mark",
+                                          G_CALLBACK(display_mark), w, 0);
+            gtk_widget_show(w->toplevel);
+            update_auto_usbredir_sensitive(conn);
+        }
+    }
+
+    for (; i < MONITORID_MAX; i++)
+        del_window(conn, get_window(conn, id, i));
+
+    g_clear_pointer(&monitors, g_array_unref);
+}
+
 static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
 {
     spice_connection *conn = data;
@@ -1517,10 +1591,9 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
         if (conn->wins[id] != NULL)
             return;
         SPICE_DEBUG("new display channel (#%d)", id);
-        conn->wins[id] = create_spice_window(conn, id, channel);
-        g_signal_connect(channel, "display-mark",
-                         G_CALLBACK(display_mark), conn->wins[id]);
-        update_auto_usbredir_sensitive(conn);
+        g_signal_connect(channel, "notify::monitors",
+                         G_CALLBACK(display_monitors), conn);
+        spice_channel_connect(channel);
     }
 
     if (SPICE_IS_INPUTS_CHANNEL(channel)) {
@@ -1552,11 +1625,8 @@ static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer dat
     if (SPICE_IS_DISPLAY_CHANNEL(channel)) {
         if (id >= SPICE_N_ELEMENTS(conn->wins))
             return;
-        if (conn->wins[id] == NULL)
-            return;
         SPICE_DEBUG("zap display channel (#%d)", id);
-        destroy_spice_window(conn->wins[id]);
-        conn->wins[id] = NULL;
+        /* FIXME destroy widget only */
     }
 
     if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
-- 
1.7.10.4



More information about the Spice-devel mailing list