1100ae103Smrg/* 2100ae103Smrg 3100ae103SmrgCopyright (c) 1988, 1991, 1994 X Consortium 4100ae103Smrg 5100ae103SmrgPermission is hereby granted, free of charge, to any person obtaining 6100ae103Smrga copy of this software and associated documentation files (the 7100ae103Smrg"Software"), to deal in the Software without restriction, including 8100ae103Smrgwithout limitation the rights to use, copy, modify, merge, publish, 9100ae103Smrgdistribute, sublicense, and/or sell copies of the Software, and to 10100ae103Smrgpermit persons to whom the Software is furnished to do so, subject to 11100ae103Smrgthe following conditions: 12100ae103Smrg 13100ae103SmrgThe above copyright notice and this permission notice shall be included 14100ae103Smrgin all copies or substantial portions of the Software. 15100ae103Smrg 16100ae103SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17100ae103SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18100ae103SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19100ae103SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20100ae103SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21100ae103SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22100ae103SmrgOTHER DEALINGS IN THE SOFTWARE. 23100ae103Smrg 24100ae103SmrgExcept as contained in this notice, the name of the X Consortium shall 25100ae103Smrgnot be used in advertising or otherwise to promote the sale, use or 26100ae103Smrgother dealings in this Software without prior written authorization 27100ae103Smrgfrom the X Consortium. 28100ae103Smrg 29100ae103Smrg*/ 30100ae103Smrg/* $XFree86: xc/programs/xmessage/xmessage.c,v 1.4 2000/02/17 16:53:03 dawes Exp $ */ 31100ae103Smrg 3214a67432Smrg#ifdef HAVE_CONFIG_H 3314a67432Smrg# include "config.h" 3414a67432Smrg#endif 3514a67432Smrg 36100ae103Smrg#include <assert.h> 37100ae103Smrg#include <X11/Intrinsic.h> 38100ae103Smrg#include <X11/StringDefs.h> 39100ae103Smrg#include <X11/Shell.h> 40100ae103Smrg#include <stdio.h> 41100ae103Smrg#include <stdlib.h> 42100ae103Smrg 43100ae103Smrg#include "xmessage.h" 44100ae103Smrg#include "readfile.h" 45100ae103Smrg 46100ae103Smrg/* 47100ae103Smrg * data used by xmessage 48100ae103Smrg */ 49100ae103Smrg 50100ae103Smrgconst char *ProgramName; 51100ae103Smrg 52100ae103Smrgstatic struct _QueryResources { 53100ae103Smrg char *file; 54100ae103Smrg char *button_list; 55100ae103Smrg char *default_button; 56100ae103Smrg Boolean print_value; 57100ae103Smrg Boolean center; 58100ae103Smrg Boolean nearmouse; 59100ae103Smrg int timeout_secs; 60100ae103Smrg Dimension maxHeight; 61100ae103Smrg Dimension maxWidth; 62100ae103Smrg} qres; /* initialized by resources below */ 63100ae103Smrg 64100ae103Smrg#define offset(field) XtOffsetOf(struct _QueryResources, field) 65100ae103Smrgstatic XtResource resources[] = { 66100ae103Smrg { "file", "File", XtRString, sizeof (char *), 67100ae103Smrg offset(file), XtRString, (XtPointer) NULL }, 68100ae103Smrg { "buttons", "Buttons", XtRString, sizeof (char *), 69100ae103Smrg offset(button_list), XtRString, (XtPointer) "okay:0" }, 70100ae103Smrg { "defaultButton", "DefaultButton", XtRString, sizeof (char *), 71100ae103Smrg offset(default_button), XtRString, (XtPointer) NULL }, 72100ae103Smrg { "printValue", "PrintValue", XtRBoolean, sizeof (Boolean), 73100ae103Smrg offset(print_value), XtRString, "false" }, 74100ae103Smrg { "center", "Center", XtRBoolean, sizeof (Boolean), 75100ae103Smrg offset(center), XtRString, "false" }, 76100ae103Smrg { "nearMouse", "NearMouse", XtRBoolean, sizeof (Boolean), 77100ae103Smrg offset(nearmouse), XtRString, "false" }, 78100ae103Smrg { "timeout", "Timeout", XtRInt, sizeof (int), 79165cb819Smrg offset(timeout_secs), XtRInt, NULL }, 80100ae103Smrg { "maxHeight", "Maximum", XtRDimension, sizeof (Dimension), 81165cb819Smrg offset(maxHeight), XtRDimension, NULL }, 82100ae103Smrg { "maxWidth", "Maximum", XtRDimension, sizeof (Dimension), 83165cb819Smrg offset(maxWidth), XtRDimension, NULL }, 84100ae103Smrg}; 85100ae103Smrg#undef offset 86100ae103Smrg 87100ae103Smrgstatic XrmOptionDescRec optionList[] = { 88100ae103Smrg { "-file", ".file", XrmoptionSepArg, (XPointer) NULL }, 89100ae103Smrg { "-buttons", ".buttons", XrmoptionSepArg, (XPointer) NULL }, 90100ae103Smrg { "-default", ".defaultButton", XrmoptionSepArg, (XPointer) NULL }, 91100ae103Smrg { "-print", ".printValue", XrmoptionNoArg, (XPointer) "on" }, 92100ae103Smrg { "-center", ".center", XrmoptionNoArg, (XPointer) "on" }, 93100ae103Smrg { "-nearmouse", ".nearMouse", XrmoptionNoArg, (XPointer) "on" }, 94100ae103Smrg { "-timeout", ".timeout", XrmoptionSepArg, (XPointer) NULL }, 95100ae103Smrg}; 96100ae103Smrg 97100ae103Smrgstatic String fallback_resources[] = { 98100ae103Smrg "*baseTranslations: #override :<Key>Return: default-exit()", 99100ae103Smrg "*message.Scroll: whenNeeded", 100100ae103Smrg NULL}; 101100ae103Smrg 102100ae103Smrg 103100ae103Smrg/* 104100ae103Smrg * usage 105100ae103Smrg */ 106100ae103Smrg 107100ae103Smrgstatic void 108100ae103Smrgusage (FILE *outf) 109100ae103Smrg{ 110100ae103Smrg static const char *options[] = { 111100ae103Smrg" -file filename file to read message from, \"-\" for stdin", 112100ae103Smrg" -buttons string comma-separated list of label:exitcode", 113100ae103Smrg" -default button button to activate if Return is pressed", 114100ae103Smrg" -print print the button label when selected", 115100ae103Smrg" -center pop up at center of screen", 116100ae103Smrg" -nearmouse pop up near the mouse cursor", 117100ae103Smrg" -timeout secs exit with status 0 after \"secs\" seconds", 118100ae103Smrg"", 119100ae103SmrgNULL}; 120100ae103Smrg const char **cpp; 121100ae103Smrg 122100ae103Smrg fprintf (outf, "usage: %s [-options] [message ...]\n\n", 123100ae103Smrg ProgramName); 124100ae103Smrg fprintf (outf, "where options include:\n"); 125100ae103Smrg for (cpp = options; *cpp; cpp++) 126100ae103Smrg fprintf (outf, "%s\n", *cpp); 127100ae103Smrg} 128100ae103Smrg 129100ae103Smrg/* 130100ae103Smrg * Action to implement ICCCM delete_window and other translations. 131100ae103Smrg * Takes one argument, the exit status. 132100ae103Smrg */ 133100ae103Smrgstatic Atom wm_delete_window; 134100ae103Smrg/* ARGSUSED */ 135100ae103Smrgstatic void 136100ae103Smrgexit_action(Widget w, XEvent *event, String *params, Cardinal *num_params) 137100ae103Smrg{ 138100ae103Smrg int exit_status = 0; 139100ae103Smrg 140100ae103Smrg if(event->type == ClientMessage 141100ae103Smrg && event->xclient.data.l[0] != wm_delete_window) 142100ae103Smrg return; 143100ae103Smrg 144100ae103Smrg if (*num_params == 1) 145100ae103Smrg exit_status = atoi(params[0]); 146100ae103Smrg exit(exit_status); 147100ae103Smrg} 148100ae103Smrg 149100ae103Smrgint default_exitstatus = -1; /* value of button named by -default */ 150100ae103Smrg 151100ae103Smrg/* ARGSUSED */ 152100ae103Smrgstatic void 153100ae103Smrgdefault_exit_action(Widget w, XEvent *event, String *params, 154100ae103Smrg Cardinal *num_params) 155100ae103Smrg{ 156100ae103Smrg if (default_exitstatus >= 0) 157100ae103Smrg exit(default_exitstatus); 158100ae103Smrg} 159100ae103Smrg 160100ae103Smrg/* Convert tabs to spaces in *messagep,*lengthp, copying to a new block of 161100ae103Smrg memory. */ 162165cb819Smrgstatic void 163100ae103Smrgdetab (char **messagep, int *lengthp) 164100ae103Smrg{ 165100ae103Smrg int i, n, col, psize; 166100ae103Smrg char *p; 167100ae103Smrg 168100ae103Smrg /* count how many tabs there are */ 169100ae103Smrg n = 0; 170100ae103Smrg for (i = 0; i < *lengthp; i++) 171100ae103Smrg if ((*messagep)[i] == '\t') 172100ae103Smrg n++; 173100ae103Smrg 174100ae103Smrg /* length increases by at most seven extra spaces for each tab */ 175100ae103Smrg psize = *lengthp + n*7 + 1; 176100ae103Smrg p = XtMalloc (psize); 177100ae103Smrg 178100ae103Smrg /* convert tabs to spaces, copying into p */ 179100ae103Smrg n = 0; 180100ae103Smrg col = 0; 181100ae103Smrg for (i = 0; i < *lengthp; i++) 182100ae103Smrg { 183100ae103Smrg switch ((*messagep)[i]) { 184100ae103Smrg case '\n': 185100ae103Smrg p[n++] = '\n'; 186100ae103Smrg col = 0; 187100ae103Smrg break; 188100ae103Smrg case '\t': 189100ae103Smrg do 190100ae103Smrg { 191100ae103Smrg p[n++] = ' '; 192100ae103Smrg col++; 193100ae103Smrg } 194100ae103Smrg while ((col % 8) != 0); 195100ae103Smrg break; 196100ae103Smrg default: 197100ae103Smrg p[n++] = (*messagep)[i]; 198100ae103Smrg col++; 199100ae103Smrg break; 200100ae103Smrg } 201100ae103Smrg } 202100ae103Smrg 203100ae103Smrg assert (n < psize); 204100ae103Smrg 205100ae103Smrg /* null-terminator needed by Label widget */ 206100ae103Smrg p[n] = '\0'; 207100ae103Smrg 208100ae103Smrg free (*messagep); 209100ae103Smrg 210100ae103Smrg *messagep = p; 211100ae103Smrg *lengthp = n; 212100ae103Smrg} 213100ae103Smrg 214100ae103Smrgstatic XtActionsRec actions_list[] = { 215100ae103Smrg {"exit", exit_action}, 216100ae103Smrg {"default-exit", default_exit_action}, 217100ae103Smrg}; 218100ae103Smrg 219100ae103Smrgstatic String top_trans = 220100ae103Smrg "<ClientMessage>WM_PROTOCOLS: exit(1)\n"; 221100ae103Smrg 222100ae103Smrg/* assumes shell widget has already been realized */ 223100ae103Smrg 224100ae103Smrgstatic void 225100ae103Smrgposition_near(Widget shell, int x, int y) 226100ae103Smrg{ 227100ae103Smrg int max_x, max_y; 228100ae103Smrg Dimension width, height, border; 229100ae103Smrg int gravity; 230100ae103Smrg 231100ae103Smrg /* some of this is copied from CenterWidgetOnPoint in Xaw/TextPop.c */ 232100ae103Smrg 233100ae103Smrg XtVaGetValues(shell, 234100ae103Smrg XtNwidth, &width, 235100ae103Smrg XtNheight, &height, 236100ae103Smrg XtNborderWidth, &border, 237100ae103Smrg NULL); 238100ae103Smrg 239100ae103Smrg width += 2 * border; 240100ae103Smrg height += 2 * border; 241100ae103Smrg 242100ae103Smrg max_x = WidthOfScreen(XtScreen(shell)); 243100ae103Smrg max_y = HeightOfScreen(XtScreen(shell)); 244100ae103Smrg 245100ae103Smrg /* set gravity hint based on position on screen */ 246100ae103Smrg gravity = 1; 247100ae103Smrg if (x > max_x/3) gravity += 1; 248100ae103Smrg if (x > max_x*2/3) gravity += 1; 249100ae103Smrg if (y > max_y/3) gravity += 3; 250100ae103Smrg if (y > max_y*2/3) gravity += 3; 251100ae103Smrg 252100ae103Smrg max_x -= width; 253100ae103Smrg max_y -= height; 254100ae103Smrg 255100ae103Smrg x -= ( (Position) width/2 ); 256100ae103Smrg if (x < 0) x = 0; 257100ae103Smrg if (x > max_x) x = max_x; 258100ae103Smrg 259100ae103Smrg y -= ( (Position) height/2 ); 260100ae103Smrg if (y < 0) y = 0; 261100ae103Smrg if ( y > max_y ) y = max_y; 262100ae103Smrg 263100ae103Smrg XtVaSetValues(shell, 264100ae103Smrg XtNx, (Position)x, 265100ae103Smrg XtNy, (Position)y, 266100ae103Smrg XtNwinGravity, gravity, 267100ae103Smrg NULL); 268100ae103Smrg} 269100ae103Smrg 270100ae103Smrgstatic void 271100ae103Smrgposition_near_mouse(Widget shell) 272100ae103Smrg{ 273100ae103Smrg int x, y; 274100ae103Smrg Window root, child; 275100ae103Smrg int winx, winy; 276100ae103Smrg unsigned int mask; 277100ae103Smrg 278100ae103Smrg XQueryPointer(XtDisplay(shell), XtWindow(shell), 279100ae103Smrg &root, &child, &x, &y, &winx, &winy, &mask); 280100ae103Smrg position_near(shell, x, y); 281100ae103Smrg} 282100ae103Smrg 283100ae103Smrgstatic void 284100ae103Smrgposition_near_center(Widget shell) 285100ae103Smrg{ 286100ae103Smrg position_near(shell, 287100ae103Smrg WidthOfScreen(XtScreen(shell))/2, 288100ae103Smrg HeightOfScreen(XtScreen(shell))/2); 289100ae103Smrg} 290100ae103Smrg 291100ae103Smrg/* ARGSUSED */ 292100ae103Smrgstatic void 293100ae103Smrgtime_out(XtPointer client_data, XtIntervalId *iid) 294100ae103Smrg{ 295100ae103Smrg exit(0); 296100ae103Smrg} 297100ae103Smrg 298100ae103Smrg/* 299100ae103Smrg * xmessage main program - make sure that there is a message, 300100ae103Smrg * then create the query box and go. Callbacks take care of exiting. 301100ae103Smrg */ 302100ae103Smrgint 303100ae103Smrgmain (int argc, char *argv[]) 304100ae103Smrg{ 305100ae103Smrg Widget top, queryform; 306100ae103Smrg XtAppContext app_con; 307100ae103Smrg char *message_str; 308100ae103Smrg int message_len; 309100ae103Smrg 310100ae103Smrg ProgramName = argv[0]; 311100ae103Smrg 312100ae103Smrg XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); 313100ae103Smrg 31414a67432Smrg /* Handle args that don't require opening a display */ 31514a67432Smrg for (int n = 1; n < argc; n++) { 31614a67432Smrg const char *argn = argv[n]; 31714a67432Smrg /* accept single or double dash for -help & -version */ 31814a67432Smrg if (argn[0] == '-' && argn[1] == '-') { 31914a67432Smrg argn++; 32014a67432Smrg } 32114a67432Smrg if (strcmp (argn, "-help") == 0) { 32214a67432Smrg usage(stdout); 32314a67432Smrg exit(0); 32414a67432Smrg } 32514a67432Smrg if (strcmp (argn, "-version") == 0) { 32614a67432Smrg puts (PACKAGE_STRING); 32714a67432Smrg exit (0); 32814a67432Smrg } 32914a67432Smrg } 33014a67432Smrg 331100ae103Smrg top = XtAppInitialize (&app_con, "Xmessage", 332100ae103Smrg optionList, XtNumber(optionList), &argc, argv, 333100ae103Smrg fallback_resources, NULL, 0); 334100ae103Smrg 335100ae103Smrg XtGetApplicationResources (top, (XtPointer) &qres, resources, 336100ae103Smrg XtNumber(resources), NULL, 0); 337100ae103Smrg 338100ae103Smrg if (argc == 1 && qres.file != NULL) { 339100ae103Smrg message_str = read_file (qres.file, &message_len); 340100ae103Smrg if (message_str == NULL) { 341100ae103Smrg fprintf (stderr, "%s: problems reading message file\n", 342100ae103Smrg ProgramName); 343100ae103Smrg exit (1); 344100ae103Smrg } 345100ae103Smrg } else if (argc > 1 && qres.file == NULL) { 346100ae103Smrg int i, len; 347100ae103Smrg char *cp; 348100ae103Smrg 349100ae103Smrg len = argc - 1; /* spaces between words and final NULL */ 350100ae103Smrg for (i=1; i<argc; i++) 351100ae103Smrg len += strlen(argv[i]); 352100ae103Smrg message_str = malloc(len); 353100ae103Smrg if (!message_str) { 354100ae103Smrg fprintf (stderr, "%s: cannot get memory for message string\n", 355100ae103Smrg ProgramName); 356100ae103Smrg exit (1); 357100ae103Smrg } 358100ae103Smrg cp = message_str; 359100ae103Smrg for (i=1; i<argc; i++) { 360100ae103Smrg strcpy(cp, argv[i]); 361100ae103Smrg cp += strlen(argv[i]); 362100ae103Smrg if (i != argc-1) 363100ae103Smrg *cp++ = ' '; 364100ae103Smrg else 365100ae103Smrg *cp = '\0'; 366100ae103Smrg } 367100ae103Smrg message_len = len; 368100ae103Smrg } else { 36914a67432Smrg fputs("Unknown argument(s):", stderr); 37014a67432Smrg for (int n = 1; n < argc; n++) { 37114a67432Smrg fprintf(stderr, " %s", argv[n]); 37214a67432Smrg } 37314a67432Smrg fputs("\n\n", stderr); 374100ae103Smrg usage(stderr); 375100ae103Smrg exit(1); 376100ae103Smrg } 377100ae103Smrg 378100ae103Smrg wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False); 379100ae103Smrg XtAppAddActions(app_con, actions_list, XtNumber(actions_list)); 380100ae103Smrg XtOverrideTranslations(top, XtParseTranslationTable(top_trans)); 381100ae103Smrg 382100ae103Smrg detab (&message_str, &message_len); 383100ae103Smrg 384100ae103Smrg /* 385100ae103Smrg * create the query form; this is where most of the real work is done 386100ae103Smrg */ 387100ae103Smrg queryform = make_queryform (top, message_str, message_len, 388100ae103Smrg qres.button_list, 389100ae103Smrg qres.print_value, qres.default_button, 390100ae103Smrg qres.maxWidth, qres.maxHeight); 391100ae103Smrg if (!queryform) { 392100ae103Smrg fprintf (stderr, 393100ae103Smrg "%s: unable to create query form with buttons: %s\n", 394100ae103Smrg ProgramName, qres.button_list); 395100ae103Smrg exit (1); 396100ae103Smrg } 397100ae103Smrg 398100ae103Smrg XtSetMappedWhenManaged(top, FALSE); 399100ae103Smrg XtRealizeWidget(top); 400100ae103Smrg 401100ae103Smrg /* do WM_DELETE_WINDOW before map */ 402100ae103Smrg XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window, 1); 403100ae103Smrg 404100ae103Smrg if (qres.center) 405100ae103Smrg position_near_center(top); 406100ae103Smrg else if (qres.nearmouse) 407100ae103Smrg position_near_mouse(top); 408100ae103Smrg 409100ae103Smrg XtMapWidget(top); 410100ae103Smrg 411100ae103Smrg if (qres.timeout_secs) 412100ae103Smrg XtAppAddTimeOut(app_con, 1000*qres.timeout_secs, time_out, NULL); 413100ae103Smrg 414100ae103Smrg XtAppMainLoop(app_con); 415100ae103Smrg 416100ae103Smrg exit (0); 417100ae103Smrg} 418