Switch over to new constraints code, unquestionably introduces some bugs,

2003-02-27  Havoc Pennington  <hp@redhat.com>

	Switch over to new constraints code, unquestionably introduces
	some bugs, but should get us on the right path.

	* src/window.c (meta_window_get_work_area_all_xineramas): create
	this function again as it turned out to be legitimate for window
	position constraint
	(adjust_for_gravity): use the width/height from the configure
	request to compute the requested move
	(meta_window_move_resize_internal): use meta_window_constrain
	(update_size_hints): clamp max size to MAXSHORT to avoid worrying
	about overflow stuff

	* src/constraints.c (meta_window_constrain): don't base placement
	on uninitialized variables, general hacking

	* src/Makefile.am (metacity_SOURCES): add constraints.c,
	constraints.h

	* src/constraints.c (meta_window_constrain): update the
	cut-and-paste aspect ratio code to have latest bugfixes
This commit is contained in:
Havoc Pennington 2003-03-08 23:43:17 +00:00 committed by Havoc Pennington
parent 4481be72d1
commit 5f75334d57
6 changed files with 849 additions and 689 deletions

View File

@ -1,3 +1,26 @@
2003-02-27 Havoc Pennington <hp@redhat.com>
Switch over to new constraints code, unquestionably introduces
some bugs, but should get us on the right path.
* src/window.c (meta_window_get_work_area_all_xineramas): create
this function again as it turned out to be legitimate for window
position constraint
(adjust_for_gravity): use the width/height from the configure
request to compute the requested move
(meta_window_move_resize_internal): use meta_window_constrain
(update_size_hints): clamp max size to MAXSHORT to avoid worrying
about overflow stuff
* src/constraints.c (meta_window_constrain): don't base placement
on uninitialized variables, general hacking
* src/Makefile.am (metacity_SOURCES): add constraints.c,
constraints.h
* src/constraints.c (meta_window_constrain): update the
cut-and-paste aspect ratio code to have latest bugfixes
2003-03-08 Rob Adams <robadams@ucla.edu>
* src/window-props.c (reload_normal_hints): Check that window min

View File

@ -14,6 +14,8 @@ metacity_SOURCES= \
bell.h \
bell.c \
common.h \
constraints.c \
constraints.h \
core.c \
core.h \
delete.c \

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
#include "xprops.h"
#include "group.h"
#include "window-props.h"
#include "constraints.h"
#include <X11/Xatom.h>
#include <string.h>
@ -65,18 +66,6 @@ typedef enum
static int destroying_windows_disallowed = 0;
static void constrain_size (MetaWindow *window,
MetaFrameGeometry *fgeom,
int width,
int height,
int *new_width,
int *new_height);
static void constrain_position (MetaWindow *window,
MetaFrameGeometry *fgeom,
int x,
int y,
int *new_x,
int *new_y);
static void update_net_wm_state (MetaWindow *window);
static void update_mwm_hints (MetaWindow *window);
@ -103,14 +92,6 @@ static GList* meta_window_get_workspaces (MetaWindow *window);
static void meta_window_save_rect (MetaWindow *window);
static void adjust_for_gravity (MetaWindow *window,
MetaFrameGeometry *fgeom,
gboolean coords_assume_border,
int x,
int y,
int *xp,
int *yp);
static void meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,
@ -2012,13 +1993,17 @@ meta_window_activate (MetaWindow *window,
meta_window_focus (window, timestamp);
}
/* returns values suitable for meta_window_move */
/* returns values suitable for meta_window_move
* i.e. static gravity
*/
static void
adjust_for_gravity (MetaWindow *window,
MetaFrameGeometry *fgeom,
gboolean coords_assume_border,
int x,
int y,
int width,
int height,
int *xp,
int *yp)
{
@ -2036,15 +2021,15 @@ adjust_for_gravity (MetaWindow *window,
{
child_x = fgeom->left_width;
child_y = fgeom->top_height;
frame_width = child_x + window->rect.width + fgeom->right_width;
frame_height = child_y + window->rect.height + fgeom->bottom_height;
frame_width = child_x + width + fgeom->right_width;
frame_height = child_y + height + fgeom->bottom_height;
}
else
{
child_x = 0;
child_y = 0;
frame_width = window->rect.width;
frame_height = window->rect.height;
frame_width = width;
frame_height = height;
}
/* We're computing position to pass to window_move, which is
@ -2061,36 +2046,36 @@ adjust_for_gravity (MetaWindow *window,
ref_y = y;
break;
case NorthGravity:
ref_x = x + window->rect.width / 2 + bw;
ref_x = x + width / 2 + bw;
ref_y = y;
break;
case NorthEastGravity:
ref_x = x + window->rect.width + bw * 2;
ref_x = x + width + bw * 2;
ref_y = y;
break;
case WestGravity:
ref_x = x;
ref_y = y + window->rect.height / 2 + bw;
ref_y = y + height / 2 + bw;
break;
case CenterGravity:
ref_x = x + window->rect.width / 2 + bw;
ref_y = y + window->rect.height / 2 + bw;
ref_x = x + width / 2 + bw;
ref_y = y + height / 2 + bw;
break;
case EastGravity:
ref_x = x + window->rect.width + bw * 2;
ref_y = y + window->rect.height / 2 + bw;
ref_x = x + width + bw * 2;
ref_y = y + height / 2 + bw;
break;
case SouthWestGravity:
ref_x = x;
ref_y = y + window->rect.height + bw * 2;
ref_y = y + height + bw * 2;
break;
case SouthGravity:
ref_x = x + window->rect.width / 2 + bw;
ref_y = y + window->rect.height + bw * 2;
ref_x = x + width / 2 + bw;
ref_y = y + height + bw * 2;
break;
case SouthEastGravity:
ref_x = x + window->rect.width + bw * 2;
ref_y = y + window->rect.height + bw * 2;
ref_x = x + width + bw * 2;
ref_y = y + height + bw * 2;
break;
case StaticGravity:
default:
@ -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)

View File

@ -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,

View File

@ -1,6 +1,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <string.h>
int gravities[10] = {
NorthWestGravity,
@ -15,17 +16,68 @@ int gravities[10] = {
StaticGravity
};
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];
}
}
}
}