]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-geometry.c
Merge commit 'staz/dnd'
[empathy.git] / libempathy-gtk / empathy-geometry.c
index d17d22cb998eebf05d4ed6a6c29b2c342ee72d03..9a3e1f79758d4ad84a08b51fb97e3cbefe4d2848 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "libempathy/empathy-utils.h"
 #include "empathy-geometry.h"
+#include "empathy-ui-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
 #include <libempathy/empathy-debug.h>
 #define GEOMETRY_DIR_CREATE_MODE  (S_IRUSR | S_IWUSR | S_IXUSR)
 #define GEOMETRY_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
 
-#define GEOMETRY_KEY_FILENAME         "geometry.ini"
-#define GEOMETRY_FORMAT               "%d,%d,%d,%d"
-#define GEOMETRY_GROUP_NAME           "geometry"
-#define GEOMETRY_MAXIMIZED_GROUP_NAME "maximized"
+/* geometry.ini file contains 2 groups:
+ *  - one with position and size of each window
+ *  - one with the maximized state of each window
+ * Windows are identified by a name. (e.g. "main-window") */
+#define GEOMETRY_FILENAME             "geometry.ini"
+#define GEOMETRY_POSITION_FORMAT      "%d,%d,%d,%d" /* "x,y,w,h" */
+#define GEOMETRY_POSITION_GROUP       "geometry"
+#define GEOMETRY_MAXIMIZED_GROUP      "maximized"
+
+/* Key used to keep window's name inside the object's qdata */
+#define GEOMETRY_NAME_KEY             "geometry-name-key"
 
 static guint store_id = 0;
 
@@ -61,7 +69,7 @@ geometry_real_store (GKeyFile *key_file)
     }
 
   filename = g_build_filename (g_get_user_config_dir (),
-    PACKAGE_NAME, GEOMETRY_KEY_FILENAME, NULL);
+    PACKAGE_NAME, GEOMETRY_FILENAME, NULL);
 
   if (!g_file_set_contents (filename, content, length, &error))
     {
@@ -108,7 +116,7 @@ geometry_get_key_file (void)
       g_mkdir_with_parents (dir, GEOMETRY_DIR_CREATE_MODE);
     }
 
-  filename = g_build_filename (dir, GEOMETRY_KEY_FILENAME, NULL);
+  filename = g_build_filename (dir, GEOMETRY_FILENAME, NULL);
   g_free (dir);
 
   key_file = g_key_file_new ();
@@ -132,6 +140,9 @@ empathy_geometry_save (GtkWindow *window,
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (!EMP_STR_EMPTY (name));
 
+  if (!GTK_WIDGET_VISIBLE (window))
+    return;
+
   /* escape the name so that unwanted characters such as # are removed */
   escaped_name = g_uri_escape_string (name, NULL, TRUE);
 
@@ -143,9 +154,7 @@ empathy_geometry_save (GtkWindow *window,
   maximized = (window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
 
   /* Don't save off-screen positioning */
-  if (x + w < 0 || y + h < 0 ||
-      x > gdk_screen_width () ||
-      y > gdk_screen_height ())
+  if (!EMPATHY_RECT_IS_ON_SCREEN (x, y, w, h))
     return;
 
   key_file = geometry_get_key_file ();
@@ -155,13 +164,14 @@ empathy_geometry_save (GtkWindow *window,
     {
       gchar *str;
 
-      str = g_strdup_printf (GEOMETRY_FORMAT, x, y, w, h);
-      g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, escaped_name, str);
+      str = g_strdup_printf (GEOMETRY_POSITION_FORMAT, x, y, w, h);
+      g_key_file_set_string (key_file, GEOMETRY_POSITION_GROUP,
+          escaped_name, str);
       g_free (str);
     }
 
-  g_key_file_set_boolean (key_file, GEOMETRY_MAXIMIZED_GROUP_NAME,
-        escaped_name, maximized);
+  g_key_file_set_boolean (key_file, GEOMETRY_MAXIMIZED_GROUP,
+      escaped_name, maximized);
 
   geometry_schedule_store (key_file);
 }
@@ -184,20 +194,19 @@ empathy_geometry_load (GtkWindow *window,
   key_file = geometry_get_key_file ();
 
   /* restore window size and position */
-  str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, escaped_name,
-      NULL);
+  str = g_key_file_get_string (key_file, GEOMETRY_POSITION_GROUP,
+      escaped_name, NULL);
   if (str)
     {
       gint x, y, w, h;
 
-      sscanf (str, GEOMETRY_FORMAT, &x, &y, &w, &h);
+      sscanf (str, GEOMETRY_POSITION_FORMAT, &x, &y, &w, &h);
       gtk_window_move (window, x, y);
       gtk_window_resize (window, w, h);
     }
 
   /* restore window maximized state */
-  maximized = g_key_file_get_boolean (key_file,
-      GEOMETRY_MAXIMIZED_GROUP_NAME,
+  maximized = g_key_file_get_boolean (key_file, GEOMETRY_MAXIMIZED_GROUP,
       escaped_name, NULL);
 
   if (maximized)
@@ -212,49 +221,82 @@ empathy_geometry_load (GtkWindow *window,
 static gboolean
 geometry_configure_event_cb (GtkWindow *window,
     GdkEventConfigure *event,
-    gchar *name)
+    gpointer user_data)
 {
+  gchar *name;
+
+  name = g_object_get_data (G_OBJECT (window), GEOMETRY_NAME_KEY);
   empathy_geometry_save (window, name);
+
   return FALSE;
 }
 
 static gboolean
 geometry_window_state_event_cb (GtkWindow *window,
     GdkEventWindowState *event,
-    gchar *name)
+    gpointer user_data)
 {
   if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0)
-    empathy_geometry_save (window, name);
+    {
+      gchar *name;
+
+      name = g_object_get_data (G_OBJECT (window), GEOMETRY_NAME_KEY);
+      empathy_geometry_save (window, name);
+    }
 
   return FALSE;
 }
 
+static void
+geometry_map_cb (GtkWindow *window,
+    gpointer user_data)
+{
+  gchar *name;
+
+  /* The WM will replace this window, restore its last position */
+  name = g_object_get_data (G_OBJECT (window), GEOMETRY_NAME_KEY);
+  empathy_geometry_load (window, name);
+}
+
 void
 empathy_geometry_bind (GtkWindow *window,
     const gchar *name)
 {
+  gchar *str;
+
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (!EMP_STR_EMPTY (name));
 
-  /* First load initial geometry */
+  /* Check if this window is already bound */
+  str = g_object_get_data (G_OBJECT (window), GEOMETRY_NAME_KEY);
+  if (str != NULL)
+    return;
+
+  /* Store the geometry name in the window's data */
+  str = g_strdup (name);
+  g_object_set_data_full (G_OBJECT (window), GEOMETRY_NAME_KEY, str, g_free);
+
+  /* Load initial geometry */
   empathy_geometry_load (window, name);
 
   /* Track geometry changes */
-  g_signal_connect_data (window, "configure-event",
-    G_CALLBACK (geometry_configure_event_cb), g_strdup (name),
-    (GClosureNotify) g_free, 0);
-  g_signal_connect_data (window, "window-state-event",
-    G_CALLBACK (geometry_window_state_event_cb), g_strdup (name),
-    (GClosureNotify) g_free, 0);
+  g_signal_connect (window, "configure-event",
+    G_CALLBACK (geometry_configure_event_cb), NULL);
+  g_signal_connect (window, "window-state-event",
+    G_CALLBACK (geometry_window_state_event_cb), NULL);
+  g_signal_connect (window, "map",
+    G_CALLBACK (geometry_map_cb), NULL);
 }
 
 void
 empathy_geometry_unbind (GtkWindow *window)
 {
-  g_signal_handlers_disconnect_matched (window,
-    G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+  g_signal_handlers_disconnect_by_func (window,
     geometry_configure_event_cb, NULL);
-  g_signal_handlers_disconnect_matched (window,
-    G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+  g_signal_handlers_disconnect_by_func (window,
     geometry_window_state_event_cb, NULL);
+  g_signal_handlers_disconnect_by_func (window,
+    geometry_map_cb, NULL);
+
+  g_object_set_data (G_OBJECT (window), GEOMETRY_NAME_KEY, NULL);
 }