[virt-tools-list] [PATCH 07/12] Add spice controller support in remote-viewer
Daniel P. Berrange
berrange at redhat.com
Thu Jan 26 16:30:06 UTC 2012
On Tue, Dec 13, 2011 at 08:35:05PM +0100, Marc-André Lureau wrote:
> Usage is simply "remote-viewer --spice-controller"
> ---
> configure.ac | 3 +-
> src/remote-viewer-main.c | 20 ++-
> src/remote-viewer.c | 374 ++++++++++++++++++++++++++++++++++++--
> src/remote-viewer.h | 4 +-
> src/virt-viewer-app.c | 7 +
> src/virt-viewer-app.h | 1 +
> src/virt-viewer-session-spice.c | 47 +++++-
> src/virt-viewer-window.c | 9 +
> src/virt-viewer-window.h | 1 +
> 9 files changed, 435 insertions(+), 31 deletions(-)
>
> diff --git a/configure.ac b/configure.ac
> index e47d60a..b2d7e8f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -92,7 +92,8 @@ AC_ARG_WITH([spice-gtk],
>
> AS_IF([test "x$with_spice_gtk" != "xno"],
> [PKG_CHECK_MODULES(SPICE_GTK,
> - spice-client-gtk-$SPICE_GTK_API_VERSION >= $SPICE_GTK_REQUIRED,
> + [spice-client-gtk-$SPICE_GTK_API_VERSION >= $SPICE_GTK_REQUIRED
> + spice-controller],
> [have_spice_gtk=yes], [have_spice_gtk=no])],
> [have_spice_gtk=no])
>
> diff --git a/src/remote-viewer-main.c b/src/remote-viewer-main.c
> index 54670d1..2256528 100644
> --- a/src/remote-viewer-main.c
> +++ b/src/remote-viewer-main.c
> @@ -56,6 +56,7 @@ main(int argc, char **argv)
> gboolean direct = FALSE;
> gboolean fullscreen = FALSE;
> RemoteViewer *viewer = NULL;
> + gboolean controller = FALSE;
> VirtViewerApp *app;
> const char *help_msg = N_("Run '" PACKAGE " --help' to see a full list of available command line options");
> const GOptionEntry options [] = {
> @@ -71,6 +72,8 @@ main(int argc, char **argv)
> N_("Display debugging information"), NULL },
> { "full-screen", 'f', 0, G_OPTION_ARG_NONE, &fullscreen,
> N_("Open in full screen mode"), NULL },
> + { "spice-controller", '\0', 0, G_OPTION_ARG_NONE, &controller,
> + N_("Open connection using Spice controller communication"), NULL },
> { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args,
> NULL, "URI" },
> { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
> @@ -99,7 +102,8 @@ main(int argc, char **argv)
>
> g_option_context_free(context);
>
> - if (!args || (g_strv_length(args) != 1)) {
> + if ((!args || (g_strv_length(args) != 1)) &&
> + !controller) {
> g_printerr(_("\nUsage: %s [OPTIONS] URI\n\n%s\n\n"), argv[0], help_msg);
> goto cleanup;
> }
> @@ -111,15 +115,19 @@ main(int argc, char **argv)
>
> virt_viewer_app_set_debug(debug);
>
> - viewer = remote_viewer_new(args[0], verbose);
> + if (controller) {
> + viewer = remote_viewer_new_with_controller(verbose);
> + g_object_set(viewer, "guest-name", "defined by Spice controller", NULL);
> + } else {
> + viewer = remote_viewer_new(args[0], verbose);
> + g_object_set(viewer, "guest-name", args[0], NULL);
> +
> + }
> if (viewer == NULL)
> goto cleanup;
>
> app = VIRT_VIEWER_APP(viewer);
> - g_object_set(app,
> - "fullscreen", fullscreen,
> - "guest-name", args[0],
> - NULL);
> + g_object_set(app, "fullscreen", fullscreen, NULL);
> virt_viewer_window_set_zoom_level(virt_viewer_app_get_main_window(app), zoom);
> virt_viewer_app_set_direct(app, direct);
>
> diff --git a/src/remote-viewer.c b/src/remote-viewer.c
> index d5c9824..388531b 100644
> --- a/src/remote-viewer.c
> +++ b/src/remote-viewer.c
> @@ -27,24 +27,41 @@
> #include <glib/gprintf.h>
> #include <glib/gi18n.h>
>
> +#include <spice-controller/spice-controller.h>
> +
> +#include "virt-viewer-session-spice.h"
> #include "virt-viewer-app.h"
> #include "remote-viewer.h"
>
> struct _RemoteViewerPrivate {
> - int _dummy;
> + SpiceCtrlController *controller;
> + GtkWidget *controller_menu;
> };
>
> G_DEFINE_TYPE (RemoteViewer, remote_viewer, VIRT_VIEWER_TYPE_APP)
> #define GET_PRIVATE(o) \
> (G_TYPE_INSTANCE_GET_PRIVATE ((o), REMOTE_VIEWER_TYPE, RemoteViewerPrivate))
>
> +enum {
> + PROP_0,
> + PROP_CONTROLLER,
> +};
> +
> static gboolean remote_viewer_start(VirtViewerApp *self);
> +static int remote_viewer_activate(VirtViewerApp *self);
> +static void remote_viewer_window_added(VirtViewerApp *self, VirtViewerWindow *win);
>
> static void
> remote_viewer_get_property (GObject *object, guint property_id,
> - GValue *value G_GNUC_UNUSED, GParamSpec *pspec)
> + GValue *value, GParamSpec *pspec)
> {
> + RemoteViewer *self = REMOTE_VIEWER(object);
> + RemoteViewerPrivate *priv = self->priv;
> +
> switch (property_id) {
> + case PROP_CONTROLLER:
> + g_value_set_object(value, priv->controller);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
> }
> @@ -52,9 +69,16 @@ remote_viewer_get_property (GObject *object, guint property_id,
>
> static void
> remote_viewer_set_property (GObject *object, guint property_id,
> - const GValue *value G_GNUC_UNUSED, GParamSpec *pspec)
> + const GValue *value, GParamSpec *pspec)
> {
> + RemoteViewer *self = REMOTE_VIEWER(object);
> + RemoteViewerPrivate *priv = self->priv;
> +
> switch (property_id) {
> + case PROP_CONTROLLER:
> + g_return_if_fail(priv->controller == NULL);
> + priv->controller = g_value_dup_object(value);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
> }
> @@ -63,6 +87,14 @@ remote_viewer_set_property (GObject *object, guint property_id,
> static void
> remote_viewer_dispose (GObject *object)
> {
> + RemoteViewer *self = REMOTE_VIEWER(object);
> + RemoteViewerPrivate *priv = self->priv;
> +
> + if (priv->controller) {
> + g_object_unref(priv->controller);
> + priv->controller = NULL;
> + }
> +
> G_OBJECT_CLASS(remote_viewer_parent_class)->dispose (object);
> }
>
> @@ -79,6 +111,18 @@ remote_viewer_class_init (RemoteViewerClass *klass)
> object_class->dispose = remote_viewer_dispose;
>
> app_class->start = remote_viewer_start;
> + app_class->activate = remote_viewer_activate;
> + app_class->window_added = remote_viewer_window_added;
> +
> + g_object_class_install_property(object_class,
> + PROP_CONTROLLER,
> + g_param_spec_object("controller",
> + "Controller",
> + "Spice controller",
> + SPICE_CTRL_TYPE_CONTROLLER,
> + G_PARAM_READWRITE |
> + G_PARAM_CONSTRUCT_ONLY |
> + G_PARAM_STATIC_STRINGS));
> }
>
> static void
> @@ -96,36 +140,326 @@ remote_viewer_new(const gchar *uri, gboolean verbose)
> NULL);
> }
>
> +RemoteViewer *
> +remote_viewer_new_with_controller(gboolean verbose)
> +{
> + RemoteViewer *self;
> + SpiceCtrlController *ctrl = spice_ctrl_controller_new();
> +
> + self = g_object_new(REMOTE_VIEWER_TYPE,
> + "controller", ctrl,
> + "verbose", verbose,
> + NULL);
> + g_object_unref(ctrl);
> +
> + return self;
> +}
> +
> +static void
> +spice_ctrl_do_connect(SpiceCtrlController *ctrl G_GNUC_UNUSED,
> + VirtViewerApp *self)
> +{
> + if (virt_viewer_app_initial_connect(self) < 0) {
> + virt_viewer_app_simple_message_dialog(self, _("Failed to initiate connection"));
> + }
> +}
> +
> +static void
> +spice_ctrl_show(SpiceCtrlController *ctrl G_GNUC_UNUSED, RemoteViewer *self)
> +{
> + virt_viewer_app_show_display(VIRT_VIEWER_APP(self));
> +}
> +
> +static void
> +spice_ctrl_hide(SpiceCtrlController *ctrl G_GNUC_UNUSED, RemoteViewer *self)
> +{
> + virt_viewer_app_show_status(VIRT_VIEWER_APP(self), _("Display disabled by controller"));
> +}
> +
> +static void
> +spice_menuitem_activate_cb(GtkMenuItem *mi, RemoteViewer *self)
> +{
> + SpiceCtrlMenuItem *menuitem = g_object_get_data(G_OBJECT(mi), "spice-menuitem");
> +
> + g_return_if_fail(menuitem != NULL);
> + if (gtk_menu_item_get_submenu(mi))
> + return;
> +
> + spice_ctrl_controller_menu_item_click_msg(self->priv->controller, menuitem->id);
> +}
> +
> +static GtkWidget *
> +ctrlmenu_to_gtkmenu (RemoteViewer *self, SpiceCtrlMenu *ctrlmenu)
> +{
> + GList *l;
> + GtkWidget *menu = gtk_menu_new();
> + guint n = 0;
> +
> + for (l = ctrlmenu->items; l != NULL; l = l->next) {
> + SpiceCtrlMenuItem *menuitem = l->data;
> + GtkWidget *item;
> + char *s;
> + if (menuitem->text == NULL) {
> + g_warn_if_reached();
> + continue;
> + }
> +
> + for (s = menuitem->text; *s; s++)
> + if (*s == '&')
> + *s = '_';
> +
> + if (g_str_equal(menuitem->text, "-")){
> + item = gtk_separator_menu_item_new();
> + } else {
> + item = gtk_menu_item_new_with_mnemonic(menuitem->text);
> + }
> +
> + g_object_set_data_full(G_OBJECT(item), "spice-menuitem",
> + g_object_ref(menuitem), g_object_unref);
> + g_signal_connect(item, "activate", G_CALLBACK(spice_menuitem_activate_cb), self);
> + gtk_menu_attach(GTK_MENU (menu), item, 0, 1, n, n + 1);
> + n += 1;
> +
> + if (menuitem->submenu) {
> + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
> + ctrlmenu_to_gtkmenu(self, menuitem->submenu));
> + }
> + }
> +
> + if (n == 0) {
> + g_object_ref_sink(menu);
> + g_object_unref(menu);
> + menu = NULL;
> + }
> +
> + gtk_widget_show_all(menu);
> + return menu;
> +}
> +
> +static void
> +spice_menu_set_visible(gpointer key G_GNUC_UNUSED,
> + gpointer value,
> + gpointer user_data)
> +{
> + gboolean visible = GPOINTER_TO_INT(user_data);
> + GtkWidget *menu = g_object_get_data(value, "spice-menu");
> +
> + gtk_widget_set_visible(menu, visible);
> +}
> +
> +static void
> +remote_viewer_window_spice_menu_set_visible(RemoteViewer *self,
> + gboolean visible)
> +{
> + GHashTable *windows = virt_viewer_app_get_windows(VIRT_VIEWER_APP(self));
> +
> + g_hash_table_foreach(windows, spice_menu_set_visible, GINT_TO_POINTER(visible));
> +}
> +
> +static void
> +spice_menu_update(gpointer key G_GNUC_UNUSED,
> + gpointer value,
> + gpointer user_data)
> +{
> + RemoteViewer *self = REMOTE_VIEWER(user_data);
> + GtkWidget *menuitem = g_object_get_data(value, "spice-menu");
> + SpiceCtrlMenu *menu;
> +
> + g_object_get(self->priv->controller, "menu", &menu, NULL);
> + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), ctrlmenu_to_gtkmenu(self, menu));
> + g_object_unref(menu);
> +}
> +
> +static void
> +spice_ctrl_menu_updated(RemoteViewer *self,
> + SpiceCtrlMenu *menu)
> +{
> + GHashTable *windows = virt_viewer_app_get_windows(VIRT_VIEWER_APP(self));
> + RemoteViewerPrivate *priv = self->priv;
> + gboolean visible;
> +
> + DEBUG_LOG("Spice controller menu updated");
> +
> + if (priv->controller_menu != NULL) {
> + g_object_unref (priv->controller_menu);
> + priv->controller_menu = NULL;
> + }
> +
> + if (menu && g_list_length(menu->items) > 0) {
> + priv->controller_menu = ctrlmenu_to_gtkmenu(self, menu);
> + g_hash_table_foreach(windows, spice_menu_update, self);
> + }
> +
> + visible = priv->controller_menu != NULL;
> +
> + remote_viewer_window_spice_menu_set_visible(self, visible);
> +}
> +
> +static SpiceSession *
> +remote_viewer_get_spice_session(RemoteViewer *self)
> +{
> + VirtViewerSession *vsession = NULL;
> + SpiceSession *session = NULL;
> +
> + g_object_get(self, "session", &vsession, NULL);
> + g_return_val_if_fail(vsession != NULL, NULL);
> +
> + g_object_get(vsession, "spice-session", &session, NULL);
> +
> + g_object_unref(vsession);
> +
> + return session;
> +}
> +
> +#ifndef G_VALUE_INIT /* see bug https://bugzilla.gnome.org/show_bug.cgi?id=654793 */
> +#define G_VALUE_INIT { 0, { { 0 } } }
> +#endif
> +
> +static void
> +spice_ctrl_notified(SpiceCtrlController *ctrl,
> + GParamSpec *pspec,
> + RemoteViewer *self)
> +{
> + SpiceSession *session = remote_viewer_get_spice_session(self);
> + GValue value = G_VALUE_INIT;
> + VirtViewerApp *app = VIRT_VIEWER_APP(self);
> +
> + g_return_if_fail(session != NULL);
> +
> + g_value_init(&value, pspec->value_type);
> + g_object_get_property(G_OBJECT(ctrl), pspec->name, &value);
> +
> + if (g_str_equal(pspec->name, "host") ||
> + g_str_equal(pspec->name, "port") ||
> + g_str_equal(pspec->name, "password") ||
> + g_str_equal(pspec->name, "ca-file")) {
> + g_object_set_property(G_OBJECT(session), pspec->name, &value);
> + } else if (g_str_equal(pspec->name, "sport")) {
> + g_object_set_property(G_OBJECT(session), "tls-port", &value);
> + } else if (g_str_equal(pspec->name, "tls-ciphers")) {
> + g_object_set_property(G_OBJECT(session), "ciphers", &value);
> + } else if (g_str_equal(pspec->name, "host-subject")) {
> + g_object_set_property(G_OBJECT(session), "cert-subject", &value);
> + } else if (g_str_equal(pspec->name, "title")) {
> + g_object_set_property(G_OBJECT(app), "title", &value);
> + } else if (g_str_equal(pspec->name, "display-flags")) {
> + guint flags = g_value_get_uint(&value);
> + gboolean fullscreen = flags & CONTROLLER_SET_FULL_SCREEN;
> + gboolean auto_res = flags & CONTROLLER_AUTO_DISPLAY_RES;
> + g_object_set(G_OBJECT(self), "fullscreen", fullscreen, NULL);
> + g_debug("unimplemented resize-guest %d", auto_res);
> + /* g_object_set(G_OBJECT(self), "resize-guest", auto_res, NULL); */
> + } else if (g_str_equal(pspec->name, "menu")) {
> + spice_ctrl_menu_updated(self, g_value_get_object(&value));
> + } else {
> + gchar *content = g_strdup_value_contents(&value);
> +
> + g_debug("unimplemented property: %s=%s", pspec->name, content);
> + g_free(content);
> + }
> +
> + g_object_unref(session);
> + g_value_unset(&value);
> +}
> +
> +static void
> +spice_ctrl_listen_async_cb(GObject *object,
> + GAsyncResult *res,
> + gpointer user_data)
> +{
> + GError *error = NULL;
> +
> + spice_ctrl_controller_listen_finish(SPICE_CTRL_CONTROLLER(object), res, &error);
> +
> + if (error != NULL) {
> + virt_viewer_app_simple_message_dialog(VIRT_VIEWER_APP(user_data),
> + _("Controller connection failed: %s"),
> + error->message);
> + g_clear_error(&error);
> + exit(1); /* TODO: make start async? */
> + }
> +}
> +
> +static int
> +remote_viewer_activate(VirtViewerApp *app)
> +{
> + g_return_val_if_fail(REMOTE_VIEWER_IS(app), -1);
> + RemoteViewer *self = REMOTE_VIEWER(app);
> + int ret = -1;
> +
> + if (self->priv->controller) {
> + SpiceSession *session = remote_viewer_get_spice_session(self);
> + ret = spice_session_connect(session);
> + g_object_unref(session);
> + } else {
> + ret = VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->activate(app);
> + }
> +
> + return ret;
> +}
> +
> +static void
> +remote_viewer_window_added(VirtViewerApp *self G_GNUC_UNUSED,
> + VirtViewerWindow *win)
> +{
> + GtkMenuShell *shell = GTK_MENU_SHELL(gtk_builder_get_object(virt_viewer_window_get_builder(win), "top-menu"));
> + GtkWidget *spice = gtk_menu_item_new_with_label("Spice");
> +
> + gtk_menu_shell_append(shell, spice);
> + g_object_set_data(G_OBJECT(win), "spice-menu", spice);
> +}
> +
> static gboolean
> remote_viewer_start(VirtViewerApp *app)
> {
> - gchar *guri;
> - gchar *type;
> + g_return_val_if_fail(REMOTE_VIEWER_IS(app), FALSE);
> +
> + RemoteViewer *self = REMOTE_VIEWER(app);
> + RemoteViewerPrivate *priv = self->priv;
> gboolean ret = FALSE;
> + gchar *guri = NULL;
> + gchar *type = NULL;
>
> - g_object_get(app, "guri", &guri, NULL);
> - g_return_val_if_fail(guri != NULL, FALSE);
> + if (priv->controller) {
> + if (virt_viewer_app_create_session(app, "spice") < 0) {
> + virt_viewer_app_simple_message_dialog(app, _("Couldn't create a Spice session"));
> + goto cleanup;
> + }
>
> - DEBUG_LOG("Opening display to %s", guri);
> + g_signal_connect(priv->controller, "notify", G_CALLBACK(spice_ctrl_notified), self);
> + g_signal_connect(priv->controller, "do_connect", G_CALLBACK(spice_ctrl_do_connect), self);
> + g_signal_connect(priv->controller, "show", G_CALLBACK(spice_ctrl_show), self);
> + g_signal_connect(priv->controller, "hide", G_CALLBACK(spice_ctrl_hide), self);
>
> - if (virt_viewer_util_extract_host(guri, &type, NULL, NULL, NULL, NULL) < 0) {
> - virt_viewer_app_simple_message_dialog(app, _("Cannot determine the connection type from URI"));
> - goto cleanup;
> - }
> + spice_ctrl_controller_listen(priv->controller, NULL, spice_ctrl_listen_async_cb, self);
> + virt_viewer_app_show_status(VIRT_VIEWER_APP(self), _("Setting up Spice session..."));
> + } else {
> + g_object_get(app, "guri", &guri, NULL);
> + g_return_val_if_fail(guri != NULL, FALSE);
>
> - if (virt_viewer_app_create_session(app, type) < 0) {
> - virt_viewer_app_simple_message_dialog(app, _("Couldn't create a session for this type: %s"), type);
> - goto cleanup;
> - }
> + DEBUG_LOG("Opening display to %s", guri);
> + g_object_set(app, "title", guri, NULL);
> +
> + if (virt_viewer_util_extract_host(guri, &type, NULL, NULL, NULL, NULL) < 0) {
> + virt_viewer_app_simple_message_dialog(app, _("Cannot determine the connection type from URI"));
> + goto cleanup;
> + }
> +
> + if (virt_viewer_app_create_session(app, type) < 0) {
> + virt_viewer_app_simple_message_dialog(app, _("Couldn't create a session for this type: %s"), type);
> + goto cleanup;
> + }
> +
> + if (virt_viewer_app_initial_connect(app) < 0) {
> + virt_viewer_app_simple_message_dialog(app, _("Failed to initiate connection"));
> + goto cleanup;
> + }
>
> - if (virt_viewer_app_activate(app) < 0) {
> - virt_viewer_app_simple_message_dialog(app, _("Failed to initiate connection"));
> - goto cleanup;
> }
>
> ret = VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->start(app);
>
> - cleanup:
> +cleanup:
> g_free(guri);
> g_free(type);
> return ret;
> diff --git a/src/remote-viewer.h b/src/remote-viewer.h
> index 1ff6d8d..3d02315 100644
> --- a/src/remote-viewer.h
> +++ b/src/remote-viewer.h
> @@ -48,8 +48,8 @@ typedef struct {
>
> GType remote_viewer_get_type (void);
>
> -RemoteViewer *
> -remote_viewer_new(const gchar *uri, gboolean verbose);
> +RemoteViewer* remote_viewer_new(const gchar *uri, gboolean verbose);
> +RemoteViewer* remote_viewer_new_with_controller(gboolean verbose);
>
> G_END_DECLS
>
ACK, but the bits that follow this point should probably go in a separate patch...
> diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c
> index 97b53c2..352f206 100644
> --- a/src/virt-viewer-app.c
> +++ b/src/virt-viewer-app.c
> @@ -1528,6 +1528,13 @@ virt_viewer_app_show_display(VirtViewerApp *self)
> g_hash_table_foreach(self->priv->windows, show_display_cb, self);
> }
>
> +GHashTable*
> +virt_viewer_app_get_windows(VirtViewerApp *self)
> +{
> + g_return_val_if_fail(VIRT_VIEWER_IS_APP(self), NULL);
> + return self->priv->windows;
> +}
> +
> /*
> * Local variables:
> * c-indent-level: 8
> diff --git a/src/virt-viewer-app.h b/src/virt-viewer-app.h
> index 7c3f0a7..320e75c 100644
> --- a/src/virt-viewer-app.h
> +++ b/src/virt-viewer-app.h
> @@ -86,6 +86,7 @@ void virt_viewer_app_set_connect_info(VirtViewerApp *self,
> gboolean virt_viewer_app_window_set_visible(VirtViewerApp *self, VirtViewerWindow *window, gboolean visible);
> void virt_viewer_app_show_status(VirtViewerApp *self, const gchar *fmt, ...);
> void virt_viewer_app_show_display(VirtViewerApp *self);
> +GHashTable* virt_viewer_app_get_windows(VirtViewerApp *self);
>
> G_END_DECLS
>
> diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c
> index 066f922..f89d042 100644
> --- a/src/virt-viewer-session-spice.c
> +++ b/src/virt-viewer-session-spice.c
> @@ -41,6 +41,12 @@ struct _VirtViewerSessionSpicePrivate {
>
> #define VIRT_VIEWER_SESSION_SPICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_SESSION_SPICE, VirtViewerSessionSpicePrivate))
>
> +enum {
> + PROP_0,
> + PROP_SPICE_SESSION,
> +};
> +
> +
> static void virt_viewer_session_spice_close(VirtViewerSession *session);
> static gboolean virt_viewer_session_spice_open_fd(VirtViewerSession *session, int fd);
> static gboolean virt_viewer_session_spice_open_host(VirtViewerSession *session, char *host, char *port);
> @@ -55,7 +61,33 @@ static void virt_viewer_session_spice_channel_destroy(SpiceSession *s,
>
>
> static void
> -virt_viewer_session_spice_finalize(GObject *obj)
> +virt_viewer_session_spice_get_property(GObject *object, guint property_id,
> + GValue *value, GParamSpec *pspec)
> +{
> + VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(object);
> + VirtViewerSessionSpicePrivate *priv = self->priv;
> +
> + switch (property_id) {
> + case PROP_SPICE_SESSION:
> + g_value_set_object(value, priv->session);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
> + }
> +}
> +
> +static void
> +virt_viewer_session_spice_set_property(GObject *object, guint property_id,
> + const GValue *value G_GNUC_UNUSED, GParamSpec *pspec)
> +{
> + switch (property_id) {
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
> + }
> +}
> +
> +static void
> +virt_viewer_session_spice_dispose(GObject *obj)
> {
> VirtViewerSessionSpice *spice = VIRT_VIEWER_SESSION_SPICE(obj);
>
> @@ -76,7 +108,9 @@ virt_viewer_session_spice_class_init(VirtViewerSessionSpiceClass *klass)
> VirtViewerSessionClass *dclass = VIRT_VIEWER_SESSION_CLASS(klass);
> GObjectClass *oclass = G_OBJECT_CLASS(klass);
>
> - oclass->finalize = virt_viewer_session_spice_finalize;
> + oclass->get_property = virt_viewer_session_spice_get_property;
> + oclass->set_property = virt_viewer_session_spice_set_property;
> + oclass->dispose = virt_viewer_session_spice_dispose;
>
> dclass->close = virt_viewer_session_spice_close;
> dclass->open_fd = virt_viewer_session_spice_open_fd;
> @@ -85,6 +119,15 @@ virt_viewer_session_spice_class_init(VirtViewerSessionSpiceClass *klass)
> dclass->channel_open_fd = virt_viewer_session_spice_channel_open_fd;
>
> g_type_class_add_private(oclass, sizeof(VirtViewerSessionSpicePrivate));
> +
> + g_object_class_install_property(oclass,
> + PROP_SPICE_SESSION,
> + g_param_spec_object("spice-session",
> + "Spice session",
> + "Spice session",
> + SPICE_TYPE_SESSION,
> + G_PARAM_READABLE |
> + G_PARAM_STATIC_STRINGS));
> }
>
> static void
> diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c
> index 324e37f..d80b456 100644
> --- a/src/virt-viewer-window.c
> +++ b/src/virt-viewer-window.c
> @@ -912,9 +912,18 @@ GtkMenuItem*
> virt_viewer_window_get_menu_displays(VirtViewerWindow *self)
> {
> g_return_val_if_fail(VIRT_VIEWER_IS_WINDOW(self), NULL);
> +
> return GTK_MENU_ITEM(gtk_builder_get_object(self->priv->builder, "menu-displays"));
> }
>
> +GtkBuilder*
> +virt_viewer_window_get_builder(VirtViewerWindow *self)
> +{
> + g_return_val_if_fail(VIRT_VIEWER_IS_WINDOW(self), NULL);
> +
> + return self->priv->builder;
> +}
> +
> /*
> * Local variables:
> * c-indent-level: 8
> diff --git a/src/virt-viewer-window.h b/src/virt-viewer-window.h
> index 9baab76..cf66f5e 100644
> --- a/src/virt-viewer-window.h
> +++ b/src/virt-viewer-window.h
> @@ -69,6 +69,7 @@ gint virt_viewer_window_get_zoom_level(VirtViewerWindow *self);
> void virt_viewer_window_leave_fullscreen(VirtViewerWindow *self);
> void virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gboolean move, gint x, gint y);
> GtkMenuItem *virt_viewer_window_get_menu_displays(VirtViewerWindow *self);
> +GtkBuilder* virt_viewer_window_get_builder(VirtViewerWindow *window);
>
> G_END_DECLS
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the virt-tools-list
mailing list