From e87b0d408c8bef387afb069e25028d9a52c58a62 Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Fri, 14 Nov 2003 16:49:23 +0000 Subject: Initial revision --- Tests | 15 +++ Xmessage-color.ad | 44 +++++++ Xmessage.ad | 6 + makeform.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++ readfile.c | 134 +++++++++++++++++++++ xmessage.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ xmessage.man | 178 +++++++++++++++++++++++++++ 7 files changed, 1079 insertions(+) create mode 100644 Tests create mode 100644 Xmessage-color.ad create mode 100644 Xmessage.ad create mode 100644 makeform.c create mode 100644 readfile.c create mode 100644 xmessage.c create mode 100644 xmessage.man diff --git a/Tests b/Tests new file mode 100644 index 0000000..296a1c1 --- /dev/null +++ b/Tests @@ -0,0 +1,15 @@ +#! /bin/sh -v +# $XConsortium: Tests,v 1.3 94/06/03 15:58:32 gildea Exp $ +xmessage this is standard usage, message on the command line +echo this is a message from standard input | xmessage -file - +xmessage -file Imakefile -buttons print,me -print +# a file so long it requires a scrollbar +xmessage -file xmessage.c +xmessage -buttons "" no buttons, use delete window from window manager +xmessage -buttons default,other -default default Type Return for the default +xmessage -buttons many,buttons,determining,the,size,of,the,window short msg +xmessage -buttons 14:14,102,3:3,27:27,105 pick a number; echo you picked $? +# fun with resources... +xmessage -buttons "" -xrm '*message.borderWidth: 0' \ + -xrm '*Translations: #override : exit(0)' \ + click here to dismiss diff --git a/Xmessage-color.ad b/Xmessage-color.ad new file mode 100644 index 0000000..e8a2e4c --- /dev/null +++ b/Xmessage-color.ad @@ -0,0 +1,44 @@ +! $XFree86: xc/programs/xmessage/Xmessage-color.ad,v 1.1 2002/10/15 02:26:12 dawes Exp $ + +#include "Xmessage" + +*background: gray85 +*foreground: gray15 + +*Scrollbar.thumb: vlines2 +*Scrollbar.width: 14 +*Scrollbar.foreground: rgb:a/5/5 +*Scrollbar.borderWidth: 0 +*Scrollbar.displayList:\ +foreground gray90;\ +lines 1,-1,-1,-1,-1,1;\ +foreground gray60;\ +lines -1,0,0,0,0,-1 + +*Text.?.cursorColor: rgb:d/5/5 +*Text.borderColor: gray80 +*Text*background: gray96 +*Text*Scrollbar.background: gray80 +*Text.displayList:\ +foreground gray90;\ +lines 1,-1,-1,-1,-1,1;\ +foreground gray60;\ +lines -1,0,0,0,0,-1 + +*Command.highlightThickness: 2 +*Command.internalWidth: 5 +*Command.internalHeight: 3 +*Command.borderColor: gray40 +*Command.shapeStyle: Rectangle +*Command.background: gray80 +*Command.displayList:\ +foreground gray60;\ +lines 1,-1,-1,-1,-1,1;\ +foreground gray90;\ +lines -1,0,0,0,0,-1 + +*Form.displayList:\ +foreground gray60;\ +lines 1,-1,-1,-1,-1,1;\ +foreground gray90;\ +lines -1,0,0,0,0,-1 diff --git a/Xmessage.ad b/Xmessage.ad new file mode 100644 index 0000000..1028ed2 --- /dev/null +++ b/Xmessage.ad @@ -0,0 +1,6 @@ +! $XConsortium: Xmessage.ad,v 1.3 94/07/26 20:23:17 gildea Exp $ +*baseTranslations: #override :Return: default-exit() +*message.scrollVertical: Always +*message.scrollHorizontal: Never +*Command.shapeStyle: oval +*Command.highlightThickness: 1 diff --git a/makeform.c b/makeform.c new file mode 100644 index 0000000..3820ebb --- /dev/null +++ b/makeform.c @@ -0,0 +1,347 @@ +/* $XConsortium: makeform.c,v 1.6 95/01/04 16:28:51 gildea Exp $ */ +/* + +Copyright (c) 1988, 1991 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ +/* $XFree86: xc/programs/xmessage/makeform.c,v 1.6 2002/11/22 03:56:39 paulo Exp $ */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern const char *ProgramName; +extern int default_exitstatus; + +typedef struct _ButtonRecord { + char *name; + int exitstatus; + Boolean print_value; + Widget widget; +} ButtonRecord; + +static void unquote_pairs (br, n) + register ButtonRecord *br; + int n; +{ + int i; + + for (i = 0; i < n; i++) { + register char *dst, *src; + register int quoted = 0; + + for (src = dst = br->name; *src; src++) { + if (quoted) { + *dst++ = *src; + quoted = 0; + } else if (src[0] == '\\') { + quoted = 1; + } else { + *dst++ = *src; + } + } + *dst = '\0'; + } + return; +} + +/* + * parses string of form "yes:11,no:12, ..." + * sets brptr to point to parsed table + * returns 0 if successful, -1 if not + */ +static int parse_name_and_exit_code_list (buttonlist, brptr) + char *buttonlist; + ButtonRecord **brptr; +{ + register char *cp; + int shouldfind = 0, npairs = 0; + int default_exitcode = 100; + int quoted = 0; + ButtonRecord *br; + int len; + char *copy; + + if (!buttonlist) return 0; + + /* + * Figure out how many matches we will find so that we can preallocate + * space for button structures. If you add stripping of white space, + * make sure that you update this as well as the walking algorithm below. + */ + if (buttonlist[0]) shouldfind++; + for (cp = buttonlist; *cp; cp++) { + if (quoted == 1) quoted = 0; + else if (*cp == '\\') quoted = 1; + else if (*cp == ',') shouldfind++; + } + len = (cp - buttonlist); + + /* + * allocate space for button record + */ + br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind); + if (!br) return -1; + + cp = malloc (len + 1); + if (!cp) { + (void) free ((char *) br); + return -1; + } + copy = cp; + strcpy (copy, buttonlist); + + + /* + * walk down list separating into name:exitcode pairs + */ + while (*cp) { + char *start, *colon, *comma; + int exitcode; + + start = cp; + colon = comma = NULL; + exitcode = ++default_exitcode; + quoted = 0; + + /* find the next name and exit code */ + for (; *cp; cp++) { + if (quoted) quoted = 0; + else if (*cp == '\\') quoted = 1; + else if (*cp == ':') colon = cp; + else if (*cp == ',') { + comma = cp; + break; + } + } + + /* + * If comma is NULL then we are at the end of the string. If colon + * is NULL, then there was no exit code given, so default to zero. + */ + + if (comma) *comma = '\0'; + + if (colon) { + exitcode = atoi (colon+1); + *colon = '\0'; + } + + /* + * make sure that we aren't about to stomp on memory + */ + if (npairs >= shouldfind) { + fprintf (stderr, + "%s: internal error, found extra pairs (should be %d)\n", + ProgramName, shouldfind); + (void) free ((char *) br); + (void) free (copy); + return -1; + } + + /* + * got it! start and exitcode contain the right values + */ + br[npairs].name = start; + br[npairs].exitstatus = exitcode; + npairs++; + + if (comma) cp++; + } + + + if (npairs != shouldfind) { + fprintf (stderr, "%s: internal error found %d instead of %d pairs\n", + ProgramName, npairs, shouldfind); + (void) free ((char *) br); + (void) free (copy); + return -1; + } + + /* + * now, strip any quoted characters + */ + unquote_pairs (br, npairs); + *brptr = br; + return npairs; +} + +/* ARGSUSED */ +static void handle_button (w, closure, client_data) + Widget w; + XtPointer closure; + XtPointer client_data; +{ + ButtonRecord *br = (ButtonRecord *) closure; + + if (br->print_value) + puts (br->name); + exit (br->exitstatus); +} + +Widget make_queryform(parent, msgstr, msglen, + button_list, print_value, default_button, + max_width, max_height) + Widget parent; /* into whom widget should be placed */ + char *msgstr; /* message string */ + int msglen; /* characters in msgstr */ + char *button_list; /* list of button title:status */ + Boolean print_value; /* print button string on stdout? */ + char *default_button; /* button activated by Return */ + Dimension max_width; + Dimension max_height; +{ + ButtonRecord *br; + int npairs, i; + Widget form, text, prev; + Arg args[10]; + Cardinal n, thisn; + char *shell_geom; + int x, y, geom_flags; + unsigned int shell_w, shell_h; + + npairs = parse_name_and_exit_code_list (button_list, &br); + + form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0); + + text = XtVaCreateManagedWidget + ("message", asciiTextWidgetClass, form, + XtNleft, XtChainLeft, + XtNright, XtChainRight, + XtNtop, XtChainTop, + XtNbottom, XtChainBottom, + XtNdisplayCaret, False, + XtNlength, msglen, + XtNstring, msgstr, + NULL); + /* + * Did the user specify our geometry? + * If so, don't bother computing it ourselves, since we will be overridden. + */ + XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL); + geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h); + if (!(geom_flags & WidthValue && geom_flags & HeightValue)) { + Dimension width, height, height_addons = 0; + Dimension scroll_size, border_width; + Widget label, scroll; + Position left, right, top, bottom; + char *tmp; + /* + * A Text widget is used for the automatic scroll bars. + * But Text widget doesn't automatically compute its size. + * The Label widget does that nicely, so we create one and examine it. + * This widget is never visible. + */ + XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom, + XtNleftMargin, &left, XtNrightMargin, &right, NULL); + label = XtVaCreateWidget("message", labelWidgetClass, form, + XtNlabel, msgstr, + XtNinternalWidth, (left+right+1)/2, + XtNinternalHeight, (top+bottom+1)/2, + NULL); + XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL); + XtDestroyWidget(label); + if (max_width == 0) + max_width = .7 * WidthOfScreen(XtScreen(text)); + if (max_height == 0) + max_height = .7 * HeightOfScreen(XtScreen(text)); + if (width > max_width) { + width = max_width; + /* add in the height of any horizontal scroll bar */ + scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text, + XtNorientation, XtorientHorizontal, + NULL); + XtVaGetValues(scroll, XtNheight, &scroll_size, + XtNborderWidth, &border_width, NULL); + XtDestroyWidget(scroll); + height_addons = scroll_size + border_width; + } + + /* This fixes the xmessage assumption that the label widget and the + * text widget have the same size. In Xaw 7, the text widget has + * one extra pixel between lines. + * Xmessage is not internationalized, so the code bellow is harmless. + */ + tmp = msgstr; + while (tmp != NULL && *tmp) { + ++tmp; + ++height; + tmp = strchr(tmp, '\n'); + } + + if (height > max_height) { + height = max_height; + /* add in the width of any vertical scroll bar */ + scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text, + XtNorientation, XtorientVertical, NULL); + XtVaGetValues(scroll, XtNwidth, &scroll_size, + XtNborderWidth, &border_width, NULL); + XtDestroyWidget(scroll); + width += scroll_size + border_width; + } + height += height_addons; + XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL); + } + /* + * Create the buttons + */ + n = 0; + XtSetArg (args[n], XtNleft, XtChainLeft); n++; + XtSetArg (args[n], XtNright, XtChainLeft); n++; + XtSetArg (args[n], XtNtop, XtChainBottom); n++; + XtSetArg (args[n], XtNbottom, XtChainBottom); n++; + XtSetArg (args[n], XtNfromVert, text); n++; + XtSetArg (args[n], XtNvertDistance, 5); n++; + + prev = NULL; + for (i = 0; i < npairs; i++) { + thisn = n; + XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++; + prev = XtCreateManagedWidget (br[i].name, commandWidgetClass, + form, args, thisn); + br[i].widget = prev; + br[i].print_value = print_value; + XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]); + if (default_button && !strcmp(default_button, br[i].name)) { + Dimension border; + + default_exitstatus = br[i].exitstatus; + XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL); + border *= 2; + XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL); + } + } + return form; +} diff --git a/readfile.c b/readfile.c new file mode 100644 index 0000000..f8683be --- /dev/null +++ b/readfile.c @@ -0,0 +1,134 @@ +/* $XConsortium: readfile.c,v 1.5 94/12/11 14:25:48 gildea Exp $ */ +/* + +Copyright (c) 1988, 1991 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ +/* $XFree86: xc/programs/xmessage/readfile.c,v 1.2 2000/02/14 19:21:04 dawes Exp $ */ + +#include /* for types.h */ +#include +#include +#include + +/* + * get_data_from_file - read data from a file into a single buffer; meant + * for small files containing messages. + */ +static char *get_data_from_file (filename, len_return) + char *filename; + int *len_return; +{ + FILE *fp; + struct stat statbuf; + char *cp; + int count; + + if (stat (filename, &statbuf) != 0 || statbuf.st_size < 0) { + perror(filename); + return NULL; + } + + cp = malloc (statbuf.st_size + 1); + if (!cp) { + fprintf(stderr, "cannot get memory for message file\n"); + return NULL; + } + + fp = fopen (filename, "r"); + if (!fp) { + perror(filename); + (void) free (cp); + return NULL; + } + + count = fread (cp, 1, statbuf.st_size, fp); + if (count == 0 && statbuf.st_size != 0) { + perror(filename); + (void) free (cp); + (void) fclose (fp); + return NULL; + } + + cp[count] = '\0'; /* since we allocated one extra */ + *len_return = count; + (void) fclose (fp); + return cp; +} + +/* + * get_data_from_stdin - read data from stdin into a single buffer. + */ +static char *get_data_from_stdin (len_return) + int *len_return; +{ + char *cp; + int count; + int allocated; + int n; + + allocated = BUFSIZ; + cp = malloc (allocated + 1); + if (!cp) { + fprintf(stderr, "cannot get memory for message file\n"); + return NULL; + } + count = 0; + + while ((n = fread (cp + count, 1, BUFSIZ, stdin)) > 0) { + count += n; + /* Here count <= allocated. Prepare for next round. */ + if (count + BUFSIZ > allocated) { + allocated = 2 * allocated; + cp = realloc (cp, allocated + 1); + if (!cp) { + fprintf(stderr, "cannot get memory for message file\n"); + return NULL; + } + } + } + + cp[count] = '\0'; /* since we allocated one extra */ + *len_return = count; + return cp; +} + + +/* + * read_file - read data from indicated file and return pointer to malloced + * buffer. Returns NULL on error or if no such file. + */ +char *read_file (filename, len) + char *filename; + int *len; /* returned */ +{ + if (filename[0] == '-' && filename[1] == '\0') { + return (get_data_from_stdin (len)); + } else { + return (get_data_from_file (filename, len)); + } +} diff --git a/xmessage.c b/xmessage.c new file mode 100644 index 0000000..c5f367c --- /dev/null +++ b/xmessage.c @@ -0,0 +1,355 @@ +static char*id="$XConsortium: xmessage.c,v 1.6 95/01/04 16:29:54 gildea Exp $"; +/* + +Copyright (c) 1988, 1991, 1994 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ +/* $XFree86: xc/programs/xmessage/xmessage.c,v 1.4 2000/02/17 16:53:03 dawes Exp $ */ + +#include +#include +#include +#include +#include + +extern char *read_file(); +extern Widget make_queryform(); + +/* + * data used by xmessage + */ + +const char *ProgramName; + +static struct _QueryResources { + char *file; + char *button_list; + char *default_button; + Boolean print_value; + Boolean center; + Boolean nearmouse; + int timeout_secs; + Dimension maxHeight; + Dimension maxWidth; +} qres; /* initialized by resources below */ + +#define offset(field) XtOffsetOf(struct _QueryResources, field) +static XtResource resources[] = { + { "file", "File", XtRString, sizeof (char *), + offset(file), XtRString, (XtPointer) NULL }, + { "buttons", "Buttons", XtRString, sizeof (char *), + offset(button_list), XtRString, (XtPointer) "okay:0" }, + { "defaultButton", "DefaultButton", XtRString, sizeof (char *), + offset(default_button), XtRString, (XtPointer) NULL }, + { "printValue", "PrintValue", XtRBoolean, sizeof (Boolean), + offset(print_value), XtRString, "false" }, + { "center", "Center", XtRBoolean, sizeof (Boolean), + offset(center), XtRString, "false" }, + { "nearMouse", "NearMouse", XtRBoolean, sizeof (Boolean), + offset(nearmouse), XtRString, "false" }, + { "timeout", "Timeout", XtRInt, sizeof (int), + offset(timeout_secs), XtRInt, 0 }, + { "maxHeight", "Maximum", XtRDimension, sizeof (Dimension), + offset(maxHeight), XtRDimension, 0 }, + { "maxWidth", "Maximum", XtRDimension, sizeof (Dimension), + offset(maxWidth), XtRDimension, 0 }, +}; +#undef offset + +static XrmOptionDescRec optionList[] = { + { "-file", ".file", XrmoptionSepArg, (XPointer) NULL }, + { "-buttons", ".buttons", XrmoptionSepArg, (XPointer) NULL }, + { "-default", ".defaultButton", XrmoptionSepArg, (XPointer) NULL }, + { "-print", ".printValue", XrmoptionNoArg, (XPointer) "on" }, + { "-center", ".center", XrmoptionNoArg, (XPointer) "on" }, + { "-nearmouse", ".nearMouse", XrmoptionNoArg, (XPointer) "on" }, + { "-timeout", ".timeout", XrmoptionSepArg, (XPointer) NULL }, +}; + +static String fallback_resources[] = { + "*baseTranslations: #override :Return: default-exit()", + "*message.Scroll: whenNeeded", + NULL}; + + +/* + * usage + */ + +static void usage (outf) + FILE *outf; +{ + static const char *options[] = { +" -file filename file to read message from, \"-\" for stdin", +" -buttons string comma-separated list of label:exitcode", +" -default button button to activate if Return is pressed", +" -print print the button label when selected", +" -center pop up at center of screen", +" -nearmouse pop up near the mouse cursor", +" -timeout secs exit with status 0 after \"secs\" seconds", +"", +NULL}; + const char **cpp; + + fprintf (outf, "usage: %s [-options] [message ...]\n\n", + ProgramName); + fprintf (outf, "where options include:\n"); + for (cpp = options; *cpp; cpp++) + fprintf (outf, "%s\n", *cpp); + fprintf (outf, "%s\n", id+1); +} + +/* + * Action to implement ICCCM delete_window and other translations. + * Takes one argument, the exit status. + */ +static Atom wm_delete_window; +/* ARGSUSED */ +static void +exit_action(w, event, params, num_params) + Widget w; /* unused */ + XEvent *event; + String *params; + Cardinal *num_params; +{ + int exit_status = 0; + + if(event->type == ClientMessage + && event->xclient.data.l[0] != wm_delete_window) + return; + + if (*num_params == 1) + exit_status = atoi(params[0]); + exit(exit_status); +} + +int default_exitstatus = -1; /* value of button named by -default */ + +/* ARGSUSED */ +static void +default_exit_action(w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + if (default_exitstatus >= 0) + exit(default_exitstatus); +} + +static XtActionsRec actions_list[] = { + {"exit", exit_action}, + {"default-exit", default_exit_action}, +}; + +static String top_trans = + "WM_PROTOCOLS: exit(1)\n"; + +/* assumes shell widget has already been realized */ + +static void +position_near(shell, x, y) + Widget shell; + int x, y; +{ + int max_x, max_y; + Dimension width, height, border; + int gravity; + + /* some of this is copied from CenterWidgetOnPoint in Xaw/TextPop.c */ + + XtVaGetValues(shell, + XtNwidth, &width, + XtNheight, &height, + XtNborderWidth, &border, + NULL); + + width += 2 * border; + height += 2 * border; + + max_x = WidthOfScreen(XtScreen(shell)); + max_y = HeightOfScreen(XtScreen(shell)); + + /* set gravity hint based on position on screen */ + gravity = 1; + if (x > max_x/3) gravity += 1; + if (x > max_x*2/3) gravity += 1; + if (y > max_y/3) gravity += 3; + if (y > max_y*2/3) gravity += 3; + + max_x -= width; + max_y -= height; + + x -= ( (Position) width/2 ); + if (x < 0) x = 0; + if (x > max_x) x = max_x; + + y -= ( (Position) height/2 ); + if (y < 0) y = 0; + if ( y > max_y ) y = max_y; + + XtVaSetValues(shell, + XtNx, (Position)x, + XtNy, (Position)y, + XtNwinGravity, gravity, + NULL); +} + +static void +position_near_mouse(shell) + Widget shell; +{ + int x, y; + Window root, child; + int winx, winy; + unsigned int mask; + + XQueryPointer(XtDisplay(shell), XtWindow(shell), + &root, &child, &x, &y, &winx, &winy, &mask); + position_near(shell, x, y); +} + +static void +position_near_center(shell) + Widget shell; +{ + position_near(shell, + WidthOfScreen(XtScreen(shell))/2, + HeightOfScreen(XtScreen(shell))/2); +} + +/* ARGSUSED */ +static void +time_out(client_data, iid) + XtPointer client_data; + XtIntervalId *iid; +{ + exit(0); +} + +/* + * xmessage main program - make sure that there is a message, + * then create the query box and go. Callbacks take care of exiting. + */ +int +main (argc, argv) + int argc; + char **argv; +{ + Widget top, queryform; + XtAppContext app_con; + char *message_str; + int message_len; + + ProgramName = argv[0]; + + XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); + + top = XtAppInitialize (&app_con, "Xmessage", + optionList, XtNumber(optionList), &argc, argv, + fallback_resources, NULL, 0); + + XtGetApplicationResources (top, (XtPointer) &qres, resources, + XtNumber(resources), NULL, 0); + + if (argc > 1 && !strcmp(argv[1], "-help")) { + usage(stdout); + exit(0); + } + if (argc == 1 && qres.file != NULL) { + message_str = read_file (qres.file, &message_len); + if (message_str == NULL) { + fprintf (stderr, "%s: problems reading message file\n", + ProgramName); + exit (1); + } + } else if (argc > 1 && qres.file == NULL) { + int i, len; + char *cp; + + len = argc - 1; /* spaces between words and final NULL */ + for (i=1; i