/* -*-c-*- */ /* This module, and the entire NoClutter program, and the concept for * interfacing this module to the Window Manager, are all original work * by Robert Nation and Nobutaka Suzuki * * Copyright 1994, Robert Nation and Nobutaka Suzuki. * No guarantees or warantees or anything * are provided or implied in any way whatsoever. Use this program at your * own risk. Permission to use this program for any purpose is given, * as long as the copyright is kept intact. */ /* 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 */ #include "config.h" #include #include #include #include #include "libs/ftime.h" #if HAVE_SYS_SELECT_H #include #endif #include #include #include #include #include #include #include #include #include #include "libs/fvwmlib.h" #include "libs/FScreen.h" #include "libs/FShape.h" #include "libs/Module.h" #include "libs/Colorset.h" #include "libs/fvwmsignal.h" #include "libs/Flocale.h" #include "libs/Parse.h" #include "libs/FRenderInit.h" #include "libs/Graphics.h" #include "libs/System.h" #include "libs/Target.h" #include "libs/XError.h" #include "FvwmIdent.h" static RETSIGTYPE TerminateHandler(int); static ModuleArgs *module; static fd_set_size_t fd_width; static int fd[2]; static Display *dpy; /* which display are we talking to */ static Window Root; static GC gc; static FlocaleFont *Ffont; static FlocaleWinString *FwinString; static int screen; static int x_fd; static char *yes = "Yes"; static char *no = "No"; /* default colorset to use, set to -1 when explicitly setting colors */ static int colorset = 0; static char *BackColor = "white"; static char *ForeColor = "black"; static char *font_string = NULL; static Pixel fore_pix; static Pixel back_pix; static Window main_win; static Bool UsePixmapDrawing = False; /* if True draw everything in a pixmap * and set the window background. Use * this with Xft */ static int main_width; static int main_height; static EventMask mw_events = ExposureMask | ButtonPressMask | KeyPressMask | ButtonReleaseMask | KeyReleaseMask | StructureNotifyMask; static Atom wm_del_win; static struct target_struct target; static int found=0; static int ListSize=0; static struct Item* itemlistRoot = NULL; static int max_col1, max_col2; static char id[15], desktop[10], swidth[10], sheight[10], borderw[10]; static char geometry[30], mymin_aspect[11], max_aspect[11], layer[10]; static char ewmh_init_state[512]; /* FIXME: default layer should be received from fvwm */ #define default_layer DEFAULT_DEFAULT_LAYER static int minimal_layer = default_layer; static int my_layer = default_layer; /* * * Procedure: * main - start of module * */ int main(int argc, char **argv) { char *display_name = NULL; char *tline; FlocaleInit(LC_CTYPE, "", "", "FvwmIdent"); module = ParseModuleArgs(argc,argv,0); /* no alias */ if (module == NULL) { fprintf( stderr, "FvwmIdent Version %s should only be executed" " by fvwm!\n", VERSION); exit(1); } #ifdef HAVE_SIGACTION { struct sigaction sigact; sigemptyset(&sigact.sa_mask); sigaddset(&sigact.sa_mask, SIGPIPE); sigaddset(&sigact.sa_mask, SIGTERM); sigaddset(&sigact.sa_mask, SIGQUIT); sigaddset(&sigact.sa_mask, SIGINT); sigaddset(&sigact.sa_mask, SIGHUP); # ifdef SA_INTERRUPT sigact.sa_flags = SA_INTERRUPT; # else sigact.sa_flags = 0; # endif sigact.sa_handler = TerminateHandler; sigaction(SIGPIPE, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGHUP, &sigact, NULL); } #else /* We don't have sigaction(), so fall back to less robust methods. */ #ifdef USE_BSD_SIGNALS fvwmSetSignalMask( sigmask(SIGPIPE) | sigmask(SIGTERM) | sigmask(SIGQUIT) | sigmask(SIGINT) | sigmask(SIGHUP) ); #endif signal(SIGPIPE, TerminateHandler); signal(SIGTERM, TerminateHandler); signal(SIGQUIT, TerminateHandler); signal(SIGINT, TerminateHandler); signal(SIGHUP, TerminateHandler); #ifdef HAVE_SIGINTERRUPT siginterrupt(SIGPIPE, 1); siginterrupt(SIGTERM, 1); siginterrupt(SIGQUIT, 1); siginterrupt(SIGINT, 1); siginterrupt(SIGHUP, 1); #endif #endif fd[0] = module->to_fvwm; fd[1] = module->from_fvwm; /* Open the Display */ if (!(dpy = XOpenDisplay(display_name))) { fprintf(stderr,"%s: can't open display %s", module->name, XDisplayName(display_name)); exit (1); } x_fd = XConnectionNumber(dpy); screen= DefaultScreen(dpy); Root = RootWindow(dpy, screen); XSetErrorHandler(ErrorHandler); flib_init_graphics(dpy); FlocaleAllocateWinString(&FwinString); SetMessageMask(fd, M_CONFIGURE_WINDOW | M_WINDOW_NAME | M_ICON_NAME | M_RES_CLASS | M_RES_NAME | M_END_WINDOWLIST | M_CONFIG_INFO | M_END_CONFIG_INFO | M_SENDCONFIG); SetMessageMask(fd, MX_PROPERTY_CHANGE); /* scan config file for set-up parameters */ /* Colors and fonts */ InitGetConfigLine(fd,CatString3("*",module->name,0)); GetConfigLine(fd,&tline); while (tline != (char *)0) { if (strlen(tline) <= 1) { continue; } if (strncasecmp(tline, CatString3("*",module->name,0), module->namelen+1) == 0) { tline += (module->namelen +1); if (strncasecmp(tline, "Font", 4) == 0) { CopyStringWithQuotes(&font_string, &tline[4]); } else if (strncasecmp(tline, "Fore", 4) == 0) { CopyString(&ForeColor, &tline[4]); colorset = -1; } else if (strncasecmp(tline, "Back", 4) == 0) { CopyString(&BackColor, &tline[4]); colorset = -1; } else if (strncasecmp(tline, "Colorset", 8) == 0) { sscanf(&tline[8], "%d", &colorset); AllocColorset(colorset); } else if (strncasecmp(tline, "MinimalLayer", 12) == 0) { char *layer_str = PeekToken(&tline[12], NULL); if (layer_str == NULL) { minimal_layer = default_layer; } else if (sscanf( layer_str, "%d", &minimal_layer) != 1) { if (strncasecmp( layer_str, "none", 4) == 0) { minimal_layer = -1; } else { minimal_layer = default_layer; } } } } else if (strncasecmp(tline, "Colorset", 8) == 0) { LoadColorset(&tline[8]); } else if (strncasecmp( tline, XINERAMA_CONFIG_STRING, sizeof(XINERAMA_CONFIG_STRING) - 1) == 0) { FScreenConfigureModule( tline + sizeof(XINERAMA_CONFIG_STRING) - 1); } GetConfigLine(fd, &tline); } if(module->window == 0) { fvwmlib_get_target_window( dpy, screen, module->name, &(module->window), True); } fd_width = GetFdWidth(); /* Create a list of all windows */ /* Request a list of all windows, * wait for ConfigureWindow packets */ SendText(fd, "Send_WindowList", 0); /* tell fvwm we're running */ SendFinishedStartupNotification(fd); if (module->window == Root) { exit(0); } Loop(fd); return 0; } /* * * Read the entire window list from fvwm * */ void Loop(int *fd) { while (1) { FvwmPacket* packet = ReadFvwmPacket(fd[1]); if ( packet == NULL ) { exit(0); } else { process_message( packet->type, packet->body ); } } } /* * * Process window list messages * */ void process_message(unsigned long type,unsigned long *body) { switch(type) { /* should turn off this packet but it comes after config_list * so have to accept at least one */ case M_CONFIGURE_WINDOW: list_configure(body); break; case M_WINDOW_NAME: list_window_name(body); break; case M_ICON_NAME: list_icon_name(body); break; case M_RES_CLASS: list_class(body); break; case M_RES_NAME: list_res_name(body); break; case M_END_WINDOWLIST: list_end(); break; default: break; } } /* * * Procedure: * SIGPIPE handler - SIGPIPE means fvwm is dying * */ static RETSIGTYPE TerminateHandler(int sig) { fvwmSetTerminate(sig); SIGNAL_RETURN; } /* * * Got window configuration info - if its our window, save data * */ void list_configure(unsigned long *body) { struct ConfigWinPacket *cfgpacket = (void *) body; if ( (module->window == cfgpacket->frame)|| (module->window == cfgpacket->w) || ((cfgpacket->icon_w != 0)&& (module->window == cfgpacket->icon_w)) || ((cfgpacket->icon_pixmap_w)&& (module->window == cfgpacket->icon_pixmap_w))) { module->window = cfgpacket->frame; target.id = cfgpacket->w; target.frame = cfgpacket->frame; target.frame_x = cfgpacket->frame_x; target.frame_y = cfgpacket->frame_y; target.frame_w = cfgpacket->frame_width; target.frame_h = cfgpacket->frame_height; target.desktop = cfgpacket->desk; target.layer = cfgpacket->layer; memcpy(&target.flags, &(cfgpacket->flags), sizeof(cfgpacket->flags)); target.title_h = cfgpacket->title_height; target.title_dir = GET_TITLE_DIR(cfgpacket); target.border_w = cfgpacket->border_width; target.base_w = cfgpacket->hints_base_width; target.base_h = cfgpacket->hints_base_height; target.width_inc = cfgpacket->orig_hints_width_inc; target.height_inc = cfgpacket->orig_hints_height_inc; target.gravity = cfgpacket->hints_win_gravity; target.ewmh_hint_layer = cfgpacket->ewmh_hint_layer; target.ewmh_hint_desktop = cfgpacket->ewmh_hint_desktop; target.ewmh_window_type = cfgpacket->ewmh_window_type; found = 1; my_layer = (int)target.layer; if (my_layer < minimal_layer) { my_layer = minimal_layer; } } } /* * * Capture Window name info * */ void list_window_name(unsigned long *body) { if ( (module->window == (Window)body[1])|| (module->window == (Window)body[0])) { strncpy(target.name,(char *)&body[3],255); } } /* * * Capture Window Icon name info * */ void list_icon_name(unsigned long *body) { if ( (module->window == (Window)body[1])|| (module->window == (Window)body[0])) { strncpy(target.icon_name,(char *)&body[3],255); } } /* * * Capture Window class name info * */ void list_class(unsigned long *body) { if ( (module->window == (Window)body[1])|| (module->window == (Window)body[0])) { strncpy(target.class,(char *)&body[3],255); } } /* * * Capture Window resource info * */ void list_res_name(unsigned long *body) { if ((module->window == (Window)body[1])|| (module->window == (Window)body[0])) { strncpy(target.res,(char *)&body[3],255); } } void list_property_change(unsigned long *body) { if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND && body[2] == 0 && CSET_IS_TRANSPARENT_PR(colorset)) { if (UsePixmapDrawing) { PixmapDrawWindow( main_width, main_height); } else { UpdateBackgroundTransparency( dpy, main_win, main_width, main_height, &Colorset[(colorset)], Pdepth, gc, True); } } } void list_config_info(unsigned long *body) { char *tline, *token; tline = (char*)&body[3]; tline = GetNextToken(tline, &token); if (StrEquals(token, "Colorset") && colorset >= 0 && LoadColorset(tline) == colorset) { if (FftSupport && Ffont->fftf.fftfont != NULL) { UsePixmapDrawing = True; } /* track all colorset changes & update display if necessary */ /* ask for movement events iff transparent */ if (CSET_IS_TRANSPARENT(colorset)) { mw_events |= StructureNotifyMask; if (CSET_IS_TRANSPARENT_PR_PURE(colorset)) { UsePixmapDrawing = False; } } else { mw_events &= ~(StructureNotifyMask); } if (UsePixmapDrawing) { #if 0 mw_events &= ~(ExposureMask); #endif } else { mw_events |= ExposureMask; } XSelectInput(dpy, main_win, mw_events); XSetForeground(dpy, gc, Colorset[colorset].fg); if (UsePixmapDrawing) { PixmapDrawWindow(main_width, main_height); } else { SetWindowBackground( dpy, main_win, main_width, main_height, &Colorset[colorset], Pdepth, gc, True); } } else if (StrEquals(token, XINERAMA_CONFIG_STRING)) { FScreenConfigureModule(tline); } if (token) free(token); } /* * * Process X Events * */ int ProcessXEvent(int x, int y) { XEvent Event,event; static int is_key_pressed = 0; static int is_button_pressed = 0; char buf[32]; static int ex=10000, ey=10000, ex2=0, ey2=0; while (FPending(dpy)) { FNextEvent(dpy,&Event); switch(Event.type) { case Expose: ex = min(ex, Event.xexpose.x); ey = min(ey, Event.xexpose.y); ex2 = max(ex2, Event.xexpose.x + Event.xexpose.width); ey2=max(ey2 , Event.xexpose.y + Event.xexpose.height); while (FCheckTypedEvent(dpy, Expose, &Event)) { ex = min(ex, Event.xexpose.x); ey = min(ey, Event.xexpose.y); ex2 = max( ex2, Event.xexpose.x + Event.xexpose.width); ey2=max(ey2, Event.xexpose.y + Event.xexpose.height); } if (FftSupport && Ffont->fftf.fftfont != NULL) { XClearArea( dpy, main_win, ex, ey, ex2-ex, ey2-ey, False); } DrawItems(main_win, ex, ey, ex2-ex, ey2-ey); ex = ey = 10000; ex2 = ey2 = 0; break; case KeyPress: is_key_pressed = 1; break; case ButtonPress: is_button_pressed = Event.xbutton.button; break; case KeyRelease: if (is_key_pressed) { exit(0); } break; case ButtonRelease: if (is_button_pressed) { if (is_button_pressed == 2 && Event.xbutton.button == 2) { /* select a new window when * button 2 is pressed */ SetMessageMask( fd, M_CONFIGURE_WINDOW | M_WINDOW_NAME | M_ICON_NAME | M_RES_CLASS | M_RES_NAME | M_END_WINDOWLIST | M_CONFIG_INFO | M_END_CONFIG_INFO| M_SENDCONFIG); SendText(fd, "Send_WindowList", 0); XDestroyWindow(dpy, main_win); DestroyList(); fvwmlib_get_target_window( dpy, screen, module->name, &(module->window), True); found = 0; return 1; } else { exit(0); } } break; case ClientMessage: if (Event.xclient.format==32 && Event.xclient.data.l[0]==wm_del_win) { exit(0); } break; case ReparentNotify: if (minimal_layer >= 0) { sprintf(buf, "Layer 0 %d", my_layer); SendText(fd, buf, main_win); } SendText(fd, "Raise", main_win); break; case ConfigureNotify: /* this only happens with transparent windows, * slurp up as many events as possible before * redrawing to reduce flickering */ while (FCheckTypedEvent( dpy, ConfigureNotify, &event)) { if (!event.xconfigure.send_event) continue; Event.xconfigure.x = event.xconfigure.x; Event.xconfigure.y = event.xconfigure.y; Event.xconfigure.send_event = True; } /* Only refresh if moved */ if ((Event.xconfigure.send_event || CSET_IS_TRANSPARENT_PR_PURE(colorset)) && (x != Event.xconfigure.x || y != Event.xconfigure.y)) { static Bool is_initial_cn = True; Bool do_eat_expose = False; x = Event.xconfigure.x; y = Event.xconfigure.y; /* flush any expose events */ if (UsePixmapDrawing) { PixmapDrawWindow( main_width, main_height); do_eat_expose = True; } else if (colorset == -1) { do_eat_expose = True; } else if (UpdateBackgroundTransparency( dpy, main_win, main_width, main_height, &Colorset[(colorset)], Pdepth, gc, True) == True) { do_eat_expose = True; } if (do_eat_expose == True && is_initial_cn == False) { while (FCheckTypedEvent( dpy, Expose, &Event)) { /* nothing */ } } is_initial_cn = False; } break; } } XFlush (dpy); return 0; } /* * * End of window list, open an x window and display data in it * */ void list_end(void) { XSizeHints mysizehints; XGCValues gcv; unsigned long gcm; int lmax,height; int x,y; XSetWindowAttributes attributes; if(!found) { exit(0); } /* tell fvwm to only send config messages */ SetMessageMask(fd, M_CONFIG_INFO | M_SENDCONFIG); if ((Ffont = FlocaleLoadFont(dpy, font_string, module->name)) == NULL) { fprintf( stderr,"%s: cannot load font, exiting\n", module->name); exit(1); } /* chose the rendering methode */ if (FftSupport && Ffont->fftf.fftfont != NULL) { UsePixmapDrawing = True; } /* make window infomation list */ MakeList(); /* size and create the window */ lmax = max_col1 + max_col2 + 15; height = ListSize * (Ffont->height); mysizehints.flags= USSize|USPosition|PWinGravity|PResizeInc|PBaseSize|PMinSize| PMaxSize; main_width = mysizehints.width = lmax + 10; main_height = mysizehints.height = height + 10; mysizehints.width_inc = 1; mysizehints.height_inc = 1; mysizehints.base_height = mysizehints.height; mysizehints.base_width = mysizehints.width; mysizehints.min_height = mysizehints.height; mysizehints.min_width = mysizehints.width; mysizehints.max_height = mysizehints.height; mysizehints.max_width = mysizehints.width; mysizehints.win_gravity = NorthWestGravity; { int sx; int sy; int sw; int sh; Window JunkW; int JunkC; unsigned int JunkM; fscreen_scr_arg fscr; if (!FQueryPointer( dpy, Root, &JunkW, &JunkW, &x, &y, &JunkC, &JunkC, &JunkM)) { /* pointer is on a different screen */ x = 0; y = 0; } fscr.xypos.x = x; fscr.xypos.y = y; FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &sx, &sy, &sw, &sh); if (y + height + 100 > sy + sh) { y = sy + sh - height - 10; mysizehints.win_gravity = SouthWestGravity; } if (x + lmax + 100 > sx + sw) { x = sx + sw - lmax - 10; if (mysizehints.win_gravity == SouthWestGravity) mysizehints.win_gravity = SouthEastGravity; else mysizehints.win_gravity = NorthEastGravity; } } if (Pdepth < 2) { back_pix = GetColor("white"); fore_pix = GetColor("black"); } else { back_pix = (colorset < 0)? GetColor(BackColor) : Colorset[colorset].bg; fore_pix = (colorset < 0)? GetColor(ForeColor) : Colorset[colorset].fg; } attributes.colormap = Pcmap; attributes.border_pixel = 0; attributes.background_pixel = back_pix; main_win = XCreateWindow( dpy, Root, x, y, mysizehints.width, mysizehints.height, 0, Pdepth, InputOutput, Pvisual, CWColormap | CWBackPixel | CWBorderPixel, &attributes); wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False); XSetWMProtocols(dpy,main_win,&wm_del_win,1); /* hack to prevent mapping on wrong screen with StartsOnScreen */ FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &mysizehints); XSetWMNormalHints(dpy,main_win,&mysizehints); /* have to ask for configure events when transparent */ if (CSET_IS_TRANSPARENT(colorset)) { mw_events |= StructureNotifyMask; if (CSET_IS_TRANSPARENT_PR_PURE(colorset)) { UsePixmapDrawing = 0; } } if (!UsePixmapDrawing) { mw_events |= ExposureMask; } XSelectInput(dpy, main_win, mw_events); change_window_name(module->name); gcm = GCForeground; gcv.foreground = fore_pix; if (Ffont->font != NULL) { gcm |= GCFont; gcv.font = Ffont->font->fid; } gc = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv); if (UsePixmapDrawing) { PixmapDrawWindow(main_width, main_height); } else if (colorset >= 0) { SetWindowBackground( dpy, main_win, main_width, main_height, &Colorset[(colorset)], Pdepth, gc, True); } XMapWindow(dpy,main_win); /* Window is created. Display it until the user clicks or deletes it. * also grok any dynamic config changes */ while(1) { FvwmPacket* packet; int x_fd = XConnectionNumber(dpy); fd_set fdset; FD_ZERO(&fdset); FD_SET(fd[1], &fdset); FD_SET(x_fd, &fdset); /* process all X events first */ if (ProcessXEvent(x,y) == 1) { return; } /* wait for X-event or config line */ select(fd_width, SELECT_FD_SET_CAST &fdset, NULL, NULL, NULL ); /* parse any dynamic config lines */ if (FD_ISSET(fd[1], &fdset)) { packet = ReadFvwmPacket(fd[1]); if (packet == NULL) exit(0); if (packet && packet->type == MX_PROPERTY_CHANGE) { list_property_change(packet->body); } if (packet && packet->type == M_CONFIG_INFO) { list_config_info(packet->body); } } } } /* * * Draw the items * */ void DrawItems(Drawable d, int x, int y, int w, int h) { int fontheight,i=0; struct Item *cur = itemlistRoot; Region region = 0; fontheight = Ffont->height; FwinString->win = d; FwinString->gc = gc; FwinString->flags.has_clip_region = False; if (w > 0) { XRectangle r; r.x = x; r.y = y; r.width = w; r.height = h; region = XCreateRegion(); XUnionRectWithRegion(&r, region, region); XSetRegion(dpy, gc, region); FwinString->flags.has_clip_region = True; FwinString->clip_region = region; } if (colorset >= 0) { FwinString->colorset = &Colorset[colorset]; FwinString->flags.has_colorset = True; } while(cur != NULL) /* may be optimised */ { /* first column */ FwinString->str = cur->col1; FwinString->x = 5; FwinString->y = 5 + Ffont->ascent + i * fontheight; FlocaleDrawString(dpy, Ffont, FwinString, 0); /* second column */ FwinString->str = cur->col2; FwinString->x = 10 + max_col1; FlocaleDrawString(dpy, Ffont, FwinString, 0); ++i; cur = cur->next; } if (FwinString->flags.has_clip_region) { XDestroyRegion(region); XSetClipMask(dpy, gc, None); } XFlush (dpy); } void PixmapDrawWindow(int w, int h) { Pixmap pix; XGCValues gcv; unsigned long gcm; if (colorset >= 0) { Pixmap cs_pix; cs_pix = CreateBackgroundPixmap(dpy, main_win, w, h, &Colorset[(colorset)], Pdepth, gc, False); if (cs_pix == ParentRelative) { pix = cs_pix; } else { pix = CreateTiledPixmap( dpy, cs_pix, 0,0,w,h,Pdepth, gc); XFreePixmap(dpy, cs_pix); } } else { gcm = GCForeground; gcv.foreground = back_pix; XChangeGC(dpy, gc, gcm, &gcv); pix = XCreatePixmap(dpy, main_win, w, h, Pdepth); XFillRectangle(dpy, pix, gc, 0, 0, w, h); gcv.foreground = fore_pix; XChangeGC(dpy, gc, gcm, &gcv); } if (pix != ParentRelative) { DrawItems(pix, 0, 0, 0, 0); XSetWindowBackgroundPixmap(dpy, main_win, pix); XClearWindow(dpy, main_win); XFreePixmap(dpy, pix); } else { XSetWindowBackgroundPixmap(dpy, main_win, pix); XClearWindow(dpy, main_win); DrawItems(main_win, 0, 0, 0, 0); } } /* * Change the window name displayed in the title bar. */ void change_window_name(char *str) { XTextProperty name; XClassHint myclasshints; if (XStringListToTextProperty(&str,1,&name) == 0) { fprintf(stderr,"%s: cannot allocate window name",module->name); return; } XSetWMName(dpy,main_win,&name); XSetWMIconName(dpy,main_win,&name); XFree(name.value); myclasshints.res_name = str; myclasshints.res_class = "FvwmIdent"; XSetClassHint(dpy,main_win,&myclasshints); } void DestroyList(void) { struct Item *t; struct Item *tmp; for (t = itemlistRoot; t; t = tmp) { tmp = t->next; free(t); } itemlistRoot = NULL; } /* * * Add s1(string at first column) and s2(string at second column) to itemlist * */ void AddToList(char *s1, char* s2) { int tw1, tw2; struct Item* item, *cur = itemlistRoot; tw1 = FlocaleTextWidth(Ffont, s1, strlen(s1)); tw2 = FlocaleTextWidth(Ffont, s2, strlen(s2)); max_col1 = max_col1 > tw1 ? max_col1 : tw1; max_col2 = max_col2 > tw2 ? max_col2 : tw2; item = (struct Item*)safemalloc(sizeof(struct Item)); item->col1 = s1; item->col2 = s2; item->next = NULL; if (cur == NULL) { itemlistRoot = item; } else { while(cur->next != NULL) { cur = cur->next; } cur->next = item; } ListSize++; } void MakeList(void) { int bw,width,height,x1,y1,x2,y2; char loc[20]; static char xstr[6],ystr[6]; /* GSFR - quick hack because the new macros depend on a prt reference */ struct target_struct *targ = ⌖ ListSize = 0; bw = 2*target.border_w; width = target.frame_w - bw; height = target.frame_h - bw; if (target.title_dir == DIR_W || target.title_dir == DIR_E) { width -= target.title_h; } else if (target.title_dir == DIR_N || target.title_dir == DIR_S) { height -= target.title_h; } sprintf(desktop, "%ld", target.desktop); sprintf(layer, "%ld", target.layer); sprintf(id, "0x%x", (unsigned int)target.id); sprintf(swidth, "%d", width); sprintf(sheight, "%d", height); sprintf(borderw, "%ld", target.border_w); sprintf(xstr, "%ld", target.frame_x); sprintf(ystr, "%ld", target.frame_y); AddToList("Name:", target.name); AddToList("Icon Name:", target.icon_name); AddToList("Class:", target.class); AddToList("Resource:", target.res); AddToList("Window ID:", id); AddToList("Desk:", desktop); AddToList("Layer:", layer); AddToList("Width:", swidth); AddToList("Height:", sheight); AddToList("X (current page):", xstr); AddToList("Y (current page):", ystr); AddToList("Boundary Width:", borderw); AddToList("StickyPage:", (IS_STICKY_ACROSS_PAGES(targ) ? yes : no)); AddToList("StickyDesk:", (IS_STICKY_ACROSS_DESKS(targ) ? yes : no)); AddToList("StickyPageIcon:", (IS_ICON_STICKY_ACROSS_PAGES(targ) ? yes : no)); AddToList("StickyDeskIcon:", (IS_ICON_STICKY_ACROSS_DESKS(targ) ? yes : no)); AddToList("NoTitle:", (HAS_TITLE(targ) ? no : yes)); AddToList("Iconified:", (IS_ICONIFIED(targ) ? yes : no)); AddToList("Transient:", (IS_TRANSIENT(targ) ? yes : no)); AddToList("WindowListSkip:", (DO_SKIP_WINDOW_LIST(targ) ? yes : no)); switch(target.gravity) { case ForgetGravity: AddToList("Gravity:", "Forget"); break; case NorthWestGravity: AddToList("Gravity:", "NorthWest"); break; case NorthGravity: AddToList("Gravity:", "North"); break; case NorthEastGravity: AddToList("Gravity:", "NorthEast"); break; case WestGravity: AddToList("Gravity:", "West"); break; case CenterGravity: AddToList("Gravity:", "Center"); break; case EastGravity: AddToList("Gravity:", "East"); break; case SouthWestGravity: AddToList("Gravity:", "SouthWest"); break; case SouthGravity: AddToList("Gravity:", "South"); break; case SouthEastGravity: AddToList("Gravity:", "SouthEast"); break; case StaticGravity: AddToList("Gravity:", "Static"); break; default: AddToList("Gravity:", "Unknown"); break; } x1 = target.frame_x; if(x1 < 0) { x1 = 0; } x2 = DisplayWidth(dpy,screen) - x1 - target.frame_w; if(x2 < 0) { x2 = 0; } y1 = target.frame_y; if(y1 < 0) { y1 = 0; } y2 = DisplayHeight(dpy,screen) - y1 - target.frame_h; if(y2 < 0) { y2 = 0; } width = (width - target.base_w)/target.width_inc; height = (height - target.base_h)/target.height_inc; sprintf(loc,"%dx%d",width,height); strcpy(geometry, loc); if ((target.gravity == EastGravity) || (target.gravity == NorthEastGravity)|| (target.gravity == SouthEastGravity)) { sprintf(loc,"-%d",x2); } else { sprintf(loc,"+%d",x1); } strcat(geometry, loc); if((target.gravity == SouthGravity)|| (target.gravity == SouthEastGravity)|| (target.gravity == SouthWestGravity)) { sprintf(loc,"-%d",y2); } else { sprintf(loc,"+%d",y1); } strcat(geometry, loc); AddToList("Geometry:", geometry); { Atom *protocols = NULL, *ap; Atom _XA_WM_TAKE_FOCUS = XInternAtom( dpy, "WM_TAKE_FOCUS", False); XWMHints *wmhintsp = XGetWMHints(dpy,target.id); int i,n; Boolean HasTakeFocus=False,InputField=True; char *focus_policy="",*ifstr="",*tfstr=""; if (wmhintsp) { InputField=wmhintsp->input; ifstr=InputField?"True":"False"; XFree(wmhintsp); } else { ifstr="XWMHints missing"; } if (XGetWMProtocols(dpy,target.id,&protocols,&n)) { for (i = 0, ap = protocols; i < n; i++, ap++) { if (*ap == (Atom)_XA_WM_TAKE_FOCUS) HasTakeFocus = True; } tfstr=HasTakeFocus?"Present":"Absent"; XFree(protocols); } else { tfstr="XGetWMProtocols failed"; } if (HasTakeFocus) { if (InputField) { focus_policy = "Locally Active"; } else { focus_policy = "Globally Active"; } } else { if (InputField) { focus_policy = "Passive"; } else { focus_policy = "No Input"; } } AddToList("Focus Policy:",focus_policy); AddToList(" - Input Field:",ifstr); AddToList(" - WM_TAKE_FOCUS:",tfstr); { /* flags hints that were supplied */ long supplied_return; int getrc; XSizeHints *size_hints = XAllocSizeHints(); /* the size hints */ if ((getrc = XGetWMSizeHints( dpy,target.id, /* get size hints */ size_hints, /* Hints */ &supplied_return, XA_WM_ZOOM_HINTS))) { if (supplied_return & PAspect) { /* if window has a aspect ratio */ sprintf( mymin_aspect, "%d/%d", size_hints->min_aspect.x, size_hints->min_aspect.y); AddToList( "Minimum aspect ratio:", mymin_aspect); sprintf( max_aspect, "%d/%d", size_hints->max_aspect.x, size_hints->max_aspect.y); AddToList( "Maximum aspect ratio:", max_aspect); } /* end aspect ratio */ XFree(size_hints); } /* end getsizehints worked */ } } /* EWMH window type */ if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DESKTOP_ID) AddToList("EWMH Window Type:","Desktop"); else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DIALOG_ID) AddToList("EWMH Window Type:","Dialog"); else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_DOCK_ID) AddToList("EWMH Window Type:","Dock"); else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_MENU_ID) AddToList("EWMH Window Type:","Menu"); else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_NORMAL_ID) AddToList("EWMH Window Type:","Normal"); else if (target.ewmh_window_type == EWMH_WINDOW_TYPE_TOOLBAR_ID) AddToList("EWMH Window Type:","ToolBar"); /* EWMH wm state */ ewmh_init_state[0] = '\0'; if (HAS_EWMH_INIT_FULLSCREEN_STATE(targ) == EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "FullScreen "); } if (HAS_EWMH_INIT_HIDDEN_STATE(targ) == EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "Iconic "); } if (HAS_EWMH_INIT_MAXHORIZ_STATE(targ) == EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "MaxHoriz "); } if (HAS_EWMH_INIT_MAXVERT_STATE(targ) == EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "MaxVert "); } if (HAS_EWMH_INIT_MODAL_STATE(targ) == EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "Modal "); } if (HAS_EWMH_INIT_SHADED_STATE(targ)== EWMH_STATE_HAS_HINT) { strcat(ewmh_init_state, "Shaded "); } if (HAS_EWMH_INIT_SKIP_PAGER_STATE(targ) == EWMH_STATE_HAS_HINT || HAS_EWMH_INIT_SKIP_TASKBAR_STATE(targ) == EWMH_STATE_HAS_HINT ) { strcat(ewmh_init_state, "SkipList "); } if (HAS_EWMH_INIT_STICKY_STATE(targ) == EWMH_STATE_HAS_HINT || (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT && (target.ewmh_hint_desktop == (unsigned long)-2 || target.ewmh_hint_desktop == (unsigned long)-1))) { strcat(ewmh_init_state, "Sticky "); } /* FIXME: we should use the fvwm default layers */ if (target.ewmh_hint_layer == 6) { strcat(ewmh_init_state, "StaysOnTop "); } else if (target.ewmh_hint_layer == 2) { strcat(ewmh_init_state, "StaysOnBottom "); } if (HAS_EWMH_INIT_WM_DESKTOP(targ) == EWMH_STATE_HAS_HINT && target.ewmh_hint_desktop < 256) { strcat(ewmh_init_state, "StartOnDesk"); sprintf(ewmh_init_state, "%s %lu ", ewmh_init_state, target.ewmh_hint_desktop); } if (ewmh_init_state[0] != '\0') { /* remove ending space */ ewmh_init_state[strlen(ewmh_init_state)-1] = '\0'; AddToList("EWMH Init State:",ewmh_init_state); } } /* X Error Handler */ static int ErrorHandler(Display *d, XErrorEvent *event) { #if 0 if (event->error_code == BadPixmap) { return 0; } if (event->error_code == BadDrawable) { return 0; } if (event->error_code == FRenderGetErrorCodeBase() + FRenderBadPicture) { return 0; } #endif PrintXErrorAndCoredump(d, event, module->name); return 0; }