DRC | 2ff39b8 | 2011-07-28 08:38:59 +0000 | [diff] [blame^] | 1 | // |
| 2 | // "$Id: Fl_arg.cxx 7903 2010-11-28 21:06:39Z matt $" |
| 3 | // |
| 4 | // Optional argument initialization code for the Fast Light Tool Kit (FLTK). |
| 5 | // |
| 6 | // Copyright 1998-2010 by Bill Spitzak and others. |
| 7 | // |
| 8 | // This library is free software; you can redistribute it and/or |
| 9 | // modify it under the terms of the GNU Library General Public |
| 10 | // License as published by the Free Software Foundation; either |
| 11 | // version 2 of the License, or (at your option) any later version. |
| 12 | // |
| 13 | // This library is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | // Library General Public License for more details. |
| 17 | // |
| 18 | // You should have received a copy of the GNU Library General Public |
| 19 | // License along with this library; if not, write to the Free Software |
| 20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 21 | // USA. |
| 22 | // |
| 23 | // Please report all bugs and problems on the following page: |
| 24 | // |
| 25 | // http://www.fltk.org/str.php |
| 26 | // |
| 27 | |
| 28 | // OPTIONAL initialization code for a program using fltk. |
| 29 | // You do not need to call this! Feel free to make up your own switches. |
| 30 | |
| 31 | #include <FL/Fl.H> |
| 32 | #include <FL/x.H> |
| 33 | #include <FL/Fl_Window.H> |
| 34 | #include <FL/Fl_Tooltip.H> |
| 35 | #include <FL/filename.H> |
| 36 | #include <FL/fl_draw.H> |
| 37 | #include <ctype.h> |
| 38 | #include "flstring.h" |
| 39 | |
| 40 | #if defined(WIN32) || defined(__APPLE__) |
| 41 | int XParseGeometry(const char*, int*, int*, unsigned int*, unsigned int*); |
| 42 | # define NoValue 0x0000 |
| 43 | # define XValue 0x0001 |
| 44 | # define YValue 0x0002 |
| 45 | # define WidthValue 0x0004 |
| 46 | # define HeightValue 0x0008 |
| 47 | # define AllValues 0x000F |
| 48 | # define XNegative 0x0010 |
| 49 | # define YNegative 0x0020 |
| 50 | #endif |
| 51 | |
| 52 | static int fl_match(const char *a, const char *s, int atleast = 1) { |
| 53 | const char *b = s; |
| 54 | while (*a && (*a == *b || tolower(*a) == *b)) {a++; b++;} |
| 55 | return !*a && b >= s+atleast; |
| 56 | } |
| 57 | |
| 58 | // flags set by previously parsed arguments: |
| 59 | extern char fl_show_iconic; // in Fl_x.cxx |
| 60 | static char arg_called; |
| 61 | static char return_i; |
| 62 | static const char *name; |
| 63 | static const char *geometry; |
| 64 | static const char *title; |
| 65 | // these are in Fl_get_system_colors and are set by the switches: |
| 66 | extern const char *fl_fg; |
| 67 | extern const char *fl_bg; |
| 68 | extern const char *fl_bg2; |
| 69 | |
| 70 | /** |
| 71 | Parse a single switch from \p argv, starting at word \p i. |
| 72 | Returns the number of words eaten (1 or 2, or 0 if it is not |
| 73 | recognized) and adds the same value to \p i. |
| 74 | |
| 75 | This is the default argument handler used internally by Fl::args(...), |
| 76 | but you can use this function if you prefer to step through the |
| 77 | standard FLTK switches yourself. |
| 78 | |
| 79 | All standard FLTK switches except -bg2 may be abbreviated to just |
| 80 | one letter and case is ignored: |
| 81 | |
| 82 | \li -bg color or -background color |
| 83 | <br> |
| 84 | Sets the background color using Fl::background(). |
| 85 | |
| 86 | \li -bg2 color or -background2 color |
| 87 | <br> |
| 88 | Sets the secondary background color using Fl::background2(). |
| 89 | |
| 90 | \li -display host:n.n |
| 91 | <br> |
| 92 | Sets the X display to use; this option is silently |
| 93 | ignored under WIN32 and MacOS. |
| 94 | |
| 95 | \li -dnd and -nodnd |
| 96 | <br> |
| 97 | Enables or disables drag and drop text operations |
| 98 | using Fl::dnd_text_ops(). |
| 99 | |
| 100 | \li -fg color or -foreground color |
| 101 | <br> |
| 102 | Sets the foreground color using Fl::foreground(). |
| 103 | |
| 104 | \li -geometry WxH+X+Y |
| 105 | <br> |
| 106 | Sets the initial window position and size according |
| 107 | to the standard X geometry string. |
| 108 | |
| 109 | \li -iconic |
| 110 | <br> |
| 111 | Iconifies the window using Fl_Window::iconize(). |
| 112 | |
| 113 | \li -kbd and -nokbd |
| 114 | <br> |
| 115 | Enables or disables visible keyboard focus for |
| 116 | non-text widgets using Fl::visible_focus(). |
| 117 | |
| 118 | \li -name string |
| 119 | <br> |
| 120 | Sets the window class using Fl_Window::xclass(). |
| 121 | |
| 122 | \li -scheme string |
| 123 | <br> |
| 124 | Sets the widget scheme using Fl::scheme(). |
| 125 | |
| 126 | \li -title string |
| 127 | <br> |
| 128 | Sets the window title using Fl_Window::label(). |
| 129 | |
| 130 | \li -tooltips and -notooltips |
| 131 | <br> |
| 132 | Enables or disables tooltips using Fl_Tooltip::enable(). |
| 133 | |
| 134 | |
| 135 | If your program requires other switches in addition to the standard |
| 136 | FLTK options, you will need to pass your own argument handler to |
| 137 | Fl::args(int,char**,int&,Fl_Args_Handler) explicitly. |
| 138 | */ |
| 139 | int Fl::arg(int argc, char **argv, int &i) { |
| 140 | arg_called = 1; |
| 141 | const char *s = argv[i]; |
| 142 | |
| 143 | if (!s) {i++; return 1;} // something removed by calling program? |
| 144 | |
| 145 | // a word that does not start with '-', or a word after a '--', or |
| 146 | // the word '-' by itself all start the "non-switch arguments" to |
| 147 | // a program. Return 0 to indicate that we don't understand the |
| 148 | // word, but set a flag (return_i) so that args() will return at |
| 149 | // that point: |
| 150 | if (s[0] != '-' || s[1] == '-' || !s[1]) {return_i = 1; return 0;} |
| 151 | s++; // point after the dash |
| 152 | |
| 153 | if (fl_match(s, "iconic")) { |
| 154 | fl_show_iconic = 1; |
| 155 | i++; |
| 156 | return 1; |
| 157 | } else if (fl_match(s, "kbd")) { |
| 158 | Fl::visible_focus(1); |
| 159 | i++; |
| 160 | return 1; |
| 161 | } else if (fl_match(s, "nokbd", 3)) { |
| 162 | Fl::visible_focus(0); |
| 163 | i++; |
| 164 | return 1; |
| 165 | } else if (fl_match(s, "dnd", 2)) { |
| 166 | Fl::dnd_text_ops(1); |
| 167 | i++; |
| 168 | return 1; |
| 169 | } else if (fl_match(s, "nodnd", 3)) { |
| 170 | Fl::dnd_text_ops(0); |
| 171 | i++; |
| 172 | return 1; |
| 173 | } else if (fl_match(s, "tooltips", 2)) { |
| 174 | Fl_Tooltip::enable(); |
| 175 | i++; |
| 176 | return 1; |
| 177 | } else if (fl_match(s, "notooltips", 3)) { |
| 178 | Fl_Tooltip::disable(); |
| 179 | i++; |
| 180 | return 1; |
| 181 | } |
| 182 | #ifdef __APPLE__ |
| 183 | // The Finder application in MacOS X passes the "-psn_N_NNNNN" option |
| 184 | // to all apps... |
| 185 | else if (strncmp(s, "psn_", 4) == 0) { |
| 186 | i++; |
| 187 | return 1; |
| 188 | } |
| 189 | #endif // __APPLE__ |
| 190 | |
| 191 | const char *v = argv[i+1]; |
| 192 | if (i >= argc-1 || !v) |
| 193 | return 0; // all the rest need an argument, so if missing it is an error |
| 194 | |
| 195 | if (fl_match(s, "geometry")) { |
| 196 | |
| 197 | int flags, gx, gy; unsigned int gw, gh; |
| 198 | flags = XParseGeometry(v, &gx, &gy, &gw, &gh); |
| 199 | if (!flags) return 0; |
| 200 | geometry = v; |
| 201 | |
| 202 | #if !defined(WIN32) && !defined(__APPLE__) |
| 203 | } else if (fl_match(s, "display", 2)) { |
| 204 | Fl::display(v); |
| 205 | #endif |
| 206 | |
| 207 | } else if (fl_match(s, "title", 2)) { |
| 208 | title = v; |
| 209 | |
| 210 | } else if (fl_match(s, "name", 2)) { |
| 211 | name = v; |
| 212 | |
| 213 | } else if (fl_match(s, "bg2", 3) || fl_match(s, "background2", 11)) { |
| 214 | fl_bg2 = v; |
| 215 | |
| 216 | } else if (fl_match(s, "bg", 2) || fl_match(s, "background", 10)) { |
| 217 | fl_bg = v; |
| 218 | |
| 219 | } else if (fl_match(s, "fg", 2) || fl_match(s, "foreground", 10)) { |
| 220 | fl_fg = v; |
| 221 | |
| 222 | } else if (fl_match(s, "scheme", 1)) { |
| 223 | Fl::scheme(v); |
| 224 | |
| 225 | } else return 0; // unrecognized |
| 226 | |
| 227 | i += 2; |
| 228 | return 2; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | /** |
| 233 | Parse command line switches using the \p cb argument handler. |
| 234 | |
| 235 | Returns 0 on error, or the number of words processed. |
| 236 | |
| 237 | FLTK provides this as an <i>entirely optional</i> command line |
| 238 | switch parser. You don't have to call it if you don't want to. |
| 239 | Everything it can do can be done with other calls to FLTK. |
| 240 | |
| 241 | To use the switch parser, call Fl::args(...) near the start |
| 242 | of your program. This does \b not open the display, instead |
| 243 | switches that need the display open are stashed into static |
| 244 | variables. Then you \b must display your first window by calling |
| 245 | <tt>window->show(argc,argv)</tt>, which will do anything stored |
| 246 | in the static variables. |
| 247 | |
| 248 | Providing an argument handler callback \p cb lets you define |
| 249 | your own switches. It is called with the same \p argc and \p argv, |
| 250 | and with \p i set to the index of the switch to be processed. |
| 251 | The \p cb handler should return zero if the switch is unrecognized, |
| 252 | and not change \p i. It should return non-zero to indicate the |
| 253 | number of words processed if the switch is recognized, i.e. 1 for |
| 254 | just the switch, and more than 1 for the switch plus associated |
| 255 | parameters. \p i should be incremented by the same amount. |
| 256 | |
| 257 | The \p cb handler is called \b before any other tests, so |
| 258 | <i>you can also override any standard FLTK switch</i> |
| 259 | (this is why FLTK can use very short switches instead of |
| 260 | the long ones all other toolkits force you to use). |
| 261 | See Fl::arg() for descriptions of the standard switches. |
| 262 | |
| 263 | On return \p i is set to the index of the first non-switch. |
| 264 | This is either: |
| 265 | |
| 266 | \li The first word that does not start with '-'. |
| 267 | \li The word '-' (used by many programs to name stdin as a file) |
| 268 | \li The first unrecognized switch (return value is 0). |
| 269 | \li \p argc |
| 270 | |
| 271 | The return value is \p i unless an unrecognized switch is found, |
| 272 | in which case it is zero. If your program takes no arguments other |
| 273 | than switches you should produce an error if the return value is less |
| 274 | than \p argc. |
| 275 | |
| 276 | |
| 277 | A usage string is displayed if Fl::args() detects an invalid argument |
| 278 | on the command-line. You can change the message by setting the |
| 279 | Fl::help pointer. |
| 280 | |
| 281 | A very simple command line parser can be found in <tt>examples/howto-parse-args.cxx</tt> |
| 282 | |
| 283 | The simpler Fl::args(int argc, char **argv) form is useful if your program |
| 284 | does not have command line switches of its own. |
| 285 | */ |
| 286 | |
| 287 | int Fl::args(int argc, char** argv, int& i, Fl_Args_Handler cb) { |
| 288 | arg_called = 1; |
| 289 | i = 1; // skip argv[0] |
| 290 | while (i < argc) { |
| 291 | if (cb && cb(argc,argv,i)) continue; |
| 292 | if (!arg(argc,argv,i)) return return_i ? i : 0; |
| 293 | } |
| 294 | return i; |
| 295 | } |
| 296 | |
| 297 | // show a main window, use any parsed arguments |
| 298 | void Fl_Window::show(int argc, char **argv) { |
| 299 | if (argc && !arg_called) Fl::args(argc,argv); |
| 300 | |
| 301 | Fl::get_system_colors(); |
| 302 | |
| 303 | #if !defined(WIN32) && !defined(__APPLE__) |
| 304 | // Get defaults for drag-n-drop and focus... |
| 305 | const char *key = 0, *val; |
| 306 | |
| 307 | if (Fl::first_window()) key = Fl::first_window()->xclass(); |
| 308 | if (!key) key = "fltk"; |
| 309 | |
| 310 | val = XGetDefault(fl_display, key, "dndTextOps"); |
| 311 | if (val) Fl::dnd_text_ops(strcasecmp(val, "true") == 0 || |
| 312 | strcasecmp(val, "on") == 0 || |
| 313 | strcasecmp(val, "yes") == 0); |
| 314 | |
| 315 | val = XGetDefault(fl_display, key, "tooltips"); |
| 316 | if (val) Fl_Tooltip::enable(strcasecmp(val, "true") == 0 || |
| 317 | strcasecmp(val, "on") == 0 || |
| 318 | strcasecmp(val, "yes") == 0); |
| 319 | |
| 320 | val = XGetDefault(fl_display, key, "visibleFocus"); |
| 321 | if (val) Fl::visible_focus(strcasecmp(val, "true") == 0 || |
| 322 | strcasecmp(val, "on") == 0 || |
| 323 | strcasecmp(val, "yes") == 0); |
| 324 | #endif // !WIN32 && !__APPLE__ |
| 325 | |
| 326 | // set colors first, so background_pixel is correct: |
| 327 | static char beenhere; |
| 328 | if (!beenhere) { |
| 329 | if (geometry) { |
| 330 | int fl = 0, gx = x(), gy = y(); unsigned int gw = w(), gh = h(); |
| 331 | fl = XParseGeometry(geometry, &gx, &gy, &gw, &gh); |
| 332 | if (fl & XNegative) gx = Fl::w()-w()+gx; |
| 333 | if (fl & YNegative) gy = Fl::h()-h()+gy; |
| 334 | // int mw,mh; minsize(mw,mh); |
| 335 | // if (mw > gw) gw = mw; |
| 336 | // if (mh > gh) gh = mh; |
| 337 | Fl_Widget *r = resizable(); |
| 338 | if (!r) resizable(this); |
| 339 | // for WIN32 we assume window is not mapped yet: |
| 340 | if (fl & (XValue | YValue)) |
| 341 | x(-1), resize(gx,gy,gw,gh); |
| 342 | else |
| 343 | size(gw,gh); |
| 344 | resizable(r); |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | // set the class, which is used by X version of get_system_colors: |
| 349 | if (name) {xclass(name); name = 0;} |
| 350 | else if (!xclass()) xclass(fl_filename_name(argv[0])); |
| 351 | |
| 352 | if (title) {label(title); title = 0;} |
| 353 | else if (!label()) label(xclass()); |
| 354 | |
| 355 | if (!beenhere) { |
| 356 | beenhere = 1; |
| 357 | Fl::scheme(Fl::scheme()); // opens display! May call Fl::fatal() |
| 358 | } |
| 359 | |
| 360 | // Show the window AFTER we have set the colors and scheme. |
| 361 | show(); |
| 362 | |
| 363 | #if !defined(WIN32) && !defined(__APPLE__) |
| 364 | // set the command string, used by state-saving window managers: |
| 365 | int j; |
| 366 | int n=0; for (j=0; j<argc; j++) n += strlen(argv[j])+1; |
| 367 | char *buffer = new char[n]; |
| 368 | char *p = buffer; |
| 369 | for (j=0; j<argc; j++) for (const char *q = argv[j]; (*p++ = *q++);); |
| 370 | XChangeProperty(fl_display, fl_xid(this), XA_WM_COMMAND, XA_STRING, 8, 0, |
| 371 | (unsigned char *)buffer, p-buffer-1); |
| 372 | delete[] buffer; |
| 373 | #endif // !WIN32 && !__APPLE__ |
| 374 | } |
| 375 | |
| 376 | // Calls useful for simple demo programs, with automatic help message: |
| 377 | |
| 378 | static const char * const helpmsg = |
| 379 | "options are:\n" |
| 380 | " -bg2 color\n" |
| 381 | " -bg color\n" |
| 382 | " -di[splay] host:n.n\n" |
| 383 | " -dn[d]\n" |
| 384 | " -fg color\n" |
| 385 | " -g[eometry] WxH+X+Y\n" |
| 386 | " -i[conic]\n" |
| 387 | " -k[bd]\n" |
| 388 | " -na[me] classname\n" |
| 389 | " -nod[nd]\n" |
| 390 | " -nok[bd]\n" |
| 391 | " -not[ooltips]\n" |
| 392 | " -s[cheme] scheme\n" |
| 393 | " -ti[tle] windowtitle\n" |
| 394 | " -to[oltips]"; |
| 395 | |
| 396 | const char * const Fl::help = helpmsg+13; |
| 397 | |
| 398 | /** |
| 399 | Parse all command line switches matching standard FLTK options only. |
| 400 | |
| 401 | It parses all the switches, and if any are not recognized it calls |
| 402 | Fl::abort(Fl::help), i.e. unlike the long form, an unrecognized |
| 403 | switch generates an error message and causes the program to exit. |
| 404 | |
| 405 | */ |
| 406 | void Fl::args(int argc, char **argv) { |
| 407 | int i; if (Fl::args(argc,argv,i) < argc) Fl::error(helpmsg); |
| 408 | } |
| 409 | |
| 410 | #if defined(WIN32) || defined(__APPLE__) |
| 411 | |
| 412 | /* the following function was stolen from the X sources as indicated. */ |
| 413 | |
| 414 | /* Copyright Massachusetts Institute of Technology 1985, 1986, 1987 */ |
| 415 | /* $XConsortium: XParseGeom.c,v 11.18 91/02/21 17:23:05 rws Exp $ */ |
| 416 | |
| 417 | /* |
| 418 | Permission to use, copy, modify, distribute, and sell this software and its |
| 419 | documentation for any purpose is hereby granted without fee, provided that |
| 420 | the above copyright notice appear in all copies and that both that |
| 421 | copyright notice and this permission notice appear in supporting |
| 422 | documentation, and that the name of M.I.T. not be used in advertising or |
| 423 | publicity pertaining to distribution of the software without specific, |
| 424 | written prior permission. M.I.T. makes no representations about the |
| 425 | suitability of this software for any purpose. It is provided "as is" |
| 426 | without express or implied warranty. |
| 427 | */ |
| 428 | |
| 429 | /* |
| 430 | * XParseGeometry parses strings of the form |
| 431 | * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where |
| 432 | * width, height, xoffset, and yoffset are unsigned integers. |
| 433 | * Example: "=80x24+300-49" |
| 434 | * The equal sign is optional. |
| 435 | * It returns a bitmask that indicates which of the four values |
| 436 | * were actually found in the string. For each value found, |
| 437 | * the corresponding argument is updated; for each value |
| 438 | * not found, the corresponding argument is left unchanged. |
| 439 | */ |
| 440 | |
| 441 | static int ReadInteger(char* string, char** NextString) |
| 442 | { |
| 443 | register int Result = 0; |
| 444 | int Sign = 1; |
| 445 | |
| 446 | if (*string == '+') |
| 447 | string++; |
| 448 | else if (*string == '-') { |
| 449 | string++; |
| 450 | Sign = -1; |
| 451 | } |
| 452 | for (; (*string >= '0') && (*string <= '9'); string++) { |
| 453 | Result = (Result * 10) + (*string - '0'); |
| 454 | } |
| 455 | *NextString = string; |
| 456 | if (Sign >= 0) |
| 457 | return (Result); |
| 458 | else |
| 459 | return (-Result); |
| 460 | } |
| 461 | |
| 462 | int XParseGeometry(const char* string, int* x, int* y, |
| 463 | unsigned int* width, unsigned int* height) |
| 464 | { |
| 465 | int mask = NoValue; |
| 466 | register char *strind; |
| 467 | unsigned int tempWidth = 0, tempHeight = 0; |
| 468 | int tempX = 0, tempY = 0; |
| 469 | char *nextCharacter; |
| 470 | |
| 471 | if ( (string == NULL) || (*string == '\0')) return(mask); |
| 472 | if (*string == '=') |
| 473 | string++; /* ignore possible '=' at beg of geometry spec */ |
| 474 | |
| 475 | strind = (char *)string; |
| 476 | if (*strind != '+' && *strind != '-' && *strind != 'x') { |
| 477 | tempWidth = ReadInteger(strind, &nextCharacter); |
| 478 | if (strind == nextCharacter) |
| 479 | return (0); |
| 480 | strind = nextCharacter; |
| 481 | mask |= WidthValue; |
| 482 | } |
| 483 | |
| 484 | if (*strind == 'x' || *strind == 'X') { |
| 485 | strind++; |
| 486 | tempHeight = ReadInteger(strind, &nextCharacter); |
| 487 | if (strind == nextCharacter) |
| 488 | return (0); |
| 489 | strind = nextCharacter; |
| 490 | mask |= HeightValue; |
| 491 | } |
| 492 | |
| 493 | if ((*strind == '+') || (*strind == '-')) { |
| 494 | if (*strind == '-') { |
| 495 | strind++; |
| 496 | tempX = -ReadInteger(strind, &nextCharacter); |
| 497 | if (strind == nextCharacter) |
| 498 | return (0); |
| 499 | strind = nextCharacter; |
| 500 | mask |= XNegative; |
| 501 | |
| 502 | } else { |
| 503 | strind++; |
| 504 | tempX = ReadInteger(strind, &nextCharacter); |
| 505 | if (strind == nextCharacter) |
| 506 | return(0); |
| 507 | strind = nextCharacter; |
| 508 | } |
| 509 | mask |= XValue; |
| 510 | if ((*strind == '+') || (*strind == '-')) { |
| 511 | if (*strind == '-') { |
| 512 | strind++; |
| 513 | tempY = -ReadInteger(strind, &nextCharacter); |
| 514 | if (strind == nextCharacter) |
| 515 | return(0); |
| 516 | strind = nextCharacter; |
| 517 | mask |= YNegative; |
| 518 | |
| 519 | } else { |
| 520 | strind++; |
| 521 | tempY = ReadInteger(strind, &nextCharacter); |
| 522 | if (strind == nextCharacter) |
| 523 | return(0); |
| 524 | strind = nextCharacter; |
| 525 | } |
| 526 | mask |= YValue; |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | /* If strind isn't at the end of the string the it's an invalid |
| 531 | geometry specification. */ |
| 532 | |
| 533 | if (*strind != '\0') return (0); |
| 534 | |
| 535 | if (mask & XValue) |
| 536 | *x = tempX; |
| 537 | if (mask & YValue) |
| 538 | *y = tempY; |
| 539 | if (mask & WidthValue) |
| 540 | *width = tempWidth; |
| 541 | if (mask & HeightValue) |
| 542 | *height = tempHeight; |
| 543 | return (mask); |
| 544 | } |
| 545 | |
| 546 | #endif // ifdef WIN32 |
| 547 | |
| 548 | // |
| 549 | // End of "$Id: Fl_arg.cxx 7903 2010-11-28 21:06:39Z matt $". |
| 550 | // |