summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-01-19 23:59:11 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-01-19 23:59:11 +0000
commit5fdb8463def40bdfa208ecfdd4655209c35e0b2b (patch)
treed3511fd6c884150d0576b37f83f4ebdacfcdd630 /src
parent19d2e8c7e1df6fcf12e5e5dcfe36430627eb8cc2 (diff)
downloadmetacity-5fdb8463def40bdfa208ecfdd4655209c35e0b2b.tar.gz
metacity-5fdb8463def40bdfa208ecfdd4655209c35e0b2b.tar.bz2
cheesy client with static bit gravity, used to test the below change.
2002-01-19 Havoc Pennington <hp@pobox.com> * src/wm-tester/test-resizing.c: cheesy client with static bit gravity, used to test the below change. * src/window.c (meta_window_move_resize_internal): implement Owen's proposal for window resizing. http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html Currently you have to do METACITY_USE_STATIC_GRAVITY=1 in order to use it, because some GDK bug is screwing up exposes on my frames when it's enabled. * src/display.c (meta_display_create_x_cursor): fix glyph for NE/NW cursors * src/frames.c (get_control): add ability to resize from top * src/frame.c (meta_frame_get_flags): can't resize shaded windows (meta_frame_sync_to_window): add gravity arg * src/common.h (MetaWindowType): move here from window.h so it can be used in themes stuff. (MetaFrameFlags): remove META_FRAME_TRANSIENT since it overlaps with window type and was unused.
Diffstat (limited to 'src')
-rw-r--r--src/common.h26
-rw-r--r--src/display.c7
-rw-r--r--src/display.h1
-rw-r--r--src/frame.c9
-rw-r--r--src/frame.h1
-rw-r--r--src/frames.c29
-rw-r--r--src/theme.c105
-rw-r--r--src/theme.h64
-rw-r--r--src/window.c167
-rw-r--r--src/window.h11
-rw-r--r--src/wm-tester/Makefile.am6
-rw-r--r--src/wm-tester/test-resizing.c255
12 files changed, 619 insertions, 62 deletions
diff --git a/src/common.h b/src/common.h
index 9ee8042..b3a3480 100644
--- a/src/common.h
+++ b/src/common.h
@@ -34,13 +34,12 @@ typedef enum
META_FRAME_ALLOWS_MAXIMIZE = 1 << 3,
META_FRAME_ALLOWS_VERTICAL_RESIZE = 1 << 4,
META_FRAME_ALLOWS_HORIZONTAL_RESIZE = 1 << 5,
- META_FRAME_TRANSIENT = 1 << 6,
- META_FRAME_HAS_FOCUS = 1 << 7,
- META_FRAME_SHADED = 1 << 8,
- META_FRAME_STUCK = 1 << 9,
- META_FRAME_MAXIMIZED = 1 << 10,
- META_FRAME_ALLOWS_SHADE = 1 << 11,
- META_FRAME_ALLOWS_MOVE = 1 << 12
+ META_FRAME_HAS_FOCUS = 1 << 6,
+ META_FRAME_SHADED = 1 << 7,
+ META_FRAME_STUCK = 1 << 8,
+ META_FRAME_MAXIMIZED = 1 << 9,
+ META_FRAME_ALLOWS_SHADE = 1 << 10,
+ META_FRAME_ALLOWS_MOVE = 1 << 11
} MetaFrameFlags;
typedef enum
@@ -130,6 +129,19 @@ typedef enum
META_FOCUS_MODE_MOUSE
} MetaFocusMode;
+typedef enum
+{
+ META_WINDOW_NORMAL,
+ META_WINDOW_DESKTOP,
+ META_WINDOW_DOCK,
+ META_WINDOW_DIALOG,
+ META_WINDOW_MODAL_DIALOG,
+ META_WINDOW_TOOLBAR,
+ META_WINDOW_MENU,
+ META_WINDOW_TYPE_LAST
+} MetaWindowType;
+
+
/* should investigate changing these to whatever most apps use */
#define META_ICON_WIDTH 32
#define META_ICON_HEIGHT 32
diff --git a/src/display.c b/src/display.c
index d51cc33..c84c451 100644
--- a/src/display.c
+++ b/src/display.c
@@ -179,6 +179,9 @@ meta_display_open (const char *name)
display->prev_focus_window = NULL;
display->showing_desktop = FALSE;
+
+ /* FIXME copy the checks from GDK probably */
+ display->static_gravity_works = g_getenv ("METACITY_USE_STATIC_GRAVITY") != NULL;
/* we have to go ahead and do this so error handlers work */
all_displays = g_slist_prepend (all_displays, display);
@@ -1638,10 +1641,10 @@ meta_display_create_x_cursor (MetaDisplay *display,
glyph = XC_bottom_left_corner;
break;
case META_CURSOR_NE_RESIZE:
- glyph = XC_top_left_corner;
+ glyph = XC_top_right_corner;
break;
case META_CURSOR_NW_RESIZE:
- glyph = XC_top_right_corner;
+ glyph = XC_top_left_corner;
break;
default:
diff --git a/src/display.h b/src/display.h
index ca7351b..bf5186c 100644
--- a/src/display.h
+++ b/src/display.h
@@ -118,6 +118,7 @@ struct _MetaDisplay
GList *workspaces;
guint showing_desktop : 1;
+ guint static_gravity_works : 1;
/*< private-ish >*/
MetaEventQueue *events;
diff --git a/src/frame.c b/src/frame.c
index 64b376a..088edda 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -210,7 +210,8 @@ meta_frame_get_flags (MetaFrame *frame)
flags |= META_FRAME_ALLOWS_MOVE;
if (frame->window->has_resize_func &&
- !frame->window->maximized)
+ !frame->window->maximized &&
+ !frame->window->shaded)
{
if (frame->window->size_hints.min_width <
frame->window->size_hints.max_width)
@@ -256,7 +257,8 @@ meta_frame_calc_geometry (MetaFrame *frame,
}
static void
-set_background_none (MetaFrame *frame)
+set_background_none (MetaFrame *frame,
+ int resize_gravity)
{
XSetWindowAttributes attrs;
@@ -269,6 +271,7 @@ set_background_none (MetaFrame *frame)
void
meta_frame_sync_to_window (MetaFrame *frame,
+ int resize_gravity,
gboolean need_move,
gboolean need_resize)
{
@@ -283,7 +286,7 @@ meta_frame_sync_to_window (MetaFrame *frame,
/* set bg to none to avoid flicker */
if (need_resize)
- set_background_none (frame);
+ set_background_none (frame, resize_gravity);
if (need_move && need_resize)
XMoveResizeWindow (frame->window->display->xdisplay,
diff --git a/src/frame.h b/src/frame.h
index f5585ba..6447763 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -67,6 +67,7 @@ MetaFrameFlags meta_frame_get_flags (MetaFrame *frame);
void meta_frame_calc_geometry (MetaFrame *frame,
MetaFrameGeometry *geomp);
void meta_frame_sync_to_window (MetaFrame *frame,
+ int gravity,
gboolean need_move,
gboolean need_resize);
diff --git a/src/frames.c b/src/frames.c
index ed18b2e..9dff136 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -2042,8 +2042,28 @@ get_control (MetaFrames *frames,
if (has_vert || has_horiz)
{
- if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
- x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS))
+ if (y < fgeom.top_height && x < RESIZE_EXTENDS)
+ {
+ if (has_vert && has_horiz)
+ return META_FRAME_CONTROL_RESIZE_NW;
+ else if (has_vert)
+ return META_FRAME_CONTROL_RESIZE_N;
+ else
+ return META_FRAME_CONTROL_RESIZE_W;
+
+ }
+ else if (y < fgeom.top_height && x >= (fgeom.width - RESIZE_EXTENDS))
+ {
+ if (has_vert && has_horiz)
+ return META_FRAME_CONTROL_RESIZE_NE;
+ else if (has_vert)
+ return META_FRAME_CONTROL_RESIZE_N;
+ else
+ return META_FRAME_CONTROL_RESIZE_E;
+
+ }
+ else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
+ x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS))
{
if (has_vert && has_horiz)
return META_FRAME_CONTROL_RESIZE_SE;
@@ -2062,6 +2082,11 @@ get_control (MetaFrames *frames,
else
return META_FRAME_CONTROL_RESIZE_W;
}
+ else if (y < fgeom.top_height)
+ {
+ if (has_vert)
+ return META_FRAME_CONTROL_RESIZE_N;
+ }
else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS))
{
if (has_vert)
diff --git a/src/theme.c b/src/theme.c
index 70a3538..7571f86 100644
--- a/src/theme.c
+++ b/src/theme.c
@@ -666,3 +666,108 @@ meta_texture_spec_draw (const MetaTextureSpec *spec,
break;
}
}
+
+MetaFrameStyle*
+meta_frame_style_new (void)
+{
+ MetaFrameStyle *style;
+
+ style = g_new0 (MetaFrameStyle, 1);
+
+ style->refcount = 1;
+
+ return style;
+}
+
+void
+meta_frame_style_ref (MetaFrameStyle *style)
+{
+ g_return_if_fail (style != NULL);
+
+ style->refcount += 1;
+}
+
+static void
+free_button_textures (MetaTextureSpec *textures[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
+{
+ int i, j;
+
+ i = 0;
+ while (i < META_BUTTON_TYPE_LAST)
+ {
+ j = 0;
+ while (j < META_BUTTON_STATE_LAST)
+ {
+ if (textures[i][j])
+ meta_texture_spec_free (textures[i][j]);
+
+ ++j;
+ }
+
+ ++i;
+ }
+}
+
+void
+meta_frame_style_unref (MetaFrameStyle *style)
+{
+ g_return_if_fail (style != NULL);
+ g_return_if_fail (style->refcount > 0);
+
+ style->refcount -= 1;
+
+ if (style->refcount == 0)
+ {
+ int i;
+
+ free_button_textures (style->button_icons);
+ free_button_textures (style->button_backgrounds);
+
+ i = 0;
+ while (i < META_FRAME_PIECE_LAST)
+ {
+ if (style->pieces[i])
+ meta_texture_spec_free (style->pieces[i]);
+
+ ++i;
+ }
+
+ if (style->layout)
+ meta_frame_layout_free (style->layout);
+
+ g_free (style);
+ }
+}
+
+MetaFrameStyleSet*
+meta_frame_style_set_new (void)
+{
+ MetaFrameStyleSet *style_set;
+
+ style_set = g_new0 (MetaFrameStyleSet, 1);
+
+ return style_set;
+}
+
+void
+meta_frame_style_set_free (MetaFrameStyleSet *style_set)
+{
+ int i, j;
+
+ i = 0;
+ while (i < META_WINDOW_TYPE_LAST)
+ {
+ j = 0;
+ while (j < META_WINDOW_STATE_LAST)
+ {
+ if (style_set->styles[i][j])
+ meta_frame_style_unref (style_set->styles[i][j]);
+
+ ++j;
+ }
+
+ ++i;
+ }
+
+ g_free (style_set);
+}
diff --git a/src/theme.h b/src/theme.h
index 1cb73f0..099b28a 100644
--- a/src/theme.h
+++ b/src/theme.h
@@ -133,6 +133,14 @@ typedef enum
META_TEXTURE_IMAGE
} MetaTextureType;
+typedef enum
+{
+ META_TEXTURE_DRAW_UNSCALED,
+ META_TEXTURE_DRAW_SCALED_VERTICALLY,
+ META_TEXTURE_DRAW_SCALED_HORIZONTALLY,
+ META_TEXTURE_DRAW_SCALED_BOTH
+} MetaTextureDrawMode;
+
struct _MetaTextureSpec
{
MetaTextureType type;
@@ -243,22 +251,60 @@ typedef enum
struct _MetaFrameStyle
{
+ int refcount;
MetaTextureSpec *button_icons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
MetaTextureSpec *button_backgrounds[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
MetaTextureSpec *pieces[META_FRAME_PIECE_LAST];
MetaFrameLayout *layout;
};
+
typedef enum
{
- META_TEXTURE_DRAW_UNSCALED,
- META_TEXTURE_DRAW_SCALED_VERTICALLY,
- META_TEXTURE_DRAW_SCALED_HORIZONTALLY,
- META_TEXTURE_DRAW_SCALED_BOTH
-} MetaTextureDrawMode;
+ /* FIXME dammit, these are not mutually exclusive; how to handle
+ * the mess...
+ *
+ * normal -> noresize / vert only / horz only / both
+ focused / unfocused
+ * max -> focused / unfocused
+ * shaded -> focused / unfocused
+ * max/shaded -> focused / unfocused
+ *
+ * so 4 states with 8 sub-states in one, 2 sub-states in the other 3,
+ * meaning 14 total
+ *
+ * 14 window states times 7 or 8 window types.
+ *
+ *
+ * MetaFrameStyleSet needs rearranging to think of it this way.
+ *
+ */
+ META_WINDOW_STATE_MAXIMIZED,
+ META_WINDOW_STATE_SHADED,
+ META_WINDOW_STATE_MAXIMIZED_AND_SHADED,
+ META_WINDOW_STATE_RESIZE_VERTICAL,
+ META_WINDOW_STATE_RESIZE_HORIZONTAL,
+ META_WINDOW_STATE_RESIZE_BOTH,
+ META_WINDOW_STATE_UNFOCUSED,
+ META_WINDOW_STATE_FOCUSED,
+ META_WINDOW_STATE_LAST
+} MetaWindowState;
+
+struct _MetaFrameStyleSet
+{
+ MetaFrameStyle *styles[META_WINDOW_TYPE_LAST][META_WINDOW_STATE_LAST];
+};
MetaFrameLayout* meta_frame_layout_new (void);
void meta_frame_layout_free (MetaFrameLayout *layout);
+void meta_frame_layout_get_borders (const MetaFrameLayout *layout,
+ GtkWidget *widget,
+ int text_height,
+ MetaFrameFlags flags,
+ int *top_height,
+ int *bottom_height,
+ int *left_width,
+ int *right_width);
void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
GtkWidget *widget,
int text_height,
@@ -267,6 +313,7 @@ void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int client_height,
MetaFrameGeometry *fgeom);
+
MetaColorSpec* meta_color_spec_new (MetaColorSpecType type);
void meta_color_spec_free (MetaColorSpec *spec);
void meta_color_spec_render (MetaColorSpec *spec,
@@ -296,4 +343,11 @@ void meta_texture_spec_draw (const MetaTextureSpec *desc,
int width,
int height);
+MetaFrameStyle* meta_frame_style_new (void);
+void meta_frame_style_ref (MetaFrameStyle *style);
+void meta_frame_style_unref (MetaFrameStyle *style);
+
+MetaFrameStyleSet* meta_frame_style_set_new (void);
+void meta_frame_style_set_free (MetaFrameStyleSet *style_set);
+
#endif
diff --git a/src/window.c b/src/window.c
index 252e533..e728d82 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1518,6 +1518,12 @@ adjust_for_gravity (MetaWindow *window,
}
}
+static gboolean
+static_gravity_works (MetaDisplay *display)
+{
+ return display->static_gravity_works;
+}
+
static void
meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
@@ -1537,14 +1543,19 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean need_resize_frame = FALSE;
int size_dx;
int size_dy;
- int pos_dx;
- int pos_dy;
int frame_size_dx;
int frame_size_dy;
gboolean is_configure_request;
gboolean do_gravity_adjust;
gboolean is_user_action;
-
+ gboolean configure_frame_first;
+ gboolean use_static_gravity;
+ /* used for the configure request, but may not be final
+ * destination due to StaticGravity etc.
+ */
+ int client_move_x;
+ int client_move_y;
+
/* We don't need it in the idle queue anymore. */
meta_window_unqueue_move_resize (window);
@@ -1590,12 +1601,10 @@ meta_window_move_resize_internal (MetaWindow *window,
else
new_h = window->rect.height + fgeom.top_height + fgeom.bottom_height;
- if (new_w != window->frame->rect.width ||
- new_h != window->frame->rect.height)
- need_resize_frame = TRUE;
-
frame_size_dx = new_w - window->frame->rect.width;
frame_size_dy = new_h - window->frame->rect.height;
+
+ need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
window->frame->rect.width = new_w;
window->frame->rect.height = new_h;
@@ -1675,6 +1684,21 @@ meta_window_move_resize_internal (MetaWindow *window,
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,
+ * see which way we're moving "more"
+ *
+ * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
+ * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
+ *
+ * An annoying fact you need to know in this code is that StaticGravity
+ * does nothing if you _only_ resize or _only_ move the frame;
+ * it must move _and_ resize, otherwise you get NorthWestGravity
+ * 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,
@@ -1687,41 +1711,100 @@ meta_window_move_resize_internal (MetaWindow *window,
if (window->frame)
{
int new_x, new_y;
+ int frame_pos_dx, frame_pos_dy;
+ /* Compute new frame coords */
new_x = root_x_nw - fgeom.left_width;
new_y = root_y_nw - fgeom.top_height;
- if (new_x != window->frame->rect.x ||
- new_y != window->frame->rect.y)
- need_move_frame = TRUE;
+ frame_pos_dx = new_x - window->frame->rect.x;
+ frame_pos_dy = new_y - window->frame->rect.y;
- if (window->rect.x != fgeom.left_width ||
- window->rect.y != fgeom.top_height)
- need_move_client = TRUE;
+ need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
window->frame->rect.x = new_x;
- window->frame->rect.y = new_y;
-
+ window->frame->rect.y = new_y;
+
+ /* If frame will both move and resize, then StaticGravity
+ * on the child window will kick in and implicitly move
+ * the child with respect to the frame. The implicit
+ * move will keep the child in the same place with
+ * respect to the root window. If frame only moves
+ * or only resizes, then the child will just move along
+ * with the frame.
+ */
+
/* window->rect.x, window->rect.y are relative to frame,
* remember they are the server coords
*/
- pos_dx = fgeom.left_width - window->rect.x;
- pos_dy = fgeom.top_height - window->rect.y;
-
- window->rect.x = fgeom.left_width;
- window->rect.y = fgeom.top_height;
+
+ new_x = fgeom.left_width;
+ new_y = fgeom.top_height;
+
+ if (need_resize_frame && need_move_frame &&
+ static_gravity_works (window->display))
+ {
+ /* static gravity kicks in because frame
+ * is both moved and resized
+ */
+ /* when we move the frame by frame_pos_dx, frame_pos_dy the
+ * client will implicitly move relative to frame by the
+ * inverse delta.
+ *
+ * When moving client then frame, we move the client by the
+ * frame delta, to be canceled out by the implicit move by
+ * the inverse frame delta, resulting in a client at new_x,
+ * new_y.
+ *
+ * When moving frame then client, we move the client
+ * by the same delta as the frame, because the client
+ * was "left behind" by the frame - resulting in a client
+ * at new_x, new_y.
+ *
+ * In both cases we need to move the client window
+ * in all cases where we had to move the frame window.
+ */
+
+ client_move_x = new_x + frame_pos_dx;
+ client_move_y = new_y + frame_pos_dy;
+
+ if (need_move_frame)
+ need_move_client = TRUE;
+
+ use_static_gravity = TRUE;
+ }
+ else
+ {
+ client_move_x = new_x;
+ client_move_y = new_y;
+
+ if (client_move_x != window->rect.x ||
+ client_move_y != window->rect.y)
+ need_move_client = TRUE;
+
+ use_static_gravity = FALSE;
+ }
+
+ /* This is the final target position, but not necessarily what
+ * we pass to XConfigureWindow, due to StaticGravity implicit
+ * movement.
+ */
+ window->rect.x = new_x;
+ window->rect.y = new_y;
}
else
{
if (root_x_nw != window->rect.x ||
root_y_nw != window->rect.y)
need_move_client = TRUE;
-
- pos_dx = root_x_nw - window->rect.x;
- pos_dy = root_y_nw - window->rect.y;
window->rect.x = root_x_nw;
window->rect.y = root_y_nw;
+
+ client_move_x = window->rect.x;
+ client_move_y = window->rect.y;
+
+ use_static_gravity = FALSE;
}
/* Fill in other frame member variables */
@@ -1736,7 +1819,7 @@ meta_window_move_resize_internal (MetaWindow *window,
/* See ICCCM 4.1.5 for when to send ConfigureNotify */
need_configure_notify = FALSE;
-
+
/* If this is a configure request and we change nothing, then we
* must send configure notify.
*/
@@ -1756,10 +1839,30 @@ meta_window_move_resize_internal (MetaWindow *window,
/* The rest of this function syncs our new size/pos with X as
* efficiently as possible
*/
+ if (use_static_gravity)
+ {
+ if ((size_dx + size_dy) >= 0)
+ configure_frame_first = FALSE;
+ else
+ configure_frame_first = TRUE;
+ }
+ else
+ {
+ configure_frame_first = FALSE;
+ }
+
+
+ if (use_static_gravity)
+ meta_window_set_gravity (window, StaticGravity);
+ if (configure_frame_first && window->frame)
+ meta_frame_sync_to_window (window->frame,
+ resize_gravity,
+ need_move_frame, need_resize_frame);
+
values.border_width = 0;
- values.x = window->rect.x;
- values.y = window->rect.y;
+ values.x = client_move_x;
+ values.y = client_move_y;
values.width = window->rect.width;
values.height = window->rect.height;
@@ -1792,12 +1895,14 @@ meta_window_move_resize_internal (MetaWindow *window,
meta_error_trap_pop (window->display);
}
- /* Now do the frame */
- if (window->frame)
- {
- meta_frame_sync_to_window (window->frame, need_move_frame, need_resize_frame);
- }
+ if (!configure_frame_first && window->frame)
+ meta_frame_sync_to_window (window->frame,
+ resize_gravity,
+ need_move_frame, need_resize_frame);
+ /* Put gravity back to be nice to lesser window managers */
+ if (use_static_gravity)
+ meta_window_set_gravity (window, NorthWestGravity);
if (need_configure_notify)
send_configure_notify (window);
diff --git a/src/window.h b/src/window.h
index bd24faf..e8dc976 100644
--- a/src/window.h
+++ b/src/window.h
@@ -28,17 +28,6 @@
#include <X11/Xutil.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-typedef enum
-{
- META_WINDOW_NORMAL,
- META_WINDOW_DESKTOP,
- META_WINDOW_DOCK,
- META_WINDOW_DIALOG,
- META_WINDOW_MODAL_DIALOG,
- META_WINDOW_TOOLBAR,
- META_WINDOW_MENU
-} MetaWindowType;
-
struct _MetaWindow
{
MetaDisplay *display;
diff --git a/src/wm-tester/Makefile.am b/src/wm-tester/Makefile.am
index 8673127..ffecdcc 100644
--- a/src/wm-tester/Makefile.am
+++ b/src/wm-tester/Makefile.am
@@ -10,8 +10,12 @@ test_gravity_SOURCES= \
focus_window_SOURCES= \
focus-window.c
-noinst_PROGRAMS=wm-tester test-gravity focus-window
+test_resizing_SOURCES= \
+ test-resizing.c
+
+noinst_PROGRAMS=wm-tester test-gravity test-resizing focus-window
wm_tester_LDADD= @METACITY_LIBS@
test_gravity_LDADD= @METACITY_LIBS@
+test_resizing_LDADD= @METACITY_LIBS@
focus_window_LDADD= @METACITY_LIBS@ \ No newline at end of file
diff --git a/src/wm-tester/test-resizing.c b/src/wm-tester/test-resizing.c
new file mode 100644
index 0000000..479fc69
--- /dev/null
+++ b/src/wm-tester/test-resizing.c
@@ -0,0 +1,255 @@
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdlib.h>
+#include <glib.h>
+
+static void
+calc_rects (XRectangle *rects, int width, int height)
+{
+ int w = (width - 21) / 3;
+ int h = (height - 21) / 3;
+ int i;
+
+ i = 0;
+ while (i < 9)
+ {
+ rects[i].width = w;
+ rects[i].height = h;
+ ++i;
+ }
+
+ /* NW */
+ rects[0].x = 0;
+ rects[0].y = 0;
+
+ /* N */
+ rects[1].x = width / 2 - w / 2;
+ rects[1].y = 0;
+
+ /* NE */
+ rects[2].x = width - w;
+ rects[2].y = 0;
+
+ /* E */
+ rects[3].x = width - w;
+ rects[3].y = height / 2 - h / 2;
+
+ /* SE */
+ rects[4].x = width - w;
+ rects[4].y = height - h;
+
+ /* S */
+ rects[5].x = width / 2 - w / 2;
+ rects[5].y = height - h;
+
+ /* SW */
+ rects[6].x = 0;
+ rects[6].y = height - h;
+
+ /* W */
+ rects[7].x = 0;
+ rects[7].y = height / 2 - h / 2;
+
+ /* Center */
+ rects[8].x = width / 2 - w / 2;
+ rects[8].y = height / 2 - h / 2;
+}
+
+static Bool
+all_events (Display *display,
+ XEvent *event,
+ XPointer arg)
+{
+ return True;
+}
+
+static void
+get_size (Display *d, Drawable draw,
+ int *xp, int *yp, int *widthp, int *heightp)
+{
+ int x, y;
+ unsigned int width, height, border, depth;
+ Window root;
+
+ XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth);
+
+ if (xp)
+ *xp = x;
+ if (yp)
+ *yp = y;
+ if (widthp)
+ *widthp = width;
+ if (*heightp)
+ *heightp = height;
+}
+
+int
+main (int argc, char **argv)
+{
+ Display *d;
+ Window w, cw;
+ XSizeHints hints;
+ int screen;
+ XEvent ev;
+ int x, y, width, height;
+ Pixmap pix;
+ GC gc;
+ XGCValues gc_vals;
+ XSetWindowAttributes set_attrs;
+ XWindowChanges changes;
+ XRectangle rects[9];
+ gboolean redraw_pending;
+ unsigned int mask;
+
+ d = XOpenDisplay (NULL);
+
+ screen = DefaultScreen (d);
+
+ /* Print some debug spew to show how StaticGravity works */
+ w = XCreateSimpleWindow (d, RootWindow (d, screen),
+ 0, 0, 100, 100, 0,
+ WhitePixel (d, screen),
+ WhitePixel (d, screen));
+ cw = XCreateSimpleWindow (d, w,
+ 0, 0, 100, 100, 0,
+ WhitePixel (d, screen),
+ WhitePixel (d, screen));
+ set_attrs.win_gravity = StaticGravity;
+
+ XChangeWindowAttributes (d, cw,
+ CWWinGravity,
+ &set_attrs);
+
+ get_size (d, w, &x, &y, &width, &height);
+
+ g_print ("Parent is %d,%d %d x %d before configuring parent\n",
+ x, y, width, height);
+
+ get_size (d, cw, &x, &y, &width, &height);
+
+ g_print ("Child is %d,%d %d x %d before configuring parent\n",
+ x, y, width, height);
+
+ changes.x = 10;
+ changes.y = 10;
+ changes.width = 110;
+ changes.height = 110;
+ /* last mask wins */
+ mask = CWX | CWY;
+ mask = CWWidth | CWHeight;
+ mask = CWX | CWY | CWWidth | CWHeight;
+
+ XConfigureWindow (d, w, mask, &changes);
+ XSync (d, False);
+
+ get_size (d, w, &x, &y, &width, &height);
+
+ g_print ("Parent is %d,%d %d x %d after configuring parent\n",
+ x, y, width, height);
+
+ get_size (d, cw, &x, &y, &width, &height);
+
+ g_print ("Child is %d,%d %d x %d after configuring parent\n",
+ x, y, width, height);
+
+ XDestroyWindow (d, w);
+
+ /* The window that gets displayed */
+
+ x = 20;
+ y = 20;
+ width = 100;
+ height = 100;
+
+ calc_rects (rects, width, height);
+
+ w = XCreateSimpleWindow (d, RootWindow (d, screen),
+ x, y, width, height, 0,
+ WhitePixel (d, screen),
+ WhitePixel (d, screen));
+
+ set_attrs.bit_gravity = StaticGravity;
+
+ XChangeWindowAttributes (d, w,
+ CWBitGravity,
+ &set_attrs);
+
+ XSelectInput (d, w,
+ ButtonPressMask | ExposureMask | StructureNotifyMask);
+
+ hints.flags = PMinSize;
+
+ hints.min_width = 100;
+ hints.min_height = 100;
+
+ XSetWMNormalHints (d, w, &hints);
+ XMapWindow (d, w);
+
+ redraw_pending = FALSE;
+ while (1)
+ {
+ XNextEvent (d, &ev);
+
+ switch (ev.xany.type)
+ {
+ case ButtonPress:
+ if (ev.xbutton.button == 3)
+ {
+ g_print ("Exiting on button 3 press\n");
+ exit (0);
+ }
+ break;
+
+ case ConfigureNotify:
+ x = ev.xconfigure.x;
+ y = ev.xconfigure.y;
+ width = ev.xconfigure.width;
+ height = ev.xconfigure.height;
+
+ redraw_pending = TRUE;
+ break;
+
+ case Expose:
+ redraw_pending = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Primitive event compression */
+ if (XCheckIfEvent (d, &ev, all_events, NULL))
+ {
+ XPutBackEvent (d, &ev);
+ }
+ else if (redraw_pending)
+ {
+ calc_rects (rects, width, height);
+
+ pix = XCreatePixmap (d, w, width, height,
+ DefaultDepth (d, screen));
+
+ gc_vals.foreground = WhitePixel (d, screen);
+
+ gc = XCreateGC (d, pix, GCForeground, &gc_vals);
+
+ XFillRectangle (d, pix, gc, 0, 0, width, height);
+
+ /* Draw rectangles at each gravity point */
+ gc_vals.foreground = BlackPixel (d, screen);
+ XChangeGC (d, gc, GCForeground, &gc_vals);
+
+ XFillRectangles (d, pix, gc, rects, G_N_ELEMENTS (rects));
+
+ XCopyArea (d, pix, w, gc, 0, 0, width, height, 0, 0);
+
+ XFreePixmap (d, pix);
+ XFreeGC (d, gc);
+
+ redraw_pending = FALSE;
+ }
+ }
+
+ return 0;
+}
+