1 /*
2  * Copyright (C) 2005 Fabian Yamaguchi <fabiany at gmx.net>
3  * Copyright (C) 2004 Sasha Vasko <sasha at aftercode.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 /*#define DO_CLOCKING      */
21 #define LOCAL_DEBUG
22 #define EVENT_TRACE
23 
24 #include "../../configure.h"
25 #include "../../libAfterStep/asapp.h"
26 
27 #include <signal.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <regex.h>
31 #include <stdlib.h>
32 #include <math.h>
33 
34 #include "../../libAfterImage/afterimage.h"
35 
36 #include "../../libAfterStep/afterstep.h"
37 #include "../../libAfterStep/screen.h"
38 #include "../../libAfterStep/module.h"
39 #include "../../libAfterStep/mystyle.h"
40 #include "../../libAfterStep/mystyle_property.h"
41 #include "../../libAfterStep/parser.h"
42 #include "../../libAfterStep/clientprops.h"
43 #include "../../libAfterStep/wmprops.h"
44 #include "../../libAfterStep/decor.h"
45 #include "../../libAfterStep/aswindata.h"
46 #include "../../libAfterStep/balloon.h"
47 #include "../../libAfterStep/event.h"
48 #include "../../libAfterStep/shape.h"
49 #include "../../libAfterStep/ascommand.h"
50 #include "../../libAfterStep/operations.h"
51 
52 #include "../../libAfterBase/aslist.h"
53 
54 #include "../../libAfterConf/afterconf.h"
55 
56 /**********************************************************************/
57 /*  ARRANGE local variables :                                         */
58 /**********************************************************************/
59 #define ARRANGE_Untitled	(0x01<<0)
60 #define ARRANGE_Transient	(0x01<<1)
61 #define ARRANGE_Sticky		(0x01<<2)
62 #define ARRANGE_Maximized	(0x01<<3)
63 #define ARRANGE_All			(ARRANGE_Untitled|ARRANGE_Transient| \
64 							 ARRANGE_Sticky|ARRANGE_Maximized| ARRANGE_WinlistSkip)
65 #define ARRANGE_Reversed	(0x01<<4)
66 #define ARRANGE_Desk		(0x01<<5)
67 #define ARRANGE_FlatX		(0x01<<6)
68 #define ARRANGE_FlatY		(0x01<<7)
69 #define ARRANGE_IncX		(0x01<<8)
70 #define ARRANGE_IncY		(0x01<<9)
71 #define ARRANGE_NoRaise		(0x01<<10)
72 #define ARRANGE_NoStretch	(0x01<<11)
73 #define ARRANGE_Resize		(0x01<<12)
74 #define ARRANGE_Tile		(0x01<<13)
75 #define ARRANGE_OffsetX_Set		(0x01<<14)
76 #define ARRANGE_OffsetY_Set		(0x01<<15)
77 #define ARRANGE_MaxWidth_Set	(0x01<<16)
78 #define ARRANGE_MaxHeight_Set	(0x01<<17)
79 #define ARRANGE_Tile_Horizontally	(0x01<<18)
80 #define ARRANGE_AllDesks                (0x01<<19)
81 #define ARRANGE_WinlistSkip             (0x01<<20)
82 #define ARRANGE_SmartTile                 (0x01<<21)
83 
84 struct ASArrangeState
85 {
86 	ASFlagType flags ;
87 	int incx, incy ;
88 	int count ;
89 
90 	int offset_x, offset_y ;
91 	int max_width, max_height ;
92 
93 	int curr_x, curr_y ;
94 
95 	int *elem, *group;
96 	int *elem_size, *group_size; /* in pixels */
97 	int start_elem; /* position of start_elem */
98 
99 	int tile_width, tile_height;
100 
101 	char *pattern;
102 
103 	ASBiDirList *clients_order;
104 
105 }ArrangeState;
106 
107 typedef struct
108 {
109 	Window cl;
110 }client_item;
111 
112 /**********************************************************************/
113 /**********************************************************************/
114 /* Our configuration options :                                        */
115 /**********************************************************************/
116 
117 /**********************************************************************/
118 void GetBaseOptions (const char *filename);
119 void HandleEvents();
120 void process_message (send_data_type type, send_data_type *body);
121 void tile_windows();
122 void cascade_windows();
123 void Arrange_DeadPipe(int);
124 
125 int
atopixel(char * s,int size)126 atopixel (char *s, int size)
127 {
128   	int l = strlen (s);
129   	if (l < 1)
130     	return 0;
131   	if (s[l-1] == 'p' || s[l-1] == 'P' )
132     {
133 	    /* number was followed by a p/P
134 	     * => number was already a pixel-value */
135 		s[l-1] = '\0' ;
136 		return atoi (s);
137     }
138   	/* return s percent of size */
139 	return (atoi (s) * size) / 100;
140 }
141 
142 void
select_suitable_windows(void)143 select_suitable_windows(void)
144 {
145 
146 	/* Select all windows, then get
147 	 * rid of those we don't want. */
148 	select_all( False );
149 
150 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
151 
152 	/* we don't want to arrange fullscreen-windows */
153         select_windows_by_flag( AS_Fullscreen, True);
154 	/* we do not want to arrange AfterSTep's modules */
155 
156 	select_windows_by_flag( AS_Module, True);
157 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
158 
159 	/* also we do not want to arrange AvoidCover windows : */
160 	select_windows_by_flag(AS_AvoidCover, True);
161 
162         /* Remove winlist-skip-windows if user doesn't want to
163 	   arrange them */
164 	if( !get_flags( ArrangeState.flags, ARRANGE_WinlistSkip))
165 		select_windows_by_flag(AS_SkipWinList, True);
166 
167 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
168 
169 	/* return if window is untitled and we don't want
170 	   to arrange untitled windows  */
171 	if( !get_flags( ArrangeState.flags, ARRANGE_Untitled ))
172 		select_untitled_windows(True);
173 
174 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
175 
176 	/* return if window is transient and we don't want
177 	   to arrange transient windows. */
178 	if( !get_flags( ArrangeState.flags, ARRANGE_Transient ))
179 		select_windows_by_flag(AS_Transient, True);
180 
181 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
182 
183 	/* return if window is sticky and we don't want
184 	   to arrange sticky windows. */
185 	if( !get_flags( ArrangeState.flags, ARRANGE_Sticky ))
186 		select_windows_by_state_flag(AS_Sticky, True);
187 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
188 
189 
190 	/*return if window is maximized and we don't want
191 	  to arrange maximized windows. */
192 
193 	if( !get_flags( ArrangeState.flags, ARRANGE_Maximized ))
194 		select_windows_by_state_flag(AS_MaximizedX|AS_MaximizedY|AS_Fullscreen, True);
195 
196 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
197 
198 	/* return if window is not on current desk and we don't want
199 	   to arrange windows of all desks. */
200 	if( !get_flags( ArrangeState.flags, ARRANGE_AllDesks))
201 	{
202 		select_windows_on_desk(False);
203 
204 		/* if user passed ARRANGE_AllDesks, it's safe to assume
205 		 * he wants to arrange on all screens as well, so we
206 		 * only check for ARRANGE_Desk if AllDesks was not set */
207 
208 	/* return if window is not on current screen and we don't want
209 	   to arrange windows on the whole desk. */
210 		if( !get_flags( ArrangeState.flags, ARRANGE_Desk))
211 			select_windows_on_screen(False);
212 	}
213 
214 	LOCAL_DEBUG_OUT("# Number of selected windows: %d\n", num_selected_windows());
215 
216 	/* If a pattern was specified, only select windows matching the pattern*/
217 	if( ArrangeState.pattern )
218 		select_windows_by_pattern(ArrangeState.pattern, False, False);
219 
220 }
221 
222 
223 int
main(int argc,char ** argv)224 main( int argc, char **argv )
225 {
226 	int i ;
227 	int nargc = 0 ;
228 	XRectangle *area;
229 	Bool resize_touched = False;
230 	/* Save our program name - for error messages */
231 	set_DeadPipe_handler(Arrange_DeadPipe);
232 	InitMyApp (CLASS_ARRANGE, argc, argv, NULL, NULL, OPTION_SINGLE|OPTION_RESTART );
233 	set_signal_handler( SIGSEGV );
234 	ConnectX( ASDefaultScr, 0 );
235 
236 	memset( &ArrangeState, 0x00, sizeof(ArrangeState));
237 
238 
239 	/* Set some sane default values if still unset */
240 
241 	ArrangeState.max_width = Scr.MyDisplayWidth ;
242 	ArrangeState.max_height = Scr.MyDisplayHeight ;
243 	ArrangeState.incx = 20 ;
244 	ArrangeState.incy = 20 ;
245 
246 
247     /* Check the Name of the Program to see wether to tile or cascade*/
248 	if( mystrcasecmp( MyName , "Tile" ) == 0 )
249 	{
250 		set_flags( ArrangeState.flags, ARRANGE_Tile	);
251 		set_flags( ArrangeState.flags, ARRANGE_Resize);
252 	}
253 
254 	for( i = 1 ; i< argc ; ++i)
255 	{
256 		if( argv[i] == NULL )
257 			continue;
258 		/*
259 		  From manpage of old Cascade:
260 		  Up to four numbers can be placed in the command line
261 		  that are not switches.
262 		  The first pair specify an x and y offset to start
263 		  the first window (default 0, 0). The second pair
264 		  specify a maximal width and height for layered windows.
265 		*/
266 		if( isdigit( argv[i][0] ) )
267 		{
268 			if( nargc == 0 )
269 			{
270 				ArrangeState.offset_x = atopixel( argv[i],  Scr.MyDisplayWidth );
271 				set_flags( ArrangeState.flags, ARRANGE_OffsetX_Set );
272 			}else if( nargc == 1 )
273 			{
274 				ArrangeState.offset_y = atopixel( argv[i], Scr.MyDisplayHeight  );
275 				set_flags( ArrangeState.flags, ARRANGE_OffsetY_Set );
276 			}else if( nargc == 2 )
277 			{
278 				ArrangeState.max_width = atopixel( argv[i], Scr.MyDisplayWidth );
279 				set_flags( ArrangeState.flags, ARRANGE_MaxWidth_Set );
280 			}else if( nargc == 3 )
281 			{
282 				ArrangeState.max_height = atopixel( argv[i], Scr.MyDisplayHeight );
283 				set_flags( ArrangeState.flags, ARRANGE_MaxHeight_Set );
284 			}
285 			++nargc ;
286 		}else if( argv[i][0] == '-' )
287 		{
288 			if( argv[i][1] == '\0' )
289 				continue;
290 			else if( argv[i][2] == '\0' )
291 			{
292 				switch( argv[i][1] )
293 				{
294 					case 'u' :     	/* Causes untitled windows to also be affected (implied by \-all). */
295 						set_flags( ArrangeState.flags, ARRANGE_Untitled );
296 				    	break ;
297 					case 't' :	   	/* Causes transient windows to also be affected (implied by \-all). */
298 						set_flags( ArrangeState.flags, ARRANGE_Transient );
299 				    	break ;
300 					case 's' :		/* Causes sticky windows to also be affected (implied by \-all). */
301 						set_flags( ArrangeState.flags, ARRANGE_Sticky );
302 				    	break ;
303 					case 'm' :		/* Causes maximized windows to also be affected (implied by \-all). */
304 						set_flags( ArrangeState.flags, ARRANGE_Maximized );
305 				    	break ;
306 					case 'a' :	   /* Causes \fIall\fP window styles to be affected, even ones with the WindowListSkip style. */
307 						set_flags( ArrangeState.flags, ARRANGE_All );
308 				    	break ;
309 					case 'r' :	   /* Reverses the window sequence. */
310 						set_flags( ArrangeState.flags, ARRANGE_Reversed );
311 				    	break ;
312 
313 				        case 'H': /* For tiling: Tile horizontally (Default is vertically ) */
314 
315 						set_flags( ArrangeState.flags, ARRANGE_Tile_Horizontally );
316 				        break;
317 				}
318 			}else if( mystrcasecmp( argv[i], "-desk" ) == 0 )
319 			{
320 				/* Causes all windows on the desk to be cascaded instead of the current screen only. */
321 				set_flags( ArrangeState.flags, ARRANGE_Desk );
322 			}else if( mystrcasecmp( argv[i], "-alldesks") == 0)
323 			{
324 				set_flags(ArrangeState.flags, ARRANGE_AllDesks);
325 			}
326 			else if( mystrcasecmp( argv[i], "-flatx" ) == 0 )
327 			{
328 				/* Inhibits border width increment. */
329 				set_flags( ArrangeState.flags, ARRANGE_FlatX );
330 			}else if( mystrcasecmp( argv[i], "-flaty" ) == 0 )
331 			{
332 				/* Inhibits border height increment. */
333 				set_flags( ArrangeState.flags, ARRANGE_FlatY );
334 			}else if( mystrcasecmp( argv[i], "-incx" ) == 0 && i+1 < argc && argv[i+1] != NULL )
335 			{
336 				/* Specifies a horizontal increment which is successively added to
337 					cascaded windows.  \fIarg\fP is a percentage of screen width, or pixel
338 					value if a \fIp\fP is suffixed.  Default is zero.
339 				 */
340 				++i ;
341 				ArrangeState.incx = atopixel (argv[i], Scr.MyDisplayWidth);
342 				set_flags( ArrangeState.flags, ARRANGE_IncX );
343 			}else if( mystrcasecmp( argv[i], "-incy" ) == 0 && i+1 < argc && argv[i+1] != NULL )
344 			{
345 				/* Specifies a vertical increment which is successively added to cascaded
346 					windows.  \fIarg\fP is a percentage of screen height, or pixel value
347 					if a \fIp\fP is suffixed.  Default is zero.
348 				 */
349 				++i ;
350 				ArrangeState.incy = atopixel (argv[i], Scr.MyDisplayHeight);
351 				set_flags( ArrangeState.flags, ARRANGE_IncY );
352 			}else if( mystrcasecmp( argv[i], "-noraise" ) == 0 )
353 			{
354 				/* Inhibits window raising, leaving the depth ordering intact. */
355 				set_flags( ArrangeState.flags, ARRANGE_NoRaise );
356 			}else if( mystrcasecmp( argv[i], "-nostretch" ) == 0 )
357 			{
358 				/* Inhibits window expansion when using the \-resize option.  Windows
359 				   will only shrink to fit the maximal width and height (if given).
360 				 */
361 				set_flags( ArrangeState.flags, ARRANGE_NoStretch );
362 			}else if( mystrcasecmp( argv[i], "-resize" ) == 0 )
363 			{
364 				/* Forces all windows to resize to the constrained width and height (if given). */
365 				set_flags( ArrangeState.flags, ARRANGE_Resize );
366 				resize_touched = True;
367 			}else if( mystrcasecmp( argv[i], "-noresize") == 0)
368 			{
369 				clear_flags( ArrangeState.flags, ARRANGE_Resize );
370 				resize_touched = True;
371 			}else if( mystrcasecmp( argv[i], "-tile") == 0 )
372 			{
373 				set_flags( ArrangeState.flags, ARRANGE_Tile	);
374 				if(! resize_touched )
375 					set_flags(ArrangeState.flags, ARRANGE_Resize );
376 			}
377 			else if( mystrcasecmp( argv[i], "-smart") == 0)
378 			{
379 				set_flags(ArrangeState.flags, ARRANGE_SmartTile);
380 			}else if( mystrcasecmp( argv[i], "-pattern") == 0 && i+1 <argc && argv[i+1] != NULL)
381 			{
382 				ArrangeState.pattern = argv[i+1];
383 			}
384 			/* these apply to tiling only : */
385 			else if( mystrcasecmp( argv[i], "-mn") == 0 && i+1 < argc )
386 			{
387 				/* Tiles up to \fIarg\fP windows in tile direction.  If more windows
388 				   exist, a new direction row or column is created (in effect, a matrix is created).
389 				 */
390 				++i ;
391 				ArrangeState.count = atoi( argv[i] );
392 			}
393 
394 		}
395 	}
396 
397 	ascom_init();
398 	/* Request a list of all windows, while we load our config */
399 	ascom_update_winlist();
400 
401 	LoadBaseConfig ( GetBaseOptions);
402 
403 	/* fix area */
404 	area = ascom_get_available_area();
405 
406 	if( !get_flags( ArrangeState.flags, ARRANGE_OffsetX_Set ) )
407 		ArrangeState.offset_x = area->x;
408 
409 	if( !get_flags( ArrangeState.flags, ARRANGE_OffsetY_Set ) )
410 		ArrangeState.offset_y = area->y;
411 
412 	if( !get_flags( ArrangeState.flags, ARRANGE_MaxWidth_Set ) )
413 		ArrangeState.max_width = area->width;
414 
415 	if( !get_flags( ArrangeState.flags, ARRANGE_MaxHeight_Set ) )
416 		ArrangeState.max_height = area->height;
417 
418 	free(area);
419 
420 	/************/
421 
422 	select_suitable_windows();
423 
424 	/* rearrange windows */
425 
426 	if( get_flags( ArrangeState.flags, ARRANGE_Tile	) )
427 		tile_windows();
428 	else
429 		cascade_windows();
430 
431 	ascom_wait();
432 	ascom_deinit();
433 
434 	/* exit */
435 	Arrange_DeadPipe (0);
436 
437 	return 0 ;
438 }
439 
440 
441 void
Arrange_DeadPipe(int nonsense)442 Arrange_DeadPipe (int nonsense)
443 {
444 	static int already_dead = False ;
445 	if( already_dead )
446 		return;/* non-reentrant function ! */
447 	already_dead = True ;
448 
449 	window_data_cleanup();
450 
451 	FreeMyAppResources();
452 
453 #ifdef DEBUG_ALLOCS
454     print_unfreed_mem ();
455 #endif /* DEBUG_ALLOCS */
456 
457     XFlush (dpy);			/* need this for SetErootPixmap to take effect */
458 	XCloseDisplay (dpy);		/* need this for SetErootPixmap to take effect */
459     exit (0);
460 }
461 
462 void
GetBaseOptions(const char * filename)463 GetBaseOptions (const char *filename)
464 {
465 	ReloadASEnvironment( NULL, NULL, NULL, False, False );
466 }
467 
468 
469 /********************************************************************/
470 /* showing our main window :                                        */
471 /********************************************************************/
472 
473 void
tile_windows()474 tile_windows()
475 {
476 	int n_groups;
477 	int n_windows = num_selected_windows();
478 	Bool reverse = get_flags(ArrangeState.flags, ARRANGE_Reversed);
479 
480 	LOCAL_DEBUG_OUT("Number of windows to be arranged: %d\n", n_windows);
481 	LOCAL_DEBUG_OUT("max_width/max_height: %d/%d\n", ArrangeState.max_width, ArrangeState.max_height);
482 
483         /* If number of elements per group was not set */
484 	if(ArrangeState.count == 0)
485 	{
486 		if( ! get_flags(ArrangeState.flags, ARRANGE_SmartTile) )
487 			ArrangeState.count = n_windows; /*Put all elements in one group*/
488 		else
489 			ArrangeState.count = (int) sqrt(n_windows);
490 	}
491 	n_groups = n_windows / ArrangeState.count;
492 	/* If not all windows fit in n_groups groups, an
493 	 * extra group for remaining windows is needed.*/
494 	if(n_windows % ArrangeState.count)
495 		n_groups++;
496 
497 	LOCAL_DEBUG_OUT("ngroups: %d", n_groups);
498 
499 	ArrangeState.curr_x = ArrangeState.offset_x ;
500 	ArrangeState.curr_y = ArrangeState.offset_y ;
501 
502 	LOCAL_DEBUG_OUT("curr_x/curr_y: %d/%d\n", ArrangeState.curr_x, ArrangeState.curr_y);
503 
504 	if(get_flags( ArrangeState.flags, ARRANGE_Tile_Horizontally))
505 	{
506 		ArrangeState.start_elem = ArrangeState.curr_x;
507 		ArrangeState.elem = &ArrangeState.curr_x;
508 		ArrangeState.group = &ArrangeState.curr_y;
509 
510 		ArrangeState.tile_width =
511 			ArrangeState.max_width / ArrangeState.count;
512 		ArrangeState.tile_height =
513 			ArrangeState.max_height/ n_groups ;
514 
515 		ArrangeState.elem_size = &ArrangeState.tile_width;
516 		ArrangeState.group_size =  &ArrangeState.tile_height;
517 
518 	}else
519 	{
520 		ArrangeState.start_elem = ArrangeState.curr_y;
521 		ArrangeState.elem = &ArrangeState.curr_y;
522 		ArrangeState.group = &ArrangeState.curr_x;
523 
524 		ArrangeState.tile_width =
525 			ArrangeState.max_width / n_groups;
526 		ArrangeState.tile_height =
527 			ArrangeState.max_height / ArrangeState.count ;
528 
529 		ArrangeState.elem_size = &ArrangeState.tile_height;
530 		ArrangeState.group_size = &ArrangeState.tile_width ;
531 	}
532 
533 	while(! winlist_is_empty() )
534 	{
535 		move_params p;
536 		const ASWindowData *wd;
537 
538 		/* If group is full */
539 		if(*(ArrangeState.elem) ==
540 		   (ArrangeState.start_elem +
541 		    ArrangeState.count * *(ArrangeState.elem_size)))
542 		{
543 			/* Make new group */
544 			*(ArrangeState.group)+= *(ArrangeState.group_size);
545 			/* Make this the first item of the new group */
546 			*(ArrangeState.elem) = ArrangeState.start_elem;
547 		}
548 
549 
550 		/* Raise the client if allowed */
551 		if( !get_flags( ArrangeState.flags, ARRANGE_NoRaise ) )
552 			ascom_do_one("raise", NULL, reverse);
553 
554 
555 		/* If the client is iconified, deiconify it. */
556 		ascom_do_one("deiconify", NULL, reverse);
557 
558 		p.x = ArrangeState.curr_x;
559 		p.y = ArrangeState.curr_y;
560 
561 		/* Move window */
562 		ascom_do_one("move", &p, reverse);
563 
564 		wd = ascom_get_next_window( reverse );
565 
566 		/* Make sure we don't stretch if ARRANGE_NoStretch was set */
567 		if ( !( get_flags( ArrangeState.flags, ARRANGE_NoStretch) &&
568 			(    (wd->frame_rect.width < ArrangeState.tile_width)
569 			     || (wd->frame_rect.height < ArrangeState.tile_height)
570 				)))
571 		{
572 			resize_params rparams;
573 			rparams.width = ArrangeState.tile_width ;
574 			rparams.height = ArrangeState.tile_height ;
575                         /* Resize window if allowed*/
576 			if( get_flags(ArrangeState.flags, ARRANGE_Resize ))
577 				ascom_do_one("resize", &rparams, reverse);
578 		}
579 
580 
581 		/* Transfer window onto CurrentDesk */
582 		if( wd->desk != Scr.CurrentDesk )
583 		{
584 			send_to_desk_params p;
585 			p.desk = Scr.CurrentDesk;
586 			LOCAL_DEBUG_OUT("#CurrentDesk: %d", Scr.CurrentDesk);
587 
588 			ascom_do_one("sendtodesk", &p, reverse);
589 		}
590 
591 		(*(ArrangeState.elem))+= *ArrangeState.elem_size;
592 
593 		ascom_pop_winlist(reverse);
594 	}
595 
596 }
597 
598 /* Cascade */
599 
600 void
cascade_windows()601 cascade_windows()
602 {
603 
604 	ArrangeState.curr_x = ArrangeState.offset_x ;
605 	ArrangeState.curr_y = ArrangeState.offset_y ;
606 
607 
608 	while( !winlist_is_empty() )
609 	{
610 		move_params p;
611 		const ASWindowData *wd;
612 		Bool reverse = get_flags(ArrangeState.flags, ARRANGE_Reversed);
613 
614 		/* Raise the client if allowed */
615 		if( !get_flags( ArrangeState.flags, ARRANGE_NoRaise ) )
616 			ascom_do_one("raise", NULL, reverse);
617 
618 
619 		/* If the client is iconified, deiconify it. */
620 		ascom_do_one("deiconify", NULL, reverse);
621 
622 		/* move window */
623 		p.x = ArrangeState.curr_x;
624 		p.y = ArrangeState.curr_y;
625 		ascom_do_one("move", &p, reverse);
626 
627 		ArrangeState.curr_x += ArrangeState.incx ;
628 		ArrangeState.curr_y += ArrangeState.incy ;
629 
630 		wd = ascom_get_next_window(reverse);
631 
632 		if( get_flags( ArrangeState.flags, ARRANGE_Resize ) )
633 		{
634 			/* Make sure we don't stretch of ARRANGE_NoStretch was set */
635 			if ( !( get_flags( ArrangeState.flags, ARRANGE_NoStretch) &&
636 				(    (wd->frame_rect.width < ArrangeState.max_width)
637 				     || (wd->frame_rect.height < ArrangeState.max_height)
638 					)))
639 			{
640 				resize_params rp;
641 				rp.width = ArrangeState.max_width ;
642 				rp.height = ArrangeState.max_height ;
643 				if( get_flags( ArrangeState.flags, ARRANGE_Resize) )
644 					ascom_do_one("resize", &rp, reverse);
645 			}
646 		}
647 
648 		/* Transfer window onto CurrentDesk */
649 		if( wd->desk != Scr.CurrentDesk )
650 		{
651 			send_to_desk_params p;
652 			p.desk = Scr.CurrentDesk;
653 
654 			ascom_do_one("sendtodesk", &p, reverse);
655 		}
656 
657 
658 		ascom_pop_winlist(reverse);
659 	}
660 
661 }
662