1 /* 2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org> 3 * Copyright (C) 2010 David King <davidk@openismus.com> 4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21 #include <string.h> 22 #include <glib/gi18n-lib.h> 23 #include "browser-window.h" 24 #include <libgda/binreloc/gda-binreloc.h> 25 #include "login-dialog.h" 26 #include "browser-core.h" 27 #include "support.h" 28 #include "browser-perspective.h" 29 #include "browser-connection.h" 30 #include "browser-connections-list.h" 31 #include "browser-spinner.h" 32 #include "browser-stock-icons.h" 33 #include "connection-binding-properties.h" 34 #include <gdk/gdkkeysyms.h> 35 36 /* 37 * structure representing a 'tab' in a window 38 * 39 * a 'page' is a set of widgets created by a single BrowserPerspectiveFactory object, for a connection 40 * Each is owned by a BrowserWindow 41 */ 42 typedef struct { 43 BrowserWindow *bwin; /* pointer to window the tab is in, no ref held here */ 44 BrowserPerspectiveFactory *factory; 45 gint page_number; /* in reference to bwin->perspectives_nb */ 46 BrowserPerspective *perspective_widget; 47 48 GtkActionGroup *customized_actions; 49 guint customized_merge_id; 50 gchar *customized_ui; 51 } PerspectiveData; 52 #define PERSPECTIVE_DATA(x) ((PerspectiveData*)(x)) 53 static PerspectiveData *perspective_data_new (BrowserWindow *bwin, BrowserPerspectiveFactory *factory); 54 static void perspective_data_free (PerspectiveData *pers); 55 56 /* 57 * Main static functions 58 */ 59 static void browser_window_class_init (BrowserWindowClass *klass); 60 static void browser_window_init (BrowserWindow *bwin); 61 static void browser_window_dispose (GObject *object); 62 63 static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event); 64 static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event); 65 static void connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, BrowserWindow *bwin); 66 67 static void connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin); 68 static void connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin); 69 70 static void transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin); 71 72 73 enum { 74 FULLSCREEN_CHANGED, 75 LAST_SIGNAL 76 }; 77 78 static gint browser_window_signals[LAST_SIGNAL] = { 0 }; 79 80 81 /* get a pointer to the parents to be able to call their destructor */ 82 static GObjectClass *parent_class = NULL; 83 84 struct _BrowserWindowPrivate { 85 BrowserConnection *bcnc; 86 GtkNotebook *perspectives_nb; /* notebook used to switch between tabs, for the selector part */ 87 GSList *perspectives; /* list of PerspectiveData pointers, owned here */ 88 PerspectiveData *current_perspective; 89 guint ui_manager_merge_id; /* for current perspective */ 90 91 GtkWidget *menubar; 92 GtkWidget *toolbar; 93 gboolean toolbar_shown; 94 gboolean cursor_in_toolbar; 95 GtkWidget *spinner; 96 guint spinner_timer; 97 GtkUIManager *ui_manager; 98 GtkActionGroup *agroup; 99 GtkActionGroup *perspectives_actions; 100 gboolean updating_transaction_status; 101 102 GtkToolbarStyle toolbar_style; 103 GtkActionGroup *cnc_agroup; /* one GtkAction for each BrowserConnection */ 104 gulong cnc_added_sigid; 105 gulong cnc_removed_sigid; 106 107 GtkWidget *notif_box; 108 GSList *notif_widgets; 109 110 GtkWidget *statusbar; 111 guint cnc_statusbar_context; 112 113 gboolean fullscreen; 114 gulong fullscreen_motion_sig_id; 115 guint fullscreen_timer_id; 116 }; 117 118 GType 119 browser_window_get_type (void) 120 { 121 static GType type = 0; 122 123 if (G_UNLIKELY (type == 0)) { 124 static GMutex registering; 125 static const GTypeInfo info = { 126 sizeof (BrowserWindowClass), 127 (GBaseInitFunc) NULL, 128 (GBaseFinalizeFunc) NULL, 129 (GClassInitFunc) browser_window_class_init, 130 NULL, 131 NULL, 132 sizeof (BrowserWindow), 133 0, 134 (GInstanceInitFunc) browser_window_init, 135 0 136 }; 137 138 139 g_mutex_lock (®istering); 140 if (type == 0) 141 type = g_type_register_static (GTK_TYPE_WINDOW, "BrowserWindow", &info, 0); 142 g_mutex_unlock (®istering); 143 } 144 return type; 145 } 146 147 static void 148 browser_window_class_init (BrowserWindowClass *klass) 149 { 150 GObjectClass *object_class = G_OBJECT_CLASS (klass); 151 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); 152 153 widget_class->window_state_event = window_state_event; 154 widget_class->key_press_event = key_press_event; 155 parent_class = g_type_class_peek_parent (klass); 156 157 browser_window_signals[FULLSCREEN_CHANGED] = 158 g_signal_new ("fullscreen_changed", 159 G_TYPE_FROM_CLASS (object_class), 160 G_SIGNAL_RUN_LAST, 161 G_STRUCT_OFFSET (BrowserWindowClass, fullscreen_changed), 162 NULL, NULL, 163 g_cclosure_marshal_VOID__BOOLEAN, 164 G_TYPE_NONE, 1, G_TYPE_BOOLEAN); 165 166 object_class->dispose = browser_window_dispose; 167 klass->fullscreen_changed = NULL; 168 } 169 170 static void 171 browser_window_init (BrowserWindow *bwin) 172 { 173 bwin->priv = g_new0 (BrowserWindowPrivate, 1); 174 bwin->priv->bcnc = NULL; 175 bwin->priv->perspectives_nb = NULL; 176 bwin->priv->perspectives = NULL; 177 bwin->priv->cnc_agroup = NULL; 178 bwin->priv->cnc_added_sigid = 0; 179 bwin->priv->cnc_removed_sigid = 0; 180 bwin->priv->updating_transaction_status = FALSE; 181 bwin->priv->fullscreen = FALSE; 182 bwin->priv->fullscreen_motion_sig_id = 0; 183 bwin->priv->fullscreen_timer_id = 0; 184 bwin->priv->spinner_timer = 0; 185 } 186 187 static void 188 browser_window_dispose (GObject *object) 189 { 190 BrowserWindow *bwin; 191 192 g_return_if_fail (object != NULL); 193 g_return_if_fail (BROWSER_IS_WINDOW (object)); 194 195 bwin = BROWSER_WINDOW (object); 196 if (bwin->priv) { 197 GSList *connections, *list; 198 199 if (bwin->priv->spinner_timer) { 200 g_source_remove (bwin->priv->spinner_timer); 201 bwin->priv->spinner_timer = 0; 202 } 203 connections = browser_core_get_connections (); 204 for (list = connections; list; list = list->next) 205 connection_removed_cb (browser_core_get(), BROWSER_CONNECTION (list->data), bwin); 206 g_slist_free (connections); 207 208 if (bwin->priv->fullscreen_timer_id) 209 g_source_remove (bwin->priv->fullscreen_timer_id); 210 211 if (bwin->priv->fullscreen_motion_sig_id) 212 g_signal_handler_disconnect (bwin, bwin->priv->fullscreen_motion_sig_id); 213 214 if (bwin->priv->cnc_added_sigid > 0) 215 g_signal_handler_disconnect (browser_core_get (), bwin->priv->cnc_added_sigid); 216 if (bwin->priv->cnc_removed_sigid > 0) 217 g_signal_handler_disconnect (browser_core_get (), bwin->priv->cnc_removed_sigid); 218 if (bwin->priv->ui_manager) 219 g_object_unref (bwin->priv->ui_manager); 220 if (bwin->priv->cnc_agroup) 221 g_object_unref (bwin->priv->cnc_agroup); 222 223 if (bwin->priv->bcnc) { 224 g_signal_handlers_disconnect_by_func (bwin->priv->bcnc, 225 G_CALLBACK (transaction_status_changed_cb), 226 bwin); 227 g_object_unref (bwin->priv->bcnc); 228 } 229 if (bwin->priv->perspectives) { 230 g_slist_foreach (bwin->priv->perspectives, (GFunc) perspective_data_free, NULL); 231 g_slist_free (bwin->priv->perspectives); 232 } 233 if (bwin->priv->perspectives_nb) 234 g_object_unref (bwin->priv->perspectives_nb); 235 236 if (bwin->priv->notif_widgets) 237 g_slist_free (bwin->priv->notif_widgets); 238 g_free (bwin->priv); 239 bwin->priv = NULL; 240 } 241 242 /* parent class */ 243 parent_class->dispose (object); 244 } 245 246 247 static gboolean 248 delete_event (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEvent *event, BrowserWindow *bwin) 249 { 250 browser_core_close_window (bwin); 251 return TRUE; 252 } 253 254 static void transaction_begin_cb (GtkAction *action, BrowserWindow *bwin); 255 static void transaction_commit_cb (GtkAction *action, BrowserWindow *bwin); 256 static void transaction_rollback_cb (GtkAction *action, BrowserWindow *bwin); 257 static void quit_cb (GtkAction *action, BrowserWindow *bwin); 258 static void about_cb (GtkAction *action, BrowserWindow *bwin); 259 #ifdef HAVE_GDU 260 static void manual_cb (GtkAction *action, BrowserWindow *bwin); 261 #endif 262 static void window_close_cb (GtkAction *action, BrowserWindow *bwin); 263 static void window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin); 264 static void window_new_cb (GtkAction *action, BrowserWindow *bwin); 265 static void window_new_with_cnc_cb (GtkAction *action, BrowserWindow *bwin); 266 static void connection_properties_cb (GtkAction *action, BrowserWindow *bwin); 267 static void connection_close_cb (GtkAction *action, BrowserWindow *bwin); 268 static void connection_open_cb (GtkAction *action, BrowserWindow *bwin); 269 static void connection_bind_cb (GtkAction *action, BrowserWindow *bwin); 270 static void connection_list_cb (GtkAction *action, BrowserWindow *bwin); 271 static void connection_meta_update_cb (GtkAction *action, BrowserWindow *bwin); 272 static void perspective_toggle_cb (GtkRadioAction *action, GtkRadioAction *current, BrowserWindow *bwin); 273 274 static const GtkToggleActionEntry ui_toggle_actions [] = 275 { 276 { "WindowFullScreen", GTK_STOCK_FULLSCREEN, N_("_Fullscreen"), "F11", N_("Use the whole screen"), G_CALLBACK (window_fullscreen_cb), FALSE} 277 }; 278 279 static const GtkActionEntry ui_actions[] = { 280 { "Connection", NULL, N_("_Connection"), NULL, N_("Connection"), NULL }, 281 { "ConnectionOpen", GTK_STOCK_CONNECT, N_("_Connect"), NULL, N_("Open a connection"), G_CALLBACK (connection_open_cb)}, 282 { "ConnectionBind", NULL, N_("_Bind Connection"), "<control>I", N_("Use connection to create\n" 283 "a new binding connection to access data\n" 284 "from multiple databases at once"), G_CALLBACK (connection_bind_cb)}, 285 { "ConnectionProps", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, N_("Connection properties"), G_CALLBACK (connection_properties_cb)}, 286 { "ConnectionList", NULL, N_("_Connections List"), NULL, N_("Connections list"), G_CALLBACK (connection_list_cb)}, 287 { "ConnectionMetaSync", GTK_STOCK_REFRESH, N_("_Fetch Meta Data"), NULL, N_("Fetch meta data"), G_CALLBACK (connection_meta_update_cb)}, 288 { "ConnectionClose", GTK_STOCK_CLOSE, N_("_Close Connection"), NULL, N_("Close this connection"), G_CALLBACK (connection_close_cb)}, 289 { "Quit", GTK_STOCK_QUIT, N_("_Quit"), NULL, N_("Quit"), G_CALLBACK (quit_cb)}, 290 { "Edit", NULL, N_("_Edit"), NULL, N_("Edit"), NULL }, 291 { "Display", NULL, N_("_Display"), NULL, N_("Display"), NULL }, 292 { "Perspective", NULL, N_("_Perspective"), NULL, N_("Perspective"), NULL }, 293 { "Window", NULL, N_("_Window"), NULL, N_("Window"), NULL }, 294 { "WindowNew", STOCK_NEW_WINDOW, N_("_New Window"), "<control>N", N_("Open a new window for current connection"), G_CALLBACK (window_new_cb)}, 295 { "WindowNewOthers", NULL, N_("New Window for _Connection"), NULL, N_("Open a new window for a connection"), NULL}, 296 { "WindowClose", GTK_STOCK_CLOSE, N_("_Close"), NULL, N_("Close this window"), G_CALLBACK (window_close_cb)}, 297 { "Help", NULL, N_("_Help"), NULL, N_("Help"), NULL }, 298 { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("About"), G_CALLBACK (about_cb) }, 299 #ifdef HAVE_GDU 300 { "HelpManual", GTK_STOCK_HELP, N_("_Manual"), "F1", N_("Manual"), G_CALLBACK (manual_cb) }, 301 #endif 302 { "TransactionBegin", BROWSER_STOCK_BEGIN, N_("Begin"), NULL, N_("Begin a new transaction"), 303 G_CALLBACK (transaction_begin_cb)}, 304 { "TransactionCommit", BROWSER_STOCK_COMMIT, N_("Commit"), NULL, N_("Commit current transaction"), 305 G_CALLBACK (transaction_commit_cb)}, 306 { "TransactionRollback", BROWSER_STOCK_ROLLBACK, N_("Rollback"), NULL, N_("Rollback current transaction"), 307 G_CALLBACK (transaction_rollback_cb)}, 308 }; 309 310 static const gchar *ui_actions_info = 311 "<ui>" 312 " <menubar name='MenuBar'>" 313 " <menu name='Connection' action='Connection'>" 314 " <menuitem name='ConnectionOpen' action= 'ConnectionOpen'/>" 315 " <menuitem name='ConnectionList' action= 'ConnectionList'/>" 316 " <menuitem name='ConnectionMetaSync' action= 'ConnectionMetaSync'/>" 317 " <separator/>" 318 " <menuitem name='ConnectionProps' action= 'ConnectionProps'/>" 319 " <menuitem name='ConnectionBind' action= 'ConnectionBind'/>" 320 " <menuitem name='ConnectionClose' action= 'ConnectionClose'/>" 321 " <separator/>" 322 " <menuitem name='TransactionBegin' action= 'TransactionBegin'/>" 323 " <menuitem name='TransactionCommit' action= 'TransactionCommit'/>" 324 " <menuitem name='TransactionRollback' action= 'TransactionRollback'/>" 325 " <separator/>" 326 " <menuitem name='Quit' action= 'Quit'/>" 327 " <separator/>" 328 " </menu>" 329 " <menu name='Edit' action='Edit'>" 330 " </menu>" 331 " <menu name='Display' action='Display'>" 332 " </menu>" 333 " <menu name='Perspective' action='Perspective'>" 334 " <placeholder name='PersList'/>" 335 " </menu>" 336 " <menu name='Window' action='Window'>" 337 " <menuitem name='WindowFullScreen' action= 'WindowFullScreen'/>" 338 " <separator/>" 339 " <menuitem name='WindowNew' action= 'WindowNew'/>" 340 " <menu name='WindowNewOthers' action='WindowNewOthers'>" 341 " <placeholder name='CncList'/>" 342 " </menu>" 343 " <separator/>" 344 " <menuitem name='WindowClose' action= 'WindowClose'/>" 345 " </menu>" 346 " <placeholder name='MenuExtension'/>" 347 " <menu name='Help' action='Help'>" 348 #ifdef HAVE_GDU 349 " <menuitem name='HelpManual' action= 'HelpManual'/>" 350 #endif 351 " <menuitem name='HelpAbout' action= 'HelpAbout'/>" 352 " </menu>" 353 " </menubar>" 354 " <toolbar name='ToolBar'>" 355 " <toolitem action='WindowClose'/>" 356 " <toolitem action='WindowFullScreen'/>" 357 " <toolitem action='TransactionBegin'/>" 358 " <toolitem action='TransactionCommit'/>" 359 " <toolitem action='TransactionRollback'/>" 360 " </toolbar>" 361 "</ui>"; 362 363 /** 364 * browser_window_new 365 * @bcnc: a #BrowserConnection 366 * @factory: a #BrowserPerspectiveFactory, may be %NULL 367 * 368 * Creates a new #BrowserWindow window for the @bcnc connection, and displays it. 369 * If @factory is not %NULL, then the new window will show the perspective corresponding 370 * to @factory. If it's %NULL, then the default #BrowserPerspectiveFactory will be used, 371 * see browser_core_get_default_factory(). 372 * 373 * Don't forget to call browser_core_take_window() to have the new window correctly 374 * managed by the browser. Similarly, to close the window, use browser_core_close_window() 375 * and not simply gtk_widget_destroy(). 376 * 377 * Returns: the new object 378 */ 379 BrowserWindow* 380 browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory) 381 { 382 BrowserWindow *bwin; 383 384 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL); 385 386 bwin = BROWSER_WINDOW (g_object_new (BROWSER_TYPE_WINDOW, NULL)); 387 bwin->priv->bcnc = g_object_ref (bcnc); 388 g_signal_connect (bcnc, "transaction-status-changed", 389 G_CALLBACK (transaction_status_changed_cb), bwin); 390 391 gchar *tmp; 392 tmp = browser_connection_get_long_name (bcnc); 393 gtk_window_set_title (GTK_WINDOW (bwin), tmp); 394 g_free (tmp); 395 396 gtk_window_set_default_size ((GtkWindow*) bwin, 900, 650); 397 g_signal_connect (G_OBJECT (bwin), "delete-event", 398 G_CALLBACK (delete_event), bwin); 399 /* icon */ 400 GdkPixbuf *icon; 401 gchar *path; 402 path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser.png", NULL); 403 icon = gdk_pixbuf_new_from_file (path, NULL); 404 g_free (path); 405 if (icon) { 406 gtk_window_set_icon (GTK_WINDOW (bwin), icon); 407 g_object_unref (icon); 408 } 409 410 /* main VBox */ 411 GtkWidget *vbox; 412 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 413 gtk_container_add (GTK_CONTAINER (bwin), vbox); 414 gtk_widget_show (vbox); 415 416 /* menu */ 417 GtkWidget *menubar; 418 GtkWidget *toolbar; 419 GtkUIManager *ui; 420 GtkActionGroup *group; 421 422 group = gtk_action_group_new ("Actions"); 423 gtk_action_group_set_translation_domain (group, GETTEXT_PACKAGE); 424 425 bwin->priv->agroup = group; 426 gtk_action_group_add_actions (group, ui_actions, G_N_ELEMENTS (ui_actions), bwin); 427 gtk_action_group_add_toggle_actions (group, ui_toggle_actions, G_N_ELEMENTS (ui_toggle_actions), bwin); 428 if (browser_connection_is_virtual (bwin->priv->bcnc)) { 429 GtkAction *action; 430 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin"); 431 gtk_action_set_visible (action, FALSE); 432 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit"); 433 gtk_action_set_visible (action, FALSE); 434 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback"); 435 gtk_action_set_visible (action, FALSE); 436 } 437 transaction_status_changed_cb (bwin->priv->bcnc, bwin); 438 439 ui = gtk_ui_manager_new (); 440 gtk_ui_manager_insert_action_group (ui, group, 0); 441 gtk_ui_manager_add_ui_from_string (ui, ui_actions_info, -1, NULL); 442 bwin->priv->ui_manager = ui; 443 444 GtkAccelGroup *accel_group; 445 accel_group = gtk_ui_manager_get_accel_group (ui); 446 gtk_window_add_accel_group (GTK_WINDOW (bwin), accel_group); 447 448 menubar = gtk_ui_manager_get_widget (ui, "/MenuBar"); 449 bwin->priv->menubar = menubar; 450 #ifdef HAVE_MAC_INTEGRATION 451 gtk_osxapplication_set_menu_bar (theApp, GTK_MENU_SHELL (menubar)); 452 #else 453 gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0); 454 gtk_widget_show (menubar); 455 #endif 456 457 toolbar = gtk_ui_manager_get_widget (ui, "/ToolBar"); 458 bwin->priv->toolbar = toolbar; 459 bwin->priv->toolbar_shown = TRUE; 460 gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0); 461 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE); 462 gtk_widget_show (toolbar); 463 bwin->priv->toolbar_style = gtk_toolbar_get_style (GTK_TOOLBAR (toolbar)); 464 465 bwin->priv->notif_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 466 gtk_box_pack_start (GTK_BOX (vbox), bwin->priv->notif_box, FALSE, FALSE, 0); 467 gtk_widget_show (bwin->priv->notif_box); 468 bwin->priv->notif_widgets = NULL; 469 470 GtkToolItem *ti; 471 GtkWidget *spinner, *svbox, *align; 472 473 ti = gtk_separator_tool_item_new (); 474 gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (ti), FALSE); 475 gtk_tool_item_set_expand (ti, TRUE); 476 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), ti, -1); 477 gtk_widget_show (GTK_WIDGET (ti)); 478 479 spinner = browser_spinner_new (); 480 browser_spinner_set_size ((BrowserSpinner*) spinner, GTK_ICON_SIZE_SMALL_TOOLBAR); 481 482 svbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 483 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); 484 gtk_container_add (GTK_CONTAINER (align), spinner); 485 gtk_box_pack_start (GTK_BOX (svbox), align, TRUE, TRUE, 0); 486 487 ti = gtk_tool_item_new (); 488 gtk_container_add (GTK_CONTAINER (ti), svbox); 489 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), ti, -1); 490 gtk_widget_show_all (GTK_WIDGET (ti)); 491 gtk_widget_hide (GTK_WIDGET (spinner)); 492 bwin->priv->spinner = spinner; 493 494 /* statusbar */ 495 bwin->priv->statusbar = gtk_statusbar_new (); 496 497 GSList *connections, *list; 498 bwin->priv->cnc_agroup = gtk_action_group_new ("CncActions"); 499 gtk_action_group_set_translation_domain (bwin->priv->cnc_agroup, GETTEXT_PACKAGE); 500 501 connections = browser_core_get_connections (); 502 for (list = connections; list; list = list->next) 503 connection_added_cb (browser_core_get(), BROWSER_CONNECTION (list->data), bwin); 504 g_slist_free (connections); 505 506 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, bwin->priv->cnc_agroup, 0); 507 bwin->priv->cnc_added_sigid = g_signal_connect (browser_core_get (), "connection-added", 508 G_CALLBACK (connection_added_cb), bwin); 509 bwin->priv->cnc_removed_sigid = g_signal_connect (browser_core_get (), "connection-removed", 510 G_CALLBACK (connection_removed_cb), bwin); 511 512 513 /* create a PerspectiveData */ 514 PerspectiveData *pers; 515 if (! factory && browser_connection_is_ldap (bcnc)) 516 factory = browser_core_get_factory (_("LDAP browser")); 517 pers = perspective_data_new (bwin, factory); 518 bwin->priv->perspectives = g_slist_prepend (bwin->priv->perspectives, pers); 519 GtkActionGroup *actions; 520 actions = browser_perspective_get_actions_group (BROWSER_PERSPECTIVE (pers->perspective_widget)); 521 if (actions) { 522 gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE); 523 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions, 0); 524 g_object_unref (actions); 525 } 526 const gchar *ui_info; 527 ui_info = browser_perspective_get_actions_ui (BROWSER_PERSPECTIVE (pers->perspective_widget)); 528 if (ui_info) 529 bwin->priv->ui_manager_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager, 530 ui_info, -1, NULL); 531 bwin->priv->current_perspective = pers; 532 browser_perspective_get_current_customization (BROWSER_PERSPECTIVE (pers->perspective_widget), 533 &actions, &ui_info); 534 browser_window_customize_perspective_ui (bwin, BROWSER_PERSPECTIVE (pers->perspective_widget), 535 actions, ui_info); 536 if (actions) 537 g_object_unref (actions); 538 539 /* insert perspective into window */ 540 bwin->priv->perspectives_nb = (GtkNotebook*) gtk_notebook_new (); 541 g_object_ref (bwin->priv->perspectives_nb); 542 gtk_notebook_set_show_tabs (bwin->priv->perspectives_nb, FALSE); 543 gtk_box_pack_start (GTK_BOX (vbox), (GtkWidget*) bwin->priv->perspectives_nb, 544 TRUE, TRUE, 0); 545 546 pers->page_number = gtk_notebook_append_page (bwin->priv->perspectives_nb, 547 GTK_WIDGET (pers->perspective_widget), NULL); 548 gtk_widget_show_all ((GtkWidget*) bwin->priv->perspectives_nb); 549 gtk_widget_grab_focus (GTK_WIDGET (pers->perspective_widget)); 550 551 /* build the perspectives menu */ 552 GtkActionGroup *agroup; 553 const GSList *plist; 554 GSList *radio_group = NULL; 555 guint mid; 556 557 mid = gtk_ui_manager_new_merge_id (bwin->priv->ui_manager); 558 agroup = gtk_action_group_new ("Perspectives"); 559 gtk_action_group_set_translation_domain (agroup, GETTEXT_PACKAGE); 560 561 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, agroup, 0); 562 bwin->priv->perspectives_actions = agroup; 563 g_object_unref (agroup); 564 565 GtkAction *active_action = NULL; 566 for (plist = browser_core_get_factories (); plist; plist = plist->next) { 567 GtkAction *action; 568 const gchar *name; 569 570 name = BROWSER_PERSPECTIVE_FACTORY (plist->data)->perspective_name; 571 if (!strcmp (name, _("LDAP browser")) && !browser_connection_is_ldap (bcnc)) 572 continue; 573 574 action = GTK_ACTION (gtk_radio_action_new (name, name, NULL, NULL, FALSE)); 575 576 if (!active_action && 577 ((factory && (BROWSER_PERSPECTIVE_FACTORY (plist->data) == factory)) || 578 (!factory && (BROWSER_PERSPECTIVE_FACTORY (plist->data) == browser_core_get_default_factory ())))) 579 active_action = action; 580 if (BROWSER_PERSPECTIVE_FACTORY (plist->data)->menu_shortcut) 581 gtk_action_group_add_action_with_accel (agroup, action, 582 BROWSER_PERSPECTIVE_FACTORY (plist->data)->menu_shortcut); 583 else 584 gtk_action_group_add_action (agroup, action); 585 586 gtk_radio_action_set_group (GTK_RADIO_ACTION (action), radio_group); 587 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action)); 588 589 g_object_set_data (G_OBJECT (action), "pers", plist->data); 590 g_signal_connect (action, "changed", 591 G_CALLBACK (perspective_toggle_cb), bwin); 592 593 g_object_unref (action); 594 595 gtk_ui_manager_add_ui (bwin->priv->ui_manager, mid, "/MenuBar/Perspective/PersList", 596 name, name, 597 GTK_UI_MANAGER_AUTO, FALSE); 598 } 599 600 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (active_action), TRUE); 601 602 gtk_box_pack_start (GTK_BOX (vbox), bwin->priv->statusbar, FALSE, FALSE, 0); 603 gtk_widget_show (bwin->priv->statusbar); 604 bwin->priv->cnc_statusbar_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar), 605 "cncbusy"); 606 607 gtk_widget_show (GTK_WIDGET (bwin)); 608 609 gtk_widget_set_can_focus ((GtkWidget* )pers->perspective_widget, TRUE); 610 gtk_widget_grab_focus ((GtkWidget* )pers->perspective_widget); 611 612 return bwin; 613 } 614 615 static void 616 perspective_toggle_cb (GtkRadioAction *action, GtkRadioAction *current, BrowserWindow *bwin) 617 { 618 BrowserPerspectiveFactory *pf; 619 GSList *list; 620 PerspectiveData *pers; 621 if (action != current) 622 return; 623 624 pf = BROWSER_PERSPECTIVE_FACTORY (g_object_get_data (G_OBJECT (action), "pers")); 625 g_assert (pf); 626 627 /* current perspective's cleanups */ 628 if (bwin->priv->current_perspective) { 629 pers = bwin->priv->current_perspective; 630 if (pers->customized_merge_id) { 631 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, pers->customized_merge_id); 632 pers->customized_merge_id = 0; 633 } 634 bwin->priv->current_perspective = NULL; 635 } 636 637 /* check if perspective already exists */ 638 for (list = bwin->priv->perspectives, pers = NULL; list; list = list->next) { 639 if (PERSPECTIVE_DATA (list->data)->factory == pf) { 640 pers = PERSPECTIVE_DATA (list->data); 641 break; 642 } 643 } 644 645 if (!pers) { 646 pers = perspective_data_new (bwin, pf); 647 bwin->priv->perspectives = g_slist_prepend (bwin->priv->perspectives, pers); 648 pers->page_number = gtk_notebook_append_page (bwin->priv->perspectives_nb, 649 GTK_WIDGET (pers->perspective_widget), NULL); 650 gtk_widget_show (GTK_WIDGET (pers->perspective_widget)); 651 652 GtkActionGroup *actions; 653 actions = browser_perspective_get_actions_group (BROWSER_PERSPECTIVE (pers->perspective_widget)); 654 if (actions) { 655 gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE); 656 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions, 0); 657 g_object_unref (actions); 658 } 659 } 660 661 gtk_notebook_set_current_page (bwin->priv->perspectives_nb, pers->page_number); 662 663 /* menus and toolbar handling */ 664 if (bwin->priv->ui_manager_merge_id > 0) { 665 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, bwin->priv->ui_manager_merge_id); 666 bwin->priv->ui_manager_merge_id = 0; 667 } 668 669 const gchar *ui_info; 670 ui_info = browser_perspective_get_actions_ui (BROWSER_PERSPECTIVE (pers->perspective_widget)); 671 if (ui_info) 672 bwin->priv->ui_manager_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager, 673 ui_info, -1, NULL); 674 675 /* current perspective's customizations */ 676 bwin->priv->current_perspective = pers; 677 678 GtkActionGroup *actions; 679 browser_perspective_get_current_customization (BROWSER_PERSPECTIVE (pers->perspective_widget), 680 &actions, &ui_info); 681 browser_window_customize_perspective_ui (bwin, BROWSER_PERSPECTIVE (pers->perspective_widget), 682 actions, ui_info); 683 if (actions) 684 g_object_unref (actions); 685 } 686 687 static gboolean 688 spinner_stop_timer (BrowserWindow *bwin) 689 { 690 browser_spinner_stop (BROWSER_SPINNER (bwin->priv->spinner)); 691 bwin->priv->spinner_timer = 0; 692 return FALSE; /* remove timer */ 693 } 694 695 static void 696 connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, BrowserWindow *bwin) 697 { 698 GtkAction *action; 699 if (bcnc == bwin->priv->bcnc) { 700 /* @bcbc is @bwin's own connection */ 701 if (bwin->priv->spinner_timer) { 702 g_source_remove (bwin->priv->spinner_timer); 703 bwin->priv->spinner_timer = 0; 704 } 705 if (is_busy) { 706 browser_spinner_start (BROWSER_SPINNER (bwin->priv->spinner)); 707 gtk_widget_set_tooltip_text (bwin->priv->spinner, reason); 708 gtk_statusbar_push (GTK_STATUSBAR (bwin->priv->statusbar), 709 bwin->priv->cnc_statusbar_context, 710 reason); 711 } 712 else { 713 bwin->priv->spinner_timer = g_timeout_add (300, 714 (GSourceFunc) spinner_stop_timer, bwin); 715 gtk_widget_set_tooltip_text (bwin->priv->spinner, NULL); 716 gtk_statusbar_pop (GTK_STATUSBAR (bwin->priv->statusbar), 717 bwin->priv->cnc_statusbar_context); 718 } 719 720 gboolean bsens = FALSE, csens = FALSE; 721 if (!is_busy) { 722 if (browser_connection_get_transaction_status (bcnc)) 723 csens = TRUE; 724 else 725 bsens = TRUE; 726 } 727 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin"); 728 gtk_action_set_sensitive (action, bsens); 729 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit"); 730 gtk_action_set_sensitive (action, csens); 731 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback"); 732 gtk_action_set_sensitive (action, csens); 733 734 action = gtk_action_group_get_action (bwin->priv->agroup, "WindowNew"); 735 gtk_action_set_sensitive (action, !is_busy); 736 action = gtk_action_group_get_action (bwin->priv->agroup, "ConnectionMetaSync"); 737 gtk_action_set_sensitive (action, !is_busy); 738 } 739 740 gchar *cncname; 741 cncname = browser_connection_get_long_name (bcnc); 742 action = gtk_action_group_get_action (bwin->priv->cnc_agroup, cncname); 743 g_free (cncname); 744 if (action) 745 gtk_action_set_sensitive (action, !is_busy); 746 } 747 748 /* update @bwin->priv->cnc_agroup and @bwin->priv->ui_manager */ 749 static void 750 connection_added_cb (G_GNUC_UNUSED BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin) 751 { 752 GtkAction *action; 753 gchar *cncname; 754 guint mid; 755 756 mid = gtk_ui_manager_new_merge_id (bwin->priv->ui_manager); 757 cncname = browser_connection_get_long_name (bcnc); 758 action = gtk_action_new (cncname, cncname, NULL, NULL); 759 gtk_action_group_add_action (bwin->priv->cnc_agroup, action); 760 guint *amid = g_new (guint, 1); 761 *amid = mid; 762 g_object_set_data_full (G_OBJECT (action), "mid", amid, g_free); 763 764 gtk_ui_manager_add_ui (bwin->priv->ui_manager, mid, "/MenuBar/Window/WindowNewOthers/CncList", 765 cncname, cncname, 766 GTK_UI_MANAGER_AUTO, FALSE); 767 g_free (cncname); 768 g_signal_connect (action, "activate", 769 G_CALLBACK (window_new_with_cnc_cb), bwin); 770 g_object_set_data (G_OBJECT (action), "bcnc", bcnc); 771 gtk_action_set_sensitive (action, ! browser_connection_is_busy (bcnc, NULL)); 772 g_object_unref (action); 773 774 gchar *reason = NULL; 775 if (browser_connection_is_busy (bcnc, &reason)) { 776 connection_busy_cb (bcnc, TRUE, reason, bwin); 777 g_free (reason); 778 } 779 g_signal_connect (bcnc, "busy", 780 G_CALLBACK (connection_busy_cb), bwin); 781 } 782 783 /* update @bwin->priv->cnc_agroup and @bwin->priv->ui_manager */ 784 static void 785 connection_removed_cb (G_GNUC_UNUSED BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin) 786 { 787 GtkAction *action; 788 gchar *path; 789 gchar *cncname; 790 guint *mid; 791 792 cncname = browser_connection_get_long_name (bcnc); 793 path = g_strdup_printf ("/MenuBar/Window/WindowNewOthers/CncList/%s", cncname); 794 g_free (cncname); 795 action = gtk_ui_manager_get_action (bwin->priv->ui_manager, path); 796 g_free (path); 797 g_assert (action); 798 799 mid = g_object_get_data (G_OBJECT (action), "mid"); 800 g_assert (mid); 801 802 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, *mid); 803 gtk_action_group_remove_action (bwin->priv->cnc_agroup, action); 804 805 g_signal_handlers_disconnect_by_func (bcnc, 806 G_CALLBACK (connection_busy_cb), bwin); 807 } 808 809 static void 810 connection_close_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 811 { 812 /* confirmation dialog */ 813 GtkWidget *dialog; 814 char *str; 815 BrowserConnection *bcnc; 816 bcnc = browser_window_get_connection (bwin); 817 818 str = g_strdup_printf (_("Do you want to close the '%s' connection?"), 819 browser_connection_get_name (bcnc)); 820 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL, 821 GTK_MESSAGE_QUESTION, 822 GTK_BUTTONS_YES_NO, 823 "<b>%s</b>", str); 824 g_free (str); 825 826 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) { 827 /* actual connection closing */ 828 browser_core_close_connection (bcnc); 829 830 /* list all the windows using bwin's connection */ 831 GSList *list, *windows, *bwin_list = NULL; 832 833 windows = browser_core_get_windows (); 834 for (list = windows; list; list = list->next) { 835 if (browser_window_get_connection (BROWSER_WINDOW (list->data)) == bcnc) 836 bwin_list = g_slist_prepend (bwin_list, list->data); 837 } 838 g_slist_free (windows); 839 840 for (list = bwin_list; list; list = list->next) 841 delete_event (NULL, NULL, BROWSER_WINDOW (list->data)); 842 g_slist_free (bwin_list); 843 } 844 gtk_widget_destroy (dialog); 845 } 846 847 static void 848 quit_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 849 { 850 /* confirmation dialog */ 851 GtkWidget *dialog; 852 GSList *connections; 853 854 connections = browser_core_get_connections (); 855 if (connections && connections->next) 856 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL, 857 GTK_MESSAGE_QUESTION, 858 GTK_BUTTONS_YES_NO, 859 "<b>%s</b>\n<small>%s</small>", 860 _("Do you want to quit the application?"), 861 _("all the connections will be closed.")); 862 else 863 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL, 864 GTK_MESSAGE_QUESTION, 865 GTK_BUTTONS_YES_NO, 866 "<b>%s</b>\n<small>%s</small>", 867 _("Do you want to quit the application?"), 868 _("the connection will be closed.")); 869 870 871 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) { 872 /* actual connection closing */ 873 GSList *list; 874 for (list = connections; list; list = list->next) 875 browser_core_close_connection (BROWSER_CONNECTION (list->data)); 876 877 /* list all the windows using bwin's connection */ 878 GSList *windows; 879 windows = browser_core_get_windows (); 880 for (list = windows; list; list = list->next) 881 delete_event (NULL, NULL, BROWSER_WINDOW (list->data)); 882 g_slist_free (windows); 883 } 884 g_slist_free (connections); 885 gtk_widget_destroy (dialog); 886 } 887 888 static void 889 transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin) 890 { 891 if (!bwin->priv->agroup) 892 return; 893 894 GtkAction *action; 895 gboolean trans_started; 896 897 trans_started = browser_connection_get_transaction_status (bcnc) ? TRUE : FALSE; 898 bwin->priv->updating_transaction_status = TRUE; 899 900 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin"); 901 gtk_action_set_sensitive (action, !trans_started); 902 903 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit"); 904 gtk_action_set_sensitive (action, trans_started); 905 906 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback"); 907 gtk_action_set_sensitive (action, trans_started); 908 909 bwin->priv->updating_transaction_status = FALSE; 910 } 911 912 static void 913 transaction_begin_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 914 { 915 if (!bwin->priv->updating_transaction_status) { 916 GError *error = NULL; 917 if (! browser_connection_begin (bwin->priv->bcnc, &error)) { 918 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)), 919 _("Error starting transaction: %s"), 920 error && error->message ? error->message : _("No detail")); 921 g_clear_error (&error); 922 } 923 } 924 } 925 926 static void 927 transaction_commit_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 928 { 929 if (!bwin->priv->updating_transaction_status) { 930 GError *error = NULL; 931 if (! browser_connection_commit (bwin->priv->bcnc, &error)) { 932 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)), 933 _("Error committing transaction: %s"), 934 error && error->message ? error->message : _("No detail")); 935 g_clear_error (&error); 936 } 937 } 938 } 939 940 static void 941 transaction_rollback_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 942 { 943 if (!bwin->priv->updating_transaction_status) { 944 GError *error = NULL; 945 if (! browser_connection_rollback (bwin->priv->bcnc, &error)) { 946 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)), 947 _("Error rolling back transaction: %s"), 948 error && error->message ? error->message : _("No detail")); 949 g_clear_error (&error); 950 } 951 } 952 } 953 954 955 static void 956 window_close_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 957 { 958 delete_event (NULL, NULL, bwin); 959 } 960 961 static gboolean 962 toolbar_hide_timeout_cb (BrowserWindow *bwin) 963 { 964 if (!bwin->priv->cursor_in_toolbar) { 965 gtk_widget_hide (bwin->priv->toolbar); 966 gtk_widget_hide (bwin->priv->menubar); 967 bwin->priv->toolbar_shown = FALSE; 968 969 /* remove timer */ 970 bwin->priv->fullscreen_timer_id = 0; 971 return FALSE; 972 } 973 else 974 /* keep timer */ 975 return TRUE; 976 } 977 978 #define BWIN_WINDOW_FULLSCREEN_POPUP_THRESHOLD 15 979 #define BWIN_WINDOW_FULLSCREEN_POPUP_TIMER 5 980 981 static gboolean 982 fullscreen_motion_notify_cb (GtkWidget *widget, GdkEventMotion *event, G_GNUC_UNUSED gpointer user_data) 983 { 984 BrowserWindow *bwin = BROWSER_WINDOW (widget); 985 if (gtk_widget_get_window (widget) != event->window) 986 return FALSE; 987 988 if (event->y < BWIN_WINDOW_FULLSCREEN_POPUP_THRESHOLD) { 989 gtk_widget_show (bwin->priv->toolbar); 990 gtk_widget_show (bwin->priv->menubar); 991 bwin->priv->toolbar_shown = TRUE; 992 } 993 994 if (bwin->priv->toolbar_shown) { 995 /* reset toolbar hiding timer */ 996 if (bwin->priv->fullscreen_timer_id) 997 g_source_remove (bwin->priv->fullscreen_timer_id); 998 bwin->priv->fullscreen_timer_id = g_timeout_add_seconds (BWIN_WINDOW_FULLSCREEN_POPUP_TIMER, 999 (GSourceFunc) toolbar_hide_timeout_cb, 1000 bwin); 1001 } 1002 return FALSE; 1003 } 1004 1005 gboolean 1006 toolbar_enter_notify_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventCrossing *event, 1007 BrowserWindow *bwin) 1008 { 1009 bwin->priv->cursor_in_toolbar = TRUE; 1010 return FALSE; 1011 } 1012 1013 gboolean 1014 toolbar_leave_notify_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventCrossing *event, BrowserWindow *bwin) 1015 { 1016 bwin->priv->cursor_in_toolbar = FALSE; 1017 return FALSE; 1018 } 1019 1020 static void 1021 window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin) 1022 { 1023 if (gtk_toggle_action_get_active (action)) { 1024 gtk_window_fullscreen (GTK_WINDOW (bwin)); 1025 browser_window_show_notice_printf (bwin, GTK_MESSAGE_INFO, 1026 "fullscreen-esc", 1027 "%s", _("Hit the Escape key to leave the fullscreen mode")); 1028 gtk_widget_hide (bwin->priv->toolbar); 1029 gtk_widget_hide (bwin->priv->menubar); 1030 bwin->priv->toolbar_shown = FALSE; 1031 bwin->priv->fullscreen_motion_sig_id = g_signal_connect (bwin, "motion-notify-event", 1032 G_CALLBACK (fullscreen_motion_notify_cb), 1033 NULL); 1034 g_signal_connect (bwin->priv->toolbar, "enter-notify-event", 1035 G_CALLBACK (toolbar_enter_notify_cb), bwin); 1036 g_signal_connect (bwin->priv->toolbar, "leave-notify-event", 1037 G_CALLBACK (toolbar_leave_notify_cb), bwin); 1038 g_signal_connect (bwin->priv->menubar, "enter-notify-event", 1039 G_CALLBACK (toolbar_enter_notify_cb), bwin); 1040 g_signal_connect (bwin->priv->menubar, "leave-notify-event", 1041 G_CALLBACK (toolbar_leave_notify_cb), bwin); 1042 } 1043 else { 1044 gtk_window_unfullscreen (GTK_WINDOW (bwin)); 1045 g_signal_handler_disconnect (bwin, bwin->priv->fullscreen_motion_sig_id); 1046 bwin->priv->fullscreen_motion_sig_id = 0; 1047 g_signal_handlers_disconnect_by_func (bwin->priv->toolbar, 1048 G_CALLBACK (toolbar_enter_notify_cb), bwin); 1049 g_signal_handlers_disconnect_by_func (bwin->priv->toolbar, 1050 G_CALLBACK (toolbar_leave_notify_cb), bwin); 1051 g_signal_handlers_disconnect_by_func (bwin->priv->menubar, 1052 G_CALLBACK (toolbar_enter_notify_cb), bwin); 1053 g_signal_handlers_disconnect_by_func (bwin->priv->menubar, 1054 G_CALLBACK (toolbar_leave_notify_cb), bwin); 1055 1056 gtk_widget_show (bwin->priv->toolbar); 1057 gtk_widget_show (bwin->priv->menubar); 1058 bwin->priv->toolbar_shown = TRUE; 1059 1060 if (bwin->priv->fullscreen_timer_id) { 1061 g_source_remove (bwin->priv->fullscreen_timer_id); 1062 bwin->priv->fullscreen_timer_id = 0; 1063 } 1064 } 1065 } 1066 1067 static gboolean 1068 key_press_event (GtkWidget *widget, GdkEventKey *event) 1069 { 1070 if ((event->keyval == GDK_KEY_Escape) && 1071 browser_window_is_fullscreen (BROWSER_WINDOW (widget))) { 1072 browser_window_set_fullscreen (BROWSER_WINDOW (widget), FALSE); 1073 return TRUE; 1074 } 1075 1076 /* parent class */ 1077 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); 1078 } 1079 1080 static gboolean 1081 window_state_event (GtkWidget *widget, GdkEventWindowState *event) 1082 { 1083 BrowserWindow *bwin = BROWSER_WINDOW (widget); 1084 gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *); 1085 window_state_event = GTK_WIDGET_CLASS (parent_class)->window_state_event; 1086 1087 /* calling parent's method */ 1088 if (window_state_event) 1089 window_state_event (widget, event); 1090 1091 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) { 1092 gboolean fullscreen; 1093 GtkWidget *wid; 1094 1095 wid = gtk_ui_manager_get_widget (bwin->priv->ui_manager, "/ToolBar"); 1096 1097 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; 1098 bwin->priv->fullscreen = fullscreen; 1099 if (fullscreen) { 1100 gtk_toolbar_set_style (GTK_TOOLBAR (wid), GTK_TOOLBAR_ICONS); 1101 browser_spinner_set_size (BROWSER_SPINNER (bwin->priv->spinner), 1102 GTK_ICON_SIZE_LARGE_TOOLBAR); 1103 } 1104 else { 1105 gtk_toolbar_set_style (GTK_TOOLBAR (wid), bwin->priv->toolbar_style); 1106 browser_spinner_set_size (BROWSER_SPINNER (bwin->priv->spinner), 1107 GTK_ICON_SIZE_SMALL_TOOLBAR); 1108 } 1109 1110 wid = gtk_ui_manager_get_widget (bwin->priv->ui_manager, "/MenuBar"); 1111 if (fullscreen) 1112 gtk_widget_hide (wid); 1113 else 1114 gtk_widget_show (wid); 1115 1116 g_signal_emit (G_OBJECT (bwin), browser_window_signals[FULLSCREEN_CHANGED], 0, fullscreen); 1117 } 1118 return FALSE; 1119 } 1120 1121 static void 1122 window_new_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1123 { 1124 BrowserWindow *nbwin; 1125 BrowserConnection *bcnc; 1126 bcnc = browser_window_get_connection (bwin); 1127 nbwin = browser_window_new (bcnc, NULL); 1128 1129 browser_core_take_window (nbwin); 1130 } 1131 1132 static void 1133 window_new_with_cnc_cb (GtkAction *action, G_GNUC_UNUSED BrowserWindow *bwin) 1134 { 1135 BrowserWindow *nbwin; 1136 BrowserConnection *bcnc; 1137 bcnc = g_object_get_data (G_OBJECT (action), "bcnc"); 1138 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc)); 1139 1140 nbwin = browser_window_new (bcnc, NULL); 1141 1142 browser_core_take_window (nbwin); 1143 } 1144 1145 static void 1146 connection_open_cb (G_GNUC_UNUSED GtkAction *action, G_GNUC_UNUSED BrowserWindow *bwin) 1147 { 1148 browser_connection_open (NULL); 1149 } 1150 1151 static void 1152 connection_properties_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1153 { 1154 if (BROWSER_IS_VIRTUAL_CONNECTION (bwin->priv->bcnc)) { 1155 GtkWidget *win; 1156 BrowserVirtualConnectionSpecs *specs; 1157 gint res; 1158 1159 g_object_get (G_OBJECT (bwin->priv->bcnc), "specs", &specs, NULL); 1160 win = connection_binding_properties_new_edit (specs); /* @specs is not modified */ 1161 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (bwin)); 1162 gtk_widget_show (win); 1163 1164 res = gtk_dialog_run (GTK_DIALOG (win)); 1165 gtk_widget_hide (win); 1166 if (res == GTK_RESPONSE_OK) { 1167 GError *error = NULL; 1168 if (!browser_virtual_connection_modify_specs (BROWSER_VIRTUAL_CONNECTION (bwin->priv->bcnc), 1169 connection_binding_properties_get_specs (CONNECTION_BINDING_PROPERTIES (win)), 1170 &error)) { 1171 browser_show_error ((GtkWindow*) bwin, 1172 _("Error updating bound connection: %s"), 1173 error && error->message ? error->message : _("No detail")); 1174 g_clear_error (&error); 1175 } 1176 1177 /* update meta store */ 1178 browser_connection_update_meta_data (bwin->priv->bcnc); 1179 } 1180 gtk_widget_destroy (win); 1181 } 1182 else { 1183 browser_connections_list_show (bwin->priv->bcnc); 1184 } 1185 } 1186 1187 static void 1188 connection_bind_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1189 { 1190 GtkWidget *win; 1191 gint res; 1192 1193 win = connection_binding_properties_new_create (bwin->priv->bcnc); 1194 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (bwin)); 1195 gtk_widget_show (win); 1196 1197 res = gtk_dialog_run (GTK_DIALOG (win)); 1198 gtk_widget_hide (win); 1199 if (res == GTK_RESPONSE_OK) { 1200 BrowserConnection *bcnc; 1201 GError *error = NULL; 1202 bcnc = browser_virtual_connection_new (connection_binding_properties_get_specs 1203 (CONNECTION_BINDING_PROPERTIES (win)), &error); 1204 if (bcnc) { 1205 BrowserWindow *bwin; 1206 bwin = browser_window_new (bcnc, NULL); 1207 1208 browser_core_take_window (bwin); 1209 browser_core_take_connection (bcnc); 1210 } 1211 else { 1212 browser_show_error ((GtkWindow*) bwin, 1213 _("Could not open binding connection: %s"), 1214 error && error->message ? error->message : _("No detail")); 1215 g_clear_error (&error); 1216 } 1217 } 1218 gtk_widget_destroy (win); 1219 } 1220 1221 static void 1222 connection_list_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1223 { 1224 browser_connections_list_show (bwin->priv->bcnc); 1225 } 1226 1227 static void 1228 connection_meta_update_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1229 { 1230 browser_connection_update_meta_data (bwin->priv->bcnc); 1231 } 1232 1233 static void 1234 about_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1235 { 1236 GdkPixbuf *icon; 1237 GtkWidget *dialog; 1238 const gchar *authors[] = { 1239 "Vivien Malerba <malerba@gnome-db.org> (current maintainer)", 1240 NULL 1241 }; 1242 const gchar *documenters[] = { 1243 NULL 1244 }; 1245 const gchar *translator_credits = ""; 1246 1247 gchar *path; 1248 path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser.png", NULL); 1249 icon = gdk_pixbuf_new_from_file (path, NULL); 1250 g_free (path); 1251 1252 dialog = gtk_about_dialog_new (); 1253 gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (dialog), _("Database browser")); 1254 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dialog), PACKAGE_VERSION); 1255 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (dialog), "(C) 2009 - 2011 GNOME Foundation"); 1256 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (dialog), _("Database access services for the GNOME Desktop")); 1257 gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (dialog), "GNU General Public License"); 1258 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), "http://www.gnome-db.org"); 1259 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (dialog), authors); 1260 gtk_about_dialog_set_documenters (GTK_ABOUT_DIALOG (dialog), documenters); 1261 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (dialog), translator_credits); 1262 gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (dialog), icon); 1263 g_signal_connect (G_OBJECT (dialog), "response", 1264 G_CALLBACK (gtk_widget_destroy), 1265 dialog); 1266 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (bwin)); 1267 gtk_widget_show (dialog); 1268 } 1269 1270 #ifdef HAVE_GDU 1271 void 1272 manual_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin) 1273 { 1274 browser_show_help (GTK_WINDOW (bwin), NULL); 1275 } 1276 #endif 1277 1278 1279 /** 1280 * browser_window_get_connection 1281 * @bwin: a #BrowserWindow 1282 * 1283 * Returns: the #BrowserConnection used in @bwin 1284 */ 1285 BrowserConnection * 1286 browser_window_get_connection (BrowserWindow *bwin) 1287 { 1288 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), NULL); 1289 return bwin->priv->bcnc; 1290 } 1291 1292 1293 /* 1294 * perspective_data_new 1295 * @bwin: a #BrowserWindow in which the perspective will be 1296 * @factory: (allow-none): a #BrowserPerspectiveFactory, or %NULL 1297 * 1298 * Creates a new #PerspectiveData structure, it increases @bcnc's reference count. 1299 * 1300 * Returns: a new #PerspectiveData 1301 */ 1302 static PerspectiveData * 1303 perspective_data_new (BrowserWindow *bwin, BrowserPerspectiveFactory *factory) 1304 { 1305 PerspectiveData *pers; 1306 1307 pers = g_new0 (PerspectiveData, 1); 1308 pers->bwin = NULL; 1309 pers->factory = factory; 1310 if (!pers->factory) 1311 pers->factory = browser_core_get_default_factory (); 1312 pers->page_number = -1; 1313 g_assert (pers->factory); 1314 pers->perspective_widget = g_object_ref (pers->factory->perspective_create (bwin)); 1315 1316 return pers; 1317 } 1318 1319 /* 1320 * perspective_data_free 1321 */ 1322 static void 1323 perspective_data_free (PerspectiveData *pers) 1324 { 1325 if (pers->perspective_widget) 1326 g_object_unref (pers->perspective_widget); 1327 if (pers->customized_actions) 1328 g_object_unref (pers->customized_actions); 1329 g_free (pers->customized_ui); 1330 g_free (pers); 1331 } 1332 1333 typedef struct { 1334 BrowserWindow *bwin; 1335 guint cid; /* statusbar context id */ 1336 guint msgid; /* statusbar message id */ 1337 } StatusData; 1338 1339 static gboolean 1340 status_auto_pop_timeout (StatusData *sd) 1341 { 1342 if (sd->bwin) { 1343 g_object_remove_weak_pointer (G_OBJECT (sd->bwin), (gpointer*) &(sd->bwin)); 1344 gtk_statusbar_remove (GTK_STATUSBAR (sd->bwin->priv->statusbar), sd->cid, sd->msgid); 1345 } 1346 g_free (sd); 1347 1348 return FALSE; /* remove source */ 1349 } 1350 1351 /** 1352 * browser_window_push_status 1353 * @bwin: a #BrowserWindow 1354 * @context: textual description of what context the new message is being used in 1355 * @text: textual message 1356 * @auto_clear: %TRUE if the message has to disappear after a while 1357 * 1358 * Pushes a new message onto @bwin's statusbar's stack. 1359 * 1360 * Returns: the message ID, see gtk_statusbar_push(), or %0 if @auto_clear is %TRUE 1361 */ 1362 guint 1363 browser_window_push_status (BrowserWindow *bwin, const gchar *context, const gchar *text, gboolean auto_clear) 1364 { 1365 guint cid; 1366 guint retval; 1367 1368 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), 0); 1369 g_return_val_if_fail (context, 0); 1370 g_return_val_if_fail (text, 0); 1371 1372 cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar), context); 1373 retval = gtk_statusbar_push (GTK_STATUSBAR (bwin->priv->statusbar), cid, text); 1374 if (auto_clear) { 1375 StatusData *sd; 1376 sd = g_new0 (StatusData, 1); 1377 sd->bwin = bwin; 1378 g_object_add_weak_pointer (G_OBJECT (sd->bwin), (gpointer*) &(sd->bwin)); 1379 sd->cid = cid; 1380 sd->msgid = retval; 1381 g_timeout_add_seconds (5, (GSourceFunc) status_auto_pop_timeout, sd); 1382 return 0; 1383 } 1384 else 1385 return retval; 1386 } 1387 1388 /** 1389 * browser_window_pop_status 1390 * @bwin: a #BrowserWindow 1391 * @context: textual description of what context the message is being used in 1392 * 1393 * Removes the first message in the @bwin's statusbar's stack with the given context. 1394 */ 1395 void 1396 browser_window_pop_status (BrowserWindow *bwin, const gchar *context) 1397 { 1398 guint cid; 1399 1400 g_return_if_fail (BROWSER_IS_WINDOW (bwin)); 1401 g_return_if_fail (context); 1402 1403 cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar), context); 1404 gtk_statusbar_pop (GTK_STATUSBAR (bwin->priv->statusbar), cid); 1405 } 1406 1407 /** 1408 * browser_window_show_notice_printf 1409 * @bwin: a #BrowserWindow 1410 * @context: textual description of what context the message is being used in 1411 * @format: the text to display 1412 * 1413 * Make @bwin display a notice 1414 */ 1415 void 1416 browser_window_show_notice_printf (BrowserWindow *bwin, GtkMessageType type, const gchar *context, 1417 const gchar *format, ...) 1418 { 1419 va_list args; 1420 gchar sz[2048]; 1421 1422 g_return_if_fail (BROWSER_IS_WINDOW (bwin)); 1423 1424 /* build the message string */ 1425 va_start (args, format); 1426 vsnprintf (sz, sizeof (sz), format, args); 1427 va_end (args); 1428 browser_window_show_notice (bwin, type, context, sz); 1429 } 1430 1431 1432 static void 1433 info_bar_response_cb (GtkInfoBar *ibar, G_GNUC_UNUSED gint response, BrowserWindow *bwin) 1434 { 1435 bwin->priv->notif_widgets = g_slist_remove (bwin->priv->notif_widgets, ibar); 1436 gtk_widget_destroy ((GtkWidget*) ibar); 1437 } 1438 1439 /* hash table to remain which context notices have to be hidden: key=context, value=GINT_TO_POINTER (1) */ 1440 static GHashTable *hidden_contexts = NULL; 1441 static void 1442 hidden_contexts_foreach_save (const gchar *context, G_GNUC_UNUSED gint value, xmlNodePtr root) 1443 { 1444 xmlNewChild (root, NULL, BAD_CAST "hide-notice", BAD_CAST context); 1445 } 1446 1447 static void 1448 hide_notice_toggled_cb (GtkToggleButton *toggle, gchar *context) 1449 { 1450 g_assert (hidden_contexts); 1451 if (gtk_toggle_button_get_active (toggle)) 1452 g_hash_table_insert (hidden_contexts, g_strdup (context), GINT_TO_POINTER (TRUE)); 1453 else 1454 g_hash_table_remove (hidden_contexts, context); 1455 1456 /* save config */ 1457 xmlDocPtr doc; 1458 xmlNodePtr root; 1459 xmlChar *xml_contents; 1460 gint size; 1461 doc = xmlNewDoc (BAD_CAST "1.0"); 1462 root = xmlNewNode (NULL, BAD_CAST "gda-browser-preferences"); 1463 xmlDocSetRootElement (doc, root); 1464 g_hash_table_foreach (hidden_contexts, (GHFunc) hidden_contexts_foreach_save, root); 1465 xmlDocDumpFormatMemory (doc, &xml_contents, &size, 1); 1466 xmlFreeDoc (doc); 1467 1468 /* save to disk */ 1469 gchar *confdir, *conffile = NULL; 1470 GError *lerror = NULL; 1471 confdir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_config_dir(), "gda-browser", NULL); 1472 if (!g_file_test (confdir, G_FILE_TEST_EXISTS)) { 1473 if (g_mkdir_with_parents (confdir, 0700)) { 1474 g_warning ("Can't create configuration directory '%s' to save preferences.", 1475 confdir); 1476 goto out; 1477 } 1478 } 1479 conffile = g_build_filename (confdir, "preferences.xml", NULL); 1480 if (! g_file_set_contents (conffile, (gchar *) xml_contents, size, &lerror)) { 1481 g_warning ("Can't save preferences file '%s': %s", conffile, 1482 lerror && lerror->message ? lerror->message : _("No detail")); 1483 g_clear_error (&lerror); 1484 } 1485 1486 out: 1487 xmlFree (xml_contents); 1488 g_free (confdir); 1489 g_free (conffile); 1490 } 1491 1492 static void 1493 load_preferences (void) 1494 { 1495 /* load preferences */ 1496 xmlDocPtr doc; 1497 xmlNodePtr root, node; 1498 gchar *conffile; 1499 conffile = g_build_path (G_DIR_SEPARATOR_S, g_get_user_config_dir(), 1500 "gda-browser", "preferences.xml", NULL); 1501 if (!g_file_test (conffile, G_FILE_TEST_EXISTS)) { 1502 g_free (conffile); 1503 return; 1504 } 1505 1506 doc = xmlParseFile (conffile); 1507 if (!doc) { 1508 g_warning ("Error loading preferences from file '%s'", conffile); 1509 g_free (conffile); 1510 return; 1511 } 1512 g_free (conffile); 1513 1514 root = xmlDocGetRootElement (doc); 1515 for (node = root->children; node; node = node->next) { 1516 xmlChar *contents; 1517 if (strcmp ((gchar *) node->name, "hide-notice")) 1518 continue; 1519 contents = xmlNodeGetContent (node); 1520 if (contents) { 1521 g_hash_table_insert (hidden_contexts, g_strdup ((gchar*) contents), 1522 GINT_TO_POINTER (TRUE)); 1523 xmlFree (contents); 1524 } 1525 } 1526 xmlFreeDoc (doc); 1527 } 1528 1529 1530 /** 1531 * browser_window_show_notice 1532 * @bwin: a #BrowserWindow 1533 * @context: textual description of what context the message is being used in 1534 * @text: the information's text 1535 * 1536 * Makes @bwin display a notice 1537 */ 1538 void 1539 browser_window_show_notice (BrowserWindow *bwin, GtkMessageType type, const gchar *context, const gchar *text) 1540 { 1541 g_return_if_fail (BROWSER_IS_WINDOW (bwin)); 1542 gboolean hide = FALSE; 1543 1544 if ((type != GTK_MESSAGE_ERROR) && context) { 1545 if (!hidden_contexts) { 1546 hidden_contexts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); 1547 load_preferences (); 1548 } 1549 hide = GPOINTER_TO_INT (g_hash_table_lookup (hidden_contexts, context)); 1550 } 1551 1552 if (hide) { 1553 gchar *ptr, *tmp; 1554 tmp = g_strdup (text); 1555 for (ptr = tmp; *ptr && (*ptr != '\n'); ptr++); 1556 if (*ptr) { 1557 *ptr = '.'; ptr++; 1558 *ptr = '.'; ptr++; 1559 *ptr = '.'; ptr++; 1560 *ptr = 0; 1561 } 1562 browser_window_push_status (bwin, "SupportNotice", tmp, TRUE); 1563 g_free (tmp); 1564 } 1565 else { 1566 if (bwin->priv->notif_widgets) { 1567 GSList *list; 1568 for (list = bwin->priv->notif_widgets; list; list = list->next) { 1569 const gchar *c1, *t1; 1570 c1 = g_object_get_data (G_OBJECT (list->data), "context"); 1571 t1 = g_object_get_data (G_OBJECT (list->data), "text"); 1572 if (((c1 && context && !strcmp (c1, context)) || (!c1 && !context)) && 1573 ((t1 && text && !strcmp (t1, text)) || (!t1 && !text))) 1574 break; 1575 } 1576 if (list) { 1577 GtkWidget *wid; 1578 wid = GTK_WIDGET (list->data); 1579 g_object_ref ((GObject*) wid); 1580 gtk_container_remove (GTK_CONTAINER (bwin->priv->notif_box), wid); 1581 gtk_box_pack_end (GTK_BOX (bwin->priv->notif_box), wid, TRUE, TRUE, 0); 1582 g_object_unref ((GObject*) wid); 1583 return; 1584 } 1585 } 1586 1587 GtkWidget *cb = NULL; 1588 if (context && (type == GTK_MESSAGE_INFO)) { 1589 cb = gtk_check_button_new_with_label (_("Don't show this message again")); 1590 g_signal_connect_data (cb, "toggled", 1591 G_CALLBACK (hide_notice_toggled_cb), g_strdup (context), 1592 (GClosureNotify) g_free, 0); 1593 } 1594 1595 /* use a GtkInfoBar */ 1596 GtkWidget *ibar, *content_area, *label; 1597 1598 ibar = gtk_info_bar_new_with_buttons (GTK_STOCK_CLOSE, 1, NULL); 1599 if (context) 1600 g_object_set_data_full (G_OBJECT (ibar), "context", g_strdup (context), g_free); 1601 if (text) 1602 g_object_set_data_full (G_OBJECT (ibar), "text", g_strdup (text), g_free); 1603 gtk_info_bar_set_message_type (GTK_INFO_BAR (ibar), type); 1604 label = gtk_label_new (""); 1605 gtk_label_set_markup (GTK_LABEL (label), text); 1606 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); 1607 gtk_misc_set_alignment (GTK_MISC (label), 0., -1); 1608 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ibar)); 1609 if (cb) { 1610 GtkWidget *box; 1611 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 1612 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0); 1613 gtk_box_pack_start (GTK_BOX (box), cb, FALSE, FALSE, 0); 1614 gtk_container_add (GTK_CONTAINER (content_area), box); 1615 gtk_widget_show_all (box); 1616 } 1617 else { 1618 gtk_container_add (GTK_CONTAINER (content_area), label); 1619 gtk_widget_show (label); 1620 } 1621 g_signal_connect (ibar, "response", 1622 G_CALLBACK (info_bar_response_cb), bwin); 1623 gtk_box_pack_end (GTK_BOX (bwin->priv->notif_box), ibar, TRUE, TRUE, 0); 1624 bwin->priv->notif_widgets = g_slist_append (bwin->priv->notif_widgets, ibar); 1625 if (g_slist_length (bwin->priv->notif_widgets) > 2) { 1626 gtk_widget_destroy (GTK_WIDGET (bwin->priv->notif_widgets->data)); 1627 bwin->priv->notif_widgets = g_slist_delete_link (bwin->priv->notif_widgets, 1628 bwin->priv->notif_widgets); 1629 } 1630 gtk_widget_show (ibar); 1631 } 1632 } 1633 1634 1635 /** 1636 * browser_window_customize_perspective_ui 1637 * @bwin: a #BrowserWindow 1638 * @bpers: the #BrowserPerspective concerned 1639 * @actions_group: (allow-none): a #GtkActionGroup object, or %NULL 1640 * @ui_info: (allow-none): a merge UI string, or %NULL. See gtk_ui_manager_add_ui_from_string() 1641 * 1642 * Customizes a UI specific to the @bpers perspective. Any 1643 * previous customization is removed, replaced by the new requested one. 1644 * 1645 * If @actions_group is %NULL then any it simply removes the customization. 1646 */ 1647 void 1648 browser_window_customize_perspective_ui (BrowserWindow *bwin, BrowserPerspective *bpers, 1649 GtkActionGroup *actions_group, 1650 const gchar *ui_info) 1651 { 1652 PerspectiveData *pdata = NULL; 1653 GSList *list; 1654 1655 g_return_if_fail (BROWSER_IS_WINDOW (bwin)); 1656 g_return_if_fail (IS_BROWSER_PERSPECTIVE (bpers)); 1657 1658 for (list = bwin->priv->perspectives; list; list = list->next) { 1659 if (PERSPECTIVE_DATA (list->data)->perspective_widget == bpers) { 1660 pdata = PERSPECTIVE_DATA (list->data); 1661 break; 1662 } 1663 } 1664 if (! pdata) 1665 return; 1666 1667 /* cleanups */ 1668 if (pdata->customized_merge_id) { 1669 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, pdata->customized_merge_id); 1670 pdata->customized_merge_id = 0; 1671 } 1672 if (pdata->customized_actions) { 1673 gtk_ui_manager_remove_action_group (bwin->priv->ui_manager, pdata->customized_actions); 1674 g_object_unref (pdata->customized_actions); 1675 pdata->customized_actions = NULL; 1676 } 1677 g_free (pdata->customized_ui); 1678 pdata->customized_ui = NULL; 1679 gtk_ui_manager_ensure_update (bwin->priv->ui_manager); 1680 1681 if (actions_group) { 1682 g_return_if_fail (GTK_IS_ACTION_GROUP (actions_group)); 1683 gtk_action_group_set_translation_domain (actions_group, GETTEXT_PACKAGE); 1684 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions_group, 0); 1685 pdata->customized_actions = g_object_ref (actions_group); 1686 } 1687 if (ui_info) { 1688 pdata->customized_ui = g_strdup (ui_info); 1689 pdata->customized_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager, 1690 pdata->customized_ui, 1691 -1, NULL); 1692 } 1693 } 1694 1695 /** 1696 * browser_window_change_perspective 1697 * @bwin: a #BrowserWindow 1698 * @perspective: the name of the perspective to change to 1699 * 1700 * Make @bwin switch to the perspective named @perspective 1701 * 1702 * Returns: a pointer to the #BrowserPerspective, or %NULL if not found 1703 */ 1704 BrowserPerspective * 1705 browser_window_change_perspective (BrowserWindow *bwin, const gchar *perspective) 1706 { 1707 BrowserPerspectiveFactory *bpf; 1708 BrowserPerspective *bpers = NULL; 1709 PerspectiveData *current_pdata; 1710 1711 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), NULL); 1712 g_return_val_if_fail (perspective, NULL); 1713 1714 current_pdata = bwin->priv->current_perspective; 1715 1716 bpf = browser_core_get_factory (perspective); 1717 if (!bpf) 1718 return NULL; 1719 GList *actions, *list; 1720 actions = gtk_action_group_list_actions (bwin->priv->perspectives_actions); 1721 for (list = actions; list; list = list->next) { 1722 GtkAction *action = (GtkAction *) list->data; 1723 BrowserPerspectiveFactory *pf; 1724 pf = BROWSER_PERSPECTIVE_FACTORY (g_object_get_data (G_OBJECT (action), "pers")); 1725 if (pf == bpf) { 1726 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); 1727 PerspectiveData *pdata = bwin->priv->current_perspective; 1728 if (pdata && ! g_ascii_strcasecmp (pdata->factory->perspective_name, perspective)) 1729 bpers = pdata->perspective_widget; 1730 break; 1731 } 1732 } 1733 g_list_free (actions); 1734 1735 gchar *tmp; 1736 tmp = g_markup_printf_escaped (_("The current perspective has changed to the '%s' perspective, you " 1737 "can switch back to previous perspective through the " 1738 "'Perspective/%s' menu, or using the '%s' shortcut"), 1739 bwin->priv->current_perspective->factory->perspective_name, 1740 current_pdata->factory->perspective_name, 1741 current_pdata->factory->menu_shortcut); 1742 1743 1744 browser_window_show_notice (bwin, GTK_MESSAGE_INFO, "Perspective change", tmp); 1745 g_free (tmp); 1746 1747 return bpers; 1748 } 1749 1750 /** 1751 * browser_window_is_fullscreen 1752 * @bwin: a #BrowserWindow 1753 * 1754 * Returns: %TRUE if @bwin is fullscreen 1755 */ 1756 gboolean 1757 browser_window_is_fullscreen (BrowserWindow *bwin) 1758 { 1759 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), FALSE); 1760 return bwin->priv->fullscreen; 1761 } 1762 1763 /** 1764 * browser_window_set_fullscreen 1765 * @bwin: a #BrowserWindow 1766 * @fullscreen: 1767 * 1768 * Requires @bwin to be fullscreen if @fullscreen is %TRUE 1769 */ 1770 void 1771 browser_window_set_fullscreen (BrowserWindow *bwin, gboolean fullscreen) 1772 { 1773 GtkAction *action; 1774 g_return_if_fail (BROWSER_IS_WINDOW (bwin)); 1775 1776 action = gtk_action_group_get_action (bwin->priv->agroup, "WindowFullScreen"); 1777 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen); 1778 } 1779