diff -urN metacity-2.20.2/src/common.h metacity-2.20.2.patched/src/common.h --- metacity-2.20.2/src/common.h 2008-01-08 01:39:42.000000000 +0200 +++ metacity-2.20.2.patched/src/common.h 2008-02-02 14:06:27.000000000 +0200 @@ -33,6 +33,15 @@ typedef enum { + META_PLACEMENT_MODE_FIRST_FIT, + META_PLACEMENT_MODE_CASCADE, + META_PLACEMENT_MODE_CENTER, + META_PLACEMENT_MODE_ORIGIN, + META_PLACEMENT_MODE_RANDOM +} MetaPlacementMode; + +typedef enum +{ META_FRAME_ALLOWS_DELETE = 1 << 0, META_FRAME_ALLOWS_MENU = 1 << 1, META_FRAME_ALLOWS_MINIMIZE = 1 << 2, diff -urN metacity-2.20.2/src/metacity.schemas.in metacity-2.20.2.patched/src/metacity.schemas.in --- metacity-2.20.2/src/metacity.schemas.in 2008-01-08 01:39:42.000000000 +0200 +++ metacity-2.20.2.patched/src/metacity.schemas.in 2008-02-02 14:45:47.000000000 +0200 @@ -2299,6 +2299,30 @@ + + /schemas/apps/metacity/general/placement_mode + /apps/metacity/general/placement_mode + metacity + string + first_fit + + Window placement behavior + + Metacity's default window-placement behavior is first-fit, + similar to the "smart" window-placement behaviors in some + other window managers. It will try to tile windows so that + they do not overlap. Set this option to "first_fit" for + this behavior. + + This option can be set to "center" to place new windows in + the centers of their workspaces, "cascade" to place new + windows in cascade style, "origin" for the upper-left + corners of the workspaces, or "random" to place new + windows at random locations within their workspaces. + + + + diff -urN metacity-2.20.2/src/place.c metacity-2.20.2.patched/src/place.c --- metacity-2.20.2/src/place.c 2008-01-08 01:39:41.000000000 +0200 +++ metacity-2.20.2.patched/src/place.c 2008-02-02 14:54:43.000000000 +0200 @@ -641,6 +641,103 @@ 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; + int i; + 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_FIRST_FIT) + { + return find_first_fit (window, fgeom, windows, + //xineramas_list, n_xineramas, + 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. + * Hristo: now we do not use 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, @@ -841,9 +938,9 @@ 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 -urN metacity-2.20.2/src/prefs.c metacity-2.20.2.patched/src/prefs.c --- metacity-2.20.2/src/prefs.c 2008-01-08 01:39:41.000000000 +0200 +++ metacity-2.20.2.patched/src/prefs.c 2008-02-02 14:28:58.000000000 +0200 @@ -44,6 +44,7 @@ */ #define KEY_MOUSE_BUTTON_MODS "/apps/metacity/general/mouse_button_modifier" #define KEY_FOCUS_MODE "/apps/metacity/general/focus_mode" +#define KEY_PLACEMENT_MODE "/apps/metacity/general/placement_mode" #define KEY_FOCUS_NEW_WINDOWS "/apps/metacity/general/focus_new_windows" #define KEY_RAISE_ON_CLICK "/apps/metacity/general/raise_on_click" #define KEY_ACTION_DOUBLE_CLICK_TITLEBAR "/apps/metacity/general/action_double_click_titlebar" @@ -90,6 +91,7 @@ static MetaVirtualModifier mouse_button_mods = Mod1Mask; static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK; static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART; +static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_FIRST_FIT; static gboolean raise_on_click = TRUE; static char* current_theme = NULL; static int num_workspaces = 4; @@ -124,6 +126,7 @@ static gboolean update_mouse_button_mods (const char *value); static gboolean update_focus_mode (const char *value); static gboolean update_focus_new_windows (const char *value); +static gboolean update_placement_mode (const char *value); static gboolean update_raise_on_click (gboolean value); static gboolean update_theme (const char *value); static gboolean update_visual_bell (gboolean v1, gboolean v2); @@ -413,6 +416,12 @@ update_focus_new_windows (str_val); g_free (str_val); + str_val = gconf_client_get_string (default_client, KEY_PLACEMENT_MODE, + &err); + cleanup_error (&err); + update_placement_mode (str_val); + g_free (str_val); + if (get_bool (KEY_RAISE_ON_CLICK, &bool_val)) update_raise_on_click (bool_val); @@ -639,6 +648,22 @@ if (update_focus_new_windows (str)) queue_changed (META_PREF_FOCUS_NEW_WINDOWS); } + else if (strcmp (key, KEY_PLACEMENT_MODE) == 0) + { + const char *str; + + if (value && value->type != GCONF_VALUE_STRING) + { + meta_warning (_("GConf key \"%s\" is set to an invalid type\n"), + KEY_PLACEMENT_MODE); + goto out; + } + + str = value ? gconf_value_get_string (value) : NULL; + + if (update_placement_mode (str)) + queue_changed (META_PREF_PLACEMENT_MODE); + } else if (strcmp (key, KEY_RAISE_ON_CLICK) == 0) { gboolean b; @@ -1155,6 +1180,48 @@ #ifdef HAVE_GCONF static gboolean +update_placement_mode (const char *value) +{ + MetaPlacementMode old_policy; + + old_policy = placement_mode; + + if (value != NULL) + { + if ((g_ascii_strcasecmp (value, "smart") == 0) || + (g_ascii_strcasecmp (value, "first_fit") == 0)) + { + placement_mode = META_PLACEMENT_MODE_FIRST_FIT; + } + else if (g_ascii_strcasecmp (value, "cascade") == 0) + { + placement_mode = META_PLACEMENT_MODE_CASCADE; + } + else if (g_ascii_strcasecmp (value, "center") == 0) + { + placement_mode = META_PLACEMENT_MODE_CENTER; + } + else if (g_ascii_strcasecmp (value, "origin") == 0) + { + placement_mode = META_PLACEMENT_MODE_ORIGIN; + } + else if (g_ascii_strcasecmp (value, "random") == 0) + { + placement_mode = META_PLACEMENT_MODE_RANDOM; + } + else + { + meta_warning (_("GConf key '%s' is set to an invalid value\n"), + KEY_PLACEMENT_MODE); + } + } + + return (old_policy != placement_mode); +} +#endif /* HAVE_GCONF */ + +#ifdef HAVE_GCONF +static gboolean update_raise_on_click (gboolean value) { gboolean old = raise_on_click; @@ -1217,6 +1284,12 @@ return focus_new_windows; } +MetaPlacementMode +meta_prefs_get_placement_mode (void) +{ + return placement_mode; +} + gboolean meta_prefs_get_raise_on_click (void) { @@ -1776,6 +1849,9 @@ case META_PREF_FOCUS_NEW_WINDOWS: return "FOCUS_NEW_WINDOWS"; + case META_PREF_PLACEMENT_MODE: + return "PLACEMENT_MODE"; + case META_PREF_RAISE_ON_CLICK: return "RAISE_ON_CLICK"; diff -urN metacity-2.20.2/src/prefs.h metacity-2.20.2.patched/src/prefs.h --- metacity-2.20.2/src/prefs.h 2008-01-08 01:39:42.000000000 +0200 +++ metacity-2.20.2.patched/src/prefs.h 2008-02-02 14:29:45.000000000 +0200 @@ -34,6 +34,7 @@ META_PREF_MOUSE_BUTTON_MODS, META_PREF_FOCUS_MODE, META_PREF_FOCUS_NEW_WINDOWS, + META_PREF_PLACEMENT_MODE, META_PREF_RAISE_ON_CLICK, META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR, META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR, @@ -75,6 +76,7 @@ MetaVirtualModifier meta_prefs_get_mouse_button_mods (void); MetaFocusMode meta_prefs_get_focus_mode (void); MetaFocusNewWindows meta_prefs_get_focus_new_windows (void); +MetaPlacementMode meta_prefs_get_placement_mode (void); gboolean meta_prefs_get_raise_on_click (void); const char* meta_prefs_get_theme (void); /* returns NULL if GTK default should be used */