From 407836ecee308b4b5ce00109bca4e70f344ebe34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 11 Feb 2021 18:18:11 +0000 Subject: [PATCH] src: convert displays menu to use actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This better decouples the user interface from the implementation. Signed-off-by: Daniel P. Berrangé --- src/virt-viewer-app.c | 288 +++++++++++++++++++++++++++++++++++------- 1 file changed, 239 insertions(+), 49 deletions(-) diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c index 1c59d95..314da82 100644 --- a/src/virt-viewer-app.c +++ b/src/virt-viewer-app.c @@ -104,6 +104,15 @@ static void virt_viewer_update_smartcard_accels(VirtViewerApp *self); static void virt_viewer_update_usbredir_accels(VirtViewerApp *self); static void virt_viewer_app_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group); static VirtViewerWindow *virt_viewer_app_get_nth_window(VirtViewerApp *self, gint nth); +static VirtViewerWindow *virt_viewer_app_get_vte_window(VirtViewerApp *self, const gchar *name); + +/* Application actions */ +static void virt_viewer_app_action_monitor(GSimpleAction *act, + GVariant *param, + gpointer opaque); +static void virt_viewer_app_action_vte(GSimpleAction *act, + GVariant *state, + gpointer opaque); typedef struct _VirtViewerAppPrivate VirtViewerAppPrivate; @@ -1059,6 +1068,32 @@ virt_viewer_app_get_nth_window(VirtViewerApp *self, gint nth) return NULL; } +static VirtViewerWindow * +virt_viewer_app_get_vte_window(VirtViewerApp *self, const gchar *name) +{ + VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); + GList *l; + + if (!name) + return NULL; + + for (l = priv->windows; l; l = l->next) { + VirtViewerDisplay *display = virt_viewer_window_get_display(l->data); + if (display && + VIRT_VIEWER_IS_DISPLAY_VTE(display)) { + char *thisname = NULL; + gboolean match; + g_object_get(display, "name", &thisname, NULL); + match = thisname && g_str_equal(name, thisname); + g_free(thisname); + if (match) { + return l->data; + } + } + } + return NULL; +} + static void viewer_window_visible_cb(GtkWidget *widget G_GNUC_UNUSED, gpointer user_data) @@ -2258,6 +2293,87 @@ virt_viewer_app_action_smartcard_remove(GSimpleAction *act G_GNUC_UNUSED, virt_viewer_session_smartcard_remove(virt_viewer_app_get_session(self)); } +static void +virt_viewer_app_action_window(VirtViewerApp *self, + VirtViewerWindow *win, + GSimpleAction *act, + GVariant *state) +{ + VirtViewerDisplay *display; + VirtViewerAppPrivate *priv; + gboolean visible = g_variant_get_boolean(state); + + g_return_if_fail(VIRT_VIEWER_IS_WINDOW(win)); + + priv = virt_viewer_app_get_instance_private(self); + display = virt_viewer_window_get_display(win); + + if (visible) { + virt_viewer_window_show(win); + } else { + if (virt_viewer_app_get_n_windows_visible(self) > 1) { + virt_viewer_window_hide(win); + } else { + virt_viewer_app_maybe_quit(self, win); + if (!priv->quitting) + /* the last item remains active, doesn't matter if we quit */ + g_action_change_state(G_ACTION(act), + g_variant_new_boolean(TRUE)); + } + } + + if (!priv->quitting) + virt_viewer_session_update_displays_geometry(virt_viewer_display_get_session(display)); + + g_simple_action_set_state(act, g_variant_new_boolean(visible)); +} + + +static void +virt_viewer_app_action_monitor(GSimpleAction *act, + GVariant *state, + gpointer opaque) +{ + VirtViewerApp *self; + VirtViewerWindow *win; + VirtViewerAppPrivate *priv; + int nth; + + g_return_if_fail(VIRT_VIEWER_IS_APP(opaque)); + self = VIRT_VIEWER_APP(opaque); + + priv = virt_viewer_app_get_instance_private(self); + if (priv->quitting) + return; + + nth = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(act), "nth")); + win = virt_viewer_app_get_nth_window(self, nth); + + virt_viewer_app_action_window(self, win, act, state); +} + +static void +virt_viewer_app_action_vte(GSimpleAction *act, + GVariant *state, + gpointer opaque) +{ + VirtViewerApp *self; + VirtViewerWindow *win; + VirtViewerAppPrivate *priv; + const gchar *name; + + g_return_if_fail(VIRT_VIEWER_IS_APP(opaque)); + self = VIRT_VIEWER_APP(opaque); + + priv = virt_viewer_app_get_instance_private(self); + if (priv->quitting) + return; + + name = g_object_get_data(G_OBJECT(act), "vte"); + win = virt_viewer_app_get_vte_window(self, name); + virt_viewer_app_action_window(self, win, act, state); +} + static GActionEntry actions[] = { { .name = "machine-reset", .activate = virt_viewer_app_action_machine_reset }, @@ -2766,30 +2882,6 @@ virt_viewer_app_set_fullscreen(VirtViewerApp *self, gboolean fullscreen) g_object_notify(G_OBJECT(self), "fullscreen"); } -static void -menu_display_visible_toggled_cb(GtkCheckMenuItem *checkmenuitem, - VirtViewerDisplay *display) -{ - VirtViewerApp *self = virt_viewer_session_get_app(virt_viewer_display_get_session(display)); - gboolean visible = gtk_check_menu_item_get_active(checkmenuitem); - VirtViewerWindow *vwin; - - vwin = ensure_window_for_display(self, display); - - if (visible) { - virt_viewer_window_show(vwin); - } else { - if (virt_viewer_app_get_n_windows_visible(self) > 1) { - virt_viewer_window_hide(vwin); - } else { - virt_viewer_app_maybe_quit(self, vwin); - /* the last item remains active, doesn't matter if we quit */ - gtk_check_menu_item_set_active(checkmenuitem, TRUE); - } - } - - virt_viewer_session_update_displays_geometry(virt_viewer_display_get_session(display)); -} static gint update_menu_displays_sort(gconstpointer a, gconstpointer b) @@ -2845,6 +2937,7 @@ window_update_menu_displays_cb(gpointer value, GList *keys = g_hash_table_get_keys(priv->displays); GList *tmp; gboolean sensitive; + int nth; keys = g_list_sort(keys, update_menu_displays_sort); submenu = window_empty_display_submenu(VIRT_VIEWER_WINDOW(value)); @@ -2854,19 +2947,92 @@ window_update_menu_displays_cb(gpointer value, tmp = keys; while (tmp) { - int nth = GPOINTER_TO_INT(tmp->data); - VirtViewerWindow *vwin = virt_viewer_app_get_nth_window(self, nth); - VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(g_hash_table_lookup(priv->displays, tmp->data)); GtkWidget *item; - gboolean visible; gchar *label; + gchar *actionname; + nth = GPOINTER_TO_INT(tmp->data); + actionname = g_strdup_printf("app.monitor-%d", nth); label = g_strdup_printf(_("Display _%d"), nth + 1); item = gtk_check_menu_item_new_with_mnemonic(label); - g_free(label); + gtk_actionable_set_action_name(GTK_ACTIONABLE(item), actionname); + + gtk_menu_shell_append(submenu, item); + + g_free(label); + g_free(actionname); + + tmp = tmp->next; + } + + for (tmp = priv->windows, nth = 0; tmp; tmp = tmp->next, nth++) { + VirtViewerWindow *win = VIRT_VIEWER_WINDOW(tmp->data); + VirtViewerDisplay *display = virt_viewer_window_get_display(win); + + if (VIRT_VIEWER_IS_DISPLAY_VTE(display)) { + gchar *name = NULL; + GtkWidget *item; + gchar *actionname; + + g_object_get(display, "name", &name, NULL); + actionname = g_strdup_printf("app.vte-%d", nth); + + item = gtk_check_menu_item_new_with_label(name); + + gtk_actionable_set_action_name(GTK_ACTIONABLE(item), actionname); + + gtk_menu_shell_append(submenu, item); + + g_free(actionname); + g_free(name); + } + } + + gtk_widget_show_all(GTK_WIDGET(submenu)); + g_list_free(keys); +} + +static void +virt_viewer_app_clear_window_actions(VirtViewerApp *self) +{ + gchar **oldactions = g_action_group_list_actions(G_ACTION_GROUP(self)); + int i; + + for (i = 0; oldactions && oldactions[i] != NULL; i++) { + if (g_str_has_prefix(oldactions[i], "monitor-") || + g_str_has_prefix(oldactions[i], "vte-")) { + g_action_map_remove_action(G_ACTION_MAP(self), oldactions[i]); + } + } + + g_strfreev(oldactions); +} + + +static void +virt_viewer_app_create_window_actions(VirtViewerApp *self) +{ + VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); + GList *keys = g_hash_table_get_keys(priv->displays); + GList *tmp; + gboolean sensitive; + gboolean visible; + GSimpleAction *action; + gchar *actionname; + int nth; + + tmp = keys; + while (tmp) { + VirtViewerWindow *vwin; + VirtViewerDisplay *display; + + nth = GPOINTER_TO_INT(tmp->data); + actionname = g_strdup_printf("monitor-%d", nth); + + vwin = virt_viewer_app_get_nth_window(self, nth); + display = VIRT_VIEWER_DISPLAY(g_hash_table_lookup(priv->displays, tmp->data)); visible = vwin && gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(vwin))); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), visible); sensitive = visible; if (display) { @@ -2878,35 +3044,57 @@ window_update_menu_displays_cb(gpointer value, if (virt_viewer_display_get_selectable(display)) sensitive = TRUE; } - gtk_widget_set_sensitive(item, sensitive); - virt_viewer_signal_connect_object(G_OBJECT(item), "toggled", - G_CALLBACK(menu_display_visible_toggled_cb), display, 0); - gtk_menu_shell_append(submenu, item); + action = g_simple_action_new_stateful(actionname, + NULL, + g_variant_new_boolean(visible)); + g_object_set_data(G_OBJECT(action), "nth", GINT_TO_POINTER(nth)); + g_simple_action_set_enabled(action, + sensitive); + + g_signal_connect(action, "change-state", + G_CALLBACK(virt_viewer_app_action_monitor), + self); + + g_action_map_add_action(G_ACTION_MAP(self), G_ACTION(action)); + + + g_free(actionname); + tmp = tmp->next; } - for (tmp = priv->windows; tmp; tmp = tmp->next) { + for (tmp = priv->windows, nth = 0; tmp; tmp = tmp->next, nth++) { VirtViewerWindow *win = VIRT_VIEWER_WINDOW(tmp->data); VirtViewerDisplay *display = virt_viewer_window_get_display(win); + gchar *name; - if (VIRT_VIEWER_IS_DISPLAY_VTE(display)) { - gchar *name = NULL; - GtkWidget *item; - - g_object_get(display, "name", &name, NULL); - item = gtk_check_menu_item_new_with_label(name); - g_free(name); - - virt_viewer_signal_connect_object(G_OBJECT(item), "toggled", - G_CALLBACK(menu_display_visible_toggled_cb), display, 0); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), - gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(win)))); - gtk_menu_shell_append(submenu, item); + if (!VIRT_VIEWER_IS_DISPLAY_VTE(display)) { + continue; } + + g_object_get(display, "name", &name, NULL); + actionname = g_strdup_printf("vte-%d", nth); + + visible = gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(win))); + + action = g_simple_action_new_stateful(actionname, + NULL, + g_variant_new_boolean(visible)); + g_object_set_data_full(G_OBJECT(action), "vte", g_strdup(name), g_free); + g_simple_action_set_enabled(G_SIMPLE_ACTION(action), + TRUE); + + g_signal_connect(action, "change-state", + G_CALLBACK(virt_viewer_app_action_vte), + self); + + g_action_map_add_action(G_ACTION_MAP(self), G_ACTION(action)); + + g_free(actionname); + g_free(name); } - gtk_widget_show_all(GTK_WIDGET(submenu)); g_list_free(keys); } @@ -2916,6 +3104,8 @@ virt_viewer_app_update_menu_displays(VirtViewerApp *self) VirtViewerAppPrivate *priv = virt_viewer_app_get_instance_private(self); if (!priv->windows) return; + virt_viewer_app_clear_window_actions(self); + virt_viewer_app_create_window_actions(self); g_list_foreach(priv->windows, window_update_menu_displays_cb, self); }