diff options
| author | Perberos <[email protected]> | 2011-12-01 23:52:01 -0300 | 
|---|---|---|
| committer | Perberos <[email protected]> | 2011-12-01 23:52:01 -0300 | 
| commit | 28a029a4990d2a84f9d6a0b890eba812ea503998 (patch) | |
| tree | 7a69477d0dd6bf351801fa9698d95224e4fe47b6 /src/core/place.c | |
| download | marco-28a029a4990d2a84f9d6a0b890eba812ea503998.tar.bz2 marco-28a029a4990d2a84f9d6a0b890eba812ea503998.tar.xz | |
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'src/core/place.c')
| -rw-r--r-- | src/core/place.c | 932 | 
1 files changed, 932 insertions, 0 deletions
| diff --git a/src/core/place.c b/src/core/place.c new file mode 100644 index 00000000..cb1458f0 --- /dev/null +++ b/src/core/place.c @@ -0,0 +1,932 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* Marco window placement */ + +/*  + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2005 Elijah Newren + *  + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#include "place.h" +#include "workspace.h" +#include "prefs.h" +#include <gdk/gdk.h> +#include <math.h> +#include <stdlib.h> + +typedef enum +{ +  META_LEFT, +  META_RIGHT, +  META_TOP, +  META_BOTTOM +} MetaWindowDirection; + +static gint +northwestcmp (gconstpointer a, gconstpointer b) +{ +  MetaWindow *aw = (gpointer) a; +  MetaWindow *bw = (gpointer) b; +  int from_origin_a; +  int from_origin_b; +  int ax, ay, bx, by; + +  /* we're interested in the frame position for cascading, +   * not meta_window_get_position() +   */ +  if (aw->frame) +    { +      ax = aw->frame->rect.x; +      ay = aw->frame->rect.y; +    } +  else +    { +      ax = aw->rect.x; +      ay = aw->rect.y; +    } + +  if (bw->frame) +    { +      bx = bw->frame->rect.x; +      by = bw->frame->rect.y; +    } +  else +    { +      bx = bw->rect.x; +      by = bw->rect.y; +    } +   +  /* probably there's a fast good-enough-guess we could use here. */ +  from_origin_a = sqrt (ax * ax + ay * ay); +  from_origin_b = sqrt (bx * bx + by * by); +     +  if (from_origin_a < from_origin_b) +    return -1; +  else if (from_origin_a > from_origin_b) +    return 1; +  else +    return 0; +} + +static void +find_next_cascade (MetaWindow *window, +                   MetaFrameGeometry *fgeom, +                   /* visible windows on relevant workspaces */ +                   GList      *windows, +                   int         x, +                   int         y, +                   int        *new_x, +                   int        *new_y) +{ +  GList *tmp; +  GList *sorted; +  int cascade_x, cascade_y; +  int x_threshold, y_threshold; +  int window_width, window_height; +  int cascade_stage; +  MetaRectangle work_area; +  const MetaXineramaScreenInfo* current; +   +  sorted = g_list_copy (windows); +  sorted = g_list_sort (sorted, northwestcmp); + +  /* This is a "fuzzy" cascade algorithm.  +   * For each window in the list, we find where we'd cascade a +   * new window after it. If a window is already nearly at that +   * position, we move on. +   */ +   +  /* arbitrary-ish threshold, honors user attempts to +   * manually cascade. +   */ +#define CASCADE_FUZZ 15 +  if (fgeom) +    { +      x_threshold = MAX (fgeom->left_width, CASCADE_FUZZ); +      y_threshold = MAX (fgeom->top_height, CASCADE_FUZZ); +    } +  else +    { +      x_threshold = CASCADE_FUZZ; +      y_threshold = CASCADE_FUZZ; +    } +   +  /* Find furthest-SE origin of all workspaces. +   * cascade_x, cascade_y are the target position +   * of NW corner of window frame. +   */ + +  current = meta_screen_get_current_xinerama (window->screen); +  meta_window_get_work_area_for_xinerama (window, current->number, &work_area); + +  cascade_x = MAX (0, work_area.x); +  cascade_y = MAX (0, work_area.y); +   +  /* Find first cascade position that's not used. */ +   +  window_width = window->frame ? window->frame->rect.width : window->rect.width; +  window_height = window->frame ? window->frame->rect.height : window->rect.height; +   +  cascade_stage = 0; +  tmp = sorted; +  while (tmp != NULL) +    { +      MetaWindow *w; +      int wx, wy; +       +      w = tmp->data; + +      /* we want frame position, not window position */ +      if (w->frame) +        { +          wx = w->frame->rect.x; +          wy = w->frame->rect.y; +        } +      else +        { +          wx = w->rect.x; +          wy = w->rect.y; +        } +       +      if (ABS (wx - cascade_x) < x_threshold && +          ABS (wy - cascade_y) < y_threshold) +        { +          /* This window is "in the way", move to next cascade +           * point. The new window frame should go at the origin +           * of the client window we're stacking above. +           */ +          meta_window_get_position (w, &wx, &wy); +          cascade_x = wx; +          cascade_y = wy; +           +          /* If we go off the screen, start over with a new cascade */ +	  if (((cascade_x + window_width) > +               (work_area.x + work_area.width)) || +              ((cascade_y + window_height) > +	       (work_area.y + work_area.height))) +	    { +	      cascade_x = MAX (0, work_area.x); +	      cascade_y = MAX (0, work_area.y); +               +#define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */ +              cascade_stage += 1; +	      cascade_x += CASCADE_INTERVAL * cascade_stage; +               +	      /* start over with a new cascade translated to the right, unless +               * we are out of space +               */ +              if ((cascade_x + window_width) < +                  (work_area.x + work_area.width)) +                { +                  tmp = sorted; +                  continue; +                } +              else +                { +                  /* All out of space, this cascade_x won't work */ +                  cascade_x = MAX (0, work_area.x); +                  break; +                } +	    } +        } +      else +        { +          /* Keep searching for a further-down-the-diagonal window. */ +        } +         +      tmp = tmp->next; +    } + +  /* cascade_x and cascade_y will match the last window in the list +   * that was "in the way" (in the approximate cascade diagonal) +   */ +   +  g_list_free (sorted); + +  /* Convert coords to position of window, not position of frame. */ +  if (fgeom == NULL) +    { +      *new_x = cascade_x; +      *new_y = cascade_y; +    } +  else +    { +      *new_x = cascade_x + fgeom->left_width; +      *new_y = cascade_y + fgeom->top_height; +    } +} + +static void +find_most_freespace (MetaWindow *window, +                     MetaFrameGeometry *fgeom, +                     /* visible windows on relevant workspaces */ +                     MetaWindow *focus_window, +                     int         x, +                     int         y, +                     int        *new_x, +                     int        *new_y) +{ +  MetaWindowDirection side; +  int max_area; +  int max_width, max_height, left, right, top, bottom; +  int left_space, right_space, top_space, bottom_space; +  int frame_size_left, frame_size_top; +  MetaRectangle work_area; +  MetaRectangle avoid; +  MetaRectangle outer; + +  frame_size_left = fgeom ? fgeom->left_width : 0; +  frame_size_top  = fgeom ? fgeom->top_height : 0; + +  meta_window_get_work_area_current_xinerama (focus_window, &work_area); +  meta_window_get_outer_rect (focus_window, &avoid); +  meta_window_get_outer_rect (window, &outer); + +  /* Find the areas of choosing the various sides of the focus window */ +  max_width  = MIN (avoid.width, outer.width); +  max_height = MIN (avoid.height, outer.height); +  left_space   = avoid.x - work_area.x; +  right_space  = work_area.width - (avoid.x + avoid.width - work_area.x); +  top_space    = avoid.y - work_area.y; +  bottom_space = work_area.height - (avoid.y + avoid.height - work_area.y); +  left   = MIN (left_space,   outer.width); +  right  = MIN (right_space,  outer.width); +  top    = MIN (top_space,    outer.height); +  bottom = MIN (bottom_space, outer.height); + +  /* Find out which side of the focus_window can show the most of the window */ +  side = META_LEFT; +  max_area = left*max_height; +  if (right*max_height > max_area) +    { +      side = META_RIGHT; +      max_area = right*max_height; +    } +  if (top*max_width > max_area) +    { +      side = META_TOP; +      max_area = top*max_width; +    } +  if (bottom*max_width > max_area) +    { +      side = META_BOTTOM; +      max_area = bottom*max_width; +    } + +  /* Give up if there's no where to put it (i.e. focus window is maximized) */ +  if (max_area == 0) +    return; + +  /* Place the window on the relevant side; if the whole window fits, +   * make it adjacent to the focus window; if not, make sure the +   * window doesn't go off the edge of the screen. +   */ +  switch (side) +    { +    case META_LEFT: +      *new_y = avoid.y + frame_size_top; +      if (left_space > outer.width) +        *new_x = avoid.x - outer.width + frame_size_left; +      else +        *new_x = work_area.x + frame_size_left; +      break; +    case META_RIGHT: +      *new_y = avoid.y + frame_size_top; +      if (right_space > outer.width) +        *new_x = avoid.x + avoid.width + frame_size_left; +      else +        *new_x = work_area.x + work_area.width - outer.width + frame_size_left; +      break; +    case META_TOP: +      *new_x = avoid.x + frame_size_left; +      if (top_space > outer.height) +        *new_y = avoid.y - outer.height + frame_size_top; +      else +        *new_y = work_area.y + frame_size_top; +      break; +    case META_BOTTOM: +      *new_x = avoid.x + frame_size_left; +      if (bottom_space > outer.height) +        *new_y = avoid.y + avoid.height + frame_size_top; +      else +        *new_y = work_area.y + work_area.height - outer.height + frame_size_top; +      break; +    } +} + +static void +avoid_being_obscured_as_second_modal_dialog (MetaWindow *window, +                                             MetaFrameGeometry *fgeom, +                                             int        *x, +                                             int        *y) +{ +  /* We can't center this dialog if it was denied focus and it +   * overlaps with the focus window and this dialog is modal and this +   * dialog is in the same app as the focus window (*phew*...please +   * don't make me say that ten times fast). See bug 307875 comment 11 +   * and 12 for details, but basically it means this is probably a +   * second modal dialog for some app while the focus window is the +   * first modal dialog.  We should probably make them simultaneously +   * visible in general, but it becomes mandatory to do so due to +   * buggy apps (e.g. those using gtk+ *sigh*) because in those cases +   * this second modal dialog also happens to be modal to the first +   * dialog in addition to the main window, while it has only let us +   * know about the modal-to-the-main-window part. +   */ + +  MetaWindow *focus_window; +  MetaRectangle overlap; + +  focus_window = window->display->focus_window; + +  if (window->denied_focus_and_not_transient && +      window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ +      meta_window_same_application (window, focus_window) && +      meta_rectangle_intersect (&window->rect, +                                &focus_window->rect, +                                &overlap)) +    { +      find_most_freespace (window, fgeom, focus_window, *x, *y, x, y); +      meta_topic (META_DEBUG_PLACEMENT, +                  "Dialog window %s was denied focus but may be modal " +                  "to the focus window; had to move it to avoid the " +                  "focus window\n", +                  window->desc); +    } +} + +static gboolean +rectangle_overlaps_some_window (MetaRectangle *rect, +                                GList         *windows) +{ +  GList *tmp; +  MetaRectangle dest; +   +  tmp = windows; +  while (tmp != NULL) +    { +      MetaWindow *other = tmp->data; +      MetaRectangle other_rect;       + +      switch (other->type) +        { +        case META_WINDOW_DOCK: +        case META_WINDOW_SPLASHSCREEN: +        case META_WINDOW_DESKTOP: +        case META_WINDOW_DIALOG: +        case META_WINDOW_MODAL_DIALOG: +          break; + +        case META_WINDOW_NORMAL: +        case META_WINDOW_UTILITY: +        case META_WINDOW_TOOLBAR: +        case META_WINDOW_MENU: +          meta_window_get_outer_rect (other, &other_rect); +           +          if (meta_rectangle_intersect (rect, &other_rect, &dest)) +            return TRUE; +          break; +        } +       +      tmp = tmp->next; +    } + +  return FALSE; +} + +static gint +leftmost_cmp (gconstpointer a, gconstpointer b) +{ +  MetaWindow *aw = (gpointer) a; +  MetaWindow *bw = (gpointer) b; +  int ax, bx; + +  /* we're interested in the frame position for cascading, +   * not meta_window_get_position() +   */ +  if (aw->frame) +    ax = aw->frame->rect.x; +  else +    ax = aw->rect.x; + +  if (bw->frame) +    bx = bw->frame->rect.x; +  else +    bx = bw->rect.x; + +  if (ax < bx) +    return -1; +  else if (ax > bx) +    return 1; +  else +    return 0; +} + +static gint +topmost_cmp (gconstpointer a, gconstpointer b) +{ +  MetaWindow *aw = (gpointer) a; +  MetaWindow *bw = (gpointer) b; +  int ay, by; + +  /* we're interested in the frame position for cascading, +   * not meta_window_get_position() +   */ +  if (aw->frame) +    ay = aw->frame->rect.y; +  else +    ay = aw->rect.y; + +  if (bw->frame) +    by = bw->frame->rect.y; +  else +    by = bw->rect.y; + +  if (ay < by) +    return -1; +  else if (ay > by) +    return 1; +  else +    return 0; +} + +static void +center_tile_rect_in_area (MetaRectangle *rect, +                          MetaRectangle *work_area) +{ +  int fluff; + +  /* The point here is to tile a window such that "extra" +   * space is equal on either side (i.e. so a full screen +   * of windows tiled this way would center the windows +   * as a group) +   */ + +  fluff = (work_area->width % (rect->width+1)) / 2; +  rect->x = work_area->x + fluff; +  fluff = (work_area->height % (rect->height+1)) / 3; +  rect->y = work_area->y + fluff; +} + +/* Find the leftmost, then topmost, empty area on the workspace + * that can contain the new window. + * + * Cool feature to have: if we can't fit the current window size, + * try shrinking the window (within geometry constraints). But + * beware windows such as Emacs with no sane minimum size, we + * don't want to create a 1x1 Emacs. + */ +static gboolean +find_first_fit (MetaWindow *window, +                MetaFrameGeometry *fgeom, +                /* visible windows on relevant workspaces */ +                GList      *windows, +		int         xinerama, +                int         x, +                int         y, +                int        *new_x, +                int        *new_y) +{ +  /* This algorithm is limited - it just brute-force tries +   * to fit the window in a small number of locations that are aligned +   * with existing windows. It tries to place the window on +   * the bottom of each existing window, and then to the right +   * of each existing window, aligned with the left/top of the +   * existing window in each of those cases. +   */   +  int retval; +  GList *below_sorted; +  GList *right_sorted; +  GList *tmp; +  MetaRectangle rect; +  MetaRectangle work_area; +   +  retval = FALSE; + +  /* Below each window */ +  below_sorted = g_list_copy (windows); +  below_sorted = g_list_sort (below_sorted, leftmost_cmp); +  below_sorted = g_list_sort (below_sorted, topmost_cmp);   + +  /* To the right of each window */ +  right_sorted = g_list_copy (windows); +  right_sorted = g_list_sort (right_sorted, topmost_cmp); +  right_sorted = g_list_sort (right_sorted, leftmost_cmp); +   +  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; +    } + +#ifdef WITH_VERBOSE_MODE +    { +      char xinerama_location_string[RECT_LENGTH]; +      meta_rectangle_to_string (&window->screen->xinerama_infos[xinerama].rect, +                                xinerama_location_string); +      meta_topic (META_DEBUG_XINERAMA, +		  "Natural xinerama is %s\n", +		  xinerama_location_string); +    } +#endif + +    meta_window_get_work_area_for_xinerama (window, xinerama, &work_area); + +    center_tile_rect_in_area (&rect, &work_area); + +    if (meta_rectangle_contains_rect (&work_area, &rect) && +        !rectangle_overlaps_some_window (&rect, windows)) +      { +        *new_x = rect.x; +        *new_y = rect.y; +        if (fgeom) +          { +            *new_x += fgeom->left_width; +            *new_y += fgeom->top_height; +          } +     +        retval = TRUE; +        +        goto out; +      } + +    /* try below each window */ +    tmp = below_sorted; +    while (tmp != NULL) +      { +        MetaWindow *w = tmp->data; +        MetaRectangle outer_rect; + +        meta_window_get_outer_rect (w, &outer_rect); +       +        rect.x = outer_rect.x; +        rect.y = outer_rect.y + outer_rect.height; +       +        if (meta_rectangle_contains_rect (&work_area, &rect) && +            !rectangle_overlaps_some_window (&rect, below_sorted)) +          { +            *new_x = rect.x; +            *new_y = rect.y; +            if (fgeom) +              { +                *new_x += fgeom->left_width; +                *new_y += fgeom->top_height; +              } +           +            retval = TRUE; +           +            goto out; +          } + +        tmp = tmp->next; +      } + +    /* try to the right of each window */ +    tmp = right_sorted; +    while (tmp != NULL) +      { +        MetaWindow *w = tmp->data; +        MetaRectangle outer_rect; +    +        meta_window_get_outer_rect (w, &outer_rect); +      +        rect.x = outer_rect.x + outer_rect.width; +        rect.y = outer_rect.y; +    +        if (meta_rectangle_contains_rect (&work_area, &rect) && +            !rectangle_overlaps_some_window (&rect, right_sorted)) +          { +            *new_x = rect.x; +            *new_y = rect.y; +            if (fgeom) +              { +                *new_x += fgeom->left_width; +                *new_y += fgeom->top_height; +              } +         +            retval = TRUE; +        +            goto out; +          } + +        tmp = tmp->next; +      } +       + out: + +  g_list_free (below_sorted); +  g_list_free (right_sorted); +  return retval; +} + +void +meta_window_place (MetaWindow        *window, +                   MetaFrameGeometry *fgeom, +                   int                x, +                   int                y, +                   int               *new_x, +                   int               *new_y) +{ +  GList *windows; +  const MetaXineramaScreenInfo *xi; + +  /* frame member variables should NEVER be used in here, only +   * MetaFrameGeometry. But remember fgeom == NULL +   * for undecorated windows. Also, this function should +   * NEVER have side effects other than computing the +   * placement coordinates. +   */ +   +  meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); + +  windows = NULL; +   +  switch (window->type) +    { +      /* Run placement algorithm on these. */ +    case META_WINDOW_NORMAL: +    case META_WINDOW_DIALOG: +    case META_WINDOW_MODAL_DIALOG: +    case META_WINDOW_SPLASHSCREEN: +      break; +           +      /* Assume the app knows best how to place these, no placement +       * algorithm ever (other than "leave them as-is") +       */ +    case META_WINDOW_DESKTOP: +    case META_WINDOW_DOCK: +    case META_WINDOW_TOOLBAR: +    case META_WINDOW_MENU: +    case META_WINDOW_UTILITY: +      goto done_no_constraints; +    } +   +  if (meta_prefs_get_disable_workarounds ()) +    { +      switch (window->type) +        { +          /* Only accept USPosition on normal windows because the app is full +           * of shit claiming the user set -geometry for a dialog or dock +           */ +        case META_WINDOW_NORMAL: +          if (window->size_hints.flags & USPosition) +            { +              /* don't constrain with placement algorithm */ +              meta_topic (META_DEBUG_PLACEMENT, +                          "Honoring USPosition for %s instead of using placement algorithm\n", window->desc); + +              goto done; +            } +          break; + +          /* Ignore even USPosition on dialogs, splashscreen */ +        case META_WINDOW_DIALOG: +        case META_WINDOW_MODAL_DIALOG: +        case META_WINDOW_SPLASHSCREEN: +          break; +           +          /* Assume the app knows best how to place these. */ +        case META_WINDOW_DESKTOP: +        case META_WINDOW_DOCK: +        case META_WINDOW_TOOLBAR: +        case META_WINDOW_MENU: +        case META_WINDOW_UTILITY: +          if (window->size_hints.flags & PPosition) +            { +              meta_topic (META_DEBUG_PLACEMENT, +                          "Not placing non-normal non-dialog window with PPosition set\n"); +              goto done_no_constraints; +            } +          break; +        } +    } +  else +    { +      /* workarounds enabled */ +       +      if ((window->size_hints.flags & PPosition) || +          (window->size_hints.flags & USPosition)) +        { +          meta_topic (META_DEBUG_PLACEMENT, +                      "Not placing window with PPosition or USPosition set\n"); +          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y); +          goto done_no_constraints; +        } +    } +   +  if ((window->type == META_WINDOW_DIALOG || +       window->type == META_WINDOW_MODAL_DIALOG) && +      window->xtransient_for != None) +    { +      /* Center horizontally, at top of parent vertically */ + +      MetaWindow *parent; +           +      parent = +        meta_display_lookup_x_window (window->display, +                                      window->xtransient_for); + +      if (parent) +        { +          int w; + +          meta_window_get_position (parent, &x, &y); +          w = parent->rect.width; + +          /* center of parent */ +          x = x + w / 2; +          /* center of child over center of parent */ +          x -= window->rect.width / 2; + +          /* "visually" center window over parent, leaving twice as +           * much space below as on top. +           */ +          y += (parent->rect.height - window->rect.height)/3; + +          /* put top of child's frame, not top of child's client */ +          if (fgeom) +            y += fgeom->top_height; + +          meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n", +                      window->desc); +           +          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y); + +          goto done; +        } +    } +   +  /* FIXME UTILITY with transient set should be stacked up +   * on the sides of the parent window or something. +   */ +   +  if (window->type == META_WINDOW_DIALOG || +      window->type == META_WINDOW_MODAL_DIALOG || +      window->type == META_WINDOW_SPLASHSCREEN) +    { +      /* Center on current xinerama (i.e. on current monitor) */ +      int w, h; + +      /* Warning, this function is a round trip! */ +      xi = meta_screen_get_current_xinerama (window->screen); + +      w = xi->rect.width; +      h = xi->rect.height; + +      x = (w - window->rect.width) / 2; +      y = (h - window->rect.height) / 2; + +      x += xi->rect.x; +      y += xi->rect.y; +       +      meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n", +                  window->desc, window->screen->number, xi->number); + +      goto done_check_denied_focus; +    } +   +  /* Find windows that matter (not minimized, on same workspace +   * as placed window, may be shaded - if shaded we pretend it isn't +   * for placement purposes) +   */ +  { +    GSList *all_windows; +    GSList *tmp; +     +    all_windows = meta_display_list_windows (window->display); + +    tmp = all_windows; +    while (tmp != NULL) +      { +        MetaWindow *w = tmp->data; + +        if (meta_window_showing_on_its_workspace (w) && +            w != window &&  +            (window->workspace == w->workspace || +             window->on_all_workspaces || w->on_all_workspaces)) +          windows = g_list_prepend (windows, w); + +        tmp = tmp->next; +      } + +    g_slist_free (all_windows); +  } + +  /* Warning, this is a round trip! */ +  xi = meta_screen_get_current_xinerama (window->screen); +   +  /* "Origin" placement algorithm */ +  x = xi->rect.x; +  y = xi->rect.y; + +  if (find_first_fit (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 +   * a hack here). Assume undecorated windows probably don't intend to +   * be maximized.   +   */ +  if (window->has_maximize_func && window->decorated && +      !window->fullscreen) +    { +      MetaRectangle workarea; +      MetaRectangle outer; + +      meta_window_get_work_area_for_xinerama (window, +                                              xi->number, +                                              &workarea);       +      meta_window_get_outer_rect (window, &outer); +       +      /* If the window is bigger than the screen, then automaximize.  Do NOT +       * auto-maximize the directions independently.  See #419810. +       */ +      if (outer.width >= workarea.width && outer.height >= workarea.height) +        { +          window->maximize_horizontally_after_placement = TRUE; +          window->maximize_vertically_after_placement = TRUE; +        } +    } + +  /* If no placement has been done, revert to cascade to avoid  +   * fully overlapping window (e.g. starting multiple terminals) +   * */ +  if (x == xi->rect.x && y == xi->rect.y)   +    find_next_cascade (window, fgeom, windows, x, y, &x, &y); + + done_check_denied_focus: +  /* If the window is being denied focus and isn't a transient of the +   * focus window, we do NOT want it to overlap with the focus window +   * if at all possible.  This is guaranteed to only be called if the +   * focus_window is non-NULL, and we try to avoid that window. +   */ +  if (window->denied_focus_and_not_transient) +    { +      gboolean       found_fit; +      MetaWindow    *focus_window; +      MetaRectangle  overlap; + +      focus_window = window->display->focus_window; +      g_assert (focus_window != NULL); + +      /* No need to do anything if the window doesn't overlap at all */ +      found_fit = !meta_rectangle_intersect (&window->rect, +                                             &focus_window->rect, +                                             &overlap); + +      /* Try to do a first fit again, this time only taking into account the +       * focus window. +       */ +      if (!found_fit) +        { +          GList *focus_window_list; +          focus_window_list = g_list_prepend (NULL, focus_window); + +          /* Reset x and y ("origin" placement algorithm) */ +          x = xi->rect.x; +          y = xi->rect.y; + +          found_fit = find_first_fit (window, fgeom, focus_window_list, +                                      xi->number, +                                      x, y, &x, &y); +          g_list_free (focus_window_list); +	} + +      /* If that still didn't work, just place it where we can see as much +       * as possible. +       */ +      if (!found_fit) +        find_most_freespace (window, fgeom, focus_window, x, y, &x, &y); +    } +   + done: +  g_list_free (windows); +   + done_no_constraints: + +  *new_x = x; +  *new_y = y; +} | 
