/* * mooui/moowindow.c * * Copyright (C) 2004-2005 by Yevgen Muntyan * * 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. * * See COPYING file that comes with this distribution. */ #include "mooui/moowindow.h" #include "mooui/moouiobject-impl.h" #include "mooui/mooshortcutsprefs.h" #include "mooui/mootoggleaction.h" #include "mooui/moomenuaction.h" #include "mooutils/mooprefs.h" #include "mooutils/moomarshals.h" #include "mooutils/moocompat.h" #include "mooutils/moostock.h" #include #define PREFS_REMEMBER_SIZE "window/remember_size" #define PREFS_WIDTH "window/width" #define PREFS_HEIGHT "window/height" #define PREFS_MAXIMIZED "window/maximized" #define PREFS_SHOW_TOOLBAR "window/show_toolbar" #define PREFS_SHOW_MENUBAR "window/show_menubar" #define PREFS_TOOLBAR_STYLE "window/toolbar_style" inline static const char *setting (MooWindow *window, const char *s) { static char *string = NULL; char *id = moo_ui_object_get_id (MOO_UI_OBJECT (window)); g_free (string); if (id) string = g_strdup_printf ("%s/%s", id, s); else string = g_strdup (s); g_free (id); return s; } static void init_prefs (MooWindow *window); static GtkToolbarStyle get_toolbar_style (MooWindow *window); struct _MooWindowPrivate { guint save_size_id; char *toolbar_ui_name; char *menubar_ui_name; GtkWidget *menubar_holder; GtkWidget *toolbar_holder; }; static void moo_window_class_init (MooWindowClass *klass); GObject *moo_window_constructor (GType type, guint n_props, GObjectConstructParam *props); static void moo_window_init (MooWindow *window); static void moo_window_finalize (GObject *object); static void moo_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void moo_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static gboolean moo_window_delete_event (GtkWidget *widget, GdkEventAny *event); static gboolean moo_window_save_size (MooWindow *window); static gboolean moo_window_create_ui (MooWindow *window); static void moo_window_shortcuts_prefs_dialog (MooWindow *window); static void moo_window_show_menubar_toggled (MooWindow *window, gboolean show); static void moo_window_show_toolbar_toggled (MooWindow *window, gboolean show); static GtkMenuItem *moo_window_create_toolbar_style_menu (MooWindow *window); enum { PROP_0, PROP_ACCEL_GROUP, PROP_MENUBAR_UI_NAME, PROP_TOOLBAR_UI_NAME, PROP_UI_OBJECT_NAME, PROP_UI_OBJECT_ID, PROP_UI_OBJECT_XML, PROP_UI_OBJECT_ACTIONS }; enum { CLOSE, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; /* MOO_TYPE_WINDOW */ static gpointer moo_window_parent_class = NULL; GType moo_window_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo info = { sizeof (MooWindowClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) moo_window_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (MooWindow), 0, /* n_preallocs */ (GInstanceInitFunc) moo_window_init, NULL /* value_table */ }; static const GInterfaceInfo iface_info = { NULL, NULL, NULL }; type = g_type_register_static (GTK_TYPE_WINDOW, "MooWindow", &info, (GTypeFlags) 0); g_type_add_interface_static (type, MOO_TYPE_UI_OBJECT, &iface_info); } return type; } static void moo_window_class_init (MooWindowClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); moo_window_parent_class = g_type_class_peek_parent (klass); gobject_class->constructor = moo_window_constructor; gobject_class->finalize = moo_window_finalize; gobject_class->set_property = moo_window_set_property; gobject_class->get_property = moo_window_get_property; widget_class->delete_event = moo_window_delete_event; moo_ui_object_class_init (gobject_class, "MooWindow", "Window"); moo_ui_object_class_new_action (gobject_class, "ConfigureShortcuts", "name", "Configure Shortcuts", "label", "Configure _Shortcuts...", "tooltip", "Configure _Shortcuts...", "icon-stock-id", MOO_STOCK_KEYBOARD, "closure::callback", moo_window_shortcuts_prefs_dialog, NULL); moo_ui_object_class_new_action (gobject_class, "ShowToolbar", "action-type::", MOO_TYPE_TOGGLE_ACTION, "name", "Show Toolbar", "label", "Show Toolbar", "tooltip", "Show Toolbar", "toggled-callback", moo_window_show_toolbar_toggled, NULL); moo_ui_object_class_new_action (gobject_class, "ShowMenubar", "action-type::", MOO_TYPE_TOGGLE_ACTION, "name", "Show Menubar", "label", "Show Menubar", "tooltip", "Show Menubar", "toggled-callback", moo_window_show_menubar_toggled, NULL); moo_ui_object_class_new_action (gobject_class, "ToolbarStyle", "action-type::", MOO_TYPE_MENU_ACTION, "name", "Toolbar Style", "create-menu-func", moo_window_create_toolbar_style_menu, NULL); g_object_class_install_property (gobject_class, PROP_ACCEL_GROUP, g_param_spec_object ("accel-group", "accel-group", "accel-group", GTK_TYPE_ACCEL_GROUP, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_MENUBAR_UI_NAME, g_param_spec_string ("menubar-ui-name", "menubar-ui-name", "menubar-ui-name", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_TOOLBAR_UI_NAME, g_param_spec_string ("toolbar-ui-name", "toolbar-ui-name", "toolbar-ui-name", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_UI_OBJECT_NAME, g_param_spec_string ("ui-object-name", "ui-object-name", "ui-object-name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_UI_OBJECT_ID, g_param_spec_string ("ui-object-id", "ui-object-id", "ui-object-id", NULL, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_UI_OBJECT_ACTIONS, g_param_spec_object ("ui-object-actions", "ui-object-actions", "ui-object-actions", MOO_TYPE_ACTION_GROUP, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_UI_OBJECT_XML, g_param_spec_object ("ui-object-xml", "ui-object-xml", "ui-object-xml", MOO_TYPE_UI_XML, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); signals[CLOSE] = g_signal_new ("close", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MooWindowClass, close), g_signal_accumulator_true_handled, NULL, _moo_marshal_BOOL__VOID, G_TYPE_BOOLEAN, 0); } GObject *moo_window_constructor (GType type, guint n_props, GObjectConstructParam *props) { GtkWidget *vbox; MooActionGroup *actions; MooWindow *window; GObject *object = G_OBJECT_CLASS(moo_window_parent_class)->constructor (type, n_props, props); moo_ui_object_init (MOO_UI_OBJECT (object)); window = MOO_WINDOW (object); init_prefs (window); window->accel_group = gtk_accel_group_new (); gtk_window_add_accel_group (GTK_WINDOW (window), window->accel_group); vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (window), vbox); window->priv->menubar_holder = gtk_vbox_new (FALSE, 0); gtk_widget_show (window->priv->menubar_holder); gtk_box_pack_start (GTK_BOX (vbox), window->priv->menubar_holder, FALSE, FALSE, 0); window->priv->toolbar_holder = gtk_vbox_new (FALSE, 0); gtk_widget_show (window->priv->toolbar_holder); gtk_box_pack_start (GTK_BOX (vbox), window->priv->toolbar_holder, FALSE, FALSE, 0); window->menubar = NULL; window->toolbar = NULL; window->vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), window->vbox, TRUE, TRUE, 0); window->statusbar = gtk_statusbar_new (); gtk_box_pack_start (GTK_BOX (vbox), window->statusbar, FALSE, FALSE, 0); gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (window->statusbar), FALSE); actions = moo_ui_object_get_actions (MOO_UI_OBJECT (window)); moo_action_group_set_accel_group (actions, window->accel_group); g_signal_connect (window, "notify::toolbar-ui-name", G_CALLBACK (moo_window_create_ui), NULL); g_signal_connect (window, "notify::menubar-ui-name", G_CALLBACK (moo_window_create_ui), NULL); g_signal_connect (window, "notify::ui-object-xml", G_CALLBACK (moo_window_create_ui), NULL); g_idle_add ((GSourceFunc) moo_window_create_ui, window); if (moo_prefs_get_bool (setting (window, PREFS_REMEMBER_SIZE))) { int width = moo_prefs_get_int (setting (window, PREFS_WIDTH)); int height = moo_prefs_get_int (setting (window, PREFS_HEIGHT)); gtk_window_set_default_size (GTK_WINDOW (window), width, height); if (moo_prefs_get_bool (setting (window, PREFS_MAXIMIZED))) gtk_window_maximize (GTK_WINDOW (window)); } g_signal_connect (window, "configure-event", G_CALLBACK (moo_window_save_size), NULL); return object; } static void moo_window_init (MooWindow *window) { window->priv = g_new0 (MooWindowPrivate, 1); } static void moo_window_finalize (GObject *object) { MooWindow *window = MOO_WINDOW(object); g_free (window->priv->menubar_ui_name); g_free (window->priv->toolbar_ui_name); if (window->accel_group) g_object_unref (window->accel_group); if (window->priv->save_size_id) g_source_remove (window->priv->save_size_id); window->priv->save_size_id = 0; g_free (window->priv); G_OBJECT_CLASS (moo_window_parent_class)->finalize (object); } static gboolean moo_window_delete_event (GtkWidget *widget, G_GNUC_UNUSED GdkEventAny *event) { gboolean result = FALSE; g_signal_emit_by_name (widget, "close", &result); return result; } static gboolean save_size (MooWindow *window) { window->priv->save_size_id = 0; if (MOO_IS_WINDOW (window) && GTK_WIDGET_REALIZED (window)) { GdkWindowState state; state = gdk_window_get_state (GTK_WIDGET(window)->window); moo_prefs_set_bool (setting (window, PREFS_MAXIMIZED), state & GDK_WINDOW_STATE_MAXIMIZED); if (!(state & GDK_WINDOW_STATE_MAXIMIZED)) { int width, height; gtk_window_get_size (GTK_WINDOW (window), &width, &height); moo_prefs_set_int (setting (window, PREFS_WIDTH), width); moo_prefs_set_int (setting (window, PREFS_HEIGHT), height); } } return FALSE; } static gboolean moo_window_save_size (MooWindow *window) { if (!window->priv->save_size_id) window->priv->save_size_id = g_idle_add ((GSourceFunc)save_size, window); return FALSE; } gboolean moo_window_close (MooWindow *window) { gboolean result = FALSE; g_signal_emit_by_name (window, "close", &result); if (!result) { gtk_widget_destroy (GTK_WIDGET (window)); return TRUE; } else { return FALSE; } } static void moo_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { const char *name = NULL; MooWindow *window = MOO_WINDOW (object); MooUIObject *ui_obj = MOO_UI_OBJECT (object); switch (prop_id) { case PROP_TOOLBAR_UI_NAME: name = g_value_get_string (value); g_free (window->priv->toolbar_ui_name); window->priv->toolbar_ui_name = name ? g_strdup (name) : g_strdup (""); g_object_notify (object, "toolbar-ui-name"); break; case PROP_MENUBAR_UI_NAME: name = g_value_get_string (value); g_free (window->priv->menubar_ui_name); window->priv->menubar_ui_name = name ? g_strdup (name) : g_strdup (""); g_object_notify (object, "menubar-ui-name"); break; case PROP_UI_OBJECT_NAME: if (g_value_get_string (value)) _moo_ui_object_set_name_impl (ui_obj, g_value_get_string (value)); break; case PROP_UI_OBJECT_XML: if (g_value_get_object (value)) _moo_ui_object_set_ui_xml_impl (ui_obj, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void moo_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MooWindow *window = MOO_WINDOW (object); MooUIObject *ui_obj = MOO_UI_OBJECT (object); switch (prop_id) { case PROP_ACCEL_GROUP: g_value_set_object (value, window->accel_group); break; case PROP_TOOLBAR_UI_NAME: g_value_set_string (value, window->priv->toolbar_ui_name); break; case PROP_MENUBAR_UI_NAME: g_value_set_string (value, window->priv->menubar_ui_name); break; case PROP_UI_OBJECT_NAME: g_value_set_string (value, _moo_ui_object_get_name_impl (ui_obj)); break; case PROP_UI_OBJECT_ID: g_value_set_string (value, _moo_ui_object_get_id_impl (ui_obj)); break; case PROP_UI_OBJECT_XML: g_value_set_object (value, _moo_ui_object_get_ui_xml_impl (ui_obj)); break; case PROP_UI_OBJECT_ACTIONS: g_value_set_object (value, _moo_ui_object_get_actions_impl (ui_obj)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean moo_window_create_ui (MooWindow *window) { MooUIXML *xml; MooAction *show_toolbar, *show_menubar; GtkToolbarStyle style; g_return_val_if_fail (MOO_IS_WINDOW (window), FALSE); xml = moo_ui_object_get_ui_xml (MOO_UI_OBJECT (window)); if (window->menubar) { gtk_widget_destroy (window->menubar); window->menubar = NULL; } if (window->toolbar) { gtk_widget_destroy (window->toolbar); window->toolbar = NULL; } if (window->priv->menubar_ui_name && window->priv->menubar_ui_name[0]) { window->menubar = moo_ui_xml_create_widget (xml, MOO_UI_MENUBAR, window->priv->menubar_ui_name, moo_ui_object_get_actions (MOO_UI_OBJECT (window)), window->accel_group); g_return_val_if_fail (window->menubar != NULL, FALSE); gtk_box_pack_start (GTK_BOX (window->priv->menubar_holder), window->menubar, FALSE, FALSE, 0); gtk_widget_show (window->menubar); show_menubar = moo_action_group_get_action (moo_ui_object_get_actions (MOO_UI_OBJECT (window)), "ShowMenubar"); moo_toggle_action_set_active (MOO_TOGGLE_ACTION (show_menubar), moo_prefs_get_bool (setting (window, PREFS_SHOW_MENUBAR))); } if (window->priv->toolbar_ui_name && window->priv->toolbar_ui_name[0]) { window->toolbar = moo_ui_xml_create_widget (xml, MOO_UI_TOOLBAR, window->priv->toolbar_ui_name, moo_ui_object_get_actions (MOO_UI_OBJECT (window)), window->accel_group); g_return_val_if_fail (window->toolbar != NULL, FALSE); gtk_box_pack_start (GTK_BOX (window->priv->toolbar_holder), window->toolbar, FALSE, FALSE, 0); gtk_widget_show (window->toolbar); show_toolbar = moo_action_group_get_action (moo_ui_object_get_actions (MOO_UI_OBJECT (window)), "ShowToolbar"); moo_toggle_action_set_active (MOO_TOGGLE_ACTION (show_toolbar), moo_prefs_get_bool (setting (window, PREFS_SHOW_TOOLBAR))); style = get_toolbar_style (window); gtk_toolbar_set_style (GTK_TOOLBAR (MOO_WINDOW(window)->toolbar), style); } return FALSE; } static void moo_window_shortcuts_prefs_dialog (MooWindow *window) { moo_shortcuts_prefs_dialog_run ( moo_ui_object_get_actions (MOO_UI_OBJECT (window)), GTK_WIDGET (window)); } static void moo_window_show_toolbar_toggled (MooWindow *window, gboolean show) { if (show != GTK_WIDGET_VISIBLE (window->toolbar)) { if (show) gtk_widget_show (window->toolbar); else gtk_widget_hide (window->toolbar); moo_prefs_set_bool (setting (window, PREFS_SHOW_TOOLBAR), show); } } static void moo_window_show_menubar_toggled (MooWindow *window, gboolean show) { if (show != GTK_WIDGET_VISIBLE (window->menubar)) { if (show) gtk_widget_show (window->menubar); else gtk_widget_hide (window->menubar); moo_prefs_set_bool (setting (window, PREFS_SHOW_MENUBAR), show); } } static void window_destroyed (GObject *menuitem, gpointer window); static void toolbar_style_menu_destroyed (GObject *window, gpointer menuitem) { g_object_weak_unref (window, (GWeakNotify)window_destroyed, menuitem); } static void window_destroyed (GObject *menuitem, gpointer window) { g_object_weak_unref (menuitem, (GWeakNotify)toolbar_style_menu_destroyed, window); gtk_widget_destroy (GTK_WIDGET (menuitem)); } static void toolbar_style_toggled (GtkCheckMenuItem *item, MooWindow *window) { GtkToolbarStyle style; if (!gtk_check_menu_item_get_active (item)) return; style = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "moo_window_toolbar_style")); gtk_toolbar_set_style (GTK_TOOLBAR (window->toolbar), style); moo_prefs_set_enum (setting (window, PREFS_TOOLBAR_STYLE), style); } static GtkMenuItem *moo_window_create_toolbar_style_menu (MooWindow *window) { GtkWidget *item; GSList *group = NULL; GtkWidget *items[3]; GtkMenuShell *menu; guint i; GtkToolbarStyle style; const char *labels[3] = { "_Icons Only", "_Labels Only", "Icons _and Labels" }; item = gtk_menu_item_new_with_mnemonic ("Toolbar _Style"); menu = GTK_MENU_SHELL (gtk_menu_new ()); for (i = 0; i < 3; ++i) { items[i] = gtk_radio_menu_item_new_with_mnemonic (group, labels[i]); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (items[i])); gtk_menu_shell_append (menu, items[i]); g_object_set_data (G_OBJECT (items[i]), "moo_window_toolbar_style", GINT_TO_POINTER (i)); } gtk_widget_show_all (GTK_WIDGET (menu)); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (menu)); style = get_toolbar_style (window); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (items[style]), TRUE); for (i = 0; i < 3; ++i) { g_signal_connect (items[i], "toggled", G_CALLBACK (toolbar_style_toggled), window); } g_object_weak_ref (G_OBJECT (window), (GWeakNotify)window_destroyed, item); g_object_weak_ref (G_OBJECT (item), (GWeakNotify)toolbar_style_menu_destroyed, window); return GTK_MENU_ITEM (item); } static GtkToolbarStyle get_toolbar_style_gtk (MooWindow *window) { GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (window)); GtkToolbarStyle style = GTK_TOOLBAR_ICONS; gpointer toolbar_class; g_return_val_if_fail (settings != NULL, style); toolbar_class = g_type_class_ref (GTK_TYPE_TOOLBAR); g_object_get (settings, "gtk-toolbar-style", &style, NULL); g_type_class_unref (toolbar_class); return style; } static void init_prefs (MooWindow *window) { moo_prefs_new_key_bool (setting (window, PREFS_REMEMBER_SIZE), TRUE); moo_prefs_new_key_bool (setting (window, PREFS_MAXIMIZED), FALSE); moo_prefs_new_key_int (setting (window, PREFS_WIDTH), -1); moo_prefs_new_key_int (setting (window, PREFS_HEIGHT), -1); moo_prefs_new_key_bool (setting (window, PREFS_SHOW_TOOLBAR), TRUE); moo_prefs_new_key_bool (setting (window, PREFS_SHOW_MENUBAR), TRUE); moo_prefs_new_key_enum (setting (window, PREFS_TOOLBAR_STYLE), GTK_TYPE_TOOLBAR_STYLE, get_toolbar_style_gtk (window)); } static GtkToolbarStyle get_toolbar_style (MooWindow *window) { return moo_prefs_get_enum (setting (window, PREFS_TOOLBAR_STYLE)); }