]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-geometry.c
account-widget-sip: add UI to configure the keepalive-mechanism and keepalive-interva...
[empathy.git] / libempathy-gtk / empathy-geometry.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
19  *
20  * Authors: Martyn Russell <martyn@imendio.com>
21  *          Xavier Claessens <xclaesse@gmail.com>
22  */
23
24 #include "config.h"
25
26 #include <sys/stat.h>
27
28 #include <glib.h>
29 #include <gdk/gdk.h>
30
31 #include "libempathy/empathy-utils.h"
32 #include "empathy-geometry.h"
33
34 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
35 #include <libempathy/empathy-debug.h>
36
37 #define GEOMETRY_DIR_CREATE_MODE  (S_IRUSR | S_IWUSR | S_IXUSR)
38 #define GEOMETRY_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
39
40 #define GEOMETRY_KEY_FILENAME         "geometry.ini"
41 #define GEOMETRY_FORMAT               "%d,%d,%d,%d"
42 #define GEOMETRY_GROUP_NAME           "geometry"
43 #define GEOMETRY_MAXIMIZED_GROUP_NAME "maximized"
44
45 static guint store_id = 0;
46
47 static void
48 geometry_real_store (GKeyFile *key_file)
49 {
50   gchar *filename;
51   gchar *content;
52   gsize length;
53   GError *error = NULL;
54
55   content = g_key_file_to_data (key_file, &length, &error);
56   if (error != NULL)
57     {
58       DEBUG ("Error: %s", error->message);
59       g_error_free (error);
60       return;
61     }
62
63   filename = g_build_filename (g_get_user_config_dir (),
64     PACKAGE_NAME, GEOMETRY_KEY_FILENAME, NULL);
65
66   if (!g_file_set_contents (filename, content, length, &error))
67     {
68       DEBUG ("Error: %s", error->message);
69       g_error_free (error);
70     }
71
72   g_free (content);
73   g_free (filename);
74 }
75
76 static gboolean
77 geometry_store_cb (gpointer key_file)
78 {
79   geometry_real_store (key_file);
80   store_id = 0;
81
82   return FALSE;
83 }
84
85 static void
86 geometry_schedule_store (GKeyFile *key_file)
87 {
88   if (store_id != 0)
89     g_source_remove (store_id);
90
91   store_id = g_timeout_add_seconds (1, geometry_store_cb, key_file);
92 }
93
94 static GKeyFile *
95 geometry_get_key_file (void)
96 {
97   static GKeyFile *key_file = NULL;
98   gchar *dir;
99   gchar *filename;
100
101   if (key_file != NULL)
102     return key_file;
103
104   dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
105   if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
106     {
107       DEBUG ("Creating directory:'%s'", dir);
108       g_mkdir_with_parents (dir, GEOMETRY_DIR_CREATE_MODE);
109     }
110
111   filename = g_build_filename (dir, GEOMETRY_KEY_FILENAME, NULL);
112   g_free (dir);
113
114   key_file = g_key_file_new ();
115   g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
116   g_free (filename);
117
118   return key_file;
119 }
120
121 void
122 empathy_geometry_save (GtkWindow *window,
123     const gchar *name)
124 {
125   GKeyFile *key_file;
126   GdkWindow *gdk_window;
127   GdkWindowState window_state;
128   gchar *escaped_name;
129   gint x, y, w, h;
130   gboolean maximized;
131
132   g_return_if_fail (GTK_IS_WINDOW (window));
133   g_return_if_fail (!EMP_STR_EMPTY (name));
134
135   /* escape the name so that unwanted characters such as # are removed */
136   escaped_name = g_uri_escape_string (name, NULL, TRUE);
137
138   /* Get window geometry */
139   gtk_window_get_position (window, &x, &y);
140   gtk_window_get_size (window, &w, &h);
141   gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
142   window_state = gdk_window_get_state (gdk_window);
143   maximized = (window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
144
145   key_file = geometry_get_key_file ();
146
147   /* Save window size only if not maximized */
148   if (!maximized)
149     {
150       gchar *str;
151
152       str = g_strdup_printf (GEOMETRY_FORMAT, x, y, w, h);
153       g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, escaped_name, str);
154       g_free (str);
155     }
156
157   g_key_file_set_boolean (key_file, GEOMETRY_MAXIMIZED_GROUP_NAME,
158         escaped_name, maximized);
159
160   geometry_schedule_store (key_file);
161 }
162
163 void
164 empathy_geometry_load (GtkWindow *window,
165     const gchar *name)
166 {
167   GKeyFile *key_file;
168   gchar    *escaped_name;
169   gchar    *str;
170   gboolean  maximized;
171
172   g_return_if_fail (GTK_IS_WINDOW (window));
173   g_return_if_fail (!EMP_STR_EMPTY (name));
174
175   /* escape the name so that unwanted characters such as # are removed */
176   escaped_name = g_uri_escape_string (name, NULL, TRUE);
177
178   key_file = geometry_get_key_file ();
179
180   /* restore window size and position */
181   str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, escaped_name,
182       NULL);
183   if (str)
184     {
185       gint x, y, w, h;
186
187       sscanf (str, GEOMETRY_FORMAT, &x, &y, &w, &h);
188       gtk_window_move (window, x, y);
189       gtk_window_resize (window, w, h);
190     }
191
192   /* restore window maximized state */
193   maximized = g_key_file_get_boolean (key_file,
194       GEOMETRY_MAXIMIZED_GROUP_NAME,
195       escaped_name, NULL);
196
197   if (maximized)
198     gtk_window_maximize (window);
199   else
200     gtk_window_unmaximize (window);
201
202   g_free (str);
203   g_free (escaped_name);
204 }
205
206 static gboolean
207 geometry_configure_event_cb (GtkWindow *window,
208     GdkEventConfigure *event,
209     gchar *name)
210 {
211   empathy_geometry_save (window, name);
212   return FALSE;
213 }
214
215 static gboolean
216 geometry_window_state_event_cb (GtkWindow *window,
217     GdkEventWindowState *event,
218     gchar *name)
219 {
220   if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0)
221     empathy_geometry_save (window, name);
222
223   return FALSE;
224 }
225
226 void
227 empathy_geometry_bind (GtkWindow *window,
228     const gchar *name)
229 {
230   g_return_if_fail (GTK_IS_WINDOW (window));
231   g_return_if_fail (!EMP_STR_EMPTY (name));
232
233   /* First load initial geometry */
234   empathy_geometry_load (window, name);
235
236   /* Track geometry changes */
237   g_signal_connect_data (window, "configure-event",
238     G_CALLBACK (geometry_configure_event_cb), g_strdup (name),
239     (GClosureNotify) g_free, 0);
240   g_signal_connect_data (window, "window-state-event",
241     G_CALLBACK (geometry_window_state_event_cb), g_strdup (name),
242     (GClosureNotify) g_free, 0);
243 }
244
245 void
246 empathy_geometry_unbind (GtkWindow *window)
247 {
248   g_signal_handlers_disconnect_matched (window,
249     G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
250     geometry_configure_event_cb, NULL);
251   g_signal_handlers_disconnect_matched (window,
252     G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
253     geometry_window_state_event_cb, NULL);
254 }