diff --git a/ChangeLog b/ChangeLog index b6bd36f90..47823b7f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2003-02-27 Havoc Pennington + + 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 * src/window-props.c (reload_normal_hints): Check that window min diff --git a/src/Makefile.am b/src/Makefile.am index 6b1087574..b4ca784b0 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 c98262484..cd686e623 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 #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 @@ -337,6 +342,36 @@ constraint_onscreen_applies_func (MetaWindow *window) window->type != META_WINDOW_DOCK; } +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, @@ -344,8 +379,12 @@ constraint_onscreen_top_func (MetaWindow *window, 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; - max_dy = info->se_y - info->fgeom.top_height - orig->y; + get_outermost_onscreen_positions (window, info, orig, + NULL, NULL, NULL, &bottommost_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; - max_dx = info->se_x - TITLEBAR_WIDTH_ONSCREEN - orig->x; + get_outermost_onscreen_positions (window, info, orig, + NULL, &rightmost_x, NULL, NULL); + + 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, ¤t, 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, ¤t, - 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, ¤t, - info.xinerama->height - current.height, + (info.xinerama->height - OUTER_HEIGHT (current)), new); current = *new; - + constrain_resize_hcenter (window, &info, ¤t, - (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, ¤t, - 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, ¤t, - info.work_area_xinerama.height - current.height, + (info.work_area_xinerama.height - OUTER_HEIGHT (current)), new); current = *new; - + constrain_resize_hcenter (window, &info, ¤t, - (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, ¤t, 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 + * min_aspect <= -------- <= max_aspect + * height + */ + double min_aspect, max_aspect; + int width, height; - width = current.width; - height = current.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; - /* 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; - } - } + width = current.width; + height = current.height; - /* 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. - */ + /* Use the standard cut-and-pasted-between-every-WM code: */ + if (min_aspect * height > width) + { + int delta; - 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, ¤t, - - x_delta, new); - break; - case META_RESIZE_CENTER: - constrain_resize_hcenter (window, &info, ¤t, - x_delta, new); - break; - case META_RESIZE_RIGHT_OR_BOTTOM: - constrain_resize_right (window, &info, ¤t, - x_delta, new); - break; - } - } + 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 (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, ¤t, - - y_delta, new); - break; - case META_RESIZE_CENTER: - constrain_resize_vcenter (window, &info, ¤t, + 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, ¤t, + - x_delta, new); + break; + case META_RESIZE_CENTER: + constrain_resize_hcenter (window, &info, ¤t, + x_delta, new); + break; + case META_RESIZE_RIGHT_OR_BOTTOM: + constrain_resize_right (window, &info, ¤t, + 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, ¤t, + - y_delta, new); + break; + case META_RESIZE_CENTER: + constrain_resize_vcenter (window, &info, ¤t, + y_delta, new); + break; + case META_RESIZE_RIGHT_OR_BOTTOM: + constrain_resize_bottom (window, &info, ¤t, y_delta, new); - break; - case META_RESIZE_RIGHT_OR_BOTTOM: - constrain_resize_bottom (window, &info, ¤t, - 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 2c3bc8629..1ae7be066 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 #include @@ -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: @@ -2151,6 +2136,47 @@ static_gravity_works (MetaDisplay *display) return display->static_gravity_works; } +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, @@ -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 @@ -5386,360 +5371,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, @@ -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 59ae99866..202bddfaf 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 10c4bcbee..d74a7c3a8 100644 --- a/src/wm-tester/test-gravity.c +++ b/src/wm-tester/test-gravity.c @@ -1,6 +1,7 @@ #include #include #include +#include int gravities[10] = { NorthWestGravity, @@ -15,17 +16,68 @@ int gravities[10] = { StaticGravity }; -Window windows[10]; +typedef struct +{ + int x, y, width, height; +} Rectangle; -int x_offset[3] = { 0, -50, -100 }; -int y_offset[3] = { 0, -50, -100 }; +Window windows[10]; +int doubled[10] = { 0, }; +Rectangle window_rects[10]; + +#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,11 +86,32 @@ 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) { Display *d; @@ -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]; + } + } } }