nautilus-window.c 44.7 KB
Newer Older
Darin Adler's avatar
Darin Adler committed
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 3 4 5

/*
 *  Nautilus
 *
Alexander Larsson's avatar
Alexander Larsson committed
6
 *  Copyright (C) 1999, 2000, 2004 Red Hat, Inc.
7
 *  Copyright (C) 1999, 2000, 2001 Eazel, Inc.
8
 *
9
 *  Nautilus is free software; you can redistribute it and/or
10 11 12 13
 *  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.
 *
14
 *  Nautilus is distributed in the hope that it will be useful,
15 16 17 18 19
 *  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
20
 *  License along with this program; if not, write to the Free
21 22
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
23 24
 *  Authors: Elliot Lee <sopwith@redhat.com>
 *  	     John Sullivan <sullivan@eazel.com>
Alexander Larsson's avatar
Alexander Larsson committed
25
 *           Alexander Larsson <alexl@redhat.com>
26
 */
27

28
/* nautilus-window.c: Implementation of the main window object */
29

30
#include <config.h>
31

32
#include "nautilus-window-private.h"
33

Alexander Larsson's avatar
Alexander Larsson committed
34
#include "nautilus-actions.h"
35
#include "nautilus-application.h"
36
#include "nautilus-bookmarks-window.h"
37 38 39 40 41
#include "nautilus-mime-actions.h"
#include "nautilus-navigation-window-pane.h"
#include "nautilus-navigation-window-slot.h"
#include "nautilus-search-bar.h"
#include "nautilus-src-marshal.h"
42
#include "nautilus-view-factory.h"
43
#include "nautilus-window-manage-views.h"
44
#include "nautilus-window-bookmarks.h"
45
#include "nautilus-window-slot.h"
46
#include "nautilus-zoom-control.h"
47

Darin Adler's avatar
Darin Adler committed
48
#include <eel/eel-debug.h>
49 50
#include <eel/eel-gtk-macros.h>
#include <eel/eel-string.h>
51
#include <gdk-pixbuf/gdk-pixbuf.h>
52
#include <gdk/gdkx.h>
Alexander Larsson's avatar
Alexander Larsson committed
53
#include <gdk/gdkkeysyms.h>
54
#include <gtk/gtk.h>
55
#include <glib/gi18n.h>
56 57 58
#ifdef HAVE_X11_XF86KEYSYM_H
#include <X11/XF86keysym.h>
#endif
59
#include <libnautilus-private/nautilus-file-utilities.h>
Alexander Larsson's avatar
Alexander Larsson committed
60
#include <libnautilus-private/nautilus-file-attributes.h>
61 62 63
#include <libnautilus-private/nautilus-global-preferences.h>
#include <libnautilus-private/nautilus-metadata.h>
#include <libnautilus-private/nautilus-program-choosing.h>
Alexander Larsson's avatar
Alexander Larsson committed
64 65
#include <libnautilus-private/nautilus-clipboard.h>
#include <libnautilus-private/nautilus-undo.h>
66
#include <libnautilus-private/nautilus-search-directory.h>
Alexander Larsson's avatar
Alexander Larsson committed
67
#include <libnautilus-private/nautilus-signaller.h>
68
#include <math.h>
69
#include <sys/time.h>
70

71
#define MAX_HISTORY_ITEMS 50
72

73 74 75
#define SIDE_PANE_MINIMUM_WIDTH 1
#define SIDE_PANE_MINIMUM_HEIGHT 400

76
/* dock items */
77

Alexander Larsson's avatar
Alexander Larsson committed
78 79 80
#define NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER	"/MenuBar/View/View Choices/Extra Viewer"
#define NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER  	"/MenuBar/View/View Choices/Short List"
#define NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR   "/MenuBar/View/View Choices/After Short List"
81

Elliot Lee's avatar
Elliot Lee committed
82
enum {
Darin Adler's avatar
Darin Adler committed
83
	ARG_0,
84
	ARG_APP
Elliot Lee's avatar
Elliot Lee committed
85 86
};

Alexander Larsson's avatar
Alexander Larsson committed
87 88
enum {
	GO_UP,
89 90
	RELOAD,
	PROMPT_FOR_LOCATION,
91
	ZOOM_CHANGED,
92
	VIEW_AS_CHANGED,
93 94
	LOADING_URI,
	HIDDEN_FILES_MODE_CHANGED,
Alexander Larsson's avatar
Alexander Larsson committed
95 96 97 98 99 100 101 102 103 104
	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

typedef struct  {
	NautilusWindow *window;
	char *id;
} ActivateViewData;

105
static void cancel_view_as_callback         (NautilusWindowSlot      *slot);
Alexander Larsson's avatar
Alexander Larsson committed
106 107
static void action_view_as_callback         (GtkAction               *action,
					     ActivateViewData        *data);
108

109
G_DEFINE_TYPE (NautilusWindow, nautilus_window, GTK_TYPE_WINDOW);
Alexander Larsson's avatar
Alexander Larsson committed
110

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
static const struct {
	unsigned int keyval;
	const char *action;
} extra_window_keybindings [] = {
#ifdef HAVE_X11_XF86KEYSYM_H
	{ XF86XK_AddFavorite,	NAUTILUS_ACTION_ADD_BOOKMARK },
	{ XF86XK_Favorites,	NAUTILUS_ACTION_EDIT_BOOKMARKS },
	{ XF86XK_Go,		NAUTILUS_ACTION_GO_TO_LOCATION },
/* TODO?{ XF86XK_History,	NAUTILUS_ACTION_HISTORY }, */
	{ XF86XK_HomePage,      NAUTILUS_ACTION_GO_HOME },
	{ XF86XK_OpenURL,	NAUTILUS_ACTION_GO_TO_LOCATION },
	{ XF86XK_Refresh,	NAUTILUS_ACTION_RELOAD },
	{ XF86XK_Reload,	NAUTILUS_ACTION_RELOAD },
	{ XF86XK_Search,	NAUTILUS_ACTION_SEARCH },
	{ XF86XK_Start,		NAUTILUS_ACTION_GO_HOME },
	{ XF86XK_Stop,		NAUTILUS_ACTION_STOP },
	{ XF86XK_ZoomIn,	NAUTILUS_ACTION_ZOOM_IN },
	{ XF86XK_ZoomOut,	NAUTILUS_ACTION_ZOOM_OUT }
#endif
};

132
static void
Alexander Larsson's avatar
Alexander Larsson committed
133
nautilus_window_init (NautilusWindow *window)
134
{
Alexander Larsson's avatar
Alexander Larsson committed
135 136 137
	GtkWidget *table;
	GtkWidget *menu;
	GtkWidget *statusbar;
138

139
	window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NAUTILUS_TYPE_WINDOW, NautilusWindowDetails);
140

141 142 143
	window->details->panes = NULL;
	window->details->active_pane = NULL;

Alexander Larsson's avatar
Alexander Larsson committed
144
	window->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
Alexander Larsson's avatar
Alexander Larsson committed
145

Anders Carlsson's avatar
Anders Carlsson committed
146 147 148
	/* Set initial window title */
	gtk_window_set_title (GTK_WINDOW (window), _("Nautilus"));

Cosimo Cecchi's avatar
Cosimo Cecchi committed
149 150
	gtk_window_set_has_resize_grip (GTK_WINDOW (window), FALSE);

151
	table = gtk_table_new (1, 6, FALSE);
Alexander Larsson's avatar
Alexander Larsson committed
152 153 154 155 156
	window->details->table = table;
	gtk_widget_show (table);
	gtk_container_add (GTK_CONTAINER (window), table);

	statusbar = gtk_statusbar_new ();
Alexander Larsson's avatar
Alexander Larsson committed
157
	gtk_widget_set_name (statusbar, "statusbar-noborder");
Alexander Larsson's avatar
Alexander Larsson committed
158 159 160
	window->details->statusbar = statusbar;
	window->details->help_message_cid = gtk_statusbar_get_context_id
		(GTK_STATUSBAR (statusbar), "help_message");
161
	/* Statusbar is packed in the subclasses */
Alexander Larsson's avatar
Alexander Larsson committed
162 163 164 165 166 167 168 169

	nautilus_window_initialize_menus (window);
	
	menu = gtk_ui_manager_get_widget (window->details->ui_manager, "/MenuBar");
	window->details->menubar = menu;
	gtk_widget_show (menu);
	gtk_table_attach (GTK_TABLE (table),
			  menu, 
170 171 172 173
			  /* X direction */                   /* Y direction */
			  0, 1,                               0, 1,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0,
			  0,                                  0);
174

Alexander Larsson's avatar
Alexander Larsson committed
175 176 177
	/* Register to menu provider extension signal managing menu updates */
	g_signal_connect_object (nautilus_signaller_get_current (), "popup_menu_changed",
			 G_CALLBACK (nautilus_window_load_extension_menus), window, G_CONNECT_SWAPPED);
178 179
}

Alexander Larsson's avatar
Alexander Larsson committed
180
/* Unconditionally synchronize the GtkUIManager of WINDOW. */
181 182 183
static void
nautilus_window_ui_update (NautilusWindow *window)
{
184 185
	g_assert (NAUTILUS_IS_WINDOW (window));

Alexander Larsson's avatar
Alexander Larsson committed
186
	gtk_ui_manager_ensure_update (window->details->ui_manager);
187 188
}

189
void
190 191
nautilus_window_push_status (NautilusWindow *window,
			     const char *text)
192
{
193 194
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));

195 196 197
	/* clear any previous message, underflow is allowed */
	gtk_statusbar_pop (GTK_STATUSBAR (window->details->statusbar), 0);

198
	if (text != NULL && text[0] != '\0') {
Alexander Larsson's avatar
Alexander Larsson committed
199
		gtk_statusbar_push (GTK_STATUSBAR (window->details->statusbar), 0, text);
200
	}
201 202
}

203 204 205 206 207
void
nautilus_window_sync_status (NautilusWindow *window)
{
	NautilusWindowSlot *slot;

208
	slot = window->details->active_pane->active_slot;
209 210 211
	nautilus_window_push_status (window, slot->status_text);
}

212
void
Alexander Larsson's avatar
Alexander Larsson committed
213
nautilus_window_go_to (NautilusWindow *window, GFile *location)
214
{
215 216
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));

217
	nautilus_window_slot_go_to (window->details->active_pane->active_slot, location, FALSE);
218 219
}

220 221 222 223 224 225 226 227 228 229 230
void
nautilus_window_go_to_full (NautilusWindow *window,
			    GFile          *location,
			    NautilusWindowGoToCallback callback,
			    gpointer        user_data)
{
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));

	nautilus_window_slot_go_to_full (window->details->active_pane->active_slot, location, FALSE, callback, user_data);
}

Alexander Larsson's avatar
Alexander Larsson committed
231 232 233
static gboolean
nautilus_window_go_up_signal (NautilusWindow *window, gboolean close_behind)
{
234 235 236
	nautilus_window_slot_go_up (nautilus_window_get_active_slot (window),
				    close_behind, FALSE);

Alexander Larsson's avatar
Alexander Larsson committed
237 238 239
	return TRUE;
}

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
void
nautilus_window_new_tab (NautilusWindow *window)
{
	NautilusWindowSlot *current_slot;
	NautilusWindowSlot *new_slot;
	NautilusWindowOpenFlags flags;
	GFile *location;
	int new_slot_position;
	char *scheme;

	current_slot = window->details->active_pane->active_slot;
	location = nautilus_window_slot_get_location (current_slot);

	if (location != NULL) {
		flags = 0;

		new_slot_position = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_NEW_TAB_POSITION);
		if (new_slot_position == NAUTILUS_NEW_TAB_POSITION_END) {
			flags = NAUTILUS_WINDOW_OPEN_SLOT_APPEND;
		}

		scheme = g_file_get_uri_scheme (location);
		if (!strcmp (scheme, "x-nautilus-search")) {
			g_object_unref (location);
			location = g_file_new_for_path (g_get_home_dir ());
		}
		g_free (scheme);

		new_slot = nautilus_window_open_slot (current_slot->pane, flags);
		nautilus_window_set_active_slot (window, new_slot);
		nautilus_window_slot_go_to (new_slot, location, FALSE);
		g_object_unref (location);
	}
}

275 276 277
static void
real_set_allow_up (NautilusWindow *window,
		   gboolean        allow)
278
{
Alexander Larsson's avatar
Alexander Larsson committed
279 280
	GtkAction *action;
	
281
        g_assert (NAUTILUS_IS_WINDOW (window));
282

Alexander Larsson's avatar
Alexander Larsson committed
283 284 285 286 287 288
	action = gtk_action_group_get_action (window->details->main_action_group,
					      NAUTILUS_ACTION_UP);
	gtk_action_set_sensitive (action, allow);
	action = gtk_action_group_get_action (window->details->main_action_group,
					      NAUTILUS_ACTION_UP_ACCEL);
	gtk_action_set_sensitive (action, allow);
289 290
}

291 292 293
void
nautilus_window_allow_up (NautilusWindow *window, gboolean allow)
{
294 295
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));

296 297 298 299
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 set_allow_up, (window, allow));
}

300 301 302
static void
update_cursor (NautilusWindow *window)
{
303
	NautilusWindowSlot *slot;
304 305
	GdkCursor *cursor;

306
	slot = window->details->active_pane->active_slot;
307 308

	if (slot->allow_stop) {
309
		cursor = gdk_cursor_new (GDK_WATCH);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
310
		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
311
		g_object_unref (cursor);
312
	} else {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
313
		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
314 315 316
	}
}

317
void
318 319
nautilus_window_sync_allow_stop (NautilusWindow *window,
				 NautilusWindowSlot *slot)
320
{
Alexander Larsson's avatar
Alexander Larsson committed
321
	GtkAction *action;
322 323 324
	gboolean allow_stop;

	g_assert (NAUTILUS_IS_WINDOW (window));
325

Alexander Larsson's avatar
Alexander Larsson committed
326 327
	action = gtk_action_group_get_action (window->details->main_action_group,
					      NAUTILUS_ACTION_STOP);
328
	allow_stop = gtk_action_get_sensitive (action);
329

330
	if (slot != window->details->active_pane->active_slot ||
331
	    allow_stop != slot->allow_stop) {
332
		if (slot == window->details->active_pane->active_slot) {
333 334
			gtk_action_set_sensitive (action, slot->allow_stop);
		}
335

336
		if (gtk_widget_get_realized (GTK_WIDGET (window))) {
337 338
			update_cursor (window);
		}
339 340 341

		EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
				 sync_allow_stop, (window, slot));
342
	}
343 344
}

345
void
346 347
nautilus_window_prompt_for_location (NautilusWindow *window,
				     const char     *initial)
348
{
349
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));
350 351
	
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
352
                         prompt_for_location, (window, initial));
353 354
}

355 356 357 358
/* Code should never force the window taller than this size.
 * (The user can still stretch the window taller if desired).
 */
static guint
359
get_max_forced_height (GdkScreen *screen)
360
{
361
	return (gdk_screen_get_height (screen) * 90) / 100;
362 363 364 365 366 367
}

/* Code should never force the window wider than this size.
 * (The user can still stretch the window wider if desired).
 */
static guint
368
get_max_forced_width (GdkScreen *screen)
369
{
370
	return (gdk_screen_get_width (screen) * 90) / 100;
371 372
}

Alexander Larsson's avatar
Alexander Larsson committed
373 374 375 376
/* This must be called when construction of NautilusWindow is finished,
 * since it depends on the type of the argument, which isn't decided at
 * construction time.
 */
377
static void
Alexander Larsson's avatar
Alexander Larsson committed
378
nautilus_window_set_initial_window_geometry (NautilusWindow *window)
379
{
380
	GdkScreen *screen;
381
	guint max_width_for_screen, max_height_for_screen;
382
	guint default_width, default_height;
383

384 385 386 387
	screen = gtk_window_get_screen (GTK_WINDOW (window));
	
	max_width_for_screen = get_max_forced_width (screen);
	max_height_for_screen = get_max_forced_height (screen);
388

389
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
Alexander Larsson's avatar
Alexander Larsson committed
390
			 get_default_size, (window, &default_width, &default_height));
Alexander Larsson's avatar
Alexander Larsson committed
391

392
	gtk_window_set_default_size (GTK_WINDOW (window), 
393
				     MIN (default_width, 
394
				          max_width_for_screen), 
395
				     MIN (default_height, 
396 397 398
				          max_height_for_screen));
}

399 400
static void
nautilus_window_constructed (GObject *self)
401
{
402 403 404
	NautilusWindow *window;

	window = NAUTILUS_WINDOW (self);
405

406
	nautilus_window_initialize_bookmarks_menu (window);
Alexander Larsson's avatar
Alexander Larsson committed
407
	nautilus_window_set_initial_window_geometry (window);
408
	nautilus_undo_manager_attach (window->details->application->undo_manager, G_OBJECT (window));
Elliot Lee's avatar
Elliot Lee committed
409 410 411
}

static void
412 413
nautilus_window_set_property (GObject *object,
			      guint arg_id,
414
			      const GValue *value,
415
			      GParamSpec *pspec)
Elliot Lee's avatar
Elliot Lee committed
416
{
417 418 419
	NautilusWindow *window;

	window = NAUTILUS_WINDOW (object);
Darin Adler's avatar
Darin Adler committed
420
	
421
	switch (arg_id) {
Darin Adler's avatar
Darin Adler committed
422
	case ARG_APP:
423
		window->details->application = NAUTILUS_APPLICATION (g_value_get_object (value));
Darin Adler's avatar
Darin Adler committed
424 425
		break;
	}
Elliot Lee's avatar
Elliot Lee committed
426 427 428
}

static void
429 430 431 432
nautilus_window_get_property (GObject *object,
			      guint arg_id,
			      GValue *value,
			      GParamSpec *pspec)
Elliot Lee's avatar
Elliot Lee committed
433
{
434
	switch (arg_id) {
Darin Adler's avatar
Darin Adler committed
435
	case ARG_APP:
436
		g_value_set_object (value, NAUTILUS_WINDOW (object)->details->application);
Darin Adler's avatar
Darin Adler committed
437 438
		break;
	}
Elliot Lee's avatar
Elliot Lee committed
439 440
}

441 442 443
static void
free_stored_viewers (NautilusWindow *window)
{
444
	g_list_free_full (window->details->short_list_viewers, g_free);
445
	window->details->short_list_viewers = NULL;
Alexander Larsson's avatar
Alexander Larsson committed
446
	g_free (window->details->extra_viewer);
447 448 449
	window->details->extra_viewer = NULL;
}

Darin Adler's avatar
Darin Adler committed
450
static void
Cosimo Cecchi's avatar
Cosimo Cecchi committed
451
nautilus_window_destroy (GtkWidget *object)
Darin Adler's avatar
Darin Adler committed
452 453
{
	NautilusWindow *window;
454
	GList *panes_copy;
455

Darin Adler's avatar
Darin Adler committed
456 457
	window = NAUTILUS_WINDOW (object);

458 459 460 461
	/* close all panes safely */
	panes_copy = g_list_copy (window->details->panes);
	g_list_foreach (panes_copy, (GFunc) nautilus_window_close_pane, NULL);
	g_list_free (panes_copy);
Darin Adler's avatar
Darin Adler committed
462

463 464
	/* the panes list should now be empty */
	g_assert (window->details->panes == NULL);
465
	g_assert (window->details->active_pane == NULL);
Darin Adler's avatar
Darin Adler committed
466

Cosimo Cecchi's avatar
Cosimo Cecchi committed
467
	GTK_WIDGET_CLASS (nautilus_window_parent_class)->destroy (object);
Darin Adler's avatar
Darin Adler committed
468 469
}

470 471
static void
nautilus_window_finalize (GObject *object)
472 473
{
	NautilusWindow *window;
474

475 476
	window = NAUTILUS_WINDOW (object);

477
	nautilus_window_remove_trash_monitor_callback (window);
478
	free_stored_viewers (window);
479

480 481 482 483
	if (window->details->bookmark_list != NULL) {
		g_object_unref (window->details->bookmark_list);
	}

484
	/* nautilus_window_close() should have run */
485
	g_assert (window->details->panes == NULL);
486

Alexander Larsson's avatar
Alexander Larsson committed
487
	g_object_unref (window->details->ui_manager);
488

Alexander Larsson's avatar
Alexander Larsson committed
489
	G_OBJECT_CLASS (nautilus_window_parent_class)->finalize (object);
490 491
}

492 493 494 495 496 497 498
static GObject *
nautilus_window_constructor (GType type,
			     guint n_construct_properties,
			     GObjectConstructParam *construct_params)
{
	GObject *object;
	NautilusWindow *window;
499
	NautilusWindowSlot *slot;
500 501 502 503 504 505 506

	object = (* G_OBJECT_CLASS (nautilus_window_parent_class)->constructor) (type,
										 n_construct_properties,
										 construct_params);

	window = NAUTILUS_WINDOW (object);

507
	slot = nautilus_window_open_slot (window->details->active_pane, 0);
508
	nautilus_window_set_active_slot (window, slot);
509

510 511 512
	return object;
}

513
void
514
nautilus_window_show_window (NautilusWindow    *window)
515
{
516
	NautilusWindowSlot *slot;
517
	NautilusWindowPane *pane;
518
	GList *l, *walk;
519

520
	for (walk = window->details->panes; walk; walk = walk->next) {
521
		pane = walk->data;
522 523
		for (l = pane->slots; l != NULL; l = l->next) {
			slot = l->data;
524

525 526 527
			nautilus_window_slot_update_title (slot);
			nautilus_window_slot_update_icon (slot);
		}
528
	}
529 530 531

	gtk_widget_show (GTK_WIDGET (window));

532
	slot = window->details->active_pane->active_slot;
533 534
}

535
void
536 537 538 539 540 541 542 543 544 545
nautilus_window_view_visible (NautilusWindow *window,
			      NautilusView *view)
{
	NautilusWindowSlot *slot;
	NautilusWindowPane *pane;
	GList *l, *walk;

	g_return_if_fail (NAUTILUS_IS_WINDOW (window));

	slot = nautilus_window_get_slot_for_view (window, view);
546
	nautilus_view_set_is_active (view, slot->pane->is_active);
547

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
	if (slot->visible) {
		return;
	}

	slot->visible = TRUE;

	pane = slot->pane;

	if (pane->visible) {
		return;
	}

	/* Look for other non-visible slots */
	for (l = pane->slots; l != NULL; l = l->next) {
		slot = l->data;

		if (!slot->visible) {
			return;
		}
	}

	/* None, this pane is visible */
	nautilus_window_pane_show (pane);

	/* Look for other non-visible panes */
	for (walk = window->details->panes; walk; walk = walk->next) {
		pane = walk->data;

		if (!pane->visible) {
			return;
		}
	}

Holger Berndt's avatar
Holger Berndt committed
581
	nautilus_window_pane_grab_focus (window->details->active_pane);
582

583 584 585 586
	/* All slots and panes visible, show window */
	nautilus_window_show_window (window);
}

587 588 589
void
nautilus_window_close (NautilusWindow *window)
{
590
	g_return_if_fail (NAUTILUS_IS_WINDOW (window));
591

Alexander Larsson's avatar
Alexander Larsson committed
592 593 594
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 close, (window));
	
595 596 597
	gtk_widget_destroy (GTK_WIDGET (window));
}

598
NautilusWindowSlot *
599
nautilus_window_open_slot (NautilusWindowPane *pane,
600 601 602 603
			   NautilusWindowOpenSlotFlags flags)
{
	NautilusWindowSlot *slot;

604 605
	g_assert (NAUTILUS_IS_WINDOW_PANE (pane));
	g_assert (NAUTILUS_IS_WINDOW (pane->window));
606

607 608
	slot = EEL_CALL_METHOD_WITH_RETURN_VALUE (NAUTILUS_WINDOW_CLASS, pane->window,
						  open_slot, (pane, flags));
609 610

	g_assert (NAUTILUS_IS_WINDOW_SLOT (slot));
611
	g_assert (pane->window == slot->pane->window);
612

613
	pane->slots = g_list_append (pane->slots, slot);
614 615 616 617

	return slot;
}

618 619 620 621 622 623 624 625 626
void
nautilus_window_close_pane (NautilusWindowPane *pane)
{
	NautilusWindow *window;

	g_assert (NAUTILUS_IS_WINDOW_PANE (pane));
	g_assert (NAUTILUS_IS_WINDOW (pane->window));
	g_assert (g_list_find (pane->window->details->panes, pane) != NULL);

627 628
	while (pane->slots != NULL) {
		NautilusWindowSlot *slot = pane->slots->data;
629

630
		nautilus_window_close_slot (slot);
631 632 633
	}

	window = pane->window;
634

635 636 637
	/* If the pane was active, set it to NULL. The caller is responsible
	 * for setting a new active pane with nautilus_window_pane_switch_to()
	 * if it wants to continue using the window. */
638
	if (window->details->active_pane == pane) {
639
		window->details->active_pane = NULL;
640 641
	}

642 643
	window->details->panes = g_list_remove (window->details->panes, pane);

644 645 646
	g_object_unref (pane);
}

647
static void
648
real_close_slot (NautilusWindowPane *pane,
649 650
		 NautilusWindowSlot *slot)
{
651
	nautilus_window_manage_views_close_slot (pane, slot);
652 653 654 655
	cancel_view_as_callback (slot);
}

void
656
nautilus_window_close_slot (NautilusWindowSlot *slot)
657
{
658
	NautilusWindowPane *pane;
659

660
	g_assert (NAUTILUS_IS_WINDOW_SLOT (slot));
661 662
	g_assert (NAUTILUS_IS_WINDOW_PANE(slot->pane));
	g_assert (g_list_find (slot->pane->slots, slot) != NULL);
663

664 665
	/* save pane because slot is not valid anymore after this call */
	pane = slot->pane;
666

667 668
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, slot->pane->window,
			 close_slot, (slot->pane, slot));
669

670 671 672
	g_object_run_dispose (G_OBJECT (slot));
	slot->pane = NULL;
	g_object_unref (slot);
673
	pane->slots = g_list_remove (pane->slots, slot);
674 675
}

676 677 678 679 680 681 682
NautilusWindowPane*
nautilus_window_get_active_pane (NautilusWindow *window)
{
	g_assert (NAUTILUS_IS_WINDOW (window));
	return window->details->active_pane;
}

683 684 685 686 687
static void
real_set_active_pane (NautilusWindow *window, NautilusWindowPane *new_pane)
{
	/* make old pane inactive, and new one active.
	 * Currently active pane may be NULL (after init). */
688 689 690
	if (window->details->active_pane &&
	    window->details->active_pane != new_pane) {
		nautilus_window_pane_set_active (new_pane->window->details->active_pane, FALSE);
691
	}
692
	nautilus_window_pane_set_active (new_pane, TRUE);
693 694 695 696 697 698 699

	window->details->active_pane = new_pane;
}

/* Make the given pane the active pane of its associated window. This
 * always implies making the containing active slot the active slot of
 * the window. */
700 701 702 703
void
nautilus_window_set_active_pane (NautilusWindow *window,
				 NautilusWindowPane *new_pane)
{
704 705 706
	g_assert (NAUTILUS_IS_WINDOW_PANE (new_pane));
	if (new_pane->active_slot) {
		nautilus_window_set_active_slot (window, new_pane->active_slot);
Alexander Larsson's avatar
Alexander Larsson committed
707
	} else if (new_pane != window->details->active_pane) {
708 709
		real_set_active_pane (window, new_pane);
	}
710 711
}

712 713 714
/* Make both, the given slot the active slot and its corresponding
 * pane the active pane of the associated window.
 * new_slot may be NULL. */
715
void
716
nautilus_window_set_active_slot (NautilusWindow *window, NautilusWindowSlot *new_slot)
717 718
{
	NautilusWindowSlot *old_slot;
719

720 721
	g_assert (NAUTILUS_IS_WINDOW (window));

722
	if (new_slot) {
723
		g_assert (NAUTILUS_IS_WINDOW_SLOT (new_slot));
724
		g_assert (NAUTILUS_IS_WINDOW_PANE (new_slot->pane));
725
		g_assert (window == new_slot->pane->window);
726
		g_assert (g_list_find (new_slot->pane->slots, new_slot) != NULL);
727 728
	}

Alexander Larsson's avatar
Alexander Larsson committed
729
	if (window->details->active_pane != NULL) {
730
		old_slot = window->details->active_pane->active_slot;
Alexander Larsson's avatar
Alexander Larsson committed
731
	} else {
732 733
		old_slot = NULL;
	}
734 735 736 737 738

	if (old_slot == new_slot) {
		return;
	}

739
	/* make old slot inactive if it exists (may be NULL after init, for example) */
740 741 742
	if (old_slot != NULL) {
		/* inform window */
		if (old_slot->content_view != NULL) {
743
			nautilus_window_disconnect_content_view (window, old_slot->content_view);
744
		}
745

746 747 748 749
		/* inform slot & view */
		g_signal_emit_by_name (old_slot, "inactive");
	}

750
	/* deal with panes */
Alexander Larsson's avatar
Alexander Larsson committed
751 752
	if (new_slot &&
	    new_slot->pane != window->details->active_pane) {
753 754
		real_set_active_pane (window, new_slot->pane);
	}
755

756
	window->details->active_pane->active_slot = new_slot;
757

758 759
	/* make new slot active, if it exists */
	if (new_slot) {
760
		/* inform sidebar panels */
761
                nautilus_window_report_location_change (window);
762 763 764
		/* TODO decide whether "selection-changed" should be emitted */

		if (new_slot->content_view != NULL) {
765
                        /* inform window */
766
                        nautilus_window_connect_content_view (window, new_slot->content_view);
767
                }
768 769

		/* inform slot & view */
770
                g_signal_emit_by_name (new_slot, "active");
771 772 773
	}
}

774
static void
775 776 777
nautilus_window_get_preferred_width (GtkWidget *widget,
				     gint *minimal_width,
				     gint *natural_width)
778
{
779
	GdkScreen *screen;
780 781
	gint max_w, min_w, min_h, default_w, default_h;
	NautilusWindow *window = NAUTILUS_WINDOW (widget);
782

783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
	screen = gtk_window_get_screen (GTK_WINDOW (widget));	

	max_w = get_max_forced_width (screen);
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 get_min_size, (window, &min_w, &min_h));
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 get_default_size, (window, &default_w, &default_h));

	*minimal_width = MIN (min_w, max_w);
	*natural_width = MIN (default_w, max_w);
}

static void
nautilus_window_get_preferred_height (GtkWidget *widget,
				      gint *minimal_height,
				      gint *natural_height)
{
	GdkScreen *screen;
	gint max_h, min_w, min_h, default_w, default_h;
	NautilusWindow *window = NAUTILUS_WINDOW (widget);

	screen = gtk_window_get_screen (GTK_WINDOW (widget));	

	max_h = get_max_forced_height (screen);
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 get_min_size, (window, &min_w, &min_h));
	EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
			 get_default_size, (window, &default_w, &default_h));

	*minimal_height = MIN (min_h, max_h);
	*natural_height = MIN (default_h, max_h);
814 815
}

816 817 818 819 820 821
static void
nautilus_window_realize (GtkWidget *widget)
{
	GTK_WIDGET_CLASS (nautilus_window_parent_class)->realize (widget);
	update_cursor (NAUTILUS_WINDOW (widget));
}
822

823 824 825 826 827 828 829 830 831
static gboolean
nautilus_window_key_press_event (GtkWidget *widget,
				 GdkEventKey *event)
{
	NautilusWindow *window;
	int i;

	window = NAUTILUS_WINDOW (widget);

832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
	for (i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++) {
		if (extra_window_keybindings[i].keyval == event->keyval) {
			const GList *action_groups;
			GtkAction *action;

			action = NULL;

			action_groups = gtk_ui_manager_get_action_groups (window->details->ui_manager);
			while (action_groups != NULL && action == NULL) {
				action = gtk_action_group_get_action (action_groups->data, extra_window_keybindings[i].action);
				action_groups = action_groups->next;
			}

			g_assert (action != NULL);
			if (gtk_action_is_sensitive (action)) {
				gtk_action_activate (action);
				return TRUE;
849
			}
850 851

			break;
852 853
		}
	}
854 855

	return GTK_WIDGET_CLASS (nautilus_window_parent_class)->key_press_event (widget, event);
856 857
}

858 859 860 861
/*
 * Main API
 */

862
static void
Alexander Larsson's avatar
Alexander Larsson committed
863
free_activate_view_data (gpointer data)
864
{
Alexander Larsson's avatar
Alexander Larsson committed
865
	ActivateViewData *activate_data;