summaryrefslogtreecommitdiff
path: root/app/fvwm/modules/FvwmWinList/FvwmWinList.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/fvwm/modules/FvwmWinList/FvwmWinList.c')
-rw-r--r--app/fvwm/modules/FvwmWinList/FvwmWinList.c1076
1 files changed, 1076 insertions, 0 deletions
diff --git a/app/fvwm/modules/FvwmWinList/FvwmWinList.c b/app/fvwm/modules/FvwmWinList/FvwmWinList.c
new file mode 100644
index 000000000..9fb6aaa39
--- /dev/null
+++ b/app/fvwm/modules/FvwmWinList/FvwmWinList.c
@@ -0,0 +1,1076 @@
+/* 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
+
+ * Bug Notes:(Don Mahurin)
+
+ * Moving a window doesnt send M_CONFIGURE, as I thought it should. Desktop
+ * for that button is not updated.
+
+*/
+
+#define TRUE 1
+#define FALSE 0
+
+#ifndef NO_CONSOLE
+#define NO_CONSOLE
+#endif
+
+#define YES "Yes"
+#define NO "No"
+
+#include "config.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <stdarg.h>
+
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef HAVE_SYS_BSDTYPES_H
+#include <sys/bsdtypes.h> /* Saul */
+#endif
+
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/cursorfont.h>
+
+#include "../../fvwm/module.h"
+
+#include "FvwmWinList.h"
+#include "ButtonArray.h"
+#include "List.h"
+#include "Colors.h"
+#include "Mallocs.h"
+
+#define GRAB_EVENTS (ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|EnterWindowMask|LeaveWindowMask)
+
+#define SomeButtonDown(a) ((a)&Button1Mask||(a)&Button2Mask||(a)&Button3Mask)
+
+/* File type information */
+FILE *console;
+int fd_width;
+int Fvwm_fd[2];
+int x_fd;
+
+/* X related things */
+Display *dpy;
+Window Root, win;
+int screen,d_depth,ScreenWidth,ScreenHeight;
+Pixel back[MAX_COLOUR_SETS], fore[MAX_COLOUR_SETS];
+GC graph[MAX_COLOUR_SETS],shadow[MAX_COLOUR_SETS],hilite[MAX_COLOUR_SETS];
+GC background[MAX_COLOUR_SETS];
+XFontStruct *ButtonFont;
+int fontheight;
+static Atom wm_del_win;
+Atom MwmAtom = None;
+
+/* Module related information */
+char *Module;
+int WindowIsUp=0,win_width=5,win_height=5,win_grav,win_x,win_y,win_title,win_border;
+int Clength,Transient=0,Pressed=0,ButPressed,Checked=0;
+int MinWidth=DEFMINWIDTH,MaxWidth=DEFMAXWIDTH;
+ButtonArray buttons;
+List windows;
+char *ClickAction[3]={"Iconify -1,Raise","Iconify","Lower"},*EnterAction,
+ *BackColor[MAX_COLOUR_SETS] = { "white" },
+ *ForeColor[MAX_COLOUR_SETS] = { "black" },
+ *geometry="";
+char *font_string = "fixed";
+int UseSkipList=0,Anchor=1,UseIconNames=0,LeftJustify=0,TruncateLeft=0,ShowFocus=1;
+
+long CurrentDesk = 0;
+int ShowCurrentDesk = 0;
+
+static volatile sig_atomic_t isTerminated = False;
+
+static RETSIGTYPE TerminateHandler(int sig);
+
+/***************************************************************************
+ * TerminateHandler - reentrant signal handler that ends the main event loop
+ ***************************************************************************/
+static RETSIGTYPE TerminateHandler(int sig)
+{
+ isTerminated = True;
+}
+
+int ItemCountD(List *list )
+{
+ if(!ShowCurrentDesk)
+ return ItemCount(list);
+ /* else */
+ return ItemCountDesk(list, CurrentDesk);
+
+}
+
+/******************************************************************************
+ 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
+
+ /* Save the program name for error messages and config parsing */
+ temp = argv[0];
+ s=strrchr(argv[0], '/');
+ if (s != NULL)
+ temp = s + 1;
+
+ /* Setup my name */
+ Module = safemalloc(strlen(temp)+2);
+ strcpy(Module,"*");
+ strcat(Module, temp);
+ Clength = strlen(Module);
+
+ /* Open the console for messages */
+ OpenConsole();
+
+ if((argc != 6)&&(argc != 7)) {
+ fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",Module,
+ VERSION);
+ ConsoleMessage("%s Version %s should only be executed by fvwm!\n",Module,
+ VERSION);
+ exit(1);
+ }
+
+
+ if ((argc==7)&&(!strcasecmp(argv[6],"Transient"))) Transient=1;
+
+ 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);
+ sigact.sa_handler = TerminateHandler;
+ sigaction(SIGPIPE, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+#else
+ signal(SIGPIPE, TerminateHandler);
+ signal(SIGTERM, TerminateHandler);
+#ifdef HAVE_SIGINTERRUPT
+ siginterrupt(SIGPIPE, True);
+ siginterrupt(SIGTERM, True);
+#endif
+#endif
+
+ /* Parse the config file */
+ ParseConfig();
+
+ /* Setup the XConnection */
+ StartMeUp();
+ XSetErrorHandler(ErrorHandler);
+
+ InitPictureCMap(dpy, Root);
+
+ InitArray(&buttons,0,0,win_width, fontheight+6);
+ InitList(&windows);
+
+ fd_width = GetFdWidth();
+
+ /* Request a list of all windows,
+ * wait for ConfigureWindow packets */
+
+ SetMessageMask(Fvwm_fd,M_CONFIGURE_WINDOW | M_RES_CLASS | M_RES_NAME |
+ M_ADD_WINDOW | M_DESTROY_WINDOW | M_ICON_NAME |
+ M_DEICONIFY | M_ICONIFY | M_END_WINDOWLIST |
+ M_NEW_DESK | M_NEW_PAGE | M_FOCUS_CHANGE | M_WINDOW_NAME |
+#ifdef MINI_ICONS
+ M_MINI_ICON |
+#endif
+ M_STRING);
+
+ SendFvwmPipe("Send_WindowList",0);
+
+ /* Recieve all messages from Fvwm */
+ atexit(ShutMeDown);
+ 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 (select(fd_width,SELECT_TYPE_ARG234 &readset,NULL,NULL,NULL) > 0) {
+
+ if (FD_ISSET(x_fd,&readset) || XPending(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)
+{
+ unsigned long header[HEADER_SIZE],*body;
+
+ if(ReadFvwmPacket(Fvwm_fd[1],header,&body) > 0)
+ {
+ ProcessMessage(header[1],body);
+ free(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;
+ long flags;
+ char *name,*string;
+ static int current_focus=-1;
+
+ Picture p;
+
+ switch(type)
+ {
+ case M_ADD_WINDOW:
+ case M_CONFIGURE_WINDOW:
+ if ((i = FindItem(&windows,body[0]))!=-1)
+ {
+ if(UpdateItemDesk(&windows, i, body[7]) > 0)
+ {
+ AdjustWindow();
+ RedrawWindow(1);
+ }
+ break;
+ }
+
+ if (!(body[8]&WINDOWLISTSKIP) || !UseSkipList)
+ AddItem(&windows,body[0],body[8], body[7] /* desk */);
+ break;
+ case M_DESTROY_WINDOW:
+ if ((i=DeleteItem(&windows,body[0]))==-1) break;
+ RemoveButton(&buttons,i);
+ if (WindowIsUp)
+ AdjustWindow();
+
+ redraw=1;
+ break;
+
+#ifdef MINI_ICONS
+ case M_MINI_ICON:
+ if ((i=FindItem(&windows,body[0]))==-1) break;
+
+ if (UpdateButton(&buttons,i,NULL,-1)!=-1)
+ {
+ p.width = body[3];
+ p.height = body[4];
+ p.depth = body[5];
+ p.picture = body[6];
+ p.mask = body[7];
+
+ UpdateButtonPicture(&buttons, i, &p);
+ redraw = 0;
+ }
+ break;
+#endif
+
+ case M_WINDOW_NAME:
+ case M_ICON_NAME:
+ if ((type==M_ICON_NAME && !UseIconNames) ||
+ (type==M_WINDOW_NAME && UseIconNames)) break;
+ if ((i=UpdateItemName(&windows,body[0],(char *)&body[3]))==-1) break;
+ string=(char *)&body[3];
+ name=makename(string,ItemFlags(&windows,body[0]));
+ if (UpdateButton(&buttons,i,name,-1)==-1)
+ {
+ AddButton(&buttons, name, NULL, 1);
+ UpdateButtonSet(&buttons,i,ItemFlags(&windows,body[0])&ICONIFIED?1:0);
+ UpdateButtonDesk(&buttons,i,ItemDesk(&windows, body[0]));
+ }
+ free(name);
+ if (WindowIsUp) AdjustWindow();
+ redraw=1;
+ break;
+ case M_DEICONIFY:
+ case M_ICONIFY:
+ if ((i=FindItem(&windows,body[0]))==-1) break;
+ flags=ItemFlags(&windows,body[0]);
+ if (type==M_DEICONIFY && !(flags&ICONIFIED)) break;
+ if (type==M_ICONIFY && flags&ICONIFIED) break;
+ flags^=ICONIFIED;
+ UpdateItemFlags(&windows,body[0],flags);
+ string=ItemName(&windows,i);
+ name=makename(string,flags);
+ if (UpdateButton(&buttons,i,name,-1)!=-1) redraw=1;
+ if (i!=current_focus||(flags&ICONIFIED))
+ if (UpdateButtonSet(&buttons,i,(flags&ICONIFIED) ? 1 : 0)!=-1) redraw=1;
+ free(name);
+ break;
+ case M_FOCUS_CHANGE:
+ if ((i=FindItem(&windows,body[0]))!=-1)
+ {
+ flags=ItemFlags(&windows,body[0]);
+ UpdateItemFlags(&windows,body[0],flags);
+ RadioButton(&buttons,i);
+ }
+ else
+ RadioButton(&buttons,-1);
+ redraw = 1;
+ break;
+ case M_END_WINDOWLIST:
+ if (!WindowIsUp) MakeMeWindow();
+ redraw = 1;
+ break;
+ case M_NEW_DESK:
+ CurrentDesk = body[0];
+ if(ShowCurrentDesk)
+ {
+ AdjustWindow();
+ RedrawWindow(1);
+ }
+ break;
+ case M_NEW_PAGE:
+ break;
+ }
+
+ if (redraw && WindowIsUp==1) RedrawWindow(0);
+}
+
+/******************************************************************************
+ SendFvwmPipe - Send a message back to fvwm
+ Based on SendInfo() from FvwmIdent:
+ Copyright 1994, Robert Nation and Nobutaka Suzuki.
+******************************************************************************/
+void SendFvwmPipe(char *message,unsigned long window)
+{
+ int w;
+ char *hold,*temp,*temp_msg;
+
+ hold=message;
+
+ while(1)
+ {
+ temp=strchr(hold,',');
+ if (temp!=NULL)
+ {
+ temp_msg=safemalloc(temp-hold+1);
+ strncpy(temp_msg,hold,(temp-hold));
+ temp_msg[(temp-hold)]='\0';
+ hold=temp+1;
+ } else temp_msg=hold;
+
+ write(Fvwm_fd[0],&window, sizeof(unsigned long));
+
+ w=strlen(temp_msg);
+ write(Fvwm_fd[0],&w,sizeof(int));
+ write(Fvwm_fd[0],temp_msg,w);
+
+ /* keep going */
+ w=1;
+ write(Fvwm_fd[0],&w,sizeof(int));
+
+ if(temp_msg!=hold) free(temp_msg);
+ else break;
+ }
+}
+
+/***********************************************************************
+ Detected a broken pipe - time to exit
+ Based on DeadPipe() from FvwmIdent:
+ Copyright 1994, Robert Nation and Nobutaka Suzuki.
+ **********************************************************************/
+void DeadPipe(int nonsense)
+{
+ /* ShutMeDown(1); */
+ /*
+ * do not call ShutMeDown, it may make X calls which are not allowed
+ * in a signal hander.
+ *
+ * THIS IS NO LONGER A SIGNAL HANDLER - we may now shut down gracefully
+ * NOTE: ShutMeDown will now be called automatically by exit().
+ */
+ exit(1);
+}
+
+/******************************************************************************
+ WaitForExpose - Used to wait for expose event so we don't draw too early
+******************************************************************************/
+void WaitForExpose(void)
+{
+ XEvent Event;
+
+ while(1)
+ {
+ /*
+ * Temporary solution to stop the process blocking
+ * in XNextEvent once we have been asked to quit.
+ * There is still a small race condition between
+ * checking the flag and calling the X-Server, but
+ * we can fix that ...
+ */
+ if (isTerminated)
+ {
+ /* Just exit - the installed exit-procedure will clean up */
+ exit(0);
+ }
+ /**/
+
+ XNextEvent(dpy,&Event);
+ if (Event.type==Expose)
+ {
+ if (Event.xexpose.count==0) break;
+ }
+ }
+}
+
+/******************************************************************************
+ RedrawWindow - Update the needed lines and erase any old ones
+******************************************************************************/
+void RedrawWindow(int force)
+{
+ DrawButtonArray(&buttons, force);
+ if (XQLength(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;
+
+ GetConfigLine(Fvwm_fd,&tline);
+ while(tline != (char *)0)
+ {
+ if(strlen(tline)>1)
+ {
+ if(strncasecmp(tline, CatString3(Module, "Font",""),Clength+4)==0)
+ CopyString(&font_string,&tline[Clength+4]);
+ else if(strncasecmp(tline,CatString3(Module,"Fore",""), Clength+4)==0)
+ CopyString(&ForeColor[0],&tline[Clength+4]);
+ else if(strncasecmp(tline,CatString3(Module,"IconFore",""), Clength+8)==0)
+ CopyString(&ForeColor[1],&tline[Clength+8]);
+ else if(strncasecmp(tline,CatString3(Module,"FocusFore",""), Clength+9)==0)
+ {
+ CopyString(&ForeColor[2],&tline[Clength+9]);
+ CopyString(&ForeColor[3],&tline[Clength+9]);
+ }
+ 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]);
+ else if(strncasecmp(tline,CatString3(Module,"IconBack",""), Clength+8)==0)
+ CopyString(&BackColor[1],&tline[Clength+8]);
+ else if(strncasecmp(tline,CatString3(Module,"FocusBack",""), Clength+9)==0)
+ {
+ CopyString(&BackColor[2],&tline[Clength+9]);
+ CopyString(&BackColor[3],&tline[Clength+9]);
+ }
+ else if(strncasecmp(tline,CatString3(Module, "NoAnchor",""),
+ Clength+8)==0) Anchor=0;
+ 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=1;
+ else if(strncasecmp(tline,CatString3(Module, "UseIconNames",""),
+ Clength+12)==0) UseIconNames=1;
+ else if(strncasecmp(tline,CatString3(Module, "ShowCurrentDesk",""),
+ Clength+15)==0) ShowCurrentDesk=1;
+ else if(strncasecmp(tline,CatString3(Module, "LeftJustify",""),
+ Clength+11)==0) LeftJustify=1;
+ else if(strncasecmp(tline,CatString3(Module, "TruncateLeft",""),
+ Clength+12)==0) TruncateLeft=1;
+ 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=0;
+ }
+ GetConfigLine(Fvwm_fd,&tline);
+ }
+}
+
+/******************************************************************************
+ LoopOnEvents - Process all the X events we get
+******************************************************************************/
+void LoopOnEvents(void)
+{
+ int num;
+ char buffer[10];
+ XEvent Event;
+ Window dummyroot,dummychild;
+ int x,x1,y,y1;
+ unsigned int dummy1;
+
+ if (Transient && !Checked)
+ {
+ XQueryPointer(dpy,win,&dummyroot,&dummychild,&x1,&y1,&x,&y,&dummy1);
+ num=WhichButton(&buttons,x,y);
+ if (num!=-1)
+ {
+ Pressed=1;
+ ButPressed=num;
+ SwitchButton(&buttons,num);
+ } else Pressed=0;
+ Checked=1;
+ }
+
+ while(XPending(dpy))
+ {
+ XNextEvent(dpy,&Event);
+
+ switch(Event.type)
+ {
+ case ButtonRelease:
+ if (Pressed)
+ {
+ num=WhichButton(&buttons,Event.xbutton.x,Event.xbutton.y);
+ if (num!=-1)
+ {
+ SendFvwmPipe(ClickAction[(Transient) ? 0: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:
+ if (Event.xexpose.count==0)
+ RedrawWindow(1);
+ 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;
+ }
+ }
+}
+
+
+/******************************************************************************
+ find_frame_window - looks for ancestor that is a child of the root
+ Cribbed from FvwmIconMan/x.c - maybe should be in a library
+ Returns the root-child and fills in off_x, off_y to give offset
+******************************************************************************/
+Window find_frame_window (Window win, int *off_x, int *off_y)
+{
+ Window root, parent, *junkw;
+ int junki;
+ XWindowAttributes attr;
+
+ while (1) {
+ XQueryTree (dpy, win, &root, &parent, &junkw, &junki);
+ if (junkw)
+ XFree (junkw);
+ if (parent == root)
+ break;
+ XGetWindowAttributes (dpy, win, &attr);
+ *off_x += attr.x + attr.border_width;
+ *off_y += attr.y + attr.border_width;
+ win = parent;
+ }
+
+ return win;
+}
+
+/******************************************************************************
+ AdjustWindow - Resize the window according to maxwidth by number of buttons
+******************************************************************************/
+void AdjustWindow(void)
+{
+ int new_width=0,new_height=0,tw,i,total,off_x,off_y;
+ char *temp;
+ Window frame;
+ XWindowAttributes win_attr, frame_attr;
+
+ total = ItemCountD(&windows );
+ if (!total)
+ {
+ if (WindowIsUp==1)
+ {
+ XUnmapWindow(dpy,win);
+ WindowIsUp=2;
+ }
+ return;
+ }
+ for(i=0;i<total;i++)
+ {
+ temp=ItemName(&windows,i);
+ if(temp != NULL)
+ {
+ tw=10+XTextWidth(ButtonFont,temp,strlen(temp));
+ tw+=XTextWidth(ButtonFont,"()",2);
+
+#ifdef MINI_ICONS
+ tw+=14; /* for title icon */ /* Magic Number ? */
+#endif
+
+ new_width=max(new_width,tw);
+ }
+ }
+ new_width=max(new_width, MinWidth);
+ new_width=min(new_width, MaxWidth);
+ new_height=(total*(fontheight+6+1));
+ if (WindowIsUp && (new_height!=win_height || new_width!=win_width))
+ {
+ if (Anchor)
+ {
+ off_x = off_y = 0;
+ MyXGrabServer(dpy);
+ frame = find_frame_window(win, &off_x, &off_y);
+ XGetWindowAttributes(dpy, frame, &frame_attr);
+ XGetWindowAttributes(dpy, win, &win_attr);
+ win_x = frame_attr.x + frame_attr.border_width + off_x;
+ win_y = frame_attr.y + frame_attr.border_width + off_y;
+
+ if (win_grav == SouthEastGravity || win_grav == NorthEastGravity)
+ win_x += win_attr.width - new_width;
+ if (win_grav == SouthEastGravity || win_grav == SouthWestGravity)
+ win_y += win_attr.height - new_height;
+
+ XMoveResizeWindow(dpy, win, win_x, win_y, new_width, new_height);
+ MyXUngrabServer(dpy);
+ }
+ else
+ XResizeWindow(dpy, win, new_width, new_height);
+
+ }
+ UpdateArray(&buttons,-1,-1,new_width,-1);
+ if (new_height>0) win_height = new_height;
+ if (new_width>0) win_width = new_width;
+ if (WindowIsUp==2)
+ {
+ XMapWindow(dpy,win);
+ WindowIsUp=1;
+ WaitForExpose();
+ }
+}
+
+/******************************************************************************
+ makename - Based on the flags return me '(name)' or 'name'
+******************************************************************************/
+char *makename(const char *string,long flags)
+{
+char *ptr;
+ ptr=safemalloc(strlen(string)+3);
+ *ptr = '\0';
+ if (flags&ICONIFIED) strcpy(ptr,"(");
+ strcat(ptr,string);
+ if (flags&ICONIFIED) strcat(ptr,")");
+ return ptr;
+}
+
+/******************************************************************************
+ LinkAction - Link an response to a users action
+******************************************************************************/
+void LinkAction(char *string)
+{
+char *temp;
+ temp=string;
+ while(isspace(*temp)) temp++;
+ if(strncasecmp(temp, "Click1", 6)==0)
+ CopyString(&ClickAction[0],&temp[6]);
+ else if(strncasecmp(temp, "Click2", 6)==0)
+ CopyString(&ClickAction[1],&temp[6]);
+ else if(strncasecmp(temp, "Click3", 6)==0)
+ CopyString(&ClickAction[2],&temp[6]);
+ 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;
+ XGCValues gcval;
+ unsigned long gcmask;
+ unsigned int dummy1, dummy2;
+ int x, y, ret, count;
+ Window dummyroot, dummychild;
+ int i;
+
+
+ if ((count = ItemCountD(&windows))==0 && Transient) exit(0);
+ AdjustWindow();
+
+ hints.width=win_width;
+ hints.height=win_height;
+ hints.win_gravity=NorthWestGravity;
+ hints.flags=PSize|PWinGravity|PResizeInc;
+ hints.width_inc=0;
+ hints.height_inc=0;
+
+ if (geometry!= NULL)
+ {
+ ret=XParseGeometry(geometry,&x,&y,&dummy1,&dummy2);
+
+ if (ret&XValue && ret &YValue)
+ {
+ hints.x=x;
+ if (ret&XNegative)
+ hints.x+=XDisplayWidth(dpy,screen)-win_width;
+
+ hints.y=y;
+ if (ret&YNegative)
+ hints.y+=XDisplayHeight(dpy,screen)-win_height;
+
+ hints.flags|=USPosition;
+ }
+
+ if (ret&XNegative)
+ {
+ if (ret&YNegative) hints.win_gravity=SouthEastGravity;
+ else hints.win_gravity=NorthEastGravity;
+ }
+ else
+ {
+ if (ret&YNegative) hints.win_gravity=SouthWestGravity;
+ else hints.win_gravity=NorthWestGravity;
+ }
+
+ }
+
+ if (Transient)
+ {
+ XQueryPointer(dpy,Root,&dummyroot,&dummychild,&hints.x,&hints.y,&x,&y,&dummy1);
+ hints.win_gravity=NorthWestGravity;
+ hints.flags |= USPosition;
+ }
+ win_grav=hints.win_gravity;
+ win_x=hints.x;
+ win_y=hints.y;
+
+
+ for (i = 0; i != MAX_COLOUR_SETS; i++)
+ if(d_depth < 2)
+ {
+ back[i] = GetColor("white");
+ fore[i] = GetColor("black");
+ }
+ else
+ {
+ back[i] = GetColor(BackColor[i] == NULL ? BackColor[0] : BackColor[i]);
+ fore[i] = GetColor(ForeColor[i] == NULL ? ForeColor[0] : ForeColor[i]);
+ }
+
+ win=XCreateSimpleWindow(dpy,Root,hints.x,hints.y,hints.width,hints.height,0,
+ fore[0],back[0]);
+
+ wm_del_win=XInternAtom(dpy,"WM_DELETE_WINDOW",False);
+ XSetWMProtocols(dpy,win,&wm_del_win,1);
+
+ XSetWMNormalHints(dpy,win,&hints);
+
+ 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];
+ gcval.font=ButtonFont->fid;
+ gcmask=GCForeground|GCBackground|GCFont;
+ graph[i]=XCreateGC(dpy,Root,gcmask,&gcval);
+
+ if(d_depth < 2)
+ gcval.foreground=GetShadow(fore[i]);
+ else
+ gcval.foreground=GetShadow(back[i]);
+ gcval.background=back[i];
+ gcmask=GCForeground|GCBackground;
+ shadow[i]=XCreateGC(dpy,Root,gcmask,&gcval);
+
+ gcval.foreground=GetHilite(back[i]);
+ gcval.background=back[i];
+ gcmask=GCForeground|GCBackground;
+ hilite[i]=XCreateGC(dpy,Root,gcmask,&gcval);
+
+ gcval.foreground=back[i];
+ gcmask=GCForeground;
+ background[i]=XCreateGC(dpy,Root,gcmask,&gcval);
+ }
+
+ XSelectInput(dpy,win,(ExposureMask | KeyPressMask));
+
+ ChangeWindowName(&Module[1]);
+
+ if (ItemCountD(&windows) > 0)
+ {
+ XMapRaised(dpy,win);
+ WaitForExpose();
+ WindowIsUp=1;
+ } else WindowIsUp=2;
+
+ if (Transient)
+ {
+ if ( XGrabPointer(dpy,win,True,GRAB_EVENTS,GrabModeAsync,GrabModeAsync,
+ None,None,CurrentTime)!=GrabSuccess) exit(1);
+ XQueryPointer(dpy,Root,&dummyroot,&dummychild,&hints.x,&hints.y,&x,&y,&dummy1);
+ if (!SomeButtonDown(dummy1)) exit(0);
+ }
+
+}
+
+/******************************************************************************
+ StartMeUp - Do X initialization things
+******************************************************************************/
+void StartMeUp(void)
+{
+ if (!(dpy = XOpenDisplay("")))
+ {
+ fprintf(stderr,"%s: can't open display %s", Module,
+ XDisplayName(""));
+ exit (1);
+ }
+ x_fd = XConnectionNumber(dpy);
+ screen= DefaultScreen(dpy);
+ Root = RootWindow(dpy, screen);
+ d_depth = DefaultDepth(dpy, screen);
+
+ ScreenHeight = DisplayHeight(dpy,screen);
+ ScreenWidth = DisplayWidth(dpy,screen);
+
+ if ((ButtonFont=XLoadQueryFont(dpy,font_string))==NULL)
+ {
+ if ((ButtonFont=XLoadQueryFont(dpy,"fixed"))==NULL) exit(1);
+ }
+
+ fontheight = ButtonFont->ascent+ButtonFont->descent;
+
+ win_width=XTextWidth(ButtonFont,"XXXXXXXXXXXXXXX",10);
+
+}
+
+/******************************************************************************
+ ShutMeDown - Do X client cleanup
+******************************************************************************/
+void ShutMeDown(void)
+{
+ FreeList(&windows);
+ FreeAllButtons(&buttons);
+/* XFreeGC(dpy,graph);*/
+ if (WindowIsUp) 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.decorations= value;
+ prop.functions = funcs;
+ prop.inputMode = input;
+ prop.flags = MWM_HINTS_DECORATIONS| MWM_HINTS_FUNCTIONS | MWM_HINTS_INPUT_MODE;
+
+ /* HOP - LA! */
+ XChangeProperty (dpy,win,
+ MwmAtom, MwmAtom,
+ 32, PropModeReplace,
+ (unsigned char *)&prop,
+ PROP_MWM_HINTS_ELEMENTS);
+ }
+}
+
+/************************************************************************
+ X Error Handler
+************************************************************************/
+int ErrorHandler(Display *d, XErrorEvent *event)
+{
+ char errmsg[256];
+
+ XGetErrorText(d, event->error_code, errmsg, sizeof(errmsg));
+ ConsoleMessage("%s failed request: %s\n", Module, errmsg);
+ ConsoleMessage("Major opcode: 0x%x, resource id: 0x%x\n",
+ event->request_code, (unsigned int)event->resourceid);
+ return 0;
+}
+