1 /* -*-c-*- */
2 /*
3  * FvwmRearrange.c -- fvwm module to arrange windows
4  *
5  * Copyright (C) 1996, 1997, 1998, 1999 Andrew T. Veliath
6  *
7  * Version 1.0
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see: <http://www.gnu.org/licenses/>
21  *
22  * Combined FvwmTile and FvwmCascade to FvwmRearrange module.
23  * 9-Nov-1998 Dominik Vogt
24  */
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <ctype.h>
29 #include "libs/ftime.h"
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <signal.h>
33 
34 #ifdef HAVE_SYS_BSDTYPES_H
35 #include <sys/bsdtypes.h>
36 #endif
37 
38 #if HAVE_SYS_SELECT_H
39 #include <sys/select.h>
40 #endif
41 
42 #include <X11/Xlib.h>
43 
44 #include "libs/fvwmlib.h"
45 #include "libs/FScreen.h"
46 #include "libs/Module.h"
47 #include "fvwm/fvwm.h"
48 #include "libs/vpacket.h"
49 #include "libs/System.h"
50 
51 typedef struct window_item {
52 	Window frame;
53 	int th, bw;
54 	unsigned long width, height;
55 	struct window_item *prev, *next;
56 } window_item, *window_list;
57 
58 /* vars */
59 Display *dpy;
60 int dx, dy;
61 int dwidth, dheight;
62 static ModuleArgs *module;
63 int fd[2];
64 fd_set_size_t fd_width;
65 window_list wins = NULL, wins_tail = NULL;
66 int wins_count = 0;
67 FILE *console;
68 
69 /* switches */
70 int ofsx = 0, ofsy = 0;
71 int maxw = 0, maxh = 0;
72 int maxx, maxy;
73 int untitled = 0, transients = 0;
74 int maximized = 0;
75 int all = 0;
76 int desk = 0;
77 int reversed = 0, raise_window = 1;
78 int resize = 0;
79 int nostretch = 0;
80 int sticky_page = 0;
81 int sticky_desk = 0;
82 int flatx = 0, flaty = 0;
83 int incx = 0, incy = 0;
84 int horizontal = 0;
85 int maxnum = 0;
86 
87 int do_maximize = 0;
88 int do_animate = 0;
89 int do_ewmhiwa = 0;
90 
91 char FvwmTile;
92 char FvwmCascade;
93 
94 
DeadPipe(int sig)95 RETSIGTYPE DeadPipe(int sig)
96 {
97   exit(0);
98   SIGNAL_RETURN;
99 }
100 
insert_window_list(window_list * wl,window_item * i)101 void insert_window_list(window_list *wl, window_item *i)
102 {
103   if (*wl) {
104     if ((i->prev = (*wl)->prev))
105       i->prev->next = i;
106     i->next = *wl;
107     (*wl)->prev = i;
108   } else
109     i->next = i->prev = NULL;
110   *wl = i;
111 }
112 
free_window_list(window_list wl)113 void free_window_list(window_list wl)
114 {
115   window_item *q;
116 
117   while (wl)
118   {
119     q = wl;
120     wl = wl->next;
121     free(q);
122   }
123 }
124 
is_suitable_window(unsigned long * body)125 int is_suitable_window(unsigned long *body)
126 {
127   XWindowAttributes xwa;
128   struct ConfigWinPacket  *cfgpacket = (void *) body;
129 
130   if ((DO_SKIP_WINDOW_LIST(cfgpacket)) && !all)
131     return 0;
132 
133   if ((IS_MAXIMIZED(cfgpacket)) && !maximized)
134     return 0;
135 
136   if ((IS_STICKY_ACROSS_PAGES(cfgpacket)) && !sticky_page)
137     return 0;
138 
139   if ((IS_STICKY_ACROSS_DESKS(cfgpacket)) && !sticky_desk)
140     return 0;
141 
142   if (!XGetWindowAttributes(dpy, cfgpacket->w, &xwa))
143     return 0;
144 
145   if (xwa.map_state != IsViewable)
146     return 0;
147 
148   if (!(IS_MAPPED(cfgpacket)))
149     return 0;
150 
151   if (IS_ICONIFIED(cfgpacket))
152     return 0;
153 
154   if (!desk)
155   {
156     int x = (int)cfgpacket->frame_x, y = (int)cfgpacket->frame_y;
157     int w = (int)cfgpacket->frame_width, h = (int)cfgpacket->frame_height;
158     if (x >= dx + dwidth || y >= dy + dheight || x + w <= dx || y + h <= dy)
159       return 0;
160   }
161 
162   if (!(HAS_TITLE(cfgpacket)) && !untitled)
163     return 0;
164 
165   if ((IS_TRANSIENT(cfgpacket)) && !transients)
166     return 0;
167 
168   return 1;
169 }
170 
get_window(void)171 int get_window(void)
172 {
173   FvwmPacket* packet;
174   struct ConfigWinPacket  *cfgpacket;
175   int last = 0;
176   fd_set infds;
177 
178   FD_ZERO(&infds);
179   FD_SET(fd[1], &infds);
180   select(fd_width, SELECT_FD_SET_CAST &infds, 0, 0, NULL);
181 
182   if ( (packet = ReadFvwmPacket(fd[1])) == NULL )
183     DeadPipe(0);
184   else {
185     cfgpacket = (struct ConfigWinPacket*) packet->body;
186     switch (packet->type) {
187     case M_CONFIGURE_WINDOW:
188       if (is_suitable_window(packet->body)) {
189 	window_item *wi =
190 	  (window_item*)safemalloc(sizeof( window_item ));
191 	wi->frame = cfgpacket->frame;
192 	wi->th = cfgpacket->title_height;
193 	wi->bw = cfgpacket->border_width;
194 	wi->width = cfgpacket->frame_width;
195 	wi->height = cfgpacket->frame_height;
196 	if (!wins_tail) wins_tail = wi;
197 	insert_window_list(&wins, wi);
198 	++wins_count;
199       }
200       last = 1;
201       break;
202 
203     case M_END_WINDOWLIST:
204       break;
205 
206     default:
207       fprintf(console,
208 	"%s: internal inconsistency: unknown message 0x%08x\n",
209 	module->name, (int)packet->type);
210       break;
211     }
212   }
213   return last;
214 }
215 
wait_configure(window_item * wi)216 void wait_configure(window_item *wi)
217 {
218   int found = 0;
219 
220   /** Uh, what's the point of the select() here?? **/
221   fd_set infds;
222   FD_ZERO(&infds);
223   FD_SET(fd[1], &infds);
224   select(fd_width, SELECT_FD_SET_CAST &infds, 0, 0, NULL);
225 
226   while (!found) {
227     FvwmPacket* packet = ReadFvwmPacket(fd[1]);
228     if ( packet == NULL )
229       DeadPipe(0);
230     if ( packet->type == M_CONFIGURE_WINDOW
231 	 && (Window)(packet->body[1]) == wi->frame )
232       found = 1;
233   }
234 }
235 
atopixel(char * s,unsigned long f)236 int atopixel(char *s, unsigned long f)
237 {
238   int l = strlen(s);
239   if (l < 1) return 0;
240   if (isalpha(s[l - 1])) {
241     char s2[24];
242     strcpy(s2,s);
243     s2[strlen(s2) - 1] = 0;
244     return atoi(s2);
245   }
246   return (atoi(s) * f) / 100;
247 }
248 
move_resize_raise_window(window_item * wi,int x,int y,int w,int h)249 void move_resize_raise_window(
250 	window_item *wi, int x, int y, int w, int h)
251 {
252 	static char msg[64];
253 	const char *ewmhiwa = do_ewmhiwa ?
254 		"ewmhiwa" : "";
255 
256 	if (resize)
257 	{
258 		const char *function = do_maximize?
259 			"ResizeMoveMaximize":
260 			"ResizeMove";
261 		sprintf(msg, "%s %dp %dp %up %upi %s", function, w, h, x, y,
262 			ewmhiwa);
263 		SendText(fd, msg, wi->frame);
264 	}
265 	else
266 	{
267 		const char *function = do_maximize?
268 			"ResizeMoveMaximize":
269 			do_animate ? "AnimatedMove" : "Move";
270 		if (do_maximize)
271 			sprintf(msg, "%s keep keep %up %up %s", function, x, y,
272 				ewmhiwa);
273 		else
274 			sprintf(msg, "%s %up %up %s", function, x, y, ewmhiwa);
275 		SendText(fd, msg, wi->frame);
276 	}
277 
278 	if (raise_window)
279 		SendText(fd, "Raise", wi->frame);
280 
281 	wait_configure(wi);
282 }
283 
tile_windows(void)284 void tile_windows(void)
285 {
286   int cur_x = ofsx, cur_y = ofsy;
287   int final_w = -1, final_h = -1;
288   int wdiv, hdiv, i, j, count = 1;
289   window_item *w = reversed ? wins_tail : wins;
290 
291   if (horizontal) {
292     if ((maxnum > 0) && (maxnum < wins_count)) {
293       count = wins_count / maxnum;
294       if (wins_count % maxnum) ++count;
295       hdiv = (maxy - ofsy + 1) / maxnum;
296     } else {
297       maxnum = wins_count;
298       hdiv = (maxy - ofsy + 1) / wins_count;
299     }
300     wdiv = (maxx - ofsx + 1) / count;
301 
302     for (i = 0; w && (i < count); ++i)  {
303       for (j = 0; w && (j < maxnum); ++j) {
304 	int nw = wdiv - w->bw * 2;
305 	int nh = hdiv - w->bw * 2 - w->th;
306 
307 	if (resize) {
308 	  if (nostretch) {
309 	    if (nw > w->width)
310 	      nw = w->width;
311 	    if (nh > w->height)
312 	      nh = w->height;
313 	  }
314 	  final_w = (nw > 0) ? nw : w->width;
315 	  final_h = (nh > 0) ? nh : w->height;
316 	}
317 	move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
318 
319 	cur_y += hdiv;
320 	w = reversed ? w->prev : w->next;
321       }
322       cur_x += wdiv;
323       cur_y = ofsy;
324     }
325   } else  {
326     if ((maxnum > 0) && (maxnum < wins_count)) {
327       count = wins_count / maxnum;
328       if (wins_count % maxnum) ++count;
329       wdiv = (maxx - ofsx + 1) / maxnum;
330     } else {
331       maxnum = wins_count;
332       wdiv = (maxx - ofsx + 1) / wins_count;
333     }
334     hdiv = (maxy - ofsy + 1) / count;
335 
336     for (i = 0; w && (i < count); ++i)  {
337       for (j = 0; w && (j < maxnum); ++j) {
338 	int nw = wdiv - w->bw * 2;
339 	int nh = hdiv - w->bw * 2 - w->th;
340 
341 	if (resize) {
342 	  if (nostretch) {
343 	    if (nw > w->width)
344 	      nw = w->width;
345 	    if (nh > w->height)
346 	      nh = w->height;
347 	  }
348 	  final_w = (nw > 0) ? nw : w->width;
349 	  final_h = (nh > 0) ? nh : w->height;
350 	}
351 	move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
352 
353 	cur_x += wdiv;
354 	w = reversed ? w->prev : w->next;
355       }
356       cur_x = ofsx;
357       cur_y += hdiv;
358     }
359   }
360 }
361 
cascade_windows(void)362 void cascade_windows(void)
363 {
364   int cur_x = ofsx, cur_y = ofsy;
365   int final_w = -1, final_h = -1;
366   window_item *w = reversed ? wins_tail : wins;
367   while (w)
368   {
369     unsigned long nw = 0, nh = 0;
370     if (resize) {
371       if (nostretch) {
372 	if (maxw
373 	    && (w->width > maxw))
374 	  nw = maxw;
375 	if (maxh
376 	    && (w->height > maxh))
377 	  nh = maxh;
378       } else {
379 	nw = maxw;
380 	nh = maxh;
381       }
382       if (nw || nh) {
383 	final_w = nw ? nw : w->width;
384 	final_h = nh ? nh : w->height;
385       }
386     }
387     move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
388 
389     if (!flatx)
390       cur_x += w->bw;
391     cur_x += incx;
392     if (!flaty)
393       cur_y += w->bw + w->th;
394     cur_y += incy;
395     w = reversed ? w->prev : w->next;
396   }
397 }
398 
parse_args(char * s,int argc,char * argv[],int argi)399 void parse_args(char *s, int argc, char *argv[], int argi)
400 {
401   int nsargc = 0;
402   /* parse args */
403   for (; argi < argc; ++argi)
404   {
405     if (!strcmp(argv[argi], "-tile") || !strcmp(argv[argi], "-cascade")) {
406       /* ignore */
407     }
408     else if (!strcmp(argv[argi], "-u")) {
409       untitled = 1;
410     }
411     else if (!strcmp(argv[argi], "-t")) {
412       transients = 1;
413     }
414     else if (!strcmp(argv[argi], "-a")) {
415       all = untitled = transients = maximized = 1;
416       if (FvwmCascade) {
417 		sticky_page = 1;
418 		sticky_desk = 1;
419       }
420     }
421     else if (!strcmp(argv[argi], "-r")) {
422       reversed = 1;
423     }
424     else if (!strcmp(argv[argi], "-noraise")) {
425       raise_window = 0;
426     }
427     else if (!strcmp(argv[argi], "-noresize")) {
428       resize = 0;
429     }
430     else if (!strcmp(argv[argi], "-nostretch")) {
431       nostretch = 1;
432     }
433     else if (!strcmp(argv[argi], "-desk")) {
434       desk = 1;
435     }
436     else if (!strcmp(argv[argi], "-flatx")) {
437       flatx = 1;
438     }
439     else if (!strcmp(argv[argi], "-flaty")) {
440       flaty = 1;
441     }
442     else if (!strcmp(argv[argi], "-r")) {
443       reversed = 1;
444     }
445     else if (!strcmp(argv[argi], "-h")) {
446       horizontal = 1;
447     }
448     else if (!strcmp(argv[argi], "-m")) {
449       maximized = 1;
450     }
451     else if (!strcmp(argv[argi], "-s")) {
452       sticky_page = 1;
453       sticky_desk = 1;
454     }
455     else if (!strcmp(argv[argi], "-sp")) {
456       sticky_page = 1;
457     }
458     else if (!strcmp(argv[argi], "-sd")) {
459       sticky_desk = 1;
460     }
461     else if (!strcmp(argv[argi], "-mn") && ((argi + 1) < argc)) {
462       maxnum = atoi(argv[++argi]);
463     }
464     else if (!strcmp(argv[argi], "-resize")) {
465       resize = 1;
466     }
467     else if (!strcmp(argv[argi], "-nostretch")) {
468       nostretch = 1;
469     }
470     else if (!strcmp(argv[argi], "-incx") && ((argi + 1) < argc)) {
471       incx = atopixel(argv[++argi], dwidth);
472     }
473     else if (!strcmp(argv[argi], "-incy") && ((argi + 1) < argc)) {
474       incy = atopixel(argv[++argi], dheight);
475     }
476     else if (!strcmp(argv[argi], "-ewmhiwa")) {
477 	    do_ewmhiwa = 1;
478     }
479     else if (!strcmp(argv[argi], "-maximize")) {
480       do_maximize = 1;
481     }
482     else if (!strcmp(argv[argi], "-nomaximize")) {
483       do_maximize = 0;
484     }
485     else if (!strcmp(argv[argi], "-animate")) {
486       do_animate = 1;
487     }
488     else if (!strcmp(argv[argi], "-noanimate")) {
489       do_animate = 0;
490     }
491     else {
492       if (++nsargc > 4) {
493 	fprintf(console,
494 		"%s: %s: ignoring unknown arg %s\n",
495 		module->name, s, argv[argi]);
496 	continue;
497       }
498       if (nsargc == 1) {
499 	ofsx = atopixel(argv[argi], dwidth);
500       } else if (nsargc == 2) {
501 	ofsy = atopixel(argv[argi], dheight);
502       } else if (nsargc == 3) {
503 	if (FvwmCascade)
504 	  maxw = atopixel(argv[argi], dwidth);
505 	else /* FvwmTile */
506 	  maxx = atopixel(argv[argi], dwidth);
507       } else if (nsargc == 4) {
508 	if (FvwmCascade)
509 	  maxh = atopixel(argv[argi], dheight);
510 	else /* FvwmTile */
511 	  maxy = atopixel(argv[argi], dheight);
512       }
513     }
514   }
515   ofsx += dx;
516   ofsy += dy;
517   maxx += dx;
518   maxy += dy;
519 }
520 
main(int argc,char * argv[])521 int main(int argc, char *argv[])
522 {
523   char match[128];
524   char *config_line;
525 
526   console = fopen("/dev/console","w");
527   if (!console) console = stderr;
528 
529   module = ParseModuleArgs(argc,argv,0);
530   if (module == NULL)
531   {
532     fprintf(stderr,"FvwmRearrange: module should be executed by fvwm only\n");
533     exit(-1);
534   }
535 
536   fd[0] = module->to_fvwm;
537   fd[1] = module->from_fvwm;
538 
539   if (!(dpy = XOpenDisplay(NULL))) {
540     fprintf(console, "%s: couldn't open display %s\n",
541 	    module->name,
542 	    XDisplayName(NULL));
543     exit(-1);
544   }
545   signal (SIGPIPE, DeadPipe);
546 
547   FScreenInit(dpy);
548   fd_width = GetFdWidth();
549 
550   strcpy(match, "*");
551   strcat(match, module->name);
552   InitGetConfigLine(fd,match);
553   GetConfigLine(fd, &config_line);
554   while (config_line != NULL)
555   {
556     if (strncasecmp(config_line, XINERAMA_CONFIG_STRING,
557 		    sizeof(XINERAMA_CONFIG_STRING) - 1) == 0)
558     {
559       FScreenConfigureModule(
560 	config_line + sizeof(XINERAMA_CONFIG_STRING) - 1);
561     }
562     GetConfigLine(fd, &config_line);
563   }
564   FScreenGetScrRect(NULL, FSCREEN_CURRENT, &dx, &dy, &dwidth, &dheight);
565 
566   if (strcmp(module->name, "FvwmCascade") &&
567       (!strcmp(module->name, "FvwmTile") ||
568        (argc >= 7 && !strcmp(argv[6], "-tile")))) {
569     FvwmTile = 1;
570     FvwmCascade = 0;
571     resize = 1;
572   } else {
573     FvwmCascade = 1;
574     FvwmTile = 0;
575     resize = 0;
576   }
577   parse_args("module args", module->user_argc, module->user_argv, 0);
578 
579   SetMessageMask(fd,
580 		 M_CONFIGURE_WINDOW |
581 		 M_END_WINDOWLIST);
582   SetMessageMask(fd,
583 		 M_EXTENDED_MSG);
584 
585   if (FvwmTile) {
586     if (maxx == dx)
587       maxx = dx + dwidth;
588     if (maxy == dy)
589       maxy = dy + dheight;
590   }
591 
592   SendText(fd, "Send_WindowList", 0);
593 
594   /* tell fvwm we're running */
595   SendFinishedStartupNotification(fd);
596 
597   while (get_window()) /* */;
598   if (wins_count) {
599     if (FvwmCascade)
600       cascade_windows();
601     else /* FvwmTile */
602       tile_windows();
603   }
604   free_window_list(wins);
605 
606   if (console != stderr)
607     fclose(console);
608 
609   return 0;
610 }
611