xenocara/app/fvwm/modules/FvwmIdent/FvwmIdent.c

832 lines
20 KiB
C
Raw Normal View History

/* 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 <nobuta-s@is.aist-nara.ac.jp>
*
* 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. */
#define TRUE 1
#define FALSE
#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>
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <unistd.h>
#include <ctype.h>
#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 "FvwmIdent.h"
char *MyName;
int fd_width;
int fd[2];
Display *dpy; /* which display are we talking to */
Window Root;
int screen;
int x_fd;
int d_depth;
int ScreenWidth, ScreenHeight;
char *BackColor = "white";
char *ForeColor = "black";
char *font_string = "fixed";
Pixel back_pix, fore_pix;
GC NormalGC;
Window main_win;
Window app_win;
XFontStruct *font;
int Width, Height,win_x,win_y;
#define MW_EVENTS (ExposureMask | ButtonReleaseMask | KeyReleaseMask)
static Atom wm_del_win;
struct target_struct target;
int found=0;
static int ListSize=0;
struct Item* itemlistRoot = NULL;
int max_col1, max_col2;
char id[15], desktop[10], swidth[10], sheight[10], borderw[10], geometry[30];
char mymin_aspect[11], max_aspect[11];
/***********************************************************************
*
* Procedure:
* main - start of module
*
***********************************************************************/
int main(int argc, char **argv)
{
char *temp, *s;
char *display_name = NULL;
int Clength;
char *tline;
/* Save the program name for error messages and config parsing */
temp = argv[0];
s=strrchr(argv[0], '/');
if (s != NULL)
temp = s + 1;
MyName = safemalloc(strlen(temp)+2);
strcpy(MyName,"*");
strcat(MyName, temp);
Clength = strlen(MyName);
if((argc != 6)&&(argc != 7))
{
fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",MyName,
VERSION);
exit(1);
}
/* Dead pipe == dead fvwm */
signal (SIGPIPE, DeadPipe);
fd[0] = atoi(argv[1]);
fd[1] = atoi(argv[2]);
/* An application window may have already been selected - look for it */
sscanf(argv[4],"%x",(unsigned int *)&app_win);
/* Open the Display */
if (!(dpy = XOpenDisplay(display_name)))
{
fprintf(stderr,"%s: can't open display %s", MyName,
XDisplayName(display_name));
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);
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);
/* scan config file for set-up parameters */
/* Colors and fonts */
GetConfigLine(fd,&tline);
while(tline != (char *)0)
{
if(strlen(tline)>1)
{
if(strncasecmp(tline, CatString3(MyName,"Font",""),Clength+4)==0)
{
CopyString(&font_string,&tline[Clength+4]);
}
else if(strncasecmp(tline,CatString3(MyName,"Fore",""),
Clength+4)==0)
{
CopyString(&ForeColor,&tline[Clength+4]);
}
else if(strncasecmp(tline,CatString3(MyName, "Back",""),
Clength+4)==0)
{
CopyString(&BackColor,&tline[Clength+4]);
}
}
GetConfigLine(fd,&tline);
}
if(app_win == 0)
GetTargetWindow(&app_win);
fd_width = GetFdWidth();
/* Create a list of all windows */
/* Request a list of all windows,
* wait for ConfigureWindow packets */
SendInfo(fd,"Send_WindowList",0);
Loop(fd);
return 0;
}
/**************************************************************************
*
* Read the entire window list from fvwm
*
*************************************************************************/
void Loop(int *fd)
{
unsigned long header[4], *body;
while(1)
{
if(ReadFvwmPacket(fd[1],header,&body) > 0)
{
process_message(header[1],body);
free(body);
}
}
}
/**************************************************************************
*
* Process window list messages
*
*************************************************************************/
void process_message(unsigned long type,unsigned long *body)
{
switch(type)
{
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;
}
}
/***********************************************************************
*
* Detected a broken pipe - time to exit
*
**********************************************************************/
void DeadPipe(int nonsense)
{
freelist();
exit(0);
}
/***********************************************************************
*
* Got window configuration info - if its our window, safe data
*
***********************************************************************/
void list_configure(unsigned long *body)
{
if((app_win == (Window)body[1])||(app_win == (Window)body[0])
||((body[19] != 0)&&(app_win == (Window)body[19]))
||((body[19] != 0)&&(app_win == (Window)body[20])))
{
app_win = body[1];
target.id = body[0];
target.frame = body[1];
target.frame_x = body[3];
target.frame_y = body[4];
target.frame_w = body[5];
target.frame_h = body[6];
target.desktop = body[7];
target.flags = body[8];
target.title_h = body[9];
target.border_w = body[10];
target.base_w = body[11];
target.base_h = body[12];
target.width_inc = body[13];
target.height_inc = body[14];
target.gravity = body[21];
found = 1;
}
}
/*************************************************************************
*
* Capture Window name info
*
************************************************************************/
void list_window_name(unsigned long *body)
{
if((app_win == (Window)body[1])||(app_win == (Window)body[0]))
{
strncpy(target.name,(char *)&body[3],255);
}
}
/*************************************************************************
*
* Capture Window Icon name info
*
************************************************************************/
void list_icon_name(unsigned long *body)
{
if((app_win == (Window)body[1])||(app_win == (Window)body[0]))
{
strncat(target.icon_name,(char *)&body[3],255);
}
}
/*************************************************************************
*
* Capture Window class name info
*
************************************************************************/
void list_class(unsigned long *body)
{
if((app_win == (Window)body[1])||(app_win == (Window)body[0]))
{
strncat(target.class,(char *)&body[3],255);
}
}
/*************************************************************************
*
* Capture Window resource info
*
************************************************************************/
void list_res_name(unsigned long *body)
{
if((app_win == (Window)body[1])||(app_win == (Window)body[0]))
{
strncat(target.res,(char *)&body[3],255);
}
}
/*************************************************************************
*
* End of window list, open an x window and display data in it
*
************************************************************************/
XSizeHints mysizehints;
void list_end(void)
{
XGCValues gcv;
unsigned long gcm;
int lmax,height;
XEvent Event;
Window JunkRoot, JunkChild;
int JunkX, JunkY;
unsigned int JunkMask;
int x,y;
if(!found)
{
/* fprintf(stderr,"%s: Couldn't find app window\n",MyName); */
exit(0);
}
close(fd[0]);
close(fd[1]);
/* load the font */
if ((font = XLoadQueryFont(dpy, font_string)) == NULL)
{
if ((font = XLoadQueryFont(dpy, "fixed")) == NULL)
exit(1);
};
/* make window infomation list */
MakeList();
/* size and create the window */
lmax = max_col1 + max_col2 + 15;
height = ListSize*(font->ascent+font->descent);
mysizehints.flags=
USSize|USPosition|PWinGravity|PResizeInc|PBaseSize|PMinSize|PMaxSize;
/* subtract one for the right/bottom border */
mysizehints.width = lmax+10;
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;
XQueryPointer( dpy, Root, &JunkRoot, &JunkChild,
&x, &y, &JunkX, &JunkY, &JunkMask);
mysizehints.win_gravity = NorthWestGravity;
if((y+height+100)>ScreenHeight)
{
y = ScreenHeight - height - 10;
mysizehints.win_gravity = SouthWestGravity;
}
if((x+lmax+100)>ScreenWidth)
{
x = ScreenWidth - lmax - 10;
if((y+height+100)>ScreenHeight)
mysizehints.win_gravity = SouthEastGravity;
else
mysizehints.win_gravity = NorthEastGravity;
}
mysizehints.x = x;
mysizehints.y = y;
if(d_depth < 2)
{
back_pix = GetColor("white");
fore_pix = GetColor("black");
}
else
{
back_pix = GetColor(BackColor);
fore_pix = GetColor(ForeColor);
}
main_win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y,
mysizehints.width,mysizehints.height,
0,fore_pix,back_pix);
XSetTransientForHint(dpy,main_win,app_win);
wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
XSetWMProtocols(dpy,main_win,&wm_del_win,1);
XSetWMNormalHints(dpy,main_win,&mysizehints);
XSelectInput(dpy,main_win,MW_EVENTS);
change_window_name(&MyName[1]);
gcm = GCForeground|GCBackground|GCFont;
gcv.foreground = fore_pix;
gcv.background = back_pix;
gcv.font = font->fid;
NormalGC = XCreateGC(dpy, Root, gcm, &gcv);
XMapWindow(dpy,main_win);
/* Window is created. Display it until the user clicks or deletes it. */
while(1)
{
XNextEvent(dpy,&Event);
switch(Event.type)
{
case Expose:
if(Event.xexpose.count == 0)
RedrawWindow();
break;
case KeyRelease:
case ButtonRelease:
freelist();
exit(0);
case ClientMessage:
if (Event.xclient.format==32 && Event.xclient.data.l[0]==wm_del_win)
{
freelist();
exit(0);
}
default:
break;
}
}
}
/**********************************************************************
*
* If no application window was indicated on the command line, prompt
* the user to select one
*
*********************************************************************/
void GetTargetWindow(Window *app_win)
{
XEvent eventp;
int val = -10,trials;
trials = 0;
while((trials <100)&&(val != GrabSuccess))
{
val=XGrabPointer(dpy, Root, True,
ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, Root,
XCreateFontCursor(dpy,XC_crosshair),
CurrentTime);
if(val != GrabSuccess)
{
usleep(1000);
}
trials++;
}
if(val != GrabSuccess)
{
fprintf(stderr,"%s: Couldn't grab the cursor!\n",MyName);
exit(1);
}
XMaskEvent(dpy, ButtonReleaseMask,&eventp);
XUngrabPointer(dpy,CurrentTime);
XSync(dpy,0);
*app_win = eventp.xany.window;
if(eventp.xbutton.subwindow != None)
*app_win = eventp.xbutton.subwindow;
}
/************************************************************************
*
* Draw the window
*
***********************************************************************/
void RedrawWindow(void)
{
int fontheight,i=0;
struct Item *cur = itemlistRoot;
fontheight = font->ascent + font->descent;
while(cur != NULL)
{
/* first column */
XDrawString(dpy,main_win,NormalGC,5,5+font->ascent+i*fontheight,
cur->col1,strlen(cur->col1));
/* second column */
XDrawString(dpy,main_win,NormalGC,10+max_col1,5+font->ascent+i*fontheight,
cur->col2,strlen(cur->col2));
++i;
cur = cur->next;
}
}
/**************************************************************************
* Change the window name displayed in the title bar.
**************************************************************************/
void change_window_name(char *str)
{
XTextProperty name;
if (XStringListToTextProperty(&str,1,&name) == 0)
{
fprintf(stderr,"%s: cannot allocate window name",MyName);
return;
}
XSetWMName(dpy,main_win,&name);
XSetWMIconName(dpy,main_win,&name);
XFree(name.value);
}
/**************************************************************************
*
* 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 = XTextWidth(font, s1, strlen(s1));
tw2 = XTextWidth(font, 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];
ListSize = 0;
bw = 2*target.border_w;
width = target.frame_w - bw;
height = target.frame_h - target.title_h - bw;
sprintf(desktop, "%ld", target.desktop);
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("Width:", swidth);
AddToList("Height:", sheight);
AddToList("X (current page):", xstr);
AddToList("Y (current page):", ystr);
AddToList("Boundary Width:", borderw);
AddToList("Sticky:", (target.flags & STICKY ? YES : NO));
AddToList("Ontop:", (target.flags & ONTOP ? YES : NO));
AddToList("NoTitle:", (target.flags & TITLE ? NO : YES));
AddToList("Iconified:", (target.flags & ICONIFIED ? YES : NO));
AddToList("Transient:", (target.flags & TRANSIENT ? 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 = ScreenWidth - x1 - target.frame_w;
if(x2 < 0)
x2 = 0;
y1 = target.frame_y;
if(y1 < 0)
y1 = 0;
y2 = ScreenHeight - 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);
#if 0
{
char tmp[20], *foo;
sprintf(tmp,"%d", target.base_w);
foo = strdup(tmp);
AddToList(" - base_w:", foo);
sprintf(tmp,"%d", target.width_inc);
foo = strdup(tmp);
AddToList(" - width_inc:", foo);
sprintf(tmp,"%d", target.base_h);
foo = strdup(tmp);
AddToList(" - base_h:", foo);
sprintf(tmp,"%d", target.height_inc);
foo = strdup(tmp);
AddToList(" - height_inc:", foo);
}
#endif
{
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);
{
long supplied_return; /* flags, hints that were supplied */
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 */
}
}
}
void freelist(void)
{
struct Item* cur = itemlistRoot, *cur2;
while(cur != NULL)
{
cur2 = cur;
cur = cur->next;
free(cur2);
}
}
void nocolor(char *a, char *b)
{
fprintf(stderr,"FvwmInitBanner: can't %s %s\n", a,b);
}
/****************************************************************************
*
* Loads a single color
*
****************************************************************************/
Pixel GetColor(char *name)
{
XColor color;
XWindowAttributes attributes;
XGetWindowAttributes(dpy,Root,&attributes);
color.pixel = 0;
if (!XParseColor (dpy, attributes.colormap, name, &color))
{
nocolor("parse",name);
}
else if(!XAllocColor (dpy, attributes.colormap, &color))
{
nocolor("alloc",name);
}
return color.pixel;
}