[metacity] add option to set window placement mode



commit 5be337ce674fe6cd955bc5c2077e86ad6c642601
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Jan 8 16:33:23 2014 +0200

    add option to set window placement mode
    
    Adapted from patch by Chad Glendenin available at:
    http://chad.glendenin.com/metacity/patch.html

 src/core/place.c                      |   98 ++++++++++++++++++++++++++++++++-
 src/core/prefs.c                      |   24 ++++++--
 src/include/prefs.h                   |   14 ++++-
 src/org.gnome.metacity.gschema.xml.in |   23 ++++++++
 4 files changed, 150 insertions(+), 9 deletions(-)
---
diff --git a/src/core/place.c b/src/core/place.c
index 4c20a3f..f9dc67f 100644
--- a/src/core/place.c
+++ b/src/core/place.c
@@ -639,6 +639,98 @@ find_first_fit (MetaWindow *window,
   return retval;
 }
 
+static gboolean
+find_preferred_position (MetaWindow *window,
+                         MetaFrameGeometry *fgeom,
+                         /* visible windows on relevant workspaces */
+                         GList      *windows,
+                         int         xinerama,
+                         int         x,
+                         int         y,
+                         int        *new_x,
+                         int        *new_y)
+{
+  MetaRectangle rect;
+  MetaRectangle work_area;
+  MetaPlacementMode placement_mode_pref = meta_prefs_get_placement_mode ();
+
+  /* If first_fit placement is the preference, just pass all the
+   * options through to the original find_first_fit function.
+   * Otherwise, process the user preference here.
+   */
+  if (placement_mode_pref == META_PLACEMENT_MODE_SMART)
+    {
+      return find_first_fit (window, fgeom, windows,
+                             xinerama,
+                             x, y, new_x, new_y);
+    }
+  else if (placement_mode_pref == META_PLACEMENT_MODE_CASCADE)
+    {
+      /* This is an abuse of find_next_cascade(), because it was not
+       * intended for this use, and because it is not designed to
+       * deal with placement on multiple Xineramas.
+       */
+      find_next_cascade (window, fgeom, windows, x, y, new_x, new_y);
+      return TRUE;
+    }
+
+  rect.width = window->rect.width;
+  rect.height = window->rect.height;
+
+  if (fgeom)
+    {
+      rect.width += fgeom->left_width + fgeom->right_width;
+      rect.height += fgeom->top_height + fgeom->bottom_height;
+    }
+
+  meta_window_get_work_area_for_xinerama (window, xinerama, &work_area);
+
+  /* Cannot use rect_fits_in_work_area here because that function
+   * also checks the x & y position of rect, but those are not set
+   * yet in this case.
+   */
+  if ((rect.width <= work_area.width) && (rect.height <= work_area.height))
+    {
+      switch (placement_mode_pref)
+        {
+          case META_PLACEMENT_MODE_CENTER:
+            /* This is a plain centering, different from center_tile */
+            *new_x = work_area.x + ((work_area.width - rect.width) / 2);
+            *new_y = work_area.y + ((work_area.height - rect.height) / 2);
+            break;
+
+          case META_PLACEMENT_MODE_ORIGIN:
+            *new_x = work_area.x;
+            *new_y = work_area.y;
+            break;
+
+          case META_PLACEMENT_MODE_RANDOM:
+            *new_x = (int) ((float) (work_area.width - rect.width) *
+                            ((float) rand() / (float) RAND_MAX));
+            *new_y = (int) ((float) (work_area.height - rect.height) *
+                            ((float) rand() / (float) RAND_MAX));
+            *new_x += work_area.x;
+            *new_y += work_area.y;
+            break;
+
+          default:
+            meta_warning ("Unknown window-placement option chosen.\n");
+            return FALSE;
+            break;
+        }
+
+      if (fgeom)
+        {
+          *new_x += fgeom->left_width;
+          *new_y += fgeom->top_height;
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 void
 meta_window_place (MetaWindow        *window,
                    MetaFrameGeometry *fgeom,
@@ -839,9 +931,9 @@ meta_window_place (MetaWindow        *window,
   x = xi->rect.x;
   y = xi->rect.y;
 
-  if (find_first_fit (window, fgeom, windows,
-                      xi->number,
-                      x, y, &x, &y))
+  if (find_preferred_position (window, fgeom, windows,
+                               xi->number,
+                               x, y, &x, &y))
     goto done_check_denied_focus;
 
   /* Maximize windows if they are too big for their work area (bit of
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 7d2ce93..3e93140 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -42,6 +42,7 @@
 #define KEY_NUM_WORKSPACES "num-workspaces"
 #define KEY_WORKSPACE_NAMES "workspace-names"
 #define KEY_COMPOSITOR "compositing-manager"
+#define KEY_PLACEMENT_MODE "placement-mode"
 
 /* Keys from "foreign" schemas */
 #define KEY_GNOME_ACCESSIBILITY "toolkit-accessibility"
@@ -92,6 +93,8 @@ static gboolean force_fullscreen = TRUE;
 static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
 static MetaButtonLayout button_layout;
 
+static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_SMART;
+
 /* NULL-terminated array */
 static char **workspace_names = NULL;
 
@@ -242,6 +245,13 @@ static MetaEnumPreference preferences_enum[] =
       },
       &action_right_click_titlebar,
     },
+    {
+      { "placement-mode",
+        SCHEMA_METACITY,
+        META_PREF_PLACEMENT_MODE,
+      },
+      &placement_mode,
+    },
     { { NULL, 0, 0 }, NULL },
   };
 
@@ -626,7 +636,6 @@ handle_preference_update_int (GSettings *settings,
     }
 }
 
-
 /****************************************************************************/
 /* Listeners.                                                               */
 /****************************************************************************/
@@ -740,7 +749,6 @@ queue_changed (MetaPreference pref)
                                     changed_idle_handler, NULL, NULL);
 }
 
-
 /****************************************************************************/
 /* Initialisation.                                                          */
 /****************************************************************************/
@@ -791,7 +799,6 @@ meta_prefs_init (void)
   init_workspace_names ();
 }
 
-
 /****************************************************************************/
 /* Updates.                                                                 */
 /****************************************************************************/
@@ -925,7 +932,6 @@ meta_prefs_get_cursor_size (void)
   return cursor_size;
 }
 
-
 /****************************************************************************/
 /* Handlers for string preferences.                                         */
 /****************************************************************************/
@@ -1412,6 +1418,9 @@ meta_preference_to_string (MetaPreference pref)
 
     case META_PREF_FORCE_FULLSCREEN:
       return "FORCE_FULLSCREEN";
+
+    case META_PREF_PLACEMENT_MODE:
+      return "PLACEMENT_MODE";
     }
 
   return "(unknown)";
@@ -1822,6 +1831,12 @@ meta_prefs_get_force_fullscreen (void)
   return force_fullscreen;
 }
 
+MetaPlacementMode
+meta_prefs_get_placement_mode (void)
+{
+  return placement_mode;
+}
+
 void
 meta_prefs_set_compositing_manager (gboolean whether)
 {
@@ -1833,4 +1848,3 @@ meta_prefs_set_force_fullscreen (gboolean whether)
 {
   force_fullscreen = whether;
 }
-
diff --git a/src/include/prefs.h b/src/include/prefs.h
index 16fdc8d..c251aba 100644
--- a/src/include/prefs.h
+++ b/src/include/prefs.h
@@ -58,9 +58,19 @@ typedef enum
   META_PREF_CURSOR_SIZE,
   META_PREF_COMPOSITING_MANAGER,
   META_PREF_RESIZE_WITH_RIGHT_BUTTON,
-  META_PREF_FORCE_FULLSCREEN
+  META_PREF_FORCE_FULLSCREEN,
+  META_PREF_PLACEMENT_MODE
 } MetaPreference;
 
+typedef enum
+{
+  META_PLACEMENT_MODE_SMART,
+  META_PLACEMENT_MODE_CASCADE,
+  META_PLACEMENT_MODE_CENTER,
+  META_PLACEMENT_MODE_ORIGIN,
+  META_PLACEMENT_MODE_RANDOM
+} MetaPlacementMode;
+
 typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
                                        gpointer       data);
 
@@ -114,6 +124,8 @@ int         meta_prefs_get_cursor_size       (void);
 gboolean    meta_prefs_get_compositing_manager (void);
 gboolean    meta_prefs_get_force_fullscreen  (void);
 
+MetaPlacementMode meta_prefs_get_placement_mode (void);
+
 /**
  * Sets whether the compositor is turned on.
  *
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index d6cda89..d1fd336 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -1,5 +1,13 @@
 <schemalist>
 
+  <enum id="org.gnome.metacity.MetaPlacementMode">
+    <value nick="smart" value="0" />
+    <value nick="cascade" value="1" />
+    <value nick="center" value="2" />
+    <value nick="origin" value="3" />
+    <value nick="random" value="4" />
+  </enum>
+
   <schema id="org.gnome.metacity" path="/org/gnome/metacity/"
           gettext-domain="@GETTEXT_PACKAGE@">
     <key name="compositing-manager" type="b">
@@ -22,6 +30,21 @@
         However, the wireframe feature is disabled when accessibility is on.
       </_description>
     </key>
+    <key name="placement-mode" enum="org.gnome.metacity.MetaPlacementMode">
+      <default>'smart'</default>
+      <_summary>Window placement behavior</_summary>
+      <_description>
+        Metacity's default window-placement behavior is smart (first-fit),
+        similar to behaviors in some other window managers. It will try to tile
+        windows so that they do not overlap. Set this option to "smart" for this
+        behavior.
+
+        This option can be set to "center" to place new windows in the centers
+        of their workspaces, "origin" for the upper-left corners of the
+        workspaces, or "random" to place new windows at random locations within
+        their workspaces.
+      </_description>
+       </key>
   </schema>
 
 </schemalist>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]