Merge of all the changes on the constraints_experiments branch. This is

2005-11-18  Elijah Newren  <newren@gmail.com>

	Merge of all the changes on the constraints_experiments branch.
	This is just a summary, to get the full ChangeLog of those
	changes (approx. 2000 lines):
	  cvs -q -z3 update -Pd -r constraints_experiments
	  cvs -q -z3 diff -pu -r CONSTRAINTS_EXPERIMENTS_BRANCHPOINT ChangeLog

	Bugs fixed:
	  unfiled - constraints.c is overly complicated[1]
	  unfiled - constraints.c is not robust when all constraints
	            cannot simultaneously be met (constraints need to be
	            prioritized)
	  unfiled - keep-titlebar-onscreen constraint is decoration
	            unaware (since get_outermost_onscreen_positions()
	            forgets to include decorations)
	  unfiled - keyboard snap-moving and snap-resizing snap to hidden
	            edges
	   109553 - gravity w/ simultaneous move & resize doesn't work
	   113601 - maximize vertical and horizontal should toggle and be
	            constrained
	   122196 - windows show up under vertical panels
	   122670 - jerky/random resizing of window via keyboard[2]
	   124582 - keyboard and mouse snap-resizing and snap-moving
	            erroneously moves the window multidimensionally
	   136307 - don't allow apps to resize themselves off the screen
	            (*cough* filechooser *cough*)
	   142016, 143784 - windows should not span multiple xineramas
	            unless placed there by the user
	   143145 - clamp new windows to screensize and force them
	            onscreen, if they'll fit
	   144126 - Handle pathological strut lists sanely[3]
	   149867 - fixed aspect ratio windows are difficult to resize[4]
	   152898 - make screen edges consistent; allow easy slamming of
	            windows into the left, right, and bottom edges of the
	            screen too.
	   154706 - bouncing weirdness at screen edge with keyboard moving
	            or resizing
	   156699 - avoid struts when placing windows, if possible (nasty
	            a11y blocker)
	   302456 - dragging offscreen too restrictive
	   304857 - wireframe moving off the top of the screen is misleading
	   308521 - make uni-directional resizing easier with
	            alt-middle-drag and prevent the occasional super
	            annoying resize-the-wrong-side(s) behavior
	   312007 - snap-resize moves windows with a minimum size
	            constraint
	   312104 - resizing the top of a window can cause the bottom to
	            grow
	   319351 - don't instantly snap on mouse-move-snapping, remove
	            braindeadedness of having order of releasing shift and
	            releasing button press matter so much

	   [1] fixed in my opinion, anyway.
	   [2] Actually, it's not totally fixed--it's just annoying
	       instead of almost completely unusable.  Matthias had a
	       suggestion that may fix the remainder of the problems (see
	       http://tinyurl.com/bwzuu).
	   [3] This bug was originally about not-quite-so-pathological
	       cases but was left open for the worse cases. The code from
	       the branch handles the remainder of the cases mentioned in
	       this bug.
	   [4] Actually, although it's far better there's still some minor
	       issues left: a slight drift that's only noticeable after
	       lots of resizing, and potential problems with partially
	       onscreen constraints due to not clearing any
	       fixed_directions flags (aspect ratio windows get resized in
	       both directions and thus aren't fixed in one of them)

	New feature:
	    81704 - edge resistance for user move and resize operations;
	            in particular 3 different kinds of resistance are
	            implemented:
             	 Pixel-Distance: window movement is resisted when it
	     	   aligns with an edge unless the movement is greater than
	     	   a threshold number of pixels
             	 Timeout: window movement past an edge is prevented until
	     	   a certain amount of time has elapsed during the
	     	   operation since the first request to move it past that
	     	   edge
             	 Keyboard-Buildup: when moving or resizing with the
	     	   keyboard, once a window is aligned with a certain edge
	     	   it cannot move past until the correct direction has
	     	   been pressed enough times (e.g. 2 or 3 times)

	Major changes:
	  - constraints.c has been rewritten; very few lines of code from
	    the old version remain.  There is a comment near the top of
	    the function explaining the basics of how the new framework
	    works.  A more detailed explanation can be found in
	    doc/how-constraints-works.txt
	  - edge-resistance.[ch] are new files implementing edge-resistance.
	  - boxes.[ch] are new files containing low-level error-prone
	    functions used heavily in constraints.c and edge-resistance.c,
	    among various places throughout the code.  testboxes.c
	    contains a thorough testsuite for the boxes.[ch] functions
	    compiled into a program, testboxes.
	  - meta_window_move_resize_internal() *must* be told the gravity
	    of the associated operation (if it's just a move operation,
	    the gravity will be ignored, but for resize and move+resize
	    the correct value is needed)
	  - the craziness of different values that
	    meta_window_move_resize_internal() accepts has been documented
	    in a large comment at the beginning of the function.  It may
	    be possible to clean this up some, but until then things will
	    remain as they were before--caller beware.
	  - screen and xinerama usable areas (i.e. places not covered by
	    e.g. panels) are cached in the workspace now, as are the
	    screen and xinerama edges.  These get updated with the
	    workarea in src/workspace.c:ensure_work_areas_validated()
This commit is contained in:
Elijah Newren 2005-11-19 14:58:50 +00:00 committed by Elijah Newren
parent cfb3bd081a
commit a7201d27d1
35 changed files with 7358 additions and 2738 deletions

View File

@ -15,6 +15,7 @@ ltconfig
ltmain.sh ltmain.sh
stamp-h stamp-h
stamp-h.in stamp-h.in
stamp-h1
stamp.h stamp.h
version.h version.h
config.h.in config.h.in

111
ChangeLog
View File

@ -1,3 +1,114 @@
2005-11-18 Elijah Newren <newren@gmail.com>
Merge of all the changes on the constraints_experiments branch.
This is just a summary, to get the full ChangeLog of those
changes (approx. 2000 lines):
cvs -q -z3 update -Pd -r constraints_experiments
cvs -q -z3 diff -pu -r CONSTRAINTS_EXPERIMENTS_BRANCHPOINT ChangeLog
Bugs fixed:
unfiled - constraints.c is overly complicated[1]
unfiled - constraints.c is not robust when all constraints
cannot simultaneously be met (constraints need to be
prioritized)
unfiled - keep-titlebar-onscreen constraint is decoration
unaware (since get_outermost_onscreen_positions()
forgets to include decorations)
unfiled - keyboard snap-moving and snap-resizing snap to hidden
edges
109553 - gravity w/ simultaneous move & resize doesn't work
113601 - maximize vertical and horizontal should toggle and be
constrained
122196 - windows show up under vertical panels
122670 - jerky/random resizing of window via keyboard[2]
124582 - keyboard and mouse snap-resizing and snap-moving
erroneously moves the window multidimensionally
136307 - don't allow apps to resize themselves off the screen
(*cough* filechooser *cough*)
142016, 143784 - windows should not span multiple xineramas
unless placed there by the user
143145 - clamp new windows to screensize and force them
onscreen, if they'll fit
144126 - Handle pathological strut lists sanely[3]
149867 - fixed aspect ratio windows are difficult to resize[4]
152898 - make screen edges consistent; allow easy slamming of
windows into the left, right, and bottom edges of the
screen too.
154706 - bouncing weirdness at screen edge with keyboard moving
or resizing
156699 - avoid struts when placing windows, if possible (nasty
a11y blocker)
302456 - dragging offscreen too restrictive
304857 - wireframe moving off the top of the screen is misleading
308521 - make uni-directional resizing easier with
alt-middle-drag and prevent the occasional super
annoying resize-the-wrong-side(s) behavior
312007 - snap-resize moves windows with a minimum size
constraint
312104 - resizing the top of a window can cause the bottom to
grow
319351 - don't instantly snap on mouse-move-snapping, remove
braindeadedness of having order of releasing shift and
releasing button press matter so much
[1] fixed in my opinion, anyway.
[2] Actually, it's not totally fixed--it's just annoying
instead of almost completely unusable. Matthias had a
suggestion that may fix the remainder of the problems (see
http://tinyurl.com/bwzuu).
[3] This bug was originally about not-quite-so-pathological
cases but was left open for the worse cases. The code from
the branch handles the remainder of the cases mentioned in
this bug.
[4] Actually, although it's far better there's still some minor
issues left: a slight drift that's only noticeable after
lots of resizing, and potential problems with partially
onscreen constraints due to not clearing any
fixed_directions flags (aspect ratio windows get resized in
both directions and thus aren't fixed in one of them)
New feature:
81704 - edge resistance for user move and resize operations;
in particular 3 different kinds of resistance are
implemented:
Pixel-Distance: window movement is resisted when it
aligns with an edge unless the movement is greater than
a threshold number of pixels
Timeout: window movement past an edge is prevented until
a certain amount of time has elapsed during the
operation since the first request to move it past that
edge
Keyboard-Buildup: when moving or resizing with the
keyboard, once a window is aligned with a certain edge
it cannot move past until the correct direction has
been pressed enough times (e.g. 2 or 3 times)
Major changes:
- constraints.c has been rewritten; very few lines of code from
the old version remain. There is a comment near the top of
the function explaining the basics of how the new framework
works. A more detailed explanation can be found in
doc/how-constraints-works.txt
- edge-resistance.[ch] are new files implementing edge-resistance.
- boxes.[ch] are new files containing low-level error-prone
functions used heavily in constraints.c and edge-resistance.c,
among various places throughout the code. testboxes.c
contains a thorough testsuite for the boxes.[ch] functions
compiled into a program, testboxes.
- meta_window_move_resize_internal() *must* be told the gravity
of the associated operation (if it's just a move operation,
the gravity will be ignored, but for resize and move+resize
the correct value is needed)
- the craziness of different values that
meta_window_move_resize_internal() accepts has been documented
in a large comment at the beginning of the function. It may
be possible to clean this up some, but until then things will
remain as they were before--caller beware.
- screen and xinerama usable areas (i.e. places not covered by
e.g. panels) are cached in the workspace now, as are the
screen and xinerama edges. These get updated with the
workarea in src/workspace.c:ensure_work_areas_validated()
2005-11-14 Elijah Newren <newren@gmail.com> 2005-11-14 Elijah Newren <newren@gmail.com>
* configure.in: post-release version bump to 2.13.2 * configure.in: post-release version bump to 2.13.2

View File

@ -0,0 +1,283 @@
File contents:
Basic Ideas
Important points to remember
Explanation of fields in the ConstraintInfo struct
Gory details of resize_gravity vs. fixed_directions
IMPORTANT NOTE: There's a big comment at the top of constraints.c
explaining how to add extra constraints or tweak others. Read it. I put
that information there because it may be enough information by itself for
people to hack on constraints.c. I won't duplicate that information in
this file; this file is for deeper details.
---------------------------------------------------------------------------
Basic Ideas
---------------------------------------------------------------------------
There are a couple basic ideas behind how this constraints.c code works and
why it works that way:
1) Split the low-level error-prone operations into a special file
2) Add robustness by prioritizing constraints
3) Make use of a minimal spanning set of rectangles for the
"onscreen region" (screen minus struts).
4) Constraints can be user-action vs app-action oriented
5) Avoid over-complification ;-)
Some more details explaining these basic ideas:
1) Split tedious operations out
boxes.[ch] have been added which contain many common, tedious, and
error-prone operations. I find that this separation helps a lot for
managing the complexity and ensuring that things work correctly.
Also, note that testboxes.c thoroughly tests all functionality in
boxes.[ch] and a testboxes program is automatically compiled.
Note that functions have also been added to this file to handle some
of the tedium necessary for edge resistance as well.
2) Prioritize constraints
In the old code, if each and every constraint could not be
simultaneously satisfied, then it would result in some
difficult-to-predict set of constraints being violated. This was
because constraints were applied in order, with the possibility for
each making changes that violated previous constraints, with no
checking done at the end.
Now, all constraints have an associated priority, defined in the
ConstraintPriority enum near the top of constraints.c. The
constraints are all applied, and then are all checked; if not all are
satisfied then the least important constraints are dropped and the
process is repeated. This ensures that the most important constraints
are satisfied.
A special note to make here is that if any one given constraint is
impossible to satisfy even individually (e.g. if minimum size hints
specify a larger window than the screen size, making the
fully-onscreen constraint impossible to satisfy) then we treat the
constraint as being satisfied. This sounds counter-intuitive, but the
idea is that we want to satisfy as many constraints as possible and if
we treat it as a violation then all constraints with a lesser priority
also get dropped along with the impossible to satisfy one.
3) Using maximal/spanning rectangles
The constraints rely heavily on something I call spanning rectangles
(which Soeren referred to as maximal rectangles, a name which I think
I like better but I don't want to go change all the code now). These
spanning rectangles have the property that a window will fit on the
screen if and only if it fits within at least one of the rectangles.
Soeren had an alternative way of describing these rectangles, namely
that they were rectangles with the property that if you made any of
them larger in any direction, they would overlap with struts or be
offscreen (with the implicit assumption that there are enough of these
rectangles that combined they cover all relevant parts of the screen).
Note that, by necessity, these spanning/maximal rectangles will often
overlap each other.
Such a list makes it relatively easy to define operations like
window-is-onscreen or clamp-window-to-region or
shove-window-into-region. Since we have a on-single-xinerama
constraint in addition to the onscreen constraint(s), we cache
number_xineramas + 1 of these lists in the workspace. These lists
then only need to be updated whenever the workarea is (e.g. when strut
list change or screen or xinerama size changes).
4) Constraints can be user-action vs app-action oriented
Such differentiation requires special care for the constraints to be
consistent; e.g. if the user does something and one constraint
applies, then the app does something you have to be careful that the
constraint on the app action doesn't result in some jarring motion.
In particular, the constraints currently allow offscreen movement or
resizing for user actions only. The way consistency is handled is
that at the end of the constraints, update_onscreen_requirements()
checks to see if the window is offscreen or split across xineramas and
updates window->require_fully_onscreen and
window->require_on_single_xinerama appropriately.
5) Avoid over-complification
The previous code tried to reform the constraints into terms of a
single variable. This made the code rather difficult to
understand. ("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.") It also failed, even on the
very example for which it used as justification for the complexity
(bug 312104 -- when keyboard resizing the top of the window,
Metacity extends the bottom once the titlebar hits the top panel),
though the reason why it failed is somewhat mysterious as it should
have worked. Further, it didn't really reform the constraints in
terms of a single variable -- there was both an x_move_delta and an
x_resize_delta, and the existence of both caused bug 109553
(gravity with simultaneous move and resize doesn't work)
---------------------------------------------------------------------------
Important points to remember
---------------------------------------------------------------------------
- Inner vs Outer window
Note that because of how configure requests work and
meta_window_move_resize_internal() and friends are set up, that the
rectangles passed to meta_window_constrain() are with respect to inner
window positions instead of outer window positions (meaning that window
manager decorations are not included in the position/size). For the
constraints that need to be enforced with respect to outer window
positions, you'll need to make use of the extend_by_frame() and
unextend_by_frame() functions.
- meta_window_move_resize_internal() accepts a really hairy set of
inputs. See the huge comment at the beginning of that function.
constraints gets screwed up if that function can't sanitize the input,
so be very careful about that. It used to be pretty busted.
---------------------------------------------------------------------------
Explanation of fields in the ConstraintInfo strut
---------------------------------------------------------------------------
As of the time of this writing, ConstraintInfo had the following fields:
orig
current
fgeom
action_type
is_user_action
resize_gravity
fixed_directions
work_area_xinerama
entire_xinerama
usable_screen_region
usable_xinerama_region
A brief description of each and/or pointers to more information are found
below:
orig
The previous position and size of the window, ignoring any window
decorations
current
The requested position and size of the window, ignoring any window
decorations. This rectangle gets modified by the various constraints
to specify the allowed position closest to the requested position.
fgeom
The geometry of the window frame (i.e. "decorations"), if it exists.
Otherwise, it's a dummy 0-size frame for convenience (i.e. this pointer
is guaranteed to be non-NULL so you don't have to do the stupid check).
action_type
Whether the action being constrained is a move, resize, or a combined
move and resize. Some constraints can run faster with this information
(e.g. constraining size increment hints or min size hints don't need to
do anything for pure move operations). This may also be used for
providing slightly different behavior (e.g. clip-to-region instead of
shove-into-region for resize vs. moving operations), but doesn't
currently have a lot of use for this.
is_user_action
Used to determine whether the action being constrained is a user
action. If so, certain parts of the constraint may be relaxed. Note
that this requires care to get right; see item 4 of the basic ideas
section for more details.
resize_gravity
The gravity used in the resize operation, used in order to make sure
windows are resized correctly if constraints specify that their size
must be modified. Explained further in the resize_gravity
vs. fixed_directions section.
fixed_directions
There may be multiple solutions to shoving a window back onscreen.
Typically, the shortest distance used is the solution picked, but if
e.g. an application only moved its window in a single direction, it's
more desirable that the window is shoved back in that direction than in
a different one. fixed_directions facilitates that. Explained further
in the resize_gravity vs. fixed_directions section.
work_area_xinerama
This region is defined in the workspace and just cached here for
convenience. It is basically the area obtained by taking the current
xinerama, treating all partial struts as full struts, and then
subtracting all struts from the current xinerama region. Useful
e.g. for enforcing maximization constraints.
entire_xinerama
Just a cache of the rectangle corresponding to the entire current
xinerama, including struts. Useful e.g. for enforcing fullscreen
constraints.
usable_screen_region
The set of maximal/spanning rectangles for the entire screen; this
region doesn't overlap with any struts and helps to enforce
e.g. onscreen constraints.
usable_xinerama_region
The set of maximal/spanning rectangles for the current xinerama; this
region doesn't overlap with any struts on the xinerama and helps to
enforce e.g. the on-single-xinerama constraint.
---------------------------------------------------------------------------
Gory details of resize_gravity vs. fixed_directions
---------------------------------------------------------------------------
Note that although resize_gravity and fixed_directions look similar, they
are used for different purposes:
- resize_gravity is only for resize operations and is used for
constraints unrelated to keeping a window within a certain region
- fixed_directions is for both move and resize operations and is
specifically for keeping a window within a specified region.
Examples of where each are used:
- If a window is simultaneously moved and resized to the southeast corner
with SouthEastGravity, but it turns out that the window was sized to
something smaller than the minimum size hint, then the size_hints
constraint should resize the window using the resize_gravity to ensure
that the southeast corner doesn't move.
- If an application resizes itself so that it grows downward only (which
I note could be using any of three different gravities, most likely
NorthWest), and happens to put the southeast part of the window under a
partial strut, then the window needs to be forced back on screen.
(Yes, shoved onscreen and not clipped; see bug 136307). It may be the
case that moving the window to the left results in less movement of the
window than moving the window up, which, in the absence of fixed
directions would cause us to chose moving to the left. But since the
user knows that only the height of the window is changing, they would
find moving to the left weird (especially if this were a dialog that
had been centered on its parent). It'd be better to shove the window
upwards so we make sure to keep the left and right sides fixed in this
case. Note that moving the window upwards (or leftwards) is probably
totally against the gravity in this case; but that's okay because
gravity typically assumes there's more than enough onscreen space for
the resize and we only override the gravity when that assumption is
wrong.
For the paranoid, a fixed directions might give an impossible to fulfill
constraint (I don't think that's true currently in the code, but I haven't
thought it through in a while). If this ever becomes a problem, it should
be relatively simple to throw out the fixed directions when this happens
and rerun the constraint. Of course, it might be better to rethink things
to just avoid such a problem.
The nitty gritty of what gets fixed:
User move:
in x direction - y direction fixed
in y direction - x direction fixed
in both dirs. - neither direction fixed
User resize: (note that for clipping, only 1 side ever changed)
in x direction - y direction fixed (technically opposite x side fixed too)
in y direction - x direction fixed (technically opposite y side fixed too)
in both dirs. - neither direction fixed
App move:
in x direction - y direction fixed
in y direction - x direction fixed
in both dirs. - neither direction fixed
App resize
in x direction - y direction fixed
in y direction - x direction fixed
in 2 parallel directions (center side gravity) - other dir. fixed
in 2 orthogonal directions (corner gravity) - neither dir. fixed
in 3 or 4 directions (a center-like gravity) - neither dir. fixed
Move & resize
Treat like resize case though this will usually mean all four sides
change and result in neither direction being fixed
Note that in all cases, if neither direction moves it is likely do to a
change in struts and thus neither direction should be fixed despite the
lack of movement.

View File

@ -5,6 +5,7 @@ Makefile
metacity metacity
metacity-theme-viewer metacity-theme-viewer
metacity-dialog metacity-dialog
testboxes
testgradient testgradient
inlinepixbufs.h inlinepixbufs.h
metacity.desktop metacity.desktop

View File

@ -13,6 +13,8 @@ metacity_SOURCES= \
async-getprop.h \ async-getprop.h \
bell.h \ bell.h \
bell.c \ bell.c \
boxes.h \
boxes.c \
common.h \ common.h \
compositor.c \ compositor.c \
compositor.h \ compositor.h \
@ -25,6 +27,8 @@ metacity_SOURCES= \
display.h \ display.h \
draw-workspace.c \ draw-workspace.c \
draw-workspace.h \ draw-workspace.h \
edge-resistance.c \
edge-resistance.h \
effects.c \ effects.c \
effects.h \ effects.h \
errors.c \ errors.c \
@ -133,11 +137,13 @@ metacity_LDADD=@METACITY_LIBS@ $(EFENCE)
metacity_theme_viewer_LDADD= @METACITY_LIBS@ libmetacity-private.la metacity_theme_viewer_LDADD= @METACITY_LIBS@ libmetacity-private.la
metacity_dialog_LDADD=@METACITY_LIBS@ metacity_dialog_LDADD=@METACITY_LIBS@
testboxes_SOURCES=util.h util.c boxes.h boxes.c testboxes.c
testgradient_SOURCES=gradient.h gradient.c testgradient.c testgradient_SOURCES=gradient.h gradient.c testgradient.c
testasyncgetprop_SOURCES=async-getprop.h async-getprop.c testasyncgetprop.c testasyncgetprop_SOURCES=async-getprop.h async-getprop.c testasyncgetprop.c
noinst_PROGRAMS=testgradient testasyncgetprop noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD= @METACITY_LIBS@
testgradient_LDADD= @METACITY_LIBS@ testgradient_LDADD= @METACITY_LIBS@
testasyncgetprop_LDADD= @METACITY_LIBS@ testasyncgetprop_LDADD= @METACITY_LIBS@

View File

@ -30,8 +30,8 @@ meta_bell_flash_screen (MetaDisplay *display,
MetaScreen *screen) MetaScreen *screen)
{ {
Window root = screen->xroot; Window root = screen->xroot;
int width = screen->width; int width = screen->rect.width;
int height = screen->height; int height = screen->rect.height;
if (screen->flash_window == None) if (screen->flash_window == None)
{ {

1745
src/boxes.c Normal file

File diff suppressed because it is too large Load Diff

239
src/boxes.h Normal file
View File

@ -0,0 +1,239 @@
/* Simple box operations */
/*
* Copyright (C) 2005 Elijah Newren
*
* 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
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* 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.
*/
#ifndef META_BOXES_H
#define META_BOXES_H
#include <glib.h>
#include "common.h"
typedef struct _MetaRectangle MetaRectangle;
struct _MetaRectangle
{
int x;
int y;
int width;
int height;
};
#define BOX_LEFT(box) ((box).x) /* Leftmost pixel of rect */
#define BOX_RIGHT(box) ((box).x + (box).width) /* One pixel past right */
#define BOX_TOP(box) ((box).y) /* Topmost pixel of rect */
#define BOX_BOTTOM(box) ((box).y + (box).height) /* One pixel past bottom */
typedef enum
{
FIXED_DIRECTION_X = 1 << 0,
FIXED_DIRECTION_Y = 1 << 1,
} FixedDirections;
typedef enum
{
META_EDGE_WINDOW,
META_EDGE_XINERAMA,
META_EDGE_SCREEN
} MetaEdgeType;
typedef struct _MetaEdge MetaEdge;
struct _MetaEdge
{
MetaRectangle rect; /* width or height should be 1 */
MetaDirection side_type; /* should only have 1 of the 4 directions set */
MetaEdgeType edge_type;
};
/* Output functions -- note that the output buffer had better be big enough:
* rect_to_string: RECT_LENGTH
* region_to_string: (RECT_LENGTH+strlen(separator_string)) *
* g_list_length (region)
* edge_to_string: EDGE_LENGTH
* edge_list_to_...: (EDGE_LENGTH+strlen(separator_string)) *
* g_list_length (edge_list)
*/
#define RECT_LENGTH 27
#define EDGE_LENGTH 37
char* meta_rectangle_to_string (const MetaRectangle *rect,
char *output);
char* meta_rectangle_region_to_string (GList *region,
const char *separator_string,
char *output);
char* meta_rectangle_edge_to_string (const MetaEdge *edge,
char *output);
char* meta_rectangle_edge_list_to_string (
GList *edge_list,
const char *separator_string,
char *output);
/* Function to make initializing a rect with a single line of code easy */
MetaRectangle meta_rect (int x, int y, int width, int height);
/* Basic comparison functions */
int meta_rectangle_area (const MetaRectangle *rect);
gboolean meta_rectangle_intersect (const MetaRectangle *src1,
const MetaRectangle *src2,
MetaRectangle *dest);
gboolean meta_rectangle_equal (const MetaRectangle *src1,
const MetaRectangle *src2);
/* overlap is similar to intersect but doesn't provide location of
* intersection information.
*/
gboolean meta_rectangle_overlap (const MetaRectangle *rect1,
const MetaRectangle *rect2);
/* vert_overlap means ignore the horizontal location and ask if the
* vertical parts overlap. An alternate way to think of it is "Does there
* exist a way to shift either rect horizontally so that the two rects
* overlap?" horiz_overlap is similar.
*/
gboolean meta_rectangle_vert_overlap (const MetaRectangle *rect1,
const MetaRectangle *rect2);
gboolean meta_rectangle_horiz_overlap (const MetaRectangle *rect1,
const MetaRectangle *rect2);
/* could_fit_rect determines whether "outer_rect" is big enough to contain
* inner_rect. contains_rect checks whether it actually contains it.
*/
gboolean meta_rectangle_could_fit_rect (const MetaRectangle *outer_rect,
const MetaRectangle *inner_rect);
gboolean meta_rectangle_contains_rect (const MetaRectangle *outer_rect,
const MetaRectangle *inner_rect);
/* Resize old_rect to the given new_width and new_height, but store the
* result in rect. NOTE THAT THIS IS RESIZE ONLY SO IT CANNOT BE USED FOR
* A MOVERESIZE OPERATION (that simplies the routine a little bit as it
* means there's no difference between NorthWestGravity and StaticGravity.
* Also, I lied a little bit--technically, you could use it in a MoveResize
* operation if you muck with old_rect just right).
*/
void meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect,
MetaRectangle *rect,
int gravity,
int new_width,
int new_height);
/* find a list of rectangles with the property that a window is contained
* in the given region if and only if it is contained in one of the
* rectangles in the list.
*
* In this case, the region is given by taking basic_rect, removing from
* it the intersections with all the rectangles in the all_struts list,
* then expanding all the rectangles in the resulting list by the given
* amounts on each side.
*
* See boxes.c for more details.
*/
GList* meta_rectangle_get_minimal_spanning_set_for_region (
const MetaRectangle *basic_rect,
const GSList *all_struts);
GList* meta_rectangle_expand_region (GList *region,
const int left_expand,
const int right_expand,
const int top_expand,
const int bottom_expand);
/* Free the list created by
* meta_rectangle_get_minimal_spanning_set_for_region()
* or
* meta_rectangle_find_onscreen_edges ()
* or
* meta_rectangle_find_nonintersected_xinerama_edges()
*/
void meta_rectangle_free_list_and_elements (GList *filled_list);
/* could_fit_in_region determines whether one of the spanning_rects is
* big enough to contain rect. contained_in_region checks whether one
* actually contains it.
*/
gboolean meta_rectangle_could_fit_in_region (
const GList *spanning_rects,
const MetaRectangle *rect);
gboolean meta_rectangle_contained_in_region (
const GList *spanning_rects,
const MetaRectangle *rect);
/* Make the rectangle small enough to fit into one of the spanning_rects,
* but make it no smaller than min_size.
*/
void meta_rectangle_clamp_to_fit_into_region (
const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect,
const MetaRectangle *min_size);
/* Clip the rectangle so that it fits into one of the spanning_rects, assuming
* it overlaps with at least one of them
*/
void meta_rectangle_clip_to_region (const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect);
/* Shove the rectangle into one of the spanning_rects, assuming it fits in
* one of them.
*/
void meta_rectangle_shove_into_region(
const GList *spanning_rects,
FixedDirections fixed_directions,
MetaRectangle *rect);
/* Finds the point on the line connecting (x1,y1) to (x2,y2) which is closest
* to (px, py). Useful for finding an optimal rectangle size when given a
* range between two sizes that are all candidates.
*/
void meta_rectangle_find_linepoint_closest_to_point (double x1, double y1,
double x2, double y2,
double px, double py,
double *valx, double *valy);
/***************************************************************************/
/* */
/* Switching gears to code for edges instead of just rectangles */
/* */
/***************************************************************************/
/* Compare two edges, so that sorting functions can put a list of edges in
* canonical order.
*/
gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b);
/* Removes an parts of edges in the given list that intersect any box in the
* given rectangle list. Returns the result.
*/
GList* meta_rectangle_remove_intersections_with_boxes_from_edges (
GList *edges,
const GSList *rectangles);
/* Finds all the edges of an onscreen region, returning a GList* of
* MetaEdgeRect's.
*/
GList* meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
const GSList *all_struts);
/* Finds edges between adjacent xineramas which are not covered by the given
* struts.
*/
GList* meta_rectangle_find_nonintersected_xinerama_edges (
const GList *xinerama_rects,
const GSList *all_struts);
#endif /* META_BOXES_H */

View File

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -64,7 +65,8 @@ typedef enum
META_MENU_OP_MOVE_LEFT = 1 << 13, META_MENU_OP_MOVE_LEFT = 1 << 13,
META_MENU_OP_MOVE_RIGHT = 1 << 14, META_MENU_OP_MOVE_RIGHT = 1 << 14,
META_MENU_OP_MOVE_UP = 1 << 15, META_MENU_OP_MOVE_UP = 1 << 15,
META_MENU_OP_MOVE_DOWN = 1 << 16 META_MENU_OP_MOVE_DOWN = 1 << 16,
META_MENU_OP_RECOVER = 1 << 17
} MetaMenuOp; } MetaMenuOp;
typedef struct _MetaWindowMenu MetaWindowMenu; typedef struct _MetaWindowMenu MetaWindowMenu;
@ -184,6 +186,22 @@ typedef enum
META_VIRTUAL_MOD5_MASK = 1 << 14 META_VIRTUAL_MOD5_MASK = 1 << 14
} MetaVirtualModifier; } MetaVirtualModifier;
/* Relative directions or sides seem to come up all over the place... */
/* FIXME: Replace
* place.[ch]:MetaWindowEdgePosition,
* screen.[ch]:MetaScreenDirection,
* workspace.[ch]:MetaMotionDirection,
* with the use of MetaDirection.
*/
typedef enum
{
META_DIRECTION_LEFT = 1 << 0,
META_DIRECTION_RIGHT = 1 << 1,
META_DIRECTION_TOP = 1 << 2,
META_DIRECTION_BOTTOM = 1 << 3,
META_DIRECTION_UP = 1 << 2, /* Alternate name for TOP */
META_DIRECTION_DOWN = 1 << 3 /* Alternate name for BOTTOM */
} MetaDirection;
/* Function a window button can have. Note, you can't add stuff here /* Function a window button can have. Note, you can't add stuff here
* without extending the theme format to draw a new function and * without extending the theme format to draw a new function and
@ -226,7 +244,3 @@ struct _MetaButtonLayout
(ycoord) < ((rect).y + (rect).height)) (ycoord) < ((rect).y + (rect).height))
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2002 Red Hat, Inc. * Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -28,32 +29,18 @@
typedef enum typedef enum
{ {
META_RESIZE_LEFT_OR_TOP, META_IS_CONFIGURE_REQUEST = 1 << 0,
META_RESIZE_CENTER, META_DO_GRAVITY_ADJUST = 1 << 1,
META_RESIZE_RIGHT_OR_BOTTOM META_IS_USER_ACTION = 1 << 2,
} MetaResizeDirection; META_IS_MOVE_ACTION = 1 << 3,
META_IS_RESIZE_ACTION = 1 << 4
} MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window, void meta_window_constrain (MetaWindow *window,
MetaFrameGeometry *fgeom, MetaFrameGeometry *orig_fgeom,
MetaMoveResizeFlags flags,
int resize_gravity,
const MetaRectangle *orig, 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); MetaRectangle *new);
MetaResizeDirection meta_x_direction_from_gravity (int gravity);
MetaResizeDirection meta_y_direction_from_gravity (int gravity);
#endif /* META_CONSTRAINTS_H */ #endif /* META_CONSTRAINTS_H */

View File

@ -3,7 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Rob Adams * Copyright (C) 2003 Rob Adams
* Copyright (C) 2004 Elijah Newren * Copyright (C) 2004, 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -48,6 +48,23 @@ meta_core_get_client_size (Display *xdisplay,
*height = window->rect.height; *height = window->rect.height;
} }
gboolean
meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, frame_xwindow);
if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
return meta_window_titlebar_is_onscreen (window);
}
Window Window
meta_core_get_client_xwindow (Display *xdisplay, meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow) Window frame_xwindow)
@ -371,7 +388,8 @@ meta_core_maximize (Display *xdisplay,
if (window == NULL || window->frame == NULL) if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
meta_window_maximize (window); meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
} }
void void
@ -387,10 +405,12 @@ meta_core_toggle_maximize (Display *xdisplay,
if (window == NULL || window->frame == NULL) if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
if (window->maximized) if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window); meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
else else
meta_window_maximize (window); meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
} }
void void
@ -406,7 +426,8 @@ meta_core_unmaximize (Display *xdisplay,
if (window == NULL || window->frame == NULL) if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
meta_window_unmaximize (window); meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
} }
void void
@ -691,6 +712,9 @@ meta_core_get_menu_accelerator (MetaMenuOp menu_op,
case META_MENU_OP_MOVE_DOWN: case META_MENU_OP_MOVE_DOWN:
name = META_KEYBINDING_MOVE_WORKSPACE_DOWN; name = META_KEYBINDING_MOVE_WORKSPACE_DOWN;
break; break;
case META_MENU_OP_RECOVER:
/* No keybinding for this one */
break;
} }
if (name) if (name)
@ -852,9 +876,9 @@ meta_core_get_screen_size (Display *xdisplay,
meta_bug ("No such frame window 0x%lx!\n", frame_on_screen); meta_bug ("No such frame window 0x%lx!\n", frame_on_screen);
if (width) if (width)
*width = window->screen->width; *width = window->screen->rect.width;
if (height) if (height)
*height = window->screen->height; *height = window->screen->rect.height;
} }
void void

View File

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -31,6 +32,9 @@ void meta_core_get_client_size (Display *xdisplay,
int *width, int *width,
int *height); int *height);
gboolean meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow);
Window meta_core_get_client_xwindow (Display *xdisplay, Window meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);

View File

@ -519,6 +519,8 @@ meta_display_open (const char *name)
display->grab_screen = NULL; display->grab_screen = NULL;
display->grab_resize_popup = NULL; display->grab_resize_popup = NULL;
display->grab_edge_resistance_data = NULL;
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
{ {
int major, minor; int major, minor;
@ -1336,6 +1338,15 @@ handle_net_moveresize_window (MetaDisplay* display,
if (window) if (window)
{ {
/* FIXME!!!! I'm pretty sure this is wrong except _maybe_ for the
* resize-only case; see comment at beginning of
* meta_window_move_resize_internal(). Basically, this should act
* like a configure request--meaning that it should count as an app
* specified change instead of a user one, and the position needs to
* be fixed up with adjust_for_gravity(). In particular,
* meta_window_resize_with_gravity(), meta_window_resize(), and
* meta_window_move_resize() should probably NOT be called.
*/
meta_window_get_gravity_position (window, &x, &y); meta_window_get_gravity_position (window, &x, &y);
width = window->rect.width; width = window->rect.width;
height = window->rect.height; height = window->rect.height;
@ -1391,10 +1402,14 @@ handle_net_restack_window (MetaDisplay* display,
if (window) if (window)
{ {
/* /* FIXME: The EWMH includes a sibling for the restack request, but we
* The EWMH includes a sibling for the restack request, but we * (stupidly) don't currently support these types of raises.
* don't currently support these types of raises.
* *
* Also, unconditionally following these is REALLY stupid--we should
* combine this code with the stuff in
* meta_window_configure_request() which is smart about whether to
* follow the request or do something else (though not smart enough
* and is also too stupid to handle the sibling stuff).
*/ */
switch (event->xclient.data.l[2]) switch (event->xclient.data.l[2])
{ {
@ -1670,36 +1685,49 @@ event_callback (XEvent *event,
{ {
if (window->has_resize_func) if (window->has_resize_func)
{ {
gboolean north; gboolean north, south;
gboolean west; gboolean west, east;
int root_x, root_y; int root_x, root_y;
MetaGrabOp op; MetaGrabOp op;
meta_window_get_position (window, &root_x, &root_y); meta_window_get_position (window, &root_x, &root_y);
west = event->xbutton.x_root < (root_x + window->rect.width / 2); west = event->xbutton.x_root < (root_x + 1 * window->rect.width / 3);
north = event->xbutton.y_root < (root_y + window->rect.height / 2); east = event->xbutton.x_root > (root_x + 2 * window->rect.width / 3);
north = event->xbutton.y_root < (root_y + 1 * window->rect.height / 3);
south = event->xbutton.y_root > (root_y + 2 * window->rect.height / 3);
if (west && north) if (north && west)
op = META_GRAB_OP_RESIZING_NW; op = META_GRAB_OP_RESIZING_NW;
else if (west) else if (north && east)
op = META_GRAB_OP_RESIZING_SW;
else if (north)
op = META_GRAB_OP_RESIZING_NE; op = META_GRAB_OP_RESIZING_NE;
else else if (south && west)
op = META_GRAB_OP_RESIZING_SW;
else if (south && east)
op = META_GRAB_OP_RESIZING_SE; op = META_GRAB_OP_RESIZING_SE;
else if (north)
op = META_GRAB_OP_RESIZING_N;
else if (west)
op = META_GRAB_OP_RESIZING_W;
else if (east)
op = META_GRAB_OP_RESIZING_E;
else if (south)
op = META_GRAB_OP_RESIZING_S;
else /* Middle region is no-op to avoid user triggering wrong action */
op = META_GRAB_OP_NONE;
meta_display_begin_grab_op (display, if (op != META_GRAB_OP_NONE)
window->screen, meta_display_begin_grab_op (display,
window, window->screen,
op, window,
TRUE, op,
event->xbutton.serial, TRUE,
event->xbutton.button, event->xbutton.serial,
0, event->xbutton.button,
event->xbutton.time, 0,
event->xbutton.x_root, event->xbutton.time,
event->xbutton.y_root); event->xbutton.x_root,
event->xbutton.y_root);
} }
} }
else if (event->xbutton.button == 3) else if (event->xbutton.button == 3)
@ -3244,6 +3272,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_old_window_stacking = NULL; display->grab_old_window_stacking = NULL;
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
display->grab_sync_request_alarm = None; display->grab_sync_request_alarm = None;
display->grab_last_user_action_was_snap = FALSE;
#endif #endif
display->grab_was_cancelled = FALSE; display->grab_was_cancelled = FALSE;
@ -3335,6 +3364,18 @@ meta_display_begin_grab_op (MetaDisplay *display,
g_assert (display->grab_window != NULL || display->grab_screen != NULL); g_assert (display->grab_window != NULL || display->grab_screen != NULL);
g_assert (display->grab_op != META_GRAB_OP_NONE); g_assert (display->grab_op != META_GRAB_OP_NONE);
/* If this is a move or resize, cache the window edges for
* resistance/snapping
*/
if (meta_grab_op_is_resizing (display->grab_op) ||
meta_grab_op_is_moving (display->grab_op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Computing edges to resist-movement or snap-to for %s.\n",
window->desc);
meta_display_compute_resistance_and_snapping_edges (display);
}
/* Save the old stacking */ /* Save the old stacking */
if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op)) if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
{ {
@ -3408,6 +3449,15 @@ meta_display_end_grab_op (MetaDisplay *display,
display->ungrab_should_not_cause_focus_window = display->grab_xwindow; display->ungrab_should_not_cause_focus_window = display->grab_xwindow;
} }
/* If this was a move or resize clear out the edge cache */
if (meta_grab_op_is_resizing (display->grab_op) ||
meta_grab_op_is_moving (display->grab_op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Clearing out the edges for resistance/snapping");
meta_display_cleanup_edges (display);
}
if (display->grab_old_window_stacking != NULL) if (display->grab_old_window_stacking != NULL)
{ {
meta_topic (META_DEBUG_WINDOW_OPS, meta_topic (META_DEBUG_WINDOW_OPS,
@ -4276,53 +4326,6 @@ meta_resize_gravity_from_grab_op (MetaGrabOp op)
return gravity; return gravity;
} }
gboolean
meta_rectangle_intersect (MetaRectangle *src1,
MetaRectangle *src2,
MetaRectangle *dest)
{
int dest_x, dest_y;
int dest_w, dest_h;
int return_val;
g_return_val_if_fail (src1 != NULL, FALSE);
g_return_val_if_fail (src2 != NULL, FALSE);
g_return_val_if_fail (dest != NULL, FALSE);
return_val = FALSE;
dest_x = MAX (src1->x, src2->x);
dest_y = MAX (src1->y, src2->y);
dest_w = MIN (src1->x + src1->width, src2->x + src2->width) - dest_x;
dest_h = MIN (src1->y + src1->height, src2->y + src2->height) - dest_y;
if (dest_w > 0 && dest_h > 0)
{
dest->x = dest_x;
dest->y = dest_y;
dest->width = dest_w;
dest->height = dest_h;
return_val = TRUE;
}
else
{
dest->width = 0;
dest->height = 0;
}
return return_val;
}
gboolean
meta_rectangle_equal (const MetaRectangle *src1,
const MetaRectangle *src2)
{
return ((src1->x == src2->x) &&
(src1->y == src2->y) &&
(src1->width == src2->width) &&
(src1->height == src2->height));
}
static MetaScreen* static MetaScreen*
find_screen_for_selection (MetaDisplay *display, find_screen_for_selection (MetaDisplay *display,
Window owner, Window owner,

View File

@ -33,6 +33,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include "eventqueue.h" #include "eventqueue.h"
#include "common.h" #include "common.h"
#include "boxes.h"
#ifdef HAVE_STARTUP_NOTIFICATION #ifdef HAVE_STARTUP_NOTIFICATION
#include <libsn/sn.h> #include <libsn/sn.h>
@ -44,17 +45,6 @@
#define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0) #define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0)
/* this doesn't really belong here, oh well. */
typedef struct _MetaRectangle MetaRectangle;
struct _MetaRectangle
{
int x;
int y;
int width;
int height;
};
typedef struct MetaCompositor MetaCompositor; typedef struct MetaCompositor MetaCompositor;
typedef struct _MetaDisplay MetaDisplay; typedef struct _MetaDisplay MetaDisplay;
typedef struct _MetaFrame MetaFrame; typedef struct _MetaFrame MetaFrame;
@ -68,6 +58,8 @@ typedef struct _MetaWorkspace MetaWorkspace;
typedef struct _MetaWindowPropHooks MetaWindowPropHooks; typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
typedef struct _MetaGroupPropHooks MetaGroupPropHooks; typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef void (* MetaWindowPingFunc) (MetaDisplay *display, typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
Window xwindow, Window xwindow,
Time timestamp, Time timestamp,
@ -280,6 +272,7 @@ struct _MetaDisplay
int grab_wireframe_last_display_width; int grab_wireframe_last_display_width;
int grab_wireframe_last_display_height; int grab_wireframe_last_display_height;
GList* grab_old_window_stacking; GList* grab_old_window_stacking;
MetaEdgeResistanceData *grab_edge_resistance_data;
/* we use property updates as sentinels for certain window focus events /* we use property updates as sentinels for certain window focus events
* to avoid some race conditions on EnterNotify events * to avoid some race conditions on EnterNotify events
@ -350,6 +343,7 @@ struct _MetaDisplay
int render_error_base; int render_error_base;
#endif #endif
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
unsigned int grab_last_user_action_was_snap;
unsigned int have_xsync : 1; unsigned int have_xsync : 1;
#define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync) #define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync)
#else #else
@ -459,6 +453,10 @@ void meta_display_grab_focus_window_button (MetaDisplay *display,
void meta_display_ungrab_focus_window_button (MetaDisplay *display, void meta_display_ungrab_focus_window_button (MetaDisplay *display,
MetaWindow *window); MetaWindow *window);
/* Next two functions are defined in edge-resistance.c */
void meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display);
void meta_display_cleanup_edges (MetaDisplay *display);
/* make a request to ensure the event serial has changed */ /* make a request to ensure the event serial has changed */
void meta_display_increment_event_serial (MetaDisplay *display); void meta_display_increment_event_serial (MetaDisplay *display);
@ -490,8 +488,6 @@ typedef enum
{ {
META_TAB_LIST_NORMAL, META_TAB_LIST_NORMAL,
META_TAB_LIST_DOCKS META_TAB_LIST_DOCKS
} MetaTabList; } MetaTabList;
GList* meta_display_get_tab_list (MetaDisplay *display, GList* meta_display_get_tab_list (MetaDisplay *display,
@ -516,12 +512,6 @@ int meta_resize_gravity_from_grab_op (MetaGrabOp op);
gboolean meta_grab_op_is_moving (MetaGrabOp op); gboolean meta_grab_op_is_moving (MetaGrabOp op);
gboolean meta_grab_op_is_resizing (MetaGrabOp op); gboolean meta_grab_op_is_resizing (MetaGrabOp op);
gboolean meta_rectangle_intersect (MetaRectangle *src1,
MetaRectangle *src2,
MetaRectangle *dest);
gboolean meta_rectangle_equal (const MetaRectangle *src1,
const MetaRectangle *src2);
void meta_display_devirtualize_modifiers (MetaDisplay *display, void meta_display_devirtualize_modifiers (MetaDisplay *display,
MetaVirtualModifier modifiers, MetaVirtualModifier modifiers,
unsigned int *mask); unsigned int *mask);

1278
src/edge-resistance.c Normal file

File diff suppressed because it is too large Load Diff

46
src/edge-resistance.h Normal file
View File

@ -0,0 +1,46 @@
/* Edge resistance for move/resize operations */
/*
* Copyright (C) 2005 Elijah Newren
*
* 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
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* 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.
*/
#ifndef META_EDGE_RESISTANCE_H
#define META_EDGE_RESISTANCE_H
#include "window.h"
void meta_window_edge_resistance_for_move (MetaWindow *window,
int old_x,
int old_y,
int *new_x,
int *new_y,
GSourceFunc timeout_func,
gboolean snap,
gboolean is_keyboard_op);
void meta_window_edge_resistance_for_resize (MetaWindow *window,
int old_width,
int old_height,
int *new_width,
int *new_height,
int gravity,
GSourceFunc timeout_func,
gboolean snap,
gboolean is_keyboard_op);
#endif /* META_EDGE_RESISTANCE_H */

View File

@ -3,6 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003, 2004 Red Hat, Inc. * Copyright (C) 2003, 2004 Red Hat, Inc.
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -264,7 +265,10 @@ meta_frame_get_flags (MetaFrame *frame)
if (frame->window->on_all_workspaces) if (frame->window->on_all_workspaces)
flags |= META_FRAME_STUCK; flags |= META_FRAME_STUCK;
if (frame->window->maximized) /* FIXME: Should we have some kind of UI for windows that are just vertically
* maximized or just horizontally maximized?
*/
if (META_WINDOW_MAXIMIZED (frame->window))
flags |= META_FRAME_MAXIMIZED; flags |= META_FRAME_MAXIMIZED;
if (frame->window->fullscreen) if (frame->window->fullscreen)

View File

@ -3,6 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -1441,16 +1442,25 @@ meta_frames_button_press_event (GtkWidget *widget,
break; break;
} }
meta_core_begin_grab_op (gdk_display, if (!meta_core_titlebar_is_onscreen (gdk_display,
frame->xwindow, frame->xwindow))
op, meta_core_show_window_menu (gdk_display,
TRUE, frame->xwindow,
meta_ui_get_last_event_serial (gdk_display), event->x_root,
event->button, event->y_root,
0, event->button,
event->time, event->time);
event->x_root, else
event->y_root); meta_core_begin_grab_op (gdk_display,
frame->xwindow,
op,
TRUE,
meta_ui_get_last_event_serial (gdk_display),
event->button,
0,
event->time,
event->x_root,
event->y_root);
} }
else if (control == META_FRAME_CONTROL_TITLE && else if (control == META_FRAME_CONTROL_TITLE &&
event->button == 1) event->button == 1)

View File

@ -26,6 +26,7 @@
#include "keybindings.h" #include "keybindings.h"
#include "workspace.h" #include "workspace.h"
#include "errors.h" #include "errors.h"
#include "edge-resistance.h"
#include "ui.h" #include "ui.h"
#include "frame.h" #include "frame.h"
#include "place.h" #include "place.h"
@ -1690,8 +1691,6 @@ process_keyboard_move_grab (MetaDisplay *display,
int x, y; int x, y;
int incr; int incr;
gboolean smart_snap; gboolean smart_snap;
int edge;
int candidate_position;
handled = FALSE; handled = FALSE;
@ -1719,7 +1718,7 @@ process_keyboard_move_grab (MetaDisplay *display,
#define NORMAL_INCREMENT 10 #define NORMAL_INCREMENT 10
if (smart_snap) if (smart_snap)
incr = 0; incr = 1;
else if (event->xkey.state & ControlMask) else if (event->xkey.state & ControlMask)
incr = SMALL_INCREMENT; incr = SMALL_INCREMENT;
else else
@ -1754,18 +1753,6 @@ process_keyboard_move_grab (MetaDisplay *display,
case XK_Up: case XK_Up:
case XK_KP_Up: case XK_KP_Up:
y -= incr; y -= incr;
edge = meta_window_find_next_horizontal_edge (window,
META_WINDOW_EDGE_TOP,
FALSE);
if (window->frame)
candidate_position = edge + window->frame->child_y;
else
candidate_position = edge;
if (smart_snap || ((candidate_position > y) && ABS (candidate_position - y) < incr))
y = candidate_position;
handled = TRUE; handled = TRUE;
break; break;
case XK_KP_End: case XK_KP_End:
@ -1773,18 +1760,6 @@ process_keyboard_move_grab (MetaDisplay *display,
case XK_Down: case XK_Down:
case XK_KP_Down: case XK_KP_Down:
y += incr; y += incr;
edge = meta_window_find_next_horizontal_edge (window,
META_WINDOW_EDGE_BOTTOM,
TRUE);
if (window->frame)
candidate_position = edge - window->frame->bottom_height - window->rect.height;
else
candidate_position = edge - window->rect.height;
if (smart_snap || ((candidate_position < y) && ABS (candidate_position - y) < incr))
y = candidate_position;
handled = TRUE; handled = TRUE;
break; break;
} }
@ -1796,19 +1771,6 @@ process_keyboard_move_grab (MetaDisplay *display,
case XK_Left: case XK_Left:
case XK_KP_Left: case XK_KP_Left:
x -= incr; x -= incr;
edge = meta_window_find_next_vertical_edge (window,
META_WINDOW_EDGE_LEFT,
FALSE);
if (window->frame)
candidate_position = edge + window->frame->child_x;
else
candidate_position = edge;
if (smart_snap ||
((candidate_position > x) && ABS (candidate_position - x) < incr))
x = candidate_position;
handled = TRUE; handled = TRUE;
break; break;
case XK_KP_Prior: case XK_KP_Prior:
@ -1816,27 +1778,34 @@ process_keyboard_move_grab (MetaDisplay *display,
case XK_Right: case XK_Right:
case XK_KP_Right: case XK_KP_Right:
x += incr; x += incr;
edge = meta_window_find_next_vertical_edge (window,
META_WINDOW_EDGE_RIGHT,
TRUE);
if (window->frame)
candidate_position = edge - window->frame->right_width - window->rect.width;
else
candidate_position = edge - window->rect.width;
if (smart_snap || ((candidate_position < x) && ABS (candidate_position - x) < incr))
x = candidate_position;
handled = TRUE; handled = TRUE;
break; break;
} }
if (handled) if (handled)
{ {
MetaRectangle old_rect;
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
"Computed new window location %d,%d due to keypress\n", "Computed new window location %d,%d due to keypress\n",
x, y); x, y);
if (display->grab_wireframe_active)
old_rect = display->grab_wireframe_rect;
else
{
old_rect = window->rect;
meta_window_get_position (window, &old_rect.x, &old_rect.y);
}
meta_window_edge_resistance_for_move (window,
old_rect.x,
old_rect.y,
&x,
&y,
NULL,
smart_snap,
TRUE);
if (display->grab_wireframe_active) if (display->grab_wireframe_active)
{ {
meta_window_update_wireframe (window, x, y, meta_window_update_wireframe (window, x, y,
@ -1986,13 +1955,9 @@ process_keyboard_resize_grab (MetaDisplay *display,
gboolean handled; gboolean handled;
int height_inc; int height_inc;
int width_inc; int width_inc;
int x, y;
int orig_x, orig_y;
int width, height; int width, height;
gboolean smart_snap; gboolean smart_snap;
int edge;
int gravity; int gravity;
int candidate_position;
handled = FALSE; handled = FALSE;
@ -2029,21 +1994,15 @@ process_keyboard_resize_grab (MetaDisplay *display,
if (display->grab_wireframe_active) if (display->grab_wireframe_active)
{ {
orig_x = display->grab_wireframe_rect.x;
orig_y = display->grab_wireframe_rect.y;
width = display->grab_wireframe_rect.width; width = display->grab_wireframe_rect.width;
height = display->grab_wireframe_rect.height; height = display->grab_wireframe_rect.height;
} }
else else
{ {
meta_window_get_position (window, &orig_x, &orig_y);
width = window->rect.width; width = window->rect.width;
height = window->rect.height; height = window->rect.height;
} }
x = orig_x;
y = orig_y;
gravity = meta_resize_gravity_from_grab_op (display->grab_op); gravity = meta_resize_gravity_from_grab_op (display->grab_op);
smart_snap = (event->xkey.state & ShiftMask) != 0; smart_snap = (event->xkey.state & ShiftMask) != 0;
@ -2053,40 +2012,28 @@ process_keyboard_resize_grab (MetaDisplay *display,
if (smart_snap) if (smart_snap)
{ {
height_inc = 0; height_inc = 1;
width_inc = 0; width_inc = 1;
} }
else if (event->xkey.state & ControlMask) else if (event->xkey.state & ControlMask)
{ {
if (window->size_hints.width_inc > 1) width_inc = SMALL_INCREMENT;
width_inc = window->size_hints.width_inc; height_inc = SMALL_INCREMENT;
else
width_inc = SMALL_INCREMENT;
if (window->size_hints.height_inc > 1)
height_inc = window->size_hints.height_inc;
else
height_inc = SMALL_INCREMENT;
} }
else else
{ {
if (window->size_hints.width_inc > 1) width_inc = NORMAL_INCREMENT;
width_inc = window->size_hints.width_inc; height_inc = NORMAL_INCREMENT;
else
width_inc = NORMAL_INCREMENT;
if (window->size_hints.height_inc > 1)
height_inc = window->size_hints.height_inc;
else
height_inc = NORMAL_INCREMENT;
} }
/* When moving by increments, we still snap to edges if the move /* If this is a resize increment window, make the amount we resize
* to the edge is smaller than the increment. This is because * the window by match that amount (well, unless snap resizing...)
* Shift + arrow to snap is sort of a hidden feature. This way
* people using just arrows shouldn't get too frustrated.
*/ */
if (window->size_hints.width_inc > 1)
width_inc = window->size_hints.width_inc;
if (window->size_hints.height_inc > 1)
height_inc = window->size_hints.height_inc;
switch (keysym) switch (keysym)
{ {
case XK_Up: case XK_Up:
@ -2097,49 +2044,14 @@ process_keyboard_resize_grab (MetaDisplay *display,
case NorthWestGravity: case NorthWestGravity:
case NorthEastGravity: case NorthEastGravity:
/* Move bottom edge up */ /* Move bottom edge up */
edge = meta_window_find_next_horizontal_edge (window, height -= height_inc;
META_WINDOW_EDGE_BOTTOM,
FALSE);
if (window->frame)
candidate_position = edge - window->frame->bottom_height;
else
candidate_position = edge;
if (smart_snap ||
((candidate_position > (y + (height - height_inc))) &&
ABS (candidate_position - (y + (height - height_inc))) < height_inc))
{
if (candidate_position - y > 0)
height = candidate_position - y;
}
else if (height - height_inc > 0)
{
height -= height_inc;
}
handled = TRUE;
break; break;
case SouthGravity: case SouthGravity:
case SouthWestGravity: case SouthWestGravity:
case SouthEastGravity: case SouthEastGravity:
/* Move top edge up */ /* Move top edge up */
y -= height_inc; height += height_inc;
edge = meta_window_find_next_horizontal_edge (window,
META_WINDOW_EDGE_TOP,
FALSE);
if (window->frame)
candidate_position = edge + window->frame->child_y;
else
candidate_position = edge;
if (smart_snap || ((candidate_position > y) && ABS (candidate_position - y) < height_inc))
y = candidate_position;
height += (orig_y - y);
break; break;
case EastGravity: case EastGravity:
@ -2161,49 +2073,13 @@ process_keyboard_resize_grab (MetaDisplay *display,
case NorthEastGravity: case NorthEastGravity:
/* Move bottom edge down */ /* Move bottom edge down */
height += height_inc; height += height_inc;
edge = meta_window_find_next_horizontal_edge (window,
META_WINDOW_EDGE_BOTTOM,
TRUE);
if (window->frame)
candidate_position = edge - window->frame->bottom_height;
else
candidate_position = edge;
if (smart_snap || ((candidate_position < (y+height)) &&
ABS (candidate_position - (y+height)) < height_inc))
height = candidate_position - y;
break; break;
case SouthGravity: case SouthGravity:
case SouthWestGravity: case SouthWestGravity:
case SouthEastGravity: case SouthEastGravity:
/* Move top edge down */ /* Move top edge down */
edge = meta_window_find_next_horizontal_edge (window, height -= height_inc;
META_WINDOW_EDGE_TOP,
TRUE);
if (window->frame)
candidate_position = edge + window->frame->child_y;
else
candidate_position = edge;
if (smart_snap ||
((candidate_position < (y + height_inc)) &&
ABS (candidate_position - (y + height_inc)) < height_inc))
{
if (height - (candidate_position - orig_y) > 0)
{
y = candidate_position;
height -= (y - orig_y);
}
}
else if (height - ((y + height_inc) - orig_y) > 0)
{
y += height_inc;
height -= (y - orig_y);
}
break; break;
case EastGravity: case EastGravity:
@ -2223,50 +2099,15 @@ process_keyboard_resize_grab (MetaDisplay *display,
case EastGravity: case EastGravity:
case SouthEastGravity: case SouthEastGravity:
case NorthEastGravity: case NorthEastGravity:
x -= width_inc;
/* Move left edge left */ /* Move left edge left */
edge = meta_window_find_next_vertical_edge (window, width += width_inc;
META_WINDOW_EDGE_LEFT,
FALSE);
if (window->frame)
candidate_position = edge + window->frame->child_x;
else
candidate_position = edge;
if (smart_snap || ((candidate_position > x) && ABS (candidate_position - x) < width_inc))
x = candidate_position;
width += (orig_x - x);
break; break;
case WestGravity: case WestGravity:
case SouthWestGravity: case SouthWestGravity:
case NorthWestGravity: case NorthWestGravity:
/* Move right edge left */ /* Move right edge left */
edge = meta_window_find_next_vertical_edge (window, width -= width_inc;
META_WINDOW_EDGE_RIGHT,
FALSE);
if (window->frame)
candidate_position = edge - window->frame->right_width;
else
candidate_position = edge;
if (smart_snap ||
((candidate_position > (x + (width - width_inc))) &&
ABS (candidate_position - (x + (width - width_inc))) < width_inc))
{
if (candidate_position - x > 0)
width = candidate_position - x;
}
else if (width - width_inc > 0)
{
width -= width_inc;
}
handled = TRUE;
break; break;
case NorthGravity: case NorthGravity:
@ -2287,30 +2128,7 @@ process_keyboard_resize_grab (MetaDisplay *display,
case SouthEastGravity: case SouthEastGravity:
case NorthEastGravity: case NorthEastGravity:
/* Move left edge right */ /* Move left edge right */
edge = meta_window_find_next_vertical_edge (window, width -= width_inc;
META_WINDOW_EDGE_LEFT,
TRUE);
if (window->frame)
candidate_position = edge + window->frame->child_x;
else
candidate_position = edge;
if (smart_snap ||
((candidate_position < (x + width_inc)) &&
ABS (candidate_position - (x + width_inc)) < width_inc))
{
if (width - (candidate_position - orig_x) > 0)
{
x = candidate_position;
width -= (x - orig_x);
}
}
else if (width - ((x + width_inc) - orig_x) > 0)
{
x += width_inc;
width -= (x - orig_x);
}
break; break;
case WestGravity: case WestGravity:
@ -2318,21 +2136,6 @@ process_keyboard_resize_grab (MetaDisplay *display,
case NorthWestGravity: case NorthWestGravity:
/* Move right edge right */ /* Move right edge right */
width += width_inc; width += width_inc;
edge = meta_window_find_next_vertical_edge (window,
META_WINDOW_EDGE_RIGHT,
TRUE);
if (window->frame)
candidate_position = edge - window->frame->right_width;
else
candidate_position = edge;
if (smart_snap || ((candidate_position > (x+width)) &&
ABS (candidate_position - (x+width)) < width_inc))
width = candidate_position - x;
handled = TRUE;
break; break;
case NorthGravity: case NorthGravity:
@ -2357,17 +2160,53 @@ process_keyboard_resize_grab (MetaDisplay *display,
if (handled) if (handled)
{ {
MetaRectangle old_rect;
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
"Computed new window location %d,%d %dx%d due to keypress\n", "Computed new window size due to keypress: "
x, y, width, height); "%dx%d, gravity %s\n",
width, height, meta_gravity_to_string (gravity));
if (display->grab_wireframe_active)
old_rect = display->grab_wireframe_rect;
else
old_rect = window->rect; /* Don't actually care about x,y */
/* Do any edge resistance/snapping */
meta_window_edge_resistance_for_resize (window,
old_rect.width,
old_rect.height,
&width,
&height,
gravity,
NULL,
smart_snap,
TRUE);
if (display->grab_wireframe_active) if (display->grab_wireframe_active)
{ {
meta_window_update_wireframe (window, x, y, width, height); MetaRectangle new_position;
meta_rectangle_resize_with_gravity (&display->grab_wireframe_rect,
&new_position,
gravity,
width,
height);
meta_window_update_wireframe (window,
new_position.x,
new_position.y,
new_position.width,
new_position.height);
} }
else else
{ {
meta_window_move_resize (window, TRUE, x, y, width, height); /* We don't need to update unless the specified width and height
* are actually different from what we had before.
*/
if (window->rect.width != width || window->rect.height != height)
meta_window_resize_with_gravity (window,
TRUE,
width,
height,
gravity);
} }
meta_window_update_keyboard_resize (window, FALSE); meta_window_update_keyboard_resize (window, FALSE);
} }
@ -2782,10 +2621,12 @@ handle_maximize_vert (MetaDisplay *display,
XEvent *event, XEvent *event,
MetaKeyBinding *binding) MetaKeyBinding *binding)
{ {
if (window) if (window && window->has_resize_func)
{ {
if (window->has_resize_func) if (window->maximized_vertically)
meta_window_fill_vertical (window); meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
else
meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
} }
} }
@ -2796,10 +2637,12 @@ handle_maximize_horiz (MetaDisplay *display,
XEvent *event, XEvent *event,
MetaKeyBinding *binding) MetaKeyBinding *binding)
{ {
if (window) if (window && window->has_resize_func)
{ {
if (window->has_resize_func) if (window->maximized_horizontally)
meta_window_fill_horizontal (window); meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
else
meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
} }
} }
@ -3230,10 +3073,14 @@ handle_toggle_maximize (MetaDisplay *display,
{ {
if (window) if (window)
{ {
if (window->maximized) if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window); meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
else if (window->has_maximize_func) else if (window->has_maximize_func)
meta_window_maximize (window); meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
} }
} }
@ -3247,7 +3094,9 @@ handle_maximize (MetaDisplay *display,
if (window) if (window)
{ {
if (window->has_maximize_func) if (window->has_maximize_func)
meta_window_maximize (window); meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
} }
} }
@ -3260,8 +3109,10 @@ handle_unmaximize (MetaDisplay *display,
{ {
if (window) if (window)
{ {
if (window->maximized) if (window->maximized_vertically || window->maximized_horizontally)
meta_window_unmaximize (window); meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
} }
} }

View File

@ -3,6 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2004 Rob Adams * Copyright (C) 2004 Rob Adams
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -60,6 +61,7 @@ static MenuItem menuitems[] = {
{ META_MENU_OP_UNABOVE, NULL, TRUE, N_("On _Top") }, { META_MENU_OP_UNABOVE, NULL, TRUE, N_("On _Top") },
{ META_MENU_OP_MOVE, NULL, FALSE, N_("_Move") }, { META_MENU_OP_MOVE, NULL, FALSE, N_("_Move") },
{ META_MENU_OP_RESIZE, NULL, FALSE, N_("_Resize") }, { META_MENU_OP_RESIZE, NULL, FALSE, N_("_Resize") },
{ META_MENU_OP_RECOVER, NULL, FALSE, N_("Move Titlebar On_screen") },
{ 0, NULL, FALSE, NULL }, /* separator */ { 0, NULL, FALSE, NULL }, /* separator */
{ META_MENU_OP_DELETE, METACITY_STOCK_DELETE, FALSE, N_("_Close") }, { META_MENU_OP_DELETE, METACITY_STOCK_DELETE, FALSE, N_("_Close") },
{ META_MENU_OP_WORKSPACES, NULL, FALSE, NULL }, /* separator */ { META_MENU_OP_WORKSPACES, NULL, FALSE, NULL }, /* separator */

View File

@ -529,16 +529,6 @@ center_tile_rect_in_area (MetaRectangle *rect,
rect->y = work_area->y + fluff; rect->y = work_area->y + fluff;
} }
static gboolean
rect_fits_in_work_area (MetaRectangle *work_area,
MetaRectangle *rect)
{
return ((rect->x >= work_area->x) &&
(rect->y >= work_area->y) &&
(rect->x + rect->width <= work_area->x + work_area->width) &&
(rect->y + rect->height <= work_area->y + work_area->height));
}
/* Find the leftmost, then topmost, empty area on the workspace /* Find the leftmost, then topmost, empty area on the workspace
* that can contain the new window. * that can contain the new window.
* *
@ -597,13 +587,15 @@ find_first_fit (MetaWindow *window,
for (i = 0; i < n_xineramas; i++) for (i = 0; i < n_xineramas; i++)
{ {
#ifdef WITH_VERBOSE_MODE
char xinerama_location_string[RECT_LENGTH];
meta_rectangle_to_string (&window->screen->xinerama_infos[xineramas_list[i]].rect,
xinerama_location_string);
meta_topic (META_DEBUG_XINERAMA, meta_topic (META_DEBUG_XINERAMA,
"Natural xinerama %d is %d,%d %dx%d\n", "Natural xinerama %d is %s\n",
i, i,
window->screen->xinerama_infos[xineramas_list[i]].x_origin, xinerama_location_string);
window->screen->xinerama_infos[xineramas_list[i]].y_origin, #endif
window->screen->xinerama_infos[xineramas_list[i]].width,
window->screen->xinerama_infos[xineramas_list[i]].height);
} }
/* try each xinerama in the natural ordering in turn */ /* try each xinerama in the natural ordering in turn */
@ -614,7 +606,7 @@ find_first_fit (MetaWindow *window,
center_tile_rect_in_area (&rect, &work_area); center_tile_rect_in_area (&rect, &work_area);
if (rect_fits_in_work_area (&work_area, &rect) && if (meta_rectangle_contains_rect (&work_area, &rect) &&
!rectangle_overlaps_some_window (&rect, windows)) !rectangle_overlaps_some_window (&rect, windows))
{ {
*new_x = rect.x; *new_x = rect.x;
@ -642,7 +634,7 @@ find_first_fit (MetaWindow *window,
rect.x = outer_rect.x; rect.x = outer_rect.x;
rect.y = outer_rect.y + outer_rect.height; rect.y = outer_rect.y + outer_rect.height;
if (rect_fits_in_work_area (&work_area, &rect) && if (meta_rectangle_contains_rect (&work_area, &rect) &&
!rectangle_overlaps_some_window (&rect, below_sorted)) !rectangle_overlaps_some_window (&rect, below_sorted))
{ {
*new_x = rect.x; *new_x = rect.x;
@ -673,7 +665,7 @@ find_first_fit (MetaWindow *window,
rect.x = outer_rect.x + outer_rect.width; rect.x = outer_rect.x + outer_rect.width;
rect.y = outer_rect.y; rect.y = outer_rect.y;
if (rect_fits_in_work_area (&work_area, &rect) && if (meta_rectangle_contains_rect (&work_area, &rect) &&
!rectangle_overlaps_some_window (&rect, right_sorted)) !rectangle_overlaps_some_window (&rect, right_sorted))
{ {
*new_x = rect.x; *new_x = rect.x;
@ -817,7 +809,6 @@ meta_window_place (MetaWindow *window,
if (parent) if (parent)
{ {
int w; int w;
MetaRectangle area;
meta_window_get_position (parent, &x, &y); meta_window_get_position (parent, &x, &y);
w = parent->rect.width; w = parent->rect.width;
@ -836,6 +827,16 @@ meta_window_place (MetaWindow *window,
if (fgeom) if (fgeom)
y += fgeom->top_height; y += fgeom->top_height;
#if 0
/* FIXME: If no one has complained about this within a couple
* months, it means that the constraints.c rewrite fixed this
* correctly and this hack is no longer necessary. Feel free to
* submit a patch removing this #ifdef'd out code. (Comment
* written on 2005-10-28).
*/
MetaRectangle area;
/* clip to xinerama of parent*/ /* clip to xinerama of parent*/
meta_window_get_work_area_current_xinerama (parent, &area); meta_window_get_work_area_current_xinerama (parent, &area);
@ -845,6 +846,7 @@ meta_window_place (MetaWindow *window,
y = area.y + area.height - window->rect.height; y = area.y + area.height - window->rect.height;
if (x < area.x) x = area.x; if (x < area.x) x = area.x;
if (y < area.y) y = area.y; if (y < area.y) y = area.y;
#endif
meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n", meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n",
window->desc); window->desc);
@ -867,20 +869,20 @@ meta_window_place (MetaWindow *window,
window->type == META_WINDOW_MODAL_DIALOG || window->type == META_WINDOW_MODAL_DIALOG ||
window->type == META_WINDOW_SPLASHSCREEN) window->type == META_WINDOW_SPLASHSCREEN)
{ {
/* Center on screen */ /* Center on current xinerama (i.e. on current monitor) */
int w, h; int w, h;
/* Warning, this function is a round trip! */ /* Warning, this function is a round trip! */
xi = meta_screen_get_current_xinerama (window->screen); xi = meta_screen_get_current_xinerama (window->screen);
w = xi->width; w = xi->rect.width;
h = xi->height; h = xi->rect.height;
x = (w - window->rect.width) / 2; x = (w - window->rect.width) / 2;
y = (h - window->rect.height) / 2; y = (h - window->rect.height) / 2;
x += xi->x_origin; x += xi->rect.x;
y += xi->y_origin; y += xi->rect.y;
meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n", meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n",
window->desc, window->screen->number, xi->number); window->desc, window->screen->number, xi->number);
@ -919,8 +921,8 @@ meta_window_place (MetaWindow *window,
xi = meta_screen_get_current_xinerama (window->screen); xi = meta_screen_get_current_xinerama (window->screen);
/* "Origin" placement algorithm */ /* "Origin" placement algorithm */
x = xi->x_origin; x = xi->rect.x;
y = xi->y_origin; y = xi->rect.y;
if (find_first_fit (window, fgeom, windows, if (find_first_fit (window, fgeom, windows,
xineramas_list, n_xineramas, xineramas_list, n_xineramas,
@ -986,11 +988,11 @@ meta_window_place (MetaWindow *window,
&workarea); &workarea);
meta_window_get_outer_rect (window, &outer); meta_window_get_outer_rect (window, &outer);
if (outer.width >= workarea.width && if (outer.width >= workarea.width)
outer.height >= workarea.height) window->maximize_horizontally_after_placement = TRUE;
{
window->maximize_after_placement = TRUE; if (outer.height >= workarea.height)
} window->maximize_vertically_after_placement = TRUE;
} }
done_check_denied_focus: done_check_denied_focus:
@ -1022,8 +1024,8 @@ meta_window_place (MetaWindow *window,
focus_window_list = g_list_prepend (NULL, focus_window); focus_window_list = g_list_prepend (NULL, focus_window);
/* Reset x and y ("origin" placement algorithm) */ /* Reset x and y ("origin" placement algorithm) */
x = xi->x_origin; x = xi->rect.x;
y = xi->y_origin; y = xi->rect.y;
found_fit = find_first_fit (window, fgeom, focus_window_list, found_fit = find_first_fit (window, fgeom, focus_window_list,
xineramas_list, n_xineramas, xineramas_list, n_xineramas,
@ -1094,33 +1096,6 @@ get_windows_showing_on_same_screen (MetaWindow *window,
return windows; return windows;
} }
static gboolean
rects_overlap_vertically (const MetaRectangle *a,
const MetaRectangle *b)
{
/* if they don't overlap, then either a is above b
* or b is above a
*/
if ((a->y + a->height) < b->y)
return FALSE;
else if ((b->y + b->height) < a->y)
return FALSE;
else
return TRUE;
}
static gboolean
rects_overlap_horizontally (const MetaRectangle *a,
const MetaRectangle *b)
{
if ((a->x + a->width) < b->x)
return FALSE;
else if ((b->x + b->width) < a->x)
return FALSE;
else
return TRUE;
}
static void static void
get_vertical_edges (MetaWindow *window, get_vertical_edges (MetaWindow *window,
int **edges_p, int **edges_p,
@ -1149,13 +1124,13 @@ get_vertical_edges (MetaWindow *window,
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
edge = 0; edge = 0;
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
g_array_append_val (edges, window->screen->width); g_array_append_val (edges, window->screen->rect.width);
/* Now get the xinerama screen edges */ /* Now get the xinerama screen edges */
for (i = 0; i < window->screen->n_xinerama_infos - 1; i++) for (i = 0; i < window->screen->n_xinerama_infos - 1; i++)
{ {
edge = window->screen->xinerama_infos[i].x_origin + edge = window->screen->xinerama_infos[i].rect.x +
window->screen->xinerama_infos[i].width; window->screen->xinerama_infos[i].rect.width;
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
} }
@ -1185,7 +1160,7 @@ get_vertical_edges (MetaWindow *window,
meta_window_get_outer_rect (w, &w_rect); meta_window_get_outer_rect (w, &w_rect);
if (rects_overlap_vertically (&rect, &w_rect)) if (meta_rectangle_vert_overlap (&rect, &w_rect))
{ {
g_array_append_val (edges, w_rect.x); g_array_append_val (edges, w_rect.x);
edge = w_rect.x + w_rect.width; edge = w_rect.x + w_rect.width;
@ -1231,13 +1206,13 @@ get_horizontal_edges (MetaWindow *window,
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
edge = 0; edge = 0;
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
g_array_append_val (edges, window->screen->height); g_array_append_val (edges, window->screen->rect.height);
/* Now get the xinerama screen edges */ /* Now get the xinerama screen edges */
for (i = 0; i < window->screen->n_xinerama_infos - 1; i++) for (i = 0; i < window->screen->n_xinerama_infos - 1; i++)
{ {
edge = window->screen->xinerama_infos[i].y_origin + edge = window->screen->xinerama_infos[i].rect.y +
window->screen->xinerama_infos[i].height; window->screen->xinerama_infos[i].rect.height;
g_array_append_val (edges, edge); g_array_append_val (edges, edge);
} }
@ -1266,7 +1241,7 @@ get_horizontal_edges (MetaWindow *window,
meta_window_get_outer_rect (w, &w_rect); meta_window_get_outer_rect (w, &w_rect);
if (rects_overlap_horizontally (&rect, &w_rect)) if (meta_rectangle_horiz_overlap (&rect, &w_rect))
{ {
g_array_append_val (edges, w_rect.y); g_array_append_val (edges, w_rect.y);
edge = w_rect.y + w_rect.height; edge = w_rect.y + w_rect.height;

View File

@ -6,7 +6,7 @@
* Some ICCCM manager selection code derived from fvwm2, * Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
* Copyright (C) 2003 Rob Adams * Copyright (C) 2003 Rob Adams
* Copyright (C) 2004 Elijah Newren * Copyright (C) 2004, 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -221,18 +221,18 @@ reload_xinerama_infos (MetaScreen *screen)
while (i < n_infos) while (i < n_infos)
{ {
screen->xinerama_infos[i].number = infos[i].screen_number; screen->xinerama_infos[i].number = infos[i].screen_number;
screen->xinerama_infos[i].x_origin = infos[i].x_org; screen->xinerama_infos[i].rect.x = infos[i].x_org;
screen->xinerama_infos[i].y_origin = infos[i].y_org; screen->xinerama_infos[i].rect.y = infos[i].y_org;
screen->xinerama_infos[i].width = infos[i].width; screen->xinerama_infos[i].rect.width = infos[i].width;
screen->xinerama_infos[i].height = infos[i].height; screen->xinerama_infos[i].rect.height = infos[i].height;
meta_topic (META_DEBUG_XINERAMA, meta_topic (META_DEBUG_XINERAMA,
"Xinerama %d is %d,%d %d x %d\n", "Xinerama %d is %d,%d %d x %d\n",
screen->xinerama_infos[i].number, screen->xinerama_infos[i].number,
screen->xinerama_infos[i].x_origin, screen->xinerama_infos[i].rect.x,
screen->xinerama_infos[i].y_origin, screen->xinerama_infos[i].rect.y,
screen->xinerama_infos[i].width, screen->xinerama_infos[i].rect.width,
screen->xinerama_infos[i].height); screen->xinerama_infos[i].rect.height);
++i; ++i;
} }
@ -282,18 +282,18 @@ reload_xinerama_infos (MetaScreen *screen)
while (i < n_monitors) while (i < n_monitors)
{ {
screen->xinerama_infos[i].number = i; screen->xinerama_infos[i].number = i;
screen->xinerama_infos[i].x_origin = monitors[i].x; screen->xinerama_infos[i].rect.x = monitors[i].x;
screen->xinerama_infos[i].y_origin = monitors[i].y; screen->xinerama_infos[i].rect.y = monitors[i].y;
screen->xinerama_infos[i].width = monitors[i].width; screen->xinerama_infos[i].rect.width = monitors[i].width;
screen->xinerama_infos[i].height = monitors[i].height; screen->xinerama_infos[i].rect.height = monitors[i].height;
meta_topic (META_DEBUG_XINERAMA, meta_topic (META_DEBUG_XINERAMA,
"Xinerama %d is %d,%d %d x %d\n", "Xinerama %d is %d,%d %d x %d\n",
screen->xinerama_infos[i].number, screen->xinerama_infos[i].number,
screen->xinerama_infos[i].x_origin, screen->xinerama_infos[i].rect.x,
screen->xinerama_infos[i].y_origin, screen->xinerama_infos[i].rect.y,
screen->xinerama_infos[i].width, screen->xinerama_infos[i].rect.width,
screen->xinerama_infos[i].height); screen->xinerama_infos[i].rect.height);
++i; ++i;
} }
@ -325,16 +325,13 @@ reload_xinerama_infos (MetaScreen *screen)
screen->n_xinerama_infos = 2; screen->n_xinerama_infos = 2;
screen->xinerama_infos[0].number = 0; screen->xinerama_infos[0].number = 0;
screen->xinerama_infos[0].x_origin = 0; screen->xinerama_infos[0].rect = screen->rect;
screen->xinerama_infos[0].y_origin = 0; screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
screen->xinerama_infos[0].width = screen->width / 2;
screen->xinerama_infos[0].height = screen->height;
screen->xinerama_infos[1].number = 1; screen->xinerama_infos[1].number = 1;
screen->xinerama_infos[1].x_origin = screen->width / 2; screen->xinerama_infos[1].rect = screen->rect;
screen->xinerama_infos[1].y_origin = 0; screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
screen->xinerama_infos[1].width = screen->width / 2 + screen->width % 2; screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
screen->xinerama_infos[1].height = screen->height;
} }
else else
{ {
@ -345,10 +342,7 @@ reload_xinerama_infos (MetaScreen *screen)
screen->n_xinerama_infos = 1; screen->n_xinerama_infos = 1;
screen->xinerama_infos[0].number = 0; screen->xinerama_infos[0].number = 0;
screen->xinerama_infos[0].x_origin = 0; screen->xinerama_infos[0].rect = screen->rect;
screen->xinerama_infos[0].y_origin = 0;
screen->xinerama_infos[0].width = screen->width;
screen->xinerama_infos[0].height = screen->height;
} }
} }
@ -520,8 +514,9 @@ meta_screen_new (MetaDisplay *display,
screen->screen_name = get_screen_name (display, number); screen->screen_name = get_screen_name (display, number);
screen->xscreen = ScreenOfDisplay (xdisplay, number); screen->xscreen = ScreenOfDisplay (xdisplay, number);
screen->xroot = xroot; screen->xroot = xroot;
screen->width = WidthOfScreen (screen->xscreen); screen->rect.x = screen->rect.y = 0;
screen->height = HeightOfScreen (screen->xscreen); screen->rect.width = WidthOfScreen (screen->xscreen);
screen->rect.height = HeightOfScreen (screen->xscreen);
screen->current_cursor = -1; /* invalid/unset */ screen->current_cursor = -1; /* invalid/unset */
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
screen->default_depth = DefaultDepthOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
@ -1015,8 +1010,8 @@ set_desktop_geometry_hint (MetaScreen *screen)
if (screen->closing > 0) if (screen->closing > 0)
return; return;
data[0] = screen->width; data[0] = screen->rect.width;
data[1] = screen->height; data[1] = screen->rect.height;
meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %ld, %ld\n", data[0], data[1]); meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %ld, %ld\n", data[0], data[1]);
@ -1212,10 +1207,7 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
if (!window->minimized || !meta_window_get_icon_geometry (window, &r)) if (!window->minimized || !meta_window_get_icon_geometry (window, &r))
meta_window_get_outer_rect (window, &r); meta_window_get_outer_rect (window, &r);
entries[i].x = r.x; entries[i].rect = r;
entries[i].y = r.y;
entries[i].width = r.width;
entries[i].height = r.height;
/* Find inside of highlight rectangle to be used /* Find inside of highlight rectangle to be used
* when window is outlined for tabbing. * when window is outlined for tabbing.
@ -1229,19 +1221,19 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
int south = window->frame->rect.height - window->frame->child_y - int south = window->frame->rect.height - window->frame->child_y -
window->rect.height; window->rect.height;
int east = window->frame->child_x; int east = window->frame->child_x;
entries[i].inner_x = east; entries[i].inner_rect.x = east;
entries[i].inner_y = south; entries[i].inner_rect.y = south;
entries[i].inner_width = window->rect.width; entries[i].inner_rect.width = window->rect.width;
entries[i].inner_height = window->frame->rect.height - south * 2; entries[i].inner_rect.height = window->frame->rect.height - south * 2;
} }
else else
{ {
/* Use an arbitrary border size */ /* Use an arbitrary border size */
#define OUTLINE_WIDTH 5 #define OUTLINE_WIDTH 5
entries[i].inner_x = OUTLINE_WIDTH; entries[i].inner_rect.x = OUTLINE_WIDTH;
entries[i].inner_y = OUTLINE_WIDTH; entries[i].inner_rect.y = OUTLINE_WIDTH;
entries[i].inner_width = window->rect.width - OUTLINE_WIDTH * 2; entries[i].inner_rect.width = window->rect.width - OUTLINE_WIDTH * 2;
entries[i].inner_height = window->rect.height - OUTLINE_WIDTH * 2; entries[i].inner_rect.height = window->rect.height - OUTLINE_WIDTH * 2;
} }
++i; ++i;
@ -1376,26 +1368,20 @@ meta_screen_get_xinerama_for_rect (MetaScreen *screen,
best_xinerama = 0; best_xinerama = 0;
xinerama_score = 0; xinerama_score = 0;
i = 0; for (i = 0; i < screen->n_xinerama_infos; i++)
while (i < screen->n_xinerama_infos)
{ {
MetaRectangle dest, screen_info; MetaRectangle dest;
if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
screen_info.x = screen->xinerama_infos[i].x_origin; rect,
screen_info.y = screen->xinerama_infos[i].y_origin; &dest))
screen_info.width = screen->xinerama_infos[i].width;
screen_info.height = screen->xinerama_infos[i].height;
if (meta_rectangle_intersect (&screen_info, rect, &dest))
{ {
if (dest.width * dest.height > xinerama_score) int cur = meta_rectangle_area (&dest);
if (cur > xinerama_score)
{ {
xinerama_score = dest.width * dest.height; xinerama_score = cur;
best_xinerama = i; best_xinerama = i;
} }
} }
++i;
} }
return &screen->xinerama_infos[best_xinerama]; return &screen->xinerama_infos[best_xinerama];
@ -1425,22 +1411,18 @@ meta_screen_get_xinerama_neighbor (MetaScreen *screen,
{ {
current = screen->xinerama_infos + i; current = screen->xinerama_infos + i;
if (((direction == META_SCREEN_RIGHT) && if ((direction == META_SCREEN_RIGHT &&
(current->x_origin == input->x_origin + input->width) && current->rect.x == input->rect.x + input->rect.width &&
(current->y_origin >= input->y_origin) && meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
(current->y_origin <= input->y_origin+input->height)) || (direction == META_SCREEN_LEFT &&
((direction == META_SCREEN_LEFT) && input->rect.x == current->rect.x + current->rect.width &&
(input->x_origin == current->x_origin + current->width) && meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
(current->y_origin >= input->y_origin) && (direction == META_SCREEN_UP &&
(current->y_origin <= input->y_origin + input->height)) || input->rect.y == current->rect.y + current->rect.height &&
((direction == META_SCREEN_UP) && meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
(input->y_origin == current->y_origin + current->height) && (direction == META_SCREEN_DOWN &&
(current->x_origin >= input->x_origin) && current->rect.y == input->rect.y + input->rect.height &&
(current->x_origin <= input->x_origin + input->width)) || meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
((direction == META_SCREEN_DOWN) &&
(current->y_origin == input->y_origin + input->height) &&
(current->x_origin >= input->x_origin) &&
(current->x_origin <= input->x_origin + input->width)))
{ {
return current; return current;
} }
@ -1544,24 +1526,6 @@ meta_screen_get_natural_xinerama_list (MetaScreen *screen,
g_queue_free (xinerama_queue); g_queue_free (xinerama_queue);
} }
gboolean
meta_screen_rect_intersects_xinerama (MetaScreen *screen,
MetaRectangle *rect,
int which_xinerama)
{
MetaRectangle dest, screen_rect;
screen_rect.x = screen->xinerama_infos[which_xinerama].x_origin;
screen_rect.y = screen->xinerama_infos[which_xinerama].y_origin;
screen_rect.width = screen->xinerama_infos[which_xinerama].width;
screen_rect.height = screen->xinerama_infos[which_xinerama].height;
if (meta_rectangle_intersect (&screen_rect, rect, &dest))
return TRUE;
return FALSE;
}
const MetaXineramaScreenInfo* const MetaXineramaScreenInfo*
meta_screen_get_current_xinerama (MetaScreen *screen) meta_screen_get_current_xinerama (MetaScreen *screen)
{ {
@ -1574,39 +1538,33 @@ meta_screen_get_current_xinerama (MetaScreen *screen)
if (screen->display->xinerama_cache_invalidated) if (screen->display->xinerama_cache_invalidated)
{ {
Window root_return, child_return; Window root_return, child_return;
int root_x_return, root_y_return;
int win_x_return, win_y_return; int win_x_return, win_y_return;
unsigned int mask_return; unsigned int mask_return;
int i; int i;
MetaRectangle pointer_position;
screen->display->xinerama_cache_invalidated = FALSE; screen->display->xinerama_cache_invalidated = FALSE;
pointer_position.width = pointer_position.height = 1;
XQueryPointer (screen->display->xdisplay, XQueryPointer (screen->display->xdisplay,
screen->xroot, screen->xroot,
&root_return, &root_return,
&child_return, &child_return,
&root_x_return, &pointer_position.x,
&root_y_return, &pointer_position.y,
&win_x_return, &win_x_return,
&win_y_return, &win_y_return,
&mask_return); &mask_return);
screen->last_xinerama_index = 0; screen->last_xinerama_index = 0;
i = 0; for (i = 0; i < screen->n_xinerama_infos; i++)
while (i < screen->n_xinerama_infos)
{ {
if ((root_x_return >= screen->xinerama_infos[i].x_origin && if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
root_x_return < (screen->xinerama_infos[i].x_origin + &pointer_position))
screen->xinerama_infos[i].width) && {
root_y_return >= screen->xinerama_infos[i].y_origin && screen->last_xinerama_index = i;
root_y_return < (screen->xinerama_infos[i].y_origin + break;
screen->xinerama_infos[i].height))) }
{
screen->last_xinerama_index = i;
break;
}
++i;
} }
meta_topic (META_DEBUG_XINERAMA, meta_topic (META_DEBUG_XINERAMA,
@ -2201,8 +2159,8 @@ meta_screen_resize (MetaScreen *screen,
int width, int width,
int height) int height)
{ {
screen->width = width; screen->rect.width = width;
screen->height = height; screen->rect.height = height;
reload_xinerama_infos (screen); reload_xinerama_infos (screen);
set_desktop_geometry_hint (screen); set_desktop_geometry_hint (screen);

View File

@ -3,7 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Rob Adams * Copyright (C) 2003 Rob Adams
* Copyright (C) 2004 Elijah Newren * Copyright (C) 2004, 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -33,10 +33,7 @@ typedef struct _MetaXineramaScreenInfo MetaXineramaScreenInfo;
struct _MetaXineramaScreenInfo struct _MetaXineramaScreenInfo
{ {
int number; int number;
int x_origin; MetaRectangle rect;
int y_origin;
int width;
int height;
}; };
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
@ -69,8 +66,7 @@ struct _MetaScreen
Window xroot; Window xroot;
int default_depth; int default_depth;
Visual *default_xvisual; Visual *default_xvisual;
int width; MetaRectangle rect; /* Size of screen; rect.x & rect.y are always 0 */
int height;
MetaUI *ui; MetaUI *ui;
MetaTabPopup *tab_popup; MetaTabPopup *tab_popup;
@ -158,9 +154,6 @@ const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_rect (MetaScreen
const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen, const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
MetaWindow *window); MetaWindow *window);
gboolean meta_screen_rect_intersects_xinerama (MetaScreen *screen,
MetaRectangle *window,
int which_xinerama);
const MetaXineramaScreenInfo* meta_screen_get_xinerama_neighbor (MetaScreen *screen, const MetaXineramaScreenInfo* meta_screen_get_xinerama_neighbor (MetaScreen *screen,
int which_xinerama, int which_xinerama,

View File

@ -3,7 +3,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington (some code in here from * Copyright (C) 2001 Havoc Pennington (some code in here from
* libgnomeui, (C) Tom Tromey, Carsten Schaar) * libgnomeui, (C) Tom Tromey, Carsten Schaar)
* Copyright (C) 2004 Elijah Newren * Copyright (C) 2004, 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -728,47 +728,6 @@ window_type_from_string (const char *str)
return META_WINDOW_NORMAL; return META_WINDOW_NORMAL;
} }
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 int static int
window_gravity_from_string (const char *str) window_gravity_from_string (const char *str)
{ {
@ -995,7 +954,7 @@ save_state (void)
fputs (" <minimized/>\n", outfile); fputs (" <minimized/>\n", outfile);
/* Maximized */ /* Maximized */
if (window->maximized) if (META_WINDOW_MAXIMIZED (window))
{ {
fprintf (outfile, fprintf (outfile,
" <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" saved_height=\"%d\"/>\n", " <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" saved_height=\"%d\"/>\n",
@ -1021,7 +980,7 @@ save_state (void)
fprintf (outfile, fprintf (outfile,
" <geometry x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" gravity=\"%s\"/>\n", " <geometry x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" gravity=\"%s\"/>\n",
x, y, w, h, x, y, w, h,
window_gravity_to_string (window->size_hints.win_gravity)); meta_gravity_to_string (window->size_hints.win_gravity));
} }
fputs (" </window>\n", outfile); fputs (" </window>\n", outfile);
@ -1480,7 +1439,7 @@ start_element_handler (GMarkupParseContext *context,
pd->info->rect.y, pd->info->rect.y,
pd->info->rect.width, pd->info->rect.width,
pd->info->rect.height, pd->info->rect.height,
window_gravity_to_string (pd->info->gravity)); meta_gravity_to_string (pd->info->gravity));
} }
else else
{ {

View File

@ -201,8 +201,7 @@ window_is_fullscreen_size (MetaWindow *window)
{ {
int i; int i;
if (window->rect.width >= window->screen->width && if (meta_rectangle_could_fit_rect (&window->rect, &window->screen->rect))
window->rect.height >= window->screen->height)
{ {
/* we use the work area since windows that try to /* we use the work area since windows that try to
* position at 0,0 will get pushed down by menu panel * position at 0,0 will get pushed down by menu panel
@ -210,26 +209,20 @@ window_is_fullscreen_size (MetaWindow *window)
MetaRectangle workarea; MetaRectangle workarea;
meta_window_get_work_area_current_xinerama (window, &workarea); meta_window_get_work_area_current_xinerama (window, &workarea);
if (window->rect.x <= workarea.x && if (meta_rectangle_contains_rect (&window->rect, &workarea))
window->rect.y <= workarea.y &&
window->rect.x + window->rect.width >= workarea.x + workarea.width &&
window->rect.y + window->rect.height >= workarea.y + workarea.height)
return TRUE; return TRUE;
} }
i = 0; i = 0;
while (i < window->screen->n_xinerama_infos) while (i < window->screen->n_xinerama_infos)
{ {
if (window->rect.width >= window->screen->xinerama_infos[i].width && if (meta_rectangle_could_fit_rect (&window->rect,
window->rect.height >= window->screen->xinerama_infos[i].height) &window->screen->xinerama_infos[i].rect))
{ {
MetaRectangle workarea; MetaRectangle workarea;
meta_window_get_work_area_current_xinerama (window, &workarea); meta_window_get_work_area_current_xinerama (window, &workarea);
if (window->rect.x <= workarea.x && if (meta_rectangle_contains_rect (&window->rect, &workarea))
window->rect.y <= workarea.y &&
window->rect.x + window->rect.width >= workarea.x + workarea.width &&
window->rect.y + window->rect.height >= workarea.y + workarea.height)
return TRUE; return TRUE;
} }

View File

@ -241,15 +241,15 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries,
if (outline) if (outline)
{ {
te->rect.x = entries[i].x; te->rect.x = entries[i].rect.x;
te->rect.y = entries[i].y; te->rect.y = entries[i].rect.y;
te->rect.width = entries[i].width; te->rect.width = entries[i].rect.width;
te->rect.height = entries[i].height; te->rect.height = entries[i].rect.height;
te->inner_rect.x = entries[i].inner_x; te->inner_rect.x = entries[i].inner_rect.x;
te->inner_rect.y = entries[i].inner_y; te->inner_rect.y = entries[i].inner_rect.y;
te->inner_rect.width = entries[i].inner_width; te->inner_rect.width = entries[i].inner_rect.width;
te->inner_rect.height = entries[i].inner_height; te->inner_rect.height = entries[i].inner_rect.height;
} }
tab_entries = g_list_prepend (tab_entries, te); tab_entries = g_list_prepend (tab_entries, te);
@ -739,7 +739,8 @@ selectable_workspace_new (MetaWorkspace *workspace)
widget = g_object_new (meta_select_workspace_get_type (), NULL); widget = g_object_new (meta_select_workspace_get_type (), NULL);
screen_aspect = (double) workspace->screen->height / (double) workspace->screen->width; screen_aspect = (double) workspace->screen->rect.height /
(double) workspace->screen->rect.width;
/* account for select rect */ /* account for select rect */
gtk_widget_set_size_request (widget, gtk_widget_set_size_request (widget,
@ -893,8 +894,8 @@ meta_select_workspace_expose_event (GtkWidget *widget,
SELECT_OUTLINE_WIDTH, SELECT_OUTLINE_WIDTH,
widget->allocation.width - SELECT_OUTLINE_WIDTH * 2, widget->allocation.width - SELECT_OUTLINE_WIDTH * 2,
widget->allocation.height - SELECT_OUTLINE_WIDTH * 2, widget->allocation.height - SELECT_OUTLINE_WIDTH * 2,
workspace->screen->width, workspace->screen->rect.width,
workspace->screen->height, workspace->screen->rect.height,
NULL, NULL,
(workspace->screen->active_workspace == workspace), (workspace->screen->active_workspace == workspace),
windows, windows,

View File

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -24,6 +25,7 @@
/* Don't include gtk.h or gdk.h here */ /* Don't include gtk.h or gdk.h here */
#include "common.h" #include "common.h"
#include "boxes.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <glib.h> #include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf.h>
@ -37,8 +39,8 @@ struct _MetaTabEntry
MetaTabEntryKey key; MetaTabEntryKey key;
const char *title; const char *title;
GdkPixbuf *icon; GdkPixbuf *icon;
int x, y, width, height; MetaRectangle rect;
int inner_x, inner_y, inner_width, inner_height; MetaRectangle inner_rect;
guint blank : 1; guint blank : 1;
guint hidden : 1; guint hidden : 1;
guint demands_attention : 1; guint demands_attention : 1;

1400
src/testboxes.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <X11/Xutil.h> /* Just for the definition of the various gravities */
#ifdef HAVE_BACKTRACE #ifdef HAVE_BACKTRACE
#include <execinfo.h> #include <execinfo.h>
@ -464,3 +465,44 @@ meta_unsigned_long_hash (gconstpointer v)
return val; return val;
#endif #endif
} }
const char*
meta_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;
}
}

View File

@ -85,6 +85,8 @@ guint meta_unsigned_long_hash (gconstpointer v);
void meta_print_backtrace (void); void meta_print_backtrace (void);
const char* meta_gravity_to_string (int gravity);
#include <libintl.h> #include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x) #define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x #define N_(x) x

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,12 @@ typedef enum
META_WINDOW_SPLASHSCREEN META_WINDOW_SPLASHSCREEN
} MetaWindowType; } MetaWindowType;
typedef enum
{
META_MAXIMIZE_HORIZONTAL = 1 << 0,
META_MAXIMIZE_VERTICAL = 1 << 1
} MetaMaximizeFlags;
struct _MetaStruts struct _MetaStruts
{ {
/* struts */ /* struts */
@ -108,8 +114,10 @@ struct _MetaWindow
Time initial_timestamp; Time initial_timestamp;
/* Whether we're maximized */ /* Whether we're maximized */
guint maximized : 1; guint maximized_horizontally : 1;
guint maximize_after_placement : 1; guint maximized_vertically : 1;
guint maximize_horizontally_after_placement : 1;
guint maximize_vertically_after_placement : 1;
/* Whether we're shaded */ /* Whether we're shaded */
guint shaded : 1; guint shaded : 1;
@ -117,6 +125,12 @@ struct _MetaWindow
/* Whether we're fullscreen */ /* Whether we're fullscreen */
guint fullscreen : 1; guint fullscreen : 1;
/* Whether we're trying to constrain the window to be fully onscreen */
guint require_fully_onscreen : 1;
/* Whether we're trying to constrain the window to be on a single xinerama */
guint require_on_single_xinerama : 1;
/* Whether we're sticky in the multi-workspace sense /* Whether we're sticky in the multi-workspace sense
* (vs. the not-scroll-with-viewport sense, we don't * (vs. the not-scroll-with-viewport sense, we don't
* have no stupid viewports) * have no stupid viewports)
@ -287,25 +301,29 @@ struct _MetaWindow
/* The size we set the window to last (i.e. what we believe /* The size we set the window to last (i.e. what we believe
* to be its actual size on the server). The x, y are * to be its actual size on the server). The x, y are
* the actual server-side x,y so are relative to the frame * the actual server-side x,y so are relative to the frame
* or the root window as appropriate. * (meaning that they just hold the frame width and height)
* or the root window (meaning they specify the location
* of the top left of the inner window) as appropriate.
*/ */
MetaRectangle rect; MetaRectangle rect;
/* The geometry to restore when we unmaximize. /* The geometry to restore when we unmaximize. The position is in
* The position is in root window coords, even if * root window coords, even if there's a frame, which contrasts with
* there's a frame, which contrasts with window->rect * window->rect above. Note that this gives the position and size
* above. * of the client window (i.e. ignoring the frame).
*/ */
MetaRectangle saved_rect; MetaRectangle saved_rect;
/* This is the geometry the window had after the last user-initiated /* This is the geometry the window had after the last user-initiated
* move/resize operations. We use this whenever we are moving the * move/resize operations. We use this whenever we are moving the
* implicitly (for example, if we move to avoid a panel, we * implicitly (for example, if we move to avoid a panel, we can snap
* can snap back to this position if the panel moves again) * back to this position if the panel moves again). Note that this
* gives the position and size of the client window (i.e. ignoring
* the frame).
* *
* Position valid if user_has_moved, size valid if user_has_resized * Position valid if user_has_moved, size valid if user_has_resized
* *
* Position always in root coords, unlike window->rect * Position always in root coords, unlike window->rect.
*/ */
MetaRectangle user_rect; MetaRectangle user_rect;
@ -330,8 +348,10 @@ struct _MetaWindow
* the dynamic window state such as "maximized", not just the * the dynamic window state such as "maximized", not just the
* window's type * window's type
*/ */
#define META_WINDOW_MAXIMIZED(w) ((w)->maximized_horizontally && \
(w)->maximized_vertically)
#define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->fullscreen) #define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->fullscreen)
#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !(w)->maximized && !(w)->fullscreen && !(w)->shaded) #define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !(w)->fullscreen && !(w)->shaded)
#define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \ #define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \
(((w)->size_hints.min_width < (w)->size_hints.max_width) || \ (((w)->size_hints.min_width < (w)->size_hints.max_width) || \
((w)->size_hints.min_height < (w)->size_hints.max_height))) ((w)->size_hints.min_height < (w)->size_hints.max_height)))
@ -350,10 +370,13 @@ void meta_window_calc_showing (MetaWindow *window);
void meta_window_queue_calc_showing (MetaWindow *window); void meta_window_queue_calc_showing (MetaWindow *window);
void meta_window_minimize (MetaWindow *window); void meta_window_minimize (MetaWindow *window);
void meta_window_unminimize (MetaWindow *window); void meta_window_unminimize (MetaWindow *window);
void meta_window_maximize (MetaWindow *window); void meta_window_maximize (MetaWindow *window,
void meta_window_maximize_internal (MetaWindow *window, MetaMaximizeFlags directions);
MetaRectangle *saved_rect); void meta_window_maximize_internal (MetaWindow *window,
void meta_window_unmaximize (MetaWindow *window); MetaMaximizeFlags directions,
MetaRectangle *saved_rect);
void meta_window_unmaximize (MetaWindow *window,
MetaMaximizeFlags directions);
void meta_window_make_above (MetaWindow *window); void meta_window_make_above (MetaWindow *window);
void meta_window_unmake_above (MetaWindow *window); void meta_window_unmake_above (MetaWindow *window);
void meta_window_shade (MetaWindow *window); void meta_window_shade (MetaWindow *window);
@ -390,9 +413,6 @@ void meta_window_resize_with_gravity (MetaWindow *window,
int gravity); int gravity);
void meta_window_fill_horizontal (MetaWindow *window);
void meta_window_fill_vertical (MetaWindow *window);
/* Return whether the window would be showing if we were on its workspace */ /* Return whether the window would be showing if we were on its workspace */
gboolean meta_window_showing_on_its_workspace (MetaWindow *window); gboolean meta_window_showing_on_its_workspace (MetaWindow *window);
@ -477,6 +497,9 @@ void meta_window_show_menu (MetaWindow *window,
int button, int button,
Time timestamp); Time timestamp);
gboolean meta_window_titlebar_is_onscreen (MetaWindow *window);
void meta_window_shove_titlebar_onscreen (MetaWindow *window);
void meta_window_set_gravity (MetaWindow *window, void meta_window_set_gravity (MetaWindow *window,
int gravity); int gravity);

View File

@ -57,17 +57,19 @@ meta_workspace_new (MetaScreen *screen)
workspace->mru_list = NULL; workspace->mru_list = NULL;
meta_screen_foreach_window (screen, maybe_add_to_list, &workspace->mru_list); meta_screen_foreach_window (screen, maybe_add_to_list, &workspace->mru_list);
workspace->work_areas = NULL;
workspace->work_areas_invalid = TRUE; workspace->work_areas_invalid = TRUE;
workspace->all_work_areas.x = 0; workspace->work_area_xinerama = NULL;
workspace->all_work_areas.y = 0; workspace->work_area_screen.x = 0;
workspace->all_work_areas.width = 0; workspace->work_area_screen.y = 0;
workspace->all_work_areas.height = 0; workspace->work_area_screen.width = 0;
workspace->work_area_screen.height = 0;
workspace->left_struts = NULL; workspace->screen_region = NULL;
workspace->right_struts = NULL; workspace->xinerama_region = NULL;
workspace->top_struts = NULL; workspace->screen_edges = NULL;
workspace->bottom_struts = NULL; workspace->xinerama_edges = NULL;
workspace->all_struts = NULL;
workspace->showing_desktop = FALSE; workspace->showing_desktop = FALSE;
@ -79,6 +81,7 @@ meta_workspace_free (MetaWorkspace *workspace)
{ {
GList *tmp; GList *tmp;
MetaScreen *screen; MetaScreen *screen;
int i;
g_return_if_fail (workspace != workspace->screen->active_workspace); g_return_if_fail (workspace != workspace->screen->active_workspace);
@ -107,13 +110,17 @@ meta_workspace_free (MetaWorkspace *workspace)
workspace->screen->workspaces = workspace->screen->workspaces =
g_list_remove (workspace->screen->workspaces, workspace); g_list_remove (workspace->screen->workspaces, workspace);
g_free (workspace->work_areas); g_free (workspace->work_area_xinerama);
g_list_free (workspace->mru_list); g_list_free (workspace->mru_list);
g_slist_free (workspace->left_struts); g_slist_free (workspace->all_struts);
g_slist_free (workspace->right_struts);
g_slist_free (workspace->top_struts); for (i = 0; i < screen->n_xinerama_infos; i++)
g_slist_free (workspace->bottom_struts); meta_rectangle_free_list_and_elements (workspace->xinerama_region[i]);
g_free (workspace->xinerama_region);
meta_rectangle_free_list_and_elements (workspace->screen_region);
meta_rectangle_free_list_and_elements (workspace->screen_edges);
meta_rectangle_free_list_and_elements (workspace->xinerama_edges);
g_free (workspace); g_free (workspace);
@ -429,6 +436,7 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
{ {
GList *tmp; GList *tmp;
GList *windows; GList *windows;
int i;
if (workspace->work_areas_invalid) if (workspace->work_areas_invalid)
{ {
@ -442,17 +450,22 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
"Invalidating work area for workspace %d\n", "Invalidating work area for workspace %d\n",
meta_workspace_index (workspace)); meta_workspace_index (workspace));
g_free (workspace->work_areas); g_free (workspace->work_area_xinerama);
workspace->work_areas = NULL; workspace->work_area_xinerama = NULL;
g_slist_free (workspace->left_struts); g_slist_free (workspace->all_struts);
workspace->left_struts = NULL; workspace->all_struts = NULL;
g_slist_free (workspace->right_struts);
workspace->right_struts = NULL; for (i = 0; i < workspace->screen->n_xinerama_infos; i++)
g_slist_free (workspace->top_struts); meta_rectangle_free_list_and_elements (workspace->xinerama_region[i]);
workspace->top_struts = NULL; g_free (workspace->xinerama_region);
g_slist_free (workspace->bottom_struts); meta_rectangle_free_list_and_elements (workspace->screen_region);
workspace->bottom_struts = NULL; meta_rectangle_free_list_and_elements (workspace->screen_edges);
meta_rectangle_free_list_and_elements (workspace->xinerama_edges);
workspace->xinerama_region = NULL;
workspace->screen_region = NULL;
workspace->screen_edges = NULL;
workspace->xinerama_edges = NULL;
workspace->work_areas_invalid = TRUE; workspace->work_areas_invalid = TRUE;
@ -491,16 +504,17 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
if (!workspace->work_areas_invalid) if (!workspace->work_areas_invalid)
return; return;
g_assert (workspace->top_struts == NULL); g_assert (workspace->all_struts == NULL);
g_assert (workspace->bottom_struts == NULL); g_assert (workspace->xinerama_region == NULL);
g_assert (workspace->left_struts == NULL); g_assert (workspace->screen_region == NULL);
g_assert (workspace->right_struts == NULL); g_assert (workspace->screen_edges == NULL);
g_assert (workspace->xinerama_edges == NULL);
windows = meta_workspace_list_windows (workspace); windows = meta_workspace_list_windows (workspace);
g_free (workspace->work_areas); g_free (workspace->work_area_xinerama);
workspace->work_areas = g_new (MetaRectangle, workspace->work_area_xinerama = g_new (MetaRectangle,
workspace->screen->n_xinerama_infos); workspace->screen->n_xinerama_infos);
i = 0; i = 0;
while (i < workspace->screen->n_xinerama_infos) while (i < workspace->screen->n_xinerama_infos)
@ -528,67 +542,63 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
if ((i == 0) && (w->struts->left.width > 0)) if ((i == 0) && (w->struts->left.width > 0))
{ {
workspace->left_struts = g_slist_prepend (workspace->left_struts, workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->left); &w->struts->left);
} }
if (meta_screen_rect_intersects_xinerama (w->screen, if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->left, &w->struts->left))
i))
{ {
left_strut = MAX (left_strut, left_strut = MAX (left_strut,
w->struts->left.width - w->struts->left.width -
workspace->screen->xinerama_infos[i].x_origin); workspace->screen->xinerama_infos[i].rect.x);
all_left_strut = MAX (all_left_strut, w->struts->left.width); all_left_strut = MAX (all_left_strut, w->struts->left.width);
} }
if ((i == 0) && (w->struts->right.width > 0)) if ((i == 0) && (w->struts->right.width > 0))
{ {
workspace->right_struts = g_slist_prepend (workspace->right_struts, workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->right); &w->struts->right);
} }
if (meta_screen_rect_intersects_xinerama (w->screen, if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->right, &w->struts->right))
i))
{ {
right_strut = MAX (right_strut, w->struts->right.width - right_strut = MAX (right_strut, w->struts->right.width -
workspace->screen->width + workspace->screen->rect.width +
workspace->screen->xinerama_infos[i].width + workspace->screen->xinerama_infos[i].rect.width +
workspace->screen->xinerama_infos[i].x_origin); workspace->screen->xinerama_infos[i].rect.x);
all_right_strut = MAX (all_right_strut, w->struts->right.width); all_right_strut = MAX (all_right_strut, w->struts->right.width);
} }
if ((i == 0) && (w->struts->top.height > 0)) if ((i == 0) && (w->struts->top.height > 0))
{ {
workspace->top_struts = g_slist_prepend (workspace->top_struts, workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->top); &w->struts->top);
} }
if (meta_screen_rect_intersects_xinerama (w->screen, if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->top, &w->struts->top))
i))
{ {
top_strut = MAX (top_strut, top_strut = MAX (top_strut,
w->struts->top.height - w->struts->top.height -
workspace->screen->xinerama_infos[i].y_origin); workspace->screen->xinerama_infos[i].rect.y);
all_top_strut = MAX (all_top_strut, w->struts->top.height); all_top_strut = MAX (all_top_strut, w->struts->top.height);
} }
if ((i == 0) && (w->struts->bottom.height > 0)) if ((i == 0) && (w->struts->bottom.height > 0))
{ {
workspace->bottom_struts = g_slist_prepend (workspace->bottom_struts, workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->bottom); &w->struts->bottom);
} }
if (meta_screen_rect_intersects_xinerama (w->screen, if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->bottom, &w->struts->bottom))
i))
{ {
bottom_strut = MAX (bottom_strut, w->struts->bottom.height - bottom_strut = MAX (bottom_strut, w->struts->bottom.height -
workspace->screen->height + workspace->screen->rect.height +
workspace->screen->xinerama_infos[i].height + workspace->screen->xinerama_infos[i].rect.height +
workspace->screen->xinerama_infos[i].y_origin); workspace->screen->xinerama_infos[i].rect.y);
all_bottom_strut = MAX (all_bottom_strut, w->struts->bottom.height); all_bottom_strut = MAX (all_bottom_strut, w->struts->bottom.height);
} }
} }
@ -600,36 +610,36 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
#define MIN_SANE_AREA 100 #define MIN_SANE_AREA 100
if ((left_strut + right_strut) > if ((left_strut + right_strut) >
(workspace->screen->xinerama_infos[i].width - MIN_SANE_AREA)) (workspace->screen->xinerama_infos[i].rect.width - MIN_SANE_AREA))
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Making left/right struts %d %d sane xinerama %d\n", "Making left/right struts %d %d sane xinerama %d\n",
left_strut, right_strut, i); left_strut, right_strut, i);
left_strut = (workspace->screen->xinerama_infos[i].width - left_strut = (workspace->screen->xinerama_infos[i].rect.width -
MIN_SANE_AREA) / 2; MIN_SANE_AREA) / 2;
right_strut = left_strut; right_strut = left_strut;
} }
if ((top_strut + bottom_strut) > if ((top_strut + bottom_strut) >
(workspace->screen->xinerama_infos[i].height - MIN_SANE_AREA)) (workspace->screen->xinerama_infos[i].rect.height - MIN_SANE_AREA))
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Making top/bottom struts %d %d sane xinerama %d\n", "Making top/bottom struts %d %d sane xinerama %d\n",
top_strut, bottom_strut, i); top_strut, bottom_strut, i);
top_strut = (workspace->screen->xinerama_infos[i].height - top_strut = (workspace->screen->xinerama_infos[i].rect.height -
MIN_SANE_AREA) / 2; MIN_SANE_AREA) / 2;
bottom_strut = top_strut; bottom_strut = top_strut;
} }
workspace->work_areas[i].x = workspace->work_area_xinerama[i].x =
left_strut + workspace->screen->xinerama_infos[i].x_origin; left_strut + workspace->screen->xinerama_infos[i].rect.x;
workspace->work_areas[i].y = top_strut + workspace->work_area_xinerama[i].y = top_strut +
workspace->screen->xinerama_infos[i].y_origin; workspace->screen->xinerama_infos[i].rect.y;
workspace->work_areas[i].width = workspace->work_area_xinerama[i].width =
workspace->screen->xinerama_infos[i].width - workspace->screen->xinerama_infos[i].rect.width -
left_strut - right_strut; left_strut - right_strut;
workspace->work_areas[i].height = workspace->work_area_xinerama[i].height =
workspace->screen->xinerama_infos[i].height - workspace->screen->xinerama_infos[i].rect.height -
top_strut - bottom_strut; top_strut - bottom_strut;
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
@ -637,10 +647,10 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
"xinerama %d: %d,%d %d x %d\n", "xinerama %d: %d,%d %d x %d\n",
meta_workspace_index (workspace), meta_workspace_index (workspace),
i, i,
workspace->work_areas[i].x, workspace->work_area_xinerama[i].x,
workspace->work_areas[i].y, workspace->work_area_xinerama[i].y,
workspace->work_areas[i].width, workspace->work_area_xinerama[i].width,
workspace->work_areas[i].height); workspace->work_area_xinerama[i].height);
++i; ++i;
} }
@ -648,41 +658,91 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
g_list_free (windows); g_list_free (windows);
if ((all_left_strut + all_right_strut) > if ((all_left_strut + all_right_strut) >
(workspace->screen->width - MIN_SANE_AREA)) (workspace->screen->rect.width - MIN_SANE_AREA))
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Making screen-wide left/right struts %d %d sane\n", "Making screen-wide left/right struts %d %d sane\n",
all_left_strut, all_right_strut); all_left_strut, all_right_strut);
all_left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2; all_left_strut = (workspace->screen->rect.width - MIN_SANE_AREA) / 2;
all_right_strut = all_left_strut; all_right_strut = all_left_strut;
} }
if ((all_top_strut + all_bottom_strut) > if ((all_top_strut + all_bottom_strut) >
(workspace->screen->height - MIN_SANE_AREA)) (workspace->screen->rect.height - MIN_SANE_AREA))
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Making top/bottom struts %d %d sane\n", "Making top/bottom struts %d %d sane\n",
all_top_strut, all_bottom_strut); all_top_strut, all_bottom_strut);
all_top_strut = (workspace->screen->height - MIN_SANE_AREA) / 2; all_top_strut = (workspace->screen->rect.height - MIN_SANE_AREA) / 2;
all_bottom_strut = all_top_strut; all_bottom_strut = all_top_strut;
} }
workspace->all_work_areas.x = all_left_strut; workspace->work_area_screen.x = all_left_strut;
workspace->all_work_areas.y = all_top_strut; workspace->work_area_screen.y = all_top_strut;
workspace->all_work_areas.width = workspace->work_area_screen.width =
workspace->screen->width - all_left_strut - all_right_strut; workspace->screen->rect.width - all_left_strut - all_right_strut;
workspace->all_work_areas.height = workspace->work_area_screen.height =
workspace->screen->height - all_top_strut - all_bottom_strut; workspace->screen->rect.height - all_top_strut - all_bottom_strut;
/* Now cache the spanning rects for the onscreen and
* on-single-xinerama regions
*/
g_assert (workspace->xinerama_region == NULL);
g_assert (workspace->screen_region == NULL);
workspace->xinerama_region = g_new (GList*,
workspace->screen->n_xinerama_infos);
for (i = 0; i < workspace->screen->n_xinerama_infos; i++)
{
workspace->xinerama_region[i] =
meta_rectangle_get_minimal_spanning_set_for_region (
&workspace->screen->xinerama_infos[i].rect,
workspace->all_struts);
}
workspace->screen_region =
meta_rectangle_get_minimal_spanning_set_for_region (
&workspace->screen->rect,
workspace->all_struts);
/* Since get_minimal_spanning_set_for_region() doesn't do the
* MIN_SANE_AREA thing, manually account for it. Note that it's okay if
* get_minimal_spanning_set_for_region() returns a very small region--all
* we really need here is a 1x1 region that corresponds to somewhere on
* the monitor for the partially onscreen constraint. If we don't get
* anything, though, we use work_area_screen just for convenience.
*/
if (workspace->screen_region == NULL)
{
MetaRectangle *nonempty_region;
nonempty_region = g_new (MetaRectangle, 1);
*nonempty_region = workspace->work_area_screen;
workspace->screen_region = g_list_prepend (NULL, nonempty_region);
}
/* Now cache the screen and xinerama edges for edge resistance and snapping */
g_assert (workspace->screen_edges == NULL);
g_assert (workspace->xinerama_edges == NULL);
workspace->screen_edges =
meta_rectangle_find_onscreen_edges (&workspace->screen->rect,
workspace->all_struts);
tmp = NULL;
for (i = 0; i < workspace->screen->n_xinerama_infos; i++)
tmp = g_list_prepend (tmp, &workspace->screen->xinerama_infos[i].rect);
workspace->xinerama_edges =
meta_rectangle_find_nonintersected_xinerama_edges (tmp,
workspace->all_struts);
g_list_free (tmp);
/* We're all done, YAAY! Record that everything has been validated. */
workspace->work_areas_invalid = FALSE; workspace->work_areas_invalid = FALSE;
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d: %d,%d %d x %d\n", "Computed work area for workspace %d: %d,%d %d x %d\n",
meta_workspace_index (workspace), meta_workspace_index (workspace),
workspace->all_work_areas.x, workspace->work_area_screen.x,
workspace->all_work_areas.y, workspace->work_area_screen.y,
workspace->all_work_areas.width, workspace->work_area_screen.width,
workspace->all_work_areas.height); workspace->work_area_screen.height);
} }
void void
@ -695,7 +755,7 @@ meta_workspace_get_work_area_for_xinerama (MetaWorkspace *workspace,
ensure_work_areas_validated (workspace); ensure_work_areas_validated (workspace);
g_assert (which_xinerama < workspace->screen->n_xinerama_infos); g_assert (which_xinerama < workspace->screen->n_xinerama_infos);
*area = workspace->work_areas[which_xinerama]; *area = workspace->work_area_xinerama[which_xinerama];
} }
void void
@ -704,7 +764,24 @@ meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
{ {
ensure_work_areas_validated (workspace); ensure_work_areas_validated (workspace);
*area = workspace->all_work_areas; *area = workspace->work_area_screen;
}
GList*
meta_workspace_get_onscreen_region (MetaWorkspace *workspace)
{
ensure_work_areas_validated (workspace);
return workspace->screen_region;
}
GList*
meta_workspace_get_onxinerama_region (MetaWorkspace *workspace,
int which_xinerama)
{
ensure_work_areas_validated (workspace);
return workspace->xinerama_region[which_xinerama];
} }
#ifdef WITH_VERBOSE_MODE #ifdef WITH_VERBOSE_MODE

View File

@ -2,7 +2,7 @@
/* /*
* Copyright (C) 2001 Havoc Pennington * Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2004 Elijah Newren * Copyright (C) 2004, 2005 Elijah Newren
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -43,12 +43,13 @@ struct _MetaWorkspace
GList *windows; GList *windows;
GList *mru_list; GList *mru_list;
MetaRectangle all_work_areas; MetaRectangle work_area_screen;
MetaRectangle *work_areas; MetaRectangle *work_area_xinerama;
GSList *left_struts; GList *screen_region;
GSList *right_struts; GList **xinerama_region;
GSList *top_struts; GList *screen_edges;
GSList *bottom_struts; GList *xinerama_edges;
GSList *all_struts;
guint work_areas_invalid : 1; guint work_areas_invalid : 1;
guint showing_desktop : 1; guint showing_desktop : 1;
@ -78,6 +79,11 @@ void meta_workspace_get_work_area_for_xinerama (MetaWorkspace *workspace,
MetaRectangle *area); MetaRectangle *area);
void meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace, void meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
MetaRectangle *area); MetaRectangle *area);
GList* meta_workspace_get_onscreen_region (MetaWorkspace *workspace);
GList* meta_workspace_get_onxinerama_region (MetaWorkspace *workspace,
int which_xinerama);
void meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
MetaRectangle *area);
void meta_workspace_focus_default_window (MetaWorkspace *workspace, void meta_workspace_focus_default_window (MetaWorkspace *workspace,
MetaWindow *not_this_one, MetaWindow *not_this_one,