2 * Copyright (C) 2006-2007 Imendio AB
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Martyn Russell <martyn@imendio.com>
21 * Xavier Claessens <xclaesse@gmail.com>
31 #include "libempathy/empathy-utils.h"
32 #include "empathy-geometry.h"
33 #include "empathy-ui-utils.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
36 #include <libempathy/empathy-debug.h>
38 #define GEOMETRY_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR)
39 #define GEOMETRY_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
41 /* geometry.ini file contains 2 groups:
42 * - one with position and size of each window
43 * - one with the maximized state of each window
44 * Windows are identified by a name. (e.g. "main-window") */
45 #define GEOMETRY_FILENAME "geometry.ini"
46 #define GEOMETRY_POSITION_FORMAT "%d,%d,%d,%d" /* "x,y,w,h" */
47 #define GEOMETRY_POSITION_GROUP "geometry"
48 #define GEOMETRY_MAXIMIZED_GROUP "maximized"
50 /* Key used to keep window's name inside the object's qdata */
51 #define GEOMETRY_NAME_KEY "geometry-name-key"
53 static guint store_id
= 0;
56 geometry_real_store (GKeyFile
*key_file
)
63 content
= g_key_file_to_data (key_file
, &length
, &error
);
66 DEBUG ("Error: %s", error
->message
);
71 filename
= g_build_filename (g_get_user_config_dir (),
72 PACKAGE_NAME
, GEOMETRY_FILENAME
, NULL
);
74 if (!g_file_set_contents (filename
, content
, length
, &error
))
76 DEBUG ("Error: %s", error
->message
);
85 geometry_store_cb (gpointer key_file
)
87 geometry_real_store (key_file
);
94 geometry_schedule_store (GKeyFile
*key_file
)
97 g_source_remove (store_id
);
99 store_id
= g_timeout_add_seconds (1, geometry_store_cb
, key_file
);
103 geometry_get_key_file (void)
105 static GKeyFile
*key_file
= NULL
;
109 if (key_file
!= NULL
)
112 dir
= g_build_filename (g_get_user_config_dir (), PACKAGE_NAME
, NULL
);
113 if (!g_file_test (dir
, G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
))
115 DEBUG ("Creating directory:'%s'", dir
);
116 g_mkdir_with_parents (dir
, GEOMETRY_DIR_CREATE_MODE
);
119 filename
= g_build_filename (dir
, GEOMETRY_FILENAME
, NULL
);
122 key_file
= g_key_file_new ();
123 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, NULL
);
130 empathy_geometry_save (GtkWindow
*window
,
134 GdkWindow
*gdk_window
;
135 GdkWindowState window_state
;
140 g_return_if_fail (GTK_IS_WINDOW (window
));
141 g_return_if_fail (!EMP_STR_EMPTY (name
));
143 if (!GTK_WIDGET_VISIBLE (window
))
146 /* escape the name so that unwanted characters such as # are removed */
147 escaped_name
= g_uri_escape_string (name
, NULL
, TRUE
);
149 /* Get window geometry */
150 gtk_window_get_position (window
, &x
, &y
);
151 gtk_window_get_size (window
, &w
, &h
);
152 gdk_window
= gtk_widget_get_window (GTK_WIDGET (window
));
153 window_state
= gdk_window_get_state (gdk_window
);
154 maximized
= (window_state
& GDK_WINDOW_STATE_MAXIMIZED
) != 0;
156 /* Don't save off-screen positioning */
157 if (!EMPATHY_RECT_IS_ON_SCREEN (x
, y
, w
, h
))
160 key_file
= geometry_get_key_file ();
162 /* Save window size only if not maximized */
167 str
= g_strdup_printf (GEOMETRY_POSITION_FORMAT
, x
, y
, w
, h
);
168 g_key_file_set_string (key_file
, GEOMETRY_POSITION_GROUP
,
173 g_key_file_set_boolean (key_file
, GEOMETRY_MAXIMIZED_GROUP
,
174 escaped_name
, maximized
);
176 geometry_schedule_store (key_file
);
180 empathy_geometry_load (GtkWindow
*window
,
188 g_return_if_fail (GTK_IS_WINDOW (window
));
189 g_return_if_fail (!EMP_STR_EMPTY (name
));
191 /* escape the name so that unwanted characters such as # are removed */
192 escaped_name
= g_uri_escape_string (name
, NULL
, TRUE
);
194 key_file
= geometry_get_key_file ();
196 /* restore window size and position */
197 str
= g_key_file_get_string (key_file
, GEOMETRY_POSITION_GROUP
,
203 sscanf (str
, GEOMETRY_POSITION_FORMAT
, &x
, &y
, &w
, &h
);
204 gtk_window_move (window
, x
, y
);
205 gtk_window_resize (window
, w
, h
);
208 /* restore window maximized state */
209 maximized
= g_key_file_get_boolean (key_file
, GEOMETRY_MAXIMIZED_GROUP
,
213 gtk_window_maximize (window
);
215 gtk_window_unmaximize (window
);
218 g_free (escaped_name
);
222 geometry_configure_event_cb (GtkWindow
*window
,
223 GdkEventConfigure
*event
,
228 name
= g_object_get_data (G_OBJECT (window
), GEOMETRY_NAME_KEY
);
229 empathy_geometry_save (window
, name
);
235 geometry_window_state_event_cb (GtkWindow
*window
,
236 GdkEventWindowState
*event
,
239 if ((event
->changed_mask
& GDK_WINDOW_STATE_MAXIMIZED
) != 0)
243 name
= g_object_get_data (G_OBJECT (window
), GEOMETRY_NAME_KEY
);
244 empathy_geometry_save (window
, name
);
251 geometry_map_cb (GtkWindow
*window
,
256 /* The WM will replace this window, restore its last position */
257 name
= g_object_get_data (G_OBJECT (window
), GEOMETRY_NAME_KEY
);
258 empathy_geometry_load (window
, name
);
262 empathy_geometry_bind (GtkWindow
*window
,
267 g_return_if_fail (GTK_IS_WINDOW (window
));
268 g_return_if_fail (!EMP_STR_EMPTY (name
));
270 /* Check if this window is already bound */
271 str
= g_object_get_data (G_OBJECT (window
), GEOMETRY_NAME_KEY
);
275 /* Store the geometry name in the window's data */
276 str
= g_strdup (name
);
277 g_object_set_data_full (G_OBJECT (window
), GEOMETRY_NAME_KEY
, str
, g_free
);
279 /* Load initial geometry */
280 empathy_geometry_load (window
, name
);
282 /* Track geometry changes */
283 g_signal_connect (window
, "configure-event",
284 G_CALLBACK (geometry_configure_event_cb
), NULL
);
285 g_signal_connect (window
, "window-state-event",
286 G_CALLBACK (geometry_window_state_event_cb
), NULL
);
287 g_signal_connect (window
, "map",
288 G_CALLBACK (geometry_map_cb
), NULL
);
292 empathy_geometry_unbind (GtkWindow
*window
)
294 g_signal_handlers_disconnect_by_func (window
,
295 geometry_configure_event_cb
, NULL
);
296 g_signal_handlers_disconnect_by_func (window
,
297 geometry_window_state_event_cb
, NULL
);
298 g_signal_handlers_disconnect_by_func (window
,
299 geometry_map_cb
, NULL
);
301 g_object_set_data (G_OBJECT (window
), GEOMETRY_NAME_KEY
, NULL
);