Commit 71c3e943 authored by John Sullivan's avatar John Sullivan

Fixed bug 168 (Save and restore window position/size per

	directory)

	Note that this is only done when in "use separate windows
	for everything" mode. My brain broke trying to figure out
	how it could be used coherently in single-window mode.

	* libnautilus-extensions/nautilus-gtk-extensions.h:
	* libnautilus-extensions/nautilus-gtk-extensions.c:
	(sanity_check_window_geometry): New helper function, takes
	four coordinates and munges them if necessary to keep the
	window at least partially on screen and not ridiculously
	huge.
	(nautilus_gtk_window_set_initial_geometry): New function,
	sets the position/location of a window before it is shown
	after calling sanity_check_window_geometry on
	top/left/width/height parameters.
	(nautilus_gtk_window_set_initial_geometry_from_string):
	New function, calls _set_initial_geometry after parsing
	geometry-as-string parameter and adjusting it for
	minimum-width and minimum-height parameters.

	* libnautilus-extensions/nautilus-metadata.h:
	#define new per-directory key for window geometry

	* src/nautilus-application.c:
	(nautilus_window_delete_event_callback): New function,
	calls nautilus_window_close.
	(nautilus_application_create_window): Hook up this new
	callback as signal handler for window's delete_event;
	this causes closing the window from the close box go
	through the same nautilus_window_close path that closing
	the window from the menu did.

	* src/nautilus-bookmarks-window.c:
	(nautilus_bookmarks_window_restore_geometry):
	Now calls nautilus_gtk_window_set_geometry_from_string,
	which was extracted from here.

	* src/nautilus-window-manage-views.c:
	(position_and_show_window_callback): New function, reads
	geometry string for this location from metadata & applies
	it (if in use-new-window mode), then shows window.
	(nautilus_window_end_location_change_callback):
	Use nautilus_directory_call_when_ready to show the window
	only after the metadata has been read, so it doesn't appear
	in one position and then bounce elsewhere.

	* src/nautilus-window-menus.c: (file_menu_new_window_callback):
	Removed gtk_widget_show from here. It wasn't necessary since
	the window is shown later after the URI is determined to be good,
	and doing it here prevented the window positioning code from
	working correctly.

	* src/nautilus-window-private.h: Moved some window geometry
	#defines in here.

	* src/nautilus-window.c:
	(nautilus_window_save_geometry): New private function, reads
	the window geometry and stores it in the directory's metadata.
	(nautilus_window_close): Calls nautilus_window_save_geometry
	if we're in use-new-windows mode.
parent b90c6952
2000-09-22 John Sullivan <sullivan@eazel.com>
Fixed bug 168 (Save and restore window position/size per
directory)
Note that this is only done when in "use separate windows
for everything" mode. My brain broke trying to figure out
how it could be used coherently in single-window mode.
* libnautilus-extensions/nautilus-gtk-extensions.h:
* libnautilus-extensions/nautilus-gtk-extensions.c:
(sanity_check_window_geometry): New helper function, takes
four coordinates and munges them if necessary to keep the
window at least partially on screen and not ridiculously
huge.
(nautilus_gtk_window_set_initial_geometry): New function,
sets the position/location of a window before it is shown
after calling sanity_check_window_geometry on
top/left/width/height parameters.
(nautilus_gtk_window_set_initial_geometry_from_string):
New function, calls _set_initial_geometry after parsing
geometry-as-string parameter and adjusting it for
minimum-width and minimum-height parameters.
* libnautilus-extensions/nautilus-metadata.h:
#define new per-directory key for window geometry
* src/nautilus-application.c:
(nautilus_window_delete_event_callback): New function,
calls nautilus_window_close.
(nautilus_application_create_window): Hook up this new
callback as signal handler for window's delete_event;
this causes closing the window from the close box go
through the same nautilus_window_close path that closing
the window from the menu did.
* src/nautilus-bookmarks-window.c:
(nautilus_bookmarks_window_restore_geometry):
Now calls nautilus_gtk_window_set_geometry_from_string,
which was extracted from here.
* src/nautilus-window-manage-views.c:
(position_and_show_window_callback): New function, reads
geometry string for this location from metadata & applies
it (if in use-new-window mode), then shows window.
(nautilus_window_end_location_change_callback):
Use nautilus_directory_call_when_ready to show the window
only after the metadata has been read, so it doesn't appear
in one position and then bounce elsewhere.
* src/nautilus-window-menus.c: (file_menu_new_window_callback):
Removed gtk_widget_show from here. It wasn't necessary since
the window is shown later after the URI is determined to be good,
and doing it here prevented the window positioning code from
working correctly.
* src/nautilus-window-private.h: Moved some window geometry
#defines in here.
* src/nautilus-window.c:
(nautilus_window_save_geometry): New private function, reads
the window geometry and stores it in the directory's metadata.
(nautilus_window_close): Calls nautilus_window_save_geometry
if we're in use-new-windows mode.
2000-09-22 Robin * Slomkowski <rslomkow@eazel.com>
* nautilus.spec.in: added --enable-more-warnings
......
......@@ -44,6 +44,12 @@
*/
#define MAXIMUM_MENU_TITLE_LENGTH 48
/* Used for window position & size sanity-checking. The sizes are big enough to prevent
* at least normal-sized gnome panels from obscuring the window at the screen edges.
*/
#define MINIMUM_ON_SCREEN_WIDTH 100
#define MINIMUM_ON_SCREEN_HEIGHT 100
static gboolean
finish_button_activation (gpointer data)
{
......@@ -306,6 +312,129 @@ nautilus_gtk_window_present (GtkWindow *window) {
gtk_widget_show (GTK_WIDGET (window));
}
static void
sanity_check_window_geometry (int *left, int *top, int *width, int *height)
{
g_assert (left != NULL);
g_assert (top != NULL);
g_assert (width != NULL);
g_assert (height != NULL);
/* Pin the size of the window to the screen, so we don't end up in
* a state where the window is so big essential parts of it can't
* be reached (might not be necessary with all window managers,
* but seems reasonable anyway).
*/
*width = MIN (*width, gdk_screen_width());
*height = MIN (*height, gdk_screen_height());
/* Make sure the top of the window is on screen, for
* draggability (might not be necessary with all window managers,
* but seems reasonable anyway). Make sure the top of the window
* isn't off the bottom of the screen, or so close to the bottom
* that it might be obscured by the panel.
*/
*top = CLAMP (*top, 0, gdk_screen_height() - MINIMUM_ON_SCREEN_HEIGHT);
/* FIXME bugzilla.eazel.com 669:
* If window has negative left coordinate, set_uposition sends it
* somewhere else entirely. Not sure what level contains this bug (XWindows?).
* Hacked around by pinning the left edge to zero, which just means you
* can't set a window to be partly off the left of the screen using
* this routine.
*/
/* Make sure the left edge of the window isn't off the right edge of
* the screen, or so close to the right edge that it might be
* obscured by the panel.
*/
*left = CLAMP (*left, 0, gdk_screen_width() - MINIMUM_ON_SCREEN_WIDTH);
}
/**
* nautilus_gtk_window_set_initial_geometry:
*
* Sets the position and size of a GtkWindow before the
* GtkWindow is shown. It is an error to call this on a window that
* is already on-screen. Takes into account screen size, and does
* some sanity-checking on the passed-in values.
*
* @window: A non-visible GtkWindow
* @left: pixel coordinate for left of window
* @top: pixel coordinate for top of window
* @width: width of window in pixels
* @height: height of window in pixels
*/
void
nautilus_gtk_window_set_initial_geometry (GtkWindow *window,
int left,
int top,
int width,
int height)
{
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (width > 0 && height > 0);
/* Setting the default size doesn't work when the window is already showing.
* Someday we could make this move an already-showing window, but we don't
* need that functionality yet.
*/
g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
sanity_check_window_geometry (&left, &top, &width, &height);
gtk_widget_set_uposition (GTK_WIDGET (window), left, top);
gtk_window_set_default_size (GTK_WINDOW (window), width, height);
}
/**
* nautilus_gtk_window_set_initial_geometry_from_string:
*
* Sets the position and size of a GtkWindow before the
* GtkWindow is shown. The geometry is passed in as a string.
* It is an error to call this on a window that
* is already on-screen. Takes into account screen size, and does
* some sanity-checking on the passed-in values.
*
* @window: A non-visible GtkWindow
* @geometry_string: A string suitable for use with gnome_parse_geometry
* @minimum_width: If the width from the string is smaller than this,
* use this for the width.
* @minimum_height: If the height from the string is smaller than this,
* use this for the height.
*/
void
nautilus_gtk_window_set_initial_geometry_from_string (GtkWindow *window,
const char *geometry_string,
guint minimum_width,
guint minimum_height)
{
int left, top, width, height;
gboolean parsed;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (geometry_string != NULL);
/* Setting the default size doesn't work when the window is already showing.
* Someday we could make this move an already-showing window, but we don't
* need that functionality yet.
*/
g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
parsed = gnome_parse_geometry (geometry_string, &left, &top, &width, &height);
/* Bogus string, dude. */
g_return_if_fail (parsed);
/* Make sure the window isn't smaller than makes sense for this window.
* Other sanity checks are performed in set_initial_geometry.
*/
width = MAX (width, minimum_width);
height = MAX (height, minimum_height);
nautilus_gtk_window_set_initial_geometry (window, left, top, width, height);
}
/**
* nautilus_gtk_selection_data_copy_deep:
*
......
......@@ -93,6 +93,16 @@ GtkWidget * nautilus_gtk_widget_find_windowed_ancestor (GtkWidget
GtkWidget *nautilus_gtk_container_get_first_child (GtkContainer *container);
/* GtkWindow */
void nautilus_gtk_window_set_initial_geometry (GtkWindow *window,
int left,
int top,
int width,
int height);
void nautilus_gtk_window_set_initial_geometry_from_string
(GtkWindow *window,
const char *geometry_string,
guint minimum_width,
guint minimum_height);
void nautilus_gtk_window_present (GtkWindow *window);
/* selection data */
......
......@@ -45,6 +45,8 @@
#define NAUTILUS_METADATA_KEY_EXPLICIT_COMPONENT "EXPLICIT_CONTENT_VIEW"
#define NAUTILUS_METADATA_SUBKEY_COMPONENT_IID "IID"
#define NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY "WINDOW_GEOMETRY"
#define NAUTILUS_METADATA_KEY_DIRECTORY_BACKGROUND_COLOR "BACKGROUND_COLOR"
#define NAUTILUS_METADATA_KEY_DIRECTORY_BACKGROUND_IMAGE "BACKGROUND_TILE_IMAGE"
......
......@@ -44,6 +44,12 @@
*/
#define MAXIMUM_MENU_TITLE_LENGTH 48
/* Used for window position & size sanity-checking. The sizes are big enough to prevent
* at least normal-sized gnome panels from obscuring the window at the screen edges.
*/
#define MINIMUM_ON_SCREEN_WIDTH 100
#define MINIMUM_ON_SCREEN_HEIGHT 100
static gboolean
finish_button_activation (gpointer data)
{
......@@ -306,6 +312,129 @@ nautilus_gtk_window_present (GtkWindow *window) {
gtk_widget_show (GTK_WIDGET (window));
}
static void
sanity_check_window_geometry (int *left, int *top, int *width, int *height)
{
g_assert (left != NULL);
g_assert (top != NULL);
g_assert (width != NULL);
g_assert (height != NULL);
/* Pin the size of the window to the screen, so we don't end up in
* a state where the window is so big essential parts of it can't
* be reached (might not be necessary with all window managers,
* but seems reasonable anyway).
*/
*width = MIN (*width, gdk_screen_width());
*height = MIN (*height, gdk_screen_height());
/* Make sure the top of the window is on screen, for
* draggability (might not be necessary with all window managers,
* but seems reasonable anyway). Make sure the top of the window
* isn't off the bottom of the screen, or so close to the bottom
* that it might be obscured by the panel.
*/
*top = CLAMP (*top, 0, gdk_screen_height() - MINIMUM_ON_SCREEN_HEIGHT);
/* FIXME bugzilla.eazel.com 669:
* If window has negative left coordinate, set_uposition sends it
* somewhere else entirely. Not sure what level contains this bug (XWindows?).
* Hacked around by pinning the left edge to zero, which just means you
* can't set a window to be partly off the left of the screen using
* this routine.
*/
/* Make sure the left edge of the window isn't off the right edge of
* the screen, or so close to the right edge that it might be
* obscured by the panel.
*/
*left = CLAMP (*left, 0, gdk_screen_width() - MINIMUM_ON_SCREEN_WIDTH);
}
/**
* nautilus_gtk_window_set_initial_geometry:
*
* Sets the position and size of a GtkWindow before the
* GtkWindow is shown. It is an error to call this on a window that
* is already on-screen. Takes into account screen size, and does
* some sanity-checking on the passed-in values.
*
* @window: A non-visible GtkWindow
* @left: pixel coordinate for left of window
* @top: pixel coordinate for top of window
* @width: width of window in pixels
* @height: height of window in pixels
*/
void
nautilus_gtk_window_set_initial_geometry (GtkWindow *window,
int left,
int top,
int width,
int height)
{
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (width > 0 && height > 0);
/* Setting the default size doesn't work when the window is already showing.
* Someday we could make this move an already-showing window, but we don't
* need that functionality yet.
*/
g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
sanity_check_window_geometry (&left, &top, &width, &height);
gtk_widget_set_uposition (GTK_WIDGET (window), left, top);
gtk_window_set_default_size (GTK_WINDOW (window), width, height);
}
/**
* nautilus_gtk_window_set_initial_geometry_from_string:
*
* Sets the position and size of a GtkWindow before the
* GtkWindow is shown. The geometry is passed in as a string.
* It is an error to call this on a window that
* is already on-screen. Takes into account screen size, and does
* some sanity-checking on the passed-in values.
*
* @window: A non-visible GtkWindow
* @geometry_string: A string suitable for use with gnome_parse_geometry
* @minimum_width: If the width from the string is smaller than this,
* use this for the width.
* @minimum_height: If the height from the string is smaller than this,
* use this for the height.
*/
void
nautilus_gtk_window_set_initial_geometry_from_string (GtkWindow *window,
const char *geometry_string,
guint minimum_width,
guint minimum_height)
{
int left, top, width, height;
gboolean parsed;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (geometry_string != NULL);
/* Setting the default size doesn't work when the window is already showing.
* Someday we could make this move an already-showing window, but we don't
* need that functionality yet.
*/
g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
parsed = gnome_parse_geometry (geometry_string, &left, &top, &width, &height);
/* Bogus string, dude. */
g_return_if_fail (parsed);
/* Make sure the window isn't smaller than makes sense for this window.
* Other sanity checks are performed in set_initial_geometry.
*/
width = MAX (width, minimum_width);
height = MAX (height, minimum_height);
nautilus_gtk_window_set_initial_geometry (window, left, top, width, height);
}
/**
* nautilus_gtk_selection_data_copy_deep:
*
......
......@@ -93,6 +93,16 @@ GtkWidget * nautilus_gtk_widget_find_windowed_ancestor (GtkWidget
GtkWidget *nautilus_gtk_container_get_first_child (GtkContainer *container);
/* GtkWindow */
void nautilus_gtk_window_set_initial_geometry (GtkWindow *window,
int left,
int top,
int width,
int height);
void nautilus_gtk_window_set_initial_geometry_from_string
(GtkWindow *window,
const char *geometry_string,
guint minimum_width,
guint minimum_height);
void nautilus_gtk_window_present (GtkWindow *window);
/* selection data */
......
......@@ -45,6 +45,8 @@
#define NAUTILUS_METADATA_KEY_EXPLICIT_COMPONENT "EXPLICIT_CONTENT_VIEW"
#define NAUTILUS_METADATA_SUBKEY_COMPONENT_IID "IID"
#define NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY "WINDOW_GEOMETRY"
#define NAUTILUS_METADATA_KEY_DIRECTORY_BACKGROUND_COLOR "BACKGROUND_COLOR"
#define NAUTILUS_METADATA_KEY_DIRECTORY_BACKGROUND_IMAGE "BACKGROUND_TILE_IMAGE"
......
......@@ -468,6 +468,19 @@ nautilus_application_destroyed_window (GtkObject *object, NautilusApplication *a
nautilus_application_window_list = g_slist_remove (nautilus_application_window_list, object);
}
static gboolean
nautilus_window_delete_event_callback (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
NautilusWindow *window;
window = NAUTILUS_WINDOW (widget);
nautilus_window_close (window);
return TRUE;
}
NautilusWindow *
nautilus_application_create_window (NautilusApplication *application)
{
......@@ -478,6 +491,11 @@ nautilus_application_create_window (NautilusApplication *application)
window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type (),
"app", GTK_OBJECT (application),
"app_id", "nautilus", NULL));
gtk_signal_connect (GTK_OBJECT (window),
"delete_event", GTK_SIGNAL_FUNC (nautilus_window_delete_event_callback),
NULL);
gtk_signal_connect (GTK_OBJECT (window),
"destroy", nautilus_application_destroyed_window,
application);
......
......@@ -103,12 +103,6 @@ static void update_built_in_bookmarks_preference_to_match_checkbox (gpointer use
#define BOOKMARKS_WINDOW_INITIAL_WIDTH 500
#define BOOKMARKS_WINDOW_INITIAL_HEIGHT 200
/* Used for window position & size sanity-checking. The sizes are big enough to prevent
* at least normal-sized gnome panels from obscuring the window at the screen edges.
*/
#define MINIMUM_ON_SCREEN_WIDTH 100
#define MINIMUM_ON_SCREEN_HEIGHT 100
/**
* create_bookmarks_window:
......@@ -341,46 +335,22 @@ nautilus_bookmarks_window_restore_geometry (GtkWidget *window)
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
window_geometry = nautilus_bookmark_list_get_window_geometry(bookmarks);
window_geometry = nautilus_bookmark_list_get_window_geometry (bookmarks);
if (window_geometry != NULL)
{
int left, top, width, height;
if (gnome_parse_geometry (window_geometry, &left, &top, &width, &height))
{
/* Adjust for sanity, in case screen size has changed or
* stored numbers are bogus. Make the entire window fit
* on the screen, so all controls can be reached. Also
* make sure the window isn't ridiculously small. Also
* make sure the top of the window is on screen, for
* draggability (perhaps not absolutely required, depending
* on window manager, but seems like a sensible rule anyway).
*/
width = CLAMP (width, BOOKMARKS_WINDOW_MIN_WIDTH, gdk_screen_width());
height = CLAMP (height, BOOKMARKS_WINDOW_MIN_HEIGHT, gdk_screen_height());
top = CLAMP (top, 0, gdk_screen_height() - MINIMUM_ON_SCREEN_HEIGHT);
/* FIXME bugzilla.eazel.com 669:
* If window has negative left coordinate, set_uposition sends it
* somewhere else entirely. Not sure what level contains this bug (XWindows?).
* Hacked around by pinning the left edge to zero.
*/
left = CLAMP (left, 0, gdk_screen_width() - MINIMUM_ON_SCREEN_WIDTH);
gtk_widget_set_uposition (window, left, top);
gtk_window_set_default_size (GTK_WINDOW (window), width, height);
return;
}
}
nautilus_gtk_window_set_initial_geometry_from_string
(GTK_WINDOW (window), window_geometry,
BOOKMARKS_WINDOW_MIN_WIDTH, BOOKMARKS_WINDOW_MIN_HEIGHT);
/* fall through to default if necessary */
gtk_window_set_default_size (GTK_WINDOW (window),
BOOKMARKS_WINDOW_INITIAL_WIDTH,
BOOKMARKS_WINDOW_INITIAL_HEIGHT);
} else {
/* use default since there was no stored geometry */
gtk_window_set_default_size (GTK_WINDOW (window),
BOOKMARKS_WINDOW_INITIAL_WIDTH,
BOOKMARKS_WINDOW_INITIAL_HEIGHT);
/* Let window manager handle default position if no position stored */
/* Let window manager handle default position if no position stored */
}
}
/**
......
......@@ -199,7 +199,6 @@ file_menu_new_window_callback (BonoboUIHandler *ui_handler,
current_window = NAUTILUS_WINDOW (user_data);
new_window = nautilus_application_create_window (current_window->application);
nautilus_window_goto_uri (new_window, current_window->location);
gtk_widget_show (GTK_WIDGET (new_window));
}
static void
......
......@@ -77,13 +77,6 @@
/* default web search uri - FIXME bugzilla.eazel.com 2465: this will be changed to point to the Eazel service */
#define DEFAULT_SEARCH_WEB_URI "http://www.google.com"
/* window geometry */
#define NAUTILUS_WINDOW_MIN_WIDTH 450
#define NAUTILUS_WINDOW_MIN_HEIGHT 350
#define NAUTILUS_WINDOW_DEFAULT_WIDTH 700
#define NAUTILUS_WINDOW_DEFAULT_HEIGHT 550
enum {
ARG_0,
......@@ -575,10 +568,39 @@ nautilus_window_destroy (GtkObject *object)
}
}
static void
nautilus_window_save_geometry (NautilusWindow *window)
{
NautilusDirectory *directory;
char *geometry_string;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
g_return_if_fail (GTK_WIDGET_VISIBLE (window));
directory = nautilus_directory_get (window->location);
geometry_string = gnome_geometry_string (GTK_WIDGET (window)->window);
nautilus_directory_set_metadata (directory,
NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY,
NULL,
geometry_string);
g_free (geometry_string);
nautilus_directory_unref (directory);
}
void
nautilus_window_close (NautilusWindow *window)
{
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
/* Save the window position in the directory's metadata only if
* we're in every-location-in-its-own-window mode. Otherwise it
* would be too apparently random when the stored positions change.
*/
if (nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_WINDOW_ALWAYS_NEW,
FALSE)) {
nautilus_window_save_geometry (window);
}
gtk_widget_destroy (GTK_WIDGET (window));
}
......
......@@ -77,13 +77,6 @@
/* default web search uri - FIXME bugzilla.eazel.com 2465: this will be changed to point to the Eazel service */
#define DEFAULT_SEARCH_WEB_URI "http://www.google.com"
/* window geometry */
#define NAUTILUS_WINDOW_MIN_WIDTH 450
#define NAUTILUS_WINDOW_MIN_HEIGHT 350
#define NAUTILUS_WINDOW_DEFAULT_WIDTH 700
#define NAUTILUS_WINDOW_DEFAULT_HEIGHT 550
enum {
ARG_0,
......@@ -575,10 +568,39 @@ nautilus_window_destroy (GtkObject *object)
}
}
static void
nautilus_window_save_geometry (NautilusWindow *window)
{
NautilusDirectory *directory;
char *geometry_string;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
g_return_if_fail (GTK_WIDGET_VISIBLE (window));
directory = nautilus_directory_get (window->location);
geometry_string = gnome_geometry_string (GTK_WIDGET (window)->window);
nautilus_directory_set_metadata (directory,
NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY,
NULL,
geometry_string);
g_free (geometry_string);
nautilus_directory_unref (directory);
}