summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-08 23:43:17 +0000
committerHavoc Pennington <hp@src.gnome.org>2003-03-08 23:43:17 +0000
commit5f75334d57e79673f0c67a6170e553f99ff1c0ff (patch)
tree0f7b059b24877eca2ab4c877f2122d46d0ac92a9
parent4481be72d1e4073fad009dc24c3bf14d9e7659f4 (diff)
downloadmetacity-5f75334d57e79673f0c67a6170e553f99ff1c0ff.tar.gz
metacity-5f75334d57e79673f0c67a6170e553f99ff1c0ff.tar.bz2
Switch over to new constraints code, unquestionably introduces some bugs,
2003-02-27 Havoc Pennington <hp@redhat.com> Switch over to new constraints code, unquestionably introduces some bugs, but should get us on the right path. * src/window.c (meta_window_get_work_area_all_xineramas): create this function again as it turned out to be legitimate for window position constraint (adjust_for_gravity): use the width/height from the configure request to compute the requested move (meta_window_move_resize_internal): use meta_window_constrain (update_size_hints): clamp max size to MAXSHORT to avoid worrying about overflow stuff * src/constraints.c (meta_window_constrain): don't base placement on uninitialized variables, general hacking * src/Makefile.am (metacity_SOURCES): add constraints.c, constraints.h * src/constraints.c (meta_window_constrain): update the cut-and-paste aspect ratio code to have latest bugfixes
-rw-r--r--ChangeLog23
-rw-r--r--src/Makefile.am2
-rw-r--r--src/constraints.c607
-rw-r--r--src/window.c677
-rw-r--r--src/window.h2
-rw-r--r--src/wm-tester/test-gravity.c235
6 files changed, 853 insertions, 693 deletions
diff --git a/ChangeLog b/ChangeLog
index b6bd36f..47823b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2003-02-27 Havoc Pennington <hp@redhat.com>
+
+ Switch over to new constraints code, unquestionably introduces
+ some bugs, but should get us on the right path.
+
+ * src/window.c (meta_window_get_work_area_all_xineramas): create
+ this function again as it turned out to be legitimate for window
+ position constraint
+ (adjust_for_gravity): use the width/height from the configure
+ request to compute the requested move
+ (meta_window_move_resize_internal): use meta_window_constrain
+ (update_size_hints): clamp max size to MAXSHORT to avoid worrying
+ about overflow stuff
+
+ * src/constraints.c (meta_window_constrain): don't base placement
+ on uninitialized variables, general hacking
+
+ * src/Makefile.am (metacity_SOURCES): add constraints.c,
+ constraints.h
+
+ * src/constraints.c (meta_window_constrain): update the
+ cut-and-paste aspect ratio code to have latest bugfixes
+
2003-03-08 Rob Adams <robadams@ucla.edu>
* src/window-props.c (reload_normal_hints): Check that window min
diff --git a/src/Makefile.am b/src/Makefile.am
index 6b10875..b4ca784 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,6 +14,8 @@ metacity_SOURCES= \
bell.h \
bell.c \
common.h \
+ constraints.c \
+ constraints.h \
core.c \
core.h \
delete.c \
diff --git a/src/constraints.c b/src/constraints.c
index c982624..cd686e6 100644
--- a/src/constraints.c
+++ b/src/constraints.c
@@ -1,8 +1,8 @@
/* Metacity size/position constraints */
-/*
- * Copyright (C) 2002 Red Hat, Inc.
- *
+/*
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
+ *
* 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
@@ -12,13 +12,14 @@
* 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 "constraints.h"
#include "place.h"
@@ -35,7 +36,7 @@
*
* After selecting the variables we plan to vary, we define
* each constraint on the window in terms of those variables.
- *
+ *
* Trivial example, say we are resizing vertically from the top of the
* window. In that case we are applying the user's mouse motion delta
* to an original size and position, note that dy is positive to
@@ -66,7 +67,7 @@
*
* new_height = orig_height - dy;
* new_y = orig_y + dy;
- *
+ *
* This way the constraint is applied simultaneously to size/position,
* so you aren't running the risk of constraining one but still
* changing the other. i.e. we've converted an operation that may
@@ -103,9 +104,11 @@
* maximized, we want to MOVE_VERTICAL/MOVE_HORIZONTAL to the top
* center of the screen, then RESIZE_BOTTOM and
* RESIZE_HORIZONTAL_CENTER. i.e. essentially NorthGravity.
- *
+ *
*/
+#define FLOOR(value, base) ( ((int) ((value) / (base))) * (base) )
+
typedef struct
{
MetaWindow *window;
@@ -113,7 +116,7 @@ typedef struct
const MetaXineramaScreenInfo *xinerama;
MetaRectangle work_area_xinerama;
MetaRectangle work_area_screen;
- int nw_x, nw_y, se_x, se_y;
+ int nw_x, nw_y, se_x, se_y; /* these are whole-screen not xinerama */
} ConstraintInfo;
/* (FIXME instead of TITLEBAR_LENGTH_ONSCREEN, get the actual
@@ -157,6 +160,7 @@ typedef void (* MetaConstrainMoveFunc) (MetaWindow *window,
typedef struct
{
+ const char *name;
MetaConstraintAppliesFunc applies_func;
MetaConstrainTopFunc top_func;
MetaConstrainBottomFunc bottom_func;
@@ -246,11 +250,12 @@ constraint_desktop_move_func (MetaWindow *window,
int *x_delta,
int *y_delta)
{
- *x_delta = 0 - orig->x;
+ *x_delta = 0 - orig->x;
*y_delta = 0 - orig->y;
}
static const Constraint constraint_desktop = {
+ "Desktop",
constraint_desktop_applies_func,
constraint_desktop_top_func,
constraint_desktop_bottom_func,
@@ -272,7 +277,7 @@ static const Constraint constraint_desktop = {
*
* Left resize
* ===
- *
+ *
* new_width = orig_width - dx
* new_x = orig_x + dx
*
@@ -311,7 +316,7 @@ static const Constraint constraint_desktop = {
*
* Vertical move
* ===
- *
+ *
* new_height = orig_height
* new_y = orig_y + dy
*
@@ -324,9 +329,9 @@ static const Constraint constraint_desktop = {
* new_y < se_y
* orig_y + dy = se_y
* so max dy is (se_y - orig_y)
- *
+ *
* Horizontal move is equivalent to vertical.
- *
+ *
*/
static gboolean
@@ -338,14 +343,48 @@ constraint_onscreen_applies_func (MetaWindow *window)
}
static void
+get_outermost_onscreen_positions (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *leftmost_x,
+ int *rightmost_x,
+ int *topmost_y,
+ int *bottommost_y)
+{
+ if (leftmost_x)
+ *leftmost_x = info->nw_x + TITLEBAR_LENGTH_ONSCREEN - orig->width;
+
+ if (rightmost_x)
+ *rightmost_x = info->se_x - TITLEBAR_LENGTH_ONSCREEN;
+
+ if (topmost_y)
+ *topmost_y = info->nw_y + info->fgeom.top_height;
+
+ if (bottommost_y)
+ {
+ /* If no frame, keep random TITLEBAR_LENGTH_ONSCREEN pixels on the
+ * screen.
+ */
+ if (window->frame)
+ *bottommost_y = info->se_y;
+ else
+ *bottommost_y = info->se_y - TITLEBAR_LENGTH_ONSCREEN;
+ }
+}
+
+static void
constraint_onscreen_top_func (MetaWindow *window,
const ConstraintInfo *info,
const MetaRectangle *orig,
int *y_delta)
{
int min_dy;
-
- min_dy = info->nw_y + info->fgeom.top_height - orig->y;
+ int topmost_y;
+
+ get_outermost_onscreen_positions (window, info, orig,
+ NULL, NULL, &topmost_y, NULL);
+
+ min_dy = topmost_y - orig->y;
if (*y_delta < min_dy)
*y_delta = min_dy;
@@ -358,8 +397,12 @@ constraint_onscreen_bottom_func (MetaWindow *window,
int *y_delta)
{
int max_dy;
+ int bottommost_y;
+
+ get_outermost_onscreen_positions (window, info, orig,
+ NULL, NULL, NULL, &bottommost_y);
- max_dy = info->se_y - info->fgeom.top_height - orig->y;
+ max_dy = bottommost_y - orig->y;
if (*y_delta > max_dy)
*y_delta = max_dy;
@@ -372,10 +415,13 @@ constraint_onscreen_vcenter_func (MetaWindow *window,
int *y_delta)
{
int max_dy;
-
- max_dy = info->nw_y + info->fgeom.top_height - orig->y;
- max_dy = ABS (max_dy);
-
+ int topmost_y;
+
+ get_outermost_onscreen_positions (window, info, orig,
+ NULL, NULL, &topmost_y, NULL);
+
+ max_dy = orig->y - topmost_y;
+
if (*y_delta > max_dy)
*y_delta = max_dy;
}
@@ -387,8 +433,12 @@ constraint_onscreen_left_func (MetaWindow *window,
int *x_delta)
{
int min_dx;
-
- min_dx = info->nw_x + info->fgeom.left_width + TITLEBAR_WIDTH_ONSCREEN - orig->x;
+ int leftmost_x;
+
+ get_outermost_onscreen_positions (window, info, orig,
+ &leftmost_x, NULL, NULL, NULL);
+
+ min_dx = leftmost_x - orig->x;
if (*x_delta < min_dx)
*x_delta = min_dx;
@@ -401,8 +451,12 @@ constraint_onscreen_right_func (MetaWindow *window,
int *x_delta)
{
int max_dx;
+ int rightmost_x;
+
+ get_outermost_onscreen_positions (window, info, orig,
+ NULL, &rightmost_x, NULL, NULL);
- max_dx = info->se_x - TITLEBAR_WIDTH_ONSCREEN - orig->x;
+ max_dx = rightmost_x - orig->x;
if (*x_delta > max_dx)
*x_delta = max_dx;
@@ -415,10 +469,13 @@ constraint_onscreen_hcenter_func (MetaWindow *window,
int *x_delta)
{
int max_dx;
+ int leftmost_x;
- max_dx = info->nw_x + info->fgeom.left_width + TITLEBAR_WIDTH_ONSCREEN - orig->x;
- max_dx = ABS (max_dx);
-
+ get_outermost_onscreen_positions (window, info, orig,
+ &leftmost_x, NULL, NULL, NULL);
+
+ max_dx = orig->x - leftmost_x;
+
if (*x_delta > max_dx)
*x_delta = max_dx;
}
@@ -432,15 +489,15 @@ constraint_onscreen_move_func (MetaWindow *window,
{
int min_delta;
int max_delta;
-
- min_delta = info->nw_y + info->fgeom.top_height - orig->y;
+ int leftmost_x, rightmost_x, topmost_y, bottommost_y;
- if (window->frame) /* if frame, the titlebar is always above the y pos */
- max_delta = info->se_y - orig->y;
- else /* else keep some client area pixels on the screen */
- max_delta = info->se_y - orig->y - TITLEBAR_WIDTH_ONSCREEN;
+ get_outermost_onscreen_positions (window, info, orig,
+ &leftmost_x, &rightmost_x,
+ &topmost_y, &bottommost_y);
+
+ min_delta = topmost_y - orig->y;
+ max_delta = bottommost_y - orig->y;
-
/* Note that min delta (top left) has priority over
* max delta (bottom right) to facilitate keeping
* titlebar on the screen
@@ -450,8 +507,8 @@ constraint_onscreen_move_func (MetaWindow *window,
if (*y_delta < min_delta)
*y_delta = min_delta;
- min_delta = info->nw_x + TITLEBAR_WIDTH_ONSCREEN - orig->x;
- max_delta = info->se_x - orig->x - TITLEBAR_WIDTH_ONSCREEN;
+ min_delta = leftmost_x - orig->x;
+ max_delta = rightmost_x - orig->x;
if (*x_delta > max_delta)
*x_delta = max_delta;
@@ -460,6 +517,7 @@ constraint_onscreen_move_func (MetaWindow *window,
}
static const Constraint constraint_onscreen = {
+ "Onscreen",
constraint_onscreen_applies_func,
constraint_onscreen_top_func,
constraint_onscreen_bottom_func,
@@ -472,7 +530,7 @@ static const Constraint constraint_onscreen = {
/* Size hints constraints:
- *
+ *
* For min/max size we just clamp to those, and for resize increment
* we clamp to the one at or below the requested place.
*
@@ -480,7 +538,7 @@ static const Constraint constraint_onscreen = {
* meta_window_constrain, because it involves both dimensions, and
* thus messes up our generic framework.
*
- * Left resize:
+ * Left resize can be solved for dx like this:
* new_width = orig_width - dx
* new_x = orig_x + dx
*
@@ -493,7 +551,7 @@ static const Constraint constraint_onscreen = {
* orig_width - dx <= max_width
* - dx <= max_width - orig_width
* dx >= orig_width - max_width
- *
+ *
*/
static gboolean
@@ -508,7 +566,27 @@ constraint_hints_top_func (MetaWindow *window,
const MetaRectangle *orig,
int *y_delta)
{
-
+ int min_dy;
+ int max_dy;
+ int height;
+
+ max_dy = orig->height - window->size_hints.min_height;
+ min_dy = orig->height - window->size_hints.max_height;
+
+ g_assert (max_dy >= min_dy);
+
+ if (*y_delta > max_dy)
+ *y_delta = max_dy;
+ if (*y_delta < min_dy)
+ *y_delta = min_dy;
+
+ /* shrink to base + N * inc
+ */
+ height = orig->height - *y_delta;
+ height = window->size_hints.base_height +
+ FLOOR (height - window->size_hints.base_height, window->size_hints.height_inc);
+
+ *y_delta = orig->height - height;
}
static void
@@ -517,7 +595,27 @@ constraint_hints_bottom_func (MetaWindow *window,
const MetaRectangle *orig,
int *y_delta)
{
+ int min_dy;
+ int max_dy;
+ int height;
+
+ min_dy = window->size_hints.min_height - orig->height;
+ max_dy = window->size_hints.max_height - orig->height;
+ g_assert (max_dy >= min_dy);
+
+ if (*y_delta > max_dy)
+ *y_delta = max_dy;
+ if (*y_delta < min_dy)
+ *y_delta = min_dy;
+
+ /* shrink to base + N * inc
+ */
+ height = orig->height + *y_delta;
+ height = window->size_hints.base_height +
+ FLOOR (height - window->size_hints.base_height, window->size_hints.height_inc);
+
+ *y_delta = height - orig->height;
}
static void
@@ -526,7 +624,32 @@ constraint_hints_vcenter_func (MetaWindow *window,
const MetaRectangle *orig,
int *y_delta)
{
+ int min_dy;
+ int max_dy;
+ int height;
+
+ /* Remember our delta is negative to shrink window, positive to
+ * grow it, and the actual resize is y_delta * 2 (which is broken,
+ * but that's how it currently is)
+ */
+
+ min_dy = (window->size_hints.min_height - orig->height) / 2;
+ max_dy = (window->size_hints.max_height - orig->height) / 2;
+
+ g_assert (max_dy >= min_dy);
+
+ if (*y_delta > max_dy)
+ *y_delta = max_dy;
+ if (*y_delta < min_dy)
+ *y_delta = min_dy;
+
+ /* shrink to base + N * inc
+ */
+ height = orig->height + *y_delta * 2;
+ height = window->size_hints.base_height +
+ FLOOR (height - window->size_hints.base_height, window->size_hints.height_inc);
+ *y_delta = (height - orig->height) / 2;
}
static void
@@ -538,10 +661,12 @@ constraint_hints_left_func (MetaWindow *window,
int min_dx;
int max_dx;
int width;
-
+
max_dx = orig->width - window->size_hints.min_width;
min_dx = orig->width - window->size_hints.max_width;
+ g_assert (max_dx >= min_dx);
+
if (*x_delta > max_dx)
*x_delta = max_dx;
if (*x_delta < min_dx)
@@ -552,7 +677,7 @@ constraint_hints_left_func (MetaWindow *window,
width = orig->width - *x_delta;
width = window->size_hints.base_width +
FLOOR (width - window->size_hints.base_width, window->size_hints.width_inc);
-
+
*x_delta = orig->width - width;
}
@@ -562,7 +687,27 @@ constraint_hints_right_func (MetaWindow *window,
const MetaRectangle *orig,
int *x_delta)
{
+ int min_dx;
+ int max_dx;
+ int width;
+
+ min_dx = window->size_hints.min_width - orig->width;
+ max_dx = window->size_hints.max_width - orig->width;
+
+ g_assert (max_dx >= min_dx);
+ if (*x_delta > max_dx)
+ *x_delta = max_dx;
+ if (*x_delta < min_dx)
+ *x_delta = min_dx;
+
+ /* shrink to base + N * inc
+ */
+ width = orig->width + *x_delta;
+ width = window->size_hints.base_width +
+ FLOOR (width - window->size_hints.base_width, window->size_hints.width_inc);
+
+ *x_delta = width - orig->width;
}
static void
@@ -571,7 +716,32 @@ constraint_hints_hcenter_func (MetaWindow *window,
const MetaRectangle *orig,
int *x_delta)
{
+ int min_dx;
+ int max_dx;
+ int width;
+
+ /* Remember our delta is negative to shrink window, positive to
+ * grow it, and the actual resize is x_delta * 2 (which is broken,
+ * but that's how it currently is)
+ */
+
+ min_dx = (window->size_hints.min_width - orig->width) / 2;
+ max_dx = (window->size_hints.max_width - orig->width) / 2;
+
+ g_assert (max_dx >= min_dx);
+
+ if (*x_delta > max_dx)
+ *x_delta = max_dx;
+ if (*x_delta < min_dx)
+ *x_delta = min_dx;
+
+ /* shrink to base + N * inc
+ */
+ width = orig->width + *x_delta * 2;
+ width = window->size_hints.base_width +
+ FLOOR (width - window->size_hints.base_width, window->size_hints.width_inc);
+ *x_delta = (width - orig->width) / 2;
}
static void
@@ -585,6 +755,7 @@ constraint_hints_move_func (MetaWindow *window,
}
static const Constraint constraint_hints = {
+ "Hints",
constraint_hints_applies_func,
constraint_hints_top_func,
constraint_hints_bottom_func,
@@ -618,10 +789,18 @@ constrain_move (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d %d (Move constraint '%s')\n",
+ x_delta, y_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->move_func) (window, info, orig,
&x_delta, &y_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d %d (Move constraint '%s')\n",
+ x_delta, y_delta, (*cp)->name);
+
++cp;
}
@@ -642,17 +821,25 @@ constrain_resize_left (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (Left constraint '%s')\n",
+ x_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->left_func) (window, info, orig,
&x_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (Left constraint '%s')\n",
+ x_delta, (*cp)->name);
+
++cp;
}
/* Moving mouse from 10 to 5 means current - orig means 5 - 10 means
* a delta of -5
*/
- new->x = orig->x - x_delta;
+ new->x = orig->x + x_delta;
new->width = orig->width - x_delta;
}
@@ -664,23 +851,34 @@ constrain_resize_hcenter (MetaWindow *window,
MetaRectangle *new)
{
const Constraint **cp;
-
+
cp = &all_constraints[0];
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (HCenter constraint '%s')\n",
+ x_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->hcenter_func) (window, info, orig,
&x_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (HCenter constraint '%s')\n",
+ x_delta, (*cp)->name);
+
++cp;
}
-
+
/* center deltas are positive to grow the window and negative to
* shrink it.
*/
new->x = orig->x - x_delta;
new->width = orig->width + x_delta * 2;
+ /* FIXME above implies that with center gravity you have to grow
+ * in increments of two
+ */
}
static void
@@ -696,10 +894,18 @@ constrain_resize_right (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (Right constraint '%s')\n",
+ x_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->right_func) (window, info, orig,
&x_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (Right constraint '%s')\n",
+ x_delta, (*cp)->name);
+
++cp;
}
@@ -719,14 +925,22 @@ constrain_resize_top (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (Top constraint '%s')\n",
+ y_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->top_func) (window, info, orig,
&y_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (Top constraint '%s')\n",
+ y_delta, (*cp)->name);
+
++cp;
}
- new->y = orig->y - y_delta;
+ new->y = orig->y + y_delta;
new->height = orig->height - y_delta;
}
@@ -743,10 +957,18 @@ constrain_resize_vcenter (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (VCenter constraint '%s')\n",
+ y_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->vcenter_func) (window, info, orig,
&y_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (VCenter constraint '%s')\n",
+ y_delta, (*cp)->name);
+
++cp;
}
@@ -755,6 +977,9 @@ constrain_resize_vcenter (MetaWindow *window,
*/
new->y = orig->y - y_delta;
new->height = orig->height + y_delta * 2;
+ /* FIXME above implies that with center gravity you have to grow
+ * in increments of two
+ */
}
static void
@@ -770,14 +995,22 @@ constrain_resize_bottom (MetaWindow *window,
while (*cp)
{
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Before: %d (Bottom constraint '%s')\n",
+ y_delta, (*cp)->name);
+
if ((* (*cp)->applies_func) (window))
(* (*cp)->bottom_func) (window, info, orig,
&y_delta);
+ meta_topic (META_DEBUG_GEOMETRY,
+ "After: %d (Bottom constraint '%s')\n",
+ y_delta, (*cp)->name);
+
++cp;
}
- new->height = orig->y + y_delta;
+ new->height = orig->height + y_delta;
}
static void
@@ -786,15 +1019,14 @@ update_position_limits (MetaWindow *window,
{
int nw_x, nw_y;
int se_x, se_y;
- int offscreen_w, offscreen_h;
-
+
nw_x = info->work_area_screen.x;
nw_y = info->work_area_screen.y;
-
+
/* find bottom-right corner of workarea */
se_x = info->work_area_screen.x + info->work_area_screen.width;
se_y = info->work_area_screen.y + info->work_area_screen.height;
-
+
/* If we have a micro-screen or huge frames maybe nw/se got
* swapped
*/
@@ -804,7 +1036,7 @@ update_position_limits (MetaWindow *window,
nw_x = se_x;
se_x = tmp;
}
-
+
if (nw_y > se_y)
{
int tmp = nw_y;
@@ -840,7 +1072,16 @@ meta_window_constrain (MetaWindow *window,
{
ConstraintInfo info;
MetaRectangle current;
+
+#define OUTER_WIDTH(rect) ((rect).width + info.fgeom.left_width + info.fgeom.right_width)
+#define OUTER_HEIGHT(rect) ((rect).height + info.fgeom.top_height + info.fgeom.bottom_height)
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Constraining %s x_move_delta = %d y_move_delta = %d x_direction = %d y_direction = %d x_delta = %d y_delta = %d orig %d,%d %dx%d\n",
+ window->desc, x_move_delta, y_move_delta,
+ x_direction, y_direction, x_delta, y_delta,
+ orig->x, orig->y, orig->width, orig->height);
+
/* Create a fake frame geometry if none really exists */
if (orig_fgeom && !window->fullscreen)
info.fgeom = *orig_fgeom;
@@ -852,9 +1093,9 @@ meta_window_constrain (MetaWindow *window,
info.fgeom.right_width = 0;
}
- meta_window_get_work_area (window, TRUE, &info.work_area_xinerama);
- meta_window_get_work_area (window, FALSE, &info.work_area_screen);
-
+ meta_window_get_work_area_current_xinerama (window, &info.work_area_xinerama);
+ meta_window_get_work_area_all_xineramas (window, &info.work_area_screen);
+
info.window = window;
info.xinerama = meta_screen_get_xinerama_for_window (window->screen,
window);
@@ -864,7 +1105,7 @@ meta_window_constrain (MetaWindow *window,
current = *orig;
*new = current;
-
+
/* Do placement if any, so we go ahead and apply position
* constraints in a move-only context. Don't place
* maximized/fullscreen windows until they are unmaximized
@@ -876,13 +1117,19 @@ meta_window_constrain (MetaWindow *window,
!window->fullscreen)
{
int x, y;
-
- meta_window_place (window, orig_fgeom, x, y, &x, &y);
+
+ meta_window_place (window, orig_fgeom, current.x, current.y,
+ &x, &y);
constrain_move (window, &info, &current,
x - current.x,
y - current.y,
new);
+ current = *new;
+
+ /* Ignore any non-placement movement */
+ x_move_delta = 0;
+ y_move_delta = 0;
}
/* Maximization, fullscreen, etc. are defined as a move followed by
@@ -890,51 +1137,63 @@ meta_window_constrain (MetaWindow *window,
* this file.
*/
if (window->fullscreen)
- {
+ {
+ int center_x;
+
+ center_x = info.xinerama->x_origin + (info.xinerama->width / 2);
+ center_x -= OUTER_WIDTH (current) / 2;
+
constrain_move (window, &info, &current,
- info.xinerama->x_origin - current.x,
- info.xinerama->y_origin - current.y,
+ center_x - current.x,
+ info.xinerama->y_origin - current.y + info.fgeom.top_height,
new);
current = *new;
-
+
constrain_resize_bottom (window, &info, &current,
- info.xinerama->height - current.height,
+ (info.xinerama->height - OUTER_HEIGHT (current)),
new);
current = *new;
-
+
constrain_resize_hcenter (window, &info, &current,
- (info.xinerama->width - current.width) / 2,
+ (info.xinerama->width - OUTER_WIDTH (current)) / 2,
new);
+ current = *new;
}
else if (window->maximized)
{
+ int center_x;
+
+ center_x = info.work_area_xinerama.x + (info.work_area_xinerama.width / 2);
+ center_x -= OUTER_WIDTH (current) / 2;
+
constrain_move (window, &info, &current,
- info.work_area_xinerama.x - current.x,
- info.work_area_xinerama.y - current.y,
+ center_x - current.x,
+ info.work_area_xinerama.y - current.y + info.fgeom.top_height,
new);
current = *new;
-
+
constrain_resize_bottom (window, &info, &current,
- info.work_area_xinerama.height - current.height,
+ (info.work_area_xinerama.height - OUTER_HEIGHT (current)),
new);
current = *new;
-
+
constrain_resize_hcenter (window, &info, &current,
- (info.work_area_xinerama.width - current.width) / 2,
+ (info.work_area_xinerama.width - OUTER_WIDTH (current)) / 2,
new);
+ current = *new;
}
else
- {
+ {
constrain_move (window, &info, &current,
x_move_delta, y_move_delta,
new);
current = *new;
-
+
switch (x_direction)
{
case META_RESIZE_LEFT_OR_TOP:
@@ -966,103 +1225,119 @@ meta_window_constrain (MetaWindow *window,
y_delta, new);
break;
}
- }
- current = *new;
+ current = *new;
+ }
+#if 0
/* Now we have to sort out the aspect ratio */
-#define FLOOR(value, base) ( ((int) ((value) / (base))) * (base) )
- {
- /*
- * width
- * min_aspect <= -------- <= max_aspect
- * height
- */
- double min_aspect, max_aspect;
- int width, height;
-
- min_aspect = window->size_hints.min_aspect.x / (double) window->size_hints.min_aspect.y;
- max_aspect = window->size_hints.max_aspect.x / (double) window->size_hints.max_aspect.y;
-
- width = current.width;
- height = current.height;
-
- /* Use the standard cut-and-pasted-between-every-WM code: */
- if (min_aspect * height > width)
- {
- delta = FLOOR (height - width * min_aspect, window->size_hints.height_inc);
- if (height - delta >= window->size_hints.min_height)
- height -= delta;
- else
- {
- delta = FLOOR (height * min_aspect - width, window->size_hints.width_inc);
- if (width + delta <= window->size_hints.max_width)
- width += delta;
- }
- }
-
- if (max_aspect * height < width)
- {
- delta = FLOOR (width - height * max_aspect, window->size_hints.width_inc);
- if (width - delta >= window->size_hints.min_width)
- width -= delta;
- else
- {
- delta = FLOOR (width / max_aspect - height, window->size_hints.height_inc);
- if (height + delta <= window->size_hints.max_height)
- height += delta;
- }
- }
-
- /* Convert into terms of the direction of resize and reapply the
- * earlier constraints; this means aspect ratio becomes the
- * least-important of the constraints. If we wanted aspect to be
- * the most important, we could just not do this next bit.
- */
-
- if (current.width != width)
- {
- x_delta = width - current.width; /* positive delta to increase width */
- switch (x_direction)
- {
- case META_RESIZE_LEFT_OR_TOP:
- constrain_resize_left (window, &info, &current,
- - x_delta, new);
- break;
- case META_RESIZE_CENTER:
- constrain_resize_hcenter (window, &info, &current,
- x_delta, new);
- break;
- case META_RESIZE_RIGHT_OR_BOTTOM:
- constrain_resize_right (window, &info, &current,
- x_delta, new);
- break;
- }
- }
-
- if (current.height != height)
- {
- y_delta = height - current.height; /* positive to increase height */
-
- switch (y_direction)
- {
- case META_RESIZE_LEFT_OR_TOP:
- constrain_resize_top (window, &info, &current,
- - y_delta, new);
- break;
- case META_RESIZE_CENTER:
- constrain_resize_vcenter (window, &info, &current,
+ {
+ /*
+ * width
+ * min_aspect <= -------- <= max_aspect
+ * height
+ */
+ double min_aspect, max_aspect;
+ int width, height;
+
+ min_aspect = window->size_hints.min_aspect.x / (double) window->size_hints.min_aspect.y;
+ max_aspect = window->size_hints.max_aspect.x / (double) window->size_hints.max_aspect.y;
+
+ width = current.width;
+ height = current.height;
+
+ /* Use the standard cut-and-pasted-between-every-WM code: */
+ if (min_aspect * height > width)
+ {
+ int delta;
+
+ delta = FLOOR (height - width / min_aspect, window->size_hints.height_inc);
+ if (height - delta >= window->size_hints.min_height)
+ height -= delta;
+ else
+ {
+ delta = FLOOR (height * min_aspect - width, window->size_hints.width_inc);
+ if (width + delta <= window->size_hints.max_width)
+ width += delta;
+ }
+ }
+
+ if (max_aspect * height < width)
+ {
+ int delta;
+
+ delta = FLOOR (width - height * max_aspect, window->size_hints.width_inc);
+ if (width - delta >= window->size_hints.min_width)
+ width -= delta;
+ else
+ {
+ delta = FLOOR (width / max_aspect - height, window->size_hints.height_inc);
+ if (height + delta <= window->size_hints.max_height)
+ height += delta;
+ }
+ }
+
+ /* Convert into terms of the direction of resize and reapply the
+ * earlier constraints; this means aspect ratio becomes the
+ * least-important of the constraints. If we wanted aspect to be
+ * the most important, we could just not do this next bit.
+ */
+
+ if (current.width != width)
+ {
+ x_delta = width - current.width; /* positive delta to increase width */
+ switch (x_direction)
+ {
+ case META_RESIZE_LEFT_OR_TOP:
+ constrain_resize_left (window, &info, &current,
+ - x_delta, new);
+ break;
+ case META_RESIZE_CENTER:
+ constrain_resize_hcenter (window, &info, &current,
+ x_delta, new);
+ break;
+ case META_RESIZE_RIGHT_OR_BOTTOM:
+ constrain_resize_right (window, &info, &current,
+ x_delta, new);
+ break;
+ }
+ }
+
+ if (current.height != height)
+ {
+ y_delta = height - current.height; /* positive to increase height */
+
+ switch (y_direction)
+ {
+ case META_RESIZE_LEFT_OR_TOP:
+ constrain_resize_top (window, &info, &current,
+ - y_delta, new);
+ break;
+ case META_RESIZE_CENTER:
+ constrain_resize_vcenter (window, &info, &current,
+ y_delta, new);
+ break;
+ case META_RESIZE_RIGHT_OR_BOTTOM:
+ constrain_resize_bottom (window, &info, &current,
y_delta, new);
- break;
- case META_RESIZE_RIGHT_OR_BOTTOM:
- constrain_resize_bottom (window, &info, &current,
- y_delta, new);
- break;
- }
- }
- }
-#undef FLOOR
+ break;
+ }
+ }
+ current = *new;
+ }
+
+
+ g_print ("3 x_delta = %d y_delta = %d pos = %d,%d size = %dx%d\n",
+ x_delta, y_delta,
+ current.x, current.y, current.width, current.height);
+#endif
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Constrained %s new %d,%d %dx%d old %d,%d %dx%d\n",
+ window->desc,
+ new->x, new->y, new->width, new->height,
+ orig->x, orig->y, orig->width, orig->height);
}
MetaResizeDirection
@@ -1086,7 +1361,7 @@ meta_x_direction_from_gravity (int gravity)
default:
return META_RESIZE_CENTER;
break;
- }
+ }
}
MetaResizeDirection
@@ -1106,7 +1381,7 @@ meta_y_direction_from_gravity (int gravity)
case StaticGravity:
return META_RESIZE_RIGHT_OR_BOTTOM;
break;
-
+
default:
return META_RESIZE_CENTER;
}
diff --git a/src/window.c b/src/window.c
index 2c3bc86..1ae7be0 100644
--- a/src/window.c
+++ b/src/window.c
@@ -38,6 +38,7 @@
#include "xprops.h"
#include "group.h"
#include "window-props.h"
+#include "constraints.h"
#include <X11/Xatom.h>
#include <string.h>
@@ -65,18 +66,6 @@ typedef enum
static int destroying_windows_disallowed = 0;
-static void constrain_size (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- int width,
- int height,
- int *new_width,
- int *new_height);
-static void constrain_position (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- int x,
- int y,
- int *new_x,
- int *new_y);
static void update_net_wm_state (MetaWindow *window);
static void update_mwm_hints (MetaWindow *window);
@@ -103,14 +92,6 @@ static GList* meta_window_get_workspaces (MetaWindow *window);
static void meta_window_save_rect (MetaWindow *window);
-static void adjust_for_gravity (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- gboolean coords_assume_border,
- int x,
- int y,
- int *xp,
- int *yp);
-
static void meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,
@@ -2012,13 +1993,17 @@ meta_window_activate (MetaWindow *window,
meta_window_focus (window, timestamp);
}
-/* returns values suitable for meta_window_move */
+/* returns values suitable for meta_window_move
+ * i.e. static gravity
+ */
static void
adjust_for_gravity (MetaWindow *window,
MetaFrameGeometry *fgeom,
gboolean coords_assume_border,
int x,
int y,
+ int width,
+ int height,
int *xp,
int *yp)
{
@@ -2036,15 +2021,15 @@ adjust_for_gravity (MetaWindow *window,
{
child_x = fgeom->left_width;
child_y = fgeom->top_height;
- frame_width = child_x + window->rect.width + fgeom->right_width;
- frame_height = child_y + window->rect.height + fgeom->bottom_height;
+ frame_width = child_x + width + fgeom->right_width;
+ frame_height = child_y + height + fgeom->bottom_height;
}
else
{
child_x = 0;
child_y = 0;
- frame_width = window->rect.width;
- frame_height = window->rect.height;
+ frame_width = width;
+ frame_height = height;
}
/* We're computing position to pass to window_move, which is
@@ -2061,36 +2046,36 @@ adjust_for_gravity (MetaWindow *window,
ref_y = y;
break;
case NorthGravity:
- ref_x = x + window->rect.width / 2 + bw;
+ ref_x = x + width / 2 + bw;
ref_y = y;
break;
case NorthEastGravity:
- ref_x = x + window->rect.width + bw * 2;
+ ref_x = x + width + bw * 2;
ref_y = y;
break;
case WestGravity:
ref_x = x;
- ref_y = y + window->rect.height / 2 + bw;
+ ref_y = y + height / 2 + bw;
break;
case CenterGravity:
- ref_x = x + window->rect.width / 2 + bw;
- ref_y = y + window->rect.height / 2 + bw;
+ ref_x = x + width / 2 + bw;
+ ref_y = y + height / 2 + bw;
break;
case EastGravity:
- ref_x = x + window->rect.width + bw * 2;
- ref_y = y + window->rect.height / 2 + bw;
+ ref_x = x + width + bw * 2;
+ ref_y = y + height / 2 + bw;
break;
case SouthWestGravity:
ref_x = x;
- ref_y = y + window->rect.height + bw * 2;
+ ref_y = y + height + bw * 2;
break;
case SouthGravity:
- ref_x = x + window->rect.width / 2 + bw;
- ref_y = y + window->rect.height + bw * 2;
+ ref_x = x + width / 2 + bw;
+ ref_y = y + height + bw * 2;
break;
case SouthEastGravity:
- ref_x = x + window->rect.width + bw * 2;
- ref_y = y + window->rect.height + bw * 2;
+ ref_x = x + width + bw * 2;
+ ref_y = y + height + bw * 2;
break;
case StaticGravity:
default:
@@ -2152,6 +2137,47 @@ static_gravity_works (MetaDisplay *display)
}
static void
+get_mouse_deltas_for_resize (MetaWindow *window,
+ int resize_gravity,
+ int w,
+ int h,
+ int *x_delta,
+ int *y_delta)
+{
+ switch (meta_x_direction_from_gravity (resize_gravity))
+ {
+ case META_RESIZE_LEFT_OR_TOP:
+ *x_delta = window->rect.width - w;
+ break;
+ case META_RESIZE_RIGHT_OR_BOTTOM:
+ *x_delta = w - window->rect.width;
+ break;
+ case META_RESIZE_CENTER:
+ /* FIXME this implies that with center gravity you have to grow
+ * in increments of two
+ */
+ *x_delta = (w - window->rect.width) / 2;
+ break;
+ }
+
+ switch (meta_y_direction_from_gravity (resize_gravity))
+ {
+ case META_RESIZE_LEFT_OR_TOP:
+ *y_delta = window->rect.height - h;
+ break;
+ case META_RESIZE_RIGHT_OR_BOTTOM:
+ *y_delta = h - window->rect.height;
+ break;
+ case META_RESIZE_CENTER:
+ /* FIXME this implies that with center gravity you have to grow
+ * in increments of two
+ */
+ *y_delta = (h - window->rect.height) / 2;
+ break;
+ }
+}
+
+static void
meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,
@@ -2168,8 +2194,6 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean need_move_frame = FALSE;
gboolean need_resize_client = FALSE;
gboolean need_resize_frame = FALSE;
- int size_dx;
- int size_dy;
int frame_size_dx;
int frame_size_dy;
gboolean is_configure_request;
@@ -2182,39 +2206,73 @@ meta_window_move_resize_internal (MetaWindow *window,
*/
int client_move_x;
int client_move_y;
+ int x_delta;
+ int y_delta;
+ MetaRectangle new_rect;
+ MetaRectangle old_rect;
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
is_user_action = (flags & META_USER_MOVE_RESIZE) != 0;
/* We don't need it in the idle queue anymore. */
- meta_window_unqueue_move_resize (window);
+ meta_window_unqueue_move_resize (window);
- {
- int oldx, oldy;
- meta_window_get_position (window, &oldx, &oldy);
- meta_topic (META_DEBUG_GEOMETRY,
- "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n",
- window->desc, root_x_nw, root_y_nw, w, h,
- is_configure_request ? " (configure request)" : "",
- is_user_action ? " (user move/resize)" : "",
- oldx, oldy, window->rect.width, window->rect.height);
- }
+ old_rect = window->rect;
+ meta_window_get_position (window, &old_rect.x, &old_rect.y);
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n",
+ window->desc, root_x_nw, root_y_nw, w, h,
+ is_configure_request ? " (configure request)" : "",
+ is_user_action ? " (user move/resize)" : "",
+ old_rect.x, old_rect.y, old_rect.width, old_rect.height);
if (window->frame)
meta_frame_calc_geometry (window->frame,
&fgeom);
- constrain_size (window, &fgeom, w, h, &w, &h);
- meta_topic (META_DEBUG_GEOMETRY,
- "Constrained resize of %s to %d x %d\n", window->desc, w, h);
+ if (is_configure_request || do_gravity_adjust)
+ {
+ adjust_for_gravity (window,
+ window->frame ? &fgeom : NULL,
+ /* configure request coords assume
+ * the border width existed
+ */
+ is_configure_request,
+ root_x_nw,
+ root_y_nw,
+ w, h,
+ &root_x_nw,
+ &root_y_nw);
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Compensated position for gravity, new pos %d,%d\n",
+ root_x_nw, root_y_nw);
+ }
+ get_mouse_deltas_for_resize (window, resize_gravity, w, h,
+ &x_delta, &y_delta);
+
+ meta_window_constrain (window,
+ &fgeom,
+ &old_rect,
+ root_x_nw - old_rect.x,
+ root_y_nw - old_rect.y,
+ meta_x_direction_from_gravity (resize_gravity),
+ x_delta,
+ meta_y_direction_from_gravity (resize_gravity),
+ y_delta,
+ &new_rect);
+
+ w = new_rect.width;
+ h = new_rect.height;
+ root_x_nw = new_rect.x;
+ root_y_nw = new_rect.y;
+
if (w != window->rect.width ||
h != window->rect.height)
need_resize_client = TRUE;
-
- size_dx = w - window->rect.width;
- size_dy = h - window->rect.height;
window->rect.width = w;
window->rect.height = h;
@@ -2249,73 +2307,6 @@ meta_window_move_resize_internal (MetaWindow *window,
frame_size_dy = 0;
}
- if (is_configure_request || do_gravity_adjust)
- {
- adjust_for_gravity (window,
- window->frame ? &fgeom : NULL,
- /* configure request coords assume
- * the border width existed
- */
- is_configure_request,
- root_x_nw,
- root_y_nw,
- &root_x_nw,
- &root_y_nw);
-
- meta_topic (META_DEBUG_GEOMETRY,
- "Compensated position for gravity, new pos %d,%d\n",
- root_x_nw, root_y_nw);
- }
-
- /* There can be somewhat bogus interactions between gravity
- * and the position constraints (with position contraints
- * basically breaking gravity). Not sure how to fix this.
- */
-
- switch (resize_gravity)
- {
- /* If client is staying fixed on the east during resize, then we
- * have to move the west edge.
- */
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- root_x_nw -= size_dx;
- break;
-
- /* centered horizontally */
- case NorthGravity:
- case SouthGravity:
- case CenterGravity:
- root_x_nw -= size_dx / 2;
- break;
-
- default:
- break;
- }
-
- switch (resize_gravity)
- {
- /* If client is staying fixed on the south during resize,
- * we have to move the north edge
- */
- case SouthGravity:
- case SouthEastGravity:
- case SouthWestGravity:
- root_y_nw -= size_dy;
- break;
-
- /* centered vertically */
- case EastGravity:
- case WestGravity:
- case CenterGravity:
- root_y_nw -= size_dy / 2;
- break;
-
- default:
- break;
- }
-
/* For nice effect, when growing the window we want to move/resize
* the frame first, when shrinking the window we want to move/resize
* the client first. If we grow one way and shrink the other,
@@ -2330,15 +2321,6 @@ meta_window_move_resize_internal (MetaWindow *window,
* behavior. The move and resize must actually occur, it is not
* enough to set CWX | CWWidth but pass in the current size/pos.
*/
-
- constrain_position (window,
- window->frame ? &fgeom : NULL,
- root_x_nw, root_y_nw,
- &root_x_nw, &root_y_nw);
-
- meta_topic (META_DEBUG_GEOMETRY,
- "Constrained position to %d,%d\n",
- root_x_nw, root_y_nw);
if (window->frame)
{
@@ -2473,6 +2455,9 @@ meta_window_move_resize_internal (MetaWindow *window,
*/
if (use_static_gravity)
{
+ int size_dx = w - window->rect.width;
+ int size_dy = h - window->rect.height;
+
if ((size_dx + size_dy) >= 0)
configure_frame_first = FALSE;
else
@@ -5387,360 +5372,6 @@ recalc_window_features (MetaWindow *window)
}
static void
-constrain_size (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- int width, int height,
- int *new_width, int *new_height)
-{
- /* This is partially borrowed from GTK (LGPL), which in turn
- * partially borrowed from fvwm,
- *
- * Copyright 1993, Robert Nation
- * You may use this code for any purpose, as long as the original
- * copyright remains in the source code and all documentation
- *
- * which in turn borrows parts of the algorithm from uwm
- */
- int delta;
- double min_aspect, max_aspect;
- int minw, minh, maxw, maxh, fullw, fullh;
-
- /* frame member variables should NEVER be used in here */
-
-#define FLOOR(value, base) ( ((int) ((value) / (base))) * (base) )
-
- /* Get the allowed size ranges, considering maximized, etc. */
- if (window->fullscreen)
- {
- const MetaXineramaScreenInfo *xinerama;
-
- xinerama = meta_screen_get_xinerama_for_window (window->screen,
- window);
-
-
- fullw = xinerama->width;
- fullh = xinerama->height;
- }
- else if (window->type == META_WINDOW_DESKTOP ||
- window->type == META_WINDOW_DOCK)
- {
-
- fullw = window->screen->width;
- fullh = window->screen->height;
- }
- else
- {
- MetaRectangle work_area;
-
- meta_window_get_work_area_current_xinerama (window, &work_area);
-
- fullw = work_area.width;
- fullh = work_area.height;
- }
-
- if (window->frame && !window->fullscreen)
- {
- fullw -= (fgeom->left_width + fgeom->right_width);
- fullh -= (fgeom->top_height + fgeom->bottom_height);
- }
-
- maxw = window->size_hints.max_width;
- maxh = window->size_hints.max_height;
-
- if (window->maximized || window->fullscreen)
- {
- maxw = MIN (maxw, fullw);
- maxh = MIN (maxh, fullh);
- }
-
- minw = window->size_hints.min_width;
- minh = window->size_hints.min_height;
-
- /* Check that fullscreen doesn't go under app-specified min size, if
- * so snap back to min size
- */
- if (maxw < minw)
- maxw = minw;
- if (maxh < minh)
- maxh = minh;
-
- if (window->maximized || window->fullscreen)
- {
- minw = MAX (minw, fullw);
- minh = MAX (minh, fullh);
- }
-
- /* Check that fullscreen doesn't exceed max width hint,
- * if so then snap back to max width hint
- */
- if (minw > maxw)
- minw = maxw;
- if (minh > maxh)
- minh = maxh;
-
- /* clamp width and height to min and max values
- */
- width = CLAMP (width, minw, maxw);
-
- height = CLAMP (height, minh, maxh);
-
- /* shrink to base + N * inc
- */
- width = window->size_hints.base_width +
- FLOOR (width - window->size_hints.base_width, window->size_hints.width_inc);
- height = window->size_hints.base_height +
- FLOOR (height - window->size_hints.base_height, window->size_hints.height_inc);
-
- /* constrain aspect ratio, according to:
- *
- * width
- * min_aspect <= -------- <= max_aspect
- * height
- */
-
- min_aspect = window->size_hints.min_aspect.x / (double) window->size_hints.min_aspect.y;
- max_aspect = window->size_hints.max_aspect.x / (double) window->size_hints.max_aspect.y;
-
- if (min_aspect * height > width)
- {
- delta = FLOOR (height - width / min_aspect, window->size_hints.height_inc);
- if (height - delta >= window->size_hints.min_height)
- height -= delta;
- else
- {
- delta = FLOOR (height * min_aspect - width, window->size_hints.width_inc);
- if (width + delta <= window->size_hints.max_width)
- width += delta;
- }
- }
-
- if (max_aspect * height < width)
- {
- delta = FLOOR (width - height * max_aspect, window->size_hints.width_inc);
- if (width - delta >= window->size_hints.min_width)
- width -= delta;
- else
- {
- delta = FLOOR (width / max_aspect - height, window->size_hints.height_inc);
- if (height + delta <= window->size_hints.max_height)
- height += delta;
- }
- }
-
-#undef FLOOR
-
- *new_width = width;
- *new_height = height;
-}
-
-static void
-constrain_position (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- int x,
- int y,
- int *new_x,
- int *new_y)
-{
- /* frame member variables should NEVER be used in here, only
- * MetaFrameGeometry
- */
-
- if (!window->placed && window->calc_placement)
- meta_window_place (window, fgeom, x, y, &x, &y);
-
- if (window->type == META_WINDOW_DESKTOP)
- {
- x = 0;
- y = 0;
- }
- else if (window->type == META_WINDOW_DOCK)
- {
- ; /* let it do whatever */
- }
- else if (window->fullscreen)
- {
- const MetaXineramaScreenInfo *xinerama;
-
- xinerama = meta_screen_get_xinerama_for_window (window->screen,
- window);
-
- x = xinerama->x_origin;
- y = xinerama->y_origin;
-
- /* If the window's geometry gridding (e.g. for a terminal)
- * prevents fullscreen, center the window within
- * the screen area.
- */
- x += (xinerama->width - window->rect.width) / 2;
-
- /* If the window is somehow larger than the screen be paranoid
- * and fix the resulting negative coords
- */
- if (x < xinerama->x_origin)
- x = xinerama->x_origin;
- }
- else if (window->maximized)
- {
- const MetaXineramaScreenInfo* xsi;
- MetaRectangle work_area;
-
- xsi = meta_screen_get_xinerama_for_rect (window->screen,
- &window->saved_rect);
-
- meta_window_get_work_area_for_xinerama (window,
- xsi->number,
- &work_area);
-
- x = work_area.x;
- y = work_area.y;
- if (window->frame)
- {
- x += fgeom->left_width;
- y += fgeom->top_height;
- }
-
- /* If the window's geometry gridding (e.g. for a terminal)
- * prevents full maximization, center the window within
- * the maximized area horizontally.
- */
- x += (work_area.width - window->rect.width -
- (window->frame ? (fgeom->left_width + fgeom->right_width) : 0)) / 2;
- }
- else
- {
- int nw_x, nw_y;
- int se_x, se_y;
- int offscreen_w, offscreen_h;
- MetaRectangle work_area;
- MetaRectangle window_area;
- const MetaXineramaScreenInfo* xsi;
-
- /* this is the rect for the window if it were where we're moving
- * it now
- */
- meta_window_get_outer_rect (window, &window_area);
- window_area.x = x;
- window_area.y = y;
- if (fgeom)
- {
- window_area.x -= fgeom->left_width;
- window_area.y -= fgeom->top_height;
- }
-
- xsi = meta_screen_get_xinerama_for_rect (window->screen, &window_area);
- meta_window_get_work_area_for_xinerama (window,
- xsi->number,
- &work_area);
-
- /* (FIXME instead of TITLEBAR_LENGTH_ONSCREEN, get the actual
- * size of the menu control?).
- */
-
-#define TITLEBAR_LENGTH_ONSCREEN 36
-
- /* find furthest northwest point the window can occupy */
- nw_x = work_area.x;
- nw_y = work_area.y;
-
- /* FIXME note this means framed windows can go off the left
- * but not unframed windows.
- */
- if (window->frame)
- {
- /* Must keep TITLEBAR_LENGTH_ONSCREEN onscreen when moving left */
- nw_x -= fgeom->left_width + window->rect.width + fgeom->right_width - TITLEBAR_LENGTH_ONSCREEN;
- /* Can't move off the top */
- nw_y += fgeom->top_height;
- }
-
- /* find bottom-right corner of workarea */
- se_x = work_area.x + work_area.width;
- se_y = work_area.y + work_area.height;
-
- /* if the window's size exceeds the screen size,
- * we allow it to go off the top/left far enough
- * to get the right/bottom edges onscreen.
- */
- offscreen_w = nw_x + window->rect.width;
- offscreen_h = nw_y + window->rect.height;
- if (window->frame)
- {
- offscreen_w += fgeom->right_width;
- offscreen_h += fgeom->bottom_height;
- }
-
- offscreen_w = offscreen_w - se_x;
- offscreen_h = offscreen_h - se_y;
-
- /* Now change NW limit to reflect amount offscreen in SE direction */
- if (offscreen_w > 0)
- nw_x -= offscreen_w;
-
- /* do it for top of window for undecorated windows,
- * since losing the titlebar isn't really an issue anyway,
- * and it fixes fullscreen mode for stuff like Xine.
- * but don't lose the titlebar on decorated windows.
- */
- if (!window->decorated && offscreen_h > 0)
- nw_y -= offscreen_h;
-
- /* Limit movement off the right/bottom.
- * Remember, we're constraining StaticGravity position.
- */
- if (window->frame)
- {
- se_x -= TITLEBAR_LENGTH_ONSCREEN;
- se_y -= 0;
- }
- else
- {
- /* for frameless windows, just require an arbitrary little
- * chunk to be onscreen
- */
- se_x -= TITLEBAR_LENGTH_ONSCREEN;
- se_y -= TITLEBAR_LENGTH_ONSCREEN;
- }
-
- /* If we have a micro-screen or huge frames maybe nw/se got
- * swapped
- */
- if (nw_x > se_x)
- {
- int tmp = nw_x;
- nw_x = se_x;
- se_x = tmp;
- }
-
- if (nw_y > se_y)
- {
- int tmp = nw_y;
- nw_y = se_y;
- se_y = tmp;
- }
-
- /* Clamp window to the given positions.
- * Do the SE clamp first, so that the NW clamp has precedence
- * and we don't tend to lose the titlebar for too-large
- * windows.
- */
- if (x > se_x)
- x = se_x;
- if (y > se_y)
- y = se_y;
-
- if (x < nw_x)
- x = nw_x;
- if (y < nw_y)
- y = nw_y;
-
-#undef TITLEBAR_LENGTH_ONSCREEN
- }
-
- *new_x = x;
- *new_y = y;
-}
-
-static void
menu_callback (MetaWindowMenu *menu,
Display *xdisplay,
Window client_xwindow,
@@ -6350,9 +5981,9 @@ meta_window_set_gravity (MetaWindow *window,
}
static void
-get_work_area (MetaWindow *window,
- MetaRectangle *area,
- int which_xinerama)
+get_work_area_xinerama (MetaWindow *window,
+ MetaRectangle *area,
+ int which_xinerama)
{
MetaRectangle space_area;
GList *tmp;
@@ -6393,7 +6024,7 @@ get_work_area (MetaWindow *window,
bottom_strut = MAX (bottom_strut,
(xinerama_height -
(space_area.y - xinerama_origin_y) -
- space_area.height));
+ space_area.height));
tmp = tmp->next;
}
@@ -6403,8 +6034,9 @@ get_work_area (MetaWindow *window,
area->height = xinerama_height - top_strut - bottom_strut;
meta_topic (META_DEBUG_WORKAREA,
- "Window %s has work area %d,%d %d x %d\n",
- window->desc, area->x, area->y, area->width, area->height);
+ "Window %s xinerama %d has work area %d,%d %d x %d\n",
+ window->desc, which_xinerama,
+ area->x, area->y, area->width, area->height);
}
void
@@ -6427,11 +6059,66 @@ meta_window_get_work_area_for_xinerama (MetaWindow *window,
{
g_return_if_fail (which_xinerama >= 0);
- get_work_area (window,
- area,
- which_xinerama);
+ get_work_area_xinerama (window,
+ area,
+ which_xinerama);
+}
+
+void
+meta_window_get_work_area_all_xineramas (MetaWindow *window,
+ MetaRectangle *area)
+{
+ MetaRectangle space_area;
+ GList *tmp;
+ int left_strut;
+ int right_strut;
+ int top_strut;
+ int bottom_strut;
+ int screen_origin_x;
+ int screen_origin_y;
+ int screen_width;
+ int screen_height;
+
+ screen_origin_x = 0;
+ screen_origin_y = 0;
+ screen_width = window->screen->width;
+ screen_height = window->screen->height;
+
+ left_strut = 0;
+ right_strut = 0;
+ top_strut = 0;
+ bottom_strut = 0;
+
+ tmp = meta_window_get_workspaces (window);
+ while (tmp != NULL)
+ {
+ meta_workspace_get_work_area_all_xineramas (tmp->data,
+ &space_area);
+
+ left_strut = MAX (left_strut, space_area.x - screen_origin_x);
+ right_strut = MAX (right_strut,
+ (screen_width -
+ (space_area.x - screen_origin_x) -
+ space_area.width));
+ top_strut = MAX (top_strut, space_area.y - screen_origin_y);
+ bottom_strut = MAX (bottom_strut,
+ (screen_height -
+ (space_area.y - screen_origin_y) -
+ space_area.height));
+ tmp = tmp->next;
+ }
+
+ area->x = screen_origin_x + left_strut;
+ area->y = screen_origin_y + top_strut;
+ area->width = screen_width - left_strut - right_strut;
+ area->height = screen_height - top_strut - bottom_strut;
+
+ meta_topic (META_DEBUG_WORKAREA,
+ "Window %s has whole-screen work area %d,%d %d x %d\n",
+ window->desc, area->x, area->y, area->width, area->height);
}
+
gboolean
meta_window_same_application (MetaWindow *window,
MetaWindow *other_window)
diff --git a/src/window.h b/src/window.h
index 59ae998..202bddf 100644
--- a/src/window.h
+++ b/src/window.h
@@ -424,6 +424,8 @@ void meta_window_get_work_area_current_xinerama (MetaWindow *window,
void meta_window_get_work_area_for_xinerama (MetaWindow *window,
int which_xinerama,
MetaRectangle *area);
+void meta_window_get_work_area_all_xineramas (MetaWindow *window,
+ MetaRectangle *area);
gboolean meta_window_same_application (MetaWindow *window,
diff --git a/src/wm-tester/test-gravity.c b/src/wm-tester/test-gravity.c
index 10c4bcb..d74a7c3 100644
--- a/src/wm-tester/test-gravity.c
+++ b/src/wm-tester/test-gravity.c
@@ -1,6 +1,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
+#include <string.h>
int gravities[10] = {
NorthWestGravity,
@@ -15,17 +16,68 @@ int gravities[10] = {
StaticGravity
};
+typedef struct
+{
+ int x, y, width, height;
+} Rectangle;
+
Window windows[10];
+int doubled[10] = { 0, };
+Rectangle window_rects[10];
-int x_offset[3] = { 0, -50, -100 };
-int y_offset[3] = { 0, -50, -100 };
+#define WINDOW_WIDTH 100
+#define WINDOW_HEIGHT 100
+
+int x_offset[3] = { 0, - WINDOW_WIDTH/2, -WINDOW_WIDTH };
+int y_offset[3] = { 0, - WINDOW_HEIGHT/2, -WINDOW_HEIGHT };
double screen_x_fraction[3] = { 0, 0.5, 1.0 };
double screen_y_fraction[3] = { 0, 0.5, 1.0 };
int screen_width;
int screen_height;
+static const char*
+window_gravity_to_string (int gravity)
+{
+ switch (gravity)
+ {
+ case NorthWestGravity:
+ return "NorthWestGravity";
+ break;
+ case NorthGravity:
+ return "NorthGravity";
+ break;
+ case NorthEastGravity:
+ return "NorthEastGravity";
+ break;
+ case WestGravity:
+ return "WestGravity";
+ break;
+ case CenterGravity:
+ return "CenterGravity";
+ break;
+ case EastGravity:
+ return "EastGravity";
+ break;
+ case SouthWestGravity:
+ return "SouthWestGravity";
+ break;
+ case SouthGravity:
+ return "SouthGravity";
+ break;
+ case SouthEastGravity:
+ return "SouthEastGravity";
+ break;
+ case StaticGravity:
+ return "StaticGravity";
+ break;
+ default:
+ return "NorthWestGravity";
+ break;
+ }
+}
+
static void
-calculate_position (int i, int *x, int *y)
+calculate_position (int i, int doubled, int *x, int *y)
{
if (i == 9)
{
@@ -34,9 +86,30 @@ calculate_position (int i, int *x, int *y)
}
else
{
- *x = screen_x_fraction[i % 3] * screen_width + x_offset[i % 3];
- *y = screen_y_fraction[i / 3] * screen_height + y_offset[i / 3];
+ int xoff = x_offset[i % 3];
+ int yoff = y_offset[i / 3];
+ if (doubled)
+ {
+ xoff *= 2;
+ yoff *= 2;
+ }
+
+ *x = screen_x_fraction[i % 3] * screen_width + xoff;
+ *y = screen_y_fraction[i / 3] * screen_height + yoff;
+ }
+}
+
+static int
+find_window (Window window)
+{
+ int i;
+ for (i=0; i<10; i++)
+ {
+ if (windows[i] == window)
+ return i;
}
+
+ return -1;
}
int main (int argc, char **argv)
@@ -58,25 +131,42 @@ int main (int argc, char **argv)
{
int x, y;
- calculate_position (i, &x, &y);
+ calculate_position (i, doubled[i], &x, &y);
- w = XCreateSimpleWindow(d, RootWindow(d, screen),
- x, y, 100, 100, 0,
- WhitePixel(d, screen), WhitePixel(d, screen));
+ w = XCreateSimpleWindow (d, RootWindow (d, screen),
+ x, y, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
+ WhitePixel (d, screen), WhitePixel (d, screen));
windows[i] = w;
-
- XSelectInput (d, w, ButtonPressMask);
+ window_rects[i].x = x;
+ window_rects[i].y = y;
+ window_rects[i].width = WINDOW_WIDTH;
+ window_rects[i].height = WINDOW_HEIGHT;
+
+ XSelectInput (d, w, ButtonPressMask | ExposureMask | StructureNotifyMask);
hints.flags = USPosition | PMinSize | PMaxSize | PWinGravity;
- hints.min_width = 100;
- hints.min_height = 100;
- hints.max_width = 200;
- hints.max_height = 200;
+ hints.min_width = WINDOW_WIDTH / 2;
+ hints.min_height = WINDOW_HEIGHT / 2;
+
+#if 1
+ /* we constrain max size below the "doubled" size so that
+ * the WM will have to deal with constraints
+ * at the same time it's dealing with configure request
+ */
+ hints.max_width = WINDOW_WIDTH * 2 - WINDOW_WIDTH / 2;
+ hints.max_height = WINDOW_HEIGHT * 2 - WINDOW_HEIGHT / 2;
+#else
+ hints.max_width = WINDOW_WIDTH * 2 + WINDOW_WIDTH / 2;
+ hints.max_height = WINDOW_HEIGHT * 2 + WINDOW_HEIGHT / 2;
+#endif
hints.win_gravity = gravities[i];
XSetWMNormalHints (d, w, &hints);
+
+ XStoreName (d, w, window_gravity_to_string (hints.win_gravity));
+
XMapWindow (d, w);
}
@@ -84,25 +174,106 @@ int main (int argc, char **argv)
{
XNextEvent (d, &ev);
- if (ev.xany.type == ButtonPress)
+ if (ev.xany.type == ConfigureNotify)
+ {
+ i = find_window (ev.xconfigure.window);
+
+ if (i >= 0)
+ {
+ Window ignored;
+
+ window_rects[i].width = ev.xconfigure.width;
+ window_rects[i].height = ev.xconfigure.height;
+
+ XClearArea (d, windows[i], 0, 0,
+ ev.xconfigure.width,
+ ev.xconfigure.height,
+ True);
+
+ if (!ev.xconfigure.send_event)
+ XTranslateCoordinates (d, windows[i], DefaultRootWindow (d),
+ 0, 0,
+ &window_rects[i].x, &window_rects[i].y,
+ &ignored);
+ else
+ {
+ window_rects[i].x = ev.xconfigure.x;
+ window_rects[i].y = ev.xconfigure.y;
+ }
+ }
+ }
+ else if (ev.xany.type == Expose)
+ {
+ i = find_window (ev.xexpose.window);
+
+ if (i >= 0)
+ {
+ GC gc;
+ XGCValues values;
+ char buf[256];
+
+ values.foreground = BlackPixel (d, screen);
+
+ gc = XCreateGC (d, windows[i],
+ GCForeground, &values);
+
+ sprintf (buf,
+ "%d,%d",
+ window_rects[i].x,
+ window_rects[i].y);
+
+ XDrawString (d, windows[i], gc, 10, 15,
+ buf, strlen (buf));
+
+ sprintf (buf,
+ "%dx%d",
+ window_rects[i].width,
+ window_rects[i].height);
+
+ XDrawString (d, windows[i], gc, 10, 35,
+ buf, strlen (buf));
+
+ XFreeGC (d, gc);
+ }
+ }
+ else if (ev.xany.type == ButtonPress)
{
- for (i=0; i<10; i++)
- {
- if (windows[i] == ev.xbutton.window)
- {
- if (ev.xbutton.button == Button1)
- {
- int x, y;
+ i = find_window (ev.xbutton.window);
+
+ if (i >= 0)
+ {
+ /* Button 1 = move, 2 = resize, 3 = both at once */
+
+ if (ev.xbutton.button == Button1)
+ {
+ int x, y;
- calculate_position (i, &x, &y);
- w = XMoveWindow (d, windows[i], x, y);
- }
- else
- {
- w = XResizeWindow (d, windows[i], 200, 200);
- }
- }
- }
+ calculate_position (i, doubled[i], &x, &y);
+ XMoveWindow (d, windows[i], x, y);
+ }
+ else if (ev.xbutton.button == Button2)
+ {
+ if (doubled[i])
+ XResizeWindow (d, windows[i], WINDOW_WIDTH, WINDOW_HEIGHT);
+ else
+ XResizeWindow (d, windows[i], WINDOW_WIDTH*2, WINDOW_HEIGHT*2);
+
+ doubled[i] = !doubled[i];
+ }
+ else if (ev.xbutton.button == Button3)
+ {
+ int x, y;
+
+ calculate_position (i, !doubled[i], &x, &y);
+
+ if (doubled[i])
+ XMoveResizeWindow (d, windows[i], x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+ else
+ XMoveResizeWindow (d, windows[i], x, y, WINDOW_WIDTH*2, WINDOW_HEIGHT*2);
+
+ doubled[i] = !doubled[i];
+ }
+ }
}
}