1/*
2 *       Copyright 1988 by Evans & Sutherland Computer Corporation,
3 *                          Salt Lake City, Utah
4 *  Portions Copyright 1989 by the Massachusetts Institute of Technology
5 *                        Cambridge, Massachusetts
6 *
7 * Copyright 1992 Claude Lecommandeur.
8 */
9
10/***********************************************************************
11 *
12 * $XConsortium: resize.c,v 1.80 91/05/11 17:35:42 dave Exp $
13 *
14 * window resizing borrowed from the "wm" window manager
15 *
16 * 11-Dec-87 Thomas E. LaStrange                File created
17 *
18 * Do the necessary modification to be integrated in ctwm.
19 * Can no longer be used for the standard twm.
20 *
21 * 22-April-92 Claude Lecommandeur.
22 *
23 *
24 ***********************************************************************/
25
26#include "ctwm.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30
31#include "events.h"
32#include "util.h"
33#include "otp.h"
34#include "functions_defs.h"
35#include "add_window.h"
36#include "colormaps.h"
37#include "screen.h"
38#include "drawing.h"
39#include "r_area.h"
40#include "r_area_list.h"
41#include "r_layout.h"
42#include "win_decorations.h"
43#include "win_ops.h"
44#include "win_resize.h"
45#include "win_utils.h"
46#include "workspace_manager.h"
47#include "iconmgr.h"
48
49#define MINHEIGHT 0     /* had been 32 */
50#define MINWIDTH 0      /* had been 60 */
51
52static int dragx;       /* all these variables are used */
53static int dragy;       /* in resize operations */
54static unsigned int dragWidth;
55static unsigned int dragHeight;
56
57static int origx;
58static int origy;
59static int origWidth;
60static int origHeight;
61
62static int clampTop;
63static int clampBottom;
64static int clampLeft;
65static int clampRight;
66static int clampDX;
67static int clampDY;
68
69static int last_width;
70static int last_height;
71
72static unsigned int resizeGrabMask;
73
74static void DisplaySize(TwmWindow *tmp_win, int width, int height);
75
76static void do_auto_clamp(TwmWindow *tmp_win, XEvent *evp)
77{
78	Window junkRoot;
79	int x, y, h, v, junkbw;
80	unsigned int junkMask;
81
82	switch(evp->type) {
83		case ButtonPress:
84			x = evp->xbutton.x_root;
85			y = evp->xbutton.y_root;
86			break;
87		case KeyPress:
88			x = evp->xkey.x_root;
89			y = evp->xkey.y_root;
90			break;
91		default:
92			if(!XQueryPointer(dpy, Scr->Root, &junkRoot, &junkRoot,
93			                  &x, &y, &junkbw, &junkbw, &junkMask)) {
94				return;
95			}
96	}
97
98	/*
99	 * Determine in which of the 9 "quadrants" of the window we are.
100	 * Cast the values to signed int: if the numerator is negative
101	 * we don't want them converted to unsigned due to the default
102	 * promotion rules: that would produce a very large quotient.
103	 */
104	h = (int)(x - dragx) / (int)(dragWidth < 3 ? 1 : (dragWidth / 3));
105	v = (int)(y - dragy - tmp_win->title_height) /
106	    (int)(dragHeight < 3 ? 1 : (dragHeight / 3));
107
108	if(h <= 0) {
109		clampLeft = 1;
110		clampDX = (x - dragx);
111	}
112	else if(h >= 2) {
113		clampRight = 1;
114		clampDX = (x - dragx - dragWidth);
115	}
116
117	if(v <= 0) {
118		clampTop = 1;
119		clampDY = (y - dragy);
120	}
121	else if(v >= 2) {
122		clampBottom = 1;
123		clampDY = (y - dragy - dragHeight);
124	}
125}
126
127/***********************************************************************
128 *
129 *  Procedure:
130 *      OpaqueResizeSize - determine if window should be resized opaquely.
131 *
132 *  Inputs:
133 *      tmp_win - the TwmWindow pointer
134 *
135 ***********************************************************************
136 */
137
138void OpaqueResizeSize(TwmWindow *tmp_win)
139{
140	if(tmp_win->OpaqueResize) {
141		/*
142		 * OpaqueResize defaults to a thousand.  Assume that any number
143		 * >= 1000 is "infinity" and don't bother calculating.
144		 */
145		if(Scr->OpaqueResizeThreshold >= 1000) {
146			Scr->OpaqueResize = true;
147		}
148		else {
149			/*
150			 * scrsz will hold the number of pixels in your resolution,
151			 * which can get big.  [signed] int may not cut it.
152			 */
153			const unsigned long winsz = tmp_win->frame_width
154			                            * tmp_win->frame_height;
155			const unsigned long scrsz = Scr->rootw  * Scr->rooth;
156			if(winsz > (scrsz * (Scr->OpaqueResizeThreshold / 100.0))) {
157				Scr->OpaqueResize = false;
158			}
159			else {
160				Scr->OpaqueResize = true;
161			}
162		}
163	}
164	else {
165		Scr->OpaqueResize = false;
166	}
167}
168
169
170/***********************************************************************
171 *
172 *  Procedure:
173 *      StartResize - begin a window resize operation
174 *
175 *  Inputs:
176 *      ev      - the event structure (button press)
177 *      tmp_win - the TwmWindow pointer
178 *      fromtitlebar - action invoked from titlebar button
179 *
180 ***********************************************************************
181 */
182
183void StartResize(XEvent *evp, TwmWindow *tmp_win,
184                 bool fromtitlebar, bool from3dborder)
185{
186	Window      junkRoot, grabwin;
187	unsigned int junkbw, junkDepth;
188	Cursor      cursor;
189
190	cursor = (Scr->BorderCursors
191	          && tmp_win->curcurs) ? tmp_win->curcurs : Scr->ResizeCursor;
192	ResizeWindow = tmp_win->frame;
193	if(! Scr->OpaqueResize || resizeWhenAdd) {
194		XGrabServer(dpy);
195	}
196	resizeGrabMask = ButtonPressMask | ButtonReleaseMask |
197	                 ButtonMotionMask | PointerMotionHintMask;
198
199	grabwin = Scr->Root;
200#ifdef WINBOX
201	if(tmp_win->winbox) {
202		grabwin = tmp_win->winbox->window;
203	}
204#endif
205	XGrabPointer(dpy, grabwin, True, resizeGrabMask,
206	             GrabModeAsync, GrabModeAsync, grabwin, cursor, CurrentTime);
207
208	XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
209	             &dragx, &dragy, &dragWidth, &dragHeight, &junkbw,
210	             &junkDepth);
211	dragx += tmp_win->frame_bw;
212	dragy += tmp_win->frame_bw;
213	origx = dragx;
214	origy = dragy;
215	origWidth = dragWidth;
216	origHeight = dragHeight;
217	clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
218
219	if(Scr->AutoRelativeResize && (from3dborder || !fromtitlebar)) {
220		do_auto_clamp(tmp_win, evp);
221	}
222
223	Scr->SizeStringOffset = SIZE_HINDENT;
224	MoveResizeSizeWindow(evp->xbutton.x_root, evp->xbutton.y_root,
225	                     Scr->SizeStringWidth + SIZE_HINDENT * 2,
226	                     Scr->SizeFont.height + SIZE_VINDENT * 2);
227	XMapRaised(dpy, Scr->SizeWindow);
228	InstallRootColormap();
229	last_width = 0;
230	last_height = 0;
231	DisplaySize(tmp_win, origWidth, origHeight);
232
233	if(! Scr->OpaqueResize || resizeWhenAdd)
234		MoveOutline(Scr->Root, dragx - tmp_win->frame_bw,
235		            dragy - tmp_win->frame_bw, dragWidth + 2 * tmp_win->frame_bw,
236		            dragHeight + 2 * tmp_win->frame_bw,
237		            tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
238}
239
240
241void MenuStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
242{
243	if(! Scr->OpaqueResize) {
244		XGrabServer(dpy);
245	}
246	resizeGrabMask = ButtonPressMask | ButtonMotionMask | PointerMotionMask;
247	XGrabPointer(dpy, Scr->Root, True, resizeGrabMask,
248	             GrabModeAsync, GrabModeAsync,
249	             Scr->Root, Scr->ResizeCursor, CurrentTime);
250	dragx = x + tmp_win->frame_bw;
251	dragy = y + tmp_win->frame_bw;
252	origx = dragx;
253	origy = dragy;
254	dragWidth = origWidth = w;
255	dragHeight = origHeight = h;
256	clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
257	last_width = 0;
258	last_height = 0;
259	Scr->SizeStringOffset = SIZE_HINDENT;
260	MoveResizeSizeWindow(dragx, dragy,
261	                     Scr->SizeStringWidth + SIZE_HINDENT * 2,
262	                     Scr->SizeFont.height + SIZE_VINDENT * 2);
263	XMapRaised(dpy, Scr->SizeWindow);
264	DisplaySize(tmp_win, origWidth, origHeight);
265	if(! Scr->OpaqueResize)
266		MoveOutline(Scr->Root, dragx - tmp_win->frame_bw,
267		            dragy - tmp_win->frame_bw,
268		            dragWidth + 2 * tmp_win->frame_bw,
269		            dragHeight + 2 * tmp_win->frame_bw,
270		            tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
271}
272
273/***********************************************************************
274 *
275 *  Procedure:
276 *      AddStartResize - begin a windorew resize operation from AddWindow
277 *
278 *  Inputs:
279 *      tmp_win - the TwmWindow pointer
280 *
281 ***********************************************************************
282 */
283
284void AddStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
285{
286	XGrabServer(dpy);
287	resizeGrabMask = ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask;
288	XGrabPointer(dpy, Scr->Root, True, resizeGrabMask,
289	             GrabModeAsync, GrabModeAsync,
290	             Scr->Root, Scr->ResizeCursor, CurrentTime);
291
292	dragx = x + tmp_win->frame_bw;
293	dragy = y + tmp_win->frame_bw;
294	origx = dragx;
295	origy = dragy;
296	dragWidth = origWidth = w - 2 * tmp_win->frame_bw;
297	dragHeight = origHeight = h - 2 * tmp_win->frame_bw;
298	clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
299	last_width = 0;
300	last_height = 0;
301	DisplaySize(tmp_win, origWidth, origHeight);
302}
303
304
305void MenuDoResize(int x_root, int y_root, TwmWindow *tmp_win)
306{
307	int action;
308	Cursor cursor = 0;
309
310	action = 0;
311
312	x_root -= clampDX;
313	y_root -= clampDY;
314
315	if(clampTop) {
316		int         delta = y_root - dragy;
317		if((int)(dragHeight - delta) < MINHEIGHT) {
318			delta = dragHeight - MINHEIGHT;
319			clampTop = 0;
320		}
321		dragy += delta;
322		dragHeight -= delta;
323		action = 1;
324		cursor = TopCursor;
325	}
326	else if(y_root <= dragy) {
327		dragy = y_root;
328		dragHeight = origy + origHeight -
329		             y_root;
330		clampBottom = 0;
331		clampTop = 1;
332		clampDY = 0;
333		action = 1;
334		cursor = TopCursor;
335	}
336	if(clampLeft) {
337		int         delta = x_root - dragx;
338		if((int)(dragWidth - delta) < MINWIDTH) {
339			delta = dragWidth - MINWIDTH;
340			clampLeft = 0;
341		}
342		dragx += delta;
343		dragWidth -= delta;
344		action = 1;
345		cursor = clampTop ? TopLeftCursor : LeftCursor;
346	}
347	else if(x_root <= dragx) {
348		dragx = x_root;
349		dragWidth = origx + origWidth -
350		            x_root;
351		clampRight = 0;
352		clampLeft = 1;
353		clampDX = 0;
354		action = 1;
355		cursor = clampTop ? TopLeftCursor : LeftCursor;
356	}
357	if(clampBottom) {
358		int         delta = y_root - dragy - dragHeight;
359		if((int)(dragHeight + delta) < MINHEIGHT) {
360			delta = MINHEIGHT - dragHeight;
361			clampBottom = 0;
362		}
363		dragHeight += delta;
364		action = 1;
365		cursor = clampLeft ? BottomLeftCursor : BottomCursor;
366	}
367	else if(y_root >= dragy + dragHeight) {
368		dragy = origy;
369		dragHeight = 1 + y_root - dragy;
370		clampTop = 0;
371		clampBottom = 1;
372		clampDY = 0;
373		action = 1;
374		cursor = clampLeft ? BottomLeftCursor : BottomCursor;
375	}
376	if(clampRight) {
377		int         delta = x_root - dragx - dragWidth;
378		if((int)(dragWidth + delta) < MINWIDTH) {
379			delta = MINWIDTH - dragWidth;
380			clampRight = 0;
381		}
382		dragWidth += delta;
383		action = 1;
384		cursor = clampBottom ? BottomRightCursor : RightCursor;
385		cursor = clampTop ? TopRightCursor : cursor;
386	}
387	else if(x_root >= dragx + dragWidth) {
388		dragx = origx;
389		dragWidth = 1 + x_root - origx;
390		clampLeft = 0;
391		clampRight = 1;
392		clampDX = 0;
393		action = 1;
394		cursor = clampBottom ? BottomRightCursor : RightCursor;
395		cursor = clampTop ? TopRightCursor : cursor;
396	}
397
398	if(action) {
399		ConstrainSize(tmp_win, &dragWidth, &dragHeight);
400		if(clampLeft) {
401			dragx = origx + origWidth - dragWidth;
402		}
403		if(clampTop) {
404			dragy = origy + origHeight - dragHeight;
405		}
406		if(Scr->OpaqueResize)
407			SetupWindow(tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
408			            dragWidth, dragHeight, -1);
409		else
410			MoveOutline(Scr->Root,
411			            dragx - tmp_win->frame_bw,
412			            dragy - tmp_win->frame_bw,
413			            dragWidth + 2 * tmp_win->frame_bw,
414			            dragHeight + 2 * tmp_win->frame_bw,
415			            tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
416		if(Scr->BorderCursors && (cursor != tmp_win->curcurs)) {
417			tmp_win->curcurs = cursor;
418			XChangeActivePointerGrab(dpy, resizeGrabMask, cursor, CurrentTime);
419		}
420	}
421
422	DisplaySize(tmp_win, dragWidth, dragHeight);
423}
424
425/***********************************************************************
426 *
427 *  Procedure:
428 *      DoResize - move the rubberband around.  This is called for
429 *                 each motion event when we are resizing
430 *
431 *  Inputs:
432 *      x_root  - the X corrdinate in the root window
433 *      y_root  - the Y corrdinate in the root window
434 *      tmp_win - the current twm window
435 *
436 ***********************************************************************
437 */
438
439void DoResize(int x_root, int y_root, TwmWindow *tmp_win)
440{
441	int action;
442	Cursor cursor = 0;
443
444	action = 0;
445
446	x_root -= clampDX;
447	y_root -= clampDY;
448
449	if(clampTop) {
450		int         delta = y_root - dragy;
451		if((int)(dragHeight - delta) < MINHEIGHT) {
452			delta = dragHeight - MINHEIGHT;
453			clampTop = 0;
454		}
455		dragy += delta;
456		dragHeight -= delta;
457		action = 1;
458		cursor = TopCursor;
459	}
460	else if(y_root <= dragy) {
461		dragy = y_root;
462		dragHeight = origy + origHeight -
463		             y_root;
464		clampBottom = 0;
465		clampTop = 1;
466		clampDY = 0;
467		action = 1;
468		cursor = TopCursor;
469	}
470	if(clampLeft) {
471		int         delta = x_root - dragx;
472		if((int)(dragWidth - delta) < MINWIDTH) {
473			delta = dragWidth - MINWIDTH;
474			clampLeft = 0;
475		}
476		dragx += delta;
477		dragWidth -= delta;
478		action = 1;
479		cursor = clampTop ? TopLeftCursor : LeftCursor;
480	}
481	else if(x_root <= dragx) {
482		dragx = x_root;
483		dragWidth = origx + origWidth -
484		            x_root;
485		clampRight = 0;
486		clampLeft = 1;
487		clampDX = 0;
488		action = 1;
489		cursor = clampTop ? TopLeftCursor : LeftCursor;
490	}
491	if(clampBottom) {
492		int         delta = y_root - dragy - dragHeight;
493		if((int)(dragHeight + delta) < MINHEIGHT) {
494			delta = MINHEIGHT - dragHeight;
495			clampBottom = 0;
496		}
497		dragHeight += delta;
498		action = 1;
499		cursor = clampLeft ? BottomLeftCursor : BottomCursor;
500	}
501	else if(y_root >= dragy + dragHeight - 1) {
502		dragy = origy;
503		dragHeight = 1 + y_root - dragy;
504		clampTop = 0;
505		clampBottom = 1;
506		clampDY = 0;
507		action = 1;
508		cursor = clampLeft ? BottomLeftCursor : BottomCursor;
509	}
510	if(clampRight) {
511		int         delta = x_root - dragx - dragWidth;
512		if((int)(dragWidth + delta) < MINWIDTH) {
513			delta = MINWIDTH - dragWidth;
514			clampRight = 0;
515		}
516		dragWidth += delta;
517		action = 1;
518		cursor = clampBottom ? BottomRightCursor : RightCursor;
519		cursor = clampTop ? TopRightCursor : cursor;
520	}
521	else if(x_root >= dragx + dragWidth - 1) {
522		dragx = origx;
523		dragWidth = 1 + x_root - origx;
524		clampLeft = 0;
525		clampRight = 1;
526		clampDX = 0;
527		action = 1;
528		cursor = clampBottom ? BottomRightCursor : RightCursor;
529		cursor = clampTop ? TopRightCursor : cursor;
530	}
531
532	if(action) {
533		ConstrainSize(tmp_win, &dragWidth, &dragHeight);
534		if(clampLeft) {
535			dragx = origx + origWidth - dragWidth;
536		}
537		if(clampTop) {
538			dragy = origy + origHeight - dragHeight;
539		}
540		if(Scr->OpaqueResize && ! resizeWhenAdd) {
541			SetupWindow(tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
542			            dragWidth, dragHeight, -1);
543		}
544		else {
545			MoveOutline(Scr->Root,
546			            dragx - tmp_win->frame_bw,
547			            dragy - tmp_win->frame_bw,
548			            dragWidth + 2 * tmp_win->frame_bw,
549			            dragHeight + 2 * tmp_win->frame_bw,
550			            tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
551		}
552		if(Scr->BorderCursors && (cursor != tmp_win->curcurs)) {
553			tmp_win->curcurs = cursor;
554			XChangeActivePointerGrab(dpy, resizeGrabMask, cursor, CurrentTime);
555		}
556	}
557
558	DisplaySize(tmp_win, dragWidth, dragHeight);
559}
560
561/***********************************************************************
562 *
563 *  Procedure:
564 *      DisplaySize - display the size in the dimensions window
565 *
566 *  Inputs:
567 *      tmp_win - the current twm window
568 *      width   - the width of the rubber band
569 *      height  - the height of the rubber band
570 *
571 ***********************************************************************
572 */
573
574static void DisplaySize(TwmWindow *tmp_win, int width, int height)
575{
576	char str[100];
577	int dwidth;
578	int dheight;
579
580	if(last_width == width && last_height == height) {
581		return;
582	}
583
584	last_width = width;
585	last_height = height;
586
587	dheight = height - tmp_win->title_height - 2 * tmp_win->frame_bw3D;
588	dwidth = width - 2 * tmp_win->frame_bw3D;
589
590	/*
591	 * ICCCM says that PMinSize is the default is no PBaseSize is given,
592	 * and vice-versa.
593	 */
594	if(tmp_win->hints.flags & (PMinSize | PBaseSize)
595	                && tmp_win->hints.flags & PResizeInc) {
596		if(tmp_win->hints.flags & PBaseSize) {
597			dwidth -= tmp_win->hints.base_width;
598			dheight -= tmp_win->hints.base_height;
599		}
600		else {
601			dwidth -= tmp_win->hints.min_width;
602			dheight -= tmp_win->hints.min_height;
603		}
604	}
605
606	if(tmp_win->hints.flags & PResizeInc) {
607		dwidth /= tmp_win->hints.width_inc;
608		dheight /= tmp_win->hints.height_inc;
609	}
610
611	sprintf(str, " %4d x %-4d ", dwidth, dheight);
612	XRaiseWindow(dpy, Scr->SizeWindow);
613
614	Draw3DBorder(Scr->SizeWindow, 0, 0,
615	             Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
616	             Scr->SizeFont.height + SIZE_VINDENT * 2,
617	             2, Scr->DefaultC, off, false, false);
618
619	FB(Scr->DefaultC.fore, Scr->DefaultC.back);
620	XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
621	                   Scr->NormalGC, Scr->SizeStringOffset,
622	                   Scr->SizeFont.ascent + SIZE_VINDENT, str, 13);
623}
624
625/***********************************************************************
626 *
627 *  Procedure:
628 *      EndResize - finish the resize operation
629 *
630 ***********************************************************************
631 */
632
633void EndResize(void)
634{
635	TwmWindow *tmp_win;
636
637#ifdef DEBUG
638	fprintf(stderr, "EndResize\n");
639#endif
640
641	MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
642	XUnmapWindow(dpy, Scr->SizeWindow);
643
644	tmp_win = GetTwmWindow(ResizeWindow);
645	if(!tmp_win) {
646		return;
647	}
648
649	ConstrainSize(tmp_win, &dragWidth, &dragHeight);
650
651	if(dragWidth != tmp_win->frame_width ||
652	                dragHeight != tmp_win->frame_height) {
653		unzoom(tmp_win);
654	}
655
656	SetupWindow(tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
657	            dragWidth, dragHeight, -1);
658
659	if(tmp_win->isiconmgr) {
660		int ncols = tmp_win->iconmgrp->cur_columns;
661		if(ncols == 0) {
662			ncols = 1;
663		}
664
665		tmp_win->iconmgrp->width = (int)(((dragWidth - 2 * tmp_win->frame_bw3D) *
666		                                  (long) tmp_win->iconmgrp->columns)
667		                                 / ncols);
668		PackIconManager(tmp_win->iconmgrp);
669	}
670
671	if(!Scr->NoRaiseResize) {
672		OtpRaise(tmp_win, WinWin);
673		WMapRaise(tmp_win);
674	}
675
676	UninstallRootColormap();
677
678	ResizeWindow = None;
679}
680
681void MenuEndResize(TwmWindow *tmp_win)
682{
683	MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
684	XUnmapWindow(dpy, Scr->SizeWindow);
685	ConstrainSize(tmp_win, &dragWidth, &dragHeight);
686	AddingX = dragx - tmp_win->frame_bw;
687	AddingY = dragy - tmp_win->frame_bw;
688	AddingW = dragWidth;
689	AddingH = dragHeight;
690	SetupWindow(tmp_win, AddingX, AddingY, AddingW, AddingH, -1);
691}
692
693
694/***********************************************************************
695 *
696 *  Procedure:
697 *      AddEndResize - finish the resize operation for AddWindo<w
698 *
699 ***********************************************************************
700 */
701
702void AddEndResize(TwmWindow *tmp_win)
703{
704
705#ifdef DEBUG
706	fprintf(stderr, "AddEndResize\n");
707#endif
708
709	ConstrainSize(tmp_win, &dragWidth, &dragHeight);
710	AddingX = dragx;
711	AddingY = dragy;
712	AddingW = dragWidth + (2 * tmp_win->frame_bw);
713	AddingH = dragHeight + (2 * tmp_win->frame_bw);
714}
715
716/***********************************************************************
717 *
718 *  Procedure:
719 *      ConstrainSize - adjust the given width and height to account for the
720 *              constraints imposed by size hints
721 *
722 *      The general algorithm, especially the aspect ratio stuff, is
723 *      borrowed from uwm's CheckConsistency routine.
724 *
725 ***********************************************************************/
726
727void ConstrainSize(TwmWindow *tmp_win,
728                   unsigned int *widthp, unsigned int *heightp)
729{
730#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
731
732	int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
733	int baseWidth, baseHeight;
734	int dwidth = *widthp, dheight = *heightp;
735
736
737	dwidth  -= 2 * tmp_win->frame_bw3D;
738	dheight -= (tmp_win->title_height + 2 * tmp_win->frame_bw3D);
739
740	if(tmp_win->hints.flags & PMinSize) {
741		minWidth = tmp_win->hints.min_width;
742		minHeight = tmp_win->hints.min_height;
743	}
744	else if(tmp_win->hints.flags & PBaseSize) {
745		minWidth = tmp_win->hints.base_width;
746		minHeight = tmp_win->hints.base_height;
747	}
748	else {
749		minWidth = minHeight = 1;
750	}
751
752	if(tmp_win->hints.flags & PBaseSize) {
753		baseWidth = tmp_win->hints.base_width;
754		baseHeight = tmp_win->hints.base_height;
755	}
756	else if(tmp_win->hints.flags & PMinSize) {
757		baseWidth = tmp_win->hints.min_width;
758		baseHeight = tmp_win->hints.min_height;
759	}
760	else {
761		baseWidth = baseHeight = 0;
762	}
763
764
765	if(tmp_win->hints.flags & PMaxSize) {
766		maxWidth = min(Scr->MaxWindowWidth, tmp_win->hints.max_width);
767		maxHeight = min(Scr->MaxWindowHeight, tmp_win->hints.max_height);
768	}
769	else {
770		maxWidth = Scr->MaxWindowWidth;
771		maxHeight = Scr->MaxWindowHeight;
772	}
773
774	if(tmp_win->hints.flags & PResizeInc) {
775		xinc = tmp_win->hints.width_inc;
776		yinc = tmp_win->hints.height_inc;
777		if(xinc == 0) {
778			xinc = 1;
779		}
780		if(yinc == 0) {
781			yinc = 1;
782		}
783	}
784	else {
785		xinc = yinc = 1;
786	}
787
788	/*
789	 * First, clamp to min and max values
790	 */
791	if(dwidth < minWidth) {
792		dwidth = minWidth;
793	}
794	if(dheight < minHeight) {
795		dheight = minHeight;
796	}
797
798	if(dwidth > maxWidth) {
799		dwidth = maxWidth;
800	}
801	if(dheight > maxHeight) {
802		dheight = maxHeight;
803	}
804
805
806	/*
807	 * Second, fit to base + N * inc
808	 */
809	dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
810	dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
811
812
813	/*
814	 * Third, adjust for aspect ratio
815	 */
816	/*
817	 * The math looks like this:
818	 *
819	 * minAspectX    dwidth     maxAspectX
820	 * ---------- <= ------- <= ----------
821	 * minAspectY    dheight    maxAspectY
822	 *
823	 * If that is multiplied out, then the width and height are
824	 * invalid in the following situations:
825	 *
826	 * minAspectX * dheight > minAspectY * dwidth
827	 * maxAspectX * dheight < maxAspectY * dwidth
828	 *
829	 */
830
831	if(tmp_win->hints.flags & PAspect) {
832		int minAspectX = tmp_win->hints.min_aspect.x;
833		int minAspectY = tmp_win->hints.min_aspect.y;
834		int maxAspectX = tmp_win->hints.max_aspect.x;
835		int maxAspectY = tmp_win->hints.max_aspect.y;
836
837		if(minAspectX && minAspectY && maxAspectX && maxAspectY) {
838			if(minAspectX * dheight > minAspectY * dwidth) {
839				delta = makemult(minAspectX * dheight / minAspectY - dwidth,
840				                 xinc);
841				if(dwidth + delta <= maxWidth) {
842					dwidth += delta;
843				}
844				else {
845					delta = makemult(dheight - dwidth * minAspectY / minAspectX,
846					                 yinc);
847					if(dheight - delta >= minHeight) {
848						dheight -= delta;
849					}
850				}
851			}
852
853			if(maxAspectX * dheight < maxAspectY * dwidth) {
854				delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
855				                 yinc);
856				if(dheight + delta <= maxHeight) {
857					dheight += delta;
858				}
859				else {
860					delta = makemult(dwidth - maxAspectX * dheight / maxAspectY,
861					                 xinc);
862					if(dwidth - delta >= minWidth) {
863						dwidth -= delta;
864					}
865				}
866			}
867		}
868	}
869
870
871	/*
872	 * Fourth, account for border width and title height
873	 */
874	*widthp = dwidth + 2 * tmp_win->frame_bw3D;
875	*heightp = dheight + tmp_win->title_height + 2 * tmp_win->frame_bw3D;
876}
877
878
879
880
881/**********************************************************************
882 *  Rutgers mod #1   - rocky.
883 *  Procedure:
884 *         fullzoom - zooms window to full height of screen or
885 *                    to full height and width of screen. (Toggles
886 *                    so that it can undo the zoom - even when switching
887 *                    between fullzoom and vertical zoom.)
888 *
889 *  Inputs:
890 *         tmp_win - the TwmWindow pointer
891 *
892 *
893 **********************************************************************
894 */
895
896void fullzoom(TwmWindow *tmp_win, int func)
897{
898	Window      junkRoot;
899	unsigned int junkbw, junkDepth;
900	int tmpX, tmpY, tmpW, tmpH;
901
902	/*
903	 * All our callers [need to] do this, so moving it here saves a few
904	 * lines in some places around the calling, and when redundant it
905	 * just wastes a comparison, so it's cheap.
906	 */
907	if(tmp_win->squeezed) {
908		XBell(dpy, 0);
909		return;
910	}
911
912
913	XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
914	             &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight,
915	             &junkbw,
916	             &junkDepth);
917
918	/*
919	 * Guard; if it was already not zoomed, and we're asking to unzoom
920	 * it, just finish right away.  This saves us work, but also avoids
921	 * really bad side effects in some cases.  e.g., if we try to
922	 * ZOOM_NONE a window that's never been ZOOM'd, tmp_win->save_* will
923	 * all be 0, so we'd wind up resizing it to a point.  It's possible
924	 * for that to happen via e.g. an EWMH message removing a _FULLSCREEN
925	 * or similar attribute; that can then call into us telling us not to
926	 * zoom, on a window that's never been zoomed.
927	 *
928	 * This wouldn't protect us if somehow it was zoomed but hadn't set
929	 * that data, but I don't see how that can happen.  Worry about that
930	 * when it does.
931	 */
932	if(func == ZOOM_NONE && tmp_win->zoomed == ZOOM_NONE) {
933		return;
934	}
935
936	if(tmp_win->zoomed == func) {
937		/* It was already zoomed this way, unzoom it */
938		dragHeight = tmp_win->save_frame_height;
939		dragWidth = tmp_win->save_frame_width;
940		dragx = tmp_win->save_frame_x;
941		dragy = tmp_win->save_frame_y;
942
943		unzoom(tmp_win);
944
945		/* XXX _should_ it be falling through here? */
946	}
947	else {
948		RLayout *borderedLayout = NULL;
949		RArea area, finalArea = RAreaInvalid();
950		int frame_bw_times_2;
951
952#ifdef WINBOX
953		if(tmp_win->winbox) {
954			XWindowAttributes winattrs;
955			if(XGetWindowAttributes(dpy, tmp_win->winbox->window, &winattrs)) {
956				borderedLayout = RLayoutNew(
957				                         RAreaListNew(1,
958				                                      RAreaNew(winattrs.x,
959				                                                      winattrs.y,
960				                                                      winattrs.width,
961				                                                      winattrs.height),
962				                                      NULL));
963			}
964		}
965#endif
966		if(borderedLayout == NULL) {
967			borderedLayout = Scr->BorderedLayout;
968		}
969
970		if(tmp_win->zoomed == ZOOM_NONE) {
971			tmp_win->save_frame_x = dragx;
972			tmp_win->save_frame_y = dragy;
973			tmp_win->save_frame_width = dragWidth;
974			tmp_win->save_frame_height = dragHeight;
975		}
976		tmp_win->zoomed = func;
977
978		frame_bw_times_2 = 2 * tmp_win->frame_bw;
979
980		area = RAreaNew(dragx, dragy, dragWidth, dragHeight);
981
982		switch(func) {
983			case ZOOM_NONE:
984				break;
985			case F_XZOOM:
986				finalArea = RLayoutFullVert(borderedLayout, &area);
987			/* fall through */
988			case F_ZOOM:
989				if(!RAreaIsValid(&finalArea)) {
990					finalArea = RLayoutFullVert1(borderedLayout, &area);
991				}
992				dragy = finalArea.y;
993				dragHeight = finalArea.height - frame_bw_times_2;
994				break;
995			case F_XHORIZOOM:
996				finalArea = RLayoutFullHoriz(borderedLayout, &area);
997			/* fall through */
998			case F_HORIZOOM:
999				if(!RAreaIsValid(&finalArea)) {
1000					finalArea = RLayoutFullHoriz1(borderedLayout, &area);
1001				}
1002				dragx = finalArea.x;
1003				dragWidth = finalArea.width - frame_bw_times_2;
1004				break;
1005			case F_XFULLZOOM:
1006				finalArea = RLayoutFull(borderedLayout, &area);
1007			/* fall through */
1008			case F_FULLZOOM:
1009				if(!RAreaIsValid(&finalArea)) {
1010					finalArea = RLayoutFull1(borderedLayout, &area);
1011				}
1012				dragx = finalArea.x;
1013				dragy = finalArea.y;
1014				dragWidth = finalArea.width - frame_bw_times_2;
1015				dragHeight = finalArea.height - frame_bw_times_2;
1016				break;
1017			case F_XLEFTZOOM:
1018				dragx = RLayoutFindLeftEdge(borderedLayout, &area);
1019				dragWidth += area.x - dragx;
1020				// TODO make it visible if hidden
1021				break;
1022			case F_LEFTZOOM:
1023				dragx = RLayoutFindMonitorLeftEdge(borderedLayout, &area);
1024				dragWidth += area.x - dragx;
1025				// TODO make it visible if hidden
1026				break;
1027			case F_XRIGHTZOOM: {
1028				int limit = RLayoutFindRightEdge(borderedLayout, &area);
1029				dragWidth = limit - area.x + 1 - frame_bw_times_2;
1030				// TODO make it visible if hidden
1031			}
1032			break;
1033			case F_RIGHTZOOM: {
1034				int limit = RLayoutFindMonitorRightEdge(borderedLayout, &area);
1035				dragWidth = limit - area.x + 1 - frame_bw_times_2;
1036				// TODO make it visible if hidden
1037			}
1038			break;
1039			case F_XTOPZOOM:
1040				dragy = RLayoutFindTopEdge(borderedLayout, &area);
1041				dragHeight += area.y - dragy;
1042				// TODO make it visible if hidden
1043				break;
1044			case F_TOPZOOM:
1045				dragy = RLayoutFindMonitorTopEdge(borderedLayout, &area);
1046				dragHeight += area.y - dragy;
1047				// TODO make it visible if hidden
1048				break;
1049			case F_XBOTTOMZOOM: {
1050				int limit = RLayoutFindBottomEdge(borderedLayout, &area);
1051				dragHeight = limit - area.y + 1 - frame_bw_times_2;
1052				// TODO make it visible if hidden
1053			}
1054			break;
1055			case F_BOTTOMZOOM: {
1056				int limit = RLayoutFindMonitorBottomEdge(borderedLayout, &area);
1057				dragHeight = limit - area.y + 1 - frame_bw_times_2;
1058				// TODO make it visible if hidden
1059			}
1060			break;
1061			case F_FULLSCREENZOOM:
1062			case F_XFULLSCREENZOOM: {
1063				int bw3D = tmp_win->frame_bw3D;
1064				int bw3D_times_2 = 2 * bw3D;
1065				int bw = tmp_win->frame_bw + bw3D;
1066
1067				finalArea = func == F_XFULLSCREENZOOM
1068				            ? RLayoutFull(borderedLayout, &area)
1069				            : RLayoutFull1(borderedLayout, &area);
1070				dragx = finalArea.x - bw;
1071				dragy = finalArea.y - tmp_win->title_height - bw;
1072				dragWidth = finalArea.width + bw3D_times_2;
1073				dragHeight = finalArea.height + tmp_win->title_height + bw3D_times_2;
1074
1075				/* and should ignore aspect ratio and size increments... */
1076#ifdef EWMH
1077				/* x-ref HandleFocusIn() comments for why we need this */
1078				OtpSetAflag(tmp_win, OTP_AFLAG_FULLSCREEN);
1079				OtpRestackWindow(tmp_win);
1080				/* the OtpRaise below is effectively already done here... */
1081#endif
1082			}
1083		}
1084
1085		/* Temporary built layout? */
1086		if(borderedLayout != Scr->BorderedLayout) {
1087			RLayoutFree(borderedLayout);
1088		}
1089	}
1090
1091	if(!Scr->NoRaiseResize && func != F_FULLSCREENZOOM) {
1092		OtpRaise(tmp_win, WinWin);
1093	}
1094
1095	if(func != F_FULLSCREENZOOM) {
1096		ConstrainSize(tmp_win, &dragWidth, &dragHeight);
1097	}
1098#ifdef BETTERZOOM
1099	if(func == F_ZOOM) {
1100		if(dragy + dragHeight < tmp_win->save_frame_y + tmp_win->save_frame_height) {
1101			dragy = tmp_win->save_frame_y + tmp_win->save_frame_height - dragHeight;
1102		}
1103	}
1104#endif
1105	SetupWindow(tmp_win, dragx, dragy, dragWidth, dragHeight, -1);
1106	/* I don't understand the reason of this. Claude.
1107	    XUngrabPointer (dpy, CurrentTime);
1108	*/
1109	XUngrabServer(dpy);
1110
1111	XQueryPointer(dpy,
1112	              tmp_win->w,
1113	              &junkRoot, &junkRoot,
1114	              &tmpX, &tmpY, &tmpW, &tmpH, &junkDepth);
1115	if(tmp_win->frame_x > tmpX ||
1116	                tmp_win->frame_x + tmp_win->frame_width < tmpX ||
1117	                tmp_win->frame_y > tmpY ||
1118	                tmp_win->frame_y + tmp_win->frame_height < tmpY) {
1119		XWarpPointer(dpy, Scr->Root, tmp_win->w, 0, 0, 0, 0, 0, 0);
1120	}
1121
1122#ifdef EWMH
1123	/*
1124	 * Reset _NET_WM_STATE prop on the window.  It sets whichever state
1125	 * applies, not always the _MAXIMIZED_VERT we specify here.
1126	 */
1127	EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_MAXIMIZED_VERT);
1128#endif
1129}
1130
1131/*
1132 * Forget about a window being zoomed.
1133 * This also needs to undo the special effects of F_FULLSCREENZOOM.
1134 */
1135void unzoom(TwmWindow *tmp_win)
1136{
1137	if(tmp_win->zoomed != ZOOM_NONE) {
1138#ifdef EWMH
1139		if(tmp_win->zoomed == F_FULLSCREENZOOM) {
1140			OtpClearAflag(tmp_win, OTP_AFLAG_FULLSCREEN);
1141			OtpRestackWindow(tmp_win);
1142		}
1143#endif
1144
1145		tmp_win->zoomed = ZOOM_NONE;
1146	}
1147}
1148
1149void savegeometry(TwmWindow *tmp_win)
1150{
1151	if(!tmp_win) {
1152		return;
1153	}
1154	tmp_win->savegeometry.x      = tmp_win->frame_x;
1155	tmp_win->savegeometry.y      = tmp_win->frame_y;
1156	tmp_win->savegeometry.width  = tmp_win->frame_width;
1157	tmp_win->savegeometry.height = tmp_win->frame_height;
1158}
1159
1160void restoregeometry(TwmWindow *tmp_win)
1161{
1162	int x, y;
1163	unsigned int w, h;
1164
1165	if(!tmp_win) {
1166		return;
1167	}
1168	if(tmp_win->savegeometry.width == (unsigned int) - 1) {
1169		return;
1170	}
1171	x = tmp_win->savegeometry.x;
1172	y = tmp_win->savegeometry.y;
1173	w = tmp_win->savegeometry.width;
1174	h = tmp_win->savegeometry.height;
1175	SetupWindow(tmp_win, x, y, w, h, -1);
1176}
1177
1178
1179void ChangeSize(char *in_string, TwmWindow *tmp_win)
1180{
1181	int change = 0, size = 0;
1182	char *endptr;
1183	int rx, ry, wx, wy, mr;
1184	Window  rr, cr;
1185
1186	if(Isdigit(in_string[0])) {
1187		/* Handle the case f.changesize "640x480" */
1188		wx = strtol(in_string, &endptr, 10);
1189		if(*endptr++ != 'x') {
1190			fprintf(stderr,
1191			        "%s: Bad argument to f.changesize: \"%s\" (pattern \"640x480\")\n",
1192			        ProgramName, in_string);
1193			return;
1194		}
1195		wy = strtol(endptr, &endptr, 10);
1196
1197		if(wy < tmp_win->title_height + 1) {
1198			wy = tmp_win->title_height + 1;
1199		}
1200
1201		SetupWindow(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
1202		            wx, wy + tmp_win->title_height, -1);
1203	}
1204	else {
1205		/* Handle the cases like f.changesize "right +10" */
1206		int cmdlen = 0;
1207
1208		while(in_string[cmdlen] != ' ' && in_string[cmdlen] != '\0') {
1209			cmdlen++;
1210		}
1211
1212		if(in_string[cmdlen] != ' ') {
1213			fprintf(stderr,
1214			        "%s: Bad argument to f.changesize: \"%s\" (sizechange missing)\n",
1215			        ProgramName, in_string);
1216			return;
1217		}
1218
1219		change = strtol(in_string + cmdlen + 1, &endptr, 10);
1220		if(*endptr != 0) {
1221			fprintf(stderr,
1222			        "%s: Bad argument to f.changesize: \"%s\" (sizechange not a number)\n",
1223			        ProgramName, in_string);
1224			return;
1225		}
1226
1227		if(strncmp("bottom", in_string, cmdlen) == 0) {
1228			size = tmp_win->frame_height + change;
1229
1230			if(size < (tmp_win->title_height + 1)) {
1231				size = tmp_win->title_height + 1;
1232			}
1233
1234			SetupWindow(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
1235			            tmp_win->frame_width, size,
1236			            -1);
1237
1238			XQueryPointer(dpy, tmp_win->w, &rr, &cr, &rx, &ry, &wx, &wy,
1239			              (unsigned int *)&mr);
1240
1241			if((wy + tmp_win->title_height) > size) {
1242				XWarpPointer(dpy, None, tmp_win->w, 0, 0, 0, 0, 0, 0);
1243			}
1244		}
1245		else if(strncmp("top", in_string, cmdlen) == 0) {
1246			size = tmp_win->frame_height + change;
1247
1248			if(size < (tmp_win->title_height + 1)) {
1249				size = tmp_win->title_height + 1;
1250			}
1251
1252			SetupWindow(tmp_win, tmp_win->frame_x, (tmp_win->frame_y - change),
1253			            tmp_win->frame_width, size,
1254			            -1);
1255
1256			XQueryPointer(dpy, tmp_win->w, &rr, &cr, &rx, &ry, &wx, &wy,
1257			              (unsigned int *)&mr);
1258
1259			if((wy + tmp_win->title_height) > size) {
1260				XWarpPointer(dpy, None, tmp_win->w, 0, 0, 0, 0, 0, 0);
1261			}
1262
1263
1264		}
1265		else if(strncmp("left", in_string, cmdlen) == 0) {
1266			size = tmp_win->frame_width + change;
1267
1268			if(size < 1) {
1269				size = 1;
1270			}
1271
1272			SetupWindow(tmp_win, (tmp_win->frame_x - change), tmp_win->frame_y,
1273			            size, tmp_win->frame_height,
1274			            -1);
1275
1276			XQueryPointer(dpy, tmp_win->w, &rr, &cr, &rx, &ry, &wx, &wy,
1277			              (unsigned int *)&mr);
1278
1279			if(wx > size) {
1280				XWarpPointer(dpy, None, tmp_win->w, 0, 0, 0, 0, 0, 0);
1281			}
1282
1283
1284		}
1285		else if(strncmp("right", in_string, cmdlen) == 0) {
1286			size = tmp_win->frame_width + change;
1287
1288			if(size < 1) {
1289				size = 1;
1290			}
1291
1292			SetupWindow(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
1293			            size, tmp_win->frame_height,
1294			            -1);
1295
1296			XQueryPointer(dpy, tmp_win->w, &rr, &cr, &rx, &ry, &wx, &wy,
1297			              (unsigned int *)&mr);
1298
1299			if(wx > size) {
1300				XWarpPointer(dpy, None, tmp_win->w, 0, 0, 0, 0, 0, 0);
1301			}
1302
1303		}
1304		else {
1305			/* error */
1306			fprintf(stderr, "%s: Bad argument to f.changesize: \"%s\"\n (unknown border)",
1307			        ProgramName, in_string);
1308			return;
1309		}
1310	}
1311}
1312
1313
1314/***********************************************************************
1315 *
1316 *  Procedure:
1317 *      resizeFromCenter -
1318 *
1319 ***********************************************************************
1320 */
1321void
1322resizeFromCenter(Window w, TwmWindow *tmp_win)
1323{
1324	int lastx, lasty, bw2;
1325
1326	bw2 = tmp_win->frame_bw * 2;
1327	AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D;
1328	AddingH = tmp_win->attr.height + tmp_win->title_height + bw2 + 2 *
1329	          tmp_win->frame_bw3D;
1330
1331	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
1332	             &DragWidth, &DragHeight,
1333	             &JunkBW, &JunkDepth);
1334
1335	XWarpPointer(dpy, None, w,
1336	             0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
1337	XQueryPointer(dpy, Scr->Root, &JunkRoot,
1338	              &JunkChild, &JunkX, &JunkY,
1339	              &AddingX, &AddingY, &JunkMask);
1340
1341	lastx = -10000;
1342	lasty = -10000;
1343
1344	MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
1345	while(1) {
1346		XMaskEvent(dpy,
1347		           ButtonPressMask | PointerMotionMask | ExposureMask, &Event);
1348
1349		if(Event.type == MotionNotify) {
1350			/* discard any extra motion events before a release */
1351			while(XCheckMaskEvent(dpy,
1352			                      ButtonMotionMask | ButtonPressMask, &Event))
1353				if(Event.type == ButtonPress) {
1354					break;
1355				}
1356		}
1357
1358		if(Event.type == ButtonPress) {
1359			MenuEndResize(tmp_win);
1360			// Next line should be unneeded, done by MenuEndResize() ?
1361			XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
1362			break;
1363		}
1364
1365		if(Event.type != MotionNotify) {
1366			DispatchEvent2();
1367			if(Cancel) {
1368				// ...
1369				MenuEndResize(tmp_win);
1370				return;
1371			}
1372			continue;
1373		}
1374
1375		/*
1376		 * XXX - if we are going to do a loop, we ought to consider
1377		 * using multiple GXxor lines so that we don't need to
1378		 * grab the server.
1379		 */
1380		XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
1381		              &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
1382
1383		if(lastx != AddingX || lasty != AddingY) {
1384			MenuDoResize(AddingX, AddingY, tmp_win);
1385
1386			lastx = AddingX;
1387			lasty = AddingY;
1388		}
1389
1390	}
1391}
1392