1578 lines
45 KiB
C
1578 lines
45 KiB
C
/* FvwmForm is original work of Thomas Zuwei Feng.
|
|
*
|
|
* Copyright Feb 1995, Thomas Zuwei Feng. No guarantees or warantees are
|
|
* provided or implied in any way whatsoever. Use this program at your own
|
|
* risk. Permission to use, modify, and redistribute this program is hereby
|
|
* given, provided that this copyright is kept intact.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include "../../libs/fvwmlib.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
|
|
#if HAVE_SYS_SELECT_H
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/cursorfont.h>
|
|
#define XK_MISCELLANY
|
|
#include <X11/keysymdef.h>
|
|
|
|
void dummy () {
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define fprintf fprintf
|
|
#else
|
|
#define fprintf dummy
|
|
#endif
|
|
|
|
|
|
#define TEXT_SPC 3
|
|
#define BOX_SPC 3
|
|
#define ITEM_HSPC 10
|
|
#define ITEM_VSPC 5
|
|
|
|
/* tba: use dynamic buffer expanding */
|
|
#define MAX_LINES 50
|
|
#define MAX_ITEMS 100
|
|
#define ITEMS_PER_LINE 64
|
|
#define CHOICES_PER_SEL 64
|
|
|
|
#define I_TEXT 1
|
|
#define I_INPUT 2
|
|
#define I_SELECT 3
|
|
#define I_CHOICE 4
|
|
#define I_BUTTON 5
|
|
|
|
#define IS_SINGLE 1
|
|
#define IS_MULTIPLE 2
|
|
|
|
#define IB_CONTINUE 1
|
|
#define IB_RESTART 2
|
|
#define IB_QUIT 3
|
|
|
|
typedef union _item {
|
|
int type; /* item type, one of I_TEXT .. I_BUTTON */
|
|
struct _head { /* common header */
|
|
int type;
|
|
int win; /* X window id */
|
|
char *name; /* identifier name */
|
|
int size_x, size_y; /* size of bounding box */
|
|
int pos_x, pos_y; /* position of top-left corner */
|
|
} header;
|
|
struct { /* I_TEXT */
|
|
struct _head head;
|
|
int n; /* string length */
|
|
char *value; /* string to display */
|
|
} text;
|
|
struct { /* I_INPUT */
|
|
struct _head head;
|
|
int buf; /* input string buffer */
|
|
int n; /* string length */
|
|
char *value; /* input string */
|
|
char *init_value; /* default string */
|
|
char *blanks; /* blank string */
|
|
int size; /* input field size */
|
|
int left; /* position of the left-most displayed char */
|
|
int o_cursor; /* store relative cursor position */
|
|
} input;
|
|
struct { /* I_SELECT */
|
|
struct _head head;
|
|
int key; /* one of IS_MULTIPLE, IS_SINGLE */
|
|
int n; /* number of choices */
|
|
union _item **choices; /* list of choices */
|
|
} select;
|
|
struct { /* I_CHOICE */
|
|
struct _head head;
|
|
int on; /* selected or not */
|
|
int init_on; /* initially selected or not */
|
|
char *value; /* value if selected */
|
|
int n; /* text string length */
|
|
char *text; /* text string */
|
|
union _item *sel; /* selection it belongs to */
|
|
} choice;
|
|
struct { /* I_BUTTON */
|
|
struct _head head;
|
|
int key; /* one of IB_CONTINUE, IB_RESTART, IB_QUIT */
|
|
int n; /* # of commands */
|
|
int len; /* text length */
|
|
char *text; /* text string */
|
|
int keypress; /* short cut */
|
|
/* Fvwm command to execute */
|
|
char **commands;
|
|
} button;
|
|
} Item;
|
|
|
|
|
|
#define L_LEFT 1
|
|
#define L_RIGHT 2
|
|
#define L_CENTER 3
|
|
#define L_LEFTRIGHT 4
|
|
|
|
typedef struct _line {
|
|
int n; /* number of items on the line */
|
|
int justify; /* justification */
|
|
int size_x, size_y; /* size of bounding rectangle */
|
|
Item **items; /* list of items */
|
|
} Line;
|
|
|
|
|
|
/* global variables */
|
|
char *prog_name; /* program name, e.g. FvwmForm */
|
|
|
|
int fd_in; /* fd for Fvwm->Module packets */
|
|
int fd_out; /* fd for Module->Fvwm packets */
|
|
int fd[2]; /* pipe pair */
|
|
int fd_err;
|
|
FILE *fp_err;
|
|
|
|
Line lines[MAX_LINES];
|
|
int n_lines;
|
|
Item items[MAX_ITEMS];
|
|
int n_items;
|
|
Item def_button;
|
|
|
|
int grab_server = 0, server_grabbed = 0;
|
|
int gx, gy, geom = 0;
|
|
int warp_pointer = 0;
|
|
|
|
Display *dpy;
|
|
int fd_x; /* fd for X connection */
|
|
|
|
Window root, frame, ref;
|
|
Colormap d_cmap;
|
|
int screen;
|
|
int scr_depth;
|
|
|
|
int max_width, total_height; /* frame size */
|
|
|
|
enum { c_back, c_fore, c_itemback, c_itemfore, c_itemlo, c_itemhi };
|
|
char *color_names[4] = {
|
|
"Light Gray", "Black", "Gray50", "Wheat"
|
|
};
|
|
unsigned long colors[6];
|
|
|
|
enum { f_text, f_input, f_button };
|
|
char *font_names[3] = {
|
|
"fixed",
|
|
"fixed",
|
|
"fixed"
|
|
};
|
|
Font fonts[3];
|
|
XFontStruct *xfs[3];
|
|
|
|
Cursor xc_ibeam, xc_hand;
|
|
|
|
GC gc_text, gc_input, gc_button;
|
|
|
|
Item *cur_text;
|
|
int abs_cursor;
|
|
int rel_cursor;
|
|
|
|
static char *buf;
|
|
static int N = 8;
|
|
|
|
/* copy a string until '\0', or up to n chars, and delete trailing spaces */
|
|
char *CopyNString (char *cp, int n)
|
|
{
|
|
char *dp, *bp;
|
|
if (n == 0)
|
|
n = strlen(cp);
|
|
bp = dp = (char *)malloc(n+1);
|
|
while (n-- > 0)
|
|
*dp++ = *cp++;
|
|
while (isspace(*(--dp)));
|
|
*(++dp) = '\0';
|
|
return bp;
|
|
}
|
|
|
|
/* copy a string until '"', or '\n', or '\0' */
|
|
char *CopyQuotedString (char *cp)
|
|
{
|
|
char *dp, *bp, c;
|
|
bp = dp = (char *)malloc(strlen(cp) + 1);
|
|
while (1) {
|
|
switch (c = *(cp++)) {
|
|
case '\\':
|
|
*(dp++) = *(cp++);
|
|
break;
|
|
case '\"':
|
|
case '\n':
|
|
case '\0':
|
|
*dp = '\0';
|
|
return bp;
|
|
break;
|
|
default:
|
|
*(dp++) = c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* copy a string until the first space */
|
|
char *CopySolidString (char *cp)
|
|
{
|
|
char *dp, *bp, c;
|
|
bp = dp = (char *)malloc(strlen(cp) + 1);
|
|
while (1) {
|
|
c = *(cp++);
|
|
if (c == '\\') {
|
|
*(dp++) = '\\';
|
|
*(dp++) = *(cp++);
|
|
} else if (isspace(c) || c == '\0') {
|
|
*dp = '\0';
|
|
return bp;
|
|
} else
|
|
*(dp++) = c;
|
|
}
|
|
}
|
|
|
|
/* get the font height */
|
|
int FontHeight (XFontStruct *xfs)
|
|
{
|
|
return (xfs->ascent + xfs->descent);
|
|
}
|
|
|
|
/* get the font width, for fixed-width font only */
|
|
int FontWidth (XFontStruct *xfs)
|
|
{
|
|
return (xfs->per_char[0].width);
|
|
}
|
|
|
|
/* read the configuration file */
|
|
void ReadConfig ()
|
|
{
|
|
FILE *fopen();
|
|
int prog_name_len, i, j, l, extra;
|
|
char *line_buf;
|
|
char *cp;
|
|
Line *cur_line, *line;
|
|
Item *item, *cur_sel, *cur_button;
|
|
|
|
#define AddToLine(item) { cur_line->items[cur_line->n++] = item; cur_line->size_x += item->header.size_x; if (cur_line->size_y < item->header.size_y) cur_line->size_y = item->header.size_y; }
|
|
|
|
n_items = 0;
|
|
n_lines = 0;
|
|
|
|
/* default line in case the first *FFLine is missing */
|
|
lines[0].n = 0;
|
|
lines[0].justify = L_CENTER;
|
|
lines[0].size_x = lines[0].size_y = 0;
|
|
lines[0].items = (Item **)malloc(sizeof(Item *) * ITEMS_PER_LINE);
|
|
cur_line = lines;
|
|
|
|
/* default button is for initial functions */
|
|
cur_button = &def_button;
|
|
def_button.button.n = 0;
|
|
def_button.button.commands = (char **)malloc(sizeof(char *) * MAX_ITEMS);
|
|
def_button.button.key = IB_CONTINUE;
|
|
|
|
/* default fonts in case the *FFFont's are missing */
|
|
xfs[f_text] = xfs[f_input] = xfs[f_button] =
|
|
GetFontOrFixed(dpy, "fixed");
|
|
fonts[f_text] = fonts[f_input] = fonts[f_button] = xfs[f_text]->fid;
|
|
|
|
prog_name_len = strlen(prog_name);
|
|
|
|
while (GetConfigLine(fd,&line_buf),line_buf) {
|
|
cp = line_buf;
|
|
while (isspace(*cp)) cp++; /* skip blanks */
|
|
if (*cp != '*') continue;
|
|
if (strncmp(++cp, prog_name, prog_name_len) != 0) continue;
|
|
cp += prog_name_len;
|
|
/* at this point we have recognized "*FvwmForm" */
|
|
if (strncmp(cp, "GrabServer", 10) == 0) {
|
|
grab_server = 1;
|
|
continue;
|
|
}
|
|
else if (strncmp(cp, "WarpPointer", 11) == 0) {
|
|
warp_pointer = 1;
|
|
}
|
|
else if (strncmp(cp, "Position", 8) == 0) {
|
|
cp += 8;
|
|
geom = 1;
|
|
while (isspace(*cp)) cp++;
|
|
gx = atoi(cp);
|
|
while (!isspace(*cp)) cp++;
|
|
while (isspace(*cp)) cp++;
|
|
gy = atoi(cp);
|
|
fprintf(fp_err, "Position @ (%d, %d)\n", gx, gy);
|
|
continue;
|
|
}
|
|
else if (strncmp(cp, "Fore", 4) == 0) {
|
|
cp += 4;
|
|
while (isspace(*cp)) cp++;
|
|
color_names[c_fore] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "ColorFore: %s\n", color_names[c_fore]);
|
|
continue;
|
|
} else if (strncmp(cp, "Back", 4) == 0) {
|
|
cp += 4;
|
|
while (isspace(*cp)) cp++;
|
|
color_names[c_back] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "ColorBack: %s\n", color_names[c_back]);
|
|
continue;
|
|
} else if (strncmp(cp, "ItemFore", 8) == 0) {
|
|
cp += 8;
|
|
while (isspace(*cp)) cp++;
|
|
color_names[c_itemfore] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "ColorItemFore: %s\n", color_names[c_itemfore]);
|
|
continue;
|
|
} else if (strncmp(cp, "ItemBack", 8) == 0) {
|
|
cp += 8;
|
|
while (isspace(*cp)) cp++;
|
|
color_names[c_itemback] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "ColorItemBack: %s\n", color_names[c_itemback]);
|
|
continue;
|
|
} else if (strncmp(cp, "Font", 4) == 0) {
|
|
cp += 4;
|
|
while (isspace(*cp)) cp++;
|
|
font_names[f_text] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "Font: %s\n", font_names[f_text]);
|
|
xfs[f_text] = GetFontOrFixed(dpy, font_names[f_text]);
|
|
fonts[f_text] = xfs[f_text]->fid;
|
|
continue;
|
|
} else if (strncmp(cp, "ButtonFont", 10) == 0) {
|
|
cp += 10;
|
|
while (isspace(*cp)) cp++;
|
|
font_names[f_button] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "ButtonFont: %s\n", font_names[f_button]);
|
|
xfs[f_button] = GetFontOrFixed(dpy, font_names[f_button]);
|
|
fonts[f_button] = xfs[f_button]->fid;
|
|
continue;
|
|
} else if (strncmp(cp, "InputFont", 9) == 0) {
|
|
cp += 9;
|
|
while (isspace(*cp)) cp++;
|
|
font_names[f_input] = CopyNString(cp, 0);
|
|
fprintf(fp_err, "InputFont: %s\n", font_names[f_input]);
|
|
xfs[f_input] = GetFontOrFixed(dpy, font_names[f_input]);
|
|
fonts[f_input] = xfs[f_input]->fid;
|
|
continue;
|
|
} else if (strncmp(cp, "Line", 4) == 0) {
|
|
cp += 4;
|
|
cur_line = lines + n_lines++;
|
|
while (isspace(*cp)) cp++;
|
|
if (strncmp(cp, "left", 4) == 0)
|
|
cur_line->justify = L_LEFT;
|
|
else if (strncmp(cp, "right", 5) == 0)
|
|
cur_line->justify = L_RIGHT;
|
|
else if (strncmp(cp, "center", 6) == 0)
|
|
cur_line->justify = L_CENTER;
|
|
else
|
|
cur_line->justify = L_LEFTRIGHT;
|
|
cur_line->n = 0;
|
|
cur_line->items = (Item **)malloc(sizeof(Item *) * ITEMS_PER_LINE);
|
|
continue;
|
|
} else if (strncmp(cp, "Text", 4) == 0) {
|
|
/* syntax: *FFText "<text>" */
|
|
cp += 4;
|
|
item = items + n_items++;
|
|
item->type = I_TEXT;
|
|
item->header.name = "";
|
|
while (isspace(*cp)) cp++;
|
|
if (*cp == '\"')
|
|
item->text.value = CopyQuotedString(++cp);
|
|
else
|
|
item->text.value = "";
|
|
item->text.n = strlen(item->text.value);
|
|
item->header.size_x = XTextWidth(xfs[f_text], item->text.value,
|
|
item->text.n) + 2 * TEXT_SPC;
|
|
item->header.size_y = FontHeight(xfs[f_text]) + 2 * TEXT_SPC;
|
|
fprintf(fp_err, "Text \"%s\" [%d, %d]\n", item->text.value,
|
|
item->header.size_x, item->header.size_y);
|
|
AddToLine(item);
|
|
continue;
|
|
}
|
|
else if (strncmp(cp, "Input", 5) == 0) {
|
|
/* syntax: *FFInput <name> <size> "<init_value>" */
|
|
cp += 5;
|
|
item = items + n_items++;
|
|
item->type = I_INPUT;
|
|
while (isspace(*cp)) cp++;
|
|
item->header.name = CopySolidString(cp);
|
|
cp += strlen(item->header.name);
|
|
while (isspace(*cp)) cp++;
|
|
item->input.size = atoi(cp);
|
|
while (!isspace(*cp)) cp++;
|
|
while (isspace(*cp)) cp++;
|
|
if (*cp == '\"')
|
|
item->input.init_value = CopyQuotedString(++cp);
|
|
else
|
|
item->input.init_value = "";
|
|
item->input.blanks = (char *)malloc(item->input.size);
|
|
for (j = 0; j < item->input.size; j++)
|
|
item->input.blanks[j] = ' ';
|
|
item->input.buf = strlen(item->input.init_value) + 1;
|
|
item->input.value = (char *)malloc(item->input.buf);
|
|
item->header.size_x = FontWidth(xfs[f_input]) * item->input.size
|
|
+ 2 * TEXT_SPC + 2 * BOX_SPC;
|
|
item->header.size_y = FontHeight(xfs[f_input]) + 3 * TEXT_SPC
|
|
+ 2 * BOX_SPC;
|
|
fprintf(fp_err, "Input, %s, [%d], \"%s\"\n", item->header.name,
|
|
item->input.size, item->input.init_value);
|
|
AddToLine(item);
|
|
}
|
|
else if (strncmp(cp, "Selection", 9) == 0) {
|
|
/* syntax: *FFSelection <name> single | multiple */
|
|
cp += 9;
|
|
cur_sel = items + n_items++;
|
|
cur_sel->type = I_SELECT;
|
|
while (isspace(*cp)) cp++;
|
|
cur_sel->header.name = CopySolidString(cp);
|
|
cp += strlen(cur_sel->header.name);
|
|
while (isspace(*cp)) cp++;
|
|
if (strncmp(cp, "multiple", 8) == 0)
|
|
cur_sel->select.key = IS_MULTIPLE;
|
|
else
|
|
cur_sel->select.key = IS_SINGLE;
|
|
cur_sel->select.n = 0;
|
|
cur_sel->select.choices =
|
|
(Item **)malloc(sizeof(Item *) * CHOICES_PER_SEL);
|
|
continue;
|
|
} else if (strncmp(cp, "Choice", 6) == 0) {
|
|
/* syntax: *FFChoice <name> <value> [on | _off_] ["<text>"] */
|
|
cp += 6;
|
|
item = items + n_items++;
|
|
item->type = I_CHOICE;
|
|
while (isspace(*cp)) cp++;
|
|
item->header.name = CopySolidString(cp);
|
|
cp += strlen(item->header.name);
|
|
while (isspace(*cp)) cp++;
|
|
item->choice.value = CopySolidString(cp);
|
|
cp += strlen(item->choice.value);
|
|
while (isspace(*cp)) cp++;
|
|
if (strncmp(cp, "on", 2) == 0)
|
|
item->choice.init_on = 1;
|
|
else
|
|
item->choice.init_on = 0;
|
|
while (!isspace(*cp)) cp++;
|
|
while (isspace(*cp)) cp++;
|
|
if (*cp == '\"')
|
|
item->choice.text = CopyQuotedString(++cp);
|
|
else
|
|
item->choice.text = "";
|
|
item->choice.n = strlen(item->choice.text);
|
|
item->choice.sel = cur_sel;
|
|
cur_sel->select.choices[cur_sel->select.n++] = item;
|
|
item->header.size_y = FontHeight(xfs[f_text]) + 2 * TEXT_SPC;
|
|
item->header.size_x = FontHeight(xfs[f_text]) + 4 * TEXT_SPC +
|
|
XTextWidth(xfs[f_text], item->choice.text, item->choice.n);
|
|
fprintf(fp_err, "Choice %s, \"%s\", [%d, %d]\n", item->header.name,
|
|
item->choice.text, item->header.size_x, item->header.size_y);
|
|
AddToLine(item);
|
|
continue;
|
|
} else if (strncmp(cp, "Button", 6) == 0) {
|
|
/* syntax: *FFButton continue | restart | quit "<text>" */
|
|
cp += 6;
|
|
item = items + n_items++;
|
|
item->type = I_BUTTON;
|
|
item->header.name = "";
|
|
while (isspace(*cp)) cp++;
|
|
if (strncmp(cp, "restart", 7) == 0)
|
|
item->button.key = IB_RESTART;
|
|
else if (strncmp(cp, "quit", 4) == 0)
|
|
item->button.key = IB_QUIT;
|
|
else
|
|
item->button.key = IB_CONTINUE;
|
|
while (!isspace(*cp)) cp++;
|
|
while (isspace(*cp)) cp++;
|
|
if (*cp == '\"') {
|
|
item->button.text = CopyQuotedString(++cp);
|
|
cp += strlen(item->button.text) + 1;
|
|
while (isspace(*cp)) cp++;
|
|
} else
|
|
item->button.text = "";
|
|
if (*cp == '^')
|
|
item->button.keypress = *(++cp) - '@';
|
|
else if (*cp == 'F')
|
|
item->button.keypress = 256 + atoi(++cp);
|
|
else
|
|
item->button.keypress = -1;
|
|
item->button.len = strlen(item->button.text);
|
|
item->button.n = 0;
|
|
item->button.commands = (char **)malloc(sizeof(char *) * MAX_ITEMS);
|
|
item->header.size_y = FontHeight(xfs[f_button]) + 2 * TEXT_SPC
|
|
+ 2 * BOX_SPC;
|
|
item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
|
|
+ XTextWidth(xfs[f_button], item->button.text, item->button.len);
|
|
AddToLine(item);
|
|
cur_button = item;
|
|
continue;
|
|
} else if (strncmp(cp, "Command", 7) == 0) {
|
|
/* syntax: *FFCommand <command> */
|
|
cp += 7;
|
|
while (isspace(*cp)) cp++;
|
|
cur_button->button.commands[cur_button->button.n++] =
|
|
CopyNString(cp, 0);
|
|
}
|
|
} /* end of switch() */
|
|
/* get the geometry right */
|
|
max_width = 0;
|
|
total_height = ITEM_VSPC;
|
|
for (l = 0; l < n_lines; l++) {
|
|
line = lines + l;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_y = total_height;
|
|
if (line->items[i]->header.size_y < line->size_y)
|
|
line->items[i]->header.pos_y += (line->size_y - line->items[i]->header.size_y) / 2 + 1 ;
|
|
}
|
|
total_height += ITEM_VSPC + line->size_y;
|
|
line->size_x += (line->n + 1) * ITEM_HSPC;
|
|
if (line->size_x > max_width)
|
|
max_width = line->size_x;
|
|
}
|
|
for (l = 0; l < n_lines; l++) {
|
|
int width;
|
|
line = lines + l;
|
|
fprintf(fp_err, "Line[%d], %d, %d items\n", l, line->justify, line->n);
|
|
switch (line->justify) {
|
|
case L_LEFT:
|
|
width = ITEM_HSPC;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_x = width;
|
|
width += ITEM_HSPC + line->items[i]->header.size_x;
|
|
}
|
|
break;
|
|
case L_RIGHT:
|
|
width = max_width - line->size_x + ITEM_HSPC;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_x = width;
|
|
width += ITEM_HSPC + line->items[i]->header.size_x;
|
|
}
|
|
break;
|
|
case L_CENTER:
|
|
width = (max_width - line->size_x) / 2 + ITEM_HSPC;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_x = width;
|
|
fprintf(fp_err, "Line[%d], Item[%d] @ (%d, %d)\n", l, i,
|
|
line->items[i]->header.pos_x, line->items[i]->header.pos_y);
|
|
width += ITEM_HSPC + line->items[i]->header.size_x;
|
|
}
|
|
break;
|
|
case L_LEFTRIGHT:
|
|
/* count the number of inputs on the line - the extra space will be
|
|
* shared amongst these if there are any, otherwise it will be added
|
|
* as space in between the elements
|
|
*/
|
|
extra = 0 ;
|
|
for (i = 0 ; i < line->n ; i++) {
|
|
if (line->items[i]->type == I_INPUT)
|
|
extra++ ;
|
|
}
|
|
if (extra == 0) {
|
|
if (line->n < 2) { /* same as L_CENTER */
|
|
width = (max_width - line->size_x) / 2 + ITEM_HSPC;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_x = width;
|
|
width += ITEM_HSPC + line->items[i]->header.size_x;
|
|
}
|
|
} else {
|
|
extra = (max_width - line->size_x) / (line->n - 1);
|
|
width = ITEM_HSPC;
|
|
for (i = 0; i < line->n; i++) {
|
|
line->items[i]->header.pos_x = width;
|
|
width += ITEM_HSPC + line->items[i]->header.size_x + extra;
|
|
}
|
|
}
|
|
} else {
|
|
extra = (max_width - line->size_x) / extra ;
|
|
width = ITEM_HSPC ;
|
|
for (i = 0 ; i < line->n ; i++) {
|
|
line->items[i]->header.pos_x = width ;
|
|
if (line->items[i]->type == I_INPUT)
|
|
line->items[i]->header.size_x += extra ;
|
|
width += ITEM_HSPC + line->items[i]->header.size_x ;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MAX_INTENSITY 65535
|
|
|
|
/* allocate color cells */
|
|
void GetColors ()
|
|
{
|
|
Visual* visual = DefaultVisual(dpy, screen);
|
|
XColor xc_item;
|
|
int red, green, blue, tmp1, tmp2 ;
|
|
if (scr_depth < 8) {
|
|
colors[c_back] = colors[c_itemback] = WhitePixel(dpy, screen);
|
|
colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
|
|
= BlackPixel(dpy, screen);
|
|
} else if (visual->class == TrueColor ||
|
|
visual->class == StaticColor ||
|
|
visual->class == StaticGray) {
|
|
if (XParseColor(dpy, d_cmap, color_names[c_fore], &xc_item) &&
|
|
XAllocColor(dpy, d_cmap, &xc_item))
|
|
colors[c_fore] = xc_item.pixel;
|
|
else
|
|
colors[c_fore] = BlackPixel(dpy, screen);
|
|
|
|
if (XParseColor(dpy, d_cmap, color_names[c_back], &xc_item) &&
|
|
XAllocColor(dpy, d_cmap, &xc_item))
|
|
colors[c_back] = xc_item.pixel;
|
|
else
|
|
colors[c_back] = WhitePixel(dpy, screen);
|
|
|
|
if (XParseColor(dpy, d_cmap, color_names[c_itemfore], &xc_item) &&
|
|
XAllocColor(dpy, d_cmap, &xc_item))
|
|
colors[c_itemfore] = xc_item.pixel;
|
|
else
|
|
colors[c_itemfore] = BlackPixel(dpy, screen);
|
|
|
|
if (XParseColor(dpy, d_cmap, color_names[c_itemback], &xc_item) &&
|
|
XAllocColor(dpy, d_cmap, &xc_item))
|
|
colors[c_itemback] = xc_item.pixel;
|
|
else
|
|
colors[c_itemback] = WhitePixel(dpy, screen);
|
|
|
|
InitPictureCMap(dpy,root); /* for shadow routines */
|
|
colors[c_itemlo] = GetShadow(colors[c_itemback]); /* alloc shadow */
|
|
colors[c_itemhi] = GetHilite(colors[c_itemback]); /* alloc shadow */
|
|
} else if (!XAllocColorCells(dpy, d_cmap, 0, NULL, 0, colors, 6)) {
|
|
colors[c_back] = colors[c_itemback] = WhitePixel(dpy, screen);
|
|
colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
|
|
= BlackPixel(dpy, screen);
|
|
} else {
|
|
XStoreNamedColor(dpy, d_cmap, color_names[c_fore], colors[c_fore],
|
|
DoRed | DoGreen | DoBlue);
|
|
XStoreNamedColor(dpy, d_cmap, color_names[c_back], colors[c_back],
|
|
DoRed | DoGreen | DoBlue);
|
|
XStoreNamedColor(dpy, d_cmap, color_names[c_itemfore],
|
|
colors[c_itemfore], DoRed | DoGreen | DoBlue);
|
|
XStoreNamedColor(dpy, d_cmap, color_names[c_itemback],
|
|
colors[c_itemback], DoRed | DoGreen | DoBlue);
|
|
XParseColor(dpy, d_cmap, color_names[c_itemback], &xc_item);
|
|
red = (int) xc_item.red ;
|
|
green = (int) xc_item.green ;
|
|
blue = (int) xc_item.blue ;
|
|
xc_item.red = (60 * red) / 100 ;
|
|
xc_item.green = (60 * green) / 100 ;
|
|
xc_item.blue = (60 * blue) / 100 ;
|
|
xc_item.pixel = colors[c_itemlo];
|
|
xc_item.flags = DoRed | DoGreen | DoBlue;
|
|
XStoreColor(dpy, d_cmap, &xc_item);
|
|
XParseColor(dpy, d_cmap, color_names[c_itemback], &xc_item);
|
|
tmp1 = (14 * red) / 10 ;
|
|
if (tmp1 > MAX_INTENSITY) tmp1 = MAX_INTENSITY ;
|
|
tmp2 = (MAX_INTENSITY + red) / 2 ;
|
|
xc_item.red = (tmp1 > tmp2) ? tmp1 : tmp2 ;
|
|
tmp1 = (14 * green) / 10 ;
|
|
if (tmp1 > MAX_INTENSITY) tmp1 = MAX_INTENSITY ;
|
|
tmp2 = (MAX_INTENSITY + green) / 2 ;
|
|
xc_item.green = (tmp1 > tmp2) ? tmp1 : tmp2 ;
|
|
tmp1 = (14 * blue) / 10 ;
|
|
if (tmp1 > MAX_INTENSITY) tmp1 = MAX_INTENSITY ;
|
|
tmp2 = (MAX_INTENSITY + blue) / 2 ;
|
|
xc_item.blue = (tmp1 > tmp2) ? tmp1 : tmp2 ;
|
|
xc_item.pixel = colors[c_itemhi];
|
|
xc_item.flags = DoRed | DoGreen | DoBlue;
|
|
XStoreColor(dpy, d_cmap, &xc_item);
|
|
}
|
|
}
|
|
|
|
/* reset all the values */
|
|
void Restart ()
|
|
{
|
|
int i;
|
|
Item *item;
|
|
|
|
cur_text = NULL;
|
|
abs_cursor = rel_cursor = 0;
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
switch (item->type) {
|
|
case I_INPUT:
|
|
if (!cur_text)
|
|
cur_text = item;
|
|
item->input.n = strlen(item->input.init_value);
|
|
strcpy(item->input.value, item->input.init_value);
|
|
item->input.left = 0;
|
|
item->input.o_cursor = 0;
|
|
break;
|
|
case I_CHOICE:
|
|
item->choice.on = item->choice.init_on;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* redraw the frame */
|
|
void RedrawFrame ()
|
|
{
|
|
int i, x, y;
|
|
Item *item;
|
|
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
switch (item->type) {
|
|
case I_TEXT:
|
|
x = item->header.pos_x + TEXT_SPC;
|
|
y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
|
|
XDrawImageString(dpy, frame, gc_text, x, y, item->text.value,
|
|
item->text.n);
|
|
break;
|
|
case I_CHOICE:
|
|
x = item->header.pos_x + TEXT_SPC + item->header.size_y;
|
|
y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
|
|
XDrawImageString(dpy, frame, gc_text, x, y, item->choice.text,
|
|
item->choice.n);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* redraw an item */
|
|
void RedrawItem (Item *item, int click)
|
|
{
|
|
int dx, dy, len, x;
|
|
static XSegment xsegs[4];
|
|
|
|
switch (item->type) {
|
|
case I_INPUT:
|
|
dx = item->header.size_x - 1;
|
|
dy = item->header.size_y - 1;
|
|
XSetForeground(dpy, gc_button, colors[c_itemlo]);
|
|
xsegs[0].x1 = 0, xsegs[0].y1 = 0;
|
|
xsegs[0].x2 = 0, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 0, xsegs[1].y1 = 0;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = 0;
|
|
xsegs[2].x1 = 1, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
|
|
xsegs[3].x1 = 1, xsegs[3].y1 = 1;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
XSetForeground(dpy, gc_button, colors[c_itemhi]);
|
|
xsegs[0].x1 = 1, xsegs[0].y1 = dy;
|
|
xsegs[0].x2 = dx, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
|
|
xsegs[2].x1 = dx, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = dx, xsegs[2].y2 = dy;
|
|
xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
if (click) {
|
|
x = BOX_SPC + TEXT_SPC + FontWidth(xfs[f_input]) * abs_cursor - 1;
|
|
XSetForeground(dpy, gc_button, colors[c_itemback]);
|
|
XDrawLine(dpy, item->header.win, gc_button,
|
|
x, BOX_SPC, x, dy - BOX_SPC);
|
|
}
|
|
len = item->input.n - item->input.left;
|
|
if (len > item->input.size)
|
|
len = item->input.size;
|
|
else
|
|
XDrawImageString(dpy, item->header.win, gc_input,
|
|
BOX_SPC + TEXT_SPC + FontWidth(xfs[f_input]) * len,
|
|
BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
|
|
item->input.blanks, item->input.size - len);
|
|
XDrawImageString(dpy, item->header.win, gc_input,
|
|
BOX_SPC + TEXT_SPC,
|
|
BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
|
|
item->input.value + item->input.left, len);
|
|
if (item == cur_text && !click) {
|
|
x = BOX_SPC + TEXT_SPC + FontWidth(xfs[f_input]) * abs_cursor - 1;
|
|
XDrawLine(dpy, item->header.win, gc_input,
|
|
x, BOX_SPC, x, dy - BOX_SPC);
|
|
}
|
|
break;
|
|
case I_CHOICE:
|
|
dx = dy = item->header.size_y - 1;
|
|
if (item->choice.on) {
|
|
XSetForeground(dpy, gc_button, colors[c_itemfore]);
|
|
if (item->choice.sel->select.key == IS_MULTIPLE) {
|
|
xsegs[0].x1 = 5, xsegs[0].y1 = 5;
|
|
xsegs[0].x2 = dx - 5, xsegs[0].y2 = dy - 5;
|
|
xsegs[1].x1 = 5, xsegs[1].y1 = dy - 5;
|
|
xsegs[1].x2 = dx - 5, xsegs[1].y2 = 5;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 2);
|
|
} else {
|
|
XDrawArc(dpy, item->header.win, gc_button,
|
|
5, 5, dx - 10, dy - 10, 0, 360 * 64);
|
|
}
|
|
} else
|
|
XClearWindow(dpy, item->header.win);
|
|
if (item->choice.on)
|
|
XSetForeground(dpy, gc_button, colors[c_itemlo]);
|
|
else
|
|
XSetForeground(dpy, gc_button, colors[c_itemhi]);
|
|
xsegs[0].x1 = 0, xsegs[0].y1 = 0;
|
|
xsegs[0].x2 = 0, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 0, xsegs[1].y1 = 0;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = 0;
|
|
xsegs[2].x1 = 1, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
|
|
xsegs[3].x1 = 1, xsegs[3].y1 = 1;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
if (item->choice.on)
|
|
XSetForeground(dpy, gc_button, colors[c_itemhi]);
|
|
else
|
|
XSetForeground(dpy, gc_button, colors[c_itemlo]);
|
|
xsegs[0].x1 = 1, xsegs[0].y1 = dy;
|
|
xsegs[0].x2 = dx, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
|
|
xsegs[2].x1 = dx, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = dx, xsegs[2].y2 = dy;
|
|
xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
break;
|
|
case I_BUTTON:
|
|
dx = item->header.size_x - 1;
|
|
dy = item->header.size_y - 1;
|
|
if (click)
|
|
XSetForeground(dpy, gc_button, colors[c_itemlo]);
|
|
else
|
|
XSetForeground(dpy, gc_button, colors[c_itemhi]);
|
|
xsegs[0].x1 = 0, xsegs[0].y1 = 0;
|
|
xsegs[0].x2 = 0, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 0, xsegs[1].y1 = 0;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = 0;
|
|
xsegs[2].x1 = 1, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
|
|
xsegs[3].x1 = 1, xsegs[3].y1 = 1;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
if (click)
|
|
XSetForeground(dpy, gc_button, colors[c_itemhi]);
|
|
else
|
|
XSetForeground(dpy, gc_button, colors[c_itemlo]);
|
|
xsegs[0].x1 = 1, xsegs[0].y1 = dy;
|
|
xsegs[0].x2 = dx, xsegs[0].y2 = dy;
|
|
xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
|
|
xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
|
|
xsegs[2].x1 = dx, xsegs[2].y1 = 1;
|
|
xsegs[2].x2 = dx, xsegs[2].y2 = dy;
|
|
xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
|
|
xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
|
|
XDrawSegments(dpy, item->header.win, gc_button, xsegs, 4);
|
|
XSetForeground(dpy, gc_button, colors[c_itemfore]);
|
|
XDrawImageString(dpy, item->header.win, gc_button,
|
|
BOX_SPC + TEXT_SPC,
|
|
BOX_SPC + TEXT_SPC + xfs[f_button]->ascent,
|
|
item->button.text, item->button.len);
|
|
break;
|
|
}
|
|
XFlush(dpy);
|
|
}
|
|
|
|
void ToggleChoice (Item *item)
|
|
{
|
|
int i;
|
|
Item *sel = item->choice.sel;
|
|
|
|
if (sel->select.key == IS_SINGLE) {
|
|
if (!item->choice.on) {
|
|
for (i = 0; i < sel->select.n; i++) {
|
|
if (sel->select.choices[i]->choice.on) {
|
|
sel->select.choices[i]->choice.on = 0;
|
|
RedrawItem(sel->select.choices[i], 0);
|
|
}
|
|
}
|
|
item->choice.on = 1;
|
|
RedrawItem(item, 0);
|
|
}
|
|
} else { /* IS_MULTIPLE */
|
|
item->choice.on = !item->choice.on;
|
|
RedrawItem(item, 0);
|
|
}
|
|
}
|
|
|
|
/* do var substitution for command string */
|
|
void ParseCommand (int dn, char *sp, char end, int *dn1, char **sp1)
|
|
#define AddChar(chr) { if (dn >= N) { N *= 2; buf = (char *)realloc(buf, N); } buf[dn++] = (chr); }
|
|
{
|
|
static char var[256];
|
|
char c, x, *wp, *cp, *vp;
|
|
int i, j, dn2;
|
|
Item *item;
|
|
|
|
while (1) {
|
|
c = *(sp++);
|
|
if (c == '\0' || c == end) { /* end of substitution */
|
|
*dn1 = dn;
|
|
*sp1 = sp;
|
|
return;
|
|
} if (c == '\\') { /* escape char */
|
|
AddChar('\\');
|
|
AddChar(*(sp++));
|
|
goto next_loop;
|
|
}
|
|
if (c == '$') { /* variable */
|
|
if (*sp != '(')
|
|
goto normal_char;
|
|
wp = ++sp;
|
|
vp = var;
|
|
while (1) {
|
|
x = *(sp++);
|
|
if (x == '\\') {
|
|
*(vp++) = '\\';
|
|
*(vp++) = *(sp++);
|
|
}
|
|
else if (x == ')' || x == '?' || x == '!') {
|
|
*(vp++) = '\0';
|
|
break;
|
|
}
|
|
else if (!isspace(x))
|
|
*(vp++) = x;
|
|
}
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
if (strcmp(var, item->header.name) == 0) {
|
|
switch (item->type) {
|
|
case I_INPUT:
|
|
if (x == ')') {
|
|
for (cp = item->input.value; *cp != '\0'; cp++) {
|
|
if (*cp == '\"' || *cp == '\'' || *cp == '\\')
|
|
AddChar('\\');
|
|
AddChar(*cp);
|
|
}
|
|
} else {
|
|
ParseCommand(dn, sp, ')', &dn2, &sp);
|
|
if ((x == '?' && strlen(item->input.value) > 0) ||
|
|
(x == '!' && strlen(item->input.value) == 0))
|
|
dn = dn2;
|
|
}
|
|
break;
|
|
case I_CHOICE:
|
|
if (x == ')') {
|
|
for (cp = item->choice.value; *cp != '\0'; cp++)
|
|
AddChar(*cp);
|
|
} else {
|
|
ParseCommand(dn, sp, ')', &dn2, &sp);
|
|
if ((x == '?' && item->choice.on) ||
|
|
(x == '!' && !item->choice.on))
|
|
dn = dn2;
|
|
}
|
|
break;
|
|
case I_SELECT:
|
|
if (x != ')')
|
|
ParseCommand(dn, sp, ')', &dn2, &sp);
|
|
AddChar(' ');
|
|
for (j = 0; j < item->select.n; j++) {
|
|
if (item->select.choices[j]->choice.on) {
|
|
for (cp = item->select.choices[j]->choice.value;
|
|
*cp != '\0'; cp++)
|
|
AddChar(*cp);
|
|
AddChar(' ');
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
goto next_loop;
|
|
}
|
|
}
|
|
goto next_loop;
|
|
}
|
|
normal_char:
|
|
AddChar(c);
|
|
next_loop:
|
|
;
|
|
}
|
|
}
|
|
|
|
/* execute a command */
|
|
void DoCommand (Item *cmd)
|
|
{
|
|
int i, k, dn, len;
|
|
char *sp;
|
|
|
|
/* pre-command */
|
|
if (cmd->button.key == IB_QUIT)
|
|
XWithdrawWindow(dpy, frame, screen);
|
|
|
|
for (k = 0; k < cmd->button.n; k++) {
|
|
/* construct command */
|
|
ParseCommand(0, cmd->button.commands[k], '\0', &dn, &sp);
|
|
AddChar('\0');
|
|
fprintf(fp_err, "Final command[%d]: [%s]\n", k, buf);
|
|
|
|
/* send command */
|
|
write(fd_out, &ref, sizeof(Window));
|
|
len = strlen(buf);
|
|
write(fd_out, &len, sizeof(int));
|
|
write(fd_out, buf, len);
|
|
len = 1;
|
|
write(fd_out, &len, sizeof(int));
|
|
}
|
|
|
|
/* post-command */
|
|
if (cmd->button.key == IB_QUIT) {
|
|
if (grab_server)
|
|
XUngrabServer(dpy);
|
|
exit(0);
|
|
}
|
|
if (cmd->button.key == IB_RESTART) {
|
|
Restart();
|
|
for (i = 0; i < n_items; i++) {
|
|
if (items[i].type == I_INPUT) {
|
|
XClearWindow(dpy, items[i].header.win);
|
|
RedrawItem(items + i, 0);
|
|
}
|
|
if (items[i].type == I_CHOICE)
|
|
RedrawItem(items + i, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* open the windows */
|
|
void OpenWindows ()
|
|
{
|
|
int i, x, y;
|
|
Item *item;
|
|
static XColor xcf, xcb;
|
|
static XSetWindowAttributes xswa;
|
|
static XGCValues xgcv;
|
|
static XWMHints wmh = { InputHint, True };
|
|
static XSizeHints sh = { PPosition | PSize | USPosition | USSize };
|
|
static int xgcv_mask = GCBackground | GCForeground | GCFont;
|
|
|
|
xc_ibeam = XCreateFontCursor(dpy, XC_xterm);
|
|
xc_hand = XCreateFontCursor(dpy, XC_hand2);
|
|
xcf.pixel = WhitePixel(dpy, screen);
|
|
XQueryColor(dpy, d_cmap, &xcf);
|
|
xcb.pixel = colors[c_itemback];
|
|
XQueryColor(dpy, d_cmap, &xcb);
|
|
XRecolorCursor(dpy, xc_ibeam, &xcf, &xcb);
|
|
|
|
/* the frame window first */
|
|
if (geom) {
|
|
if (gx >= 0)
|
|
x = gx;
|
|
else
|
|
x = DisplayWidth(dpy, screen) - max_width + gx;
|
|
if (gy >= 0)
|
|
y = gy;
|
|
else
|
|
y = DisplayHeight(dpy, screen) - total_height + gy;
|
|
} else {
|
|
x = (DisplayWidth(dpy, screen) - max_width) / 2;
|
|
y = (DisplayHeight(dpy, screen) - total_height) / 2;
|
|
}
|
|
frame = XCreateSimpleWindow(dpy, root, x, y, max_width, total_height,
|
|
0, BlackPixel(dpy, screen), colors[c_back]);
|
|
XSelectInput(dpy, frame, KeyPressMask | ExposureMask);
|
|
XStoreName(dpy, frame, prog_name);
|
|
XSetWMHints(dpy, frame, &wmh);
|
|
sh.x = x, sh.y = y;
|
|
sh.width = max_width, sh.height = total_height;
|
|
XSetWMNormalHints(dpy, frame, &sh);
|
|
|
|
xgcv.foreground = colors[c_fore];
|
|
xgcv.background = colors[c_back];
|
|
xgcv.font = fonts[f_text];
|
|
gc_text = XCreateGC(dpy, frame, xgcv_mask, &xgcv);
|
|
xgcv.background = colors[c_itemback];
|
|
xgcv.foreground = colors[c_itemfore];
|
|
xgcv.font = fonts[f_input];
|
|
gc_input = XCreateGC(dpy, frame, xgcv_mask, &xgcv);
|
|
xgcv.font = fonts[f_button];
|
|
gc_button = XCreateGC(dpy, frame, xgcv_mask, &xgcv);
|
|
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
switch (item->type) {
|
|
case I_INPUT:
|
|
item->header.win =
|
|
XCreateSimpleWindow(dpy, frame,
|
|
item->header.pos_x, item->header.pos_y,
|
|
item->header.size_x, item->header.size_y,
|
|
0, colors[c_back], colors[c_itemback]);
|
|
XSelectInput(dpy, item->header.win, ButtonPressMask | ExposureMask);
|
|
xswa.cursor = xc_ibeam;
|
|
XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
|
|
break;
|
|
case I_CHOICE:
|
|
item->header.win =
|
|
XCreateSimpleWindow(dpy, frame,
|
|
item->header.pos_x, item->header.pos_y,
|
|
item->header.size_y, item->header.size_y,
|
|
0, colors[c_back], colors[c_itemback]);
|
|
XSelectInput(dpy, item->header.win, ButtonPressMask | ExposureMask);
|
|
xswa.cursor = xc_hand;
|
|
XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
|
|
break;
|
|
case I_BUTTON:
|
|
item->header.win =
|
|
XCreateSimpleWindow(dpy, frame,
|
|
item->header.pos_x, item->header.pos_y,
|
|
item->header.size_x, item->header.size_y,
|
|
0, colors[c_back], colors[c_itemback]);
|
|
XSelectInput(dpy, item->header.win,
|
|
ButtonPressMask | ExposureMask);
|
|
xswa.cursor = xc_hand;
|
|
XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
|
|
break;
|
|
}
|
|
}
|
|
Restart();
|
|
XMapRaised(dpy, frame);
|
|
XMapSubwindows(dpy, frame);
|
|
if (warp_pointer) {
|
|
XWarpPointer(dpy, None, frame, 0, 0, 0, 0,
|
|
max_width / 2, total_height - 1);
|
|
}
|
|
DoCommand(&def_button);
|
|
}
|
|
|
|
/* read something from Fvwm */
|
|
void ReadFvwm ()
|
|
{
|
|
static char buffer[32];
|
|
int n;
|
|
|
|
n = read(fd_in, buffer, 32);
|
|
if (n == 0) {
|
|
if (grab_server)
|
|
XUngrabServer(dpy);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
/* read an X event */
|
|
void ReadXServer ()
|
|
{
|
|
static XEvent event;
|
|
int i, old_cursor, keypress;
|
|
Item *item, *old_item;
|
|
KeySym ks;
|
|
char *sp, *dp, *ep;
|
|
static unsigned char buf[10], n;
|
|
|
|
while (XEventsQueued(dpy, QueuedAfterReading)) {
|
|
XNextEvent(dpy, &event);
|
|
if (event.xany.window == frame) {
|
|
switch (event.type) {
|
|
case Expose:
|
|
RedrawFrame();
|
|
if (grab_server && !server_grabbed) {
|
|
if (GrabSuccess ==
|
|
XGrabPointer(dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
|
|
None, None, CurrentTime))
|
|
server_grabbed = 1;
|
|
}
|
|
break;
|
|
case KeyPress: /* we do text input here */
|
|
n = XLookupString(&event.xkey, buf, 10, &ks, NULL);
|
|
keypress = buf[0];
|
|
fprintf(fp_err, "Keypress [%s]\n", buf);
|
|
if (n == 0) { /* not a regular key, translate it into one */
|
|
switch (ks) {
|
|
case XK_Home:
|
|
case XK_Begin:
|
|
buf[0] = '\001'; /* ^A */
|
|
break;
|
|
case XK_End:
|
|
buf[0] = '\005'; /* ^E */
|
|
break;
|
|
case XK_Left:
|
|
buf[0] = '\002'; /* ^B */
|
|
break;
|
|
case XK_Right:
|
|
buf[0] = '\006'; /* ^F */
|
|
break;
|
|
case XK_Up:
|
|
buf[0] = '\020'; /* ^P */
|
|
break;
|
|
case XK_Down:
|
|
buf[0] = '\016'; /* ^N */
|
|
break;
|
|
default:
|
|
if (ks >= XK_F1 && ks <= XK_F35) {
|
|
buf[0] = '\0';
|
|
keypress = 257 + ks - XK_F1;
|
|
} else
|
|
goto no_redraw; /* no action for this event */
|
|
}
|
|
}
|
|
if (!cur_text) { /* no text input fields */
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
fprintf(fp_err, "Button[%d], keypress==%d\n", i,
|
|
item->button.keypress);
|
|
if (item->type == I_BUTTON && item->button.keypress == buf[0]) {
|
|
RedrawItem(item, 1);
|
|
sleep(1);
|
|
RedrawItem(item, 0);
|
|
DoCommand(item);
|
|
goto no_redraw;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
switch (buf[0]) {
|
|
case '\001': /* ^A */
|
|
old_cursor = abs_cursor;
|
|
rel_cursor = 0;
|
|
abs_cursor = 0;
|
|
cur_text->input.left = 0;
|
|
goto redraw_newcursor;
|
|
break;
|
|
case '\005': /* ^E */
|
|
old_cursor = abs_cursor;
|
|
rel_cursor = cur_text->input.n;
|
|
if ((cur_text->input.left = rel_cursor - cur_text->input.size) < 0)
|
|
cur_text->input.left = 0;
|
|
abs_cursor = rel_cursor - cur_text->input.left;
|
|
goto redraw_newcursor;
|
|
break;
|
|
case '\002': /* ^B */
|
|
old_cursor = abs_cursor;
|
|
if (rel_cursor > 0) {
|
|
rel_cursor--;
|
|
abs_cursor--;
|
|
if (abs_cursor <= 0 && rel_cursor > 0) {
|
|
abs_cursor++;
|
|
cur_text->input.left--;
|
|
}
|
|
}
|
|
goto redraw_newcursor;
|
|
break;
|
|
case '\006': /* ^F */
|
|
old_cursor = abs_cursor;
|
|
if (rel_cursor < cur_text->input.n) {
|
|
rel_cursor++;
|
|
abs_cursor++;
|
|
if (abs_cursor >= cur_text->input.size &&
|
|
rel_cursor < cur_text->input.n) {
|
|
abs_cursor--;
|
|
cur_text->input.left++;
|
|
}
|
|
}
|
|
goto redraw_newcursor;
|
|
break;
|
|
case '\010': /* ^H */
|
|
old_cursor = abs_cursor;
|
|
if (rel_cursor > 0) {
|
|
sp = cur_text->input.value + rel_cursor;
|
|
dp = sp - 1;
|
|
for (; *dp = *sp, *sp != '\0'; dp++, sp++);
|
|
cur_text->input.n--;
|
|
rel_cursor--;
|
|
if (rel_cursor < abs_cursor) {
|
|
abs_cursor--;
|
|
if (abs_cursor <= 0 && rel_cursor > 0) {
|
|
abs_cursor++;
|
|
cur_text->input.left--;
|
|
}
|
|
} else
|
|
cur_text->input.left--;
|
|
}
|
|
goto redraw_newcursor;
|
|
break;
|
|
case '\177': /* DEL */
|
|
case '\004': /* ^D */
|
|
if (rel_cursor < cur_text->input.n) {
|
|
sp = cur_text->input.value + rel_cursor + 1;
|
|
dp = sp - 1;
|
|
for (; *dp = *sp, *sp != '\0'; dp++, sp++);
|
|
cur_text->input.n--;
|
|
goto redraw;
|
|
}
|
|
break;
|
|
case '\013': /* ^K */
|
|
cur_text->input.value[rel_cursor] = '\0';
|
|
cur_text->input.n = rel_cursor;
|
|
goto redraw;
|
|
case '\025': /* ^U */
|
|
old_cursor = abs_cursor;
|
|
cur_text->input.value[0] = '\0';
|
|
cur_text->input.n = cur_text->input.left = 0;
|
|
rel_cursor = abs_cursor = 0;
|
|
goto redraw_newcursor;
|
|
case '\t':
|
|
case '\n':
|
|
case '\015':
|
|
case '\016': /* LINEFEED, TAB, RETURN, ^N, jump to the next field */
|
|
for (i = (cur_text - items) + 1; i < n_items; i++) {
|
|
item = items + i;
|
|
if (item->type == I_INPUT) {
|
|
old_item = cur_text;
|
|
old_item->input.o_cursor = rel_cursor;
|
|
cur_text = item;
|
|
RedrawItem(old_item, 1);
|
|
rel_cursor = item->input.o_cursor;
|
|
abs_cursor = rel_cursor - item->input.left;
|
|
goto redraw;
|
|
}
|
|
}
|
|
/* end of all text input fields, check for buttons */
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
fprintf(fp_err, "Button[%d], keypress==%d\n", i,
|
|
item->button.keypress);
|
|
if (item->type == I_BUTTON && item->button.keypress == buf[0]) {
|
|
RedrawItem(item, 1);
|
|
sleep(1);
|
|
RedrawItem(item, 0);
|
|
DoCommand(item);
|
|
goto no_redraw;
|
|
}
|
|
}
|
|
/* goto the first text input field */
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
if (item->type == I_INPUT) {
|
|
old_item = cur_text;
|
|
old_item->input.o_cursor = rel_cursor;
|
|
cur_text = item;
|
|
RedrawItem(old_item, 1);
|
|
rel_cursor = item->input.o_cursor;
|
|
abs_cursor = rel_cursor - item->input.left;
|
|
goto redraw;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
old_cursor = abs_cursor;
|
|
if((buf[0] >= ' ' &&
|
|
buf[0] < '\177') ||
|
|
(buf[0] >= 160)) { /* regular or intl char */
|
|
if (++(cur_text->input.n) >= cur_text->input.buf) {
|
|
cur_text->input.buf += cur_text->input.size;
|
|
cur_text->input.value =
|
|
(char *)realloc(cur_text->input.value,
|
|
cur_text->input.buf);
|
|
}
|
|
dp = cur_text->input.value + cur_text->input.n;
|
|
sp = dp - 1;
|
|
ep = cur_text->input.value + rel_cursor;
|
|
for (; *dp = *sp, sp != ep; sp--, dp--);
|
|
*ep = buf[0];
|
|
rel_cursor++;
|
|
abs_cursor++;
|
|
if (abs_cursor >= cur_text->input.size) {
|
|
if (rel_cursor < cur_text->input.n)
|
|
abs_cursor = cur_text->input.size - 1;
|
|
else
|
|
abs_cursor = cur_text->input.size;
|
|
cur_text->input.left = rel_cursor - abs_cursor;
|
|
}
|
|
goto redraw_newcursor;
|
|
}
|
|
/* unrecognized key press, check for buttons */
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
fprintf(fp_err, "Button[%d], keypress==%d\n", i,
|
|
item->button.keypress);
|
|
if (item->type == I_BUTTON && item->button.keypress == keypress) {
|
|
RedrawItem(item, 1);
|
|
sleep(1); /* .5 seconds */
|
|
RedrawItem(item, 0);
|
|
DoCommand(item);
|
|
goto no_redraw;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
redraw_newcursor:
|
|
{
|
|
int x, dy;
|
|
x = BOX_SPC + TEXT_SPC + FontWidth(xfs[f_input]) * old_cursor - 1;
|
|
dy = cur_text->header.size_y - 1;
|
|
XSetForeground(dpy, gc_button, colors[c_itemback]);
|
|
XDrawLine(dpy, cur_text->header.win, gc_button,
|
|
x, BOX_SPC, x, dy - BOX_SPC);
|
|
}
|
|
redraw:
|
|
{
|
|
int len, x, dy;
|
|
len = cur_text->input.n - cur_text->input.left;
|
|
if (len > cur_text->input.size)
|
|
len = cur_text->input.size;
|
|
else
|
|
XDrawImageString(dpy, cur_text->header.win, gc_input,
|
|
BOX_SPC + TEXT_SPC +
|
|
FontWidth(xfs[f_input]) * len,
|
|
BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
|
|
cur_text->input.blanks,
|
|
cur_text->input.size - len);
|
|
XDrawImageString(dpy, cur_text->header.win, gc_input,
|
|
BOX_SPC + TEXT_SPC,
|
|
BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
|
|
cur_text->input.value + cur_text->input.left, len);
|
|
x = BOX_SPC + TEXT_SPC + FontWidth(xfs[f_input]) * abs_cursor - 1;
|
|
dy = cur_text->header.size_y - 1;
|
|
XDrawLine(dpy, cur_text->header.win, gc_input,
|
|
x, BOX_SPC, x, dy - BOX_SPC);
|
|
}
|
|
no_redraw:
|
|
break; /* end of case KeyPress */
|
|
} /* end of switch (event.type) */
|
|
continue;
|
|
} /* end of if (event.xany.window == frame) */
|
|
for (i = 0; i < n_items; i++) {
|
|
item = items + i;
|
|
if (event.xany.window == item->header.win) {
|
|
switch (event.type) {
|
|
case Expose:
|
|
RedrawItem(item, 0);
|
|
break;
|
|
case ButtonPress:
|
|
if (item->type == I_INPUT) {
|
|
old_item = cur_text;
|
|
old_item->input.o_cursor = rel_cursor;
|
|
cur_text = item;
|
|
RedrawItem(old_item, 1);
|
|
abs_cursor = (event.xbutton.x - BOX_SPC -
|
|
TEXT_SPC + FontWidth(xfs[f_input]) / 2)
|
|
/ FontWidth(xfs[f_input]);
|
|
if (abs_cursor < 0)
|
|
abs_cursor = 0;
|
|
if (abs_cursor > item->input.size)
|
|
abs_cursor = item->input.size;
|
|
rel_cursor = abs_cursor + item->input.left;
|
|
if (rel_cursor < 0)
|
|
rel_cursor = 0;
|
|
if (rel_cursor > item->input.n)
|
|
rel_cursor = item->input.n;
|
|
if (rel_cursor > 0 && rel_cursor == item->input.left)
|
|
item->input.left--;
|
|
if (rel_cursor < item->input.n &&
|
|
rel_cursor == item->input.left + item->input.size)
|
|
item->input.left++;
|
|
abs_cursor = rel_cursor - item->input.left;
|
|
RedrawItem(item, 0);
|
|
}
|
|
if (item->type == I_CHOICE)
|
|
ToggleChoice(item);
|
|
if (item->type == I_BUTTON) {
|
|
RedrawItem(item, 1);
|
|
XGrabPointer(dpy, item->header.win, False, ButtonReleaseMask,
|
|
GrabModeAsync, GrabModeAsync,
|
|
None, None, CurrentTime);
|
|
}
|
|
break;
|
|
case ButtonRelease:
|
|
RedrawItem(item, 0);
|
|
if (grab_server && server_grabbed) {
|
|
XGrabPointer(dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
|
|
None, None, CurrentTime);
|
|
XFlush(dpy);
|
|
} else {
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
XFlush(dpy);
|
|
}
|
|
if (event.xbutton.x >= 0 &&
|
|
event.xbutton.x < item->header.size_x &&
|
|
event.xbutton.y >= 0 &&
|
|
event.xbutton.y < item->header.size_y) {
|
|
DoCommand(item);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} /* end of for (i = 0 */
|
|
} /* while loop */
|
|
}
|
|
|
|
/* main event loop */
|
|
void MainLoop ()
|
|
{
|
|
fd_set fds;
|
|
|
|
while (1) {
|
|
FD_ZERO(&fds);
|
|
FD_SET(fd_in, &fds);
|
|
FD_SET(fd_x, &fds);
|
|
|
|
XFlush(dpy);
|
|
if (select(32, &fds, NULL, NULL, NULL) > 0) {
|
|
if (FD_ISSET(fd_in, &fds))
|
|
ReadFvwm();
|
|
if (FD_ISSET(fd_x, &fds))
|
|
ReadXServer();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* main procedure */
|
|
int main (int argc, char **argv)
|
|
{
|
|
FILE *fdopen();
|
|
int i;
|
|
|
|
buf = (char *)malloc(N); /* some kludge */
|
|
|
|
#ifdef DEBUG
|
|
fd_err = open(".FvwmFormErrors", O_WRONLY | O_CREAT, 0777);
|
|
fp_err = fdopen(fd_err, "w");
|
|
#else
|
|
fd_err = open("/dev/null", O_WRONLY, 0);
|
|
fp_err = fdopen(fd_err, "w");
|
|
#endif
|
|
|
|
/* we get rid of the path from program name */
|
|
prog_name = argv[0];
|
|
i = strlen(prog_name);
|
|
while (prog_name[--i] != '/' && i > 0);
|
|
if (i > 0)
|
|
prog_name = prog_name + (i + 1);
|
|
fprintf(fp_err, "%s started...\n", prog_name);
|
|
|
|
if (argc < 6) {
|
|
#ifndef DEBUG
|
|
fprintf(fp_err, "%s must be started by Fvwm.\n", prog_name);
|
|
exit(1);
|
|
#else
|
|
fd_out = 1;
|
|
fd_in = 0;
|
|
ref = None;
|
|
#endif
|
|
} else {
|
|
if(argc==7)
|
|
prog_name = argv[6];
|
|
fd_out = atoi(argv[1]);
|
|
fd_in = atoi(argv[2]);
|
|
ref = strtol(argv[4], NULL, 16);
|
|
if (ref == 0) ref = None;
|
|
#ifdef DEBUG
|
|
fprintf(fp_err, "ref == %d\n", ref);
|
|
#endif
|
|
}
|
|
|
|
fd[0]=fd_out;
|
|
fd[1]=fd_in;
|
|
|
|
if (!(dpy = XOpenDisplay(NULL))) {
|
|
fprintf(fp_err, "%s: can't open display.\n", prog_name);
|
|
exit(1);
|
|
}
|
|
fd_x = XConnectionNumber(dpy);
|
|
|
|
screen = DefaultScreen(dpy);
|
|
root = RootWindow(dpy, screen);
|
|
scr_depth = DefaultDepth(dpy, screen);
|
|
d_cmap = DefaultColormap(dpy, screen);
|
|
|
|
ReadConfig();
|
|
|
|
GetColors();
|
|
|
|
OpenWindows();
|
|
|
|
MainLoop();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void DeadPipe(int nonsense)
|
|
{
|
|
exit(0);
|
|
}
|