/* X11dialogs - Low level dialog objects for X11 */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
/* You may give out copies of this software; for conditions see the */
/* file COPYING included with this distribution. */
/***********************************************************************/
/** **/
/** General Includes and Definitions **/
/** **/
/***********************************************************************/
#include "dialogs.h"
#define NullWindow ((Window) 0)
extern Display *StX11Display();
extern LVAL s_window_id, sk_show_window;
typedef struct {
unsigned long fore, back;
} ColorPair;
/***********************************************************************/
/** **/
/** Global Variables **/
/** **/
/***********************************************************************/
/* configuration parameters - should be set using the defaults database */
static char *DialogFontName = "9x15";
XFontStruct *DialogFont;
unsigned long DialogBorderColor, ButtonBorderColor;
ColorPair DialogC, ButtonC;
unsigned int dialog_border_width, button_border_width, text_border_width,
list_border_width;
int min_button_height, min_button_width, min_toggle_height, min_choice_height,
dialog_item_gap;
GC DialogGC, DialogRGC;
extern XContext EventContext, ObjectContext;
/* forward declarations */
LOCAL int FindItemType _((LVAL item));
LOCAL LVAL frame_handler _((XEvent report, int modal));
LOCAL VOID InstallDialogItems _((Window win, LVAL dialog));
LOCAL VOID InstallItemList _((Window win, LVAL items));
LOCAL VOID InstallItem _((Window win, LVAL item));
LOCAL VOID DeleteDialogItems _((LVAL dialog));
LOCAL VOID DeleteItemList _((Window win, LVAL items));
LOCAL VOID DeleteItem _((Window win, LVAL item));
LOCAL int is_item_window _((Display *dpy, Window event_win, LVAL dialog));
#define TOGGLE_MARK_HEIGHT 16
#define CHOICE_MARK_HEIGHT 16
/* gray stipple pattern bitmap data for scroll bar thumb items */
#define gray_width 16
#define gray_height 16
static unsigned char gray_bits[] = {
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
Pixmap ScrollThumbPM;
/* toggle item bitmaps */
#define toggle_off_width TOGGLE_MARK_HEIGHT
#define toggle_off_height TOGGLE_MARK_HEIGHT
static unsigned char toggle_off_bits[] = {
0xff, 0xff, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xff, 0xff};
Pixmap ToggleOffPM;
#define toggle_on_width CHOICE_MARK_HEIGHT
#define toggle_on_height CHOICE_MARK_HEIGHT
static unsigned char toggle_on_bits[] = {
0xff, 0xff, 0x03, 0xc0, 0x05, 0xa0, 0x09, 0x90, 0x11, 0x88, 0x21, 0x84,
0x41, 0x82, 0x81, 0x81, 0x81, 0x81, 0x41, 0x82, 0x21, 0x84, 0x11, 0x88,
0x09, 0x90, 0x05, 0xa0, 0x03, 0xc0, 0xff, 0xff};
Pixmap ToggleOnPM;
/* choice item bitmaps */
#define choice_off_width 16
#define choice_off_height 16
static unsigned char choice_off_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x08, 0x10,
0xe4, 0x27, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28,
0x14, 0x28, 0xe4, 0x27, 0x08, 0x10, 0xf0, 0x0f};
Pixmap ChoiceOffPM;
#define choice_on_width 16
#define choice_on_height 16
static unsigned char choice_on_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x08, 0x10,
0xe4, 0x27, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f,
0xf4, 0x2f, 0xe4, 0x27, 0x08, 0x10, 0xf0, 0x0f};
Pixmap ChoiceOnPM;
/* slider button pixmap */
#define left_slider_width 16
#define left_slider_height 16
static unsigned char left_slider_bits[] = {
0x00, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0xfc, 0xff,
0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0xfc, 0xff, 0x08, 0x00, 0x10, 0x00,
0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
Pixmap LeftSliderPM;
#define right_slider_width 16
#define right_slider_height 16
static unsigned char right_slider_bits[] = {
0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0xff, 0x3f,
0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0xff, 0x3f, 0x00, 0x10, 0x00, 0x08,
0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
Pixmap RightSliderPM;
extern Cursor ArrowCursor;
Cursor DoubleArrowCursor, RightArrowCursor, LeftArrowCursor;
Cursor UpDownArrowCursor, UpArrowCursor, DownArrowCursor;
/***********************************************************************/
/** **/
/** Utility Functions **/
/** **/
/***********************************************************************/
Point DialogStringSize(s)
char *s;
{
Point pt;
pt.v = DialogFont->max_bounds.ascent + DialogFont->max_bounds.descent;
pt.h = XTextWidth(DialogFont,s, strlen(s));
return(pt);
}
char *checkstring(s)
LVAL s;
{
if (! stringp(s)) xlerror("not a string", s);
return((char *) getstring(s));
}
LVAL StX11ItemObject(dpy, win)
Display *dpy;
Window win;
{
LVAL item, win_id;
win_id = NIL;
if (XFindContext(dpy, win, ObjectContext, (caddr_t *) &item) == 0
&& objectp(item)) {
win_id = slot_value(item, s_window_id);
if (! fixp(win_id)) item = NIL;
}
else item = NIL;
return(item);
}
LOCAL int FindItemType(item)
LVAL item;
{
if (consp(item)) return(ITEM_LIST);
else if (button_item_p(item)) return(BUTTON_ITEM);
else if (toggle_item_p(item)) return(TOGGLE_ITEM);
else if (text_item_p(item)) return(TEXT_ITEM);
else if (choice_item_p(item)) return(CHOICE_ITEM);
else if (scroll_item_p(item)) return(SCROLL_ITEM);
else if (list_item_p(item)) return(LIST_ITEM);
else xlfail("item of unknown type");
/* not reached */
return(0);
}
/***********************************************************************/
/** **/
/** Dialog System Initialization and Cleanup **/
/** **/
/***********************************************************************/
VOID StX11InitDialogs()
{
Display *dpy = StX11Display();
int screen = StX11Screen();
unsigned long valuemask;
XGCValues values;
int font_height, margin;
char *font;
dialog_border_width = 1;
button_border_width = 1;
list_border_width = 1;
text_border_width = 1;
min_button_height = 20;
min_button_width = 100;
dialog_item_gap = 5;
DialogC.fore = BlackPixel(dpy, screen);
DialogC.back = WhitePixel(dpy, screen);
ButtonC.fore = BlackPixel(dpy, screen);
ButtonC.back = WhitePixel(dpy, screen);
DialogBorderColor = BlackPixel(dpy, screen);
ButtonBorderColor = BlackPixel(dpy, screen);
font = StX11GetDefault("xlisp.dialog.font");
if (font == NULL) font = StX11GetDefault("xlisp.font");
if (font == NULL) font = DialogFontName;
if ((DialogFont = XLoadQueryFont(dpy, font)) == NULL) {
fprintf(stderr, "xlisp: Can't open %s font\n", font);
if ((DialogFont = XLoadQueryFont(dpy, DialogFontName)) == NULL) {
fprintf(stderr, "xlisp: Can't open %s font\n", DialogFontName);
if ((DialogFont = XLoadQueryFont(dpy, "fixed")) == NULL) {
fprintf(stderr, "xlisp: Can't open %s font\n", "fixed");
exit(-1);
}
}
}
min_toggle_height = TOGGLE_MARK_HEIGHT + DialogFont->max_bounds.descent;
min_choice_height = CHOICE_MARK_HEIGHT + DialogFont->max_bounds.descent;
ScrollThumbPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
(char *) gray_bits,
gray_width, gray_height,
BlackPixel(dpy, screen),
WhitePixel(dpy, screen),
DefaultDepth(dpy, screen));
ToggleOffPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *) toggle_off_bits,
toggle_off_width, toggle_off_height);
ToggleOnPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *) toggle_on_bits,
toggle_on_width, toggle_on_height);
ChoiceOffPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *) choice_off_bits,
choice_off_width, choice_off_height);
ChoiceOnPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *) choice_on_bits,
choice_on_width, choice_on_height);
LeftSliderPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
(char *) left_slider_bits,
left_slider_width,
left_slider_height,
BlackPixel(dpy, screen),
WhitePixel(dpy, screen),
DefaultDepth(dpy, screen));
RightSliderPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
(char *) right_slider_bits,
right_slider_width,
right_slider_height,
BlackPixel(dpy, screen),
WhitePixel(dpy, screen),
DefaultDepth(dpy, screen));
valuemask = 0; /* ignore XGCValues and use defaults */
DialogGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
XSetFont(dpy, DialogGC, DialogFont->fid);
XSetForeground(dpy, DialogGC, DialogC.fore);
XSetBackground(dpy, DialogGC, DialogC.back);
valuemask = 0; /* ignore XGCValues and use defaults */
DialogRGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
XSetFont(dpy, DialogRGC, DialogFont->fid);
XSetForeground(dpy, DialogRGC, DialogC.back);
XSetBackground(dpy, DialogRGC, DialogC.fore);
font_height = DialogFont->max_bounds.ascent
+ DialogFont->max_bounds.descent;
margin = DialogFont->max_bounds.descent / 2;
if (min_button_height < font_height + 2 * margin)
min_button_height = font_height + 2 * margin;
DoubleArrowCursor = XCreateFontCursor(dpy, XC_sb_h_double_arrow);
RightArrowCursor = XCreateFontCursor(dpy, XC_sb_right_arrow);
LeftArrowCursor = XCreateFontCursor(dpy, XC_sb_left_arrow);
UpDownArrowCursor = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
UpArrowCursor = XCreateFontCursor(dpy, XC_sb_up_arrow);
DownArrowCursor = XCreateFontCursor(dpy, XC_sb_down_arrow);
}
VOID StX11FinishDialogs()
{
Display *dpy = StX11Display();
XUnloadFont(dpy, DialogFont->fid);
XFreeGC(dpy, DialogGC);
XFreePixmap(dpy, ScrollThumbPM);
XFreePixmap(dpy, ToggleOffPM);
XFreePixmap(dpy, ToggleOnPM);
XFreePixmap(dpy, ChoiceOffPM);
XFreePixmap(dpy, ChoiceOnPM);
XFreePixmap(dpy, LeftSliderPM);
XFreePixmap(dpy, RightSliderPM);
XFreeCursor(dpy, DoubleArrowCursor);
XFreeCursor(dpy, RightArrowCursor);
XFreeCursor(dpy, LeftArrowCursor);
XFreeCursor(dpy, UpDownArrowCursor);
XFreeCursor(dpy, UpArrowCursor);
XFreeCursor(dpy, DownArrowCursor);
}
VOID StX11DialogReset(V)
{
Display *dpy = StX11Display();
XUngrabPointer(dpy, CurrentTime);
XSync(dpy, TRUE);
}
/***********************************************************************/
/** **/
/** Constructing and Removing Dialogs **/
/** **/
/***********************************************************************/
LOCAL LVAL frame_handler(report, modal)
XEvent report;
int modal;
{
if (modal) return(NIL);
switch(report.type) {
case ClientMessage:
StX11HandleClientMessage(report);
break;
default:
break;
}
return(NIL);
}
VOID DialogAllocate(dialog)
LVAL dialog;
{
char *title;
Point loc, size;
int go_away, modeless;
Window win, panel;
unsigned int width, height, wheight;
int left, top;
XSetWindowAttributes setwinattr;
unsigned long valuemask;
Display *dpy = StX11Display();
int screen = StX11Screen();
if (check_dialog_address(dialog)) DialogRemove(dialog);
if (! stringp(slot_value(dialog, s_title)))
xlerror("not a string", slot_value(dialog, s_title));
title = (char *) getstring(slot_value(dialog, s_title));
loc = ListToPoint(slot_value(dialog, s_location));
size = ListToPoint(slot_value(dialog, s_size));
go_away = (slot_value(dialog, s_go_away) != NIL) ? TRUE : FALSE;
modeless = (slot_value(dialog, s_type) == s_modeless) ? TRUE : FALSE;
/* create opaque dialog window */
left = loc.h; top = loc.v;
width = size.h; height = size.v;
wheight = (modeless && go_away) ? height + ClosePanelHeight() : height;
win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
left, top, width, wheight, dialog_border_width,
DialogBorderColor, DialogC.back);
if (modeless) StX11SetWindowClass(dpy, win);
StX11SetNormalHints(dpy, win, left, top, width, wheight);
if (XSaveContext(dpy, win, EventContext, (caddr_t) frame_handler) != 0)
xlfail("could not install event handler");
if (XSaveContext(dpy, win, ObjectContext, (caddr_t) dialog) != 0)
xlfail("could not install object in window");
if (! modeless) {
if (StX11UseICCCM()) StX11SetTransientHint(dpy, win);
else {
/* set override_redirect and save_under attributes for a modal dialog */
valuemask = CWOverrideRedirect | CWSaveUnder;
setwinattr.override_redirect = TRUE;
setwinattr.save_under = TRUE;
XChangeWindowAttributes(dpy, win, valuemask, &setwinattr);
}
}
XStoreName(dpy, win, title);
set_dialog_address((CPTR) win, dialog);
XDefineCursor(dpy, win, ArrowCursor);
StX11SetStandardHints(dpy, win);
left = 0;
top = (modeless && go_away) ? ClosePanelHeight() : 0;
panel = XCreateSimpleWindow(dpy, win,
left, top, width, height, dialog_border_width,
DialogBorderColor, DialogC.back);
InstallDialogItems(panel, dialog);
if (modeless && go_away) InstallCloseButton(win, dialog);
/* Display (map) the windows */
XMapSubwindows(dpy, panel);
XMapSubwindows(dpy, win);
XMapWindow(dpy, win);
}
VOID DialogRemove(dialog)
LVAL dialog;
{
Window win;
Display *dpy = StX11Display();
if (check_dialog_address(dialog)
&& (win = (Window) GETDIALOGADDRESS(dialog)) != NullWindow) {
if (XDeleteContext(dpy, win, EventContext) != 0)
xlfail("could not delete event context");
if (XDeleteContext(dpy, win, ObjectContext) != 0)
xlfail("could not delete object context");
DeleteDialogItems(dialog);
DeleteCloseButton(win);
XDestroyWindow(dpy, win);
XFlush(dpy);
}
if (objectp(dialog)) standard_hardware_clobber(dialog);
}
VOID DialogSetDefaultButton(dialog, item)
LVAL dialog, item;
{
if (item == NIL || button_item_p(item))
set_slot_value(dialog, s_default_button, item);
}
LOCAL VOID InstallDialogItems(win, dialog)
Window win;
LVAL dialog;
{
LVAL items;
items = slot_value(dialog, s_items);
InstallItemList(win, items);
}
LOCAL VOID InstallItemList(win, items)
Window win;
LVAL items;
{
for (; consp(items); items = cdr(items))
if (consp(car(items))) InstallItemList(win, car(items));
else InstallItem(win, car(items));
}
LOCAL VOID InstallItem(win, item)
Window win;
LVAL item;
{
int type;
if (! dialog_item_p(item)) xlerror("not a dialog item", item);
type = FindItemType(item);
switch (type) {
case BUTTON_ITEM: InstallButtonItem(win, item); break;
case TOGGLE_ITEM: InstallToggleItem(win, item); break;
case CHOICE_ITEM: InstallChoiceItem(win, item); break;
case TEXT_ITEM: InstallTextItem(win, item); break;
case SCROLL_ITEM: InstallScrollItem(win, item); break;
case LIST_ITEM: InstallListItem(win, item); break;
default: xlfail("unkown item type");
}
}
LOCAL VOID DeleteDialogItems(dialog)
LVAL dialog;
{
Window win;
LVAL items;
win = (Window) GETDIALOGADDRESS(dialog);
if (win != NullWindow) {
items = slot_value(dialog, s_items);
DeleteItemList(win, items);
}
}
LOCAL VOID DeleteItemList(win, items)
Window win;
LVAL items;
{
for (; consp(items); items = cdr(items))
if (consp(car(items))) DeleteItemList(win, car(items));
else DeleteItem(win, car(items));
}
LOCAL VOID DeleteItem(win, item)
Window win;
LVAL item;
{
int type;
if (! dialog_item_p(item)) xlerror("not a dialog item", item);
type = FindItemType(item);
switch (type) {
case BUTTON_ITEM: DeleteButtonItem(win, item); break;
case TOGGLE_ITEM: DeleteToggleItem(win, item); break;
case CHOICE_ITEM: DeleteChoiceItem(win, item); break;
case TEXT_ITEM: DeleteTextItem(win, item); break;
case SCROLL_ITEM: DeleteScrollItem(win, item); break;
case LIST_ITEM: DeleteListItem(win, item); break;
default: xlfail("unkown item type");
}
}
/***********************************************************************/
/** **/
/** Modal Dialog Loop **/
/** **/
/***********************************************************************/
LVAL DialogGetModalItem(dialog)
LVAL dialog;
{
Window win, event_win, old_focus_win;
Display *dpy = StX11Display();
XEvent report;
LVAL result = NIL;
LVAL (*callback)();
int old_revert_to, use_icccm;
send_message(dialog, sk_show_window);
win = (Window) GETDIALOGADDRESS(dialog);
if (win != NullWindow) {
StX11ReleaseButton();
use_icccm = StX11UseICCCM();
if (! use_icccm) {
/* set the input focus and grap the pointer */
XGetInputFocus(dpy, &old_focus_win, &old_revert_to);
XSetInputFocus(dpy, win, RevertToPointerRoot, CurrentTime);
XGrabPointer(dpy, win, TRUE, ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
}
/* Loop until button is released, examining each event */
while (result == NIL) {
XNextEvent(dpy, &report);
event_win = report.xany.window;
if (is_item_window(dpy, event_win, dialog)
&& XFindContext(dpy, event_win, EventContext, (caddr_t *) &callback)
== 0
&& callback != NULL)
result = (*callback)(report, TRUE);
else if (report.type == Expose)
StProcessEvent(dpy, report);
else if (report.type == MappingNotify)
XRefreshKeyboardMapping((XMappingEvent *) &report);
}
if (! use_icccm) {
XUngrabPointer(dpy, CurrentTime);
XSetInputFocus(dpy, old_focus_win, old_revert_to, CurrentTime);
}
else StX11FlushStdin();
}
return(result);
}
LOCAL int is_item_window(dpy, event_win, dialog)
Display *dpy;
Window event_win;
LVAL dialog;
{
LVAL item;
if (XFindContext(dpy, event_win, ObjectContext, (caddr_t *) &item) != 0)
return(FALSE);
else if (! objectp(item) || ! dialog_item_p(item)) return(FALSE);
else if (slot_value(item, s_dialog) != dialog) return(FALSE);
else return(TRUE);
}
VOID install_dialog_item_handler(dpy, win, handler, item)
Display *dpy;
Window win;
LVAL (*handler)(), item;
{
if (XSaveContext(dpy, win, EventContext, (caddr_t) handler) != 0)
xlfail("could not install event handler");
}
VOID delete_dialog_item_handler(dpy, win)
Display *dpy;
Window win;
{
if (XDeleteContext(dpy, win, EventContext) != 0)
xlfail("could not delete event context");
}
#ifdef TODO
register dialog with all subwindows; use in modal loop
make hitting return envoke default button for all dialogs
#endif /* TODO */
syntax highlighted by Code2HTML, v. 0.9.1