~ctwm/ctwm/trunk

535.1.24 by Matthew Fuller
Pull the first few window move/resize related funcs out into a new
1
/*
2
 * Functions related to moving/resizing windows.
3
 */
4
5
#include "ctwm.h"
6
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
7
#include <stdio.h>
8
#include <stdlib.h>
9
10
#include "colormaps.h"
11
#include "events.h"
12
#include "event_handlers.h"
13
#include "functions.h"
14
#include "functions_defs.h"
535.1.24 by Matthew Fuller
Pull the first few window move/resize related funcs out into a new
15
#include "functions_internal.h"
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
16
#include "icons.h"
17
#include "otp.h"
18
#include "parse.h"
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
19
#include "r_area.h"
614.2.4 by Matthew Fuller
r_layout.h includes r_structs.h, so including it in screen.h
20
#include "r_layout.h"
535.1.24 by Matthew Fuller
Pull the first few window move/resize related funcs out into a new
21
#include "screen.h"
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
22
#include "util.h"
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
23
#include "vscreen.h"
538.1.3 by Matthew Fuller
Rename the decorations*.h to win_decorations*.h.
24
#include "win_decorations.h"
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
25
#include "win_ops.h"
538.1.5 by Matthew Fuller
And rename over resize.h.
26
#include "win_resize.h"
535.1.24 by Matthew Fuller
Pull the first few window move/resize related funcs out into a new
27
#include "win_utils.h"
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
28
#include "workspace_manager.h"
614.1.23 by Maxime Soulé
Some geometries can be relative to a monitor
29
#include "xparsegeometry.h"
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
30
31
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
32
/*
33
 * MoveFillDir-ectional specifiers, used in jump/pack/fill
34
 */
535.1.31 by Matthew Fuller
Remove f.resize from the switch now that it's external, and pull out
35
typedef enum {
36
	MFD_BOTTOM,
37
	MFD_LEFT,
38
	MFD_RIGHT,
39
	MFD_TOP,
40
} MoveFillDir;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
41
static int FindConstraint(TwmWindow *tmp_win, MoveFillDir direction);
535.1.31 by Matthew Fuller
Remove f.resize from the switch now that it's external, and pull out
42
535.1.64 by Matthew Fuller
belongs_to_twm_window() is only used with the move/resize bits, so
43
/* Internal util */
44
static bool belongs_to_twm_window(TwmWindow *t, Window w);
45
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
46
47
/*
48
 * Constrained move variables
49
 *
50
 * Used in the resize handling, but needed over in event code for
51
 * ButtonRelease as well.
52
 */
53
bool ConstMove = false;
54
CMoveDir ConstMoveDir;
55
int ConstMoveX;
56
int ConstMoveY;
57
int ConstMoveXL;
58
int ConstMoveXR;
59
int ConstMoveYT;
60
int ConstMoveYB;
61
535.1.37 by Matthew Fuller
These globals now really belong with the moveresize bits, so move them
62
/*
63
 * Which move-ish function is in progress.  This is _almost_ really a
64
 * local var in the movewindow() function, but we also reference it in
65
 * the HandleButtonRelease() event handler because that has to know
66
 * which move variant we're doing to figure out whether it has to
67
 * constrain the final coordinates in various ways.
68
 */
69
int MoveFunction;
70
71
/*
72
 * Globals used to keep track of whether the mouse has moved during a
73
 * resize function.
74
 */
75
int ResizeOrigX;
76
int ResizeOrigY;
77
78
79
80
/*
81
 * Now, on to the actual handlers.
82
 */
535.1.24 by Matthew Fuller
Pull the first few window move/resize related funcs out into a new
83
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
84
85
/*
86
 *********************************************************
87
 *
88
 * First, the various methods of moving windows around.
89
 *
90
 *********************************************************
91
 */
92
93
/*
94
 * Simple f.move and related
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
95
 */
535.1.36 by Matthew Fuller
Move this prototype down to alongside its callers, like we do on other
96
static void movewindow(EF_FULLPROTO);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
97
DFHANDLER(move)
98
{
99
	movewindow(EF_ARGS);
100
}
101
DFHANDLER(forcemove)
102
{
103
	movewindow(EF_ARGS);
104
}
105
DFHANDLER(movepack)
106
{
107
	movewindow(EF_ARGS);
108
}
109
DFHANDLER(movepush)
110
{
111
	movewindow(EF_ARGS);
112
}
113
535.1.28 by Matthew Fuller
Pull out the zooming resize funcs.
114
/* f.move and friends backend */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
115
static void
116
movewindow(EF_FULLPROTO)
117
{
118
	int origX, origY;
555.1.10 by Matthew Fuller
Don't initialize this up top, do it in the branch where we set the
119
	bool moving_icon;
555.1.15 by Matthew Fuller
Pull this var back out in scope; I think it needs to live through
120
	bool fromtitlebar;
555.1.3 by Matthew Fuller
This var is just a shortcut, so assign it up top and const-ify to make
121
	const Window dragroot = Scr->XineramaRoot;
555.1.8 by Matthew Fuller
This is another var that's just a shortcut, and I don't see any way
122
	const Window rootw = eventp->xbutton.root;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
123
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
124
	/* Better not be a menu open */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
125
	PopDownMenu();
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
126
555.1.11 by Matthew Fuller
Move setting MoveFunction up near the top, since it's a sort of
127
	/* Stash up just which f.move* variant we are */
128
	MoveFunction = func;
129
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
130
	/*
131
	 * Figure whether we're moving opaquely.
132
	 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
133
	if(tmp_win->OpaqueMove) {
571.1.3 by Matthew Fuller
Make the default (200) or higher for OpaqueMove act as infinity,
134
		if(Scr->OpaqueMoveThreshold >= 200) {
135
			Scr->OpaqueMove = true;
136
		}
137
		else {
138
			const unsigned long sw = tmp_win->frame_width
571.1.8 by Matthew Fuller
make indent
139
			                         * tmp_win->frame_height;
571.1.3 by Matthew Fuller
Make the default (200) or higher for OpaqueMove act as infinity,
140
			const unsigned long ss = Scr->rootw  * Scr->rooth;
141
			const float sf = Scr->OpaqueMoveThreshold / 100.0;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
142
571.1.3 by Matthew Fuller
Make the default (200) or higher for OpaqueMove act as infinity,
143
			if(sw > (ss * sf)) {
144
				Scr->OpaqueMove = false;
145
			}
146
			else {
147
				Scr->OpaqueMove = true;
148
			}
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
149
		}
150
	}
151
	else {
152
		Scr->OpaqueMove = false;
153
	}
154
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
155
#ifdef WINBOX
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
156
	/* If it's in a WindowBox, adjust coordinates as necessary */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
157
	if(tmp_win->winbox) {
158
		XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
159
		                      eventp->xbutton.x_root, eventp->xbutton.y_root,
160
		                      &(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild);
161
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
162
#endif
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
163
164
	/*
165
	 * XXX pulldown=true only when we're triggering from a ButtonRelease
166
	 * in a menu, and this warp should only be going somewhere if we hit
167
	 * the winbox case above and had to translate the coordinates?  But,
168
	 * in that case, the coordinates would be changed to be relative to
169
	 * the winbox window, and here we're positioning relative to Root?
170
	 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
171
	if(pulldown)
172
		XWarpPointer(dpy, None, Scr->Root,
173
		             0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
174
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
175
	/*
176
	 * Stub out handlers for enter/leave notifications while we do stuff.
177
	 * They get reset toward the end of the ButtonRelease handler.
178
	 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
179
	EventHandler[EnterNotify] = HandleUnknown;
180
	EventHandler[LeaveNotify] = HandleUnknown;
181
182
	if(!Scr->NoGrabServer || !Scr->OpaqueMove) {
183
		XGrabServer(dpy);
184
	}
185
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
186
	/*
187
	 * Setup size for the window showing current location as we move it.
188
	 * The same window is used for resize ops too, where it might be a
189
	 * different size.
190
	 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
191
	Scr->SizeStringOffset = SIZE_HINDENT;
614.1.28 by Maxime Soulé
If CenterFeedbackWindow, feedback window centered in current monitor
192
	MoveResizeSizeWindow(eventp->xbutton.x_root, eventp->xbutton.y_root,
193
	                     Scr->SizeStringWidth + SIZE_HINDENT * 2,
194
	                     Scr->SizeFont.height + SIZE_VINDENT * 2);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
195
	XMapRaised(dpy, Scr->SizeWindow);
196
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
197
	/*
198
	 * Use XGrabPointer() to configure how we get events locations
199
	 * reported relative to what root.
200
	 */
555.1.7 by Matthew Fuller
This var is only used to make it easier to pick one of these two for
201
	{
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
202
#ifdef WINBOX
555.1.7 by Matthew Fuller
This var is only used to make it easier to pick one of these two for
203
		const Window grabwin = (tmp_win->winbox ? tmp_win->winbox->window
204
		                        : Scr->XineramaRoot);
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
205
#else
206
		const Window grabwin = Scr->XineramaRoot;
207
#endif
555.1.7 by Matthew Fuller
This var is only used to make it easier to pick one of these two for
208
209
		XGrabPointer(dpy, grabwin, True,
210
		             ButtonPressMask | ButtonReleaseMask |
211
		             ButtonMotionMask | PointerMotionMask,
212
		             GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor,
213
		             CurrentTime);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
214
	}
215
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
216
	/*
217
	 * Set w to what we're actually moving.  If it's an icon, we always
218
	 * move it opaquely anyway.  If it's a window (that's not iconofied),
219
	 * we move the frame.
220
	 */
555.1.19 by Matthew Fuller
Move this initialization outside, since it's presumably possible to
221
	moving_icon = false;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
222
	if(context == C_ICON && tmp_win->icon && tmp_win->icon->w) {
223
		w = tmp_win->icon->w;
224
		DragX = eventp->xbutton.x;
225
		DragY = eventp->xbutton.y;
226
		moving_icon = true;
227
		if(tmp_win->OpaqueMove) {
228
			Scr->OpaqueMove = true;
229
		}
230
	}
231
	else if(! tmp_win->icon || w != tmp_win->icon->w) {
232
		XTranslateCoordinates(dpy, w, tmp_win->frame,
233
		                      eventp->xbutton.x,
234
		                      eventp->xbutton.y,
235
		                      &DragX, &DragY, &JunkChild);
236
237
		w = tmp_win->frame;
238
	}
239
240
	DragWindow = None;
241
242
	/* Get x/y relative to parent window, i.e. the virtual screen, Root.
243
	 * XMoveWindow() moves are relative to this.
244
	 * MoveOutline()s however are drawn from the XineramaRoot since they
245
	 * may cross virtual screens.
246
	 */
247
	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
248
	             &DragWidth, &DragHeight, &DragBW,
249
	             &JunkDepth);
250
251
	origX = eventp->xbutton.x_root;
252
	origY = eventp->xbutton.y_root;
253
	CurrentDragX = origDragX;
254
	CurrentDragY = origDragY;
255
256
	/*
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
257
	 * Setup ConstrainedMove if this is a double-click.  That means
258
	 * setting the flags, and moving the pointer off to the middle of the
259
	 * window.
260
	 *
261
	 * Only do the constrained move if timer is set; need to check it
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
262
	 * in case of stupid or wicked fast servers
263
	 */
264
	if(ConstrainedMoveTime &&
265
	                (eventp->xbutton.time - last_time) < ConstrainedMoveTime) {
266
		int width, height;
267
268
		ConstMove = true;
269
		ConstMoveDir = MOVE_NONE;
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
270
		ConstMoveX = eventp->xbutton.x_root - DragX - DragBW;
271
		ConstMoveY = eventp->xbutton.y_root - DragY - DragBW;
272
		width = DragWidth + 2 * DragBW;
273
		height = DragHeight + 2 * DragBW;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
274
		ConstMoveXL = ConstMoveX + width / 3;
275
		ConstMoveXR = ConstMoveX + 2 * (width / 3);
276
		ConstMoveYT = ConstMoveY + height / 3;
277
		ConstMoveYB = ConstMoveY + 2 * (height / 3);
278
279
		XWarpPointer(dpy, None, w,
280
		             0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
281
282
		XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
283
		              &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
284
	}
285
	last_time = eventp->xbutton.time;
286
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
287
	/* If not moving opaquely, setup the outline bits */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
288
	if(!Scr->OpaqueMove) {
289
		InstallRootColormap();
290
		if(!Scr->MoveDelta) {
291
			/*
292
			 * Draw initial outline.  This was previously done the
293
			 * first time though the outer loop by dropping out of
294
			 * the XCheckMaskEvent inner loop down to one of the
295
			 * MoveOutline's below.
296
			 */
297
			MoveOutline(dragroot,
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
298
			            origDragX - DragBW + Scr->currentvs->x,
299
			            origDragY - DragBW + Scr->currentvs->y,
300
			            DragWidth + 2 * DragBW, DragHeight + 2 * DragBW,
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
301
			            tmp_win->frame_bw,
302
			            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
303
			/*
304
			 * This next line causes HandleReleaseNotify to call
305
			 * XRaiseWindow().  This is solely to preserve the
306
			 * previous behaviour that raises a window being moved
307
			 * on button release even if you never actually moved
308
			 * any distance (unless you move less than MoveDelta or
309
			 * NoRaiseMove is set or OpaqueMove is set).
310
			 */
311
			DragWindow = w;
312
		}
313
	}
314
555.1.15 by Matthew Fuller
Pull this var back out in scope; I think it needs to live through
315
	/*
316
	 * Init whether triggered from something on the titlebar (e.g., a
317
	 * TitleButton bound to f.move).  We need to keep this var in a scope
318
	 * outside the event loop below because the resetting of it in there
319
	 * is supposed to have effect on future loops.
320
	 */
321
	fromtitlebar = belongs_to_twm_window(tmp_win, eventp->xbutton.window);
322
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
323
	if(menuFromFrameOrWindowOrTitlebar) {
324
		/* warp the pointer to the middle of the window */
325
		XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
326
		             origDragX + DragWidth / 2,
327
		             origDragY + DragHeight / 2);
328
		XFlush(dpy);
329
	}
330
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
331
	/* Fill in the position window with where we're starting */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
332
	DisplayPosition(tmp_win, CurrentDragX, CurrentDragY);
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
333
334
	/*
335
	 * Internal event loop for doing the moving.
336
	 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
337
	while(1) {
555.1.12 by Matthew Fuller
Mark these up as const for documentation purposes.
338
		const long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
339
		                          ButtonPress : ButtonRelease;
340
		const long movementMask = menuFromFrameOrWindowOrTitlebar ?
341
		                          PointerMotionMask : ButtonMotionMask;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
342
343
		/* block until there is an interesting event */
344
		XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
345
		           EnterWindowMask | LeaveWindowMask |
346
		           ExposureMask | movementMask |
347
		           VisibilityChangeMask, &Event);
348
349
		/* throw away enter and leave events until release */
350
		if(Event.xany.type == EnterNotify ||
351
		                Event.xany.type == LeaveNotify) {
352
			continue;
353
		}
354
555.1.13 by Matthew Fuller
Pull out comment to higher level for consistency.
355
		/* discard any extra motion events before a logical release */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
356
		if(Event.type == MotionNotify) {
555.1.14 by Matthew Fuller
Unbreak line.
357
			while(XCheckMaskEvent(dpy, movementMask | releaseEvent, &Event))
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
358
				if(Event.type == releaseEvent) {
359
					break;
360
				}
361
		}
362
363
		/* test to see if we have a second button press to abort move */
364
		if(!menuFromFrameOrWindowOrTitlebar) {
365
			if(Event.type == ButtonPress && DragWindow != None) {
366
				Cursor cur;
367
				if(Scr->OpaqueMove) {
368
					XMoveWindow(dpy, DragWindow, origDragX, origDragY);
369
					if(moving_icon) {
370
						tmp_win->icon->w_x = origDragX;
371
						tmp_win->icon->w_y = origDragY;
372
					}
373
				}
374
				else {
375
					MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
376
				}
377
				DragWindow = None;
378
379
				XUnmapWindow(dpy, Scr->SizeWindow);
380
				cur = LeftButt;
381
				if(Event.xbutton.button == Button2) {
382
					cur = MiddleButt;
383
				}
384
				else if(Event.xbutton.button >= Button3) {
385
					cur = RightButt;
386
				}
387
388
				XGrabPointer(dpy, Scr->Root, True,
389
				             ButtonReleaseMask | ButtonPressMask,
390
				             GrabModeAsync, GrabModeAsync,
391
				             Scr->Root, cur, CurrentTime);
392
				func_reset_cursor = false;  // Leave cursor alone
393
				return;
394
			}
395
		}
396
397
		if(fromtitlebar && Event.type == ButtonPress) {
398
			fromtitlebar = false;
399
			CurrentDragX = origX = Event.xbutton.x_root;
400
			CurrentDragY = origY = Event.xbutton.y_root;
401
			XTranslateCoordinates(dpy, rootw, tmp_win->frame,
402
			                      origX, origY,
403
			                      &DragX, &DragY, &JunkChild);
404
			continue;
405
		}
406
407
		if(!DispatchEvent2()) {
408
			continue;
409
		}
410
411
		if(Cancel) {
412
			WindowMoved = false;
413
			if(!Scr->OpaqueMove) {
414
				UninstallRootColormap();
415
			}
416
			func_reset_cursor = false;  // Leave cursor alone
417
			return;
418
		}
419
		if(Event.type == releaseEvent) {
420
			MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
421
			if(moving_icon &&
422
			                ((CurrentDragX != origDragX ||
423
			                  CurrentDragY != origDragY))) {
424
				tmp_win->icon_moved = true;
425
			}
426
			if(!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) {
427
				int xl = Event.xbutton.x_root - (DragWidth  / 2),
428
				    yt = Event.xbutton.y_root - (DragHeight / 2);
429
				if(!moving_icon &&
430
				                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
431
					TryToPack(tmp_win, &xl, &yt);
432
				}
433
				XMoveWindow(dpy, DragWindow, xl, yt);
434
			}
435
			if(menuFromFrameOrWindowOrTitlebar) {
436
				DragWindow = None;
437
			}
438
			break;
439
		}
440
441
		/* something left to do only if the pointer moved */
442
		if(Event.type != MotionNotify) {
443
			continue;
444
		}
445
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
446
		/* Get info about where the pointer is */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
447
		XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
448
		              &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
449
		              &JunkX, &JunkY, &JunkMask);
450
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
451
		/*
452
		 * Tweak up for root.  XXX Is this even right?  There are too
453
		 * many Root's, and this corrects for a specific one, but I'm not
454
		 * sure it's the right one...
455
		 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
456
		FixRootEvent(eventp);
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
457
458
		/* Tweak for window box, if this is in one */
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
459
#ifdef WINBOX
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
460
		if(tmp_win->winbox) {
461
			XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
462
			                      eventp->xmotion.x_root, eventp->xmotion.y_root,
463
			                      &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild);
464
		}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
465
#endif
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
466
467
		/*
468
		 * If we haven't moved MoveDelta yet, we're not yet sure we're
469
		 * doing anything, so just loop back around.
470
		 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
471
		if(DragWindow == None &&
472
		                abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
473
		                abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta) {
474
			continue;
475
		}
476
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
477
		/*
478
		 * Now we know we're moving whatever the window is.
479
		 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
480
		DragWindow = w;
481
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
482
		/* Raise when the move starts if we should */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
483
		if(!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) {
555.1.9 by Matthew Fuller
Move this var into the inner scope where it's used.
484
			TwmWindow *t;
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
485
486
			/*
487
			 * XXX In several of the error cases listed in here, it's
488
			 * seems almost that we should just abort the whole move
489
			 * process immediately if any of them are hit, because things
490
			 * get nonsensical.
491
			 */
492
493
			/* Find TwmWindow bits related to what we're dragging */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
494
			if(XFindContext(dpy, DragWindow, TwmContext, (XPointer *) &t) == XCNOENT) {
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
495
				fprintf(stderr, "%s(): Can't find TwmWindow.\n", __func__);
496
				/* XXX abort? */
497
				t = NULL;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
498
			}
499
500
			if(t != tmp_win) {
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
501
				fprintf(stderr, "%s(): DragWindow isn't tmp_win!\n", __func__);
502
				/* XXX abort? */
503
			}
504
505
			if(t == NULL) {
506
				/* Don't try doing this stuff... */
507
			}
508
			else if(DragWindow == t->frame) {
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
509
				if(moving_icon) {
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
510
					fprintf(stderr, "%s(): moving_icon is true incorrectly!\n",
511
					        __func__);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
512
				}
513
				OtpRaise(t, WinWin);
514
			}
515
			else if(t->icon && DragWindow == t->icon->w) {
516
				if(!moving_icon) {
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
517
					fprintf(stderr, "%s(): moving_icon is false incorrectly!\n",
518
					        __func__);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
519
				}
520
				OtpRaise(t, IconWin);
521
			}
522
			else {
555.1.18 by Matthew Fuller
Improve these warnings in the raising so they actually say something
523
				fprintf(stderr, "%s(): Couldn't figure what to raise.\n",
524
				        __func__);
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
525
			}
526
		}
527
528
		WindowMoved = true;
529
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
530
		/*
531
		 * Handle moving the step
532
		 */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
533
		if(ConstMove) {
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
534
			/* Did we already decide it's constrained?  Do that. */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
535
			switch(ConstMoveDir) {
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
536
				case MOVE_NONE: {
537
					/* Haven't figured direction yet, so do so */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
538
					if(eventp->xmotion.x_root < ConstMoveXL ||
539
					                eventp->xmotion.x_root > ConstMoveXR) {
540
						ConstMoveDir = MOVE_HORIZ;
541
					}
542
543
					if(eventp->xmotion.y_root < ConstMoveYT ||
544
					                eventp->xmotion.y_root > ConstMoveYB) {
545
						ConstMoveDir = MOVE_VERT;
546
					}
547
548
					XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
549
					              &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
550
					break;
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
551
				}
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
552
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
553
				/* We know which dir it's contrained to, so figure amount */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
554
				case MOVE_VERT:
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
555
					ConstMoveY = eventp->xmotion.y_root - DragY - DragBW;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
556
					break;
557
558
				case MOVE_HORIZ:
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
559
					ConstMoveX = eventp->xmotion.x_root - DragX - DragBW;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
560
					break;
561
			}
562
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
563
			/* We've got a move to do, so do it */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
564
			if(ConstMoveDir != MOVE_NONE) {
565
				int xl, yt, width, height;
566
567
				xl = ConstMoveX;
568
				yt = ConstMoveY;
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
569
				width = DragWidth + 2 * DragBW;
570
				height = DragHeight + 2 * DragBW;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
571
572
				if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
573
					TryToGrid(tmp_win, &xl, &yt);
574
				}
575
				if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
576
					TryToPush(tmp_win, xl, yt);
577
				}
578
579
				if(!moving_icon &&
580
				                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
581
					TryToPack(tmp_win, &xl, &yt);
582
				}
583
584
				if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
585
					ConstrainByBorders(tmp_win, &xl, width, &yt, height);
586
				}
587
				CurrentDragX = xl;
588
				CurrentDragY = yt;
589
				if(Scr->OpaqueMove) {
590
					if(MoveFunction == F_MOVEPUSH && !moving_icon) {
591
						SetupWindow(tmp_win, xl, yt,
592
						            tmp_win->frame_width, tmp_win->frame_height, -1);
593
					}
594
					else {
595
						XMoveWindow(dpy, DragWindow, xl, yt);
596
						if(moving_icon) {
597
							tmp_win->icon->w_x = xl;
598
							tmp_win->icon->w_y = yt;
599
						}
600
					}
601
					WMapSetupWindow(tmp_win, xl, yt, -1, -1);
602
				}
603
				else {
604
					MoveOutline(dragroot, xl + Scr->currentvs->x,
605
					            yt + Scr->currentvs->y, width, height,
606
					            tmp_win->frame_bw,
607
					            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
608
				}
609
			}
610
		}
611
		else if(DragWindow != None) {
612
			/*
555.1.17 by Matthew Fuller
const-ify these vars where they're trivial to do so, for documentation
613
			 * There's a non-constrained move to process
614
			 *
615
			 * This is split out for virtual screens.  In that case, it's
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
616
			 * possible to drag windows from one workspace to another, and
617
			 * as such, these need to be adjusted to the root, rather
618
			 * than this virtual screen...
619
			 */
555.1.17 by Matthew Fuller
const-ify these vars where they're trivial to do so, for documentation
620
			const int xroot = eventp->xmotion.x_root;
621
			const int yroot = eventp->xmotion.y_root;
622
			const int width  = DragWidth + 2 * DragBW;
623
			const int height = DragHeight + 2 * DragBW;
624
			int xl, yt;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
625
626
			if(!menuFromFrameOrWindowOrTitlebar) {
555.1.4 by Matthew Fuller
Eliminate brdw var. Its only purpose seems to be that it's 2 chars
627
				xl = xroot - DragX - DragBW;
628
				yt = yroot - DragY - DragBW;
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
629
			}
630
			else {
631
				xl = xroot - (DragWidth / 2);
632
				yt = yroot - (DragHeight / 2);
633
			}
634
635
			if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
636
				TryToGrid(tmp_win, &xl, &yt);
637
			}
638
			if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
639
				TryToPush(tmp_win, xl, yt);
640
			}
641
642
			if(!moving_icon &&
643
			                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
644
				TryToPack(tmp_win, &xl, &yt);
645
			}
646
647
			if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
648
				ConstrainByBorders(tmp_win, &xl, width, &yt, height);
649
			}
650
651
			CurrentDragX = xl;
652
			CurrentDragY = yt;
653
			if(Scr->OpaqueMove) {
654
				if(MoveFunction == F_MOVEPUSH && !moving_icon) {
655
					SetupWindow(tmp_win, xl, yt,
656
					            tmp_win->frame_width, tmp_win->frame_height, -1);
657
				}
658
				else {
659
					XMoveWindow(dpy, DragWindow, xl, yt);
660
					if(moving_icon) {
661
						tmp_win->icon->w_x = xl;
662
						tmp_win->icon->w_y = yt;
663
					}
664
				}
665
				if(! moving_icon) {
666
					WMapSetupWindow(tmp_win, xl, yt, -1, -1);
667
				}
668
			}
669
			else {
670
				MoveOutline(dragroot, xl + Scr->currentvs->x,
671
				            yt + Scr->currentvs->y, width, height,
672
				            tmp_win->frame_bw,
673
				            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
674
			}
675
		}
555.1.16 by Matthew Fuller
Add some comments through the innards of the move event loop.
676
677
		/* We've moved a step, so update the displayed position */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
678
		DisplayPosition(tmp_win, CurrentDragX, CurrentDragY);
679
	}
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
680
681
	/* Done, so hide away the position display window */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
682
	XUnmapWindow(dpy, Scr->SizeWindow);
683
555.1.2 by Matthew Fuller
Add a little frame commenting through the f.move-and-friends backend.
684
	/* Restore colormap if we replaced it */
535.1.25 by Matthew Fuller
Move the geometry save/restore and the various window move functions
685
	if(!Scr->OpaqueMove && DragWindow == None) {
686
		UninstallRootColormap();
687
	}
688
689
	return;
690
}
535.1.28 by Matthew Fuller
Pull out the zooming resize funcs.
691
692
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
693
/*
694
 * f.pack -- moving until collision
695
 *
696
 * XXX Collapse this down; no need for an extra level of indirection on
697
 * the function calling.
698
 */
699
static void packwindow(TwmWindow *tmp_win, const char *direction);
700
DFHANDLER(pack)
701
{
702
	if(tmp_win->squeezed) {
703
		XBell(dpy, 0);
704
		return;
705
	}
706
	packwindow(tmp_win, action);
707
}
708
709
static void
710
packwindow(TwmWindow *tmp_win, const char *direction)
711
{
712
	int          cons, newx, newy;
713
	int          x, y, px, py, junkX, junkY;
714
	unsigned int junkK;
715
	Window       junkW;
716
717
	if(!strcmp(direction,   "left")) {
718
		cons  = FindConstraint(tmp_win, MFD_LEFT);
719
		if(cons == -1) {
720
			return;
721
		}
722
		newx  = cons;
723
		newy  = tmp_win->frame_y;
724
	}
725
	else if(!strcmp(direction,  "right")) {
726
		cons  = FindConstraint(tmp_win, MFD_RIGHT);
727
		if(cons == -1) {
728
			return;
729
		}
730
		newx  = cons;
731
		newx -= tmp_win->frame_width + 2 * tmp_win->frame_bw;
732
		newy  = tmp_win->frame_y;
733
	}
734
	else if(!strcmp(direction,    "top")) {
735
		cons  = FindConstraint(tmp_win, MFD_TOP);
736
		if(cons == -1) {
737
			return;
738
		}
739
		newx  = tmp_win->frame_x;
740
		newy  = cons;
741
	}
742
	else if(!strcmp(direction, "bottom")) {
743
		cons  = FindConstraint(tmp_win, MFD_BOTTOM);
744
		if(cons == -1) {
745
			return;
746
		}
747
		newx  = tmp_win->frame_x;
748
		newy  = cons;
749
		newy -= tmp_win->frame_height + 2 * tmp_win->frame_bw;
750
	}
751
	else {
752
		return;
753
	}
754
755
	XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK);
756
	px = x - tmp_win->frame_x + newx;
757
	py = y - tmp_win->frame_y + newy;
758
	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py);
759
	OtpRaise(tmp_win, WinWin);
760
	XMoveWindow(dpy, tmp_win->frame, newx, newy);
761
	SetupWindow(tmp_win, newx, newy, tmp_win->frame_width,
762
	            tmp_win->frame_height, -1);
763
}
764
765
766
/*
767
 * f.jump* -- moving incrementally in various directions
768
 */
769
static void jump(TwmWindow *tmp_win, MoveFillDir direction, const char *action);
770
DFHANDLER(jumpleft)
771
{
772
	jump(tmp_win, MFD_LEFT, action);
773
}
774
DFHANDLER(jumpright)
775
{
776
	jump(tmp_win, MFD_RIGHT, action);
777
}
778
DFHANDLER(jumpdown)
779
{
780
	jump(tmp_win, MFD_BOTTOM, action);
781
}
782
DFHANDLER(jumpup)
783
{
784
	jump(tmp_win, MFD_TOP, action);
785
}
786
787
static void
788
jump(TwmWindow *tmp_win, MoveFillDir direction, const char *action)
789
{
790
	int          fx, fy, px, py, step, status, cons;
791
	int          fwidth, fheight;
792
	int          junkX, junkY;
793
	unsigned int junkK;
794
	Window       junkW;
795
796
	if(tmp_win->squeezed) {
797
		XBell(dpy, 0);
798
		return;
799
	}
800
801
	if(! action) {
802
		return;
803
	}
804
	status = sscanf(action, "%d", &step);
805
	if(status != 1) {
806
		return;
807
	}
808
	if(step < 1) {
809
		return;
810
	}
811
812
	fx = tmp_win->frame_x;
813
	fy = tmp_win->frame_y;
814
	XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
815
	px -= fx;
816
	py -= fy;
817
818
	fwidth  = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
819
	fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw;
820
	switch(direction) {
821
		case MFD_LEFT:
822
			cons  = FindConstraint(tmp_win, MFD_LEFT);
823
			if(cons == -1) {
824
				return;
825
			}
826
			fx -= step * Scr->XMoveGrid;
827
			if(fx < cons) {
828
				fx = cons;
829
			}
830
			break;
831
		case MFD_RIGHT:
832
			cons  = FindConstraint(tmp_win, MFD_RIGHT);
833
			if(cons == -1) {
834
				return;
835
			}
836
			fx += step * Scr->XMoveGrid;
837
			if(fx + fwidth > cons) {
838
				fx = cons - fwidth;
839
			}
840
			break;
841
		case MFD_TOP:
842
			cons  = FindConstraint(tmp_win, MFD_TOP);
843
			if(cons == -1) {
844
				return;
845
			}
846
			fy -= step * Scr->YMoveGrid;
847
			if(fy < cons) {
848
				fy = cons;
849
			}
850
			break;
851
		case MFD_BOTTOM:
852
			cons  = FindConstraint(tmp_win, MFD_BOTTOM);
853
			if(cons == -1) {
854
				return;
855
			}
856
			fy += step * Scr->YMoveGrid;
857
			if(fy + fheight > cons) {
858
				fy = cons - fheight;
859
			}
860
			break;
861
	}
862
	/* Pebl Fixme: don't warp if jump happens through iconmgr */
863
	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py);
864
	if(!Scr->NoRaiseMove) {
865
		OtpRaise(tmp_win, WinWin);
866
	}
867
	SetupWindow(tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1);
868
}
869
870
871
872
/*
873
 *********************************************************
874
 *
875
 * Next up, straightforward resizing operations
876
 *
877
 *********************************************************
878
 */
879
880
/*
881
 * Standard f.resize
535.1.30 by Matthew Fuller
Pull out f.resize.
882
 */
883
DFHANDLER(resize)
884
{
885
	PopDownMenu();
886
	if(tmp_win->squeezed) {
887
		XBell(dpy, 0);
888
		return;
889
	}
890
	EventHandler[EnterNotify] = HandleUnknown;
891
	EventHandler[LeaveNotify] = HandleUnknown;
892
893
	OpaqueResizeSize(tmp_win);
894
895
	if(pulldown)
896
		XWarpPointer(dpy, None, Scr->Root,
897
		             0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
898
899
	if(!tmp_win->icon || (w != tmp_win->icon->w)) {         /* can't resize icons */
900
901
		/*        fromMenu = False;  ????? */
902
		if((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE
903
		                || Context == C_ROOT)
904
		                && cur_fromMenu()) {
905
			resizeFromCenter(w, tmp_win);
906
		}
907
		else {
908
			/*
909
			 * see if this is being done from the titlebar
910
			 */
911
			bool from3dborder = (eventp->xbutton.window == tmp_win->frame);
912
			bool fromtitlebar = !from3dborder &&
913
			                    belongs_to_twm_window(tmp_win, eventp->xbutton.window);
914
915
			/* Save pointer position so we can tell if it was moved or
916
			   not during the resize. */
917
			ResizeOrigX = eventp->xbutton.x_root;
918
			ResizeOrigY = eventp->xbutton.y_root;
919
920
			StartResize(eventp, tmp_win, fromtitlebar, from3dborder);
921
			func_reset_cursor = false;  // Leave special cursor alone
922
923
			do {
924
				XMaskEvent(dpy,
925
				           ButtonPressMask | ButtonReleaseMask |
926
				           EnterWindowMask | LeaveWindowMask |
927
				           ButtonMotionMask | VisibilityChangeMask | ExposureMask, &Event);
928
929
				if(fromtitlebar && Event.type == ButtonPress) {
930
					fromtitlebar = false;
931
					continue;
932
				}
933
934
				if(Event.type == MotionNotify) {
935
					/* discard any extra motion events before a release */
936
					while
937
					(XCheckMaskEvent
938
					                (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
939
						if(Event.type == ButtonRelease) {
940
							break;
941
						}
942
				}
943
944
				if(!DispatchEvent2()) {
945
					continue;
946
				}
947
948
			}
949
			while(!(Event.type == ButtonRelease || Cancel));
950
		}
951
	}
952
	return;
953
}
535.1.31 by Matthew Fuller
Remove f.resize from the switch now that it's external, and pull out
954
955
956
/*
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
957
 * The various zoom resizes
535.1.31 by Matthew Fuller
Remove f.resize from the switch now that it's external, and pull out
958
 */
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
959
DFHANDLER(zoom)
960
{
961
	fullzoom(tmp_win, func);
962
}
963
DFHANDLER(horizoom)
964
{
965
	fullzoom(tmp_win, func);
966
}
967
DFHANDLER(fullzoom)
968
{
969
	fullzoom(tmp_win, func);
970
}
971
DFHANDLER(fullscreenzoom)
972
{
973
	fullzoom(tmp_win, func);
974
}
975
DFHANDLER(leftzoom)
976
{
977
	fullzoom(tmp_win, func);
978
}
979
DFHANDLER(rightzoom)
980
{
981
	fullzoom(tmp_win, func);
982
}
983
DFHANDLER(topzoom)
984
{
985
	fullzoom(tmp_win, func);
986
}
987
DFHANDLER(bottomzoom)
988
{
989
	fullzoom(tmp_win, func);
990
}
535.1.33 by Matthew Fuller
Pull out f.fill and its backing func.
991
614.1.15 by Maxime Soulé
Old f.*zoom functions now limited to current monitor
992
DFHANDLER(xzoom)
993
{
994
	fullzoom(tmp_win, func);
995
}
996
DFHANDLER(xhorizoom)
997
{
998
	fullzoom(tmp_win, func);
999
}
1000
DFHANDLER(xfullzoom)
1001
{
1002
	fullzoom(tmp_win, func);
1003
}
1004
DFHANDLER(xfullscreenzoom)
1005
{
1006
	fullzoom(tmp_win, func);
1007
}
1008
DFHANDLER(xleftzoom)
1009
{
1010
	fullzoom(tmp_win, func);
1011
}
1012
DFHANDLER(xrightzoom)
1013
{
1014
	fullzoom(tmp_win, func);
1015
}
1016
DFHANDLER(xtopzoom)
1017
{
1018
	fullzoom(tmp_win, func);
1019
}
1020
DFHANDLER(xbottomzoom)
1021
{
1022
	fullzoom(tmp_win, func);
1023
}
1024
535.1.33 by Matthew Fuller
Pull out f.fill and its backing func.
1025
1026
/*
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
1027
 * f.fill - resizing until collision
535.1.33 by Matthew Fuller
Pull out f.fill and its backing func.
1028
 *
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
1029
 * XXX Similar to f.pack's, collapse away this extra level of function.
535.1.33 by Matthew Fuller
Pull out f.fill and its backing func.
1030
 */
1031
static void fillwindow(TwmWindow *tmp_win, const char *direction);
1032
DFHANDLER(fill)
1033
{
1034
	if(tmp_win->squeezed) {
1035
		XBell(dpy, 0);
1036
		return;
1037
	}
1038
	fillwindow(tmp_win, action);
1039
}
1040
1041
static void
1042
fillwindow(TwmWindow *tmp_win, const char *direction)
1043
{
1044
	int cons, newx, newy, save;
1045
	unsigned int neww, newh;
1046
	int i;
1047
	const int winx = tmp_win->frame_x;
1048
	const int winy = tmp_win->frame_y;
1049
	const int winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
1050
	const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
1051
1052
	if(!strcmp(direction, "left")) {
1053
		cons = FindConstraint(tmp_win, MFD_LEFT);
1054
		if(cons == -1) {
1055
			return;
1056
		}
1057
		newx = cons;
1058
		newy = tmp_win->frame_y;
1059
		neww = winw + winx - newx;
1060
		newh = winh;
1061
		neww -= 2 * tmp_win->frame_bw;
1062
		newh -= 2 * tmp_win->frame_bw;
1063
		ConstrainSize(tmp_win, &neww, &newh);
1064
	}
1065
	else if(!strcmp(direction, "right")) {
1066
		for(i = 0; i < 2; i++) {
1067
			cons = FindConstraint(tmp_win, MFD_RIGHT);
1068
			if(cons == -1) {
1069
				return;
1070
			}
1071
			newx = tmp_win->frame_x;
1072
			newy = tmp_win->frame_y;
1073
			neww = cons - winx;
1074
			newh = winh;
1075
			save = neww;
1076
			neww -= 2 * tmp_win->frame_bw;
1077
			newh -= 2 * tmp_win->frame_bw;
1078
			ConstrainSize(tmp_win, &neww, &newh);
1079
			if((neww != winw) || (newh != winh) ||
1080
			                (cons == Scr->rootw - Scr->BorderRight)) {
1081
				break;
1082
			}
1083
			neww = save;
1084
			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
1085
		}
1086
	}
1087
	else if(!strcmp(direction, "top")) {
1088
		cons = FindConstraint(tmp_win, MFD_TOP);
1089
		if(cons == -1) {
1090
			return;
1091
		}
1092
		newx = tmp_win->frame_x;
1093
		newy = cons;
1094
		neww = winw;
1095
		newh = winh + winy - newy;
1096
		neww -= 2 * tmp_win->frame_bw;
1097
		newh -= 2 * tmp_win->frame_bw;
1098
		ConstrainSize(tmp_win, &neww, &newh);
1099
	}
1100
	else if(!strcmp(direction, "bottom")) {
1101
		for(i = 0; i < 2; i++) {
1102
			cons = FindConstraint(tmp_win, MFD_BOTTOM);
1103
			if(cons == -1) {
1104
				return;
1105
			}
1106
			newx = tmp_win->frame_x;
1107
			newy = tmp_win->frame_y;
1108
			neww = winw;
1109
			newh = cons - winy;
1110
			save = newh;
1111
			neww -= 2 * tmp_win->frame_bw;
1112
			newh -= 2 * tmp_win->frame_bw;
1113
			ConstrainSize(tmp_win, &neww, &newh);
1114
			if((neww != winw) || (newh != winh) ||
1115
			                (cons == Scr->rooth - Scr->BorderBottom)) {
1116
				break;
1117
			}
1118
			newh = save;
1119
			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
1120
		}
1121
	}
1122
	else if(!strcmp(direction, "vertical")) {
1123
		if(tmp_win->zoomed == ZOOM_NONE) {
1124
			tmp_win->save_frame_height = tmp_win->frame_height;
1125
			tmp_win->save_frame_width = tmp_win->frame_width;
1126
			tmp_win->save_frame_y = tmp_win->frame_y;
1127
			tmp_win->save_frame_x = tmp_win->frame_x;
1128
1129
			tmp_win->frame_y++;
1130
			newy = FindConstraint(tmp_win, MFD_TOP);
1131
			tmp_win->frame_y--;
1132
			newh = FindConstraint(tmp_win, MFD_BOTTOM) - newy;
1133
			newh -= 2 * tmp_win->frame_bw;
1134
1135
			newx = tmp_win->frame_x;
1136
			neww = tmp_win->frame_width;
1137
1138
			ConstrainSize(tmp_win, &neww, &newh);
1139
1140
			/* if the bottom of the window has moved up
1141
			 * it will be pushed down */
1142
			if(newy + newh < tmp_win->save_frame_y + tmp_win->save_frame_height) {
1143
				newy = tmp_win->save_frame_y +
1144
				       tmp_win->save_frame_height - newh;
1145
			}
1146
			tmp_win->zoomed = F_ZOOM;
1147
			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
1148
		}
1149
		else {
1150
			fullzoom(tmp_win, tmp_win->zoomed);
1151
		}
1152
		return;
1153
	}
1154
	else {
1155
		return;
1156
	}
1157
	SetupWindow(tmp_win, newx, newy, neww, newh, -1);
1158
}
535.1.34 by Matthew Fuller
Pull out the f.jump* bits.
1159
1160
1161
1162
/*
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
1163
 *********************************************************
1164
 *
1165
 * Resizing/moving to specified geometries
1166
 *
1167
 *********************************************************
1168
 */
1169
1170
/*
1171
 * Resizing to a window's idea of its "normal" size, from WM_NORMAL_HINTS
1172
 * property.
1173
 */
1174
DFHANDLER(initsize)
1175
{
1176
	int grav, x, y;
1177
	unsigned int width, height, swidth, sheight;
1178
1179
	grav = ((tmp_win->hints.flags & PWinGravity)
1180
	        ? tmp_win->hints.win_gravity : NorthWestGravity);
1181
1182
	if(!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) {
1183
		return;
1184
	}
1185
1186
	width  = tmp_win->hints.width  + 2 * tmp_win->frame_bw3D;
1187
	height  = tmp_win->hints.height + 2 * tmp_win->frame_bw3D +
1188
	          tmp_win->title_height;
1189
	ConstrainSize(tmp_win, &width, &height);
1190
1191
	x  = tmp_win->frame_x;
1192
	y  = tmp_win->frame_y;
1193
	swidth = tmp_win->frame_width;
1194
	sheight = tmp_win->frame_height;
1195
1196
	switch(grav) {
1197
		case ForgetGravity:
1198
		case StaticGravity:
1199
		case NorthWestGravity:
1200
		case NorthGravity:
1201
		case WestGravity:
1202
		case CenterGravity:
1203
			break;
1204
1205
		case NorthEastGravity:
1206
		case EastGravity:
1207
			x += swidth - width;
1208
			break;
1209
1210
		case SouthWestGravity:
1211
		case SouthGravity:
1212
			y += sheight - height;
1213
			break;
1214
1215
		case SouthEastGravity:
1216
			x += swidth - width;
1217
			y += sheight - height;
1218
			break;
1219
	}
1220
1221
	SetupWindow(tmp_win, x, y, width, height, -1);
1222
	return;
1223
}
1224
1225
1226
/*
1227
 * Setting a window to a specific specified geometry string.
1228
 */
1229
DFHANDLER(moveresize)
1230
{
1231
	int x, y, mask;
1232
	unsigned int width, height;
1233
	int px = 20, py = 30;
1234
614.1.23 by Maxime Soulé
Some geometries can be relative to a monitor
1235
	mask = RLayoutXParseGeometry(Scr->Layout, action, &x, &y, &width, &height);
535.1.38 by Matthew Fuller
Reorganize this file so similar bits are grouped better, with headers
1236
	if(!(mask &  WidthValue)) {
1237
		width = tmp_win->frame_width;
1238
	}
1239
	else {
1240
		width += 2 * tmp_win->frame_bw3D;
1241
	}
1242
	if(!(mask & HeightValue)) {
1243
		height = tmp_win->frame_height;
1244
	}
1245
	else {
1246
		height += 2 * tmp_win->frame_bw3D + tmp_win->title_height;
1247
	}
1248
	ConstrainSize(tmp_win, &width, &height);
1249
	if(mask & XValue) {
1250
		if(mask & XNegative) {
1251
			x += Scr->rootw  - width;
1252
		}
1253
	}
1254
	else {
1255
		x = tmp_win->frame_x;
1256
	}
1257
	if(mask & YValue) {
1258
		if(mask & YNegative) {
1259
			y += Scr->rooth - height;
1260
		}
1261
	}
1262
	else {
1263
		y = tmp_win->frame_y;
1264
	}
1265
1266
	{
1267
		int          junkX, junkY;
1268
		unsigned int junkK;
1269
		Window       junkW;
1270
		XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
1271
	}
1272
	px -= tmp_win->frame_x;
1273
	if(px > width) {
1274
		px = width / 2;
1275
	}
1276
	py -= tmp_win->frame_y;
1277
	if(py > height) {
1278
		px = height / 2;
1279
	}
1280
1281
	SetupWindow(tmp_win, x, y, width, height, -1);
1282
	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py);
1283
	return;
1284
}
1285
1286
1287
/*
1288
 * Making a specified alteration to a window's size
1289
 */
1290
DFHANDLER(changesize)
1291
{
1292
	/* XXX Only use of this func; should we collapse? */
1293
	ChangeSize(action, tmp_win);
1294
}
1295
1296
1297
/*
1298
 * Stashing and flipping back to a geometry
1299
 */
1300
DFHANDLER(savegeometry)
1301
{
1302
	savegeometry(tmp_win);
1303
}
1304
1305
DFHANDLER(restoregeometry)
1306
{
1307
	restoregeometry(tmp_win);
1308
}
1309
1310
1311
1312
1313
/*
1314
 *********************************************************
1315
 *
1316
 * Misc utils used in the above
1317
 *
1318
 *********************************************************
1319
 */
1320
1321
/*
1322
 * Used in the various move/fill/pack/etc bits
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1323
 */
1324
static int
1325
FindConstraint(TwmWindow *tmp_win, MoveFillDir direction)
1326
{
1327
	TwmWindow  *t;
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1328
	int ret, limit;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1329
	const int winx = tmp_win->frame_x;
1330
	const int winy = tmp_win->frame_y;
1331
	const int winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
1332
	const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
1333
614.1.25 by Maxime Soulé
RArea struct is never malloc()ed anymore
1334
	RArea area = RAreaNew(winx, winy, winw, winh);
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1335
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1336
	switch(direction) {
1337
		case MFD_LEFT:
614.1.12 by Maxime Soulé
f.fill, f.pack & f.jump* functions detect inter-monitors edges
1338
			limit = RLayoutFindMonitorLeftEdge(Scr->BorderedLayout, &area);
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1339
			if(winx < limit) {
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1340
				return -1;
1341
			}
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1342
			ret = limit;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1343
			break;
1344
		case MFD_RIGHT:
614.1.12 by Maxime Soulé
f.fill, f.pack & f.jump* functions detect inter-monitors edges
1345
			limit = RLayoutFindMonitorRightEdge(Scr->BorderedLayout, &area);
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1346
			if(winx + winw > limit) {
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1347
				return -1;
1348
			}
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1349
			ret = limit + 1;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1350
			break;
1351
		case MFD_TOP:
614.1.12 by Maxime Soulé
f.fill, f.pack & f.jump* functions detect inter-monitors edges
1352
			limit = RLayoutFindMonitorTopEdge(Scr->BorderedLayout, &area);
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1353
			if(winy < limit) {
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1354
				return -1;
1355
			}
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1356
			ret = limit;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1357
			break;
1358
		case MFD_BOTTOM:
614.1.12 by Maxime Soulé
f.fill, f.pack & f.jump* functions detect inter-monitors edges
1359
			limit = RLayoutFindMonitorBottomEdge(Scr->BorderedLayout, &area);
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1360
			if(winy + winh > limit) {
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1361
				return -1;
1362
			}
614.1.7 by Maxime Soulé
FindConstraint() now uses layout
1363
			ret = limit + 1;
535.1.35 by Matthew Fuller
Now we can move FindConstraint() and the related enum type wholly into
1364
			break;
1365
		default:
1366
			return -1;
1367
	}
1368
	for(t = Scr->FirstWindow; t != NULL; t = t->next) {
1369
		const int w = t->frame_width  + 2 * t->frame_bw;
1370
		const int h = t->frame_height + 2 * t->frame_bw;
1371
1372
		if(t == tmp_win) {
1373
			continue;
1374
		}
1375
		if(!visible(t)) {
1376
			continue;
1377
		}
1378
		if(!t->mapped) {
1379
			continue;
1380
		}
1381
1382
		switch(direction) {
1383
			case MFD_LEFT:
1384
				if(winx        <= t->frame_x + w) {
1385
					continue;
1386
				}
1387
				if(winy        >= t->frame_y + h) {
1388
					continue;
1389
				}
1390
				if(winy + winh <= t->frame_y) {
1391
					continue;
1392
				}
1393
				ret = MAX(ret, t->frame_x + w);
1394
				break;
1395
			case MFD_RIGHT:
1396
				if(winx + winw >= t->frame_x) {
1397
					continue;
1398
				}
1399
				if(winy        >= t->frame_y + h) {
1400
					continue;
1401
				}
1402
				if(winy + winh <= t->frame_y) {
1403
					continue;
1404
				}
1405
				ret = MIN(ret, t->frame_x);
1406
				break;
1407
			case MFD_TOP:
1408
				if(winy        <= t->frame_y + h) {
1409
					continue;
1410
				}
1411
				if(winx        >= t->frame_x + w) {
1412
					continue;
1413
				}
1414
				if(winx + winw <= t->frame_x) {
1415
					continue;
1416
				}
1417
				ret = MAX(ret, t->frame_y + h);
1418
				break;
1419
			case MFD_BOTTOM:
1420
				if(winy + winh >= t->frame_y) {
1421
					continue;
1422
				}
1423
				if(winx        >= t->frame_x + w) {
1424
					continue;
1425
				}
1426
				if(winx + winw <= t->frame_x) {
1427
					continue;
1428
				}
1429
				ret = MIN(ret, t->frame_y);
1430
				break;
1431
		}
1432
	}
1433
	return ret;
1434
}
535.1.64 by Matthew Fuller
belongs_to_twm_window() is only used with the move/resize bits, so
1435
1436
1437
/*
1438
 * Is Window w part of the conglomerate of metawindows we put around the
1439
 * real window for TwmWindow t?  Note that this does _not_ check if w is
1440
 * the actual window we built the TwmWindow t around.
1441
 */
1442
static bool
1443
belongs_to_twm_window(TwmWindow *t, Window w)
1444
{
1445
	/* Safety */
1446
	if(!t) {
1447
		return false;
1448
	}
1449
1450
	/* Part of the framing we put around the window? */
1451
	if(w == t->frame || w == t->title_w
1452
	                || w == t->hilite_wl || w == t->hilite_wr) {
1453
		return true;
1454
	}
1455
1456
	/* Part of the icon bits? */
1457
	if(t->icon && (w == t->icon->w || w == t->icon->bm_w)) {
1458
		return true;
1459
	}
1460
1461
	/* One of the title button windows? */
1462
	if(t->titlebuttons) {
1463
		TBWindow *tbw;
1464
		int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1465
		for(tbw = t->titlebuttons ; nb > 0 ; tbw++, nb--) {
1466
			if(tbw->window == w) {
1467
				return true;
1468
			}
1469
		}
1470
	}
1471
1472
	/* Then no */
1473
	return false;
1474
}