[bglug] Chi riesce a compilarlo?
k|b|s
kbs@bglug.it
Ven 27 Feb 2004 16:11:32 CET
A chi riesce a compilarlo staticamente birra pagata ;^)
--8<-- CUT HERE --8<--
/* slrnface - feeble attempt at delivering X-Faces to slrn and mutt users
* Copyright (C) 2000, 2001, 2002 Drazen Kacar
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#ifdef __linux
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termio.h>
#else
#include <termios.h>
#endif
#define countof(x) (sizeof(x)/sizeof(x[0]))
extern void uncompface (char *);
extern int errno;
/*
* The values in optvalues[] array are just fallbacks if appropriate
* X resources are not found. You can set them here if you like, but
* you should really use X resources for that. Command line parameters
* should also work.
*/
typedef enum {
val_int,
val_color
} OptionType;
struct optval {
OptionType type;
union {
unsigned long intval;
char *string;
} value;
};
struct optval optvalues[] = {
{ val_int, { 0 }},
{ val_int, { 1 }},
{ val_int, { 0 }},
{ val_int, { 2 }},
{ val_int, { 0 }},
{ val_color, { 0 }},
{ val_color, { 0 }},
{ val_color, { 0 }}
};
#define X_OFFSET_CHAR (optvalues[0].value.intval)
#define Y_OFFSET_CHAR (optvalues[1].value.intval)
#define X_OFFSET_PIX (optvalues[2].value.intval)
#define Y_OFFSET_PIX (optvalues[3].value.intval)
#define XFACE_PAD (optvalues[4].value.intval)
/* Very unconsistent */
#define INK (optvalues[5])
#define PAPER (optvalues[6])
#define PADCOLOR (optvalues[7])
XrmOptionDescRec my_options[] = {
{ "-xOffsetChar", "*slrnface.xOffsetChar", XrmoptionSepArg, NULL },
{ "-yOffsetChar", "*slrnface.yOffsetChar", XrmoptionSepArg, NULL },
{ "-xOffsetPix", "*slrnface.xOffsetPix", XrmoptionSepArg, NULL },
{ "-yOffsetPix", "*slrnface.yOffsetPix", XrmoptionSepArg, NULL },
{ "-XFacePad", "*slrnface.XFacePad", XrmoptionSepArg, NULL },
{ "-ink", "*slrnface.ink", XrmoptionSepArg, NULL },
{ "-paper", "*slrnface.paper", XrmoptionSepArg, NULL },
{ "-padColor", "*slrnface.padColor", XrmoptionSepArg, NULL }
};
/*
* MAXRESOURCESIZE should be the size of the longest resource string in the
* above array. It can be a bit larger, of course. If you're adding
* resources, make sure it's not smaller. Wouldn't it be nice if preprocessor
* was able to calculate that?
*/
#define MAXRESOURCESIZE 30
Display *d = NULL;
Window win = 0, winid; /* win is X-Face window, winid is the parent */
int winchild;
Cursor cursor_move;
int x_pos, y_pos; /* X-Face window position */
Colormap cmap;
GC gc;
XGCValues gcvals;
unsigned long gcmask;
unsigned long pad_color;
Pixmap bitmap = 0;
int fifo_fd, term_fd;
struct winsize winsz;
int is_mapped = 0; /* Whether X-Face window is mapped */
int buffered_face_len = -1; /* Length of last X-Face data */
int pixmap_stale = 1; /* If set, X-Face data in the buffer doesn't
match pixmap, ie. pixmap needs to be
regenerated. */
int face_cleared = 1; /* If set, the last command told us to clear
X-Face. We'll still keep the pixmap
and the buffer data (if we had any), just
in case the next X-Face will be the same,
but this means we'll not show X-Face
until we get a command with the new
X-Face data. */
char last_face[8000]; /* Buffer for X-Face data. We keep the last
one here for comparison. If the new X-Face
turns out to be the same as the previous
one, we can save some round trips. */
struct pollfd fifo_pollfd;
/*
* Flags for signals. We can't use bits in the same variable because bit
* operations are not atomic.
*/
volatile sig_atomic_t got_sigterm = 0, got_sigstop = 0, got_sigcont = 0;
volatile sig_atomic_t got_sigwinch = 0;
/* Signal handlers */
/* ARGSUSED */
void
handle_sigterm (int sig)
{
got_sigterm = 1;
}
/* ARGSUSED */
void
handle_sigstop (int sig)
{
got_sigstop = 1;
}
/* ARGSUSED */
void
handle_sigcont (int sig)
{
got_sigcont = 1;
}
/* ARGSUSED */
void
handle_sigwinch (int sig)
{
got_sigwinch = 1;
}
void
cleanup (void)
{
if (d)
{
if (bitmap)
XFreePixmap (d, bitmap);
if (win)
{
XFreeCursor (d, cursor_move);
XDestroyWindow (d, win);
}
XCloseDisplay (d);
}
}
void
suspend_me (void)
{
if (is_mapped)
{
XUnmapWindow (d, win);
XFlush (d);
}
got_sigstop = 0;
/*
* And we'll proceed to sleep in poll(). In case we get a command through
* the FIFO we'll process it, so something might show up on the screen.
* I'm not sure if this is a bug or a feature. :-)
*/
}
void
restart_me (void)
{
if (is_mapped)
{
XMapWindow (d, win);
XFlush (d);
}
got_sigcont = 0;
}
/*
* We don't know if we got top level window id or an id for a child
* window. A child window typically won't have WM_CLASS set, so we need
* to traverse up the window hierarchy until we find a window with that
* property.
*
* Input: w - window id where the search starts
* hint - pointer to XClassHint structure
* Output: 0 - WM_CLASS not found
* 1 - WM_CLASS found on window w
* 2 - WM_CLASS found on one of w's parents
*
* If WM_CLASS was found, it's stored in h.
*/
int
get_class_hint (Window w, XClassHint *hint)
{
Window root, parent, *children;
unsigned int nchld;
int childwin = 0;
do {
if (XGetClassHint (d, w, hint))
return childwin + 1;
if (!XQueryTree (d, w, &root, &parent, &children, &nchld))
return 0;
if (children)
XFree (children);
childwin = 1;
w = parent;
} while (parent != root);
return 0;
}
/*
* Calculate the position at which X-Face window should be placed.
*
* Input: global variables X_OFFSET_CHAR, X_OFFSET_PIX, Y_OFFSET_CHAR,
* Y_OFFSET_PIX and XFACE_PAD
* Output: global variables x_pos and y_pos
* Uses: global struct winsz and variables winid and winchild
*/
void
get_face_position (void)
{
/*
* The problem with terminals is that they might have scrollbars on
* the unknown side. But if we detected WM_CLASS on a parent window,
* we can reasonably assume that our window id is just the text window
* and nothing else.
*/
if (!winsz.ws_xpixel || !winsz.ws_ypixel) /* Bastards... */
{
Window root_return;
int x_return, y_return;
unsigned width_return, height_return;
unsigned border_width_return;
unsigned depth_return;
XGetGeometry (d, winid, &root_return, &x_return, &y_return,
&width_return, &height_return, &border_width_return,
&depth_return);
if (winchild > 1)
x_pos = width_return - X_OFFSET_CHAR * (width_return / winsz.ws_col)
- X_OFFSET_PIX;
else
{
/*
* First try to substract scrollbar and hope the rest are
* just characters on the screen.
*/
width_return -= X_OFFSET_PIX;
x_pos = width_return - X_OFFSET_CHAR * (width_return / winsz.ws_col);
}
y_pos = Y_OFFSET_CHAR * (height_return / winsz.ws_row) + Y_OFFSET_PIX;
}
else
{
x_pos = winsz.ws_xpixel - X_OFFSET_CHAR * (winsz.ws_xpixel / winsz.ws_col)
- X_OFFSET_PIX;
y_pos = Y_OFFSET_CHAR * (winsz.ws_ypixel / winsz.ws_row) + Y_OFFSET_PIX;
}
x_pos -= 48 + XFACE_PAD; /* X-Face window width. */
}
/*
* We need to allocate black and white colors instead of using
* BlackPixelOfScreen and WhitePixelOfScreen macros because we'll want to
* deallocate them in case we get a command to change one of the colors.
* Using macros and trying to deallocate would result in BadAccess.
*/
unsigned long
alloc_named_color (char *name)
{
XColor col;
if (XParseColor (d, cmap, name, &col) && XAllocColor (d, cmap, &col))
return col.pixel;
/*
* XXX This isn't kosher in the general case, but we're currently
* using this only for black & white, so it's not going to fail.
*/
return 0;
}
void
parse_resource(int idx, char *resource)
{
if (optvalues[idx].type == val_int)
optvalues[idx].value.intval = strtol (resource, NULL, 0);
else /* val_color */
{
XColor col;
if (XParseColor (d, cmap, resource, &col)
&& XAllocColor (d, cmap, &col))
{
optvalues[idx].value.intval = col.pixel;
/*
* Change type to val_int, so we know the value is set here.
*/
optvalues[idx].type = val_int;
}
}
}
void
force_cmd_line (int argc, char **argv)
{
int i, j;
for (i = 1; i < argc; ++i)
{
if (*argv[i] != '-')
continue;
for (j = 0; j < countof(my_options); ++j)
if (!strcmp (argv[i], my_options[j].option))
{
if (argv[i + 1])
{
parse_resource (j, argv[i + 1]);
i++;
}
break;
}
}
}
void
setup (int *argc, char **argv)
{
int i, free_fifo = 0, status;
char *winenv, *fifo_file, *home;
XWindowAttributes winattrs;
XSetWindowAttributes winsetattrs;
unsigned long winmask;
struct stat inode;
XClassHint terminal;
/* See if we can connect to the display */
if (!(d = XOpenDisplay (NULL)))
exit (1);
/* Then close because we'll fork. We'll reopen it in the child. Hopefully
it won't run away. */
XCloseDisplay (d);
/* Terminal Window ID. We must have this. */
if (!(winenv = getenv ("WINDOWID")) || !(winid = strtol (winenv, NULL, 0)))
exit (2);
/* Stupid method for determining controlling terminal. It should be
one of those. But it doesn't have to. FIXME */
for (i = 0; i < 3; ++i)
if (isatty (term_fd = i))
break;
if (i == 3)
exit (3);
ioctl (term_fd, TIOCGWINSZ, &winsz);
/* We could work without this, but we're just picky. */
if (!winsz.ws_row || !winsz.ws_col)
exit (4);
/* See if we got FIFO name as the argument. */
fifo_file = NULL;
for (i = 1; i < *argc && argv[i]; i += 2)
{
if (*argv[i] != '-')
{
fifo_file = argv[i];
break;
}
}
if (!fifo_file)
{
/* FIFO not in argument; construct the name */
struct utsname u;
size_t maxlen;
if (!(home = getenv ("HOME")))
{
struct passwd *pw;
pw = getpwuid (geteuid ());
if (!pw || !(home = pw->pw_dir))
exit (5);
}
if (uname (&u) < 0)
exit (5);
maxlen = strlen (home) + sizeof ("/.slrnfaces/") + strlen (u.nodename)
+ 30;
fifo_file = malloc (maxlen);
if (!fifo_file)
exit (5);
free_fifo = 1;
if (snprintf(fifo_file, maxlen, "%s/.slrnfaces/%s.%ld", home,
u.nodename, (long) getppid ()) < 0)
exit (5);
}
/*
* The FIFO should have been created by the parent. If it doesn't exist
* we'll create it here, but it's a bad omen. If the file exists, but
* is not a FIFO, we need to return an error now, because we won't have
* the chance later. Parent could block waiting for us or waiting on a
* FIFO without a reader. We can't allow that. This whole show would have
* been unnecessary if slang could open a pipe. A simple, unnamed,
* unidirectional pipe. Is that too much to ask?
*/
/* Open non-blocking FIFO now and remove that flag after the fork. */
if (stat (fifo_file, &inode))
if (errno == ENOENT)
{
if (mkfifo (fifo_file, 0600))
exit (5);
}
else
exit (5);
else
if (!S_ISFIFO (inode.st_mode))
exit (5);
if ((fifo_fd = open (fifo_file, O_RDONLY | O_NONBLOCK)) < 0)
exit (5);
if (free_fifo)
free (fifo_file);
switch (fork ())
{
case -1: exit (6);
case 0: break; /* Child. Just continue. */
default: exit (0); /* Parent. Return success and make its parent happy. */
}
fcntl (fifo_fd, F_SETFL, 0);
/*
* Fill this here. The structure will be used for the normal processing
* as well, which is why it's a global thing.
*/
fifo_pollfd.fd = fifo_fd;
fifo_pollfd.events = POLLIN;
/* Sync with the parent. */
do {
status = poll (&fifo_pollfd, 1, -1);
} while (status == -1 && errno == EINTR);
if (!(d = XOpenDisplay (NULL)))
exit (1);
/* Get colormap, preferably the one used by the parent terminal window. */
if (XGetWindowAttributes (d, winid, &winattrs) == Success)
cmap = winattrs.colormap;
else
cmap = DefaultColormap (d, DefaultScreen (d));
/* X Resources stuff. Suggested by a user's demented mind. */
winchild = get_class_hint (winid, &terminal);
if (winchild)
{
/*
* It seems there's a lot of idiots who are putting dots in the name
* property. Examples are gnome-terminal and Eterm. If you run into
* this problem, quote them Xlib manual for me:
Note that the name set in this property may differ from the name
set as WM_NAME. That is, WM_NAME specifies what should be
displayed in the title bar and, therefore, can contain temporal
information (for example, the name of a file currently in an
editor's buffer). On the other hand, the name specified as part
of WM_CLASS is the formal name of the application that should be
used when retrieving the application's resources from the
resource database.
* We'll try to work around the brain damage by parsing command
* line parameters directly, so at least that will work.
*/
if (strpbrk (terminal.res_name, ".*?")
|| strpbrk (terminal.res_class, ".*?"))
{
force_cmd_line (*argc, argv);
}
else
{
XtAppContext app_context;
XrmDatabase res;
size_t name_len, class_len;
int i;
char *name_str, *class_str;
char *name_start, *class_start;
char *type_str;
XrmValue value;
XtToolkitInitialize ();
app_context = XtCreateApplicationContext ();
XtDisplayInitialize (app_context, d, terminal.res_name,
terminal.res_class, my_options,
countof (my_options), argc, argv);
res = XtScreenDatabase (DefaultScreenOfDisplay (d));
name_len = strlen (terminal.res_name);
name_str = malloc (name_len + MAXRESOURCESIZE);
memcpy (name_str, terminal.res_name, name_len);
name_str[name_len] = '.';
name_start = name_str + name_len + 1;
class_len = strlen (terminal.res_class);
class_str = malloc (class_len + MAXRESOURCESIZE);
memcpy (class_str, terminal.res_class, class_len);
class_str[class_len] = '.';
class_start = class_str + class_len + 1;
for (i = 0; i < countof (my_options); ++i)
{
strcpy (name_start, my_options[i].specifier + 1);
strcpy (class_start, my_options[i].specifier + 1);
if(XrmGetResource(res, name_str, class_str, &type_str,
&value) == True)
{
/* We don't have generic strings yet, so this will do. */
char *resource = malloc (value.size + 1);
memcpy (resource, value.addr, value.size);
resource[value.size] = 0;
parse_resource (i, resource);
free (resource);
}
}
free (name_str);
free (class_str);
XrmDestroyDatabase (res);
}
XFree (terminal.res_name);
XFree (terminal.res_class);
}
else
force_cmd_line (*argc, argv);
/* Calculate X-Face window position. */
get_face_position ();
/* Set up background color and create our window. */
if (PADCOLOR.type == val_color)
pad_color = alloc_named_color ("black");
else
pad_color = PADCOLOR.value.intval;
winsetattrs.background_pixel = pad_color;
winsetattrs.win_gravity = NorthEastGravity;
winsetattrs.colormap = cmap;
winmask = CWBackPixel | CWWinGravity | CWColormap;
win = XCreateWindow (d, winid, x_pos, y_pos, 48 + XFACE_PAD, 48,
0, CopyFromParent, CopyFromParent, CopyFromParent,
winmask, &winsetattrs);
/* Then set up colors in the GC. */
if (INK.type == val_color)
gcvals.foreground = alloc_named_color ("black");
else
gcvals.foreground = INK.value.intval;
if (PAPER.type == val_color)
gcvals.background = alloc_named_color ("white");
else
gcvals.background = PAPER.value.intval;
gcvals.graphics_exposures = False;
gcmask = GCForeground | GCBackground | GCGraphicsExposures;
gc = XCreateGC(d, win, gcmask, &gcvals);
/* And the last piece of crap. */
cursor_move = XCreateFontCursor (d, XC_fleur);
XGrabButton (d, Button1, AnyModifier, win, False,
ButtonPressMask | ButtonReleaseMask | Button1MotionMask,
GrabModeSync, GrabModeAsync, win, cursor_move);
XSelectInput (d, win, ExposureMask | StructureNotifyMask);
/* We are done. Amazing. */
}
#define MAXCOLORLEN 40
unsigned long
chk_alloc_color (char *color, unsigned long pixel, unsigned long *pixel_return)
{
char *p, *s, clr[MAXCOLORLEN];
XColor col;
p = color;
while (*p != '\n' && isspace (*(unsigned char *)p))
++p;
if (*p == '\n')
return 0;
for (s = clr; !isspace (*(unsigned char *)p) && s < clr + MAXCOLORLEN;
++p, ++s)
*s = *p;
if (s == clr + MAXCOLORLEN)
return 0;
*s = 0;
if (!XParseColor (d, cmap, clr, &col) || !XAllocColor (d, cmap, &col))
return 0;
XFreeColors (d, cmap, &pixel, 1, 0);
if (col.pixel == pixel)
return 0;
*pixel_return = col.pixel;
return 1;
}
int
chk_get_naturalnum (char *buf)
{
long num;
char *endptr;
errno = 0;
num = strtol (buf, &endptr, 0);
if (!errno && num >= 0 && *endptr == '\n' && num < INT_MAX)
return num;
else
return -1;
}
typedef enum {
xface_eof, /* EOF or error on FIFO */
xface_noop, /* Do nothing */
xface_flush, /* Flush the display */
xface_unmap, /* Unmap window */
xface_map, /* Map window */
xface_display /* Map window and paint X-Face */
} XFaceState;
/* Read data from FIFO and return state. Reimplementing stdio is always fun. */
XFaceState
read_fifo (void)
{
int n, status, refresh_gc = 0, refresh_pad = 0, reposition_face = 0;
size_t toread;
int state, skip_junk = 0;
char *command, *bufstart, *bufend, *bufp;
int xoffsetchar = -1, yoffsetchar = -1, xoffsetpix = -1, yoffsetpix = -1;
char buf[8000];
do {
begin:
toread = sizeof (buf);
bufstart = command = buf;
readmore:
do {
n = read (fifo_fd, bufstart, toread);
} while (n < 0 && errno == EINTR);
if (n <= 0)
return xface_eof;
bufend = bufstart + n;
bufp = bufstart;
state = xface_noop;
while (bufp < bufend)
{
/* Find the end of the command. */
while (bufp < bufend && *bufp != '\n')
++bufp;
if (*bufp != '\n')
{
/* Partial command in the buffer. Try to read some more. */
toread = sizeof(buf) - (bufend - buf);
if (toread)
{
bufstart = bufend;
goto readmore;
}
if (command == buf)
{
/*
* The command doesn't fit in the buffer. It must be
* some junk, so discard it and resync on newline.
*/
skip_junk = 1;
goto begin;
}
/*
* Copy what we have to the beginning of the buffer and read
* some more.
*/
memmove (buf, command, bufend - command);
bufstart = buf + (bufend - command);
toread = sizeof (buf) - (bufend - command) + 1;
goto readmore;
}
/*
* See if we were supposed to skip the junk. This can happen
* only with the first chunk in the buffer.
*/
if (skip_junk)
{
skip_junk = 0;
if (bufend == bufp + 1)
goto begin;
/* The next command needs our attention. */
command = ++bufp;
continue;
}
if (!memcmp (command, "clear\n", sizeof "clear"))
{
state = xface_unmap;
face_cleared = 1;
}
else if (!memcmp (command, "suppress\n", sizeof "suppress"))
state = xface_unmap;
else if (!memcmp (command, "show\n", sizeof "show"))
{
if (!face_cleared)
if (pixmap_stale)
state = xface_display;
else
state = xface_map;
}
else if (!memcmp (command, "xface ", sizeof "xface"))
{
int face_len;
char *face_start;
face_start = command + sizeof "xface";
face_len = bufp - face_start;
/*
* We need to do all sanity checking here because of supress
* command. Our caller cannot afford to ignore certain kinds
* of data because it wouldn't know what the previous good
* data was.
*
* We are ignoring X-Faces longer than 2000 bytes because
* uncompface() uses the same buffer for input and output and
* it's concievable that this might lead to buffer overruns,
* since there's no way to pass the buffer size to it.
*
* TODO: mmap a chunk of memory somewhere, make sure there is
* a gap above it, catch SIGSEGV temporarily and do uncompressing
* there. It's the only safe way.
*/
if (face_len <= 2000)
{
if (face_len == buffered_face_len
&& !memcmp (face_start, last_face, face_len))
if (pixmap_stale)
state = xface_display;
else
state = xface_map;
else
{
memcpy (last_face, face_start, face_len);
pixmap_stale = 1;
buffered_face_len = face_len;
state = xface_display;
}
face_cleared = 0;
}
}
else if (!memcmp (command, "ink ", sizeof "ink"))
{
unsigned long pixel;
if (chk_alloc_color (command + sizeof "ink", gcvals.foreground,
&pixel))
{
gcvals.foreground = pixel;
refresh_gc = 1;
}
}
else if (!memcmp (command, "paper ", sizeof "paper"))
{
unsigned long pixel;
if (chk_alloc_color (command + sizeof "paper", gcvals.background,
&pixel))
{
gcvals.background = pixel;
refresh_gc = 1;
}
}
else if (!memcmp (command, "padcolor ", sizeof "padcolor"))
{
unsigned long pixel;
if (chk_alloc_color (command + sizeof "padcolor", pad_color,
&pixel))
{
pad_color = pixel;
refresh_pad = 1;
}
}
else if (!memcmp (command, "xoffsetchar ", sizeof "xoffsetchar"))
{
xoffsetchar = chk_get_naturalnum (command + sizeof "xoffsetchar");
if (xoffsetchar >= 0)
reposition_face = 1;
}
else if (!memcmp (command, "yoffsetchar ", sizeof "yoffsetchar"))
{
yoffsetchar = chk_get_naturalnum (command + sizeof "yoffsetchar");
if (yoffsetchar >= 0)
reposition_face = 1;
}
else if (!memcmp (command, "xoffsetpix ", sizeof "xoffsetpix"))
{
xoffsetpix = chk_get_naturalnum (command + sizeof "xoffsetpix");
if (xoffsetpix >= 0)
reposition_face = 1;
}
else if (!memcmp (command, "yoffsetpix ", sizeof "yoffsetpix"))
{
yoffsetpix = chk_get_naturalnum (command + sizeof "yoffsetpix");
if (yoffsetpix >= 0)
reposition_face = 1;
}
/* Otherwise it's unrecognized command. Just skip it. */
command = ++bufp;
}
/*
* Wait 10 milliseconds in case the parent has something else to send.
* The user is not likely to notice this pause and we might avoid
* certain amount of processing and roundtrips.
*/
do {
status = poll (&fifo_pollfd, 1, 10);
} while (status == -1 && errno == EINTR);
} while (status > 0);
if (refresh_gc)
{
XChangeGC (d, gc, gcmask, &gcvals);
pixmap_stale = 1;
if (!face_cleared)
state = xface_display;
}
if (refresh_pad)
{
XSetWindowBackground (d, win, pad_color);
XClearArea (d, win, 0, 0, XFACE_PAD, 48, False);
if (state == xface_noop)
state = xface_flush;
}
if (reposition_face)
{
if (got_sigwinch)
{
ioctl (term_fd, TIOCGWINSZ, &winsz);
got_sigwinch = 0;
}
if (xoffsetchar >= 0)
X_OFFSET_CHAR = xoffsetchar;
if (yoffsetchar >= 0)
Y_OFFSET_CHAR = yoffsetchar;
if (xoffsetpix >= 0)
X_OFFSET_PIX = xoffsetpix;
if (yoffsetpix >= 0)
Y_OFFSET_PIX = yoffsetpix;
get_face_position ();
XMoveWindow (d, win, x_pos, y_pos);
if (state == xface_noop)
state = xface_flush;
}
return state;
}
char ls[] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
int
process_command (void)
{
int i, n;
unsigned char *datap;
unsigned char data[288];
char uncompfacebuf[15000];
switch (read_fifo ())
{
case xface_eof:
return 1;
case xface_unmap:
if (is_mapped)
{
XUnmapWindow (d, win);
is_mapped = 0;
XFlush (d);
}
break;
case xface_map:
if (!is_mapped)
{
XMapWindow (d, win);
is_mapped = 1;
XFlush (d);
}
break;
case xface_display:
memcpy (uncompfacebuf, last_face, buffered_face_len);
uncompfacebuf[buffered_face_len] = 0;
pixmap_stale = 0;
uncompface (uncompfacebuf);
/* Are we alive? No buffer overruns? Fuck. */
for (i = 0, n = 0, datap = data; i < 48; ++i)
{
int i1, i2, i3, len;
sscanf (uncompfacebuf + n, "%i,%i,%i,%n", &i1, &i2, &i3, &len);
n += len;
/* Who invented that all-bits-are-reversed format? */
*datap++ = ls[i1 >> 12 & 15] | ls[i1 >> 8 & 15] << 4;
*datap++ = ls[i1 >> 4 & 15] | ls[i1 & 15] << 4;
*datap++ = ls[i2 >> 12 & 15] | ls[i2 >> 8 & 15] << 4;
*datap++ = ls[i2 >> 4 & 15] | ls[i2 & 15] << 4;
*datap++ = ls[i3 >> 12 & 15] | ls[i3 >> 8 & 15] << 4;
*datap++ = ls[i3 >> 4 & 15] | ls[i3 & 15] << 4;
}
if (bitmap)
XFreePixmap (d, bitmap);
bitmap = XCreateBitmapFromData (d, win, (char *) data, 48, 48);
if (is_mapped)
XCopyPlane(d, bitmap, win, gc, 0, 0, 48, 48, XFACE_PAD, 0, 1);
else
XMapWindow (d, win); /* It will be filled on expose. */
XFlush (d);
break;
case xface_flush:
XFlush (d);
}
return 0;
}
void
process_xevent (void)
{
static int x_pointer, y_pointer;
static int grab = AnyButton;
int x, y;
XEvent event;
while (XPending (d))
{
XNextEvent (d, &event);
switch (event.type)
{
case MapNotify:
case Expose:
is_mapped = 1;
XCopyPlane (d, bitmap, win, gc, 0, 0, 48, 48, XFACE_PAD, 0, 1);
XFlush (d);
break;
case ButtonPress:
switch (((XButtonEvent *) &event)->button)
{
case Button1:
if (grab == AnyButton)
{
grab = Button1;
x_pointer = ((XButtonEvent *) &event)->x_root;
y_pointer = ((XButtonEvent *) &event)->y_root;
}
XAllowEvents (d, SyncPointer, CurrentTime);
break;
}
break;
case ButtonRelease:
if(grab == ((XButtonEvent *) &event)->button)
grab = AnyButton;
XAllowEvents (d, AsyncPointer, CurrentTime);
break;
case MotionNotify:
x = ((XMotionEvent *) &event)->x_root;
y = ((XMotionEvent *) &event)->y_root;
x_pos += x - x_pointer;
y_pos += y - y_pointer;
x_pointer = x;
y_pointer = y;
XMoveWindow (d, win, x_pos, y_pos);
break;
case GravityNotify:
x = ((XGravityEvent *) &event)->x;
y = ((XGravityEvent *) &event)->y;
if (grab != AnyButton)
{
x_pointer += x - x_pos;
y_pointer += y - y_pos;
}
x_pos = x;
y_pos = y;
break;
}
}
}
int
main (int argc, char **argv)
{
struct pollfd p[2];
struct sigaction sigact;
/*
* We don't need setlocale() call, because nothing here depends on the
* locale. The only effect it might have is loading and initializing
* one or more shared libraries. We don't need that.
*
* setlocale (LC_ALL, "");
*
*/
setup (&argc, argv); /* child returns, FIFO set and ready, window created */
/*
* We'll ignore Ctrl-C because our action should depend on parent's
* action. If the parent decides to exit it will close the pipe and
* then we'll exit as well. If it doesn't exit, we are not supposed
* to exit either. So we need to ignore this signal.
*/
signal (SIGINT, SIG_IGN);
/* But we need to handle these. */
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = SA_RESTART; /* Not that it matters. */
sigact.sa_handler = handle_sigterm;
sigaction (SIGTERM, &sigact, NULL);
sigact.sa_handler = handle_sigstop;
sigaction (SIGTSTP, &sigact, NULL);
sigact.sa_handler = handle_sigcont;
sigaction (SIGCONT, &sigact, NULL);
sigact.sa_handler = handle_sigwinch;
sigaction (SIGWINCH, &sigact, NULL);
/* Set up poll struct. */
p[0].fd = ConnectionNumber (d);
p[1].fd = fifo_fd;
p[0].events = p[1].events = POLLIN;
while (1)
{
int status;
status = poll (p, 2, -1);
if (status < 0)
{
/* A signal was caught, most likely. */
if (got_sigterm)
break;
if (got_sigstop)
suspend_me ();
if (got_sigcont)
restart_me ();
}
else
{
if ((p[0].revents | p[1].revents) & (POLLERR | POLLHUP | POLLNVAL))
break;
if (p[0].revents)
process_xevent ();
if (p[1].revents)
if (process_command ())
break;
}
}
cleanup ();
return 0;
}
--8<-- CUT HERE --8<--
ciao
--
Tutti si voltarono a guardar Franti. E quell'infame sorrise. :^)
k|b|s ~> mailto `echo ti.gulgb@sbk|'rev'`
Maggiori informazioni sulla lista
bglug