makeform.c revision 100ae103
1/* $XConsortium: makeform.c,v 1.6 95/01/04 16:28:51 gildea Exp $ */ 2/* 3 4Copyright (c) 1988, 1991 X Consortium 5 6Permission is hereby granted, free of charge, to any person obtaining 7a copy of this software and associated documentation files (the 8"Software"), to deal in the Software without restriction, including 9without limitation the rights to use, copy, modify, merge, publish, 10distribute, sublicense, and/or sell copies of the Software, and to 11permit persons to whom the Software is furnished to do so, subject to 12the following conditions: 13 14The above copyright notice and this permission notice shall be included 15in all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 21OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of the X Consortium shall 26not be used in advertising or otherwise to promote the sale, use or 27other dealings in this Software without prior written authorization 28from the X Consortium. 29 30*/ 31/* $XFree86: xc/programs/xmessage/makeform.c,v 1.6 2002/11/22 03:56:39 paulo Exp $ */ 32 33#include <X11/Intrinsic.h> 34#include <X11/StringDefs.h> 35#include <stdio.h> 36#include <stdlib.h> 37 38#include <X11/Shell.h> 39#include <X11/Xaw/Form.h> 40#include <X11/Xaw/AsciiText.h> 41#include <X11/Xaw/Command.h> 42#include <X11/Xaw/Label.h> 43#include <X11/Xaw/Scrollbar.h> 44 45#include "xmessage.h" 46 47typedef struct _ButtonRecord { 48 char *name; 49 int exitstatus; 50 Boolean print_value; 51 Widget widget; 52} ButtonRecord; 53 54static void 55unquote_pairs (ButtonRecord *br, int n) 56{ 57 int i; 58 59 for (i = 0; i < n; i++) { 60 char *dst, *src; 61 int quoted = 0; 62 63 for (src = dst = br->name; *src; src++) { 64 if (quoted) { 65 *dst++ = *src; 66 quoted = 0; 67 } else if (src[0] == '\\') { 68 quoted = 1; 69 } else { 70 *dst++ = *src; 71 } 72 } 73 *dst = '\0'; 74 } 75 return; 76} 77 78/* 79 * parses string of form "yes:11,no:12, ..." 80 * sets brptr to point to parsed table 81 * returns 0 if successful, -1 if not 82 */ 83static int 84parse_name_and_exit_code_list (char *buttonlist, ButtonRecord **brptr) 85{ 86 char *cp; 87 int shouldfind = 0, npairs = 0; 88 int default_exitcode = 100; 89 int quoted = 0; 90 ButtonRecord *br; 91 int len; 92 char *copy; 93 94 if (!buttonlist) return 0; 95 96 /* 97 * Figure out how many matches we will find so that we can preallocate 98 * space for button structures. If you add stripping of white space, 99 * make sure that you update this as well as the walking algorithm below. 100 */ 101 if (buttonlist[0]) shouldfind++; 102 for (cp = buttonlist; *cp; cp++) { 103 if (quoted == 1) quoted = 0; 104 else if (*cp == '\\') quoted = 1; 105 else if (*cp == ',') shouldfind++; 106 } 107 len = (cp - buttonlist); 108 109 /* 110 * allocate space for button record 111 */ 112 br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind); 113 if (!br) return -1; 114 115 cp = malloc (len + 1); 116 if (!cp) { 117 (void) free ((char *) br); 118 return -1; 119 } 120 copy = cp; 121 strcpy (copy, buttonlist); 122 123 124 /* 125 * walk down list separating into name:exitcode pairs 126 */ 127 while (*cp) { 128 char *start, *colon, *comma; 129 int exitcode; 130 131 start = cp; 132 colon = comma = NULL; 133 exitcode = ++default_exitcode; 134 quoted = 0; 135 136 /* find the next name and exit code */ 137 for (; *cp; cp++) { 138 if (quoted) quoted = 0; 139 else if (*cp == '\\') quoted = 1; 140 else if (*cp == ':') colon = cp; 141 else if (*cp == ',') { 142 comma = cp; 143 break; 144 } 145 } 146 147 /* 148 * If comma is NULL then we are at the end of the string. If colon 149 * is NULL, then there was no exit code given, so default to zero. 150 */ 151 152 if (comma) *comma = '\0'; 153 154 if (colon) { 155 exitcode = atoi (colon+1); 156 *colon = '\0'; 157 } 158 159 /* 160 * make sure that we aren't about to stomp on memory 161 */ 162 if (npairs >= shouldfind) { 163 fprintf (stderr, 164 "%s: internal error, found extra pairs (should be %d)\n", 165 ProgramName, shouldfind); 166 (void) free ((char *) br); 167 (void) free (copy); 168 return -1; 169 } 170 171 /* 172 * got it! start and exitcode contain the right values 173 */ 174 br[npairs].name = start; 175 br[npairs].exitstatus = exitcode; 176 npairs++; 177 178 if (comma) cp++; 179 } 180 181 182 if (npairs != shouldfind) { 183 fprintf (stderr, "%s: internal error found %d instead of %d pairs\n", 184 ProgramName, npairs, shouldfind); 185 (void) free ((char *) br); 186 (void) free (copy); 187 return -1; 188 } 189 190 /* 191 * now, strip any quoted characters 192 */ 193 unquote_pairs (br, npairs); 194 *brptr = br; 195 return npairs; 196} 197 198/* ARGSUSED */ 199static void 200handle_button (Widget w, XtPointer closure, XtPointer client_data) 201{ 202 ButtonRecord *br = (ButtonRecord *) closure; 203 204 if (br->print_value) 205 puts (br->name); 206 exit (br->exitstatus); 207} 208 209Widget 210make_queryform(Widget parent, /* into whom widget should be placed */ 211 char *msgstr, /* message string */ 212 int msglen, /* characters in msgstr */ 213 char *button_list, /* list of button title:status */ 214 Boolean print_value, /* print button string on stdout? */ 215 char *default_button, /* button activated by Return */ 216 Dimension max_width, 217 Dimension max_height) 218{ 219 ButtonRecord *br; 220 int npairs, i; 221 Widget form, text, prev; 222 Arg args[10]; 223 Cardinal n, thisn; 224 char *shell_geom; 225 int x, y, geom_flags; 226 unsigned int shell_w, shell_h; 227 228 npairs = parse_name_and_exit_code_list (button_list, &br); 229 230 form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0); 231 232 text = XtVaCreateManagedWidget 233 ("message", asciiTextWidgetClass, form, 234 XtNleft, XtChainLeft, 235 XtNright, XtChainRight, 236 XtNtop, XtChainTop, 237 XtNbottom, XtChainBottom, 238 XtNdisplayCaret, False, 239 XtNlength, msglen, 240 XtNstring, msgstr, 241 NULL); 242 /* 243 * Did the user specify our geometry? 244 * If so, don't bother computing it ourselves, since we will be overridden. 245 */ 246 XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL); 247 geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h); 248 if (!(geom_flags & WidthValue && geom_flags & HeightValue)) { 249 Dimension width, height, height_addons = 0; 250 Dimension scroll_size, border_width; 251 Widget label, scroll; 252 Position left, right, top, bottom; 253 char *tmp; 254 /* 255 * A Text widget is used for the automatic scroll bars. 256 * But Text widget doesn't automatically compute its size. 257 * The Label widget does that nicely, so we create one and examine it. 258 * This widget is never visible. 259 */ 260 XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom, 261 XtNleftMargin, &left, XtNrightMargin, &right, NULL); 262 label = XtVaCreateWidget("message", labelWidgetClass, form, 263 XtNlabel, msgstr, 264 XtNinternalWidth, (left+right+1)/2, 265 XtNinternalHeight, (top+bottom+1)/2, 266 NULL); 267 XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL); 268 XtDestroyWidget(label); 269 if (max_width == 0) 270 max_width = .7 * WidthOfScreen(XtScreen(text)); 271 if (max_height == 0) 272 max_height = .7 * HeightOfScreen(XtScreen(text)); 273 if (width > max_width) { 274 width = max_width; 275 /* add in the height of any horizontal scroll bar */ 276 scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text, 277 XtNorientation, XtorientHorizontal, 278 NULL); 279 XtVaGetValues(scroll, XtNheight, &scroll_size, 280 XtNborderWidth, &border_width, NULL); 281 XtDestroyWidget(scroll); 282 height_addons = scroll_size + border_width; 283 } 284 285 /* This fixes the xmessage assumption that the label widget and the 286 * text widget have the same size. In Xaw 7, the text widget has 287 * one extra pixel between lines. 288 * Xmessage is not internationalized, so the code bellow is harmless. 289 */ 290 tmp = msgstr; 291 while (tmp != NULL && *tmp) { 292 ++tmp; 293 ++height; 294 tmp = strchr(tmp, '\n'); 295 } 296 297 if (height > max_height) { 298 height = max_height; 299 /* add in the width of any vertical scroll bar */ 300 scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text, 301 XtNorientation, XtorientVertical, NULL); 302 XtVaGetValues(scroll, XtNwidth, &scroll_size, 303 XtNborderWidth, &border_width, NULL); 304 XtDestroyWidget(scroll); 305 width += scroll_size + border_width; 306 } 307 height += height_addons; 308 XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL); 309 } 310 /* 311 * Create the buttons 312 */ 313 n = 0; 314 XtSetArg (args[n], XtNleft, XtChainLeft); n++; 315 XtSetArg (args[n], XtNright, XtChainLeft); n++; 316 XtSetArg (args[n], XtNtop, XtChainBottom); n++; 317 XtSetArg (args[n], XtNbottom, XtChainBottom); n++; 318 XtSetArg (args[n], XtNfromVert, text); n++; 319 XtSetArg (args[n], XtNvertDistance, 5); n++; 320 321 prev = NULL; 322 for (i = 0; i < npairs; i++) { 323 thisn = n; 324 XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++; 325 prev = XtCreateManagedWidget (br[i].name, commandWidgetClass, 326 form, args, thisn); 327 br[i].widget = prev; 328 br[i].print_value = print_value; 329 XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]); 330 if (default_button && !strcmp(default_button, br[i].name)) { 331 Dimension border; 332 333 default_exitstatus = br[i].exitstatus; 334 XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL); 335 border *= 2; 336 XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL); 337 } 338 } 339 return form; 340} 341