xenocara/app/fvwm/modules/FvwmTalk/FvwmTalk.c

482 lines
11 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
*
* Copyright 1994, Robert Nation. 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 UPDATE_ONLY 1
#define ALL 2
#define PROP_SIZE 1024
#include "config.h"
#ifdef HAVE_SYS_BSDTYPES_H
#include <sys/bsdtypes.h> /* Saul */
#endif
#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/keysym.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include "../../fvwm/module.h"
#include "FvwmTalk.h"
char *MyName;
int fd_width,screen, d_depth;
int fd[2];
int x_fd;
Window Root;
Display *dpy;
/* char *font_string = "helvetica"; */
char *font_string = "fixed";
char *ForeColor = "green";
char *BackColor = "black";
char *display_name = NULL;
XFontStruct *font;
Pixel fore_pix,back_pix;
static Atom wm_del_win;
unsigned long valuemask;
XSetWindowAttributes attributes;
XWMHints wmhints;
Window window;
char last_error[256],previous_line[256];
char Text[256];
int pos = 0;
XSizeHints sizehints =
{
(PMinSize | PResizeInc | PBaseSize | PWinGravity | PMaxSize),
0, 0, 100, 100, /* x, y, width and height */
1, 1, /* Min width and height */
0, 0, /* Max width and height */
1, 1, /* Width and height increments */
{0, 0}, {0, 0}, /* Aspect ratio - not used */
1, 1, /* base size */
(NorthWestGravity) /* gravity */
};
Pixel GetColor(char *name);
void nocolor(char *a, char *b);
XGCValues gcv;
GC myGC;
int My_XNextEvent(Display *dpy, XEvent *event);
void DrawWindow(int mode);
void paste_primary(int window,int property,int Delete);
void request_selection(int time);
/***********************************************************************
*
* Procedure:
* main - start of module
*
***********************************************************************/
int main(int argc, char **argv)
{
char *temp, *s;
XWMHints wm_hints;
XClassHint class_hints;
XTextProperty window_name;
/* Save the program name - its used for error messages and option parsing */
temp = argv[0];
s=strrchr(argv[0], '/');
if (s != NULL)
temp = s + 1;
MyName = safemalloc(strlen(temp)+2);
strcpy(MyName,"*");
strcat(MyName, temp);
if((argc != 6)&&(argc != 7))
{
fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",MyName,
VERSION);
exit(1);
}
/* Dead pipes mean fvwm died */
signal (SIGPIPE, DeadPipe);
fd[0] = atoi(argv[1]);
fd[1] = atoi(argv[2]);
/* Initialize X connection */
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);
if(Root == None)
{
fprintf(stderr,"%s: Screen %d is not valid ", MyName, (int)screen);
exit(1);
}
d_depth = DefaultDepth(dpy, screen);
fd_width = GetFdWidth();
wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
/* load the font */
if ((font = XLoadQueryFont(dpy, font_string)) == NULL)
{
if ((font = XLoadQueryFont(dpy, "fixed")) == NULL)
{
fprintf(stderr,"%s: No fonts available\n",MyName);
exit(1);
}
};
fore_pix = GetColor(ForeColor);
back_pix = GetColor(BackColor);
valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
attributes.background_pixel = back_pix;
attributes.border_pixel = fore_pix;
attributes.event_mask = KeyPressMask | ExposureMask | ButtonPressMask;
sizehints.width = 8*XTextWidth(font,"MMMMMMMMMM",10);
sizehints.height = 3*(font->ascent+font->descent+2)+2;
sizehints.x = 0;
sizehints.y = 0;
sizehints.width_inc = 0.1*XTextWidth(font,"MMMMMMMMMM",10);
sizehints.height_inc = 3*(font->ascent+font->descent+2)+2;
sizehints.base_width = 1;
sizehints.base_height = 3*(font->ascent+font->descent+2)+2;
sizehints.min_width = 1;
sizehints.min_height = 3*(font->ascent+font->descent+2)+2;
sizehints.max_height = 3*(font->ascent+font->descent+2)+2;
sizehints.max_width = 26*XTextWidth(font,"MMMMMMMMMM",10);
window = XCreateWindow (dpy, Root, 0, 0, sizehints.width,sizehints.height,
(unsigned int) 1,
CopyFromParent, InputOutput,
(Visual *) CopyFromParent,
valuemask, &attributes);
class_hints.res_name = "FvwmTalk";
class_hints.res_class = "FvwmTalk";
wm_hints.flags = InputHint;
wm_hints.input = True;;
XSetWMProtocols(dpy,window,&wm_del_win,1);
XSetWMNormalHints(dpy,window,&sizehints);
/* XStringListToTextProperty(&(argv[0]), 1, &window_name); */
XStringListToTextProperty(&temp, 1, &window_name);
XSetWMProperties(dpy, window, &window_name, &window_name,
argv, argc, &sizehints, &wm_hints, &class_hints);
gcv.foreground = fore_pix;
gcv.background = back_pix;
gcv.font = font->fid;
myGC = XCreateGC(dpy,window,GCForeground|GCBackground|GCFont,&gcv);
previous_line[0] = 0;
last_error[0] = 0;
XMapWindow(dpy,window);
Loop(fd);
return 0;
}
/***********************************************************************
*
* Procedure:
* Loop - wait for data to process
*
***********************************************************************/
void Loop(int *fd)
{
KeySym keysym;
static XComposeStatus compose = {NULL,0};
XEvent event;
char kbuf[100];
int count;
pos = 0;
Text[0] = 0;
while(1)
{
if(My_XNextEvent(dpy, &event))
{
switch(event.type)
{
case KeyPress:
count = XLookupString(&(event.xkey),kbuf,99,&keysym,&compose);
kbuf[count] = (unsigned char)0;
if((keysym == XK_BackSpace )||(keysym == XK_Delete))
{
if(pos > 0)
Text[--pos] = 0;
}
else if((keysym == XK_Return)||(keysym == XK_KP_Enter))
{
SendText(fd,Text,0);
last_error[0] = 0;
strncpy(previous_line,Text,255);
previous_line[255] = 0;
pos = 0;
Text[pos] = 0;
DrawWindow(ALL);
}
else
{
if(pos + count < 255)
{
strcat(Text,kbuf);
pos += count;
}
else
XBell(dpy,0);
}
DrawWindow(UPDATE_ONLY);
break;
case ButtonPress:
if(event.xbutton.button == 2)
request_selection(event.xbutton.time);
break;
case Expose:
DrawWindow(ALL);
break;
case ClientMessage:
if ((event.xclient.format==32) &&
(event.xclient.data.l[0]==wm_del_win))
{
exit(0);
}
break;
case SelectionNotify:
paste_primary(event.xselection.requestor,
event.xselection.property,True);
default:
break;
}
}
}
}
/***********************************************************************
*
* Procedure:
* SIGPIPE handler - SIGPIPE means fvwm is dying
*
***********************************************************************/
void DeadPipe(int nonsense)
{
fprintf(stderr,"FvwmTalk: dead pipe\n");
exit(0);
}
/****************************************************************************
*
* 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;
}
void nocolor(char *a, char *b)
{
fprintf(stderr,"%s: can't %s %s\n", MyName, a,b);
}
/***************************************************************************
*
* Waits for next X event, or for an auto-raise timeout.
*
****************************************************************************/
int My_XNextEvent(Display *dpy, XEvent *event)
{
fd_set in_fdset;
unsigned long header[HEADER_SIZE];
int count;
static int miss_counter = 0;
unsigned long *body;
if(XPending(dpy))
{
XNextEvent(dpy,event);
return 1;
}
FD_ZERO(&in_fdset);
FD_SET(x_fd,&in_fdset);
FD_SET(fd[1],&in_fdset);
select(fd_width,SELECT_TYPE_ARG234 &in_fdset, 0, 0, NULL);
if(FD_ISSET(x_fd, &in_fdset))
{
if(XPending(dpy))
{
XNextEvent(dpy,event);
miss_counter = 0;
return 1;
}
else
miss_counter++;
if(miss_counter > 100)
DeadPipe(0);
}
if(FD_ISSET(fd[1], &in_fdset))
{
if((count = ReadFvwmPacket(fd[1],header,&body)) > 0)
{
if(header[1] == M_ERROR || header[1] == M_STRING)
{
strncpy(last_error,(char *)(&body[3]),255);
/*last_error[strlen(last_error)-1] = 0;*/
last_error[strlen(last_error)] = 0;
last_error[255] = 0;
XClearArea(dpy,window,0,0,10000,10000,1);
}
free(body);
}
}
return 0;
}
void request_selection(int time)
{
Atom sel_property;
if (XGetSelectionOwner(dpy,XA_PRIMARY) == None)
{
/* No primary selection so use the cut buffer.
*/
paste_primary(DefaultRootWindow(dpy),XA_CUT_BUFFER0,False);
return;
}
sel_property = XInternAtom(dpy,"VT_SELECTION",False);
XConvertSelection(dpy,XA_PRIMARY,XA_STRING,sel_property,window,time);
}
void paste_primary(int window,int property,int Delete)
{
Atom actual_type;
int actual_format,i;
unsigned long nitems, bytes_after, nread;
unsigned char *data, *data2;
if (property == None)
return;
nread = 0;
do
{
if (XGetWindowProperty(dpy,window,property,nread/4,PROP_SIZE,Delete,
AnyPropertyType,&actual_type,&actual_format,
&nitems,&bytes_after,(unsigned char **)&data)
!= Success)
return;
if (actual_type != XA_STRING)
return;
data2 = data;
/* want to make a \n to \r mapping for cut and paste only */
for(i=0;i<nitems;i++)
{
if(*data == '\n')
*data = '\r';
data++;
}
if(255-pos > 0)
{
strncat(Text,(char *)data2,255-pos-nitems);
pos = strlen(Text);
DrawWindow(UPDATE_ONLY);
}
nread += nitems;
XFree(data2);
} while (bytes_after > 0);
}
void DrawWindow(int mode)
{
int w;
if(mode == ALL)
{
XClearWindow(dpy,window);
XDrawImageString(dpy,window,myGC,2,(font->ascent+font->descent+2)+
font->ascent+2,last_error,strlen(last_error));
XDrawImageString(dpy,window,myGC,2, font->ascent+2,
previous_line,strlen(previous_line));
}
else
{
XClearArea(dpy,window,0,
2*(font->ascent+font->descent+2),10000,10000,0);
}
XDrawImageString(dpy,window,myGC,2,2*(font->ascent+font->descent+2)+
font->ascent+2,Text,pos);
w=XTextWidth(font,Text,pos);
XDrawLine(dpy,window,myGC,4+w,2*(font->ascent+font->descent+2)+2,
4+w,2*(font->ascent+font->descent+2)+
font->ascent+font->descent);
}