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
fl_match(const char * a,const char * s,int atleast=1)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 */
arg(int argc,char ** argv,int & i)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
args(int argc,char ** argv,int & i,Fl_Args_Handler cb)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
show(int argc,char ** argv)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 */
args(int argc,char ** argv)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
ReadInteger(char * string,char ** NextString)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
XParseGeometry(const char * string,int * x,int * y,unsigned int * width,unsigned int * height)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 //
551