|
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) ![]() |
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 //