summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-08-06 04:11:23 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-08-06 04:11:23 +0000
commit00dcef82e32456c6202f2ebb509ce411b5825eb8 (patch)
tree6595ec8a2ede066e71620e8013947daf379ad15b
parentf15e959634f57513088143e81491ab9deacbeee9 (diff)
downloadmetacity-00dcef82e32456c6202f2ebb509ce411b5825eb8.tar.gz
metacity-00dcef82e32456c6202f2ebb509ce411b5825eb8.tar.bz2
disable animation when shading windows, just doesn't really convey the
2002-07-28 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_shade): disable animation when shading windows, just doesn't really convey the idea anyway. * src/effects.c: Move to using a shaped window instead of IncludeInferiors to do the animations, looks a lot better because we don't have to grab the server. * src/window.c (meta_window_change_workspace): remove bogus assertion that was causing a crash (meta_window_new): auto-fullscreen huge undecorated windows. * src/keybindings.c (switch_to_workspace): use meta_window_change_workspace() to avoid same bug in cut-and-paste code from there
-rw-r--r--ChangeLog17
-rwxr-xr-xautogen.sh4
-rw-r--r--src/constraints.c1017
-rw-r--r--src/constraints.h17
-rw-r--r--src/display.c2
-rw-r--r--src/effects.c140
-rw-r--r--src/keybindings.c10
-rw-r--r--src/screen.c1
-rw-r--r--src/window.c50
9 files changed, 1151 insertions, 107 deletions
diff --git a/ChangeLog b/ChangeLog
index 74e2039..bde18b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2002-07-28 Havoc Pennington <hp@pobox.com>
+
+ * src/window.c (meta_window_shade): disable animation when shading
+ windows, just doesn't really convey the idea anyway.
+
+ * src/effects.c: Move to using a shaped window instead of
+ IncludeInferiors to do the animations, looks a lot better
+ because we don't have to grab the server.
+
+ * src/window.c (meta_window_change_workspace): remove bogus
+ assertion that was causing a crash
+ (meta_window_new): auto-fullscreen huge undecorated windows.
+
+ * src/keybindings.c (switch_to_workspace): use
+ meta_window_change_workspace() to avoid same bug in cut-and-paste
+ code from there
+
2002-08-06 He Qiangqiang <carton@linux.net.cn>
* configure.in: Added "zh_CN" to ALL_LINGUAS.
diff --git a/autogen.sh b/autogen.sh
index ac91e64..8b44400 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -112,14 +112,18 @@ do
echo "Running libtoolize..."
libtoolize --force --copy
fi
+
echo "Running $ACLOCAL $aclocalinclude ..."
$ACLOCAL $aclocalinclude
+
if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
echo "Running autoheader..."
autoheader
fi
+
echo "Running $AUTOMAKE --gnu $am_opt ..."
$AUTOMAKE --add-missing --gnu $am_opt
+
echo "Running autoconf ..."
autoconf
)
diff --git a/src/constraints.c b/src/constraints.c
index 796d19b..c982624 100644
--- a/src/constraints.c
+++ b/src/constraints.c
@@ -19,7 +19,8 @@
* 02111-1307, USA.
*/
-#include <constraints.h>
+#include "constraints.h"
+#include "place.h"
/* The way this code works was suggested by Owen Taylor.
*
@@ -72,7 +73,9 @@
* modify both the Y position and the height of the window into an
* operation that modifies a single variable, dy. That variable is
* then constrained, rather than the constraining the Y pos and height
- * separately.
+ * separately. This is a rather complicated fix for an obscure bug
+ * that happened when resizing a window and encountering a constraint
+ * such as the top edge of the screen.
*
*/
@@ -103,55 +106,160 @@
*
*/
-/* Clamps the delta to nearest permitted.
- * delta is the "free variable" in any given operation.
+typedef struct
+{
+ MetaWindow *window;
+ MetaFrameGeometry fgeom;
+ const MetaXineramaScreenInfo *xinerama;
+ MetaRectangle work_area_xinerama;
+ MetaRectangle work_area_screen;
+ int nw_x, nw_y, se_x, se_y;
+} ConstraintInfo;
+
+/* (FIXME instead of TITLEBAR_LENGTH_ONSCREEN, get the actual
+ * size of the menu control?).
*/
-typedef void (* MetaConstraintFunc) (MetaWindow *window,
- MetaFrameGeometry *fgeom,
- const MetaRectangle *orig,
- int *x_delta,
- int *y_delta);
+#define TITLEBAR_LENGTH_ONSCREEN 36
-/* This enum marks what x_delta and y_delta mean, i.e. it
- * identifies the current free variables.
- */
-enum
-{
- RESIZE_TOP,
- RESIZE_BOTTOM,
- RESIZE_LEFT,
- RESIZE_RIGHT,
- RESIZE_VERTICAL_CENTER,
- RESIZE_HORIZONTAL_CENTER,
- MOVE_VERTICAL,
- MOVE_HORIZONTAL,
- LAST_MOVE_CONTEXT
-} MoveContext;
+typedef gboolean (* MetaConstraintAppliesFunc) (MetaWindow *window);
+/* There's a function for each case with a different "free variable" */
+typedef void (* MetaConstrainTopFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta);
+typedef void (* MetaConstrainBottomFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta);
+typedef void (* MetaConstrainVCenterFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta);
+typedef void (* MetaConstrainLeftFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta);
+typedef void (* MetaConstrainRightFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta);
+typedef void (* MetaConstrainHCenterFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta);
+typedef void (* MetaConstrainMoveFunc) (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta,
+ int *y_delta);
-/* Maximization constraint:
- *
- * new_x = workarea_x + frame_left
- * new_y = workarea_y + frame_top
- * new_w = workarea_w - frame_left - frame_right
- * new_h = workarea_h - frame_top - frame_bottom
- *
- * No need to do anything hard because it just locks specific
- * size/pos.
- *
- * The min/max size constraints override maximization.
- */
+typedef struct
+{
+ MetaConstraintAppliesFunc applies_func;
+ MetaConstrainTopFunc top_func;
+ MetaConstrainBottomFunc bottom_func;
+ MetaConstrainVCenterFunc vcenter_func;
+ MetaConstrainLeftFunc left_func;
+ MetaConstrainRightFunc right_func;
+ MetaConstrainHCenterFunc hcenter_func;
+ MetaConstrainMoveFunc move_func;
+} Constraint;
-/* Full screen constraint:
+/* "Is the desktop window" constraint:
*
- * new_x = 0;
- * new_y = 0;
- * new_w = xinerama_width;
- * new_h = xinerama_height;
+ * new_x = 0;
+ * new_y = 0;
+ * new_w = orig_width;
+ * new_h = orig_height;
*
- * The min/max size constraints override fullscreen.
+ * Note that if we are applying a resize constraint,
+ * e.g. constraint_desktop_top_func, this is kind of broken since we
+ * end up resizing the window in order to get its position right. But
+ * that case shouldn't happen in practice.
*/
+static gboolean
+constraint_desktop_applies_func (MetaWindow *window)
+{
+ return window->type == META_WINDOW_DESKTOP;
+}
+
+static void
+constraint_desktop_top_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+ *y_delta = 0 - orig->y;
+}
+
+static void
+constraint_desktop_bottom_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+ /* nothing */
+}
+
+static void
+constraint_desktop_vcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+ *y_delta = 0 - orig->y;
+}
+
+static void
+constraint_desktop_left_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ *x_delta = 0 - orig->x;
+}
+
+static void
+constraint_desktop_right_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ /* nothing */
+}
+
+static void
+constraint_desktop_hcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ *x_delta = 0 - orig->x;
+}
+
+static void
+constraint_desktop_move_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta,
+ int *y_delta)
+{
+ *x_delta = 0 - orig->x;
+ *y_delta = 0 - orig->y;
+}
+
+static const Constraint constraint_desktop = {
+ constraint_desktop_applies_func,
+ constraint_desktop_top_func,
+ constraint_desktop_bottom_func,
+ constraint_desktop_vcenter_func,
+ constraint_desktop_left_func,
+ constraint_desktop_right_func,
+ constraint_desktop_hcenter_func,
+ constraint_desktop_move_func
+};
/* Titlebar is onscreen constraint:
*
@@ -162,45 +270,54 @@ enum
*
* NW limit has priority over SE, since titlebar is on NW
*
- * RESIZE_LEFT:
- * new_width = orig_width + dx
- * new_x = orig_x - dx
+ * Left resize
+ * ===
*
- * new_x >= nw_x - (left_width + new_width + right_width - titlebar_width_onscreen)
+ * new_width = orig_width - dx
+ * new_x = orig_x + dx
*
- * orig_x - dx >= nw_x - (left_width + orig_width + dx + right_width - titlebar_width_onscreen)
- * 0 >= nw_x - left_width - orig_width - right_width + titlebar_width_onscreen - orig_x
+ * Amount of window+frame that doesn't fit in the work area:
*
- * i.e. dx drops out so there is no constraint at all when moving left edge.
+ * offscreen_width = left_width + new_width + right_width - (se_x - nw_x)
*
- * RESIZE_RIGHT and RESIZE_BOTTOM are the same, cannot break this constraint
- * by moving in those directions.
+ * If we keep the old metacity rule where a window can be offscreen by
+ * offscreen_width, then the math works out that left/top resizes are not
+ * constrained. If we instead have a rule where the window can never be offscreen,
+ * you get the following:
*
- * RESIZE_TOP:
+ * new_x >= nw_x + left_width + titlebar_width_offscreen
+ * orig_x + dx >= nw_x + left_width + titlebar_width_onscreen
+ * dx >= nw_x + left_width + titlebar_width_onscreen - orig_x
*
- * new_height = orig_height - dy
- * new_y = orig_y + dy
+ * i.e. the minimum dx is: nw_x + left_width + titlebar_width_onscreen - orig_x
*
- * Can't move titlebar off the top at all regardless of height:
- * new_y >= nw_y + top_height
+ * We could have a more complicated rule that constrains only if the current
+ * offscreen width is positive, thus allowing something more like the old
+ * behavior, but not doing that for now.
*
- * orig_y + dy = nw_y + top_height
- * dy = nw_y + top_height - orig_y
+ * Top resize works the same as left resize. Right/bottom resize don't have a limit
+ * because the constraint is designed to keep the top right corner of the
+ * window or its titlebar on the screen, and right/bottom resize will never move that
+ * area. Center resize is almost like left/top but dx has the opposite sign
+ * and new_width = orig_width + 2dx.
*
- * Max dy is thus (nw_y + top_height - orig_y)
+ * For right/bottom we can try to handle windows that aren't in a valid
+ * location to begin with:
*
- * RESIZE_VERTICAL_CENTER:
+ * new_x <= se_x - titlebar_width_onscreen
+ * dx <= se_x - titlebar_width_onscreen - orig_x
*
- * RESIZE_HORIZONTAL_CENTER is like vertical
- *
+ * but in principle this constraint is never triggered.
*
- * MOVE_VERTICAL:
+ * Vertical move
+ * ===
+ *
* new_height = orig_height
* new_y = orig_y + dy
*
* new_y >= nw_y + top_height
*
- * Min negative dy (nw_y + top_height - orig_y) just as with RESIZE_TOP
+ * Min negative dy (nw_y + top_height - orig_y) just as with top resize.
* Max positive dy has to be computed from se_y and given less priority than the
* min negative:
*
@@ -208,45 +325,789 @@ enum
* orig_y + dy = se_y
* so max dy is (se_y - orig_y)
*
- *
- * MOVE_HORIZONTAL:
- * works out same as vertical in the other direction
- *
+ * Horizontal move is equivalent to vertical.
*
*/
+static gboolean
+constraint_onscreen_applies_func (MetaWindow *window)
+{
+ return
+ window->type != META_WINDOW_DESKTOP &&
+ window->type != META_WINDOW_DOCK;
+}
+
+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;
+
+ if (*y_delta < min_dy)
+ *y_delta = min_dy;
+}
+
+static void
+constraint_onscreen_bottom_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+ int max_dy;
+
+ max_dy = info->se_y - info->fgeom.top_height - orig->y;
+
+ if (*y_delta > max_dy)
+ *y_delta = max_dy;
+}
+
+static void
+constraint_onscreen_vcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+ int max_dy;
+
+ max_dy = info->nw_y + info->fgeom.top_height - orig->y;
+ max_dy = ABS (max_dy);
+
+ if (*y_delta > max_dy)
+ *y_delta = max_dy;
+}
+
+static void
+constraint_onscreen_left_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ int min_dx;
+
+ min_dx = info->nw_x + info->fgeom.left_width + TITLEBAR_WIDTH_ONSCREEN - orig->x;
+
+ if (*x_delta < min_dx)
+ *x_delta = min_dx;
+}
+
+static void
+constraint_onscreen_right_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ int max_dx;
+
+ max_dx = info->se_x - TITLEBAR_WIDTH_ONSCREEN - orig->x;
+
+ if (*x_delta > max_dx)
+ *x_delta = max_dx;
+}
+
+static void
+constraint_onscreen_hcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ int max_dx;
+
+ max_dx = info->nw_x + info->fgeom.left_width + TITLEBAR_WIDTH_ONSCREEN - orig->x;
+ max_dx = ABS (max_dx);
+
+ if (*x_delta > max_dx)
+ *x_delta = max_dx;
+}
+
+static void
+constraint_onscreen_move_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta,
+ int *y_delta)
+{
+ int min_delta;
+ int max_delta;
+
+ min_delta = info->nw_y + info->fgeom.top_height - orig->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;
+
+
+ /* Note that min delta (top left) has priority over
+ * max delta (bottom right) to facilitate keeping
+ * titlebar on the screen
+ */
+ if (*y_delta > max_delta)
+ *y_delta = max_delta;
+ 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;
+
+ if (*x_delta > max_delta)
+ *x_delta = max_delta;
+ if (*x_delta < min_delta)
+ *x_delta = min_delta;
+}
+
+static const Constraint constraint_onscreen = {
+ constraint_onscreen_applies_func,
+ constraint_onscreen_top_func,
+ constraint_onscreen_bottom_func,
+ constraint_onscreen_vcenter_func,
+ constraint_onscreen_left_func,
+ constraint_onscreen_right_func,
+ constraint_onscreen_hcenter_func,
+ constraint_onscreen_move_func
+};
+
+
+/* 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.
+ *
+ * For aspect ratio, we special-case it at the end of
+ * meta_window_constrain, because it involves both dimensions, and
+ * thus messes up our generic framework.
+ *
+ * Left resize:
+ * new_width = orig_width - dx
+ * new_x = orig_x + dx
+ *
+ * new_width >= min_width
+ * orig_width - dx >= min_width
+ * - dx >= min_width - orig_width
+ * dx <= orig_width - min_width
+ *
+ * new_width <= max_width
+ * orig_width - dx <= max_width
+ * - dx <= max_width - orig_width
+ * dx >= orig_width - max_width
+ *
+ */
+
+static gboolean
+constraint_hints_applies_func (MetaWindow *window)
+{
+ return TRUE;
+}
+
+static void
+constraint_hints_top_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+
+}
+
+static void
+constraint_hints_bottom_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+
+}
+
+static void
+constraint_hints_vcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *y_delta)
+{
+}
+
+static void
+constraint_hints_left_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+ 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;
+
+ 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 = orig->width - width;
+}
+
+static void
+constraint_hints_right_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+
+}
+
+static void
+constraint_hints_hcenter_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta)
+{
+}
+
+static void
+constraint_hints_move_func (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int *x_delta,
+ int *y_delta)
+{
+ /* nothing */
+}
+
+static const Constraint constraint_hints = {
+ constraint_hints_applies_func,
+ constraint_hints_top_func,
+ constraint_hints_bottom_func,
+ constraint_hints_vcenter_func,
+ constraint_hints_left_func,
+ constraint_hints_right_func,
+ constraint_hints_hcenter_func,
+ constraint_hints_move_func
+};
+
+/* Array of all constraints at once */
+static const Constraint *all_constraints[] = {
+ &constraint_desktop,
+ &constraint_onscreen,
+ &constraint_hints,
+ NULL
+};
+
+/* Move with no accompanying change to window size */
+static void
+constrain_move (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int x_delta,
+ int y_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->move_func) (window, info, orig,
+ &x_delta, &y_delta);
+
+ ++cp;
+ }
+
+ new->x = orig->x + x_delta;
+ new->y = orig->y + y_delta;
+}
+
+static void
+constrain_resize_left (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int x_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->left_func) (window, info, orig,
+ &x_delta);
+
+ ++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->width = orig->width - x_delta;
+}
+
+static void
+constrain_resize_hcenter (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int x_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->hcenter_func) (window, info, orig,
+ &x_delta);
+
+ ++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;
+}
+
+static void
+constrain_resize_right (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int x_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->right_func) (window, info, orig,
+ &x_delta);
+
+ ++cp;
+ }
+
+ new->width = orig->width + x_delta;
+}
+
+static void
+constrain_resize_top (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int y_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->top_func) (window, info, orig,
+ &y_delta);
+
+ ++cp;
+ }
+
+ new->y = orig->y - y_delta;
+ new->height = orig->height - y_delta;
+}
+
+static void
+constrain_resize_vcenter (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int y_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->vcenter_func) (window, info, orig,
+ &y_delta);
+
+ ++cp;
+ }
+
+ /* center deltas are positive to grow the window and negative to
+ * shrink it.
+ */
+ new->y = orig->y - y_delta;
+ new->height = orig->height + y_delta * 2;
+}
+
+static void
+constrain_resize_bottom (MetaWindow *window,
+ const ConstraintInfo *info,
+ const MetaRectangle *orig,
+ int y_delta,
+ MetaRectangle *new)
+{
+ const Constraint **cp;
+
+ cp = &all_constraints[0];
+
+ while (*cp)
+ {
+ if ((* (*cp)->applies_func) (window))
+ (* (*cp)->bottom_func) (window, info, orig,
+ &y_delta);
+
+ ++cp;
+ }
+
+ new->height = orig->y + y_delta;
+}
+
+static void
+update_position_limits (MetaWindow *window,
+ ConstraintInfo *info)
+{
+ 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
+ */
+ 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;
+ }
+
+ info->nw_x = nw_x;
+ info->nw_y = nw_y;
+ info->se_x = se_x;
+ info->se_y = se_y;
+}
+
+/* The delta values are the mouse motion distance deltas,
+ * i.e. mouse_current_pos - mouse_orig_pos, for resizing on
+ * the sides, or moving. For center resize, the delta
+ * value is positive to grow the window and negative to
+ * shrink it (while the sign of the mouse delta
+ * depends on which side of the window you are center resizing
+ * from)
+ */
void
meta_window_constrain (MetaWindow *window,
MetaFrameGeometry *orig_fgeom,
- int resize_gravity,
const MetaRectangle *orig,
+ int x_move_delta,
+ int y_move_delta,
+ MetaResizeDirection x_direction,
+ int x_delta,
+ MetaResizeDirection y_direction,
+ int y_delta,
MetaRectangle *new)
{
- MetaFrameGeometry fgeom;
-
+ ConstraintInfo info;
+ MetaRectangle current;
+
/* Create a fake frame geometry if none really exists */
- if (orig_fgeom)
- fgeom = *orig_fgeom;
+ if (orig_fgeom && !window->fullscreen)
+ info.fgeom = *orig_fgeom;
else
{
- fgeom.top_height = 0;
- fgeom.bottom_height = 0;
- fgeom.left_width = 0;
- fgeom.right_width = 0;
+ info.fgeom.top_height = 0;
+ info.fgeom.bottom_height = 0;
+ info.fgeom.left_width = 0;
+ 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);
+ info.window = window;
+ info.xinerama = meta_screen_get_xinerama_for_window (window->screen,
+ window);
+
+ /* Init info->nw_x etc. */
+ update_position_limits (window, &info);
+
+ 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
+ * and unfullscreened
+ */
+ if (!window->placed &&
+ window->calc_placement &&
+ !window->maximized &&
+ !window->fullscreen)
+ {
+ int x, y;
+
+ meta_window_place (window, orig_fgeom, x, y, &x, &y);
-}
+ constrain_move (window, &info, &current,
+ x - current.x,
+ y - current.y,
+ new);
+ }
+
+ /* Maximization, fullscreen, etc. are defined as a move followed by
+ * a resize, as explained in one of the big comments at the top of
+ * this file.
+ */
+ if (window->fullscreen)
+ {
+ constrain_move (window, &info, &current,
+ info.xinerama->x_origin - current.x,
+ info.xinerama->y_origin - current.y,
+ new);
+
+ current = *new;
+
+ constrain_resize_bottom (window, &info, &current,
+ info.xinerama->height - current.height,
+ new);
+
+ current = *new;
+
+ constrain_resize_hcenter (window, &info, &current,
+ (info.xinerama->width - current.width) / 2,
+ new);
+ }
+ else if (window->maximized)
+ {
+ constrain_move (window, &info, &current,
+ info.work_area_xinerama.x - current.x,
+ info.work_area_xinerama.y - current.y,
+ new);
+
+ current = *new;
+
+ constrain_resize_bottom (window, &info, &current,
+ info.work_area_xinerama.height - current.height,
+ new);
+
+ current = *new;
+
+ constrain_resize_hcenter (window, &info, &current,
+ (info.work_area_xinerama.width - current.width) / 2,
+ 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:
+ 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;
+ }
+ 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;
+ }
+ }
+
+ current = *new;
+
+ /* 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,
+ y_delta, new);
+ break;
+ case META_RESIZE_RIGHT_OR_BOTTOM:
+ constrain_resize_bottom (window, &info, &current,
+ y_delta, new);
+ break;
+ }
+ }
+ }
+#undef FLOOR
+
+}
+MetaResizeDirection
+meta_x_direction_from_gravity (int gravity)
+{
+ switch (gravity)
+ {
+ case EastGravity:
+ case NorthEastGravity:
+ case SouthEastGravity:
+ return META_RESIZE_LEFT_OR_TOP;
+ break;
+ case WestGravity:
+ case NorthWestGravity:
+ case SouthWestGravity:
+ case StaticGravity:
+ return META_RESIZE_RIGHT_OR_BOTTOM;
+ break;
+ default:
+ return META_RESIZE_CENTER;
+ break;
+ }
+}
+MetaResizeDirection
+meta_y_direction_from_gravity (int gravity)
+{
+ switch (gravity)
+ {
+ case SouthGravity:
+ case SouthWestGravity:
+ case SouthEastGravity:
+ return META_RESIZE_LEFT_OR_TOP;
+ break;
+ case NorthGravity:
+ case NorthWestGravity:
+ case NorthEastGravity:
+ case StaticGravity:
+ return META_RESIZE_RIGHT_OR_BOTTOM;
+ break;
+
+ default:
+ return META_RESIZE_CENTER;
+ }
+}
diff --git a/src/constraints.h b/src/constraints.h
index e901cf2..de8555b 100644
--- a/src/constraints.h
+++ b/src/constraints.h
@@ -24,13 +24,28 @@
#include "util.h"
#include "window.h"
+#include "frame.h"
+
+typedef enum
+{
+ META_RESIZE_LEFT_OR_TOP,
+ META_RESIZE_CENTER,
+ META_RESIZE_RIGHT_OR_BOTTOM
+} MetaResizeDirection;
void meta_window_constrain (MetaWindow *window,
MetaFrameGeometry *fgeom,
- int resize_gravity,
const MetaRectangle *orig,
+ int x_move_delta,
+ int y_move_delta,
+ MetaResizeDirection x_direction,
+ int x_delta,
+ MetaResizeDirection y_direction,
+ int y_delta,
MetaRectangle *new);
+MetaResizeDirection meta_x_direction_from_gravity (int gravity);
+MetaResizeDirection meta_y_direction_from_gravity (int gravity);
#endif /* META_CONSTRAINTS_H */
diff --git a/src/display.c b/src/display.c
index 3c6b7a4..78ade79 100644
--- a/src/display.c
+++ b/src/display.c
@@ -633,6 +633,8 @@ meta_display_close (MetaDisplay *display)
if (display->leader_window != None)
XDestroyWindow (display->xdisplay, display->leader_window);
+ XFlush (display->xdisplay);
+
#ifndef USE_GDK_DISPLAY
meta_event_queue_free (display->events);
XCloseDisplay (display->xdisplay);
diff --git a/src/effects.c b/src/effects.c
index e486edb..4b73e4d 100644
--- a/src/effects.c
+++ b/src/effects.c
@@ -19,10 +19,23 @@
* 02111-1307, USA.
*/
+#include <config.h>
#include "effects.h"
#include "display.h"
#include "ui.h"
+#ifdef HAVE_SHAPE
+#include <X11/extensions/shape.h>
+#endif
+
+typedef enum
+{
+ META_ANIMATION_DRAW_ROOT,
+ META_ANIMATION_WINDOW_WIREFRAME,
+ META_ANIMATION_WINDOW_OPAQUE
+
+} MetaAnimationStyle;
+
typedef struct
{
MetaScreen *screen;
@@ -41,11 +54,14 @@ typedef struct
/* used instead of the global flag, since
* we don't want to change midstream.
*/
- gboolean use_opaque;
+ MetaAnimationStyle style;
- /* For wireframe */
+ /* For wireframe drawn on root window */
GC gc;
+ /* For wireframe window */
+ Window wireframe_xwindow;
+
/* For opaque */
MetaImageWindow *image_window;
GdkPixbuf *orig_pixbuf;
@@ -54,6 +70,61 @@ typedef struct
} BoxAnimationContext;
+static void
+update_wireframe_window (MetaDisplay *display,
+ Window xwindow,
+ const MetaRectangle *rect)
+{
+ XMoveResizeWindow (display->xdisplay,
+ xwindow,
+ rect->x, rect->y,
+ rect->width, rect->height);
+
+#ifdef HAVE_SHAPE
+
+#define OUTLINE_WIDTH 3
+
+ if (rect->width > OUTLINE_WIDTH * 2 &&
+ rect->height > OUTLINE_WIDTH * 2)
+ {
+ XRectangle xrect;
+ Region inner_xregion;
+ Region outer_xregion;
+
+ inner_xregion = XCreateRegion ();
+ outer_xregion = XCreateRegion ();
+
+ xrect.x = 0;
+ xrect.y = 0;
+ xrect.width = rect->width;
+ xrect.height = rect->height;
+
+ XUnionRectWithRegion (&xrect, outer_xregion, outer_xregion);
+
+ xrect.x += OUTLINE_WIDTH;
+ xrect.y += OUTLINE_WIDTH;
+ xrect.width -= OUTLINE_WIDTH * 2;
+ xrect.height -= OUTLINE_WIDTH * 2;
+
+ XUnionRectWithRegion (&xrect, inner_xregion, inner_xregion);
+
+ XSubtractRegion (outer_xregion, inner_xregion, outer_xregion);
+
+ XShapeCombineRegion (display->xdisplay, xwindow,
+ ShapeBounding, 0, 0, outer_xregion, ShapeSet);
+
+ XDestroyRegion (outer_xregion);
+ XDestroyRegion (inner_xregion);
+ }
+ else
+ {
+ /* Unset the shape */
+ XShapeCombineMask (display->xdisplay, xwindow,
+ ShapeBounding, 0, 0, None, ShapeSet);
+ }
+#endif
+}
+
static gboolean
effects_draw_box_animation_timeout (BoxAnimationContext *context)
{
@@ -64,7 +135,7 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (!context->first_time)
{
- if (!context->use_opaque)
+ if (context->style == META_ANIMATION_DRAW_ROOT)
{
/* Restore the previously drawn background */
XDrawRectangle (context->screen->display->xdisplay,
@@ -94,18 +165,23 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (elapsed > context->millisecs_duration)
{
/* All done */
- if (context->use_opaque)
+ if (context->style == META_ANIMATION_WINDOW_OPAQUE)
{
g_object_unref (G_OBJECT (context->orig_pixbuf));
meta_image_window_free (context->image_window);
}
- else
+ else if (context->style == META_ANIMATION_DRAW_ROOT)
{
meta_display_ungrab (context->screen->display);
meta_ui_pop_delay_exposes (context->screen->ui);
XFreeGC (context->screen->display->xdisplay,
context->gc);
}
+ else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
+ {
+ XDestroyWindow (context->screen->display->xdisplay,
+ context->wireframe_xwindow);
+ }
g_free (context);
return FALSE;
@@ -130,7 +206,7 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
context->last_rect = draw_rect;
- if (context->use_opaque)
+ if (context->style == META_ANIMATION_WINDOW_OPAQUE)
{
GdkPixbuf *scaled;
@@ -174,7 +250,7 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
g_object_unref (G_OBJECT (scaled));
}
}
- else
+ else if (context->style == META_ANIMATION_DRAW_ROOT)
{
/* Draw the rectangle */
XDrawRectangle (context->screen->display->xdisplay,
@@ -183,6 +259,12 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
draw_rect.x, draw_rect.y,
draw_rect.width, draw_rect.height);
}
+ else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
+ {
+ update_wireframe_window (context->screen->display,
+ context->wireframe_xwindow,
+ &draw_rect);
+ }
/* kick changes onto the server */
XFlush (context->screen->display->xdisplay);
@@ -198,7 +280,7 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
* and unmapping of windows that's going on.
*/
-static gboolean use_opaque_animations = FALSE;
+static MetaAnimationStyle animation_style = META_ANIMATION_WINDOW_WIREFRAME;
void
meta_effects_draw_box_animation (MetaScreen *screen,
@@ -225,9 +307,14 @@ meta_effects_draw_box_animation (MetaScreen *screen,
context->end_rect = *destination_rect;
context->anim_type = anim_type;
- context->use_opaque = use_opaque_animations;
+ context->style = animation_style;
- if (context->use_opaque)
+#ifndef HAVE_SHAPE
+ if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
+ context->style = META_ANIMATION_DRAW_ROOT;
+#endif
+
+ if (context->style == META_ANIMATION_WINDOW_OPAQUE)
{
GdkPixbuf *pix;
@@ -242,7 +329,7 @@ meta_effects_draw_box_animation (MetaScreen *screen,
if (pix == NULL)
{
/* Fall back to wireframe */
- context->use_opaque = FALSE;
+ context->style = META_ANIMATION_WINDOW_WIREFRAME;
}
else
{
@@ -258,7 +345,36 @@ meta_effects_draw_box_animation (MetaScreen *screen,
}
/* Not an else, so that fallback works */
- if (!context->use_opaque)
+ if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
+ {
+ XSetWindowAttributes attrs;
+
+ attrs.override_redirect = True;
+ attrs.background_pixel = BlackPixel (screen->display->xdisplay,
+ screen->number);
+
+ context->wireframe_xwindow = XCreateWindow (screen->display->xdisplay,
+ screen->xroot,
+ initial_rect->x,
+ initial_rect->y,
+ initial_rect->width,
+ initial_rect->height,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWBackPixel,
+ &attrs);
+
+ update_wireframe_window (screen->display,
+ context->wireframe_xwindow,
+ initial_rect);
+
+ XMapWindow (screen->display->xdisplay,
+ context->wireframe_xwindow);
+ }
+
+ if (context->style == META_ANIMATION_DRAW_ROOT)
{
XGCValues gc_values;
diff --git a/src/keybindings.c b/src/keybindings.c
index 5d36585..bb8b44c 100644
--- a/src/keybindings.c
+++ b/src/keybindings.c
@@ -729,6 +729,8 @@ meta_display_init_keys (MetaDisplay *display)
void
meta_display_shutdown_keys (MetaDisplay *display)
{
+ /* Note that display->xdisplay is invalid in this function */
+
meta_prefs_remove_listener (bindings_changed_callback, display);
if (display->keymap)
@@ -1995,12 +1997,8 @@ switch_to_workspace (MetaDisplay *display,
if (move_window)
{
- /* Lamely rely on prepend */
- g_assert (move_window->workspaces->data == workspace);
-
- while (move_window->workspaces->next) /* while list size > 1 */
- meta_workspace_remove_window (move_window->workspaces->next->data,
- move_window);
+ /* Removes window from other spaces */
+ meta_window_change_workspace (move_window, workspace);
}
}
diff --git a/src/screen.c b/src/screen.c
index c2b7497..999d3db 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -535,6 +535,7 @@ meta_screen_free (MetaScreen *screen)
g_free (screen->screen_name);
g_free (screen);
+ XFlush (display->xdisplay);
meta_display_ungrab (display);
}
diff --git a/src/window.c b/src/window.c
index e02d6be..c446591 100644
--- a/src/window.c
+++ b/src/window.c
@@ -627,6 +627,24 @@ meta_window_new (MetaDisplay *display, Window xwindow,
outer.height >= workarea.height)
meta_window_maximize (window);
}
+ /* Assume screen-size undecorated windows are intended to be
+ * fullscreen
+ */
+ else if (window->has_fullscreen_func && !window->decorated &&
+ !window->maximized)
+ {
+ const MetaXineramaScreenInfo *xinerama;
+ MetaRectangle outer;
+
+ xinerama = meta_screen_get_xinerama_for_window (window->screen,
+ window);
+
+ meta_window_get_outer_rect (window, &outer);
+
+ if (outer.width >= xinerama->width &&
+ outer.height >= xinerama->height)
+ meta_window_make_fullscreen (window);
+ }
/* Sync stack changes */
meta_stack_thaw (window->screen->stack);
@@ -1661,6 +1679,7 @@ meta_window_shade (MetaWindow *window)
"Shading %s\n", window->desc);
if (!window->shaded)
{
+#if 0
if (window->mapped)
{
/* Animation */
@@ -1682,7 +1701,8 @@ meta_window_shade (MetaWindow *window)
META_SHADE_ANIMATION_LENGTH,
META_BOX_ANIM_SLIDE_UP);
}
-
+#endif
+
window->shaded = TRUE;
meta_window_queue_move_resize (window);
@@ -2785,25 +2805,35 @@ meta_window_focus (MetaWindow *window,
void
meta_window_change_workspace (MetaWindow *window,
MetaWorkspace *workspace)
-{
+{
+ GList *next;
+
meta_verbose ("Changing window %s to workspace %d\n",
window->desc, meta_workspace_index (workspace));
/* See if we're already on this space. If not, make sure we are */
if (g_list_find (window->workspaces, workspace) == NULL)
- {
- meta_workspace_add_window (workspace, window);
- }
+ meta_workspace_add_window (workspace, window);
+
/* unstick if stuck */
if (window->on_all_workspaces)
meta_window_unstick (window);
- /* Lamely rely on prepend */
- g_assert (window->workspaces->data == workspace);
-
/* Remove from all other spaces */
- while (window->workspaces->next) /* while list size > 1 */
- meta_workspace_remove_window (window->workspaces->next->data, window);
+ next = window->workspaces;
+ while (next != NULL)
+ {
+ MetaWorkspace *remove;
+ remove = next->data;
+ next = next->next;
+
+ if (remove != workspace)
+ meta_workspace_remove_window (remove, window);
+ }
+
+ /* list size == 1 */
+ g_assert (window->workspaces != NULL);
+ g_assert (window->workspaces->next == NULL);
}
void