summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk/spicy.c99
1 files changed, 85 insertions, 14 deletions
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 5ffe3b7..0571cf7 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -32,6 +32,7 @@
#include "smartcard-manager.h"
#endif
+#include "glib-compat.h"
#include "spice-widget.h"
#include "spice-gtk-session.h"
#include "spice-audio.h"
@@ -62,7 +63,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 +89,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 +1148,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 +1161,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 +1212,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 +1332,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 +1501,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 +1592,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 +1626,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)) {