/* -*-c-*- */ /* * FvwmRearrange.c -- fvwm module to arrange windows * * Copyright (C) 1996, 1997, 1998, 1999 Andrew T. Veliath * * Version 1.0 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Combined FvwmTile and FvwmCascade to FvwmRearrange module. * 9-Nov-1998 Dominik Vogt */ #include "config.h" #include #include #include "libs/ftime.h" #include #include #include #ifdef HAVE_SYS_BSDTYPES_H #include #endif #if HAVE_SYS_SELECT_H #include #endif #include #include "libs/fvwmlib.h" #include "libs/FScreen.h" #include "libs/Module.h" #include "fvwm/fvwm.h" #include "libs/vpacket.h" #include "libs/System.h" typedef struct window_item { Window frame; int th, bw; unsigned long width, height; struct window_item *prev, *next; } window_item, *window_list; /* vars */ Display *dpy; int dx, dy; int dwidth, dheight; static ModuleArgs *module; int fd[2]; fd_set_size_t fd_width; window_list wins = NULL, wins_tail = NULL; int wins_count = 0; FILE *console; /* switches */ int ofsx = 0, ofsy = 0; int maxw = 0, maxh = 0; int maxx, maxy; int untitled = 0, transients = 0; int maximized = 0; int all = 0; int desk = 0; int reversed = 0, raise_window = 1; int resize = 0; int nostretch = 0; int sticky_page = 0; int sticky_desk = 0; int flatx = 0, flaty = 0; int incx = 0, incy = 0; int horizontal = 0; int maxnum = 0; int do_maximize = 0; int do_animate = 0; char FvwmTile; char FvwmCascade; RETSIGTYPE DeadPipe(int sig) { exit(0); SIGNAL_RETURN; } void insert_window_list(window_list *wl, window_item *i) { if (*wl) { if ((i->prev = (*wl)->prev)) i->prev->next = i; i->next = *wl; (*wl)->prev = i; } else i->next = i->prev = NULL; *wl = i; } void free_window_list(window_list wl) { window_item *q; while (wl) { q = wl; wl = wl->next; free(q); } } int is_suitable_window(unsigned long *body) { XWindowAttributes xwa; struct ConfigWinPacket *cfgpacket = (void *) body; if ((DO_SKIP_WINDOW_LIST(cfgpacket)) && !all) return 0; if ((IS_MAXIMIZED(cfgpacket)) && !maximized) return 0; if ((IS_STICKY_ACROSS_PAGES(cfgpacket)) && !sticky_page) return 0; if ((IS_STICKY_ACROSS_DESKS(cfgpacket)) && !sticky_desk) return 0; if (!XGetWindowAttributes(dpy, cfgpacket->w, &xwa)) return 0; if (xwa.map_state != IsViewable) return 0; if (!(IS_MAPPED(cfgpacket))) return 0; if (IS_ICONIFIED(cfgpacket)) return 0; if (!desk) { int x = (int)cfgpacket->frame_x, y = (int)cfgpacket->frame_y; int w = (int)cfgpacket->frame_width, h = (int)cfgpacket->frame_height; if (x >= dx + dwidth || y >= dy + dheight || x + w <= dx || y + h <= dy) return 0; } if (!(HAS_TITLE(cfgpacket)) && !untitled) return 0; if ((IS_TRANSIENT(cfgpacket)) && !transients) return 0; return 1; } int get_window(void) { FvwmPacket* packet; struct ConfigWinPacket *cfgpacket; int last = 0; fd_set infds; FD_ZERO(&infds); FD_SET(fd[1], &infds); select(fd_width, SELECT_FD_SET_CAST &infds, 0, 0, NULL); if ( (packet = ReadFvwmPacket(fd[1])) == NULL ) DeadPipe(0); else { cfgpacket = (struct ConfigWinPacket*) packet->body; switch (packet->type) { case M_CONFIGURE_WINDOW: if (is_suitable_window(packet->body)) { window_item *wi = (window_item*)safemalloc(sizeof( window_item )); wi->frame = cfgpacket->frame; wi->th = cfgpacket->title_height; wi->bw = cfgpacket->border_width; wi->width = cfgpacket->frame_width; wi->height = cfgpacket->frame_height; if (!wins_tail) wins_tail = wi; insert_window_list(&wins, wi); ++wins_count; } last = 1; break; case M_END_WINDOWLIST: break; default: fprintf(console, "%s: internal inconsistency: unknown message 0x%08x\n", module->name, (int)packet->type); break; } } return last; } void wait_configure(window_item *wi) { int found = 0; /** Uh, what's the point of the select() here?? **/ fd_set infds; FD_ZERO(&infds); FD_SET(fd[1], &infds); select(fd_width, SELECT_FD_SET_CAST &infds, 0, 0, NULL); while (!found) { FvwmPacket* packet = ReadFvwmPacket(fd[1]); if ( packet == NULL ) DeadPipe(0); if ( packet->type == M_CONFIGURE_WINDOW && (Window)(packet->body[1]) == wi->frame ) found = 1; } } int atopixel(char *s, unsigned long f) { int l = strlen(s); if (l < 1) return 0; if (isalpha(s[l - 1])) { char s2[24]; strcpy(s2,s); s2[strlen(s2) - 1] = 0; return atoi(s2); } return (atoi(s) * f) / 100; } void move_resize_raise_window( window_item *wi, int x, int y, int w, int h) { static char msg[64]; if (resize) { const char *function = do_maximize? "ResizeMoveMaximize": "ResizeMove"; sprintf(msg, "%s %dp %dp %up %up", function, w, h, x, y); SendText(fd, msg, wi->frame); } else { const char *function = do_maximize? "ResizeMoveMaximize": do_animate ? "AnimatedMove" : "Move"; if (do_maximize) sprintf(msg, "%s keep keep %up %up", function, x, y); else sprintf(msg, "%s %up %up", function, x, y); SendText(fd, msg, wi->frame); } if (raise_window) SendText(fd, "Raise", wi->frame); wait_configure(wi); } void tile_windows(void) { int cur_x = ofsx, cur_y = ofsy; int final_w = -1, final_h = -1; int wdiv, hdiv, i, j, count = 1; window_item *w = reversed ? wins_tail : wins; if (horizontal) { if ((maxnum > 0) && (maxnum < wins_count)) { count = wins_count / maxnum; if (wins_count % maxnum) ++count; hdiv = (maxy - ofsy + 1) / maxnum; } else { maxnum = wins_count; hdiv = (maxy - ofsy + 1) / wins_count; } wdiv = (maxx - ofsx + 1) / count; for (i = 0; w && (i < count); ++i) { for (j = 0; w && (j < maxnum); ++j) { int nw = wdiv - w->bw * 2; int nh = hdiv - w->bw * 2 - w->th; if (resize) { if (nostretch) { if (nw > w->width) nw = w->width; if (nh > w->height) nh = w->height; } final_w = (nw > 0) ? nw : w->width; final_h = (nh > 0) ? nh : w->height; } move_resize_raise_window(w, cur_x, cur_y, final_w, final_h); cur_y += hdiv; w = reversed ? w->prev : w->next; } cur_x += wdiv; cur_y = ofsy; } } else { if ((maxnum > 0) && (maxnum < wins_count)) { count = wins_count / maxnum; if (wins_count % maxnum) ++count; wdiv = (maxx - ofsx + 1) / maxnum; } else { maxnum = wins_count; wdiv = (maxx - ofsx + 1) / wins_count; } hdiv = (maxy - ofsy + 1) / count; for (i = 0; w && (i < count); ++i) { for (j = 0; w && (j < maxnum); ++j) { int nw = wdiv - w->bw * 2; int nh = hdiv - w->bw * 2 - w->th; if (resize) { if (nostretch) { if (nw > w->width) nw = w->width; if (nh > w->height) nh = w->height; } final_w = (nw > 0) ? nw : w->width; final_h = (nh > 0) ? nh : w->height; } move_resize_raise_window(w, cur_x, cur_y, final_w, final_h); cur_x += wdiv; w = reversed ? w->prev : w->next; } cur_x = ofsx; cur_y += hdiv; } } } void cascade_windows(void) { int cur_x = ofsx, cur_y = ofsy; int final_w = -1, final_h = -1; window_item *w = reversed ? wins_tail : wins; while (w) { unsigned long nw = 0, nh = 0; if (resize) { if (nostretch) { if (maxw && (w->width > maxw)) nw = maxw; if (maxh && (w->height > maxh)) nh = maxh; } else { nw = maxw; nh = maxh; } if (nw || nh) { final_w = nw ? nw : w->width; final_h = nh ? nh : w->height; } } move_resize_raise_window(w, cur_x, cur_y, final_w, final_h); if (!flatx) cur_x += w->bw; cur_x += incx; if (!flaty) cur_y += w->bw + w->th; cur_y += incy; w = reversed ? w->prev : w->next; } } void parse_args(char *s, int argc, char *argv[], int argi) { int nsargc = 0; /* parse args */ for (; argi < argc; ++argi) { if (!strcmp(argv[argi], "-tile") || !strcmp(argv[argi], "-cascade")) { /* ignore */ } else if (!strcmp(argv[argi], "-u")) { untitled = 1; } else if (!strcmp(argv[argi], "-t")) { transients = 1; } else if (!strcmp(argv[argi], "-a")) { all = untitled = transients = maximized = 1; if (FvwmCascade) sticky_page = 1; sticky_desk = 1; } else if (!strcmp(argv[argi], "-r")) { reversed = 1; } else if (!strcmp(argv[argi], "-noraise")) { raise_window = 0; } else if (!strcmp(argv[argi], "-noresize")) { resize = 0; } else if (!strcmp(argv[argi], "-nostretch")) { nostretch = 1; } else if (!strcmp(argv[argi], "-desk")) { desk = 1; } else if (!strcmp(argv[argi], "-flatx")) { flatx = 1; } else if (!strcmp(argv[argi], "-flaty")) { flaty = 1; } else if (!strcmp(argv[argi], "-r")) { reversed = 1; } else if (!strcmp(argv[argi], "-h")) { horizontal = 1; } else if (!strcmp(argv[argi], "-m")) { maximized = 1; } else if (!strcmp(argv[argi], "-s")) { sticky_page = 1; sticky_desk = 1; } else if (!strcmp(argv[argi], "-sp")) { sticky_page = 1; } else if (!strcmp(argv[argi], "-sd")) { sticky_desk = 1; } else if (!strcmp(argv[argi], "-mn") && ((argi + 1) < argc)) { maxnum = atoi(argv[++argi]); } else if (!strcmp(argv[argi], "-resize")) { resize = 1; } else if (!strcmp(argv[argi], "-nostretch")) { nostretch = 1; } else if (!strcmp(argv[argi], "-incx") && ((argi + 1) < argc)) { incx = atopixel(argv[++argi], dwidth); } else if (!strcmp(argv[argi], "-incy") && ((argi + 1) < argc)) { incy = atopixel(argv[++argi], dheight); } else if (!strcmp(argv[argi], "-maximize")) { do_maximize = 1; } else if (!strcmp(argv[argi], "-nomaximize")) { do_maximize = 0; } else if (!strcmp(argv[argi], "-animate")) { do_animate = 1; } else if (!strcmp(argv[argi], "-noanimate")) { do_animate = 0; } else { if (++nsargc > 4) { fprintf(console, "%s: %s: ignoring unknown arg %s\n", module->name, s, argv[argi]); continue; } if (nsargc == 1) { ofsx = atopixel(argv[argi], dwidth); } else if (nsargc == 2) { ofsy = atopixel(argv[argi], dheight); } else if (nsargc == 3) { if (FvwmCascade) maxw = atopixel(argv[argi], dwidth); else /* FvwmTile */ maxx = atopixel(argv[argi], dwidth); } else if (nsargc == 4) { if (FvwmCascade) maxh = atopixel(argv[argi], dheight); else /* FvwmTile */ maxy = atopixel(argv[argi], dheight); } } } ofsx += dx; ofsy += dy; maxx += dx; maxy += dy; } int main(int argc, char *argv[]) { char match[128]; char *config_line; int scr; console = fopen("/dev/console","w"); if (!console) console = stderr; module = ParseModuleArgs(argc,argv,0); if (module == NULL) { fprintf(stderr,"FvwmRearrange: module should be executed by fvwm only\n"); exit(-1); } fd[0] = module->to_fvwm; fd[1] = module->from_fvwm; if (!(dpy = XOpenDisplay(NULL))) { fprintf(console, "%s: couldn't open display %s\n", module->name, XDisplayName(NULL)); exit(-1); } signal (SIGPIPE, DeadPipe); FScreenInit(dpy); scr = DefaultScreen(dpy); fd_width = GetFdWidth(); strcpy(match, "*"); strcat(match, module->name); InitGetConfigLine(fd,match); GetConfigLine(fd, &config_line); while (config_line != NULL) { if (strncasecmp(config_line, XINERAMA_CONFIG_STRING, sizeof(XINERAMA_CONFIG_STRING) - 1) == 0) { FScreenConfigureModule( config_line + sizeof(XINERAMA_CONFIG_STRING) - 1); } GetConfigLine(fd, &config_line); } FScreenGetScrRect(NULL, FSCREEN_CURRENT, &dx, &dy, &dwidth, &dheight); if (strcmp(module->name, "FvwmCascade") && (!strcmp(module->name, "FvwmTile") || (argc >= 7 && !strcmp(argv[6], "-tile")))) { FvwmTile = 1; FvwmCascade = 0; resize = 1; } else { FvwmCascade = 1; FvwmTile = 0; resize = 0; } parse_args("module args", module->user_argc, module->user_argv, 0); SetMessageMask(fd, M_CONFIGURE_WINDOW | M_END_WINDOWLIST); SetMessageMask(fd, M_EXTENDED_MSG); if (FvwmTile) { if (maxx == dx) maxx = dx + dwidth; if (maxy == dy) maxy = dy + dheight; } SendText(fd, "Send_WindowList", 0); /* tell fvwm we're running */ SendFinishedStartupNotification(fd); while (get_window()) /* */; if (wins_count) { if (FvwmCascade) cascade_windows(); else /* FvwmTile */ tile_windows(); } free_window_list(wins); if (console != stderr) fclose(console); return 0; }