gedit-window.c 123 KB
Newer Older
Paolo Borelli's avatar
Paolo Borelli committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/*
 * gedit-window.c
 * This file is part of gedit
 *
 * Copyright (C) 2005 - Paolo Maggi 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA 02111-1307, USA.
 */
 
/*
 * Modified by the gedit Team, 2005. See the AUTHORS file for a 
 * list of people on the gedit Team.  
 * See the ChangeLog files for a list of changes. 
 *
 * $Id$
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <time.h>
#include <sys/types.h>
#include <string.h>

#include <glib/gi18n.h>
40
#include <gio/gio.h>
Paolo Borelli's avatar
Paolo Borelli committed
41 42 43 44 45 46 47 48 49 50

#include "gedit-ui.h"
#include "gedit-window.h"
#include "gedit-window-private.h"
#include "gedit-app.h"
#include "gedit-notebook.h"
#include "gedit-statusbar.h"
#include "gedit-utils.h"
#include "gedit-commands.h"
#include "gedit-debug.h"
51
#include "gedit-language-manager.h"
Paolo Borelli's avatar
Paolo Borelli committed
52 53 54 55
#include "gedit-prefs-manager-app.h"
#include "gedit-panel.h"
#include "gedit-documents-panel.h"
#include "gedit-plugins-engine.h"
56
#include "gedit-enum-types.h"
57
#include "gedit-dirs.h"
58
#include "gedit-status-combo-box.h"
Paolo Borelli's avatar
Paolo Borelli committed
59

60
#ifdef OS_OSX
61 62 63
#include "osx/gedit-osx.h"
#endif

64
#define LANGUAGE_NONE (const gchar *)"LangNone"
Paolo Borelli's avatar
:  
Paolo Borelli committed
65
#define GEDIT_UIFILE "gedit-ui.xml"
66 67
#define TAB_WIDTH_DATA "GeditWindowTabWidthData"
#define LANGUAGE_DATA "GeditWindowLanguageData"
68
#define FULLSCREEN_ANIMATION_SPEED 4
69

70 71 72
#define GEDIT_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object),\
					 GEDIT_TYPE_WINDOW,                    \
					 GeditWindowPrivate))
Paolo Borelli's avatar
Paolo Borelli committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

/* Signals */
enum
{
	TAB_ADDED,
	TAB_REMOVED,
	TABS_REORDERED,
	ACTIVE_TAB_CHANGED,
	ACTIVE_TAB_STATE_CHANGED,
	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

enum
{
	PROP_0,
	PROP_STATE
};

enum
{
	TARGET_URI_LIST = 100
};

G_DEFINE_TYPE(GeditWindow, gedit_window, GTK_TYPE_WINDOW)

100 101 102
static void	recent_manager_changed	(GtkRecentManager *manager,
					 GeditWindow *window);

Paolo Borelli's avatar
Paolo Borelli committed
103 104 105 106 107 108 109 110 111 112 113
static void
gedit_window_get_property (GObject    *object,
			   guint       prop_id,
			   GValue     *value,
			   GParamSpec *pspec)
{
	GeditWindow *window = GEDIT_WINDOW (object);

	switch (prop_id)
	{
		case PROP_STATE:
114 115
			g_value_set_enum (value,
					  gedit_window_get_state (window));
Paolo Borelli's avatar
Paolo Borelli committed
116 117 118 119 120 121 122
			break;			
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
			break;			
	}
}

123 124 125 126 127
static void
save_panes_state (GeditWindow *window)
{
	gint pane_page;

128 129
	gedit_debug (DEBUG_WINDOW);

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	if (gedit_prefs_manager_window_size_can_set ())
		gedit_prefs_manager_set_window_size (window->priv->width,
						     window->priv->height);

	if (gedit_prefs_manager_window_state_can_set ())
		gedit_prefs_manager_set_window_state (window->priv->window_state);

	if ((window->priv->side_panel_size > 0) &&
	    gedit_prefs_manager_side_panel_size_can_set ())
		gedit_prefs_manager_set_side_panel_size	(
					window->priv->side_panel_size);

	pane_page = _gedit_panel_get_active_item_id (GEDIT_PANEL (window->priv->side_panel));
	if (pane_page != 0 &&
	    gedit_prefs_manager_side_panel_active_page_can_set ())
		gedit_prefs_manager_set_side_panel_active_page (pane_page);

	if ((window->priv->bottom_panel_size > 0) && 
	    gedit_prefs_manager_bottom_panel_size_can_set ())
		gedit_prefs_manager_set_bottom_panel_size (
					window->priv->bottom_panel_size);

	pane_page = _gedit_panel_get_active_item_id (GEDIT_PANEL (window->priv->bottom_panel));
	if (pane_page != 0 &&
	    gedit_prefs_manager_bottom_panel_active_page_can_set ())
		gedit_prefs_manager_set_bottom_panel_active_page (pane_page);
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
#ifdef OS_OSX
static GtkMenuItem *
ui_manager_menu_item (GtkUIManager *uimanager,
                      const gchar  *path)
{
	return GTK_MENU_ITEM (gtk_ui_manager_get_widget (uimanager, path));
}

static void
add_mac_root_menu (GeditWindow *window)
{
	if (window->priv->mac_menu_group != NULL)
	{
		return;
	}
	
	window->priv->mac_menu_group = ige_mac_menu_add_app_menu_group ();

	ige_mac_menu_add_app_menu_item (window->priv->mac_menu_group,
	                                ui_manager_menu_item (window->priv->manager, "/ui/MenuBar/HelpMenu/HelpAboutMenu"),
	                                NULL);
}

static void
remove_mac_root_menu (GeditWindow *window)
{
	if (window->priv->mac_menu_group == NULL)
	{
		return;
	}
	
	ige_mac_menu_remove_app_menu_group (window->priv->mac_menu_group);
	window->priv->mac_menu_group = NULL;
}

static gboolean
gedit_window_focus_in_event (GtkWidget     *widget,
                             GdkEventFocus *event)
{
	add_mac_root_menu (GEDIT_WINDOW (widget));
	return GTK_WIDGET_CLASS (gedit_window_parent_class)->focus_in_event (widget, event);
}

static gboolean
gedit_window_focus_out_event (GtkWidget     *widget,
                              GdkEventFocus *event)
{
	remove_mac_root_menu (GEDIT_WINDOW (widget));
	return GTK_WIDGET_CLASS (gedit_window_parent_class)->focus_out_event (widget, event);
}
#endif

Paolo Borelli's avatar
Paolo Borelli committed
210
static void
211
gedit_window_dispose (GObject *object)
Paolo Borelli's avatar
Paolo Borelli committed
212
{
213
	GeditWindow *window;
Paolo Borelli's avatar
Paolo Borelli committed
214

215 216
	gedit_debug (DEBUG_WINDOW);

217
	window = GEDIT_WINDOW (object);
218

219 220 221 222 223 224 225 226 227 228
	/* Stop tracking removal of panes otherwise we always
	 * end up with thinking we had no pane active, since they
	 * should all be removed below */
	if (window->priv->bottom_panel_item_removed_handler_id != 0)
	{
		g_signal_handler_disconnect (window->priv->bottom_panel,
					     window->priv->bottom_panel_item_removed_handler_id);
		window->priv->bottom_panel_item_removed_handler_id = 0;
	}

229 230 231
	/* First of all, force collection so that plugins
	 * really drop some of the references.
	 */
232
	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
233

234 235
	/* save the panes position and make sure to deactivate plugins
	 * for this window, but only once */
236 237
	if (!window->priv->dispose_has_run)
	{
238 239
		save_panes_state (window);

240 241 242 243 244
		gedit_plugins_engine_deactivate_plugins (gedit_plugins_engine_get_default (),
					                  window);
		window->priv->dispose_has_run = TRUE;
	}

245 246 247 248 249 250
	if (window->priv->fullscreen_animation_timeout_id != 0)
	{
		g_source_remove (window->priv->fullscreen_animation_timeout_id);
		window->priv->fullscreen_animation_timeout_id = 0;
	}

251 252 253 254 255 256 257
	if (window->priv->fullscreen_controls != NULL)
	{
		gtk_widget_destroy (window->priv->fullscreen_controls);
		
		window->priv->fullscreen_controls = NULL;
	}

258
	if (window->priv->recents_handler_id != 0)
259
	{
260 261 262 263 264 265
		GtkRecentManager *recent_manager;

		recent_manager =  gtk_recent_manager_get_default ();
		g_signal_handler_disconnect (recent_manager,
					     window->priv->recents_handler_id);
		window->priv->recents_handler_id = 0;
266 267 268 269 270 271 272 273
	}

	if (window->priv->manager != NULL)
	{
		g_object_unref (window->priv->manager);
		window->priv->manager = NULL;
	}

274 275 276 277 278 279
	if (window->priv->message_bus != NULL)
	{
		g_object_unref (window->priv->message_bus);
		window->priv->message_bus = NULL;
	}

280 281 282 283 284
	if (window->priv->window_group != NULL)
	{
		g_object_unref (window->priv->window_group);
		window->priv->window_group = NULL;
	}
285
	
286 287 288
	/* Now that there have broken some reference loops,
	 * force collection again.
	 */
289
	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
290

291 292 293 294
#ifdef OS_OSX
	remove_mac_root_menu (window);
#endif

295 296
	G_OBJECT_CLASS (gedit_window_parent_class)->dispose (object);
}
297

298 299 300 301
static void
gedit_window_finalize (GObject *object)
{
	GeditWindow *window; 
Paolo Borelli's avatar
Paolo Borelli committed
302

303 304
	gedit_debug (DEBUG_WINDOW);

305
	window = GEDIT_WINDOW (object);
Paolo Borelli's avatar
Paolo Borelli committed
306

307 308
	if (window->priv->default_location != NULL)
		g_object_unref (window->priv->default_location);
Paolo Borelli's avatar
Paolo Borelli committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326

	G_OBJECT_CLASS (gedit_window_parent_class)->finalize (object);
}

static gboolean
gedit_window_window_state_event (GtkWidget           *widget,
				 GdkEventWindowState *event)
{
	GeditWindow *window = GEDIT_WINDOW (widget);

	window->priv->window_state = event->new_window_state;

	if (event->changed_mask &
	    (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))
	{
		gboolean show;

		show = !(event->new_window_state &
327
			(GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN));
Paolo Borelli's avatar
Paolo Borelli committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351

		_gedit_statusbar_set_has_resize_grip (GEDIT_STATUSBAR (window->priv->statusbar),
						      show);
	}

	return FALSE;
}

static gboolean 
gedit_window_configure_event (GtkWidget         *widget,
			      GdkEventConfigure *event)
{
	GeditWindow *window = GEDIT_WINDOW (widget);

	window->priv->width = event->width;
	window->priv->height = event->height;

	return GTK_WIDGET_CLASS (gedit_window_parent_class)->configure_event (widget, event);
}

/*
 * GtkWindow catches keybindings for the menu items _before_ passing them to
 * the focused widget. This is unfortunate and means that pressing ctrl+V
 * in an entry on a panel ends up pasting text in the TextView.
352 353 354
 * Here we override GtkWindow's handler to do the same things that it
 * does, but in the opposite order and then we chain up to the grand
 * parent handler, skipping gtk_window_key_press_event.
Paolo Borelli's avatar
Paolo Borelli committed
355 356 357 358 359
 */
static gboolean
gedit_window_key_press_event (GtkWidget   *widget,
			      GdkEventKey *event)
{
360 361
	static gpointer grand_parent_class = NULL;
	GtkWindow *window = GTK_WINDOW (widget);
Paolo Borelli's avatar
Paolo Borelli committed
362 363
	gboolean handled = FALSE;

364 365
	if (grand_parent_class == NULL)
		grand_parent_class = g_type_class_peek_parent (gedit_window_parent_class);
Paolo Borelli's avatar
Paolo Borelli committed
366

367 368 369 370 371 372 373 374 375 376 377
	/* handle focus widget key events */
	if (!handled)
		handled = gtk_window_propagate_key_event (window, event);

	/* handle mnemonics and accelerators */
	if (!handled)
		handled = gtk_window_activate_key (window, event);

	/* Chain up, invokes binding set */
	if (!handled)
		handled = GTK_WIDGET_CLASS (grand_parent_class)->key_press_event (widget, event);
Paolo Borelli's avatar
Paolo Borelli committed
378

379
	return handled;
Paolo Borelli's avatar
Paolo Borelli committed
380 381
}

382
static void
383 384
gedit_window_tab_removed (GeditWindow *window,
			  GeditTab    *tab) 
385
{
386
	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
387 388
}

Paolo Borelli's avatar
Paolo Borelli committed
389 390 391 392 393 394
static void
gedit_window_class_init (GeditWindowClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

395 396
	klass->tab_removed = gedit_window_tab_removed;

397
	object_class->dispose = gedit_window_dispose;
Paolo Borelli's avatar
Paolo Borelli committed
398 399 400 401 402 403 404
	object_class->finalize = gedit_window_finalize;
	object_class->get_property = gedit_window_get_property;

	widget_class->window_state_event = gedit_window_window_state_event;
	widget_class->configure_event = gedit_window_configure_event;
	widget_class->key_press_event = gedit_window_key_press_event;

405 406 407 408 409
#ifdef OS_OSX
	widget_class->focus_in_event = gedit_window_focus_in_event;
	widget_class->focus_out_event = gedit_window_focus_out_event;
#endif

Paolo Borelli's avatar
Paolo Borelli committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
	signals[TAB_ADDED] =
		g_signal_new ("tab_added",
			      G_OBJECT_CLASS_TYPE (object_class),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GeditWindowClass, tab_added),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__OBJECT,
			      G_TYPE_NONE,
			      1,
			      GEDIT_TYPE_TAB);
	signals[TAB_REMOVED] =
		g_signal_new ("tab_removed",
			      G_OBJECT_CLASS_TYPE (object_class),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GeditWindowClass, tab_removed),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__OBJECT,
			      G_TYPE_NONE,
			      1,
			      GEDIT_TYPE_TAB);
	signals[TABS_REORDERED] =
		g_signal_new ("tabs_reordered",
			      G_OBJECT_CLASS_TYPE (object_class),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GeditWindowClass, tabs_reordered),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__VOID,
			      G_TYPE_NONE,
			      0);
	signals[ACTIVE_TAB_CHANGED] =
		g_signal_new ("active_tab_changed",
			      G_OBJECT_CLASS_TYPE (object_class),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GeditWindowClass, active_tab_changed),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__OBJECT,
			      G_TYPE_NONE,
			      1,
			      GEDIT_TYPE_TAB);
	signals[ACTIVE_TAB_STATE_CHANGED] =
		g_signal_new ("active_tab_state_changed",
			      G_OBJECT_CLASS_TYPE (object_class),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GeditWindowClass, active_tab_state_changed),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__VOID,
			      G_TYPE_NONE,
			      0);			      			      

	g_object_class_install_property (object_class,
					 PROP_STATE,
461 462 463 464 465
					 g_param_spec_flags ("state",
							     "State",
							     "The window's state",
							     GEDIT_TYPE_WINDOW_STATE,
							     GEDIT_WINDOW_STATE_NORMAL,
466 467 468
							     G_PARAM_READABLE |
							     G_PARAM_STATIC_STRINGS));

Paolo Borelli's avatar
Paolo Borelli committed
469 470 471 472 473
	g_type_class_add_private (object_class, sizeof(GeditWindowPrivate));
}

static void
menu_item_select_cb (GtkMenuItem *proxy,
474
		     GeditWindow *window)
Paolo Borelli's avatar
Paolo Borelli committed
475 476 477 478
{
	GtkAction *action;
	char *message;

479
	action = gtk_widget_get_action (GTK_WIDGET (proxy));
Paolo Borelli's avatar
Paolo Borelli committed
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
	g_return_if_fail (action != NULL);

	g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
	if (message)
	{
		gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
				    window->priv->tip_message_cid, message);
		g_free (message);
	}
}

static void
menu_item_deselect_cb (GtkMenuItem *proxy,
                       GeditWindow *window)
{
	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
			   window->priv->tip_message_cid);
}

static void
connect_proxy_cb (GtkUIManager *manager,
                  GtkAction *action,
                  GtkWidget *proxy,
                  GeditWindow *window)
{
	if (GTK_IS_MENU_ITEM (proxy))
	{
		g_signal_connect (proxy, "select",
				  G_CALLBACK (menu_item_select_cb), window);
		g_signal_connect (proxy, "deselect",
				  G_CALLBACK (menu_item_deselect_cb), window);
	}
}

static void
disconnect_proxy_cb (GtkUIManager *manager,
                     GtkAction *action,
                     GtkWidget *proxy,
                     GeditWindow *window)
{
	if (GTK_IS_MENU_ITEM (proxy))
	{
		g_signal_handlers_disconnect_by_func
			(proxy, G_CALLBACK (menu_item_select_cb), window);
		g_signal_handlers_disconnect_by_func
			(proxy, G_CALLBACK (menu_item_deselect_cb), window);
	}
}

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
static void
apply_toolbar_style (GeditWindow *window,
		     GtkWidget *toolbar)
{
	switch (window->priv->toolbar_style)
	{
		case GEDIT_TOOLBAR_SYSTEM:
			gedit_debug_message (DEBUG_WINDOW, "GEDIT: SYSTEM");
			gtk_toolbar_unset_style (
					GTK_TOOLBAR (toolbar));
			break;

		case GEDIT_TOOLBAR_ICONS:
			gedit_debug_message (DEBUG_WINDOW, "GEDIT: ICONS");
			gtk_toolbar_set_style (
					GTK_TOOLBAR (toolbar),
					GTK_TOOLBAR_ICONS);
			break;

		case GEDIT_TOOLBAR_ICONS_AND_TEXT:
			gedit_debug_message (DEBUG_WINDOW, "GEDIT: ICONS_AND_TEXT");
			gtk_toolbar_set_style (
					GTK_TOOLBAR (toolbar),
					GTK_TOOLBAR_BOTH);
			break;

		case GEDIT_TOOLBAR_ICONS_BOTH_HORIZ:
			gedit_debug_message (DEBUG_WINDOW, "GEDIT: ICONS_BOTH_HORIZ");
			gtk_toolbar_set_style (
					GTK_TOOLBAR (toolbar),
					GTK_TOOLBAR_BOTH_HORIZ);
			break;
	}
}

Paolo Borelli's avatar
Paolo Borelli committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
/* Returns TRUE if toolbar is visible */
static gboolean
set_toolbar_style (GeditWindow *window,
		   GeditWindow *origin)
{
	gboolean visible;
	GeditToolbarSetting style;
	GtkAction *action;
	
	if (origin == NULL)
		visible = gedit_prefs_manager_get_toolbar_visible ();
	else
		visible = GTK_WIDGET_VISIBLE (origin->priv->toolbar);
	
	/* Set visibility */
	if (visible)
		gtk_widget_show (window->priv->toolbar);
	else
		gtk_widget_hide (window->priv->toolbar);
583 584

	action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
Paolo Borelli's avatar
Paolo Borelli committed
585
					      "ViewToolbar");
586

Paolo Borelli's avatar
Paolo Borelli committed
587 588
	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
589

Paolo Borelli's avatar
Paolo Borelli committed
590 591 592 593 594
	/* Set style */
	if (origin == NULL)
		style = gedit_prefs_manager_get_toolbar_buttons_style ();
	else
		style = origin->priv->toolbar_style;
595
	
Paolo Borelli's avatar
Paolo Borelli committed
596
	window->priv->toolbar_style = style;
597 598
	
	apply_toolbar_style (window, window->priv->toolbar);
Paolo Borelli's avatar
Paolo Borelli committed
599 600 601 602
	
	return visible;
}

603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
static void
update_next_prev_doc_sensitivity (GeditWindow *window,
				  GeditTab    *tab)
{
	gint	     tab_number;
	GtkNotebook *notebook;
	GtkAction   *action;
	
	gedit_debug (DEBUG_WINDOW);
	
	notebook = GTK_NOTEBOOK (_gedit_window_get_notebook (window));
	
	tab_number = gtk_notebook_page_num (notebook, GTK_WIDGET (tab));
	g_return_if_fail (tab_number >= 0);
	
	action = gtk_action_group_get_action (window->priv->action_group,
					      "DocumentsPreviousDocument");
	gtk_action_set_sensitive (action, tab_number != 0);
	
	action = gtk_action_group_get_action (window->priv->action_group,
					      "DocumentsNextDocument");
	gtk_action_set_sensitive (action, 
				  tab_number < gtk_notebook_get_n_pages (notebook) - 1);
}

static void
update_next_prev_doc_sensitivity_per_window (GeditWindow *window)
{
	GeditTab  *tab;
	GtkAction *action;
	
	gedit_debug (DEBUG_WINDOW);
	
	tab = gedit_window_get_active_tab (window);
	if (tab != NULL)
	{
		update_next_prev_doc_sensitivity (window, tab);
		
		return;
	}
	
	action = gtk_action_group_get_action (window->priv->action_group,
					      "DocumentsPreviousDocument");
	gtk_action_set_sensitive (action, FALSE);
	
	action = gtk_action_group_get_action (window->priv->action_group,
					      "DocumentsNextDocument");
	gtk_action_set_sensitive (action, FALSE);
	
}

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
static void
received_clipboard_contents (GtkClipboard     *clipboard,
			     GtkSelectionData *selection_data,
			     GeditWindow      *window)
{
	gboolean sens;
	GtkAction *action;

	/* getting clipboard contents is async, so we need to
	 * get the current tab and its state */

	if (window->priv->active_tab != NULL)
	{
		GeditTabState state;
		gboolean state_normal;

		state = gedit_tab_get_state (window->priv->active_tab);
		state_normal = (state == GEDIT_TAB_STATE_NORMAL);

		sens = state_normal &&
		       gtk_selection_data_targets_include_text (selection_data);
	}
	else
	{
		sens = FALSE;
	}

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditPaste");

	gtk_action_set_sensitive (action, sens);

	g_object_unref (window);
}

static void
set_paste_sensitivity_according_to_clipboard (GeditWindow  *window,
					      GtkClipboard *clipboard)
{
	GdkDisplay *display;

	display = gtk_clipboard_get_display (clipboard);

	if (gdk_display_supports_selection_notification (display))
	{
		gtk_clipboard_request_contents (clipboard,
700
						gdk_atom_intern_static_string ("TARGETS"),
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
						(GtkClipboardReceivedFunc) received_clipboard_contents,
						g_object_ref (window));
	}
	else
	{
		GtkAction *action;

		action = gtk_action_group_get_action (window->priv->action_group,
						      "EditPaste");

		/* XFIXES extension not availbale, make
		 * Paste always sensitive */
		gtk_action_set_sensitive (action, TRUE);
	}
}

Paolo Borelli's avatar
Paolo Borelli committed
717 718 719 720 721 722 723 724 725
static void
set_sensitivity_according_to_tab (GeditWindow *window,
				  GeditTab    *tab)
{
	GeditDocument *doc;
	GeditView     *view;
	GtkAction     *action;
	gboolean       b;
	gboolean       state_normal;
726
	gboolean       editable;
Paolo Borelli's avatar
Paolo Borelli committed
727
	GeditTabState  state;
728
	GtkClipboard  *clipboard;
729
	GeditLockdownMask lockdown;
Paolo Borelli's avatar
Paolo Borelli committed
730 731 732 733 734

	g_return_if_fail (GEDIT_TAB (tab));

	gedit_debug (DEBUG_WINDOW);

735 736
	lockdown = gedit_app_get_lockdown (gedit_app_get_default ());

Paolo Borelli's avatar
Paolo Borelli committed
737 738 739 740
	state = gedit_tab_get_state (tab);
	state_normal = (state == GEDIT_TAB_STATE_NORMAL);

	view = gedit_tab_get_view (tab);
741 742
	editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));

Paolo Borelli's avatar
Paolo Borelli committed
743
	doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
744

745 746 747
	clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
					      GDK_SELECTION_CLIPBOARD);

Paolo Borelli's avatar
Paolo Borelli committed
748 749 750 751
	action = gtk_action_group_get_action (window->priv->action_group,
					      "FileSave");
	gtk_action_set_sensitive (action,
				  (state_normal ||
752
				   (state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
Paolo Borelli's avatar
Paolo Borelli committed
753
				   (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
754 755
				  !gedit_document_get_readonly (doc) &&
				  !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
Paolo Borelli's avatar
Paolo Borelli committed
756 757 758 759

	action = gtk_action_group_get_action (window->priv->action_group,
					      "FileSaveAs");
	gtk_action_set_sensitive (action,
760
				  (state_normal ||
761
				   (state == GEDIT_TAB_STATE_SAVING_ERROR) ||
762 763
				   (state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
				   (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
764
				  !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
765

Paolo Borelli's avatar
Paolo Borelli committed
766 767
	action = gtk_action_group_get_action (window->priv->action_group,
					      "FileRevert");
768 769 770 771
	gtk_action_set_sensitive (action,
				  (state_normal ||
				   (state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)) &&
				  !gedit_document_is_untitled (doc));
Paolo Borelli's avatar
Paolo Borelli committed
772 773 774 775

	action = gtk_action_group_get_action (window->priv->action_group,
					      "FilePrintPreview");
	gtk_action_set_sensitive (action,
776 777
				  state_normal &&
				  !(lockdown & GEDIT_LOCKDOWN_PRINTING));
Paolo Borelli's avatar
Paolo Borelli committed
778 779 780 781

	action = gtk_action_group_get_action (window->priv->action_group,
					      "FilePrint");
	gtk_action_set_sensitive (action,
782 783 784
				  (state_normal ||
				  (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
				  !(lockdown & GEDIT_LOCKDOWN_PRINTING));
Paolo Borelli's avatar
Paolo Borelli committed
785
				  
786
	action = gtk_action_group_get_action (window->priv->close_action_group,
Paolo Borelli's avatar
Paolo Borelli committed
787 788 789
					      "FileClose");

	gtk_action_set_sensitive (action,
790
				  (state != GEDIT_TAB_STATE_CLOSING) &&
Paolo Borelli's avatar
Paolo Borelli committed
791 792
				  (state != GEDIT_TAB_STATE_SAVING) &&
				  (state != GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW) &&
Paolo Borelli's avatar
Paolo Borelli committed
793 794
				  (state != GEDIT_TAB_STATE_PRINTING) &&
				  (state != GEDIT_TAB_STATE_PRINT_PREVIEWING) &&
Paolo Borelli's avatar
Paolo Borelli committed
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
				  (state != GEDIT_TAB_STATE_SAVING_ERROR));

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditUndo");
	gtk_action_set_sensitive (action, 
				  state_normal &&
				  gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (doc)));

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditRedo");
	gtk_action_set_sensitive (action, 
				  state_normal &&
				  gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (doc)));

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditCut");
	gtk_action_set_sensitive (action,
				  state_normal &&
813
				  editable &&
814
				  gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
Paolo Borelli's avatar
Paolo Borelli committed
815 816 817 818

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditCopy");
	gtk_action_set_sensitive (action,
819 820
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) &&
821
				  gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
Paolo Borelli's avatar
Paolo Borelli committed
822 823 824
				  
	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditPaste");
825
	if (state_normal && editable)
826 827 828 829 830 831 832 833
	{
		set_paste_sensitivity_according_to_clipboard (window,
							      clipboard);
	}
	else
	{
		gtk_action_set_sensitive (action, FALSE);
	}
Paolo Borelli's avatar
Paolo Borelli committed
834 835 836 837 838

	action = gtk_action_group_get_action (window->priv->action_group,
					      "EditDelete");
	gtk_action_set_sensitive (action,
				  state_normal &&
839
				  editable &&
840
				  gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
Paolo Borelli's avatar
Paolo Borelli committed
841 842 843 844

	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchFind");
	gtk_action_set_sensitive (action,
845 846
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
Paolo Borelli's avatar
Paolo Borelli committed
847

Paolo Maggi's avatar
Paolo Maggi committed
848
	action = gtk_action_group_get_action (window->priv->action_group,
Paolo Borelli's avatar
Paolo Borelli committed
849
					      "SearchIncrementalSearch");
Paolo Maggi's avatar
Paolo Maggi committed
850
	gtk_action_set_sensitive (action,
851 852
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
Paolo Maggi's avatar
Paolo Maggi committed
853

Paolo Borelli's avatar
Paolo Borelli committed
854 855 856
	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchReplace");
	gtk_action_set_sensitive (action,
857 858
				  state_normal &&
				  editable);
Paolo Borelli's avatar
Paolo Borelli committed
859 860 861 862

	b = gedit_document_get_can_search_again (doc);
	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchFindNext");
863 864 865
	gtk_action_set_sensitive (action,
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
Paolo Borelli's avatar
Paolo Borelli committed
866 867 868

	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchFindPrevious");
869 870 871
	gtk_action_set_sensitive (action,
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
Paolo Borelli's avatar
Paolo Borelli committed
872

873 874
	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchClearHighlight");
875 876 877
	gtk_action_set_sensitive (action,
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
878

Paolo Borelli's avatar
Paolo Borelli committed
879 880
	action = gtk_action_group_get_action (window->priv->action_group,
					      "SearchGoToLine");
881 882 883
	gtk_action_set_sensitive (action,
				  (state_normal ||
				   state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
Paolo Borelli's avatar
Paolo Borelli committed
884 885 886 887 888 889 890
	
	action = gtk_action_group_get_action (window->priv->action_group,
					      "ViewHighlightMode");
	gtk_action_set_sensitive (action, 
				  (state != GEDIT_TAB_STATE_CLOSING) &&
				  gedit_prefs_manager_get_enable_syntax_highlighting ());

891
	update_next_prev_doc_sensitivity (window, tab);
892

893
	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
894
						 window);
Paolo Borelli's avatar
Paolo Borelli committed
895 896 897 898 899 900 901
}

static void
language_toggled (GtkToggleAction *action,
		  GeditWindow     *window)
{
	GeditDocument *doc;
902 903
	GtkSourceLanguage *lang;
	const gchar *lang_id;
Paolo Borelli's avatar
Paolo Borelli committed
904 905 906 907 908 909 910 911

	if (gtk_toggle_action_get_active (action) == FALSE)
		return;

	doc = gedit_window_get_active_document (window);
	if (doc == NULL)
		return;

912 913 914
	lang_id = gtk_action_get_name (GTK_ACTION (action));
	
	if (strcmp (lang_id, LANGUAGE_NONE) == 0)
Paolo Borelli's avatar
Paolo Borelli committed
915 916 917 918 919 920
	{
		/* Normal (no highlighting) */
		lang = NULL;
	}
	else
	{
921
		lang = gtk_source_language_manager_get_language (
922 923 924 925 926 927
				gedit_get_language_manager (),
				lang_id);
		if (lang == NULL)
		{
			g_warning ("Could not get language %s\n", lang_id);
		}
Paolo Borelli's avatar
Paolo Borelli committed
928 929
	}

930
	gedit_document_set_language (doc, lang);
Paolo Borelli's avatar
Paolo Borelli committed
931 932
}

933
static gchar *
934
escape_section_name (const gchar *name)
935 936 937
{
	gchar *ret;

938
	ret = g_markup_escape_text (name, -1);
939

940 941
	/* Replace '/' with '-' to avoid problems in xml paths */
	g_strdelimit (ret, "/", '-');
942 943 944 945

	return ret;
}

Paolo Borelli's avatar
Paolo Borelli committed
946 947 948 949 950 951 952 953 954 955
static void
create_language_menu_item (GtkSourceLanguage *lang,
			   gint               index,
			   guint              ui_id,
			   GeditWindow       *window)
{
	GtkAction *section_action;
	GtkRadioAction *action;
	GtkAction *normal_action;
	GSList *group;
956
	const gchar *section;
957
	gchar *escaped_section;
958
	const gchar *lang_id;
959
	const gchar *lang_name;
960
	gchar *escaped_lang_name;
Paolo Borelli's avatar
Paolo Borelli committed
961 962 963 964
	gchar *tip;
	gchar *path;

	section = gtk_source_language_get_section (lang);
965
	escaped_section = escape_section_name (section);
Paolo Borelli's avatar
Paolo Borelli committed
966 967 968

	/* check if the section submenu exists or create it */
	section_action = gtk_action_group_get_action (window->priv->languages_action_group,
969
						      escaped_section);
Paolo Borelli's avatar
Paolo Borelli committed
970 971 972

	if (section_action == NULL)
	{
973 974 975 976
		gchar *section_name;
		
		section_name = gedit_utils_escape_underscores (section, -1);
		
977
		section_action = gtk_action_new (escaped_section,
978
						 section_name,
Paolo Borelli's avatar
Paolo Borelli committed
979 980
						 NULL,
						 NULL);
981 982
						 
		g_free (section_name);
Paolo Borelli's avatar
Paolo Borelli committed
983 984 985 986 987 988 989 990

		gtk_action_group_add_action (window->priv->languages_action_group,
					     section_action);
		g_object_unref (section_action);

		gtk_ui_manager_add_ui (window->priv->manager,
				       ui_id,
				       "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
991 992
				       escaped_section,
				       escaped_section,
Paolo Borelli's avatar
Paolo Borelli committed
993 994 995 996 997 998
				       GTK_UI_MANAGER_MENU,
				       FALSE);
	}

	/* now add the language item to the section */
	lang_name = gtk_source_language_get_name (lang);
999 1000 1001 1002
	lang_id = gtk_source_language_get_id (lang);
	
	escaped_lang_name = gedit_utils_escape_underscores (lang_name, -1);
	
Paolo Borelli's avatar
Paolo Borelli committed
1003 1004
	tip = g_strdup_printf (_("Use %s highlight mode"), lang_name);
	path = g_strdup_printf ("/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder/%s",
1005
				escaped_section);
Paolo Borelli's avatar
Paolo Borelli committed
1006

1007 1008
	action = gtk_radio_action_new (lang_id,
				       escaped_lang_name,
Paolo Borelli's avatar
Paolo Borelli committed
1009 1010 1011 1012
				       tip,
				       NULL,
				       index);

1013
	g_free (escaped_lang_name);
1014

1015 1016 1017 1018
	/* Action is added with a NULL accel to make the accel overridable */
	gtk_action_group_add_action_with_accel (window->priv->languages_action_group,
						GTK_ACTION (action),
						NULL);
Paolo Borelli's avatar
Paolo Borelli committed
1019 1020 1021 1022
	g_object_unref (action);

	/* add the action to the same radio group of the "Normal" action */
	normal_action = gtk_action_group_get_action (window->priv->languages_action_group,
1023
						     LANGUAGE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
	group = gtk_radio_action_get_group (GTK_RADIO_ACTION (normal_action));
	gtk_radio_action_set_group (action, group);

	g_signal_connect (action,
			  "activate",
			  G_CALLBACK (language_toggled),
			  window);

	gtk_ui_manager_add_ui (window->priv->manager,
			       ui_id,
			       path,
1035 1036
			       lang_id, 
			       lang_id,
Paolo Borelli's avatar
Paolo Borelli committed
1037 1038 1039 1040 1041
			       GTK_UI_MANAGER_MENUITEM,
			       FALSE);

	g_free (path);
	g_free (tip);
1042
	g_free (escaped_section);
Paolo Borelli's avatar
Paolo Borelli committed
1043 1044 1045 1046 1047
}

static void
create_languages_menu (GeditWindow *window)
{
1048
	GtkRadioAction *action_none;
1049 1050
	GSList *languages;
	GSList *l;
Paolo Borelli's avatar
Paolo Borelli committed
1051 1052 1053 1054 1055
	guint id;
	gint i;

	gedit_debug (DEBUG_WINDOW);

1056
	/* add the "Plain Text" item before all the others */
1057
	
1058
	/* Translators: "Plain Text" means that no highlight mode is selected in the 
1059
	 * "View->Highlight Mode" submenu and so syntax highlighting is disabled */
1060
	action_none = gtk_radio_action_new (LANGUAGE_NONE, _("Plain Text"),
1061 1062 1063
					    _("Disable syntax highlighting"),
					    NULL,
					    -1);
Paolo Borelli's avatar
Paolo Borelli committed
1064 1065

	gtk_action_group_add_action (window->priv->languages_action_group,
1066 1067
				     GTK_ACTION (action_none));
	g_object_unref (action_none);
Paolo Borelli's avatar
Paolo Borelli committed
1068

1069
	g_signal_connect (action_none,
Paolo Borelli's avatar
Paolo Borelli committed
1070 1071 1072 1073 1074 1075 1076 1077 1078
			  "activate",
			  G_CALLBACK (language_toggled),
			  window);

	id = gtk_ui_manager_new_merge_id (window->priv->manager);

	gtk_ui_manager_add_ui (window->priv->manager,
			       id,
			       "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
1079 1080
			       LANGUAGE_NONE, 
			       LANGUAGE_NONE,
Paolo Borelli's avatar
Paolo Borelli committed
1081 1082 1083
			       GTK_UI_MANAGER_MENUITEM,
			       TRUE);

1084
	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action_none), TRUE);
Paolo Borelli's avatar
Paolo Borelli committed
1085 1086

	/* now add all the known languages */
1087
	languages = gedit_language_manager_list_languages_sorted (
1088 1089
						gedit_get_language_manager (),
						FALSE);
Paolo Borelli's avatar
Paolo Borelli committed
1090 1091

	for (l = languages, i = 0; l != NULL; l = l->next, ++i)
1092
	{
1093
		create_language_menu_item (l->data,
1094 1095 1096 1097 1098 1099
					   i,
					   id,
					   window);
	}

	g_slist_free (languages);
Paolo Borelli's avatar
Paolo Borelli committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
}

static void
update_languages_menu (GeditWindow *window)
{
	GeditDocument *doc;
	GList *actions;
	GList *l;
	GtkAction *action;
	GtkSourceLanguage *lang;
1110
	const gchar *lang_id;
Paolo Borelli's avatar
Paolo Borelli committed
1111 1112 1113 1114 1115 1116 1117

	doc = gedit_window_get_active_document (window);
	if (doc == NULL)
		return;

	lang = gedit_document_get_language (doc);
	if (lang != NULL)
1118
		lang_id = gtk_source_language_get_id (lang);
Paolo Borelli's avatar
Paolo Borelli committed
1119
	else
1120
		lang_id = LANGUAGE_NONE;
1121

Paolo Borelli's avatar
Paolo Borelli committed
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
	actions = gtk_action_group_list_actions (window->priv->languages_action_group);

	/* prevent recursion */
	for (l = actions; l != NULL; l = l->next)
	{
		g_signal_handlers_block_by_func (GTK_ACTION (l->data),
						 G_CALLBACK (language_toggled),
						 window);
	}

	action = gtk_action_group_get_action (window->priv->languages_action_group,
1133
					      lang_id);
Paolo Borelli's avatar
Paolo Borelli committed
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146

	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);

	for (l = actions; l != NULL; l = l->next)
	{
		g_signal_handlers_unblock_by_func (GTK_ACTION (l->data),
						   G_CALLBACK (language_toggled),
						   window);
	}

	g_list_free (actions);
}

1147 1148 1149 1150
void
_gedit_recent_add (GeditWindow *window,
		   const gchar *uri,
		   const gchar *mime)
Paolo Borelli's avatar
Paolo Borelli committed
1151
{
1152
	GtkRecentManager *recent_manager;
1153
	GtkRecentData *recent_data;
Paolo Borelli's avatar
Paolo Borelli committed
1154

1155 1156 1157 1158 1159
	static gchar *groups[2] = {
		"gedit",
		NULL
	};

1160 1161
	recent_manager =  gtk_recent_manager_get_default ();

1162
	recent_data = g_slice_new (GtkRecentData);
Paolo Borelli's avatar
Paolo Borelli committed
1163

1164 1165 1166 1167 1168 1169 1170
	recent_data->display_name = NULL;
	recent_data->description = NULL;
	recent_data->mime_type = (gchar *) mime;
	recent_data->app_name = (gchar *) g_get_application_name ();
	recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
	recent_data->groups = groups;
	recent_data->is_private = FALSE;
Paolo Borelli's avatar
Paolo Borelli committed
1171

1172
	gtk_recent_manager_add_full (recent_manager,
1173 1174 1175 1176 1177 1178
				     uri,
				     recent_data);

	g_free (recent_data->app_exec);

	g_slice_free (GtkRecentData, recent_data);
Paolo Borelli's avatar
Paolo Borelli committed
1179 1180
}

1181 1182 1183 1184
void
_gedit_recent_remove (GeditWindow *window,
		      const gchar *uri)
{
1185 1186 1187 1188 1189
	GtkRecentManager *recent_manager;

	recent_manager =  gtk_recent_manager_get_default ();

	gtk_recent_manager_remove_item (recent_manager, uri, NULL);
1190
}
Paolo Borelli's avatar
Paolo Borelli committed
1191 1192

static void
1193 1194
open_recent_file (const gchar *uri,
		  GeditWindow *window)
Paolo Borelli's avatar
Paolo Borelli committed
1195
{
1196 1197 1198
	GSList *uris = NULL;

	uris = g_slist_prepend (uris, (gpointer) uri);
Paolo Borelli's avatar
Paolo Borelli committed
1199

1200 1201 1202 1203
	if (gedit_commands_load_uris (window, uris, NULL, 0) != 1)
	{
		_gedit_recent_remove (window, uri);
	}
Paolo Borelli's avatar
Paolo Borelli committed
1204

1205 1206
	g_slist_free (uris);
}
Paolo Borelli's avatar
Paolo Borelli committed
1207

1208 1209 1210 1211 1212
static void
recent_chooser_item_activated (GtkRecentChooser *chooser,
			       GeditWindow      *window)
{
	gchar *uri;
Paolo Borelli's avatar
Paolo Borelli committed
1213

1214
	uri = gtk_recent_chooser_get_current_uri (chooser);
Paolo Borelli's avatar
Paolo Borelli committed
1215

1216
	open_recent_file (uri, window);
Paolo Borelli's avatar
Paolo Borelli committed
1217

1218
	g_free (uri);
Paolo Borelli's avatar
Paolo Borelli committed
1219 1220
}

1221 1222 1223
static void
recents_menu_activate (GtkAction   *action,
		       GeditWindow *window)
Paolo Borelli's avatar
Paolo Borelli committed
1224
{
1225 1226
	GtkRecentInfo *info;
	const gchar *uri;
Paolo Borelli's avatar
Paolo Borelli committed
1227

1228 1229
	info = g_object_get_data (G_OBJECT (action), "gtk-recent-info");
	g_return_if_fail (info != NULL);
Paolo Borelli's avatar
Paolo Borelli committed
1230

1231
	uri = gtk_recent_info_get_uri (info);
Paolo Borelli's avatar
Paolo Borelli committed
1232

1233 1234 1235 1236 1237 1238
	open_recent_file (uri, window);
}

static gint
sort_recents_mru (GtkRecentInfo *a, GtkRecentInfo *b)
{
1239
	return (gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a));
1240
}
Paolo Borelli's avatar
Paolo Borelli committed
1241

1242
static void	update_recent_files_menu (GeditWindow *window);
Paolo Borelli's avatar
Paolo Borelli committed
1243

1244 1245 1246 1247 1248 1249
static void
recent_manager_changed (GtkRecentManager *manager,
			GeditWindow      *window)
{
	/* regenerate the menu when the model changes */
	update_recent_files_menu (window);
Paolo Borelli's avatar
Paolo Borelli committed
1250 1251
}

1252 1253 1254 1255
/*
 * Manually construct the inline recents list in the File menu.
 * Hopefully gtk 2.12 will add support for it.
 */
Paolo Borelli's avatar
Paolo Borelli committed
1256
static void
1257
update_recent_files_menu (GeditWindow *window)
Paolo Borelli's avatar
Paolo Borelli committed
1258
{
1259
	GeditWindowPrivate *p = window->priv;
1260
	GtkRecentManager *recent_manager;
1261 1262
	gint max_recents;
	GList *actions, *l, *items;
1263
	GList *filtered_items = NULL;
1264
	gint i;
Paolo Borelli's avatar
Paolo Borelli committed
1265

1266
	gedit_debug (DEBUG_WINDOW);
Paolo Borelli's avatar
Paolo Borelli committed
1267

1268
	max_recents = gedit_prefs_manager_get_max_recents ();
Paolo Borelli's avatar
Paolo Borelli committed
1269

1270
	g_return_if_fail (p->recents_action_group != NULL);
Paolo Borelli's avatar
Paolo Borelli committed
1271

1272 1273 1274
	if (p->recents_menu_ui_id != 0)
		gtk_ui_manager_remove_ui (p->manager,
					  p->recents_menu_ui_id);
Paolo Borelli's avatar
Paolo Borelli committed
1275

1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
	actions = gtk_action_group_list_actions (p->recents_action_group);
	for (l = actions; l != NULL; l = l->next)
	{
		g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
						      G_CALLBACK (recents_menu_activate),
						      window);
 		gtk_action_group_remove_action (p->recents_action_group,
						GTK_ACTION (l->data));
	}
	g_list_free (actions);
Paolo Borelli's avatar
Paolo Borelli committed
1286

1287
	p->recents_menu_ui_id = gtk_ui_manager_new_merge_id (p->manager);
Paolo Borelli's avatar
Paolo Borelli committed
1288

1289 1290
	recent_manager =  gtk_recent_manager_get_default ();
	items = gtk_recent_manager_get_items (recent_manager);
Paolo Borelli's avatar
Paolo Borelli committed
1291

1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
	/* filter */
	for (l = items; l != NULL; l = l->next)
	{
		GtkRecentInfo *info = l->data;

		if (!gtk_recent_info_has_group (info, "gedit"))
			continue;

		filtered_items = g_list_prepend (filtered_items, info);
	}

	/* sort */
	filtered_items = g_list_sort (filtered_items,
				      (GCompareFunc) sort_recents_mru);
1306 1307

	i = 0;
1308
	for (l = filtered_items; l != NULL; l = l->next)
1309 1310 1311 1312 1313 1314
	{
		gchar *action_name;
		const gchar *display_name;
		gchar *escaped;
		gchar *label;
		gchar *uri;
1315
		gchar *ruri;
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
		gchar *tip;
		GtkAction *action;
		GtkRecentInfo *info = l->data;

		/* clamp */
		if (i >= max_recents)
			break;

		i++;

		action_name = g_strdup_printf ("recent-info-%d", i);

		display_name = gtk_recent_info_get_display_name (info);
		escaped = gedit_utils_escape_underscores (display_name, -1);
		if (i >= 10)
			label = g_strdup_printf ("%d.  %s",
						 i, 
						 escaped);
		else
			label = g_strdup_printf ("_%d.  %s",
						 i, 
						 escaped);
		g_free (escaped);

1340 1341
		/* gtk_recent_info_get_uri_display (info) is buggy and
		 * works only for local files */
1342
		uri = gedit_utils_uri_for_display (gtk_recent_info_get_uri (info));
1343
		ruri = gedit_utils_replace_home_dir_with_tilde (uri);
1344 1345 1346
		g_free (uri);

		/* Translators: %s is a URI */
1347 1348
		tip = g_strdup_printf (_("Open '%s'"), ruri);
		g_free (ruri);
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366

		action = gtk_action_new (action_name,
					 label,
					 tip,
					 NULL);

		g_object_set_data_full (G_OBJECT (action),
					"gtk-recent-info",
					gtk_recent_info_ref (info),
					(GDestroyNotify) gtk_recent_info_unref);

		g_signal_connect (action,
				  "activate",
				  G_CALLBACK (recents_menu_activate),
				  window);

		gtk_action_group_add_action (p->recents_action_group,
					     action);
1367
		g_object_unref (action);
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381

		gtk_ui_manager_add_ui (p->manager,
				       p->recents_menu_ui_id,
				       "/MenuBar/FileMenu/FileRecentsPlaceholder",
				       action_name,
				       action_name,
				       GTK_UI_MANAGER_MENUITEM,
				       FALSE);

		g_free (action_name);
		g_free (label);
		g_free (tip);
	}

1382 1383
	g_list_free (filtered_items);

1384 1385
	g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
	g_list_free (items);
Paolo Borelli's avatar
Paolo Borelli committed
1386 1387 1388 1389 1390 1391 1392
}

static void
set_non_homogeneus (GtkWidget *widget, gpointer data)
{
	gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
}
1393

1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
static void
toolbar_visibility_changed (GtkWidget   *toolbar,
			    GeditWindow *window)
{
	gboolean visible;
	GtkAction *action;

	visible = GTK_WIDGET_VISIBLE (toolbar);

	if (gedit_prefs_manager_toolbar_visible_can_set ())
		gedit_prefs_manager_set_toolbar_visible (visible);

	action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
					      "ViewToolbar");

	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
}

1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
static GtkWidget *
setup_toolbar_open_button (GeditWindow *window,
			   GtkWidget *toolbar)
{
	GtkRecentManager *recent_manager;
	GtkRecentFilter *filter;
	GtkWidget *toolbar_recent_menu;
	GtkToolItem *open_button;
	GtkAction *action;

	recent_manager = gtk_recent_manager_get_default ();

	/* recent files menu tool button */
	toolbar_recent_menu = gtk_recent_chooser_menu_new_for_manager (recent_manager);

	gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (toolbar_recent_menu),
					   FALSE);
	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (toolbar_recent_menu),
					  GTK_RECENT_SORT_MRU);
	gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (toolbar_recent_menu),
				      gedit_prefs_manager_get_max_recents ());

	filter = gtk_recent_filter_new ();
	gtk_recent_filter_add_group (filter, "gedit");
	gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (toolbar_recent_menu),
				       filter);

	g_signal_connect (toolbar_recent_menu,
			  "item_activated",
			  G_CALLBACK (recent_chooser_item_activated),
			  window);
	
	/* add the custom Open button to the toolbar */
	open_button = gtk_menu_tool_button_new_from_stock (GTK_STOCK_OPEN);
	gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button),
				       toolbar_recent_menu);

	gtk_tool_item_set_tooltip_text (open_button, _("Open a file"));
	gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button),
						     _("Open a recently used file"));

	action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
					      "FileOpen");
	g_object_set (action,
		      "is_important", TRUE,
		      "short_label", _("Open"),
		      NULL);
	gtk_action_connect_proxy (action, GTK_WIDGET (open_button));

	gtk_toolbar_insert (GTK_TOOLBAR (toolbar),
			    open_button,
			    1);
	
	return toolbar_recent_menu;
}

Paolo Borelli's avatar
Paolo Borelli committed
1469 1470 1471 1472 1473 1474 1475
static void
create_menu_bar_and_toolbar (GeditWindow *window, 
			     GtkWidget   *main_box)
{
	GtkActionGroup *action_group;
	GtkAction *action;
	GtkUIManager *manager;
1476
	GtkRecentManager *recent_manager;
Paolo Borelli's avatar
Paolo Borelli committed
1477
	GError *error = NULL;
1478
	gchar *ui_file;
Paolo Borelli's avatar
Paolo Borelli committed
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493

	gedit_debug (DEBUG_WINDOW);

	manager = gtk_ui_manager_new ();
	window->priv->manager = manager;

	gtk_window_add_accel_group (GTK_WINDOW (window),
				    gtk_ui_manager_get_accel_group (manager));

	action_group = gtk_action_group_new ("GeditWindowAlwaysSensitiveActions");
	gtk_action_group_set_translation_domain (action_group, NULL);
	gtk_action_group_add_actions (action_group,
				      gedit_always_sensitive_menu_entries,
				      G_N_ELEMENTS (gedit_always_sensitive_menu_entries),
				      window);
1494 1495 1496 1497
	gtk_action_group_add_toggle_actions (action_group,
					     gedit_always_sensitive_toggle_menu_entries,
					     G_N_ELEMENTS (gedit_always_sensitive_toggle_menu_entries),
					     window);
Paolo Borelli's avatar
Paolo Borelli committed
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515

	gtk_ui_manager_insert_action_group (manager, action_group, 0);
	g_object_unref (action_group);
	window->priv->always_sensitive_action_group = action_group;

	action_group = gtk_action_group_new ("GeditWindowActions");
	gtk_action_group_set_translation_domain (action_group, NULL);
	gtk_action_group_add_actions (action_group,
				      gedit_menu_entries,
				      G_N_ELEMENTS (gedit_menu_entries),
				      window);
	gtk_ui_manager_insert_action_group (manager, action_group, 0);
	g_object_unref (action_group);
	window->priv->action_group = action_group;

	/* set short labels to use in the toolbar */
	action = gtk_action_group_get_action (action_group, "FileSave");
	g_object_set (action, "short_label", _("Save"), NULL);
Paolo Borelli's avatar
Paolo Borelli committed
1516 1517
	action = gtk_action_group_get_action (action_group, "FilePrint");
	g_object_set (action, "short_label", _("Print"), NULL);
Paolo Borelli's avatar
Paolo Borelli committed
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
	action = gtk_action_group_get_action (action_group, "SearchFind");
	g_object_set (action, "short_label", _("Find"), NULL);
	action = gtk_action_group_get_action (action_group, "SearchReplace");
	g_object_set (action, "short_label", _("Replace"), NULL);

	/* set which actions should have priority on the toolbar */
	action = gtk_action_group_get_action (action_group, "FileSave");
	g_object_set (action, "is_important", TRUE, NULL);
	action = gtk_action_group_get_action (action_group, "EditUndo");
	g_object_set (action, "is_important", TRUE, NULL);

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
	action_group = gtk_action_group_new ("GeditQuitWindowActions");
	gtk_action_group_set_translation_domain (action_group, NULL);
	gtk_action_group_add_actions (action_group,
				      gedit_quit_menu_entries,
				      G_N_ELEMENTS (gedit_quit_menu_entries),
				      window);

	gtk_ui_manager_insert_action_group (manager, action_group, 0);
	g_object_unref (action_group);
	window->priv->quit_action_group = action_group;

1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
	action_group = gtk_action_group_new ("GeditCloseWindowActions");
	gtk_action_group_set_translation_domain (action_group, NULL);
	gtk_action_group_add_actions (action_group,
	                              gedit_close_menu_entries,
	                              G_N_ELEMENTS (gedit_close_menu_entries),
	                              window);

	gtk_ui_manager_insert_action_group (manager, action_group, 0);
	g_object_unref (action_group);
	window->priv->close_action_group = action_group;

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
	action_group = gtk_action_group_new ("GeditWindowPanesActions");
	gtk_action_group_set_translation_domain (action_group, NULL);
	gtk_action_group_add_toggle_actions (action_group,
					     gedit_panes_toggle_menu_entries,
					     G_N_ELEMENTS (gedit_panes_toggle_menu_entries),
					     window);

	gtk_ui_manager_insert_action_group (manager, action_group, 0);
	g_object_unref (action_group);
	window->priv->panes_action_group = action_group;

Paolo Borelli's avatar
Paolo Borelli committed
1562
	/* now load the UI definition */
1563 1564
	ui_file = gedit_dirs_get_ui_file (GEDIT_UIFILE);
	gtk_ui_manager_add_ui_from_file (manager, ui_file, &error);
Paolo Borelli's avatar
Paolo Borelli committed
1565 1566
	if (error != NULL)
	{
1567
		g_warning ("Could not merge %s: %s",