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