todo-2.6 -- add note for fvwm-menu-desktop (2.6.X release)
[fvwm.git] / modules / FvwmRearrange / FvwmRearrange.c
blobaf7c897064a87d7d27951f5cda80bfb46fa2382a
1 /* -*-c-*- */
2 /*
3 * FvwmRearrange.c -- fvwm module to arrange windows
5 * Copyright (C) 1996, 1997, 1998, 1999 Andrew T. Veliath
7 * Version 1.0
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.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Combined FvwmTile and FvwmCascade to FvwmRearrange module.
24 * 9-Nov-1998 Dominik Vogt
26 #include "config.h"
28 #include <stdio.h>
29 #include <ctype.h>
30 #include "libs/ftime.h"
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <signal.h>
35 #ifdef HAVE_SYS_BSDTYPES_H
36 #include <sys/bsdtypes.h>
37 #endif
39 #if HAVE_SYS_SELECT_H
40 #include <sys/select.h>
41 #endif
43 #include <X11/Xlib.h>
45 #include "libs/fvwmlib.h"
46 #include "libs/FScreen.h"
47 #include "libs/Module.h"
48 #include "fvwm/fvwm.h"
49 #include "libs/vpacket.h"
50 #include "libs/System.h"
52 typedef struct window_item {
53 Window frame;
54 int th, bw;
55 unsigned long width, height;
56 struct window_item *prev, *next;
57 } window_item, *window_list;
59 /* vars */
60 Display *dpy;
61 int dx, dy;
62 int dwidth, dheight;
63 static ModuleArgs *module;
64 int fd[2];
65 fd_set_size_t fd_width;
66 window_list wins = NULL, wins_tail = NULL;
67 int wins_count = 0;
68 FILE *console;
70 /* switches */
71 int ofsx = 0, ofsy = 0;
72 int maxw = 0, maxh = 0;
73 int maxx, maxy;
74 int untitled = 0, transients = 0;
75 int maximized = 0;
76 int all = 0;
77 int desk = 0;
78 int reversed = 0, raise_window = 1;
79 int resize = 0;
80 int nostretch = 0;
81 int sticky_page = 0;
82 int sticky_desk = 0;
83 int flatx = 0, flaty = 0;
84 int incx = 0, incy = 0;
85 int horizontal = 0;
86 int maxnum = 0;
88 int do_maximize = 0;
89 int do_animate = 0;
91 char FvwmTile;
92 char FvwmCascade;
95 RETSIGTYPE DeadPipe(int sig)
97 exit(0);
98 SIGNAL_RETURN;
101 void insert_window_list(window_list *wl, window_item *i)
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;
113 void free_window_list(window_list wl)
115 window_item *q;
117 while (wl)
119 q = wl;
120 wl = wl->next;
121 free(q);
125 int is_suitable_window(unsigned long *body)
127 XWindowAttributes xwa;
128 struct ConfigWinPacket *cfgpacket = (void *) body;
130 if ((DO_SKIP_WINDOW_LIST(cfgpacket)) && !all)
131 return 0;
133 if ((IS_MAXIMIZED(cfgpacket)) && !maximized)
134 return 0;
136 if ((IS_STICKY_ACROSS_PAGES(cfgpacket)) && !sticky_page)
137 return 0;
139 if ((IS_STICKY_ACROSS_DESKS(cfgpacket)) && !sticky_desk)
140 return 0;
142 if (!XGetWindowAttributes(dpy, cfgpacket->w, &xwa))
143 return 0;
145 if (xwa.map_state != IsViewable)
146 return 0;
148 if (!(IS_MAPPED(cfgpacket)))
149 return 0;
151 if (IS_ICONIFIED(cfgpacket))
152 return 0;
154 if (!desk)
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;
162 if (!(HAS_TITLE(cfgpacket)) && !untitled)
163 return 0;
165 if ((IS_TRANSIENT(cfgpacket)) && !transients)
166 return 0;
168 return 1;
171 int get_window(void)
173 FvwmPacket* packet;
174 struct ConfigWinPacket *cfgpacket;
175 int last = 0;
176 fd_set infds;
178 FD_ZERO(&infds);
179 FD_SET(fd[1], &infds);
180 select(fd_width, SELECT_FD_SET_CAST &infds, 0, 0, NULL);
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;
200 last = 1;
201 break;
203 case M_END_WINDOWLIST:
204 break;
206 default:
207 fprintf(console,
208 "%s: internal inconsistency: unknown message 0x%08x\n",
209 module->name, (int)packet->type);
210 break;
213 return last;
216 void wait_configure(window_item *wi)
218 int found = 0;
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);
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;
236 int atopixel(char *s, unsigned long f)
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);
246 return (atoi(s) * f) / 100;
249 void move_resize_raise_window(
250 window_item *wi, int x, int y, int w, int h)
252 static char msg[64];
254 if (resize)
256 const char *function = do_maximize?
257 "ResizeMoveMaximize":
258 "ResizeMove";
259 sprintf(msg, "%s %dp %dp %up %up", function, w, h, x, y);
260 SendText(fd, msg, wi->frame);
262 else
264 const char *function = do_maximize?
265 "ResizeMoveMaximize":
266 do_animate ? "AnimatedMove" : "Move";
267 if (do_maximize)
268 sprintf(msg, "%s keep keep %up %up", function, x, y);
269 else
270 sprintf(msg, "%s %up %up", function, x, y);
271 SendText(fd, msg, wi->frame);
274 if (raise_window)
275 SendText(fd, "Raise", wi->frame);
277 wait_configure(wi);
280 void tile_windows(void)
282 int cur_x = ofsx, cur_y = ofsy;
283 int final_w = -1, final_h = -1;
284 int wdiv, hdiv, i, j, count = 1;
285 window_item *w = reversed ? wins_tail : wins;
287 if (horizontal) {
288 if ((maxnum > 0) && (maxnum < wins_count)) {
289 count = wins_count / maxnum;
290 if (wins_count % maxnum) ++count;
291 hdiv = (maxy - ofsy + 1) / maxnum;
292 } else {
293 maxnum = wins_count;
294 hdiv = (maxy - ofsy + 1) / wins_count;
296 wdiv = (maxx - ofsx + 1) / count;
298 for (i = 0; w && (i < count); ++i) {
299 for (j = 0; w && (j < maxnum); ++j) {
300 int nw = wdiv - w->bw * 2;
301 int nh = hdiv - w->bw * 2 - w->th;
303 if (resize) {
304 if (nostretch) {
305 if (nw > w->width)
306 nw = w->width;
307 if (nh > w->height)
308 nh = w->height;
310 final_w = (nw > 0) ? nw : w->width;
311 final_h = (nh > 0) ? nh : w->height;
313 move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
315 cur_y += hdiv;
316 w = reversed ? w->prev : w->next;
318 cur_x += wdiv;
319 cur_y = ofsy;
321 } else {
322 if ((maxnum > 0) && (maxnum < wins_count)) {
323 count = wins_count / maxnum;
324 if (wins_count % maxnum) ++count;
325 wdiv = (maxx - ofsx + 1) / maxnum;
326 } else {
327 maxnum = wins_count;
328 wdiv = (maxx - ofsx + 1) / wins_count;
330 hdiv = (maxy - ofsy + 1) / count;
332 for (i = 0; w && (i < count); ++i) {
333 for (j = 0; w && (j < maxnum); ++j) {
334 int nw = wdiv - w->bw * 2;
335 int nh = hdiv - w->bw * 2 - w->th;
337 if (resize) {
338 if (nostretch) {
339 if (nw > w->width)
340 nw = w->width;
341 if (nh > w->height)
342 nh = w->height;
344 final_w = (nw > 0) ? nw : w->width;
345 final_h = (nh > 0) ? nh : w->height;
347 move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
349 cur_x += wdiv;
350 w = reversed ? w->prev : w->next;
352 cur_x = ofsx;
353 cur_y += hdiv;
358 void cascade_windows(void)
360 int cur_x = ofsx, cur_y = ofsy;
361 int final_w = -1, final_h = -1;
362 window_item *w = reversed ? wins_tail : wins;
363 while (w)
365 unsigned long nw = 0, nh = 0;
366 if (resize) {
367 if (nostretch) {
368 if (maxw
369 && (w->width > maxw))
370 nw = maxw;
371 if (maxh
372 && (w->height > maxh))
373 nh = maxh;
374 } else {
375 nw = maxw;
376 nh = maxh;
378 if (nw || nh) {
379 final_w = nw ? nw : w->width;
380 final_h = nh ? nh : w->height;
383 move_resize_raise_window(w, cur_x, cur_y, final_w, final_h);
385 if (!flatx)
386 cur_x += w->bw;
387 cur_x += incx;
388 if (!flaty)
389 cur_y += w->bw + w->th;
390 cur_y += incy;
391 w = reversed ? w->prev : w->next;
395 void parse_args(char *s, int argc, char *argv[], int argi)
397 int nsargc = 0;
398 /* parse args */
399 for (; argi < argc; ++argi)
401 if (!strcmp(argv[argi], "-tile") || !strcmp(argv[argi], "-cascade")) {
402 /* ignore */
404 else if (!strcmp(argv[argi], "-u")) {
405 untitled = 1;
407 else if (!strcmp(argv[argi], "-t")) {
408 transients = 1;
410 else if (!strcmp(argv[argi], "-a")) {
411 all = untitled = transients = maximized = 1;
412 if (FvwmCascade)
413 sticky_page = 1;
414 sticky_desk = 1;
416 else if (!strcmp(argv[argi], "-r")) {
417 reversed = 1;
419 else if (!strcmp(argv[argi], "-noraise")) {
420 raise_window = 0;
422 else if (!strcmp(argv[argi], "-noresize")) {
423 resize = 0;
425 else if (!strcmp(argv[argi], "-nostretch")) {
426 nostretch = 1;
428 else if (!strcmp(argv[argi], "-desk")) {
429 desk = 1;
431 else if (!strcmp(argv[argi], "-flatx")) {
432 flatx = 1;
434 else if (!strcmp(argv[argi], "-flaty")) {
435 flaty = 1;
437 else if (!strcmp(argv[argi], "-r")) {
438 reversed = 1;
440 else if (!strcmp(argv[argi], "-h")) {
441 horizontal = 1;
443 else if (!strcmp(argv[argi], "-m")) {
444 maximized = 1;
446 else if (!strcmp(argv[argi], "-s")) {
447 sticky_page = 1;
448 sticky_desk = 1;
450 else if (!strcmp(argv[argi], "-sp")) {
451 sticky_page = 1;
453 else if (!strcmp(argv[argi], "-sd")) {
454 sticky_desk = 1;
456 else if (!strcmp(argv[argi], "-mn") && ((argi + 1) < argc)) {
457 maxnum = atoi(argv[++argi]);
459 else if (!strcmp(argv[argi], "-resize")) {
460 resize = 1;
462 else if (!strcmp(argv[argi], "-nostretch")) {
463 nostretch = 1;
465 else if (!strcmp(argv[argi], "-incx") && ((argi + 1) < argc)) {
466 incx = atopixel(argv[++argi], dwidth);
468 else if (!strcmp(argv[argi], "-incy") && ((argi + 1) < argc)) {
469 incy = atopixel(argv[++argi], dheight);
471 else if (!strcmp(argv[argi], "-maximize")) {
472 do_maximize = 1;
474 else if (!strcmp(argv[argi], "-nomaximize")) {
475 do_maximize = 0;
477 else if (!strcmp(argv[argi], "-animate")) {
478 do_animate = 1;
480 else if (!strcmp(argv[argi], "-noanimate")) {
481 do_animate = 0;
483 else {
484 if (++nsargc > 4) {
485 fprintf(console,
486 "%s: %s: ignoring unknown arg %s\n",
487 module->name, s, argv[argi]);
488 continue;
490 if (nsargc == 1) {
491 ofsx = atopixel(argv[argi], dwidth);
492 } else if (nsargc == 2) {
493 ofsy = atopixel(argv[argi], dheight);
494 } else if (nsargc == 3) {
495 if (FvwmCascade)
496 maxw = atopixel(argv[argi], dwidth);
497 else /* FvwmTile */
498 maxx = atopixel(argv[argi], dwidth);
499 } else if (nsargc == 4) {
500 if (FvwmCascade)
501 maxh = atopixel(argv[argi], dheight);
502 else /* FvwmTile */
503 maxy = atopixel(argv[argi], dheight);
507 ofsx += dx;
508 ofsy += dy;
509 maxx += dx;
510 maxy += dy;
513 int main(int argc, char *argv[])
515 char match[128];
516 char *config_line;
517 int scr;
519 console = fopen("/dev/console","w");
520 if (!console) console = stderr;
522 module = ParseModuleArgs(argc,argv,0);
523 if (module == NULL)
525 fprintf(stderr,"FvwmRearrange: module should be executed by fvwm only\n");
526 exit(-1);
529 fd[0] = module->to_fvwm;
530 fd[1] = module->from_fvwm;
532 if (!(dpy = XOpenDisplay(NULL))) {
533 fprintf(console, "%s: couldn't open display %s\n",
534 module->name,
535 XDisplayName(NULL));
536 exit(-1);
538 signal (SIGPIPE, DeadPipe);
540 FScreenInit(dpy);
541 scr = DefaultScreen(dpy);
542 fd_width = GetFdWidth();
544 strcpy(match, "*");
545 strcat(match, module->name);
546 InitGetConfigLine(fd,match);
547 GetConfigLine(fd, &config_line);
548 while (config_line != NULL)
550 if (strncasecmp(config_line, XINERAMA_CONFIG_STRING,
551 sizeof(XINERAMA_CONFIG_STRING) - 1) == 0)
553 FScreenConfigureModule(
554 config_line + sizeof(XINERAMA_CONFIG_STRING) - 1);
556 GetConfigLine(fd, &config_line);
558 FScreenGetScrRect(NULL, FSCREEN_CURRENT, &dx, &dy, &dwidth, &dheight);
560 if (strcmp(module->name, "FvwmCascade") &&
561 (!strcmp(module->name, "FvwmTile") ||
562 (argc >= 7 && !strcmp(argv[6], "-tile")))) {
563 FvwmTile = 1;
564 FvwmCascade = 0;
565 resize = 1;
566 } else {
567 FvwmCascade = 1;
568 FvwmTile = 0;
569 resize = 0;
571 parse_args("module args", module->user_argc, module->user_argv, 0);
573 SetMessageMask(fd,
574 M_CONFIGURE_WINDOW |
575 M_END_WINDOWLIST);
576 SetMessageMask(fd,
577 M_EXTENDED_MSG);
579 if (FvwmTile) {
580 if (maxx == dx)
581 maxx = dx + dwidth;
582 if (maxy == dy)
583 maxy = dy + dheight;
586 SendText(fd, "Send_WindowList", 0);
588 /* tell fvwm we're running */
589 SendFinishedStartupNotification(fd);
591 while (get_window()) /* */;
592 if (wins_count) {
593 if (FvwmCascade)
594 cascade_windows();
595 else /* FvwmTile */
596 tile_windows();
598 free_window_list(wins);
600 if (console != stderr)
601 fclose(console);
603 return 0;