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