/* -*-c-*- */ /* FvwmWinList Module for Fvwm. * * Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or * Mike_Finger@atk.com) * * The author makes not guarantees or warantees, either express or * implied. Feel free to use any contained here for any purpose, as long * and this and any other applicible copyrights are kept intact. * * The functions in this source file that are based on part of the FvwmIdent * module for Fvwm are noted by a small copyright atop that function, all * others are copyrighted by Mike Finger. For those functions modified/used, * here is the full, origonal copyright: * * 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. * * Modifications Done to Add Pixmaps, focus highlighting and Current Desk Only * By Don Mahurin, 1996, Some of this Code was taken from FvwmTaskBar */ /* 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 */ #ifndef NO_CONSOLE #define NO_CONSOLE #endif #define YES "Yes" #define NO "No" #include "config.h" #include #include #include #include "libs/ftime.h" #ifdef HAVE_SYS_BSDTYPES_H #include /* Saul */ #endif #include "libs/Module.h" #include "libs/fvwmsignal.h" #include "libs/fvwmlib.h" #include "libs/FScreen.h" #include "libs/FShape.h" #include "libs/FRenderInit.h" #include "libs/Flocale.h" #include "libs/gravity.h" #include "libs/FRender.h" #include "libs/FRenderInterface.h" #include "libs/ColorUtils.h" #include "libs/Graphics.h" #include "libs/Strings.h" #include "libs/System.h" #include "libs/XError.h" #include "FvwmWinList.h" #include "ButtonArray.h" #include "List.h" #include "Mallocs.h" #include "libs/Colorset.h" #define MAX_NO_ICON_ACTION_LENGTH (MAX_MODULE_INPUT_TEXT_LEN - 100) #define GRAB_EVENTS (ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|EnterWindowMask|LeaveWindowMask) #define COMPLEX_WINDOW_PLACEMENT #define SomeButtonDown(a) ((a) & DEFAULT_ALL_BUTTONS_MASK) /* File type information */ FILE *console; fd_set_size_t fd_width; int Fvwm_fd[2]; int x_fd; /* X related things */ Display *dpy; Window Root; Window win; int screen; int fscreen; rectangle screen_g; Pixel back[MAX_COLOUR_SETS]; Pixel fore[MAX_COLOUR_SETS]; GC graph[MAX_COLOUR_SETS]; GC shadow[MAX_COLOUR_SETS]; GC hilite[MAX_COLOUR_SETS]; GC background[MAX_COLOUR_SETS]; Pixmap win_bg; FlocaleFont *FButtonFont; FlocaleWinString *FwinString; int fontheight; int buttonheight; static Atom wm_del_win; Atom MwmAtom = None; /* Module related information */ char *Module; int WindowState=0; int win_width=5; int win_height=5; int win_grav; int win_x; int win_y; int win_title; #ifdef COMPLEX_WINDOW_PLACEMENT int win_border_x=0; int win_border_y=0; #endif int Clength; int Transient=0; int Pressed=0; int ButPressed=-1; int Checked=0; int MinWidth=DEFMINWIDTH; int MaxWidth=DEFMAXWIDTH; ButtonArray buttons; List windows; char *ClickAction[NUMBER_OF_EXTENDED_MOUSE_BUTTONS] = { "Iconify -1,Raise", "Iconify", "Lower" }, *EnterAction, *BackColor[MAX_COLOUR_SETS] = { "white" }, *ForeColor[MAX_COLOUR_SETS] = { "black" }, *geometry=""; int colorset[MAX_COLOUR_SETS]; Pixmap pixmap[MAX_COLOUR_SETS]; char *font_string = NULL; Bool UseSkipList = False; Bool Anchor = True; Bool UseIconNames = False; Bool LeftJustify = False; Bool TruncateLeft = False; Bool ShowFocus = True; Bool Follow = False; int ReliefWidth = 2; long CurrentDesk = 0; int ShowCurrentDesk = 0; struct { unsigned is_shaded : 1; unsigned needs_resize_after_unshade : 1; } flags = { 0, 0 }; rectangle cfg_g = { 0, 0, 0, 0 }; /* win geometry from M_CONFIGURE_WINDOW */ static RETSIGTYPE TerminateHandler(int sig); static char *AnimCommand = NULL; /* * TerminateHandler - reentrant signal handler that ends the main event loop */ static RETSIGTYPE TerminateHandler(int sig) { /* * This function might not return - it could "long-jump" * right out, so we need to do everything we need to do * BEFORE we call it ... */ fvwmSetTerminate(sig); SIGNAL_RETURN; } static void window_shade(unsigned long *body, int do_shade) { Window w; w = (Window)(body[0]); if (w != win) { return; } if (do_shade) { flags.is_shaded = 1; flags.needs_resize_after_unshade = 0; } else { flags.is_shaded = 0; if (flags.needs_resize_after_unshade) { AdjustWindow(True); flags.needs_resize_after_unshade = 0; } } return; } /* Main - Setup the XConnection,request the window list and loop forever Based on main() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ int main(int argc, char **argv) { char *temp, *s; #ifdef HAVE_SIGACTION struct sigaction sigact; #endif int i; short opt_num; for (i = 3; i < NUMBER_OF_EXTENDED_MOUSE_BUTTONS; i++) { ClickAction[i] = "Nop"; } /* Save the program name for error messages and config parsing */ temp = argv[0]; s=strrchr(argv[0], '/'); if (s != NULL) temp = s + 1; /* Open the console for messages */ OpenConsole(); if((argc != 6)&&(argc != 7)&&(argc != 8)) { fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",temp, VERSION); ConsoleMessage("%s Version %s should only be executed by fvwm!\n",temp, VERSION); exit(1); } opt_num = 6; if (argc == 7 && (strcasecmp(argv[6],"Transient") == 0 || strcasecmp(argv[6],"-Transient") == 0)) { Transient=1; opt_num++; } /* Check for an alias */ if (argc >= opt_num + 1 && argv[opt_num] != NULL) { Module = safemalloc(strlen(argv[opt_num])+2); strcpy(Module,"*"); strcat(Module, argv[opt_num]); Clength = strlen(Module); } else { Module = safemalloc(strlen(temp)+2); strcpy(Module,"*"); strcat(Module, temp); Clength = strlen(Module); } FlocaleInit(LC_CTYPE, "", "", "FvwmWinList"); Fvwm_fd[0] = atoi(argv[1]); Fvwm_fd[1] = atoi(argv[2]); #ifdef HAVE_SIGACTION #ifdef SA_INTERRUPT sigact.sa_flags = SA_INTERRUPT; #else sigact.sa_flags = 0; #endif sigemptyset(&sigact.sa_mask); sigaddset(&sigact.sa_mask, SIGTERM); sigaddset(&sigact.sa_mask, SIGPIPE); sigaddset(&sigact.sa_mask, SIGINT); sigact.sa_handler = TerminateHandler; sigaction(SIGPIPE, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); #else #ifdef USE_BSD_SIGNALS fvwmSetSignalMask( sigmask(SIGPIPE) | sigmask(SIGINT) | sigmask(SIGTERM) ); #endif signal(SIGPIPE, TerminateHandler); signal(SIGTERM, TerminateHandler); signal(SIGINT, TerminateHandler); #ifdef HAVE_SIGINTERRUPT siginterrupt(SIGPIPE, True); siginterrupt(SIGTERM, True); siginterrupt(SIGINT, True); #endif #endif /* set default colorsets */ colorset[0] = colorset[1] = 0; colorset[2] = colorset[3] = 1; AllocColorset(1); FlocaleAllocateWinString(&FwinString); /* Setup the XConnection */ StartMeUp_I(); /* Parse the config file */ ParseConfig(); /* more initialisations */ StartMeUp_II(); XSetErrorHandler(ErrorHandler); InitArray(&buttons,0,0,win_width, fontheight+2, ReliefWidth); InitList(&windows); fd_width = GetFdWidth(); /* Request a list of all windows, * wait for ConfigureWindow packets */ SetMessageMask(Fvwm_fd, M_MINI_ICON | M_CONFIGURE_WINDOW | M_ADD_WINDOW | M_DESTROY_WINDOW | M_VISIBLE_NAME | M_DEICONIFY | M_ICONIFY | M_END_WINDOWLIST | M_NEW_DESK | M_FOCUS_CHANGE | M_CONFIG_INFO | M_SENDCONFIG | M_WINDOWSHADE | M_DEWINDOWSHADE); /* extended messages */ SetMessageMask(Fvwm_fd, MX_VISIBLE_ICON_NAME | MX_PROPERTY_CHANGE); SendText(Fvwm_fd, "Send_WindowList",0); /* Recieve all messages from Fvwm */ atexit(ShutMeDown); /* tell fvwm we're running */ SendFinishedStartupNotification(Fvwm_fd); /* Lock on send only for iconify and deiconify (for NoIconAction) */ SetSyncMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY); SetNoGrabMask(Fvwm_fd, M_DEICONIFY | M_ICONIFY); MainEventLoop(); return 0; } /* MainEventLoop - Read and redraw until we die, blocking when can't read */ void MainEventLoop(void) { fd_set readset; while( !isTerminated ) { FD_ZERO(&readset); FD_SET(Fvwm_fd[1],&readset); FD_SET(x_fd,&readset); /* This code restyled after FvwmIconMan, which is simpler. * The biggest advantage over the original approach is * having one fewer select statements */ XFlush(dpy); if (fvwmSelect(fd_width, &readset, NULL, NULL, NULL) > 0) { if (FD_ISSET(x_fd,&readset) || FPending(dpy)) LoopOnEvents(); if (FD_ISSET(Fvwm_fd[1],&readset)) ReadFvwmPipe(); } } /* while */ } /* ReadFvwmPipe - Read a single message from the pipe from Fvwm Originally Loop() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ReadFvwmPipe(void) { FvwmPacket* packet = ReadFvwmPacket(Fvwm_fd[1]); if ( packet == NULL ) exit(0); else ProcessMessage( packet->type, packet->body ); } /* ProcessMessage - Process the message coming from Fvwm Skeleton based on processmessage() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ProcessMessage(unsigned long type,unsigned long *body) { int redraw=0,i,j; Item *flagitem; char *name,*string; static int current_focus=-1; struct ConfigWinPacket *cfgpacket; FvwmPicture p; switch(type) { case M_ADD_WINDOW: case M_CONFIGURE_WINDOW: cfgpacket = (void *) body; /* We get the win_borders only when WinList map it self, this is ok * since we need it only after an unmap */ if (cfgpacket->w == win) { cfg_g.x = cfgpacket->frame_x; cfg_g.y = cfgpacket->frame_y; cfg_g.width = cfgpacket->frame_width; cfg_g.height = cfgpacket->frame_height; #ifdef COMPLEX_WINDOW_PLACEMENT win_border_x = win_border_y = cfgpacket->border_width; if (((win_grav == NorthWestGravity || win_grav == NorthEastGravity) && HAS_TITLE_DIR(cfgpacket, DIR_N)) || ((win_grav == SouthWestGravity || win_grav == SouthEastGravity) && HAS_TITLE_DIR(cfgpacket, DIR_S))) { win_border_y += cfgpacket->title_height; } if (((win_grav == NorthWestGravity || win_grav == SouthWestGravity) && HAS_TITLE_DIR(cfgpacket, DIR_W)) || ((win_grav == NorthEastGravity || win_grav == SouthEastGravity) && HAS_TITLE_DIR(cfgpacket, DIR_E))) { win_border_x += cfgpacket->title_height; } #endif } if ((i = FindItem(&windows,cfgpacket->w))!=-1) { flagitem=ItemFlags(&windows,cfgpacket->w); if(UpdateItemDesk(&windows, cfgpacket) > 0 || IS_STICKY_ACROSS_DESKS(cfgpacket) != IS_STICKY_ACROSS_DESKS(flagitem) || DO_SKIP_WINDOW_LIST(cfgpacket) != DO_SKIP_WINDOW_LIST(flagitem)) { UpdateItemGSFRFlags(&windows, cfgpacket); UpdateButtonDeskFlags(&buttons, i, cfgpacket->desk, IS_STICKY_ACROSS_DESKS(cfgpacket), DO_SKIP_WINDOW_LIST(cfgpacket)); AdjustWindow(False); RedrawWindow(True, True, NULL); } else UpdateItemGSFRFlags(&windows, cfgpacket); break; } else { AddItem(&windows, cfgpacket); /* Make sure the lists are synced in order If windows are created during a Send_WindowList strange things might happen */ AddButton(&buttons, NULL, NULL, 1); i = FindItem(&windows,cfgpacket->w); UpdateButtonDeskFlags(&buttons, i, cfgpacket->desk, IS_STICKY_ACROSS_DESKS(cfgpacket), DO_SKIP_WINDOW_LIST(cfgpacket)); } break; case M_DESTROY_WINDOW: cfgpacket = (void *) body; if ((i=DeleteItem(&windows,cfgpacket->w))==-1) break; RemoveButton(&buttons,i); if (WindowState) AdjustWindow(False); redraw=1; break; case M_MINI_ICON: if (!FMiniIconsSupported || (i=FindItem(&windows,body[0]))==-1) break; if (UpdateButton(&buttons,i,NULL,-1)!=-1) { MiniIconPacket *mip = (MiniIconPacket *) body; p.picture = mip->picture; p.mask = mip->mask; p.alpha = mip->alpha; p.width = mip->width; p.height = mip->height; p.depth = mip->depth; UpdateButtonPicture(&buttons, i, &p); AdjustWindow(False); redraw = 1; } break; case M_VISIBLE_NAME: case MX_VISIBLE_ICON_NAME: if ((type == MX_VISIBLE_ICON_NAME) ^ UseIconNames) break; string=(char *)&body[3]; if ((i=UpdateItemName(&windows,body[0],string))==-1) break; flagitem = ItemFlags(&windows,body[0]); name=makename(string, (IS_ICONIFIED(flagitem)?True:False)); if (UpdateButton(&buttons,i,name,-1)==-1) { AddButton(&buttons, name, NULL, 1); UpdateButtonSet(&buttons, i, (IS_ICONIFIED(flagitem)?1:0)); UpdateButtonDeskFlags(&buttons,i,ItemDesk(&windows, body[0]), IS_STICKY_ACROSS_DESKS(flagitem), DO_SKIP_WINDOW_LIST(flagitem)); } free(name); if (WindowState) AdjustWindow(False); redraw=1; break; case M_DEICONIFY: case M_ICONIFY: /* fwvm will wait for an Unlock message before continuing * be careful when changing this construct, make sure unlock happens */ if ((i = FindItem(&windows, body[0])) != -1) { flagitem = ItemFlags(&windows, body[0]); if ((type == M_DEICONIFY && IS_ICONIFIED(flagitem)) || (type == M_ICONIFY && !IS_ICONIFIED(flagitem))) { if (IS_ICON_SUPPRESSED(flagitem) && IsItemIndexVisible(&windows,i) && AnimCommand && WindowState && AnimCommand[0] != 0) { char buff[MAX_MODULE_INPUT_TEXT_LEN]; Window child; int x, y, w, h; /* find out where our button is */ j = FindItemVisible(&windows, body[0]); XTranslateCoordinates( dpy, win, Root, 0, j * buttonheight, &x, &y, &child); w = win_width; h = buttonheight; if (flags.is_shaded) { if (w > cfg_g.width - win_border_x) { w = 1; } if (h > cfg_g.height - win_border_y) { h = 1; } if (x < cfg_g.x || x > cfg_g.x + cfg_g.width) { x = cfg_g.x + win_border_x; } if (y < cfg_g.y || y > cfg_g.y + cfg_g.height) { y = cfg_g.y + win_border_y; } } /* tell FvwmAnimate to animate to our button */ if (IS_ICONIFIED(flagitem)) { sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand, x, y, w, h, (int)body[7], (int)body[8], (int)body[9], (int)body[10]); } else { sprintf(buff, "%s %d %d %d %d %d %d %d %d", AnimCommand, (int)body[7], (int)body[8], (int)body[9], (int)body[10], x, y, w, h); } SendText(Fvwm_fd, buff, 0); } SET_ICONIFIED(flagitem, !IS_ICONIFIED(flagitem)); string = ItemName(&windows, i); name = makename(string, IS_ICONIFIED(flagitem)); UpdateButtonIconified(&buttons, i, IS_ICONIFIED(flagitem)); if (UpdateButton(&buttons, i, name, -1) != -1) redraw = 1; if (i != current_focus || (IS_ICONIFIED(flagitem))) if (UpdateButtonSet(&buttons, i, (IS_ICONIFIED(flagitem)) ? 1 : 0) != -1) redraw = 1; free(name); } } SendUnlockNotification(Fvwm_fd); break; case M_FOCUS_CHANGE: redraw = 1; if ((i=FindItem(&windows,body[0]))!=-1) { RadioButton(&buttons,i,ButPressed); if (Follow && i) { /* rearrange order */ ReorderList(&windows,i,body[2]); if (WindowState) ReorderButtons(&buttons,i,body[2]); } } else RadioButton(&buttons,-1,ButPressed); break; case M_END_WINDOWLIST: if (!WindowState) MakeMeWindow(); redraw = 1; break; case M_NEW_DESK: CurrentDesk = body[0]; if(ShowCurrentDesk) { AdjustWindow(False); RedrawWindow(True, True, NULL); } break; case M_WINDOWSHADE: window_shade(body, 1); break; case M_DEWINDOWSHADE: window_shade(body, 0); break; case MX_PROPERTY_CHANGE: if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND && body[2] == 0 && WindowState && win_bg == ParentRelative) { RedrawWindow(True, True, NULL); } break; case M_CONFIG_INFO: ParseConfigLine((char *)&body[3]); break; } if (redraw && WindowState==1) RedrawWindow(False, True, NULL); } /* RedrawWindow - Update the needed lines and erase any old ones */ void RedrawWindow(Bool force, Bool clear_bg, XEvent *evp) { DrawButtonArray(&buttons, force, clear_bg, evp); XFlush(dpy); /** Put here for VMS; ifdef if causes performance problem **/ if (FQLength(dpy) && !force) LoopOnEvents(); } /* ConsoleMessage - Print a message on the console. Works like printf. */ void ConsoleMessage(const char *fmt, ...) { #ifndef NO_CONSOLE va_list args; FILE *filep; if (console==NULL) filep=stderr; else filep=console; va_start(args,fmt); vfprintf(filep,fmt,args); va_end(args); #endif } /* OpenConsole - Open the console as a way of sending messages */ int OpenConsole(void) { #ifndef NO_CONSOLE if ((console=fopen("/dev/console","w"))==NULL) { fprintf(stderr,"%s: cannot open console\n",Module); return 0; } #endif return 1; } /* ParseConfig - Parse the configuration file fvwm to us to use Based on part of main() from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ParseConfig(void) { char *tline; InitGetConfigLine(Fvwm_fd,Module); GetConfigLine(Fvwm_fd,&tline); while(tline != (char *)0) { ParseConfigLine(tline); GetConfigLine(Fvwm_fd,&tline); } } void ParseConfigLine(char *tline) { static Bool has_icon_back = False; static Bool has_icon_fore = False; static Bool has_icon_cset = False; if (!tline) return; if (strlen(tline) > 1) { if (strncasecmp(tline, CatString3(Module, "Font", ""), Clength + 4) == 0) CopyStringWithQuotes(&font_string, &tline[Clength + 4]); else if (strncasecmp(tline, CatString3(Module, "Fore", ""), Clength + 4) == 0) { CopyString(&ForeColor[0], &tline[Clength + 4]); colorset[0] = -1; if (!has_icon_cset) colorset[1] = -1; if (!has_icon_fore) CopyString(&ForeColor[1], &tline[Clength + 4]); } else if (strncasecmp(tline, CatString3(Module, "IconFore", ""), Clength + 8) == 0) { CopyString(&ForeColor[1], &tline[Clength + 8]); if (colorset[0] >= 0) colorset[1] = colorset[0]; else colorset[1] = -1; has_icon_fore = True; has_icon_cset = False; } else if (strncasecmp(tline, CatString3(Module, "FocusFore", ""), Clength + 9) == 0) { CopyString(&ForeColor[2], &tline[Clength + 9]); CopyString(&ForeColor[3], &tline[Clength + 9]); colorset[2] = colorset[3] = -1; } else if (strncasecmp(tline, CatString3(Module, "Geometry", ""), Clength + 8) == 0) CopyString(&geometry, &tline[Clength + 8]); else if (strncasecmp(tline, CatString3(Module, "Back", ""), Clength + 4) == 0) { CopyString(&BackColor[0], &tline[Clength + 4]); colorset[0] = -1; if (!has_icon_cset) colorset[1] = -1; if (!has_icon_back) CopyString(&BackColor[1], &tline[Clength + 4]); } else if (strncasecmp(tline, CatString3(Module, "IconBack", ""), Clength + 8) == 0) { CopyString(&BackColor[1], &tline[Clength + 8]); if (colorset[0] >= 0) colorset[1] = colorset[0]; else colorset[1] = -1; has_icon_fore = True; has_icon_cset = False; } else if (strncasecmp(tline, CatString3(Module, "FocusBack", ""), Clength + 9) == 0) { CopyString(&BackColor[2], &tline[Clength + 9]); CopyString(&BackColor[3], &tline[Clength + 9]); colorset[2] = colorset[3] = -1; } else if (strncasecmp(tline, CatString3(Module, "NoAnchor", ""), Clength + 8) == 0) Anchor = False; else if (strncasecmp(tline, CatString3(Module, "Action", ""), Clength + 6) == 0) LinkAction(&tline[Clength + 6]); else if (strncasecmp(tline, CatString3(Module, "UseSkipList", ""), Clength + 11) == 0) UseSkipList = True; else if (strncasecmp(tline, CatString3(Module, "UseIconNames", ""), Clength + 12) == 0) UseIconNames = True; else if (strncasecmp(tline, CatString3(Module, "ShowCurrentDesk", ""), Clength + 15) == 0) ShowCurrentDesk = 1; else if (strncasecmp(tline, CatString3(Module, "LeftJustify", ""), Clength + 11) == 0) LeftJustify = True; else if (strncasecmp(tline, CatString3(Module, "TruncateLeft", ""), Clength + 12) == 0) TruncateLeft = True; else if (strncasecmp(tline, CatString3(Module, "MinWidth", ""), Clength + 8) == 0) MinWidth = atoi(&tline[Clength + 8]); else if (strncasecmp(tline, CatString3(Module, "MaxWidth", ""), Clength + 8) == 0) MaxWidth = atoi(&tline[Clength + 8]); else if (strncasecmp(tline, CatString3(Module, "DontDepressFocus", ""), Clength + 16) == 0) ShowFocus = False; else if (strncasecmp(tline, CatString3(Module, "FollowWindowList", ""), Clength + 16) == 0) Follow = True; else if (strncasecmp(tline, CatString3(Module, "ButtonFrameWidth", ""), Clength + 16) == 0) { ReliefWidth = atoi(&tline[Clength + 16]); buttonheight = fontheight + 3 + 2 * ReliefWidth; } else if (strncasecmp(tline, CatString3(Module, "NoIconAction", ""), Clength + 12) == 0) { CopyString(&AnimCommand, &tline[Clength + 12]); if (strlen(AnimCommand) > MAX_NO_ICON_ACTION_LENGTH) AnimCommand[MAX_NO_ICON_ACTION_LENGTH] = 0; } else if (strncasecmp(tline, CatString3(Module, "Colorset", ""), Clength + 8) == 0) { colorset[0] = atoi(&tline[Clength + 8]); AllocColorset(colorset[0]); } else if (strncasecmp(tline, CatString3(Module, "IconColorset", ""), Clength + 12) == 0) { colorset[1] = atoi(&tline[Clength + 12]); AllocColorset(colorset[1]); has_icon_cset = True; } else if (strncasecmp(tline, CatString3(Module, "FocusColorset", ""), Clength + 13) == 0) { colorset[2] = colorset[3] = atoi(&tline[Clength + 13]); AllocColorset(colorset[3]); has_icon_cset = True; } else if (strncasecmp(tline, "Colorset", 8) == 0) { int cset = LoadColorset(&tline[8]); if (WindowState && (cset >= 0)) { int i; Pixmap old_win_bg = win_bg; /* set the window background */ win_bg = None; for (i = 0; i != MAX_COLOUR_SETS; i++) { if (CSET_IS_TRANSPARENT_PR(colorset[i])) win_bg = ParentRelative; } if (old_win_bg != win_bg) XSetWindowBackgroundPixmap(dpy, win, win_bg); /* refresh if this colorset is used */ for (i = 0; i != MAX_COLOUR_SETS; i++) { if (colorset[i] == cset) { AdjustWindow(True); RedrawWindow(True, True, NULL); break; } } } } else if (strncasecmp(tline, XINERAMA_CONFIG_STRING, sizeof(XINERAMA_CONFIG_STRING) - 1) == 0) { FScreenConfigureModule( tline + sizeof(XINERAMA_CONFIG_STRING) - 1); } } } /* LoopOnEvents - Process all the X events we get */ void LoopOnEvents(void) { int num; char buffer[10]; XEvent Event; #if 1 Window dummyroot,dummychild; int x,xdummy,y,ydummy; unsigned int dummy1; if (Transient && !Checked) { if (Pressed) { if (FQueryPointer( dpy, win, &dummyroot, &dummychild, &xdummy, &ydummy, &x, &y, &dummy1) == False) { /* pointer is on a different screen - that's okay here */ } num=WhichButton(&buttons,x,y); if (num!=-1) { Pressed=1; ButPressed=num; UpdateButton(&buttons, num, NULL, 0); } else { Pressed=0; } } Checked=1; } #endif while(FPending(dpy)) { FNextEvent(dpy,&Event); switch(Event.type) { case ButtonRelease: if (Pressed) { num=WhichButton(&buttons,Event.xbutton.x,Event.xbutton.y); if (num!=-1 && Event.xbutton.button >= 1 && Event.xbutton.button <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS) { SendFvwmPipe(Fvwm_fd, ClickAction[Event.xbutton.button-1], ItemID(&windows,num)); SwitchButton(&buttons,num); } } if (Transient) { exit(0); } Pressed=0; ButPressed=-1; break; case ButtonPress: num=WhichButton(&buttons,Event.xbutton.x,Event.xbutton.y); if (num != -1) { SwitchButton(&buttons,num); ButPressed=num; } else ButPressed=-1; Pressed=1; break; case Expose: { int ex = Event.xexpose.x; int ey = Event.xexpose.y; int ex2 = Event.xexpose.x + Event.xexpose.width; int ey2 = Event.xexpose.y + Event.xexpose.height; while (FCheckTypedWindowEvent(dpy, win, 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); } Event.xexpose.x = ex; Event.xexpose.y = ey; Event.xexpose.width = ex2 - ex; Event.xexpose.height = ey2 - ey; RedrawWindow(True, True, &Event); break; } case ConfigureNotify: { XEvent event; /* Opaque moves cause lots of these to be sent which causes flickering * It's better to miss out on intermediate steps than to do them all * and take too long. Look down the event queue and do the last one */ while (FCheckTypedWindowEvent(dpy, win, ConfigureNotify, &event)) { /* if send_event is true it means the user has moved the window or * winlist has mapped itself, take note of the new position. * If it is false it comes from the Xserver and is bogus */ if (!event.xconfigure.send_event) continue; Event.xconfigure.x = event.xconfigure.x; Event.xconfigure.y = event.xconfigure.y; Event.xconfigure.send_event = True; } if (Event.xconfigure.send_event && (win_x != Event.xconfigure.x || win_y != Event.xconfigure.y || win_bg == ParentRelative)) { win_x = Event.xconfigure.x; win_y = Event.xconfigure.y; DrawTransparentButtonArray(&buttons); } } break; case KeyPress: num=XLookupString(&Event.xkey,buffer,10,NULL,0); if (num==1) { if (buffer[0]=='q' || buffer[0]=='Q') exit(0); else if (buffer[0]=='i' || buffer[0]=='I') PrintList(&windows); else if (buffer[0]=='b' || buffer[0]=='B') PrintButtons(&buttons); } break; case ClientMessage: if ((Event.xclient.format==32) && (Event.xclient.data.l[0]==wm_del_win)) exit(0); case EnterNotify: if (!SomeButtonDown(Event.xcrossing.state)) break; num=WhichButton(&buttons,Event.xcrossing.x,Event.xcrossing.y); if (num!=-1) { SwitchButton(&buttons,num); ButPressed=num; } else ButPressed=-1; Pressed=1; break; case LeaveNotify: if (!SomeButtonDown(Event.xcrossing.state)) break; if (ButPressed!=-1) SwitchButton(&buttons,ButPressed); Pressed=0; break; case MotionNotify: if (!Pressed) break; num=WhichButton(&buttons,Event.xmotion.x,Event.xmotion.y); if (num==ButPressed) break; if (ButPressed!=-1) SwitchButton(&buttons,ButPressed); if (num!=-1) { SwitchButton(&buttons,num); ButPressed=num; } else ButPressed=-1; break; } } } /* AdjustWindow - Resize the window according to maxwidth by number of buttons */ void AdjustWindow(Bool force) { int new_width=0,new_height=0,tw,i,total,all; char *temp; int base_miw = 0; total = ItemCountVisible(&windows); all = ItemCount(&windows); if (!total) { if (WindowState==1) { XUnmapWindow(dpy,win); WindowState=2; } return; } if (FMiniIconsSupported) { for(i=0; ipicture != None) { if (ButtonPicture(&buttons,i)->width > base_miw) base_miw = ButtonPicture(&buttons,i)->width; break; } } base_miw += 2; } for(i=0;i= 0) { fore[i] = Colorset[cset].fg; back[i] = Colorset[cset].bg; XSetForeground(dpy, graph[i], fore[i]); XSetForeground(dpy, background[i], back[i]); XSetForeground(dpy, hilite[i], Colorset[cset].hilite); XSetForeground(dpy, shadow[i], Colorset[cset].shadow); } } } /* change the pixmap if forced or if width changed (the height is fixed) */ if (WindowState && (force || new_width != win_width)) { for (i = 0; i != MAX_COLOUR_SETS; i++) { int cset = colorset[i]; if (cset >= 0) { if (pixmap[i]) XFreePixmap(dpy, pixmap[i]); if (Colorset[cset].pixmap && !CSET_IS_TRANSPARENT_PR(cset)) { if (CSET_IS_TRANSPARENT_ROOT(cset)) { pixmap[i] = CreateBackgroundPixmap( dpy, win, new_width, win_height, &Colorset[cset], Pdepth, background[i], False); } else { pixmap[i] = CreateBackgroundPixmap( dpy, win, win_width, buttonheight, &Colorset[cset], Pdepth, background[i], False); } XSetTile(dpy, background[i], pixmap[i]); XSetFillStyle(dpy, background[i], FillTiled); } else { pixmap[i] = None; XSetFillStyle(dpy, background[i], FillSolid); } } } } if (WindowState && (new_height!=win_height || new_width!=win_width || (!flags.is_shaded && flags.needs_resize_after_unshade))) { #ifdef COMPLEX_WINDOW_PLACEMENT if (Anchor) { /* compensate for fvwm borders when going from unmapped to mapped */ int map_x_adjust = (WindowState - 1) * win_border_x; int map_y_adjust = (WindowState - 1) * win_border_y; switch (win_grav) { case NorthWestGravity: case SouthWestGravity: win_x -= map_x_adjust; break; case NorthEastGravity: case SouthEastGravity: win_x += win_width - new_width + map_x_adjust; break; } switch (win_grav) { case NorthWestGravity: case NorthEastGravity: win_y -= map_y_adjust; break; case SouthEastGravity: case SouthWestGravity: win_y += win_height - new_height + map_y_adjust; break; } /* XMoveResizeWindow(dpy, win, win_x, win_y, new_width, new_height); */ } if (flags.is_shaded) flags.needs_resize_after_unshade = 1; else if (Anchor && WindowState == 2) XMoveResizeWindow(dpy, win, win_x, win_y, new_width, new_height); else XResizeWindow(dpy, win, new_width, new_height); /* The new code is sooo much simpler :-) */ #else if (flags.is_shaded) flags.needs_resize_after_unshade = 1; else /* This relies on fvwm honouring South/East gemoetry when resizing. */ XResizeWindow(dpy, win, new_width, new_height); #endif } UpdateArray(&buttons,new_width); if (new_height>0) win_height = new_height; if (new_width>0) win_width = new_width; if (WindowState==2) { XMapWindow(dpy,win); WindowState=1; } } /* makename - Based on the flags return me '(name)' or 'name' */ char *makename(const char *string, Bool iconified) { char *ptr; if (!iconified) return safestrdup(string); ptr=safemalloc(strlen(string)+3); sprintf(ptr, "(%s)", string); return ptr; } /* LinkAction - Link an response to a users action */ void LinkAction(char *string) { char *temp; temp=string; while(isspace((unsigned char)*temp)) temp++; if(strncasecmp(temp, "Click", 5)==0) { int n; int b; int i; i = sscanf(temp + 5, "%d%n", &b, &n); if (i > 0 && b >=1 && b <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS) { CopyString(&ClickAction[b - 1], temp + 5 + n); } } else if(strncasecmp(temp, "Enter", 5)==0) CopyString(&EnterAction,&temp[5]); } /* MakeMeWindow - Create and setup the window we will need */ void MakeMeWindow(void) { XSizeHints hints; XClassHint classhints; XGCValues gcval; unsigned long gcmask; unsigned int dummy1, dummy2; int x, y, ret, count; int wx; int wy; Window dummyroot, dummychild; int i; XSetWindowAttributes attr; if ((count = ItemCountVisible(&windows))==0 && Transient) { exit(0); } AdjustWindow(False); hints.width=win_width; hints.height=win_height; hints.win_gravity=NorthWestGravity; hints.flags=PSize|PWinGravity; if (Transient) { fscreen_scr_arg fscr; if (FQueryPointer( dpy, Root, &dummyroot, &dummychild, &wx, &wy, &x, &y, &dummy1) == False) { /* pointer is on a different screen */ wx = 0; wy = 0; } fscr.xypos.x = wx; fscr.xypos.y = wy; FScreenGetScrRect( &fscr, FSCREEN_XYPOS, &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height); wx -= hints.width / 2; wy -= buttonheight / 2; if (wx + hints.width > screen_g.x + screen_g.width) { wx = screen_g.x + screen_g.width - hints.width; } if (wx < screen_g.x) { wx = screen_g.x; } if (wy + hints.height > screen_g.y + screen_g.height) { wy = screen_g.y + screen_g.height - hints.height; } if (wy < screen_g.y) { wy = screen_g.y; } hints.win_gravity = NorthWestGravity; hints.flags |= USPosition; } else if (geometry!= NULL) { /* now evaluate the geometry parsed above */ ret = FScreenParseGeometry(geometry, &x, &y, &dummy1, &dummy2); hints.win_gravity=NorthWestGravity; if ((ret & XValue) && (ret & YValue)) { wx = x; wy = y; if (ret & XNegative) { wx += XDisplayWidth(dpy,screen) - win_width; hints.win_gravity=NorthEastGravity; } if (ret & YNegative) { wy += XDisplayHeight(dpy,screen) - win_height; if (ret & XNegative) { hints.win_gravity=SouthEastGravity; } else { hints.win_gravity=SouthWestGravity; } } hints.flags |= USPosition; } #ifndef COMPLEX_WINDOW_PLACEMENT if (!Anchor) { if (hints.win_gravity == SouthWestGravity) hints.win_gravity=NorthWestGravity; else if (hints.win_gravity == SouthEastGravity) hints.win_gravity=NorthEastGravity; } #endif } win_x = wx; win_y = wy; win_grav = hints.win_gravity; for (i = 0; i != MAX_COLOUR_SETS; i++) if(Pdepth < 2) { back[i] = GetColor("white"); fore[i] = GetColor("black"); } else { if (colorset[i] >= 0) { back[i] = Colorset[colorset[i]].bg; fore[i] = Colorset[colorset[i]].fg; } else { back[i] = GetColor(BackColor[i] == NULL ? BackColor[0] : BackColor[i]); fore[i] = GetColor(ForeColor[i] == NULL ? ForeColor[0] : ForeColor[i]); } } /* FvwmWinList paints the entire window and does not rely on the xserver to * render the background. Setting the background_pixmap to None prevents the * server from doing anything on expose events. The exception is when one of * the colorsets is transparent which requires help from the server */ win_bg = None; for (i = 0; i != MAX_COLOUR_SETS; i++) { if (CSET_IS_TRANSPARENT_PR(colorset[i])) { win_bg = ParentRelative; break; } } attr.background_pixmap = win_bg; attr.border_pixel = 0; attr.colormap = Pcmap; win=XCreateWindow(dpy, Root, wx, wy, hints.width, hints.height, 0, Pdepth, InputOutput, Pvisual, CWBackPixmap | CWBorderPixel | CWColormap, &attr); if (Transient) { XSetTransientForHint(dpy, win, Root); } wm_del_win=XInternAtom(dpy,"WM_DELETE_WINDOW",False); XSetWMProtocols(dpy,win,&wm_del_win,1); FwinString->win = win; { XTextProperty nametext; char *list[]={NULL,NULL}; list[0] = Module+1; classhints.res_name=safestrdup(Module+1); classhints.res_class=safestrdup("FvwmWinList"); if(!XStringListToTextProperty(list,1,&nametext)) { fprintf(stderr,"%s: Failed to convert name to XText\n",Module); exit(1); } XSetWMProperties(dpy,win,&nametext,&nametext, NULL,0,&hints,NULL,&classhints); XFree(nametext.value); } if (!Transient) { XGrabButton(dpy,1,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync, GrabModeAsync,None,None); XGrabButton(dpy,2,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync, GrabModeAsync,None,None); XGrabButton(dpy,3,AnyModifier,win,True,GRAB_EVENTS,GrabModeAsync, GrabModeAsync,None,None); SetMwmHints( MWM_DECOR_ALL|MWM_DECOR_RESIZEH|MWM_DECOR_MAXIMIZE|MWM_DECOR_MINIMIZE, MWM_FUNC_ALL|MWM_FUNC_RESIZE|MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE, MWM_INPUT_MODELESS); } else { SetMwmHints(0,MWM_FUNC_ALL,MWM_INPUT_MODELESS); } for (i = 0; i != MAX_COLOUR_SETS; i++) { gcval.foreground=fore[i]; gcval.background=back[i]; gcmask=GCForeground|GCBackground; if (FButtonFont->font != NULL) { gcval.font=FButtonFont->font->fid; gcmask |= GCFont; } graph[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); if(Pdepth < 2) gcval.foreground=GetShadow(fore[i]); else if (colorset[i] < 0) gcval.foreground=GetShadow(back[i]); else gcval.foreground=Colorset[colorset[i]].shadow; gcval.background=back[i]; gcmask=GCForeground|GCBackground; shadow[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); if (colorset[i] < 0) gcval.foreground=GetHilite(back[i]); else gcval.foreground=Colorset[colorset[i]].hilite; gcval.background=back[i]; gcmask=GCForeground|GCBackground; hilite[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); gcval.foreground=back[i]; gcmask=GCForeground; background[i]=fvwmlib_XCreateGC(dpy,win,gcmask,&gcval); if ((colorset[i] >= 0) && Colorset[colorset[i]].pixmap && !CSET_IS_TRANSPARENT_PR(colorset[i])) { if (CSET_IS_TRANSPARENT_ROOT(colorset[i])) { pixmap[i] = CreateBackgroundPixmap( dpy, win, win_width, win_height, &Colorset[colorset[i]], Pdepth, background[i], False); } else { pixmap[i] = CreateBackgroundPixmap( dpy, win, win_width, buttonheight, &Colorset[colorset[i]], Pdepth, background[i], False); } XSetTile(dpy, background[i], pixmap[i]); XSetFillStyle(dpy, background[i], FillTiled); } } AdjustWindow(True); XSelectInput(dpy,win,(StructureNotifyMask | ExposureMask | KeyPressMask)); if (ItemCountVisible(&windows) > 0) { XMapRaised(dpy,win); WindowState=1; } else WindowState=2; if (Transient) { int i = 0; XSync(dpy,0); while (i < 1000 && XGrabPointer(dpy, win, True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| PointerMotionMask|EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess) { i++; /* If you go too fast, other windows may not get a change to release * any grab that they have. */ usleep(1000); } XSync(dpy,0); if (i >= 1000) { fprintf(stderr,"failed to grab pointer\n"); exit(1); } Pressed = !!SomeButtonDown(dummy1); } } /* StartMeUp - Do X initialization things */ void StartMeUp_I(void) { if (!(dpy = XOpenDisplay(""))) { fprintf(stderr,"%s: can't open display %s", Module, XDisplayName("")); exit (1); } flib_init_graphics(dpy); x_fd = XConnectionNumber(dpy); screen= DefaultScreen(dpy); Root = RootWindow(dpy, screen); win = None; return; } void StartMeUp_II(void) { XSizeHints g_hints; int g_hints_rc; if (geometry == NULL) UpdateString(&geometry, ""); /* evaluate further down */ g_hints_rc = FScreenParseGeometryWithScreen( geometry, &g_hints.x, &g_hints.y, (unsigned int *)&g_hints.width, (unsigned int *)&g_hints.height, &fscreen); FScreenGetScrRect( NULL, fscreen, &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height); if ((FButtonFont = FlocaleLoadFont(dpy,font_string,Module)) == NULL) { fprintf(stderr,"%s: Cannot load font, Exitting\n", Module); exit(1); } fontheight = FButtonFont->height; buttonheight = fontheight + 3 + 2 * ReliefWidth; win_width=FlocaleTextWidth(FButtonFont,"XXXXXXXXXXXXXXX",10); } /* ShutMeDown - Do X client cleanup */ void ShutMeDown(void) { FreeList(&windows); FreeAllButtons(&buttons); /* XFreeGC(dpy,graph);*/ if (WindowState) XDestroyWindow(dpy,win); XCloseDisplay(dpy); } /* ChangeWindowName - Self explanitory Original work from FvwmIdent: Copyright 1994, Robert Nation and Nobutaka Suzuki. */ void ChangeWindowName(char *str) { XTextProperty name; if (XStringListToTextProperty(&str,1,&name) == 0) { fprintf(stderr,"%s: cannot allocate window name.\n",Module); return; } XSetWMName(dpy,win,&name); XSetWMIconName(dpy,win,&name); XFree(name.value); } /* * * Sets mwm hints * */ /* * Now, if we (hopefully) have MWW - compatible window manager , * say, mwm, ncdwm, or else, we will set useful decoration style. * Never check for MWM_RUNNING property.May be considered bad. */ void SetMwmHints(unsigned int value, unsigned int funcs, unsigned int input) { PropMwmHints prop; if (MwmAtom==None) { MwmAtom=XInternAtom(dpy,"_MOTIF_WM_HINTS",False); } if (MwmAtom!=None) { /* sh->mwm.decorations contains OR of the MWM_DECOR_XXXXX */ prop.props[0] = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS | MWM_HINTS_INPUT_MODE; prop.props[1] = funcs; prop.props[2]= value; prop.props[3] = input; /* HOP - LA! */ XChangeProperty( dpy, win, MwmAtom, MwmAtom, 32, PropModeReplace, (unsigned char *)&(prop.props[0]), PROP_MWM_HINTS_ELEMENTS); } } /* X Error Handler */ int ErrorHandler(Display *d, XErrorEvent *event) { /* some errors are OK=ish */ if (event->error_code == BadPixmap) return 0; if (event->error_code == BadDrawable) return 0; if (FRenderGetErrorCodeBase() + FRenderBadPicture == event->error_code) return 0; PrintXErrorAndCoredump(d, event, Module); return 0; }