From 0e432d00a2ef323edf48960fbce2c087ee2023c6 Mon Sep 17 00:00:00 2001 From: Jose Antonio Ortega Ruiz Date: Wed, 30 Jun 2004 14:07:51 +0000 Subject: detachable windows in gtk+2 --- mixgtk/mixgtk_wm.c | 559 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 450 insertions(+), 109 deletions(-) (limited to 'mixgtk/mixgtk_wm.c') diff --git a/mixgtk/mixgtk_wm.c b/mixgtk/mixgtk_wm.c index 9a7e2ef..76072a8 100644 --- a/mixgtk/mixgtk_wm.c +++ b/mixgtk/mixgtk_wm.c @@ -1,32 +1,40 @@ /* -*-c-*- -------------- mixgtk_wm.c : * Implementation of the functions declared in mixgtk_wm.h * ------------------------------------------------------------------ - * $Id: mixgtk_wm.c,v 1.6 2002/03/29 16:30:49 jao Exp $ + * $Id: mixgtk_wm.c,v 1.7 2004/06/30 14:07:52 jao Exp $ * ------------------------------------------------------------------ - * Copyright (C) 2001, 2002 Free Software Foundation, Inc. - * + * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * + * */ #include +#include "mixgtk_wm.h" + #include "mixgtk_widgets.h" #include "mixgtk_config.h" -#include "mixgtk_wm.h" +#include "mixgtk_device.h" +#include "mixgtk_mixvm.h" +#include "mixgtk_mixal.h" +#include "mixgtk_widgets.h" +#include "mixgtk_cmd_dispatcher.h" +#include "mixgtk.h" + typedef struct window_info_t_ { mixgtk_dialog_id_t dialog; @@ -34,93 +42,121 @@ typedef struct window_info_t_ GtkCheckMenuItem *menu; const gchar *menu_name; const gchar *config_key; - gboolean visible; + gboolean detached; const gchar *toolbar_name; + void (*detach) (void); + void (*attach) (void); } window_info_t_; -static window_info_t_ infos_[] = { - {MIXGTK_MIXVM_DIALOG, NULL, NULL, "mix_view", "MIX.view", FALSE, NULL}, - {MIXGTK_MIXAL_DIALOG, NULL, NULL, "mixal_view", "MIXAL.view", FALSE, - "mixal_toolbar"}, - {MIXGTK_DEVICES_DIALOG, NULL, NULL, "devices_view", "Devices.view", - FALSE, "devices_toolbar"} -}; +static const gchar *DETACH_YES_ = "Yes"; +static const gchar *DETACH_NO_ = "No"; +static GtkWidget *about_ = NULL; -static size_t INF_NO_ = sizeof (infos_) / sizeof (infos_[0]); +static GtkContainer *mixvm_container_ = NULL; +static GtkContainer *mixal_container_ = NULL; +static GtkContainer *dev_container_ = NULL; -static gboolean split_ = FALSE; static const gchar *TB_MENU_NAME_ = "show_toolbars"; static GtkCheckMenuItem *tb_menu_ = NULL; +static GtkNotebook *notebook_ = NULL; + +static mix_vm_t *vm_ = NULL; + +static void init_info_ (void); +static void init_notebook_ (void); +static void init_dispatcher_ (void); +static void init_mixvm_ (void); +static void init_mixal_ (void); +static void init_dev_ (void); +static void init_signals_ (void); +static void init_visibility_ (void); +static void init_tb_ (void); +static void init_about_ (void); +static void init_autosave_ (void); +static void remove_page_ (gint page); +static void add_page_ (GtkWidget *w, mixgtk_window_id_t id); +static void mixvm_attach_ (void); +static void mixvm_detach_ (void); +static void mixal_attach_ (void); +static void mixal_detach_ (void); +static void dev_attach_ (void); +static void dev_detach_ (void); +static void on_nb_switch_ (GtkNotebook *notebook, GtkNotebookPage *page, + guint page_num, gpointer user_data); -static const gchar *VIEW_YES_ = "Yes"; -static const gchar *VIEW_NO_ = "No"; +static window_info_t_ infos_[] = { + {MIXGTK_MIXVM_DIALOG, NULL, NULL, "detach_vm", "MIX.detach", + FALSE, NULL, mixvm_detach_, mixvm_attach_}, + {MIXGTK_MIXAL_DIALOG, NULL, NULL, "detach_source", "MIXAL.detach", + FALSE, "mixal_toolbar", mixal_detach_, mixal_attach_}, + {MIXGTK_DEVICES_DIALOG, NULL, NULL, "detach_dev", "Devices.detach", + FALSE, "devices_toolbar", dev_detach_, dev_attach_} +}; -/* flag marking that we are inside a restart process */ -static gboolean restart_ = FALSE; +static size_t INF_NO_ = sizeof (infos_) / sizeof (infos_[0]); + gboolean mixgtk_wm_init (void) { - split_ = mixgtk_config_is_split (); - if (split_) - { - gint i; - for (i = 0; i < INF_NO_; ++i) - { - const gchar *view = mixgtk_config_get (infos_[i].config_key); - infos_[i].visible = !view || !strcmp (VIEW_YES_, view); - if (!view) mixgtk_config_update (infos_[i].config_key, VIEW_YES_); - infos_[i].widget = - mixgtk_widget_factory_get_dialog (infos_[i].dialog); - g_return_val_if_fail (infos_[i].widget, FALSE); - infos_[i].menu = GTK_CHECK_MENU_ITEM - (mixgtk_widget_factory_get_child_by_name - (MIXGTK_MAIN, infos_[i].menu_name)); - g_return_val_if_fail (infos_[i].menu, FALSE); - if (infos_[i].visible) gtk_widget_show (infos_[i].widget); - gtk_check_menu_item_set_active (infos_[i].menu, infos_[i].visible); - } - } - else + gint k; + + init_info_ (); + init_notebook_ (); + init_dispatcher_ (); + init_mixvm_ (); + init_mixal_ (); + init_dev_ (); + + for (k = 0; k < INF_NO_; ++k) { - gint k; - for (k = 0; k < INF_NO_; ++k) - if (infos_[k].widget) gtk_widget_destroy (infos_[k].widget); + if (infos_[k].detached) + mixgtk_wm_detach_window (k); + else + mixgtk_wm_attach_window (k); } - tb_menu_ = GTK_CHECK_MENU_ITEM - (mixgtk_widget_factory_get_child_by_name (MIXGTK_MAIN, - TB_MENU_NAME_)); - g_return_val_if_fail (tb_menu_, FALSE); - gtk_check_menu_item_set_active (tb_menu_, mixgtk_config_show_toolbars ()); - mixgtk_wm_show_toolbars (mixgtk_config_show_toolbars ()); + init_tb_ (); + init_about_ (); + init_autosave_ (); + init_visibility_ (); + init_signals_ (); return TRUE; } void -mixgtk_wm_show_window (mixgtk_window_id_t w) +mixgtk_wm_detach_window (mixgtk_window_id_t w) { - g_return_if_fail (w < INF_NO_); - if (!infos_[w].visible) + if (w < INF_NO_) { - infos_[w].visible = TRUE; + (*(infos_[w].detach)) (); + infos_[w].detached = TRUE; gtk_check_menu_item_set_active (infos_[w].menu, TRUE); - mixgtk_config_update (infos_[w].config_key, VIEW_YES_); - gtk_widget_show (infos_[w].widget); + mixgtk_config_update (infos_[w].config_key, DETACH_YES_); + if (infos_[w].widget != NULL) gtk_widget_show (infos_[w].widget); + if (gtk_notebook_get_n_pages (notebook_) < 1) + gtk_widget_hide (GTK_WIDGET (notebook_)); + gtk_widget_show (mixgtk_widget_factory_get_dialog (infos_[w].dialog)); } } void -mixgtk_wm_hide_window (mixgtk_window_id_t w) +mixgtk_wm_attach_window (mixgtk_window_id_t w) { - g_return_if_fail (w < INF_NO_); - if (infos_[w].visible && !restart_) + if (w < INF_NO_) { - infos_[w].visible = FALSE; + gint page = gtk_notebook_page_num (notebook_, infos_[w].widget); + + gtk_widget_hide (mixgtk_widget_factory_get_dialog (infos_[w].dialog)); + + if (page < 0) (*(infos_[w].attach)) (); + + infos_[w].detached = FALSE; gtk_check_menu_item_set_active (infos_[w].menu, FALSE); - mixgtk_config_update (infos_[w].config_key, VIEW_NO_); - gtk_widget_hide (infos_[w].widget); + mixgtk_config_update (infos_[w].config_key, DETACH_NO_); + if (gtk_notebook_get_n_pages (notebook_) == 1) + gtk_widget_show (GTK_WIDGET (notebook_)); } } @@ -128,92 +164,397 @@ void mixgtk_wm_show_toolbars (gboolean show) { static const gchar *MAIN_TB_NAME = "main_toolbar"; + int k; + GtkWidget *toolbar = mixgtk_widget_factory_get_child_by_name (MIXGTK_MAIN, MAIN_TB_NAME); + if (toolbar != NULL) { if (show) gtk_widget_show (toolbar); else gtk_widget_hide (toolbar); } - - if (split_) + + for (k = 0; k < INF_NO_; ++k) { - int k; - for (k = 0; k < INF_NO_; ++k) - { - if (infos_[k].toolbar_name != NULL) - { - GtkWidget *tb = mixgtk_widget_factory_get_child_by_name - (infos_[k].dialog, infos_[k].toolbar_name); - if (show && tb) gtk_widget_show (tb); - else if (tb) gtk_widget_hide (tb); + if (infos_[k].toolbar_name != NULL) + { + GtkWidget *tb = mixgtk_widget_factory_get_child_by_name + (infos_[k].dialog, infos_[k].toolbar_name); + if (tb) + { + if (show) gtk_widget_show (tb); else gtk_widget_hide (tb); } } } - + mixgtk_config_set_show_toolbars (show); } + /* callbacks */ void -on_view_toggled (GtkCheckMenuItem *item) +on_detach_clicked (GtkWidget *ignored) { - if (!restart_) + gint page = gtk_notebook_get_current_page (notebook_); + if (page >= 0) { gint k; + GtkWidget *w = gtk_notebook_get_nth_page (notebook_, page); + for (k = 0; k < INF_NO_; ++k) - if (item == infos_[k].menu) break; - g_return_if_fail (k < INF_NO_); - if (item->active) - mixgtk_wm_show_window (k); - else - mixgtk_wm_hide_window (k); - mixgtk_config_update (infos_[k].config_key, - (item->active)? VIEW_YES_ : VIEW_NO_); - infos_[k].visible = item->active; + if (infos_[k].widget == w) mixgtk_wm_detach_window (k); } } void -on_one_window_activate () +on_attach_toggled (GtkCheckMenuItem *item) { - mixgtk_config_set_split (FALSE); - restart_ = TRUE; - gtk_widget_destroy (mixgtk_widget_factory_get_dialog (MIXGTK_MAIN)); + gint k; + for (k = 0; k < INF_NO_; ++k) + if (item == infos_[k].menu) break; + g_return_if_fail (k < INF_NO_); + if (item->active) mixgtk_wm_detach_window (k); + else mixgtk_wm_attach_window (k); + mixgtk_config_update (infos_[k].config_key, + (item->active)? DETACH_YES_ : DETACH_NO_); } void -on_split_windows_activate () +on_window_hide (GtkWidget *w) { - mixgtk_config_set_split (TRUE); - restart_ = TRUE; - gtk_widget_destroy (mixgtk_widget_factory_get_dialog (MIXGTK_MAIN)); + gint k; + for (k = 0; k < INF_NO_; ++k) + if (w == mixgtk_widget_factory_get_dialog (infos_[k].dialog)) break; + g_return_if_fail (k < INF_NO_); + mixgtk_wm_attach_window (k); } void -on_window_hide (GtkWidget *w) +on_show_toolbars_toggled (GtkCheckMenuItem *item) +{ + if (item->active != mixgtk_config_show_toolbars ()) + mixgtk_wm_show_toolbars (item->active); +} + +/* about box */ +void +on_about_activate (GtkWidget *w, gpointer data) +{ + if (!about_) init_about_ (); + gtk_widget_show (about_); +} + + +static void +init_info_ (void) { gint k; for (k = 0; k < INF_NO_; ++k) - if (w == infos_[k].widget) break; - g_return_if_fail (k < INF_NO_); - mixgtk_wm_hide_window (k); + { + const gchar *txt; + + infos_[k].menu = + GTK_CHECK_MENU_ITEM + (mixgtk_widget_factory_get_child_by_name (MIXGTK_MAIN, + infos_[k].menu_name)); + g_assert (infos_[k].menu != NULL); + txt = mixgtk_config_get (infos_[k].config_key); + infos_[k].detached = txt && !g_ascii_strcasecmp (txt, DETACH_YES_); + } } - -void -on_main_window_destroy (GtkWidget *w, gpointer data) + +static void +init_notebook_ (void) +{ + notebook_ = + GTK_NOTEBOOK (mixgtk_widget_factory_get (MIXGTK_MAIN, + MIXGTK_WIDGET_NOTEBOOK)); + g_assert (notebook_ != NULL); + + gtk_notebook_set_tab_pos (notebook_, GTK_POS_TOP); + gtk_notebook_popup_disable (notebook_); + gtk_notebook_remove_page (notebook_, 0); + + gtk_widget_show (GTK_WIDGET (notebook_)); +} + +static void +add_page_ (GtkWidget *page, mixgtk_window_id_t id) { - if (restart_) + static const gchar *LABELS[] = { + N_("_Virtual machine"), N_("_Source"), N_("_Devices") + }; + + g_assert (page != NULL); + g_assert (id < INF_NO_); + g_assert (notebook_ != NULL); + + gtk_notebook_append_page (notebook_, page, + gtk_label_new_with_mnemonic (LABELS[id])); + gtk_notebook_set_show_tabs (notebook_, + gtk_notebook_get_n_pages (notebook_) > 1); + gtk_widget_show (page); + gtk_widget_show (GTK_WIDGET (notebook_)); +} + +static void +remove_page_ (gint page) +{ + gint pages; + + g_assert (notebook_ != NULL); + gtk_notebook_remove_page (notebook_, page); + + pages = gtk_notebook_get_n_pages (notebook_); + if (pages < 1) gtk_widget_hide (GTK_WIDGET (notebook_)); + else gtk_notebook_set_show_tabs (notebook_, pages > 1); +} + +static void +init_signals_ (void) +{ + gint k; + for (k = 0; k < INF_NO_; ++k) { - mixgtk_restart (); - restart_ = FALSE; + GObject *dialog = + G_OBJECT (mixgtk_widget_factory_get_dialog (infos_[k].dialog)); + + g_assert (dialog); + + g_signal_connect (dialog, "destroy", + G_CALLBACK (on_window_hide), NULL); + g_signal_connect (dialog, "destroy_event", + G_CALLBACK (on_window_hide), NULL); + g_signal_connect (dialog, "delete_event", + G_CALLBACK (on_window_hide), NULL); + g_signal_connect (G_OBJECT (infos_[k].menu), "toggled", + G_CALLBACK (on_attach_toggled), NULL); } - else gtk_main_quit (); + + g_signal_connect (G_OBJECT (notebook_), "switch-page", + G_CALLBACK (on_nb_switch_), NULL); } -void -on_show_toolbars_toggled (GtkCheckMenuItem *item) +static void +init_visibility_ (void) { - if (!restart_ && item->active != mixgtk_config_show_toolbars ()) - mixgtk_wm_show_toolbars (item->active); + gint k; + for (k = 0; k < INF_NO_; ++k) + if (infos_[k].detached) + gtk_widget_show (mixgtk_widget_factory_get_dialog (infos_[k].dialog)); + gtk_widget_show (mixgtk_widget_factory_get_dialog (MIXGTK_MAIN)); +} + +static void +init_dispatcher_ (void) +{ + if (!mixgtk_cmd_dispatcher_init (MIXGTK_MAIN)) + g_assert (FALSE); + vm_ = mixgtk_cmd_dispatcher_get_vm (); + g_assert (vm_ != NULL); +} + +static void +init_mixvm_ (void) +{ + GtkContainer *vm = + GTK_CONTAINER + (mixgtk_widget_factory_get (MIXGTK_MIXVM_DIALOG, MIXGTK_WIDGET_MIXVM)); + + mixvm_container_ = + GTK_CONTAINER (mixgtk_widget_factory_get (MIXGTK_MIXVM_DIALOG, + MIXGTK_WIDGET_MIXVM_CONTAINER)); + + g_assert (mixvm_container_ != NULL); + + g_assert (vm != NULL); + g_object_ref (G_OBJECT (vm)); + infos_[MIXGTK_MIXVM_WINDOW].widget = GTK_WIDGET (vm); + + mixgtk_mixvm_init (vm_); + mixgtk_mixvm_update_vm_widgets (); + + gtk_widget_show (GTK_WIDGET (vm)); + +} + +static void +init_mixal_ (void) +{ + GtkWidget *page = gtk_scrolled_window_new (NULL, NULL); + GtkWidget *mixal = mixgtk_mixal_init (vm_); + + g_assert (page != NULL); + g_assert (mixal != NULL); + + g_object_ref (page); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (page), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_container_add (GTK_CONTAINER (page), mixal); + + infos_[MIXGTK_MIXAL_WINDOW].widget = page; + + mixal_container_ = + GTK_CONTAINER (mixgtk_widget_factory_get (MIXGTK_MIXAL_DIALOG, + MIXGTK_WIDGET_MIXAL_CONTAINER)); + + g_assert (mixal_container_ != NULL); + + gtk_container_add (mixal_container_, page); + + gtk_widget_show (mixal); + gtk_widget_show (page); +} + +static void +init_dev_ (void) +{ + GtkWidget *page = gtk_scrolled_window_new (NULL, NULL); + GtkWidget *devs = mixgtk_device_init (vm_); + + g_assert (page != NULL); + g_assert (devs != NULL); + + g_object_ref (page); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (page), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (page), devs); + + infos_[MIXGTK_DEVICES_WINDOW].widget = page; + + dev_container_ = + GTK_CONTAINER (mixgtk_widget_factory_get (MIXGTK_DEVICES_DIALOG, + MIXGTK_WIDGET_DEV_CONTAINER)); + + g_assert (dev_container_ != NULL); + + gtk_container_add (dev_container_, page); + + gtk_widget_show (devs); + gtk_widget_show (page); +} + +static void +init_tb_ (void) +{ + tb_menu_ = GTK_CHECK_MENU_ITEM + (mixgtk_widget_factory_get_child_by_name (MIXGTK_MAIN, + TB_MENU_NAME_)); + g_assert (tb_menu_ != NULL); + + gtk_check_menu_item_set_active (tb_menu_, mixgtk_config_show_toolbars ()); + mixgtk_wm_show_toolbars (mixgtk_config_show_toolbars ()); + + g_signal_connect (G_OBJECT (tb_menu_), "toggled", + G_CALLBACK (on_show_toolbars_toggled), NULL); +} + +static void +init_autosave_ (void) +{ +#define AUTOSAVE_ITEM_ "save_on_exit" + + GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM + (mixgtk_widget_factory_get_child_by_name (MIXGTK_MAIN, AUTOSAVE_ITEM_)); + if (item) + { + gtk_check_menu_item_set_active (item, mixgtk_config_is_autosave ()); + } +} + +static void +init_about_ (void) +{ +#define VERSION_LABEL_ "version_label" +#define GPL_TEXT_ "gpl_text" + GtkWidget *label; + about_ = mixgtk_widget_factory_get_dialog (MIXGTK_ABOUT_DIALOG); + g_assert (about_ != NULL); + label = mixgtk_widget_factory_get_child_by_name (MIXGTK_ABOUT_DIALOG, + VERSION_LABEL_); + g_assert (label != NULL); + gtk_label_set_text (GTK_LABEL (label), VERSION); + gtk_widget_show (label); +} + +static void +mixvm_attach_ (void) +{ + gtk_container_remove (mixvm_container_, infos_[MIXGTK_MIXVM_WINDOW].widget); + add_page_ (infos_[MIXGTK_MIXVM_WINDOW].widget, MIXGTK_MIXVM_WINDOW); +} + +static void +mixvm_detach_ (void) +{ + gtk_widget_reparent (infos_[MIXGTK_MIXVM_WINDOW].widget, + GTK_WIDGET (mixvm_container_)); +} + +static void +mixal_attach_ (void) +{ + static GtkStatusbar *stat = NULL; + + if (stat == NULL) + { + stat = + GTK_STATUSBAR + (mixgtk_widget_factory_get (MIXGTK_MAIN, MIXGTK_WIDGET_STATUSBAR)); + g_assert (stat); + + } + + mixgtk_mixal_reparent (stat); + gtk_container_remove (mixal_container_, infos_[MIXGTK_MIXAL_WINDOW].widget); + add_page_ (infos_[MIXGTK_MIXAL_WINDOW].widget, MIXGTK_MIXAL_WINDOW); +} + +static void +mixal_detach_ (void) +{ + static GtkStatusbar *stat = NULL; + + if (stat == NULL) + { + stat = + GTK_STATUSBAR + (mixgtk_widget_factory_get (MIXGTK_MIXAL_DIALOG, + MIXGTK_WIDGET_MIXAL_STATUSBAR)); + g_assert (stat); + } + else + gtk_widget_reparent (infos_[MIXGTK_MIXAL_WINDOW].widget, + GTK_WIDGET (mixal_container_)); + + mixgtk_mixal_reparent (stat); +} + +static void +dev_attach_ (void) +{ + gtk_container_remove (dev_container_, infos_[MIXGTK_DEVICES_WINDOW].widget); + add_page_ (infos_[MIXGTK_DEVICES_WINDOW].widget, MIXGTK_DEVICES_WINDOW); +} + +static void +dev_detach_ (void) +{ + gtk_widget_reparent (infos_[MIXGTK_DEVICES_WINDOW].widget, + GTK_WIDGET (dev_container_)); +} + +static void +on_nb_switch_ (GtkNotebook *notebook, GtkNotebookPage *page, + guint page_num, gpointer user_data) +{ + if (!infos_[MIXGTK_MIXAL_WINDOW].detached + && page != NULL + && GTK_WIDGET (page) != infos_[MIXGTK_MIXAL_WINDOW].widget) + mixgtk_mixal_pop_status (); } -- cgit v1.2.3