2007-09-24 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / src / anjuta-app.c
blob2527cc43a7f5c6f074a76580d4e78fd7cc30b7e8
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta.c Copyright (C) 2003 Naba Kumar <naba@gnome.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc., 59
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <sys/wait.h>
30 #include <gnome.h>
31 #include <gtk/gtkwidget.h>
32 #include <glade/glade.h>
34 #include <gdl/gdl-dock.h>
35 #include <gdl/gdl-dock-bar.h>
37 #include <bonobo/bonobo-dock-item.h>
39 #include <libanjuta/anjuta-shell.h>
40 #include <libanjuta/anjuta-utils.h>
41 #include <libanjuta/resources.h>
42 #include <libanjuta/anjuta-plugin-manager.h>
43 #include <libanjuta/anjuta-debug.h>
45 #include "anjuta-app.h"
46 #include "anjuta-callbacks.h"
47 #include "anjuta-actions.h"
48 #include "about.h"
50 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta.ui"
51 #define GLADE_FILE PACKAGE_DATA_DIR"/glade/anjuta.glade"
52 #define ICON_FILE "preferences-general.png"
54 #define DOCK_PH_LEFT "ph_left"
55 #define DOCK_PH_RIGHT "ph_right"
56 #define DOCK_PH_TOP "ph_top"
57 #define DOCK_PH_BOTTOM "ph_bottom"
59 static void anjuta_app_layout_load (AnjutaApp *app,
60 const gchar *layout_filename,
61 const gchar *name);
62 static void anjuta_app_layout_save (AnjutaApp *app,
63 const gchar *layout_filename,
64 const gchar *name);
66 static gpointer parent_class = NULL;
67 static GList* toolbars = NULL;
69 static void
70 on_toggle_widget_view (GtkCheckMenuItem *menuitem, GtkWidget *dockitem)
72 gboolean state;
73 state = gtk_check_menu_item_get_active (menuitem);
74 if (state)
75 gdl_dock_item_show_item (GDL_DOCK_ITEM (dockitem));
76 else
77 gdl_dock_item_hide_item (GDL_DOCK_ITEM (dockitem));
80 static void
81 on_update_widget_view_menuitem (gpointer key, gpointer wid, gpointer data)
83 GtkCheckMenuItem *menuitem;
84 GdlDockItem *dockitem;
86 dockitem = g_object_get_data (G_OBJECT (wid), "dockitem");
87 menuitem = g_object_get_data (G_OBJECT (wid), "menuitem");
89 g_signal_handlers_block_by_func (menuitem,
90 G_CALLBACK (on_toggle_widget_view),
91 dockitem);
93 if (GDL_DOCK_OBJECT_ATTACHED (dockitem))
94 gtk_check_menu_item_set_active (menuitem, TRUE);
95 else
96 gtk_check_menu_item_set_active (menuitem, FALSE);
98 g_signal_handlers_unblock_by_func (menuitem,
99 G_CALLBACK (on_toggle_widget_view),
100 dockitem);
103 static void
104 on_layout_dirty_notify (GObject *object, GParamSpec *pspec, gpointer user_data)
106 if (!strcmp (pspec->name, "dirty")) {
107 gboolean dirty;
108 g_object_get (object, "dirty", &dirty, NULL);
109 if (dirty) {
110 /* Update UI toggle buttons */
111 g_hash_table_foreach (ANJUTA_APP (user_data)->widgets,
112 on_update_widget_view_menuitem,
113 NULL);
118 static void
119 on_layout_locked_notify (GdlDockMaster *master,
120 GParamSpec *pspec,
121 AnjutaApp *app)
123 AnjutaUI *ui;
124 GtkAction *action;
125 gint locked;
127 ui = app->ui;
128 action = anjuta_ui_get_action (ui, "ActionGroupToggleView",
129 "ActionViewLockLayout");
131 g_object_get (master, "locked", &locked, NULL);
132 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
133 (locked == 1));
136 static void
137 on_toolbar_view_toggled (GtkCheckMenuItem *menuitem, GtkWidget *widget)
139 AnjutaApp *app;
140 BonoboDockItem *dock_item;
141 const gchar *name;
142 gint band;
143 gint position;
144 gint offset;
147 name = gtk_widget_get_name (widget);
148 app = g_object_get_data (G_OBJECT(widget), "app");
149 dock_item = g_object_get_data (G_OBJECT(widget), "dock_item");
150 band = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(widget), "band"));
151 position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(widget), "position"));
152 offset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(widget), "offset"));
155 if (gtk_check_menu_item_get_active (menuitem))
157 if (!dock_item)
159 static gint count;
160 gchar *unique_name = g_strdup_printf ("%s-%d", name, count);
162 /* gnome_app_add_docked() does not allow adding a widget using
163 * a previously used name (even if the previous widget has
164 * has be destroyed. Hence a unique_name is used by using a
165 * static counter */
166 DEBUG_PRINT ("Adding dock item %s band %d, offset %d, position %d", unique_name,
167 band, offset, position);
169 /* Widget not yet added to the dock. Add it */
170 gnome_app_add_docked (GNOME_APP (app), widget,
171 unique_name,
172 BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL |
173 BONOBO_DOCK_ITEM_BEH_NEVER_FLOATING,
174 BONOBO_DOCK_TOP, band, position, offset);
176 dock_item = gnome_app_get_dock_item_by_name (GNOME_APP (app),
177 unique_name);
178 g_object_set_data_full (G_OBJECT(dock_item), "unique_name", unique_name, g_free);
179 g_object_set_data (G_OBJECT(widget), "dock_item", dock_item);
180 count++;
182 gtk_widget_show (GTK_WIDGET (dock_item));
183 gtk_widget_show (GTK_BIN (dock_item)->child);
185 else if (dock_item)
187 gtk_widget_hide (GTK_WIDGET (dock_item));
188 gtk_widget_hide (GTK_BIN (dock_item)->child);
192 static void
193 on_merge_widget_destroy (GtkWidget *merge_widget, GtkWidget *menuitem)
195 toolbars = g_list_remove (toolbars, merge_widget);
196 DEBUG_PRINT ("Destroying menuitem for toolbar widget");
197 gtk_widget_destroy (menuitem);
200 static void
201 on_add_merge_widget (GtkUIManager *merge, GtkWidget *widget,
202 GtkWidget *ui_container)
204 DEBUG_PRINT ("Adding UI item ...");
206 if (GTK_IS_MENU_BAR (widget))
208 gnome_app_set_menus (GNOME_APP (ui_container), GTK_MENU_BAR (widget));
209 gtk_widget_show (widget);
211 else
213 static gint count = 0;
214 const gchar *toolbarname;
215 gchar* visible_key;
216 gchar* band_key;
217 gchar* position_key;
218 gchar* offset_key;
219 AnjutaPreferences *pr;
220 GtkWidget *menuitem;
221 gint band;
222 gint position;
223 gint offset;
224 pr = ANJUTA_PREFERENCES (ANJUTA_APP(ui_container)->preferences);
226 /* Showing the arrows seem to break anything completly! */
227 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (widget), FALSE);
229 gtk_widget_show (widget);
230 g_object_set_data (G_OBJECT (widget), "app", ui_container);
232 /* Load toolbar position */
233 toolbarname = gtk_widget_get_name (widget);
234 band_key = g_strconcat (toolbarname, ".band", NULL);
235 position_key = g_strconcat (toolbarname, ".position", NULL);
236 offset_key = g_strconcat (toolbarname, ".offset", NULL);
237 band = anjuta_preferences_get_int_with_default(pr, band_key, -1);
238 position = anjuta_preferences_get_int_with_default(pr, position_key, 0);
239 offset = anjuta_preferences_get_int_with_default(pr, offset_key, 0);
240 /* Without these check you might see odd results */
241 if (band < 1)
242 band = count + 1;
243 g_object_set_data(G_OBJECT(widget), "position", GINT_TO_POINTER(position));
244 g_object_set_data(G_OBJECT(widget), "offset", GINT_TO_POINTER(offset));
245 g_object_set_data (G_OBJECT (widget), "band",
246 GINT_TO_POINTER(band));
247 g_free(offset_key);
248 g_free(position_key);
249 g_free(band_key);
250 DEBUG_PRINT ("Adding toolbar: %s", toolbarname);
252 if (!ANJUTA_APP (ui_container)->toolbars_menu)
254 ANJUTA_APP (ui_container)->toolbars_menu = gtk_menu_new ();
255 gtk_widget_show (GTK_WIDGET (ANJUTA_APP (ui_container)->toolbars_menu));
258 menuitem = gtk_check_menu_item_new_with_label (toolbarname);
259 gtk_menu_append (GTK_MENU (ANJUTA_APP (ui_container)->toolbars_menu),
260 menuitem);
261 gtk_widget_show (GTK_WIDGET (menuitem));
262 g_signal_connect (G_OBJECT (menuitem), "toggled",
263 G_CALLBACK (on_toolbar_view_toggled), widget);
264 g_object_set_data(G_OBJECT(widget), "menuitem", menuitem);
266 /* When the toolbar is destroyed make sure corresponding menuitem is
267 * also destroyed */
268 g_signal_connect (widget, "destroy",
269 G_CALLBACK (on_merge_widget_destroy),
270 menuitem);
272 toolbars = g_list_append(toolbars, widget);
274 /* Show/hide toolbar */
275 visible_key = g_strconcat (toolbarname, ".visible", NULL);
276 if (anjuta_preferences_get_int_with_default (pr, visible_key,
277 (count == 0)? 1:0))
279 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
280 TRUE);
282 g_free (visible_key);
283 count ++;
287 static void
288 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase,
289 AnjutaSession *session, AnjutaApp *app)
291 gchar *geometry, *layout_file;
292 GdkWindowState state;
293 GList* node = toolbars;
296 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
297 return;
299 /* Save toolbars */
300 while (node)
302 GtkWidget* widget = node->data;
303 GtkWidget* dock_item = g_object_get_data (G_OBJECT(widget), "dock_item");;
304 const gchar* toolbarname = gtk_widget_get_name(widget);
305 AnjutaPreferences* pr = ANJUTA_PREFERENCES (app->preferences);
307 if (dock_item)
309 gboolean visible;
310 gchar* key = g_strconcat (toolbarname, ".visible", NULL);
311 gchar* band_key = g_strconcat (toolbarname, ".band", NULL);
312 gchar* position_key = g_strconcat (toolbarname, ".position", NULL);
313 gchar* offset_key = g_strconcat (toolbarname, ".offset", NULL);
314 GnomeApp* gnome_app = GNOME_APP(app);
316 /* Save visibility */
317 g_object_get(G_OBJECT(dock_item), "visible", &visible, NULL);
318 anjuta_preferences_set_int(pr, key, visible);
319 g_free(key);
321 /* Save toolbar position */
322 if (gnome_app->dock != NULL)
324 guint band;
325 guint position;
326 guint offset;
327 BonoboDockPlacement placement;
328 gchar* unique_name = g_object_get_data(G_OBJECT(dock_item), "unique_name");
330 BonoboDockItem* item = bonobo_dock_get_item_by_name(BONOBO_DOCK(gnome_app->dock),
331 unique_name, &placement,
332 &band, &position, &offset);
333 g_return_if_fail(item != NULL);
335 anjuta_preferences_set_int(pr, band_key, band);
336 anjuta_preferences_set_int(pr, position_key, position);
337 anjuta_preferences_set_int(pr, offset_key, offset);
340 node = g_list_next(node);
343 /* Save geometry */
344 state = gdk_window_get_state (GTK_WIDGET (app)->window);
345 if (state & GDK_WINDOW_STATE_MAXIMIZED) {
346 anjuta_session_set_int (session, "Anjuta", "Maximized", 1);
348 if (state & GDK_WINDOW_STATE_FULLSCREEN) {
349 anjuta_session_set_int (session, "Anjuta", "Fullscreen", 1);
352 /* Save geometry only if window is not maximized or fullscreened */
353 if (!(state & GDK_WINDOW_STATE_MAXIMIZED) ||
354 !(state & GDK_WINDOW_STATE_FULLSCREEN))
356 geometry = anjuta_app_get_geometry (app);
357 if (geometry)
358 anjuta_session_set_string (session, "Anjuta", "Geometry",
359 geometry);
360 g_free (geometry);
363 /* Save layout */
364 layout_file = g_build_filename (anjuta_session_get_session_directory (session),
365 "dock-layout.xml", NULL);
366 anjuta_app_layout_save (app, layout_file, NULL);
367 g_free (layout_file);
370 static void
371 on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase,
372 AnjutaSession *session, AnjutaApp *app)
374 /* We load layout at last so that all plugins would have loaded by now */
375 if (phase == ANJUTA_SESSION_PHASE_LAST)
377 gchar *geometry;
378 gchar *layout_file;
380 /* Restore geometry */
381 geometry = anjuta_session_get_string (session, "Anjuta", "Geometry");
382 anjuta_app_set_geometry (app, geometry);
384 /* Restore window state */
385 if (anjuta_session_get_int (session, "Anjuta", "Fullscreen"))
387 /* bug #304495 */
388 AnjutaUI* ui = anjuta_shell_get_ui(shell, NULL);
389 GtkAction* action = anjuta_ui_get_action (ui, "ActionGroupToggleView",
390 "ActionViewFullscreen");
391 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
392 TRUE);
394 gtk_window_fullscreen (GTK_WINDOW (shell));
397 else if (anjuta_session_get_int (session, "Anjuta", "Maximized"))
399 gtk_window_maximize (GTK_WINDOW (shell));
402 /* Restore layout */
403 layout_file = g_build_filename (anjuta_session_get_session_directory (session),
404 "dock-layout.xml", NULL);
405 anjuta_app_layout_load (app, layout_file, NULL);
406 g_free (layout_file);
410 static void
411 on_accel_changed (GtkAccelGroup *accelgroup, guint arg1, GdkModifierType arg2,
412 GClosure *arg3, AnjutaApp *app)
414 gnome_accelerators_sync ();
417 static void
418 anjuta_app_dispose (GObject *widget)
420 AnjutaApp *app;
421 GList *tmp_list;
423 g_return_if_fail (ANJUTA_IS_APP (widget));
425 app = ANJUTA_APP (widget);
427 if (app->widgets)
429 if (g_hash_table_size (app->widgets) > 0)
432 g_warning ("Some widgets are still inside shell (%d widgets), they are:",
433 g_hash_table_size (app->widgets));
434 g_hash_table_foreach (app->widgets, (GHFunc)puts, NULL);
437 g_hash_table_destroy (app->widgets);
438 app->widgets = NULL;
441 if (app->values)
443 if (g_hash_table_size (app->values) > 0)
446 g_warning ("Some Values are still left in shell (%d Values), they are:",
447 g_hash_table_size (app->values));
448 g_hash_table_foreach (app->values, (GHFunc)puts, NULL);
451 g_hash_table_destroy (app->values);
452 app->values = NULL;
455 /* We need to destroy to the toolbars now so that the
456 * on_merge_widget_destroy() does not produce a error trying to destory
457 * already destroyed menuitems which happen when the window is being
458 * destroyed
460 * Make a tmp list because the handler removes items from 'toolbars' list.
461 * FIXME: Why is 'toolbars' a global static variable?
463 tmp_list = g_list_copy (toolbars);
464 g_list_foreach (tmp_list, (GFunc)gtk_widget_destroy, NULL);
465 g_list_free (tmp_list);
467 if (app->layout_manager) {
468 g_object_unref (app->layout_manager);
469 app->layout_manager = NULL;
471 if (app->profile_manager) {
472 g_object_unref (G_OBJECT (app->profile_manager));
473 app->profile_manager = NULL;
475 if (app->plugin_manager) {
476 g_object_unref (G_OBJECT (app->plugin_manager));
477 app->plugin_manager = NULL;
479 if (app->status) {
480 g_object_unref (G_OBJECT (app->status));
481 app->status = NULL;
483 GNOME_CALL_PARENT(G_OBJECT_CLASS, dispose, (widget));
486 static void
487 anjuta_app_finalize (GObject *widget)
489 AnjutaApp *app;
491 g_return_if_fail (ANJUTA_IS_APP (widget));
493 app = ANJUTA_APP (widget);
495 gtk_widget_destroy (GTK_WIDGET (app->ui));
496 gtk_widget_destroy (GTK_WIDGET (app->preferences));
498 GNOME_CALL_PARENT(G_OBJECT_CLASS, finalize, (widget));
501 static void
502 anjuta_app_instance_init (AnjutaApp *app)
504 gint merge_id;
505 GtkWidget *toolbar_menu, *about_menu;
506 GtkWidget *view_menu, *hbox;
507 GtkWidget *dockbar;
508 GtkAccelGroup *accel_group;
509 GtkAction* action;
510 GList *plugins_dirs = NULL;
511 GdkGeometry size_hints = {
512 100, 100, 0, 0, 100, 100, 1, 1, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
515 DEBUG_PRINT ("Initializing Anjuta...");
517 gtk_window_set_geometry_hints (GTK_WINDOW (app), GTK_WIDGET (app),
518 &size_hints, GDK_HINT_RESIZE_INC);
519 gtk_window_set_resizable (GTK_WINDOW (app), TRUE);
521 gnome_app_enable_layout_config (GNOME_APP (app), FALSE);
523 app->layout_manager = NULL;
525 app->values = NULL;
526 app->widgets = NULL;
528 /* configure dock */
529 hbox = gtk_hbox_new (FALSE, 0);
530 gtk_widget_show (hbox);
531 gnome_app_set_contents (GNOME_APP (app), hbox);
532 app->dock = gdl_dock_new ();
533 gtk_widget_show (app->dock);
534 gtk_box_pack_end(GTK_BOX (hbox), app->dock, TRUE, TRUE, 0);
536 dockbar = gdl_dock_bar_new (GDL_DOCK(app->dock));
537 gtk_widget_show (dockbar);
538 gtk_box_pack_start(GTK_BOX (hbox), dockbar, FALSE, FALSE, 0);
540 app->layout_manager = gdl_dock_layout_new (GDL_DOCK (app->dock));
541 g_signal_connect (app->layout_manager, "notify::dirty",
542 G_CALLBACK (on_layout_dirty_notify), app);
543 g_signal_connect (app->layout_manager->master, "notify::locked",
544 G_CALLBACK (on_layout_locked_notify), app);
545 /* Status bar */
546 app->status = ANJUTA_STATUS (anjuta_status_new ());
547 anjuta_status_set_title_window (app->status, GTK_WIDGET (app));
548 gtk_widget_show (GTK_WIDGET (app->status));
549 gnome_app_set_statusbar (GNOME_APP (app), GTK_WIDGET (app->status));
550 g_object_ref (G_OBJECT (app->status));
551 g_object_add_weak_pointer (G_OBJECT (app->status), (gpointer)&app->status);
553 /* UI engine */
554 app->ui = anjuta_ui_new ();
556 accel_group = anjuta_ui_get_accel_group (app->ui);
557 g_signal_connect (accel_group, "accel-changed",
558 G_CALLBACK (on_accel_changed), app);
560 gtk_window_add_accel_group (GTK_WINDOW (app), accel_group);
561 g_signal_connect (G_OBJECT (app->ui),
562 "add_widget", G_CALLBACK (on_add_merge_widget),
563 app);
564 g_object_add_weak_pointer (G_OBJECT (app->ui), (gpointer)&app->ui);
566 /* Plugin Manager */
567 plugins_dirs = g_list_prepend (plugins_dirs, PACKAGE_PLUGIN_DIR);
568 app->plugin_manager = anjuta_plugin_manager_new (G_OBJECT (app),
569 app->status,
570 plugins_dirs);
571 app->profile_manager = anjuta_profile_manager_new (app->plugin_manager);
572 g_list_free (plugins_dirs);
574 /* Preferences */
575 app->preferences = anjuta_preferences_new (app->plugin_manager);
576 g_object_add_weak_pointer (G_OBJECT (app->preferences),
577 (gpointer)&app->preferences);
579 /* Register actions */
580 anjuta_ui_add_action_group_entries (app->ui, "ActionGroupFile", _("File"),
581 menu_entries_file,
582 G_N_ELEMENTS (menu_entries_file),
583 GETTEXT_PACKAGE, TRUE, app);
584 anjuta_ui_add_action_group_entries (app->ui, "ActionGroupEdit", _("Edit"),
585 menu_entries_edit,
586 G_N_ELEMENTS (menu_entries_edit),
587 GETTEXT_PACKAGE, TRUE, app);
588 anjuta_ui_add_action_group_entries (app->ui, "ActionGroupView", _("View"),
589 menu_entries_view,
590 G_N_ELEMENTS (menu_entries_view),
591 GETTEXT_PACKAGE, TRUE, app);
592 anjuta_ui_add_toggle_action_group_entries (app->ui, "ActionGroupToggleView",
593 _("Toggle View"),
594 menu_entries_toggle_view,
595 G_N_ELEMENTS (menu_entries_toggle_view),
596 GETTEXT_PACKAGE, TRUE, app);
597 anjuta_ui_add_action_group_entries (app->ui, "ActionGroupHelp", _("Help"),
598 menu_entries_help,
599 G_N_ELEMENTS (menu_entries_help),
600 GETTEXT_PACKAGE, TRUE, app);
602 /* Merge UI */
603 merge_id = anjuta_ui_merge (app->ui, UI_FILE);
605 /* Disable unavailible tutorials */
606 action = anjuta_ui_get_action(app->ui, "ActionGroupHelp", "ActionHelpTutorial");
607 g_object_set(G_OBJECT(action), "visible", FALSE, NULL);
608 action = anjuta_ui_get_action(app->ui, "ActionGroupHelp", "ActionHelpAdvancedTutorial");
609 g_object_set(G_OBJECT(action), "visible", FALSE, NULL);
611 /* create toolbar menus */
612 toolbar_menu =
613 gtk_ui_manager_get_widget (GTK_UI_MANAGER(app->ui),
614 "/MenuMain/MenuView/Toolbars");
615 if (toolbar_menu)
616 gtk_menu_item_set_submenu (GTK_MENU_ITEM (toolbar_menu),
617 app->toolbars_menu);
618 else
619 g_warning ("Cannot retrive main menu widget");
621 /* Create widgets menu */
622 view_menu =
623 gtk_ui_manager_get_widget (GTK_UI_MANAGER(app->ui),
624 "/MenuMain/MenuView");
625 app->view_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (view_menu));
627 /* Create about plugins menu */
628 about_menu =
629 gtk_ui_manager_get_widget (GTK_UI_MANAGER(app->ui),
630 "/MenuMain/PlaceHolderHelpMenus/MenuHelp/"
631 "PlaceHolderHelpAbout/AboutPlugins");
632 about_create_plugins_submenu (ANJUTA_SHELL (app), about_menu);
634 /* Connect to session */
635 g_signal_connect (G_OBJECT (app), "save_session",
636 G_CALLBACK (on_session_save), app);
637 g_signal_connect (G_OBJECT (app), "load_session",
638 G_CALLBACK (on_session_load), app);
641 static void
642 anjuta_app_class_init (AnjutaAppClass *class)
644 GObjectClass *object_class;
645 GtkWidgetClass *widget_class;
647 parent_class = g_type_class_peek_parent (class);
648 object_class = (GObjectClass*) class;
649 widget_class = (GtkWidgetClass*) class;
650 object_class->finalize = anjuta_app_finalize;
651 object_class->dispose = anjuta_app_dispose;
654 GtkWidget *
655 anjuta_app_new (void)
657 AnjutaApp *app;
659 app = ANJUTA_APP (g_object_new (ANJUTA_TYPE_APP,
660 "title", "Anjuta",
661 NULL));
662 return GTK_WIDGET (app);
665 gchar*
666 anjuta_app_get_geometry (AnjutaApp *app)
668 gchar *geometry;
669 gint width, height, posx, posy;
671 g_return_val_if_fail (ANJUTA_IS_APP (app), NULL);
673 geometry = NULL;
674 width = height = posx = posy = 0;
675 if (GTK_WIDGET(app)->window)
677 gtk_window_get_size (GTK_WINDOW (app), &width, &height);
678 gtk_window_get_position (GTK_WINDOW(app), &posx, &posy);
680 geometry = g_strdup_printf ("%dx%d+%d+%d", width, height, posx, posy);
682 return geometry;
685 void
686 anjuta_app_set_geometry (AnjutaApp *app, const gchar *geometry)
688 gint width, height, posx, posy;
689 gboolean geometry_set = FALSE;
691 if (geometry && strlen (geometry) > 0)
693 DEBUG_PRINT ("Setting geometry: %s", geometry);
695 if (sscanf (geometry, "%dx%d+%d+%d", &width, &height,
696 &posx, &posy) == 4)
698 if (GTK_WIDGET_REALIZED (app))
700 gtk_window_resize (GTK_WINDOW (app), width, height);
702 else
704 gtk_window_set_default_size (GTK_WINDOW (app), width, height);
705 gtk_window_move (GTK_WINDOW (app), posx, posy);
707 geometry_set = TRUE;
709 else
711 g_warning ("Failed to parse geometry: %s", geometry);
714 if (!geometry_set)
716 posx = 10;
717 posy = 10;
718 width = gdk_screen_width () - 10;
719 height = gdk_screen_height () - 25;
720 width = (width < 790)? width : 790;
721 height = (height < 575)? width : 575;
722 if (GTK_WIDGET_REALIZED (app) == FALSE)
724 gtk_window_set_default_size (GTK_WINDOW (app), width, height);
725 gtk_window_move (GTK_WINDOW (app), posx, posy);
730 static void
731 anjuta_app_layout_save (AnjutaApp *app, const gchar *filename,
732 const gchar *name)
734 g_return_if_fail (ANJUTA_IS_APP (app));
735 g_return_if_fail (filename != NULL);
737 gdl_dock_layout_save_layout (app->layout_manager, name);
738 if (!gdl_dock_layout_save_to_file (app->layout_manager, filename))
739 g_warning ("Saving dock layout to '%s' failed!", filename);
742 static void
743 anjuta_app_layout_load (AnjutaApp *app, const gchar *layout_filename,
744 const gchar *name)
746 g_return_if_fail (ANJUTA_IS_APP (app));
748 if (!layout_filename ||
749 !gdl_dock_layout_load_from_file (app->layout_manager, layout_filename))
751 gchar *datadir, *filename;
752 datadir = anjuta_res_get_data_dir();
754 filename = g_build_filename (datadir, "layout.xml", NULL);
755 DEBUG_PRINT ("Layout = %s", filename);
756 g_free (datadir);
757 if (!gdl_dock_layout_load_from_file (app->layout_manager, filename))
758 g_warning ("Loading layout from '%s' failed!!", filename);
759 g_free (filename);
762 if (!gdl_dock_layout_load_layout (app->layout_manager, name))
763 g_warning ("Loading layout failed!!");
766 void
767 anjuta_app_layout_reset (AnjutaApp *app)
769 anjuta_app_layout_load (app, NULL, NULL);
772 void
773 anjuta_app_install_preferences (AnjutaApp *app)
775 GladeXML *gxml;
776 GtkWidget *notebook, *shortcuts, *plugins, *remember_plugins;
778 /* Create preferences page */
779 gxml = glade_xml_new (GLADE_FILE, "anjuta_preferences_window", NULL);
780 anjuta_preferences_add_page (app->preferences, gxml,
781 "General", _("General"), ICON_FILE);
782 notebook = glade_xml_get_widget (gxml, "General");
783 shortcuts = anjuta_ui_get_accel_editor (ANJUTA_UI (app->ui));
784 plugins = anjuta_plugin_manager_get_plugins_page (app->plugin_manager);
785 remember_plugins = anjuta_plugin_manager_get_remembered_plugins_page (app->plugin_manager);
787 gtk_widget_show (shortcuts);
788 gtk_widget_show (plugins);
789 gtk_widget_show (remember_plugins);
791 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), plugins,
792 gtk_label_new (_("Installed plugins")));
793 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), remember_plugins,
794 gtk_label_new (_("Preferred plugins")));
795 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), shortcuts,
796 gtk_label_new (_("Shortcuts")));
798 g_object_unref (gxml);
801 /* AnjutaShell Implementation */
803 static void
804 on_value_removed_from_hash (gpointer value)
806 g_value_unset ((GValue*)value);
807 g_free (value);
810 static void
811 anjuta_app_add_value (AnjutaShell *shell, const char *name,
812 const GValue *value, GError **error)
814 GValue *copy;
815 AnjutaApp *app;
817 g_return_if_fail (ANJUTA_IS_APP (shell));
818 g_return_if_fail (name != NULL);
819 g_return_if_fail (G_IS_VALUE(value));
821 app = ANJUTA_APP (shell);
823 if (app->values == NULL)
825 app->values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
826 on_value_removed_from_hash);
828 anjuta_shell_remove_value (shell, name, error);
830 copy = g_new0 (GValue, 1);
831 g_value_init (copy, value->g_type);
832 g_value_copy (value, copy);
834 g_hash_table_insert (app->values, g_strdup (name), copy);
835 g_signal_emit_by_name (shell, "value_added", name, copy);
838 static void
839 anjuta_app_get_value (AnjutaShell *shell, const char *name, GValue *value,
840 GError **error)
842 GValue *val;
843 AnjutaApp *app;
845 g_return_if_fail (ANJUTA_IS_APP (shell));
846 g_return_if_fail (name != NULL);
847 /* g_return_if_fail (G_IS_VALUE (value)); */
849 app = ANJUTA_APP (shell);
851 val = NULL;
852 if (app->values)
853 val = g_hash_table_lookup (app->values, name);
854 if (val)
856 if (!value->g_type)
858 g_value_init (value, val->g_type);
860 g_value_copy (val, value);
862 else
864 if (error)
866 *error = g_error_new (ANJUTA_SHELL_ERROR,
867 ANJUTA_SHELL_ERROR_DOESNT_EXIST,
868 _("Value doesn't exist"));
873 static void
874 anjuta_app_remove_value (AnjutaShell *shell, const char *name, GError **error)
876 AnjutaApp *app;
877 GValue *value;
878 char *key;
880 g_return_if_fail (ANJUTA_IS_APP (shell));
881 g_return_if_fail (name != NULL);
883 app = ANJUTA_APP (shell);
886 g_return_if_fail (app->values != NULL);
887 if (app->widgets && g_hash_table_lookup_extended (app->widgets, name,
888 (gpointer*)&key,
889 (gpointer*)&w)) {
890 GtkWidget *item;
891 item = g_object_get_data (G_OBJECT (w), "dockitem");
892 gdl_dock_item_hide_item (GDL_DOCK_ITEM (item));
893 gdl_dock_object_unbind (GDL_DOCK_OBJECT (item));
894 g_free (key);
898 if (app->values && g_hash_table_lookup_extended (app->values, name,
899 (gpointer)&key,
900 (gpointer)&value)) {
901 g_signal_emit_by_name (app, "value_removed", name);
902 g_hash_table_remove (app->values, name);
906 static gboolean
907 remove_from_widgets_hash (gpointer name, gpointer hash_widget, gpointer widget)
909 if (hash_widget == widget)
910 return TRUE;
911 return FALSE;
914 static void
915 on_widget_destroy (GtkWidget *widget, AnjutaApp *app)
917 DEBUG_PRINT ("Widget about to be destroyed");
918 g_hash_table_foreach_remove (app->widgets, remove_from_widgets_hash,
919 widget);
922 static void
923 on_widget_remove (GtkWidget *container, GtkWidget *widget, AnjutaApp *app)
925 GtkWidget *dock_item;
926 GList* node = toolbars;
927 while (node)
929 if (node->data == widget)
931 g_message("Removing toolbar");
932 GtkWidget* menuitem = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "menuitem"));
933 gtk_widget_hide(menuitem);
934 gtk_widget_destroy(menuitem);
935 toolbars = g_list_delete_link(toolbars, node);
936 break;
938 node = g_list_next(node);
941 dock_item = g_object_get_data (G_OBJECT (widget), "dockitem");
942 if (dock_item)
944 gchar* unique_name = g_object_get_data(G_OBJECT(dock_item), "unique_name");
945 g_free(unique_name);
946 g_signal_handlers_disconnect_by_func (G_OBJECT (dock_item),
947 G_CALLBACK (on_widget_remove), app);
948 gdl_dock_item_unbind (GDL_DOCK_ITEM(dock_item));
950 if (g_hash_table_foreach_remove (app->widgets,
951 remove_from_widgets_hash,
952 widget)){
953 DEBUG_PRINT ("Widget removed from container");
957 static void
958 on_widget_removed_from_hash (gpointer widget)
960 AnjutaApp *app;
961 GtkWidget *menuitem;
962 GdlDockItem *dockitem;
964 DEBUG_PRINT ("Removing widget from hash");
966 app = g_object_get_data (G_OBJECT (widget), "app-object");
967 dockitem = g_object_get_data (G_OBJECT (widget), "dockitem");
968 menuitem = g_object_get_data (G_OBJECT (widget), "menuitem");
970 gtk_widget_destroy (menuitem);
972 g_object_set_data (G_OBJECT (widget), "dockitem", NULL);
973 g_object_set_data (G_OBJECT (widget), "menuitem", NULL);
975 g_signal_handlers_disconnect_by_func (G_OBJECT (widget),
976 G_CALLBACK (on_widget_destroy), app);
977 g_signal_handlers_disconnect_by_func (G_OBJECT (dockitem),
978 G_CALLBACK (on_widget_remove), app);
980 g_object_unref (G_OBJECT (widget));
983 static void
984 anjuta_app_add_widget_full (AnjutaShell *shell,
985 GtkWidget *widget,
986 const char *name,
987 const char *title,
988 const char *stock_id,
989 AnjutaShellPlacement placement,
990 gboolean locked,
991 GError **error)
993 AnjutaApp *app;
994 GtkWidget *item;
995 GtkCheckMenuItem* menuitem;
997 g_return_if_fail (ANJUTA_IS_APP (shell));
998 g_return_if_fail (GTK_IS_WIDGET (widget));
999 g_return_if_fail (name != NULL);
1000 g_return_if_fail (title != NULL);
1002 app = ANJUTA_APP (shell);
1005 anjuta_shell_add (shell, name, G_TYPE_FROM_INSTANCE (widget),
1006 widget, NULL);
1009 /* Add the widget to hash */
1010 if (app->widgets == NULL)
1012 app->widgets = g_hash_table_new_full (g_str_hash, g_str_equal,
1013 g_free,
1014 on_widget_removed_from_hash);
1016 g_hash_table_insert (app->widgets, g_strdup (name), widget);
1017 g_object_ref (widget);
1019 /* Add the widget to dock */
1020 if (stock_id == NULL)
1021 item = gdl_dock_item_new (name, title, GDL_DOCK_ITEM_BEH_NORMAL);
1022 else
1023 item = gdl_dock_item_new_with_stock (name, title, stock_id,
1024 GDL_DOCK_ITEM_BEH_NORMAL);
1025 if (locked)
1027 guint flags = 0;
1028 flags |= GDL_DOCK_ITEM_BEH_NEVER_FLOATING;
1029 flags |= GDL_DOCK_ITEM_BEH_CANT_CLOSE;
1030 flags |= GDL_DOCK_ITEM_BEH_CANT_ICONIFY;
1031 flags |= GDL_DOCK_ITEM_BEH_NO_GRIP;
1032 g_object_set(G_OBJECT(item), "behavior", flags, NULL);
1035 gtk_container_add (GTK_CONTAINER (item), widget);
1036 gdl_dock_add_item (GDL_DOCK (app->dock),
1037 GDL_DOCK_ITEM (item), placement);
1038 gtk_widget_show_all (item);
1040 /* Add toggle button for the widget */
1041 menuitem = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_label (title));
1042 gtk_widget_show (GTK_WIDGET (menuitem));
1043 gtk_check_menu_item_set_active (menuitem, TRUE);
1044 gtk_menu_append (GTK_MENU (app->view_menu), GTK_WIDGET (menuitem));
1046 if (locked)
1047 g_object_set( G_OBJECT(menuitem), "visible", FALSE, NULL);
1050 g_object_set_data (G_OBJECT (widget), "app-object", app);
1051 g_object_set_data (G_OBJECT (widget), "menuitem", menuitem);
1052 g_object_set_data (G_OBJECT (widget), "dockitem", item);
1054 /* For toggling widget view on/off */
1055 g_signal_connect (G_OBJECT (menuitem), "toggled",
1056 G_CALLBACK (on_toggle_widget_view), item);
1059 Watch for widget removal/destruction so that it could be
1060 removed from widgets hash.
1062 g_signal_connect (G_OBJECT (item), "remove",
1063 G_CALLBACK (on_widget_remove), app);
1064 g_signal_connect_after (G_OBJECT (widget), "destroy",
1065 G_CALLBACK (on_widget_destroy), app);
1068 static void
1069 anjuta_app_remove_widget (AnjutaShell *shell, GtkWidget *widget,
1070 GError **error)
1072 AnjutaApp *app;
1073 GtkWidget *dock_item;
1075 g_return_if_fail (ANJUTA_IS_APP (shell));
1076 g_return_if_fail (GTK_IS_WIDGET (widget));
1078 app = ANJUTA_APP (shell);
1080 g_return_if_fail (app->widgets != NULL);
1082 dock_item = g_object_get_data (G_OBJECT (widget), "dockitem");
1083 g_return_if_fail (dock_item != NULL);
1085 /* Remove the widget from container */
1086 g_object_ref (widget);
1087 /* It should call on_widget_remove() and clean up should happen */
1088 gtk_container_remove (GTK_CONTAINER (dock_item), widget);
1089 g_object_unref (widget);
1092 static void
1093 anjuta_app_present_widget (AnjutaShell *shell, GtkWidget *widget,
1094 GError **error)
1096 AnjutaApp *app;
1097 GdlDockItem *dock_item;
1098 GtkWidget *parent;
1100 g_return_if_fail (ANJUTA_IS_APP (shell));
1101 g_return_if_fail (GTK_IS_WIDGET (widget));
1103 app = ANJUTA_APP (shell);
1105 g_return_if_fail (app->widgets != NULL);
1107 dock_item = g_object_get_data (G_OBJECT(widget), "dockitem");
1108 g_return_if_fail (dock_item != NULL);
1110 /* Hack to present the dock item if it's in a notebook dock item */
1111 parent = gtk_widget_get_parent (GTK_WIDGET(dock_item) );
1112 if (GTK_IS_NOTEBOOK (parent))
1114 gint pagenum;
1115 pagenum = gtk_notebook_page_num (GTK_NOTEBOOK (parent), GTK_WIDGET (dock_item));
1116 gtk_notebook_set_current_page (GTK_NOTEBOOK (parent), pagenum);
1118 else if (!GDL_DOCK_OBJECT_ATTACHED (dock_item))
1120 gdl_dock_item_show_item (GDL_DOCK_ITEM (dock_item));
1123 /* FIXME: If the item is floating, present the window */
1124 /* FIXME: There is no way to detect if a widget was floating before it was
1125 detached since it no longer has a parent there is no way to access the
1126 floating property of the GdlDock structure.*/
1129 static GObject*
1130 anjuta_app_get_object (AnjutaShell *shell, const char *iface_name,
1131 GError **error)
1133 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1134 g_return_val_if_fail (iface_name != NULL, NULL);
1135 return anjuta_plugin_manager_get_plugin (ANJUTA_APP (shell)->plugin_manager,
1136 iface_name);
1139 static AnjutaStatus*
1140 anjuta_app_get_status (AnjutaShell *shell, GError **error)
1142 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1143 return ANJUTA_APP (shell)->status;
1146 static AnjutaUI *
1147 anjuta_app_get_ui (AnjutaShell *shell, GError **error)
1149 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1150 return ANJUTA_APP (shell)->ui;
1153 static AnjutaPreferences *
1154 anjuta_app_get_preferences (AnjutaShell *shell, GError **error)
1156 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1157 return ANJUTA_APP (shell)->preferences;
1160 static AnjutaPluginManager *
1161 anjuta_app_get_plugin_manager (AnjutaShell *shell, GError **error)
1163 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1164 return ANJUTA_APP (shell)->plugin_manager;
1167 static AnjutaProfileManager *
1168 anjuta_app_get_profile_manager (AnjutaShell *shell, GError **error)
1170 g_return_val_if_fail (ANJUTA_IS_APP (shell), NULL);
1171 return ANJUTA_APP (shell)->profile_manager;
1174 static void
1175 anjuta_shell_iface_init (AnjutaShellIface *iface)
1177 iface->add_widget_full = anjuta_app_add_widget_full;
1178 iface->remove_widget = anjuta_app_remove_widget;
1179 iface->present_widget = anjuta_app_present_widget;
1180 iface->add_value = anjuta_app_add_value;
1181 iface->get_value = anjuta_app_get_value;
1182 iface->remove_value = anjuta_app_remove_value;
1183 iface->get_object = anjuta_app_get_object;
1184 iface->get_status = anjuta_app_get_status;
1185 iface->get_ui = anjuta_app_get_ui;
1186 iface->get_preferences = anjuta_app_get_preferences;
1187 iface->get_plugin_manager = anjuta_app_get_plugin_manager;
1188 iface->get_profile_manager = anjuta_app_get_profile_manager;
1191 ANJUTA_TYPE_BEGIN(AnjutaApp, anjuta_app, GNOME_TYPE_APP);
1192 ANJUTA_TYPE_ADD_INTERFACE(anjuta_shell, ANJUTA_TYPE_SHELL);
1193 ANJUTA_TYPE_END;