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