fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl.cxx 8198 2011-01-06 10:24:58Z manolo $"
00003 //
00004 // Main event handling code for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 
00029 // warning: the Apple Quartz version still uses some Quickdraw calls,
00030 //          mostly to get around the single active context in QD and 
00031 //          to implement clipping. This should be changed into pure
00032 //          Quartz calls in the near future.
00033 #include <config.h>
00034 #include <FL/Fl.H>
00035 #include <FL/Fl_Window.H>
00036 #include <FL/Fl_Tooltip.H>
00037 
00038 // recent versions of MinGW warn: "Please include winsock2.h before windows.h",
00039 // hence we must include winsock2.h before FL/x.H (A.S. Dec. 2010)
00040 #if defined(WIN32) && !defined(__CYGWIN__)
00041 #  include <winsock2.h>
00042 #endif
00043 
00044 #include <FL/x.H>
00045 
00046 #include <ctype.h>
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include "flstring.h"
00050 
00051 #if defined(DEBUG) || defined(DEBUG_WATCH)
00052 #  include <stdio.h>
00053 #endif // DEBUG || DEBUG_WATCH
00054 
00055 #ifdef WIN32
00056 #  include <ole2.h>
00057 void fl_free_fonts(void);
00058 HBRUSH fl_brush_action(int action);
00059 void fl_cleanup_pens(void);
00060 void fl_release_dc(HWND,HDC);
00061 void fl_cleanup_dc_list(void);
00062 #elif defined(__APPLE__)
00063 extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle);
00064 #endif // WIN32
00065 
00066 //
00067 // Globals...
00068 //
00069 #ifndef FL_DOXYGEN
00070 Fl_Widget       *Fl::belowmouse_,
00071                 *Fl::pushed_,
00072                 *Fl::focus_,
00073                 *Fl::selection_owner_;
00074 int             Fl::damage_,
00075                 Fl::e_number,
00076                 Fl::e_x,
00077                 Fl::e_y,
00078                 Fl::e_x_root,
00079                 Fl::e_y_root,
00080                 Fl::e_dx,
00081                 Fl::e_dy,
00082                 Fl::e_state,
00083                 Fl::e_clicks,
00084                 Fl::e_is_click,
00085                 Fl::e_keysym,
00086                 Fl::e_original_keysym,
00087                 Fl::scrollbar_size_ = 16;
00088 
00089 char            *Fl::e_text = (char *)"";
00090 int             Fl::e_length;
00091 
00092 unsigned char   Fl::options_[] = { 0, 0 };
00093 unsigned char   Fl::options_read_ = 0;
00094 
00095 
00096 Fl_Window *fl_xfocus;   // which window X thinks has focus
00097 Fl_Window *fl_xmousewin;// which window X thinks has FL_ENTER
00098 Fl_Window *Fl::grab_;   // most recent Fl::grab()
00099 Fl_Window *Fl::modal_;  // topmost modal() window
00100 
00101 #endif // FL_DOXYGEN
00102 
00103 //
00104 // 'Fl::version()' - Return the API version number...
00105 //
00106 
00107 double
00112 Fl::version() {
00113   return FL_VERSION;
00114 }
00115 
00124 int Fl::scrollbar_size() {
00125   return scrollbar_size_;
00126 }
00127 
00136 void Fl::scrollbar_size(int W) {
00137   scrollbar_size_ = W;
00138 }
00139 
00140 
00148 int Fl::event_inside(int xx,int yy,int ww,int hh) /*const*/ {
00149   int mx = e_x - xx;
00150   int my = e_y - yy;
00151   return (mx >= 0 && mx < ww && my >= 0 && my < hh);
00152 }
00153 
00160 int Fl::event_inside(const Fl_Widget *o) /*const*/ {
00161   int mx = e_x - o->x();
00162   int my = e_y - o->y();
00163   return (mx >= 0 && mx < o->w() && my >= 0 && my < o->h());
00164 }
00165 
00166 //
00167 //
00168 // timer support
00169 //
00170 
00171 #ifdef WIN32
00172 
00174 
00175 #elif defined(__APPLE__)
00176 
00178 
00179 #else
00180 
00181 //
00182 // X11 timers
00183 //
00184 
00185 
00187 // Timeouts are stored in a sorted list, so only the first one needs
00188 // to be checked to see if any should be called.
00189   
00190 struct Timeout {
00191   double time;
00192   void (*cb)(void*);
00193   void* arg;
00194   Timeout* next;
00195 };
00196 static Timeout* first_timeout, *free_timeout;
00197 static int first_timeout_count, free_timeout_count;
00198 
00199 #include <sys/time.h>
00200 
00201 // I avoid the overhead of getting the current time when we have no
00202 // timeouts by setting this flag instead of getting the time.
00203 // In this case calling elapse_timeouts() does nothing, but records
00204 // the current time, and the next call will actualy elapse time.
00205 static char reset_clock = 1;
00206 
00207 static void elapse_timeouts() {
00208   static struct timeval prevclock;
00209   struct timeval newclock;
00210   gettimeofday(&newclock, NULL);
00211   double elapsed = newclock.tv_sec - prevclock.tv_sec +
00212     (newclock.tv_usec - prevclock.tv_usec)/1000000.0;
00213   prevclock.tv_sec = newclock.tv_sec;
00214   prevclock.tv_usec = newclock.tv_usec;
00215   if (reset_clock) {
00216     reset_clock = 0;
00217   } else if (elapsed > 0) {
00218     for (Timeout* t = first_timeout; t; t = t->next) t->time -= elapsed;
00219   }
00220 }
00221 
00222 // Continuously-adjusted error value, this is a number <= 0 for how late
00223 // we were at calling the last timeout. This appears to make repeat_timeout
00224 // very accurate even when processing takes a significant portion of the
00225 // time interval:
00226 static double missed_timeout_by;
00227 
00228 void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
00229   elapse_timeouts();
00230   repeat_timeout(time, cb, argp);
00231 }
00232 
00233 void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
00234   time += missed_timeout_by; if (time < -.05) time = 0;
00235   Timeout* t = free_timeout;
00236   if (t) {
00237       free_timeout = t->next;
00238       --free_timeout_count;
00239   } else {
00240       t = new Timeout;
00241   }
00242   t->time = time;
00243   t->cb = cb;
00244   t->arg = argp;
00245   // insert-sort the new timeout:
00246   Timeout** p = &first_timeout; 
00247   while (*p && (*p)->time <= time) p = &((*p)->next);
00248   t->next = *p;
00249   *p = t;
00250 }
00251 
00255 int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) {
00256   for (Timeout* t = first_timeout; t; t = t->next)
00257     if (t->cb == cb && t->arg == argp) return 1;
00258   return 0;
00259 }
00260 
00265 void Fl::remove_timeout(Fl_Timeout_Handler cb, void *argp) {
00266   // This version removes all matching timeouts, not just the first one.
00267   // This may change in the future.
00268   for (Timeout** p = &first_timeout; *p;) {
00269     Timeout* t = *p;
00270     if (t->cb == cb && (t->arg == argp || !argp)) {
00271       *p = t->next;
00272       t->next = free_timeout;
00273       free_timeout = t;
00274     } else {
00275       p = &(t->next);
00276     }
00277   }
00278 }
00279 
00280 #endif
00281 
00283 // Checks are just stored in a list. They are called in the reverse
00284 // order that they were added (this may change in the future).
00285 // This is a bit messy because I want to allow checks to be added,
00286 // removed, and have wait() called from inside them, to do this
00287 // next_check points at the next unprocessed one for the outermost
00288 // call to Fl::wait().
00289 
00290 struct Check {
00291   void (*cb)(void*);
00292   void* arg;
00293   Check* next;
00294 };
00295 static Check *first_check, *next_check, *free_check;
00296 
00328 void Fl::add_check(Fl_Timeout_Handler cb, void *argp) {
00329   Check* t = free_check;
00330   if (t) free_check = t->next;
00331   else t = new Check;
00332   t->cb = cb;
00333   t->arg = argp;
00334   t->next = first_check;
00335   if (next_check == first_check) next_check = t;
00336   first_check = t;
00337 }
00338 
00343 void Fl::remove_check(Fl_Timeout_Handler cb, void *argp) {
00344   for (Check** p = &first_check; *p;) {
00345     Check* t = *p;
00346     if (t->cb == cb && t->arg == argp) {
00347       if (next_check == t) next_check = t->next;
00348       *p = t->next;
00349       t->next = free_check;
00350       free_check = t;
00351     } else {
00352       p = &(t->next);
00353     }
00354   }
00355 }
00356 
00360 int Fl::has_check(Fl_Timeout_Handler cb, void *argp) {
00361   for (Check** p = &first_check; *p;) {
00362     Check* t = *p;
00363     if (t->cb == cb && t->arg == argp) {
00364       return 1;
00365     } else {
00366       p = &(t->next);
00367     }
00368   }
00369   return 0;
00370 }
00371 
00372 static void run_checks()
00373 {
00374   // checks are a bit messy so that add/remove and wait may be called
00375   // from inside them without causing an infinite loop:
00376   if (next_check == first_check) {
00377     while (next_check) {
00378       Check* checkp = next_check;
00379       next_check = checkp->next;
00380       (checkp->cb)(checkp->arg);
00381     }
00382     next_check = first_check;
00383   }
00384 }
00385 
00386 #ifndef WIN32
00387 static char in_idle;
00388 #endif
00389 
00391 // wait/run/check/ready:
00392 
00393 void (*Fl::idle)(); // see Fl_add_idle.cxx for the add/remove functions
00394 
00395 extern int fl_ready(); // in Fl_<platform>.cxx
00396 extern int fl_wait(double time); // in Fl_<platform>.cxx
00397 
00401 double Fl::wait(double time_to_wait) {
00402   // delete all widgets that were listed during callbacks
00403   do_widget_deletion();
00404 
00405 #ifdef WIN32
00406 
00407   return fl_wait(time_to_wait);
00408 
00409 #elif defined(__APPLE__)
00410 
00411   run_checks();
00412   if (idle) {
00413     if (!in_idle) {
00414       in_idle = 1;
00415       idle();
00416       in_idle = 0;
00417     }
00418     // the idle function may turn off idle, we can then wait:
00419     if (idle) time_to_wait = 0.0;
00420   }
00421   return fl_mac_flush_and_wait(time_to_wait, in_idle);
00422 
00423 #else
00424 
00425   if (first_timeout) {
00426     elapse_timeouts();
00427     Timeout *t;
00428     while ((t = first_timeout)) {
00429       if (t->time > 0) break;
00430       // The first timeout in the array has expired.
00431       missed_timeout_by = t->time;
00432       // We must remove timeout from array before doing the callback:
00433       void (*cb)(void*) = t->cb;
00434       void *argp = t->arg;
00435       first_timeout = t->next;
00436       t->next = free_timeout;
00437       free_timeout = t;
00438       ++free_timeout_count;
00439       --first_timeout_count;
00440       // Now it is safe for the callback to do add_timeout:
00441       cb(argp);
00442     }
00443   } else {
00444     reset_clock = 1; // we are not going to check the clock
00445   }
00446   run_checks();
00447 //  if (idle && !fl_ready()) {
00448   if (idle) {
00449     if (!in_idle) {
00450       in_idle = 1;
00451       idle();
00452       in_idle = 0;
00453     }
00454     // the idle function may turn off idle, we can then wait:
00455     if (idle) time_to_wait = 0.0;
00456   }
00457   if (first_timeout && first_timeout->time < time_to_wait)
00458     time_to_wait = first_timeout->time;
00459   if (time_to_wait <= 0.0) {
00460     // do flush second so that the results of events are visible:
00461     int ret = fl_wait(0.0);
00462     flush();
00463     return ret;
00464   } else {
00465     // do flush first so that user sees the display:
00466     flush();
00467     if (idle && !in_idle) // 'idle' may have been set within flush()
00468       time_to_wait = 0.0;
00469     return fl_wait(time_to_wait);
00470   }
00471 #endif
00472 }
00473 
00474 #define FOREVER 1e20
00475 
00483 int Fl::run() {
00484   while (Fl_X::first) wait(FOREVER);
00485   return 0;
00486 }
00487 
00488 #ifdef WIN32
00489 
00490 // Function to initialize COM/OLE for usage. This must be done only once.
00491 // We define a flag to register whether we called it:
00492 static char oleInitialized = 0;
00493 
00494 // This calls the Windows function OleInitialize() exactly once.
00495 void fl_OleInitialize() {
00496   if (!oleInitialized) {
00497     OleInitialize(0L);
00498     oleInitialized = 1;
00499   }
00500 }
00501 
00502 // This calls the Windows function OleUninitialize() only, if
00503 // OleInitialize has been called before.
00504 void fl_OleUninitialize() {
00505   if (oleInitialized) {
00506     OleUninitialize();
00507     oleInitialized = 0;
00508   }
00509 }
00510 
00511 class Fl_Win32_At_Exit {
00512 public:
00513   Fl_Win32_At_Exit() { }
00514   ~Fl_Win32_At_Exit() {
00515     fl_free_fonts();        // do some WIN32 cleanup
00516     fl_cleanup_pens();
00517     fl_OleUninitialize();
00518     fl_brush_action(1);
00519     fl_cleanup_dc_list();
00520   }
00521 };
00522 static Fl_Win32_At_Exit win32_at_exit;
00523 #endif
00524 
00525 
00526 
00552 int Fl::wait() {
00553   if (!Fl_X::first) return 0;
00554   wait(FOREVER);
00555   return Fl_X::first != 0; // return true if there is a window
00556 }
00557 
00574 int Fl::check() {
00575   wait(0.0);
00576   return Fl_X::first != 0; // return true if there is a window
00577 }
00578 
00597 int Fl::ready() {
00598 #if ! defined( WIN32 )  &&  ! defined(__APPLE__)
00599   if (first_timeout) {
00600     elapse_timeouts();
00601     if (first_timeout->time <= 0) return 1;
00602   } else {
00603     reset_clock = 1;
00604   }
00605 #endif
00606   return fl_ready();
00607 }
00608 
00610 // Window list management:
00611 
00612 #ifndef FL_DOXYGEN
00613 Fl_X* Fl_X::first;
00614 #endif
00615 
00616 Fl_Window* fl_find(Window xid) {
00617   Fl_X *window;
00618   for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next)
00619 #if defined(WIN32) || defined(USE_X11)
00620    if (window->xid == xid) 
00621 #elif defined(__APPLE_QUARTZ__)
00622    if (window->xid == xid && !window->w->window()) 
00623 #else
00624 # error unsupported platform
00625 #endif // __APPLE__
00626         {
00627       if (window != Fl_X::first && !Fl::modal()) {
00628         // make this window be first to speed up searches
00629         // this is not done if modal is true to avoid messing up modal stack
00630         *pp = window->next;
00631         window->next = Fl_X::first;
00632         Fl_X::first = window;
00633       }
00634       return window->w;
00635     }
00636   return 0;
00637 }
00638 
00651 Fl_Window* Fl::first_window() {
00652   Fl_X* i = Fl_X::first;
00653   return i ? i->w : 0;
00654 }
00655 
00660 Fl_Window* Fl::next_window(const Fl_Window* window) {
00661   Fl_X* i = Fl_X::i(window)->next;
00662   return i ? i->w : 0;
00663 }
00664 
00668 void Fl::first_window(Fl_Window* window) {
00669   if (!window || !window->shown()) return;
00670   fl_find( Fl_X::i(window)->xid );
00671 }
00672 
00676 void Fl::redraw() {
00677   for (Fl_X* i = Fl_X::first; i; i = i->next) i->w->redraw();
00678 }
00679 
00691 void Fl::flush() {
00692   if (damage()) {
00693     damage_ = 0;
00694     for (Fl_X* i = Fl_X::first; i; i = i->next) {
00695       if (i->wait_for_expose) {damage_ = 1; continue;}
00696       Fl_Window* wi = i->w;
00697       if (!wi->visible_r()) continue;
00698       if (wi->damage()) {i->flush(); wi->clear_damage();}
00699       // destroy damage regions for windows that don't use them:
00700       if (i->region) {XDestroyRegion(i->region); i->region = 0;}
00701     }
00702   }
00703 #if defined(USE_X11)
00704   if (fl_display) XFlush(fl_display);
00705 #elif defined(WIN32)
00706   GdiFlush();
00707 #elif defined (__APPLE_QUARTZ__)
00708   if (fl_gc)
00709     CGContextFlush(fl_gc);
00710 #else
00711 # error unsupported platform
00712 #endif
00713 }
00714 
00716 // Event handlers:
00717 
00718 struct handler_link {
00719   int (*handle)(int);
00720   handler_link *next;
00721 };
00722 
00723 static handler_link *handlers = 0;
00724 
00739 void Fl::add_handler(Fl_Event_Handler ha) {
00740   handler_link *l = new handler_link;
00741   l->handle = ha;
00742   l->next = handlers;
00743   handlers = l;
00744 }
00745 
00749 void Fl::remove_handler(Fl_Event_Handler ha) {
00750   handler_link *l, *p;
00751 
00752   // Search for the handler in the list...
00753   for (l = handlers, p = 0; l && l->handle != ha; p = l, l = l->next);
00754 
00755   if (l) {
00756     // Found it, so remove it from the list...
00757     if (p) p->next = l->next;
00758     else handlers = l->next;
00759 
00760     // And free the record...
00761     delete l;
00762   }
00763 }
00764 
00765 int (*fl_local_grab)(int); // used by fl_dnd.cxx
00766 
00767 static int send_handlers(int e) {
00768   for (const handler_link *hl = handlers; hl; hl = hl->next)
00769     if (hl->handle(e)) return 1;
00770   return 0;
00771 }
00772 
00774 
00775 Fl_Widget* fl_oldfocus; // kludge for Fl_Group...
00776 
00789 void Fl::focus(Fl_Widget *o) {
00790   if (o && !o->visible_focus()) return;
00791   if (grab()) return; // don't do anything while grab is on
00792   Fl_Widget *p = focus_;
00793   if (o != p) {
00794     Fl::compose_reset();
00795     focus_ = o;
00796     // make sure that fl_xfocus is set to the top level window
00797     // of this widget, or fl_fix_focus will clear our focus again
00798     if (o) {
00799       Fl_Window *win = 0, *w1 = o->window();
00800       while (w1) { win=w1; w1=win->window(); }
00801       if (win) fl_xfocus = win;
00802     }
00803     // take focus from the old focused window
00804     fl_oldfocus = 0;
00805     int old_event = e_number;
00806     e_number = FL_UNFOCUS;
00807     for (; p; p = p->parent()) {
00808       p->handle(FL_UNFOCUS);
00809       fl_oldfocus = p;
00810     }
00811     e_number = old_event;
00812   }
00813 }
00814 
00815 static char dnd_flag = 0; // make 'belowmouse' send DND_LEAVE instead of LEAVE
00816 
00831 void Fl::belowmouse(Fl_Widget *o) {
00832   if (grab()) return; // don't do anything while grab is on
00833   Fl_Widget *p = belowmouse_;
00834   if (o != p) {
00835     belowmouse_ = o;
00836     int old_event = e_number;
00837     e_number = dnd_flag ? FL_DND_LEAVE : FL_LEAVE;
00838     for (; p && !p->contains(o); p = p->parent()) {
00839       p->handle(e_number);
00840     }
00841     e_number = old_event;
00842   }
00843 }
00844 
00857  void Fl::pushed(Fl_Widget *o) {
00858   pushed_ = o;
00859 }
00860 
00861 static void nothing(Fl_Widget *) {}
00862 void (*Fl_Tooltip::enter)(Fl_Widget *) = nothing;
00863 void (*Fl_Tooltip::exit)(Fl_Widget *) = nothing;
00864 
00865 // Update modal(), focus() and other state according to system state,
00866 // and send FL_ENTER, FL_LEAVE, FL_FOCUS, and/or FL_UNFOCUS events.
00867 // This is the only function that produces these events in response
00868 // to system activity.
00869 // This is called whenever a window is added or hidden, and whenever
00870 // X says the focus or mouse window have changed.
00871 
00872 void fl_fix_focus() {
00873 #ifdef DEBUG
00874   puts("fl_fix_focus();");
00875 #endif // DEBUG
00876 
00877   if (Fl::grab()) return; // don't do anything while grab is on.
00878 
00879   // set focus based on Fl::modal() and fl_xfocus
00880   Fl_Widget* w = fl_xfocus;
00881   if (w) {
00882     int saved = Fl::e_keysym;
00883     if (Fl::e_keysym < (FL_Button + FL_LEFT_MOUSE) ||
00884         Fl::e_keysym > (FL_Button + FL_RIGHT_MOUSE))
00885       Fl::e_keysym = 0; // make sure widgets don't think a keystroke moved focus
00886     while (w->parent()) w = w->parent();
00887     if (Fl::modal()) w = Fl::modal();
00888     if (!w->contains(Fl::focus()))
00889       if (!w->take_focus()) Fl::focus(w);
00890     Fl::e_keysym = saved;
00891   } else
00892     Fl::focus(0);
00893 
00894 // MRS: Originally we checked the button state, but a user reported that it
00895 //      broke click-to-focus in FLWM?!?
00896 //  if (!(Fl::event_state() & 0x7f00000 /*FL_BUTTONS*/)) {
00897   if (!Fl::pushed()) {
00898     // set belowmouse based on Fl::modal() and fl_xmousewin:
00899     w = fl_xmousewin;
00900     if (w) {
00901       if (Fl::modal()) w = Fl::modal();
00902       if (!w->contains(Fl::belowmouse())) {
00903         int old_event = Fl::e_number;
00904         w->handle(Fl::e_number = FL_ENTER);
00905         Fl::e_number = old_event;
00906         if (!w->contains(Fl::belowmouse())) Fl::belowmouse(w);
00907       } else {
00908         // send a FL_MOVE event so the enter/leave state is up to date
00909         Fl::e_x = Fl::e_x_root-fl_xmousewin->x();
00910         Fl::e_y = Fl::e_y_root-fl_xmousewin->y();
00911         int old_event = Fl::e_number;
00912         w->handle(Fl::e_number = FL_MOVE);
00913         Fl::e_number = old_event;
00914       }
00915     } else {
00916       Fl::belowmouse(0);
00917       Fl_Tooltip::enter(0);
00918     }
00919   }
00920 }
00921 
00922 #if !(defined(WIN32) || defined(__APPLE__))
00923 extern Fl_Widget *fl_selection_requestor; // from Fl_x.cxx
00924 #endif
00925 
00926 // This function is called by ~Fl_Widget() and by Fl_Widget::deactivate
00927 // and by Fl_Widget::hide().  It indicates that the widget does not want
00928 // to receive any more events, and also removes all global variables that
00929 // point at the widget.
00930 // I changed this from the 1.0.1 behavior, the older version could send
00931 // FL_LEAVE or FL_UNFOCUS events to the widget.  This appears to not be
00932 // desirable behavior and caused flwm to crash.
00933 
00934 void fl_throw_focus(Fl_Widget *o) {
00935 #ifdef DEBUG
00936   printf("fl_throw_focus(o=%p)\n", o);
00937 #endif // DEBUG
00938 
00939   if (o->contains(Fl::pushed())) Fl::pushed_ = 0;
00940 #if !(defined(WIN32) || defined(__APPLE__))
00941   if (o->contains(fl_selection_requestor)) fl_selection_requestor = 0;
00942 #endif
00943   if (o->contains(Fl::belowmouse())) Fl::belowmouse_ = 0;
00944   if (o->contains(Fl::focus())) Fl::focus_ = 0;
00945   if (o == fl_xfocus) fl_xfocus = 0;
00946   if (o == Fl_Tooltip::current()) Fl_Tooltip::current(0);
00947   if (o == fl_xmousewin) fl_xmousewin = 0;
00948   Fl_Tooltip::exit(o);
00949   fl_fix_focus();
00950 }
00951 
00953 
00954 // Call to->handle but first replace the mouse x/y with the correct
00955 // values to account for nested X windows. 'window' is the outermost
00956 // window the event was posted to by X:
00957 static int send(int event, Fl_Widget* to, Fl_Window* window) {
00958   int dx, dy;
00959   int old_event = Fl::e_number;
00960   if (window) {
00961     dx = window->x();
00962     dy = window->y();
00963   } else {
00964     dx = dy = 0;
00965   }
00966   for (const Fl_Widget* w = to; w; w = w->parent())
00967     if (w->type()>=FL_WINDOW) {dx -= w->x(); dy -= w->y();}
00968   int save_x = Fl::e_x; Fl::e_x += dx;
00969   int save_y = Fl::e_y; Fl::e_y += dy;
00970   int ret = to->handle(Fl::e_number = event);
00971   Fl::e_number = old_event;
00972   Fl::e_y = save_y;
00973   Fl::e_x = save_x;
00974   return ret;
00975 }
00976 
00977 int Fl::handle(int e, Fl_Window* window)
00982 {
00983   e_number = e;
00984   if (fl_local_grab) return fl_local_grab(e);
00985 
00986   Fl_Widget* wi = window;
00987 
00988   switch (e) {
00989 
00990   case FL_CLOSE:
00991     if ( grab() || (modal() && window != modal()) ) return 0;
00992     wi->do_callback();
00993     return 1;
00994 
00995   case FL_SHOW:
00996     wi->Fl_Widget::show(); // this calls Fl_Widget::show(), not Fl_Window::show()
00997     return 1;
00998 
00999   case FL_HIDE:
01000     wi->Fl_Widget::hide(); // this calls Fl_Widget::hide(), not Fl_Window::hide()
01001     return 1;
01002 
01003   case FL_PUSH:
01004 #ifdef DEBUG
01005     printf("Fl::handle(e=%d, window=%p);\n", e, window);
01006 #endif // DEBUG
01007 
01008     if (grab()) wi = grab();
01009     else if (modal() && wi != modal()) return 0;
01010     pushed_ = wi;
01011     Fl_Tooltip::current(wi);
01012     if (send(e, wi, window)) return 1;
01013     // raise windows that are clicked on:
01014     window->show();
01015     return 1;
01016 
01017   case FL_DND_ENTER:
01018   case FL_DND_DRAG:
01019     dnd_flag = 1;
01020     break;
01021 
01022   case FL_DND_LEAVE:
01023     dnd_flag = 1;
01024     belowmouse(0);
01025     dnd_flag = 0;
01026     return 1;
01027 
01028   case FL_DND_RELEASE:
01029     wi = belowmouse();
01030     break;
01031 
01032   case FL_MOVE:
01033   case FL_DRAG:
01034     fl_xmousewin = window; // this should already be set, but just in case.
01035     if (pushed()) {
01036       wi = pushed();
01037       if (grab()) wi = grab();
01038       e_number = e = FL_DRAG;
01039       break;
01040     }
01041     if (modal() && wi != modal()) wi = 0;
01042     if (grab()) wi = grab();
01043     { int ret;
01044       Fl_Widget* pbm = belowmouse();
01045 #ifdef __APPLE__
01046       if (fl_mac_os_version < 0x1050) {
01047         // before 10.5, mouse moved events aren't sent to borderless windows such as tooltips
01048         Fl_Window *tooltip = Fl_Tooltip::current_window();
01049         int inside = 0;
01050         if (tooltip && tooltip->shown() ) { // check if a tooltip window is currently opened
01051           // check if mouse is inside the tooltip
01052           inside = (Fl::event_x_root() >= tooltip->x() && Fl::event_x_root() < tooltip->x() + tooltip->w() &&
01053           Fl::event_y_root() >= tooltip->y() && Fl::event_y_root() < tooltip->y() + tooltip->h() );
01054         }
01055         // if inside, send event to tooltip window instead of background window
01056         if (inside) ret = send(e, tooltip, window);
01057         else ret = (wi && send(e, wi, window));
01058       } else
01059 #endif
01060       ret = (wi && send(e, wi, window));
01061    if (pbm != belowmouse()) {
01062 #ifdef DEBUG
01063       printf("Fl::handle(e=%d, window=%p);\n", e, window);
01064 #endif // DEBUG
01065       Fl_Tooltip::enter(belowmouse());
01066     }
01067     return ret;}
01068 
01069   case FL_RELEASE: {
01070 //    printf("FL_RELEASE: window=%p, pushed() = %p, grab() = %p, modal() = %p\n",
01071 //           window, pushed(), grab(), modal());
01072 
01073     if (grab()) {
01074       wi = grab();
01075       pushed_ = 0; // must be zero before callback is done!
01076     } else if (pushed()) {
01077       wi = pushed();
01078       pushed_ = 0; // must be zero before callback is done!
01079     } else if (modal() && wi != modal()) return 0;
01080     int r = send(e, wi, window);
01081     fl_fix_focus();
01082     return r;}
01083 
01084   case FL_UNFOCUS:
01085     window = 0;
01086   case FL_FOCUS:
01087     fl_xfocus = window;
01088     fl_fix_focus();
01089     return 1;
01090 
01091   case FL_KEYUP:
01092     // Send the key-up to the current focus. This is not 
01093     // always the same widget that received the corresponding
01094     // FL_KEYBOARD event because focus may have changed.
01095     // Sending the KEYUP to the right KEYDOWN is possible, but
01096     // would require that we track the KEYDOWN for every possible 
01097     // key stroke (users may hold down multiple keys!) and then 
01098     // make sure that the widget still exists before sending
01099     // a KEYUP there. I believe that the current solution is
01100     // "close enough".
01101     for (wi = grab() ? grab() : focus(); wi; wi = wi->parent())
01102       if (send(FL_KEYUP, wi, window)) return 1;
01103     return 0;
01104 
01105   case FL_KEYBOARD:
01106 #ifdef DEBUG
01107     printf("Fl::handle(e=%d, window=%p);\n", e, window);
01108 #endif // DEBUG
01109 
01110     Fl_Tooltip::enter((Fl_Widget*)0);
01111 
01112     fl_xfocus = window; // this should not happen!  But maybe it does:
01113 
01114     // Try it as keystroke, sending it to focus and all parents:
01115     for (wi = grab() ? grab() : focus(); wi; wi = wi->parent())
01116       if (send(FL_KEYBOARD, wi, window)) return 1;
01117 
01118     // recursive call to try shortcut:
01119     if (handle(FL_SHORTCUT, window)) return 1;
01120 
01121     // and then try a shortcut with the case of the text swapped, by
01122     // changing the text and falling through to FL_SHORTCUT case:
01123     {unsigned char* c = (unsigned char*)event_text(); // cast away const
01124     if (!isalpha(*c)) return 0;
01125     *c = isupper(*c) ? tolower(*c) : toupper(*c);}
01126     e_number = e = FL_SHORTCUT;
01127 
01128   case FL_SHORTCUT:
01129     if (grab()) {wi = grab(); break;} // send it to grab window
01130 
01131     // Try it as shortcut, sending to mouse widget and all parents:
01132     wi = belowmouse();
01133     if (!wi) {
01134       wi = modal();
01135       if (!wi) wi = window;
01136     } else if (wi->window() != first_window()) {
01137       if (send(FL_SHORTCUT, first_window(), first_window())) return 1;
01138     }
01139 
01140     for (; wi; wi = wi->parent()) {
01141       if (send(FL_SHORTCUT, wi, wi->window())) return 1;
01142     }
01143 
01144     // try using add_handle() functions:
01145     if (send_handlers(FL_SHORTCUT)) return 1;
01146 
01147     // make Escape key close windows:
01148     if (event_key()==FL_Escape) {
01149       wi = modal(); if (!wi) wi = window;
01150       wi->do_callback();
01151       return 1;
01152     }
01153 
01154     return 0;
01155 
01156   case FL_ENTER:
01157 #ifdef DEBUG
01158     printf("Fl::handle(e=%d, window=%p);\n", e, window);
01159 #endif // DEBUG
01160 
01161     fl_xmousewin = window;
01162     fl_fix_focus();
01163     Fl_Tooltip::enter(belowmouse());
01164     return 1;
01165 
01166   case FL_LEAVE:
01167 #ifdef DEBUG
01168     printf("Fl::handle(e=%d, window=%p);\n", e, window);
01169 #endif // DEBUG
01170 
01171     if (!pushed_) {
01172       belowmouse(0);
01173       Fl_Tooltip::enter(0);
01174     }
01175     if (window == fl_xmousewin) {fl_xmousewin = 0; fl_fix_focus();}
01176     return 1;
01177 
01178   case FL_MOUSEWHEEL:
01179     fl_xfocus = window; // this should not happen!  But maybe it does:
01180 
01181     // Try sending it to the "grab" first
01182     if (grab() && grab()!=modal() && grab()!=window) {
01183       if (send(FL_MOUSEWHEEL, grab(), window)) return 1;
01184     }
01185     // Now try sending it to the "modal" window
01186     if (modal()) {
01187       send(FL_MOUSEWHEEL, modal(), window);
01188       return 1;
01189     }
01190     // Finally try sending it to the window, the event occured in
01191     if (send(FL_MOUSEWHEEL, window, window)) return 1;
01192   default:
01193     break;
01194   }
01195   if (wi && send(e, wi, window)) {
01196     dnd_flag = 0;
01197     return 1;
01198   }
01199   dnd_flag = 0;
01200   return send_handlers(e);
01201 }
01202 
01204 // hide() destroys the X window, it does not do unmap!
01205 
01206 #if !defined(WIN32) && USE_XFT
01207 extern void fl_destroy_xft_draw(Window);
01208 #endif
01209 
01210 void Fl_Window::hide() {
01211   clear_visible();
01212 
01213   if (!shown()) return;
01214 
01215   // remove from the list of windows:
01216   Fl_X* ip = i;
01217   Fl_X** pp = &Fl_X::first;
01218   for (; *pp != ip; pp = &(*pp)->next) if (!*pp) return;
01219   *pp = ip->next;
01220 #ifdef __APPLE__
01221   ip->unlink();
01222   // MacOS X manages a single pointer per application. Make sure that hiding
01223   // a toplevel window will not leave us with some random pointer shape, or
01224   // worst case, an invisible pointer
01225   if (!parent()) cursor(FL_CURSOR_DEFAULT);
01226 #endif
01227   i = 0;
01228 
01229   // recursively remove any subwindows:
01230   for (Fl_X *wi = Fl_X::first; wi;) {
01231     Fl_Window* W = wi->w;
01232     if (W->window() == this) {
01233       W->hide();
01234       W->set_visible();
01235       wi = Fl_X::first;
01236     } else wi = wi->next;
01237   }
01238 
01239   if (this == Fl::modal_) { // we are closing the modal window, find next one:
01240     Fl_Window* W;
01241     for (W = Fl::first_window(); W; W = Fl::next_window(W))
01242       if (W->modal()) break;
01243     Fl::modal_ = W;
01244   }
01245 
01246   // Make sure no events are sent to this window:
01247   fl_throw_focus(this);
01248   handle(FL_HIDE);
01249 
01250 #if defined(WIN32)
01251   // this little trick keeps the current clipboard alive, even if we are about
01252   // to destroy the window that owns the selection.
01253   if (GetClipboardOwner()==ip->xid) {
01254     Fl_Window *w1 = Fl::first_window();
01255     if (w1 && OpenClipboard(fl_xid(w1))) {
01256       EmptyClipboard();
01257       SetClipboardData(CF_TEXT, NULL);
01258       CloseClipboard();
01259     }
01260   }
01261   // Send a message to myself so that I'll get out of the event loop...
01262   PostMessage(ip->xid, WM_APP, 0, 0);
01263   if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
01264     if (ip->xid == fl_window && fl_gc) {
01265       fl_release_dc(fl_window, fl_gc);
01266       fl_window = (HWND)-1;
01267       fl_gc = 0;
01268 # ifdef FLTK_USE_CAIRO
01269       if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0);
01270 # endif
01271     }
01272 #elif defined(__APPLE_QUARTZ__)
01273   Fl_X::q_release_context(ip);
01274   if ( ip->xid == fl_window && !parent() )
01275     fl_window = 0;
01276 #endif
01277 
01278   if (ip->region) XDestroyRegion(ip->region);
01279 
01280 #if defined(USE_X11)
01281 # if USE_XFT
01282   fl_destroy_xft_draw(ip->xid);
01283 # endif
01284   XDestroyWindow(fl_display, ip->xid);
01285 #elif defined(WIN32)
01286   // this little trickery seems to avoid the popup window stacking problem
01287   HWND p = GetForegroundWindow();
01288   if (p==GetParent(ip->xid)) {
01289     ShowWindow(ip->xid, SW_HIDE);
01290     ShowWindow(p, SW_SHOWNA);
01291   }
01292   XDestroyWindow(fl_display, ip->xid);
01293 #elif defined(__APPLE_QUARTZ__)
01294   ip->destroy();
01295 #else
01296 # error unsupported platform
01297 #endif
01298   
01299 #ifdef WIN32
01300   // Try to stop the annoying "raise another program" behavior
01301   if (non_modal() && Fl::first_window() && Fl::first_window()->shown())
01302     Fl::first_window()->show();
01303 #endif
01304   delete ip;
01305 }
01306 
01307 Fl_Window::~Fl_Window() {
01308   hide();
01309   if (xclass_) {
01310     free(xclass_);
01311   }
01312 }
01313 
01314 // FL_SHOW and FL_HIDE are called whenever the visibility of this widget
01315 // or any parent changes.  We must correctly map/unmap the system's window.
01316 
01317 // For top-level windows it is assumed the window has already been
01318 // mapped or unmapped!!!  This is because this should only happen when
01319 // Fl_Window::show() or Fl_Window::hide() is called, or in response to
01320 // iconize/deiconize events from the system.
01321 
01322 int Fl_Window::handle(int ev)
01323 {
01324   if (parent()) {
01325     switch (ev) {
01326     case FL_SHOW:
01327       if (!shown()) show();
01328       else {
01329 #if defined(USE_X11) || defined(WIN32)
01330         XMapWindow(fl_display, fl_xid(this)); // extra map calls are harmless
01331 #elif defined(__APPLE_QUARTZ__)
01332         i->map();
01333 #else
01334 # error unsupported platform
01335 #endif // __APPLE__
01336       }
01337       break;
01338     case FL_HIDE:
01339       if (shown()) {
01340         // Find what really turned invisible, if is was a parent window
01341         // we do nothing.  We need to avoid unnecessary unmap calls
01342         // because they cause the display to blink when the parent is
01343         // remapped.  However if this or any intermediate non-window
01344         // widget has really had hide() called directly on it, we must
01345         // unmap because when the parent window is remapped we don't
01346         // want to reappear.
01347         if (visible()) {
01348          Fl_Widget* p = parent(); for (;p->visible();p = p->parent()) {}
01349          if (p->type() >= FL_WINDOW) break; // don't do the unmap
01350         }
01351 #if defined(USE_X11) || defined(WIN32)
01352         XUnmapWindow(fl_display, fl_xid(this));
01353 #elif defined(__APPLE_QUARTZ__)
01354         i->unmap();
01355 #else
01356 # error platform unsupported
01357 #endif
01358       }
01359       break;
01360     }
01361 //  } else if (ev == FL_FOCUS || ev == FL_UNFOCUS) {
01362 //    Fl_Tooltip::exit(Fl_Tooltip::current());
01363   }
01364 
01365   return Fl_Group::handle(ev);
01366 }
01367 
01369 // Back compatibility cut & paste functions for fltk 1.1 only:
01370 
01383 void Fl::selection_owner(Fl_Widget *owner) {selection_owner_ = owner;}
01384 
01392 void Fl::selection(Fl_Widget &owner, const char* text, int len) {
01393   selection_owner_ = &owner;
01394   Fl::copy(text, len, 0);
01395 }
01396 
01400 void Fl::paste(Fl_Widget &receiver) {
01401   Fl::paste(receiver, 0);
01402 }
01403 
01405 
01406 #include <FL/fl_draw.H>
01407 
01408 void Fl_Widget::redraw() {
01409   damage(FL_DAMAGE_ALL);
01410 }
01411 
01412 void Fl_Widget::redraw_label() {
01413   if (window()) {
01414     if (box() == FL_NO_BOX) {
01415       // Widgets with the FL_NO_BOX boxtype need a parent to
01416       // redraw, since it is responsible for redrawing the
01417       // background...
01418       int X = x() > 0 ? x() - 1 : 0;
01419       int Y = y() > 0 ? y() - 1 : 0;
01420       window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2);
01421     }
01422 
01423     if (align() && !(align() & FL_ALIGN_INSIDE) && window()->shown()) {
01424       // If the label is not inside the widget, compute the location of
01425       // the label and redraw the window within that bounding box...
01426       int W = 0, H = 0;
01427       label_.measure(W, H);
01428       W += 5; // Add a little to the size of the label to cover overflow
01429       H += 5;
01430 
01431       // FIXME:
01432       // This assumes the measure() returns the correct outline, which it does 
01433       // not in all possible cases of alignment combinedwith image and symbols.
01434       switch (align() & 0x0f) {
01435         case FL_ALIGN_TOP_LEFT:
01436           window()->damage(FL_DAMAGE_EXPOSE, x(), y()-H, W, H); break;
01437         case FL_ALIGN_TOP:
01438           window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()-H, W, H); break;
01439         case FL_ALIGN_TOP_RIGHT:
01440           window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()-H, W, H); break;
01441         case FL_ALIGN_LEFT_TOP:
01442           window()->damage(FL_DAMAGE_EXPOSE, x()-W, y(), W, H); break;
01443         case FL_ALIGN_RIGHT_TOP:
01444           window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y(), W, H); break;
01445         case FL_ALIGN_LEFT:
01446           window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+(h()-H)/2, W, H); break;
01447         case FL_ALIGN_RIGHT:
01448           window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+(h()-H)/2, W, H); break;
01449         case FL_ALIGN_LEFT_BOTTOM:
01450           window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+h()-H, W, H); break;
01451         case FL_ALIGN_RIGHT_BOTTOM:
01452           window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+h()-H, W, H); break;
01453         case FL_ALIGN_BOTTOM_LEFT:
01454           window()->damage(FL_DAMAGE_EXPOSE, x(), y()+h(), W, H); break;
01455         case FL_ALIGN_BOTTOM:
01456           window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()+h(), W, H); break;
01457         case FL_ALIGN_BOTTOM_RIGHT:
01458           window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()+h(), W, H); break;
01459         default:
01460           window()->damage(FL_DAMAGE_ALL); break;
01461       }
01462     } else {
01463       // The label is inside the widget, so just redraw the widget itself...
01464       damage(FL_DAMAGE_ALL);
01465     }
01466   }
01467 }
01468 
01469 void Fl_Widget::damage(uchar fl) {
01470   if (type() < FL_WINDOW) {
01471     // damage only the rectangle covered by a child widget:
01472     damage(fl, x(), y(), w(), h());
01473   } else {
01474     // damage entire window by deleting the region:
01475     Fl_X* i = Fl_X::i((Fl_Window*)this);
01476     if (!i) return; // window not mapped, so ignore it
01477     if (i->region) {XDestroyRegion(i->region); i->region = 0;}
01478     damage_ |= fl;
01479     Fl::damage(FL_DAMAGE_CHILD);
01480   }
01481 }
01482 
01483 void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
01484   Fl_Widget* wi = this;
01485   // mark all parent widgets between this and window with FL_DAMAGE_CHILD:
01486   while (wi->type() < FL_WINDOW) {
01487     wi->damage_ |= fl;
01488     wi = wi->parent();
01489     if (!wi) return;
01490     fl = FL_DAMAGE_CHILD;
01491   }
01492   Fl_X* i = Fl_X::i((Fl_Window*)wi);
01493   if (!i) return; // window not mapped, so ignore it
01494 
01495   // clip the damage to the window and quit if none:
01496   if (X < 0) {W += X; X = 0;}
01497   if (Y < 0) {H += Y; Y = 0;}
01498   if (W > wi->w()-X) W = wi->w()-X;
01499   if (H > wi->h()-Y) H = wi->h()-Y;
01500   if (W <= 0 || H <= 0) return;
01501 
01502   if (!X && !Y && W==wi->w() && H==wi->h()) {
01503     // if damage covers entire window delete region:
01504     wi->damage(fl);
01505     return;
01506   }
01507 
01508   if (wi->damage()) {
01509     // if we already have damage we must merge with existing region:
01510     if (i->region) {
01511 #if defined(USE_X11)
01512       XRectangle R;
01513       R.x = X; R.y = Y; R.width = W; R.height = H;
01514       XUnionRectWithRegion(&R, i->region, i->region);
01515 #elif defined(WIN32)
01516       Fl_Region R = XRectangleRegion(X, Y, W, H);
01517       CombineRgn(i->region, i->region, R, RGN_OR);
01518       XDestroyRegion(R);
01519 #elif defined(__APPLE_QUARTZ__)
01520       CGRect arg = fl_cgrectmake_cocoa(X, Y, W, H);
01521       int j; // don't add a rectangle totally inside the Fl_Region
01522       for(j = 0; j < i->region->count; j++) {
01523         if(CGRectContainsRect(i->region->rects[j], arg)) break;
01524       }
01525       if( j >= i->region->count) {
01526         i->region->rects = (CGRect*)realloc(i->region->rects, (++(i->region->count)) * sizeof(CGRect));
01527         i->region->rects[i->region->count - 1] = arg;
01528       }
01529 #else
01530 # error unsupported platform
01531 #endif
01532     }
01533     wi->damage_ |= fl;
01534   } else {
01535     // create a new region:
01536     if (i->region) XDestroyRegion(i->region);
01537     i->region = XRectangleRegion(X,Y,W,H);
01538     wi->damage_ = fl;
01539   }
01540   Fl::damage(FL_DAMAGE_CHILD);
01541 }
01542 void Fl_Window::flush() {
01543   make_current();
01544 //if (damage() == FL_DAMAGE_EXPOSE && can_boxcheat(box())) fl_boxcheat = this;
01545   fl_clip_region(i->region); i->region = 0;
01546   draw();
01547 }
01548 
01549 #ifdef WIN32
01550 #  include "Fl_win32.cxx"
01551 //#elif defined(__APPLE__)
01552 #endif
01553 
01554 //
01555 // The following methods allow callbacks to schedule the deletion of
01556 // widgets at "safe" times.
01557 //
01558 
01559 static int              num_dwidgets = 0, alloc_dwidgets = 0;
01560 static Fl_Widget        **dwidgets = 0;
01561 
01582 void Fl::delete_widget(Fl_Widget *wi) {
01583   if (!wi) return;
01584 
01585   if (num_dwidgets >= alloc_dwidgets) {
01586     Fl_Widget   **temp;
01587 
01588     temp = new Fl_Widget *[alloc_dwidgets + 10];
01589     if (alloc_dwidgets) {
01590       memcpy(temp, dwidgets, alloc_dwidgets * sizeof(Fl_Widget *));
01591       delete[] dwidgets;
01592     }
01593 
01594     dwidgets = temp;
01595     alloc_dwidgets += 10;
01596   }
01597 
01598   dwidgets[num_dwidgets] = wi;
01599   num_dwidgets ++;
01600 }
01601 
01613 void Fl::do_widget_deletion() {
01614   if (!num_dwidgets) return;
01615 
01616   for (int i = 0; i < num_dwidgets; i ++)
01617     delete dwidgets[i];
01618 
01619   num_dwidgets = 0;
01620 }
01621 
01622 static Fl_Widget ***widget_watch = 0;
01623 static int num_widget_watch = 0;
01624 static int max_widget_watch = 0;
01625 
01671 void Fl::watch_widget_pointer(Fl_Widget *&w) 
01672 {
01673   Fl_Widget **wp = &w;
01674   int i;
01675   for (i=0; i<num_widget_watch; ++i) {
01676     if (widget_watch[i]==wp) return;
01677   }
01678   if (num_widget_watch==max_widget_watch) {
01679     max_widget_watch += 8;
01680     widget_watch = (Fl_Widget***)realloc(widget_watch, sizeof(Fl_Widget**)*max_widget_watch);
01681   }
01682   widget_watch[num_widget_watch++] = wp;
01683 #ifdef DEBUG_WATCH
01684   printf ("\nwatch_widget_pointer:   (%d/%d) %8p => %8p\n",
01685     num_widget_watch,num_widget_watch,wp,*wp);
01686   fflush(stdout);
01687 #endif // DEBUG_WATCH
01688 }
01689 
01700 void Fl::release_widget_pointer(Fl_Widget *&w)
01701 {
01702   Fl_Widget **wp = &w;
01703   int i,j=0;
01704   for (i=0; i<num_widget_watch; ++i) {
01705     if (widget_watch[i]!=wp) {
01706       if (j<i) widget_watch[j] = widget_watch[i]; // fill gap
01707       j++;
01708     }
01709 #ifdef DEBUG_WATCH
01710     else { // found widget pointer
01711       printf ("release_widget_pointer: (%d/%d) %8p => %8p\n",
01712         i+1,num_widget_watch,wp,*wp);
01713     }
01714 #endif //DEBUG_WATCH
01715   }
01716   num_widget_watch = j;
01717 #ifdef DEBUG_WATCH
01718   printf ("                        num_widget_watch = %d\n\n",num_widget_watch);
01719   fflush(stdout);
01720 #endif // DEBUG_WATCH
01721   return;
01722 }
01739 void Fl::clear_widget_pointer(Fl_Widget const *w) 
01740 {
01741   if (w==0L) return;
01742   int i;
01743   for (i=0; i<num_widget_watch; ++i) {
01744     if (widget_watch[i] && *widget_watch[i]==w) {
01745       *widget_watch[i] = 0L;
01746     }
01747   }
01748 }
01749 
01750 
01768 bool Fl::option(Fl_Option opt)
01769 {
01770   if (!options_read_) {
01771     int tmp;
01772     { // first, read the system wide preferences
01773       Fl_Preferences prefs(Fl_Preferences::SYSTEM, "fltk.org", "fltk");
01774       Fl_Preferences opt_prefs(prefs, "options");
01775       opt_prefs.get("ArrowFocus", tmp, 0);                      // default: off
01776       options_[OPTION_ARROW_FOCUS] = tmp;
01777       //opt_prefs.get("NativeFilechooser", tmp, 1);             // default: on
01778       //options_[OPTION_NATIVE_FILECHOOSER] = tmp;
01779       //opt_prefs.get("FilechooserPreview", tmp, 1);            // default: on
01780       //options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
01781       opt_prefs.get("VisibleFocus", tmp, 1);                    // default: on
01782       options_[OPTION_VISIBLE_FOCUS] = tmp;
01783       opt_prefs.get("DNDText", tmp, 1);                         // default: on
01784       options_[OPTION_DND_TEXT] = tmp;
01785       opt_prefs.get("ShowTooltips", tmp, 1);                    // default: on
01786       options_[OPTION_SHOW_TOOLTIPS] = tmp;
01787     }
01788     { // next, check the user preferences
01789       // override system options only, if the option is set ( >= 0 )
01790       Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "fltk");
01791       Fl_Preferences opt_prefs(prefs, "options");
01792       opt_prefs.get("ArrowFocus", tmp, -1); 
01793       if (tmp >= 0) options_[OPTION_ARROW_FOCUS] = tmp;
01794       //opt_prefs.get("NativeFilechooser", tmp, -1); 
01795       //if (tmp >= 0) options_[OPTION_NATIVE_FILECHOOSER] = tmp;
01796       //opt_prefs.get("FilechooserPreview", tmp, -1);
01797       //if (tmp >= 0) options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
01798       opt_prefs.get("VisibleFocus", tmp, -1); 
01799       if (tmp >= 0) options_[OPTION_VISIBLE_FOCUS] = tmp;
01800       opt_prefs.get("DNDText", tmp, -1); 
01801       if (tmp >= 0) options_[OPTION_DND_TEXT] = tmp;
01802       opt_prefs.get("ShowTooltips", tmp, -1); 
01803       if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
01804     }
01805     { // now, if the developer has registered this app, we could as for per-application preferences
01806     }
01807     options_read_ = 1;
01808   }
01809   if (opt<0 || opt>=OPTION_LAST) 
01810     return false;
01811   return (bool)options_[opt];
01812 }
01813 
01823 void Fl::option(Fl_Option opt, bool val)
01824 {
01825   if (opt<0 || opt>=OPTION_LAST) 
01826     return;
01827   if (!options_read_) {
01828     // first read this option, so we don't override our setting later
01829     option(opt);
01830   }
01831   options_[opt] = val;
01832 }
01833 
01834 
01835 // Helper class Fl_Widget_Tracker
01836 
01840 Fl_Widget_Tracker::Fl_Widget_Tracker(Fl_Widget *wi) 
01841 {
01842   wp_ = wi;
01843   Fl::watch_widget_pointer(wp_); // add pointer to watch list
01844 }
01845 
01849 Fl_Widget_Tracker::~Fl_Widget_Tracker() 
01850 {
01851   Fl::release_widget_pointer(wp_); // remove pointer from watch list
01852 }
01853 
01854 
01855 //
01856 // End of "$Id: Fl.cxx 8198 2011-01-06 10:24:58Z manolo $".
01857 //