blob: 134e4d073ec548ca42e2a25b58faf3213b8bfa8b [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: Fl.cxx 8723 2011-05-23 16:49:02Z manolo $"
3//
4// Main event handling code for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28
29// warning: the Apple Quartz version still uses some Quickdraw calls,
30// mostly to get around the single active context in QD and
31// to implement clipping. This should be changed into pure
32// Quartz calls in the near future.
33#include <config.h>
34
35/* We require Windows 2000 features (e.g. VK definitions) */
36#if defined(WIN32)
37# if !defined(WINVER) || (WINVER < 0x0500)
38# ifdef WINVER
39# undef WINVER
40# endif
41# define WINVER 0x0500
42# endif
43# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
44# ifdef _WIN32_WINNT
45# undef _WIN32_WINNT
46# endif
47# define _WIN32_WINNT 0x0500
48# endif
49#endif
50
51// recent versions of MinGW warn: "Please include winsock2.h before windows.h",
52// hence we must include winsock2.h before FL/Fl.H (A.S. Dec. 2010, IMM May 2011)
53#if defined(WIN32) && !defined(__CYGWIN__)
54# include <winsock2.h>
55#endif
56
57#include <FL/Fl.H>
58#include <FL/Fl_Window.H>
59#include <FL/Fl_Tooltip.H>
60#include <FL/x.H>
61
62#include <ctype.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include "flstring.h"
66
67#if defined(DEBUG) || defined(DEBUG_WATCH)
68# include <stdio.h>
69#endif // DEBUG || DEBUG_WATCH
70
71#ifdef WIN32
72# include <ole2.h>
73void fl_free_fonts(void);
74HBRUSH fl_brush_action(int action);
75void fl_cleanup_pens(void);
76void fl_release_dc(HWND,HDC);
77void fl_cleanup_dc_list(void);
78#elif defined(__APPLE__)
79extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle);
80#endif // WIN32
81
DRC685f17e2011-07-28 09:23:00 +000082extern void fl_update_focus(void);
83
DRC2ff39b82011-07-28 08:38:59 +000084//
85// Globals...
86//
87#if defined(__APPLE__) || defined(FL_DOXYGEN)
88const char *Fl_Mac_App_Menu::about = "About ";
Henrik Andersson485f4192011-09-16 11:51:32 +000089const char *Fl_Mac_App_Menu::copyright = NULL;
DRC2ff39b82011-07-28 08:38:59 +000090const char *Fl_Mac_App_Menu::print = "Print Front Window";
91const char *Fl_Mac_App_Menu::services = "Services";
92const char *Fl_Mac_App_Menu::hide = "Hide ";
93const char *Fl_Mac_App_Menu::hide_others = "Hide Others";
94const char *Fl_Mac_App_Menu::show = "Show All";
95const char *Fl_Mac_App_Menu::quit = "Quit ";
96#endif // __APPLE__
97#ifndef FL_DOXYGEN
98Fl_Widget *Fl::belowmouse_,
99 *Fl::pushed_,
100 *Fl::focus_,
101 *Fl::selection_owner_;
102int Fl::damage_,
103 Fl::e_number,
104 Fl::e_x,
105 Fl::e_y,
106 Fl::e_x_root,
107 Fl::e_y_root,
108 Fl::e_dx,
109 Fl::e_dy,
110 Fl::e_state,
111 Fl::e_clicks,
112 Fl::e_is_click,
113 Fl::e_keysym,
114 Fl::e_original_keysym,
115 Fl::scrollbar_size_ = 16;
116
117char *Fl::e_text = (char *)"";
118int Fl::e_length;
119
120Fl_Event_Dispatch Fl::e_dispatch = 0;
121
122unsigned char Fl::options_[] = { 0, 0 };
123unsigned char Fl::options_read_ = 0;
124
125
126Fl_Window *fl_xfocus; // which window X thinks has focus
127Fl_Window *fl_xmousewin;// which window X thinks has FL_ENTER
128Fl_Window *Fl::grab_; // most recent Fl::grab()
129Fl_Window *Fl::modal_; // topmost modal() window
130
131#endif // FL_DOXYGEN
132
133//
134// 'Fl::version()' - Return the API version number...
135//
136
137double
138/**
139 Returns the compiled-in value of the FL_VERSION constant. This
140 is useful for checking the version of a shared library.
141*/
142Fl::version() {
143 return FL_VERSION;
144}
145
146/**
147 Gets the default scrollbar size used by
148 Fl_Browser_,
149 Fl_Help_View,
150 Fl_Scroll, and
151 Fl_Text_Display widgets.
152 \returns The default size for widget scrollbars, in pixels.
153*/
154int Fl::scrollbar_size() {
155 return scrollbar_size_;
156}
157
158/**
159 Sets the default scrollbar size that is used by the
160 Fl_Browser_,
161 Fl_Help_View,
162 Fl_Scroll, and
163 Fl_Text_Display widgets.
164 \param[in] W The new default size for widget scrollbars, in pixels.
165*/
166void Fl::scrollbar_size(int W) {
167 scrollbar_size_ = W;
168}
169
170
171/** Returns whether or not the mouse event is inside the given rectangle.
172
173 Returns non-zero if the current Fl::event_x() and Fl::event_y()
174 put it inside the given arbitrary bounding box.
175
176 You should always call this rather than doing your own comparison
177 so you are consistent about edge effects.
178
179 To find out, whether the event is inside a child widget of the
180 current window, you can use Fl::event_inside(const Fl_Widget *).
181
182 \param[in] xx,yy,ww,hh bounding box
183 \return non-zero, if mouse event is inside
184*/
185int Fl::event_inside(int xx,int yy,int ww,int hh) /*const*/ {
186 int mx = e_x - xx;
187 int my = e_y - yy;
188 return (mx >= 0 && mx < ww && my >= 0 && my < hh);
189}
190
191/** Returns whether or not the mouse event is inside a given child widget.
192
193 Returns non-zero if the current Fl::event_x() and Fl::event_y()
194 put it inside the given child widget's bounding box.
195
196 This method can only be used to check whether the mouse event is
197 inside a \b child widget of the window that handles the event, and
198 there must not be an intermediate subwindow (i.e. the widget must
199 not be inside a subwindow of the current window). However, it is
200 valid if the widget is inside a nested Fl_Group.
201
202 You must not use it with the window itself as the \p o argument
203 in a window's handle() method.
204
205 \note The mentioned restrictions are necessary, because this method
206 does not transform coordinates of child widgets, and thus the given
207 widget \p o must be within the \e same window that is handling the
208 current event. Otherwise the results are undefined.
209
210 You should always call this rather than doing your own comparison
211 so you are consistent about edge effects.
212
213 \see Fl::event_inside(int, int, int, int)
214
215 \param[in] o child widget to be tested
216 \return non-zero, if mouse event is inside the widget
217*/
218int Fl::event_inside(const Fl_Widget *o) /*const*/ {
219 int mx = e_x - o->x();
220 int my = e_y - o->y();
221 return (mx >= 0 && mx < o->w() && my >= 0 && my < o->h());
222}
223
224//
225//
226// timer support
227//
228
229#ifdef WIN32
230
231// implementation in Fl_win32.cxx
232
233#elif defined(__APPLE__)
234
235// implementation in Fl_mac.cxx
236
237#else
238
239//
240// X11 timers
241//
242
243
244////////////////////////////////////////////////////////////////////////
245// Timeouts are stored in a sorted list (*first_timeout), so only the
246// first one needs to be checked to see if any should be called.
247// Allocated, but unused (free) Timeout structs are stored in another
248// linked list (*free_timeout).
249
250struct Timeout {
251 double time;
252 void (*cb)(void*);
253 void* arg;
254 Timeout* next;
255};
256static Timeout* first_timeout, *free_timeout;
257
258#include <sys/time.h>
259
260// I avoid the overhead of getting the current time when we have no
261// timeouts by setting this flag instead of getting the time.
262// In this case calling elapse_timeouts() does nothing, but records
263// the current time, and the next call will actually elapse time.
264static char reset_clock = 1;
265
266static void elapse_timeouts() {
267 static struct timeval prevclock;
268 struct timeval newclock;
269 gettimeofday(&newclock, NULL);
270 double elapsed = newclock.tv_sec - prevclock.tv_sec +
271 (newclock.tv_usec - prevclock.tv_usec)/1000000.0;
272 prevclock.tv_sec = newclock.tv_sec;
273 prevclock.tv_usec = newclock.tv_usec;
274 if (reset_clock) {
275 reset_clock = 0;
276 } else if (elapsed > 0) {
277 for (Timeout* t = first_timeout; t; t = t->next) t->time -= elapsed;
278 }
279}
280
281// Continuously-adjusted error value, this is a number <= 0 for how late
282// we were at calling the last timeout. This appears to make repeat_timeout
283// very accurate even when processing takes a significant portion of the
284// time interval:
285static double missed_timeout_by;
286
287void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
288 elapse_timeouts();
289 repeat_timeout(time, cb, argp);
290}
291
292void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) {
293 time += missed_timeout_by; if (time < -.05) time = 0;
294 Timeout* t = free_timeout;
295 if (t) {
296 free_timeout = t->next;
297 } else {
298 t = new Timeout;
299 }
300 t->time = time;
301 t->cb = cb;
302 t->arg = argp;
303 // insert-sort the new timeout:
304 Timeout** p = &first_timeout;
305 while (*p && (*p)->time <= time) p = &((*p)->next);
306 t->next = *p;
307 *p = t;
308}
309
310/**
311 Returns true if the timeout exists and has not been called yet.
312*/
313int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) {
314 for (Timeout* t = first_timeout; t; t = t->next)
315 if (t->cb == cb && t->arg == argp) return 1;
316 return 0;
317}
318
319/**
320 Removes a timeout callback. It is harmless to remove a timeout
321 callback that no longer exists.
322
323 \note This version removes all matching timeouts, not just the first one.
324 This may change in the future.
325*/
326void Fl::remove_timeout(Fl_Timeout_Handler cb, void *argp) {
327 for (Timeout** p = &first_timeout; *p;) {
328 Timeout* t = *p;
329 if (t->cb == cb && (t->arg == argp || !argp)) {
330 *p = t->next;
331 t->next = free_timeout;
332 free_timeout = t;
333 } else {
334 p = &(t->next);
335 }
336 }
337}
338
339#endif
340
341////////////////////////////////////////////////////////////////
342// Checks are just stored in a list. They are called in the reverse
343// order that they were added (this may change in the future).
344// This is a bit messy because I want to allow checks to be added,
345// removed, and have wait() called from inside them. To do this
346// next_check points at the next unprocessed one for the outermost
347// call to Fl::wait().
348
349struct Check {
350 void (*cb)(void*);
351 void* arg;
352 Check* next;
353};
354static Check *first_check, *next_check, *free_check;
355
356/**
357 FLTK will call this callback just before it flushes the display and
358 waits for events. This is different than an idle callback because it
359 is only called once, then FLTK calls the system and tells it not to
360 return until an event happens.
361
362 This can be used by code that wants to monitor the
363 application's state, such as to keep a display up to date. The
364 advantage of using a check callback is that it is called only when no
365 events are pending. If events are coming in quickly, whole blocks of
366 them will be processed before this is called once. This can save
367 significant time and avoid the application falling behind the events.
368
369 Sample code:
370
371 \code
372 bool state_changed; // anything that changes the display turns this on
373
374 void callback(void*) {
375 if (!state_changed) return;
376 state_changed = false;
377 do_expensive_calculation();
378 widget-&gt;redraw();
379 }
380
381 main() {
382 Fl::add_check(callback);
383 return Fl::run();
384 }
385 \endcode
386*/
387void Fl::add_check(Fl_Timeout_Handler cb, void *argp) {
388 Check* t = free_check;
389 if (t) free_check = t->next;
390 else t = new Check;
391 t->cb = cb;
392 t->arg = argp;
393 t->next = first_check;
394 if (next_check == first_check) next_check = t;
395 first_check = t;
396}
397
398/**
399 Removes a check callback. It is harmless to remove a check
400 callback that no longer exists.
401*/
402void Fl::remove_check(Fl_Timeout_Handler cb, void *argp) {
403 for (Check** p = &first_check; *p;) {
404 Check* t = *p;
405 if (t->cb == cb && t->arg == argp) {
406 if (next_check == t) next_check = t->next;
407 *p = t->next;
408 t->next = free_check;
409 free_check = t;
410 } else {
411 p = &(t->next);
412 }
413 }
414}
415
416/**
417 Returns 1 if the check exists and has not been called yet, 0 otherwise.
418*/
419int Fl::has_check(Fl_Timeout_Handler cb, void *argp) {
420 for (Check** p = &first_check; *p;) {
421 Check* t = *p;
422 if (t->cb == cb && t->arg == argp) {
423 return 1;
424 } else {
425 p = &(t->next);
426 }
427 }
428 return 0;
429}
430
431static void run_checks()
432{
433 // checks are a bit messy so that add/remove and wait may be called
434 // from inside them without causing an infinite loop:
435 if (next_check == first_check) {
436 while (next_check) {
437 Check* checkp = next_check;
438 next_check = checkp->next;
439 (checkp->cb)(checkp->arg);
440 }
441 next_check = first_check;
442 }
443}
444
445#ifndef WIN32
446static char in_idle;
447#endif
448
449////////////////////////////////////////////////////////////////
DRC685f17e2011-07-28 09:23:00 +0000450// Clipboard notifications
451
452struct Clipboard_Notify {
453 Fl_Clipboard_Notify_Handler handler;
454 void *data;
455 struct Clipboard_Notify *next;
456};
457
458static struct Clipboard_Notify *clip_notify_list = NULL;
459
460extern void fl_clipboard_notify_change(); // in Fl_<platform>.cxx
461
462void Fl::add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data) {
463 struct Clipboard_Notify *node;
464
465 remove_clipboard_notify(h);
466
467 node = new Clipboard_Notify;
468
469 node->handler = h;
470 node->data = data;
471 node->next = clip_notify_list;
472
473 clip_notify_list = node;
474
475 fl_clipboard_notify_change();
476}
477
478void Fl::remove_clipboard_notify(Fl_Clipboard_Notify_Handler h) {
479 struct Clipboard_Notify *node, **prev;
480
481 node = clip_notify_list;
482 prev = &clip_notify_list;
483 while (node != NULL) {
484 if (node->handler == h) {
485 *prev = node->next;
486 delete node;
487
488 fl_clipboard_notify_change();
489
490 return;
491 }
492
493 prev = &node->next;
494 node = node->next;
495 }
496}
497
498bool fl_clipboard_notify_empty(void) {
499 return clip_notify_list == NULL;
500}
501
502void fl_trigger_clipboard_notify(int source) {
503 struct Clipboard_Notify *node;
504
505 node = clip_notify_list;
506 while (node != NULL) {
507 node->handler(source, node->data);
508 node = node->next;
509 }
510}
511
512////////////////////////////////////////////////////////////////
DRC2ff39b82011-07-28 08:38:59 +0000513// wait/run/check/ready:
514
515void (*Fl::idle)(); // see Fl::add_idle.cxx for the add/remove functions
516
517extern int fl_ready(); // in Fl_<platform>.cxx
518extern int fl_wait(double time); // in Fl_<platform>.cxx
519
520/**
521 See int Fl::wait()
522*/
523double Fl::wait(double time_to_wait) {
524 // delete all widgets that were listed during callbacks
525 do_widget_deletion();
526
527#ifdef WIN32
528
529 return fl_wait(time_to_wait);
530
531#elif defined(__APPLE__)
532
533 run_checks();
534 if (idle) {
535 if (!in_idle) {
536 in_idle = 1;
537 idle();
538 in_idle = 0;
539 }
540 // the idle function may turn off idle, we can then wait:
541 if (idle) time_to_wait = 0.0;
542 }
543 return fl_mac_flush_and_wait(time_to_wait, in_idle);
544
545#else
546
547 if (first_timeout) {
548 elapse_timeouts();
549 Timeout *t;
550 while ((t = first_timeout)) {
551 if (t->time > 0) break;
552 // The first timeout in the array has expired.
553 missed_timeout_by = t->time;
554 // We must remove timeout from array before doing the callback:
555 void (*cb)(void*) = t->cb;
556 void *argp = t->arg;
557 first_timeout = t->next;
558 t->next = free_timeout;
559 free_timeout = t;
560 // Now it is safe for the callback to do add_timeout:
561 cb(argp);
562 }
563 } else {
564 reset_clock = 1; // we are not going to check the clock
565 }
566 run_checks();
567// if (idle && !fl_ready()) {
568 if (idle) {
569 if (!in_idle) {
570 in_idle = 1;
571 idle();
572 in_idle = 0;
573 }
574 // the idle function may turn off idle, we can then wait:
575 if (idle) time_to_wait = 0.0;
576 }
577 if (first_timeout && first_timeout->time < time_to_wait)
578 time_to_wait = first_timeout->time;
579 if (time_to_wait <= 0.0) {
580 // do flush second so that the results of events are visible:
581 int ret = fl_wait(0.0);
582 flush();
583 return ret;
584 } else {
585 // do flush first so that user sees the display:
586 flush();
587 if (idle && !in_idle) // 'idle' may have been set within flush()
588 time_to_wait = 0.0;
589 return fl_wait(time_to_wait);
590 }
591#endif
592}
593
594#define FOREVER 1e20
595
596/**
597 As long as any windows are displayed this calls Fl::wait()
598 repeatedly. When all the windows are closed it returns zero
599 (supposedly it would return non-zero on any errors, but FLTK calls
600 exit directly for these). A normal program will end main()
601 with return Fl::run();.
602*/
603int Fl::run() {
604 while (Fl_X::first) wait(FOREVER);
605 return 0;
606}
607
608#ifdef WIN32
609
610// Function to initialize COM/OLE for usage. This must be done only once.
611// We define a flag to register whether we called it:
612static char oleInitialized = 0;
613
614// This calls the Windows function OleInitialize() exactly once.
615void fl_OleInitialize() {
616 if (!oleInitialized) {
617 OleInitialize(0L);
618 oleInitialized = 1;
619 }
620}
621
622// This calls the Windows function OleUninitialize() only, if
623// OleInitialize has been called before.
624void fl_OleUninitialize() {
625 if (oleInitialized) {
626 OleUninitialize();
627 oleInitialized = 0;
628 }
629}
630
631class Fl_Win32_At_Exit {
632public:
633 Fl_Win32_At_Exit() { }
634 ~Fl_Win32_At_Exit() {
635 fl_free_fonts(); // do some WIN32 cleanup
636 fl_cleanup_pens();
637 fl_OleUninitialize();
638 fl_brush_action(1);
639 fl_cleanup_dc_list();
640 }
641};
642static Fl_Win32_At_Exit win32_at_exit;
643#endif
644
645
646
647/**
648 Waits until "something happens" and then returns. Call this
649 repeatedly to "run" your program. You can also check what happened
650 each time after this returns, which is quite useful for managing
651 program state.
652
653 What this really does is call all idle callbacks, all elapsed
654 timeouts, call Fl::flush() to get the screen to update, and
655 then wait some time (zero if there are idle callbacks, the shortest of
656 all pending timeouts, or infinity), for any events from the user or
657 any Fl::add_fd() callbacks. It then handles the events and
658 calls the callbacks and then returns.
659
660 The return value of Fl::wait() is non-zero if there are any
661 visible windows - this may change in future versions of FLTK.
662
663 Fl::wait(time) waits a maximum of \e time seconds.
664 <i>It can return much sooner if something happens.</i>
665
666 The return value is positive if an event or fd happens before the
667 time elapsed. It is zero if nothing happens (on Win32 this will only
668 return zero if \e time is zero). It is negative if an error
669 occurs (this will happen on UNIX if a signal happens).
670*/
671int Fl::wait() {
672 if (!Fl_X::first) return 0;
673 wait(FOREVER);
674 return Fl_X::first != 0; // return true if there is a window
675}
676
677/**
678 Same as Fl::wait(0). Calling this during a big calculation
679 will keep the screen up to date and the interface responsive:
680
681 \code
682 while (!calculation_done()) {
683 calculate();
684 Fl::check();
685 if (user_hit_abort_button()) break;
686 }
687 \endcode
688
689 This returns non-zero if any windows are displayed, and 0 if no
690 windows are displayed (this is likely to change in future versions of
691 FLTK).
692*/
693int Fl::check() {
694 wait(0.0);
695 return Fl_X::first != 0; // return true if there is a window
696}
697
698/**
699 This is similar to Fl::check() except this does \e not
700 call Fl::flush() or any callbacks, which is useful if your
701 program is in a state where such callbacks are illegal. This returns
702 true if Fl::check() would do anything (it will continue to
703 return true until you call Fl::check() or Fl::wait()).
704
705 \code
706 while (!calculation_done()) {
707 calculate();
708 if (Fl::ready()) {
709 do_expensive_cleanup();
710 Fl::check();
711 if (user_hit_abort_button()) break;
712 }
713 }
714 \endcode
715*/
716int Fl::ready() {
717#if ! defined( WIN32 ) && ! defined(__APPLE__)
718 if (first_timeout) {
719 elapse_timeouts();
720 if (first_timeout->time <= 0) return 1;
721 } else {
722 reset_clock = 1;
723 }
724#endif
725 return fl_ready();
726}
727
728////////////////////////////////////////////////////////////////
729// Window list management:
730
731#ifndef FL_DOXYGEN
732Fl_X* Fl_X::first;
733#endif
734
735Fl_Window* fl_find(Window xid) {
736 Fl_X *window;
737 for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next)
738#if defined(WIN32) || defined(USE_X11)
739 if (window->xid == xid)
740#elif defined(__APPLE_QUARTZ__)
741 if (window->xid == xid && !window->w->window())
742#else
743# error unsupported platform
744#endif // __APPLE__
745 {
746 if (window != Fl_X::first && !Fl::modal()) {
747 // make this window be first to speed up searches
748 // this is not done if modal is true to avoid messing up modal stack
749 *pp = window->next;
750 window->next = Fl_X::first;
751 Fl_X::first = window;
752 }
753 return window->w;
754 }
755 return 0;
756}
757
758/**
759 Returns the first top-level window in the list of shown() windows. If
760 a modal() window is shown this is the top-most modal window, otherwise
761 it is the most recent window to get an event.
762*/
763Fl_Window* Fl::first_window() {
764 Fl_X* i = Fl_X::first;
765 return i ? i->w : 0;
766}
767
768/**
769 Returns the next top-level window in the list of shown() windows.
770 You can use this call to iterate through all the windows that are shown().
771 \param[in] window must be shown and not NULL
772*/
773Fl_Window* Fl::next_window(const Fl_Window* window) {
774 Fl_X* i = Fl_X::i(window)->next;
775 return i ? i->w : 0;
776}
777
778/**
779 Sets the window that is returned by first_window().
780 The window is removed from wherever it is in the
781 list and inserted at the top. This is not done if Fl::modal()
782 is on or if the window is not shown(). Because the first window
783 is used to set the "parent" of modal windows, this is often
784 useful.
785 */
786void Fl::first_window(Fl_Window* window) {
787 if (!window || !window->shown()) return;
788 fl_find( Fl_X::i(window)->xid );
789}
790
791/**
792 Redraws all widgets.
793*/
794void Fl::redraw() {
795 for (Fl_X* i = Fl_X::first; i; i = i->next) i->w->redraw();
796}
797
798/**
799 Causes all the windows that need it to be redrawn and graphics forced
800 out through the pipes.
801
802 This is what wait() does before looking for events.
803
804 Note: in multi-threaded applications you should only call Fl::flush()
805 from the main thread. If a child thread needs to trigger a redraw event,
806 it should instead call Fl::awake() to get the main thread to process the
807 event queue.
808*/
809void Fl::flush() {
810 if (damage()) {
811 damage_ = 0;
812 for (Fl_X* i = Fl_X::first; i; i = i->next) {
813 if (i->wait_for_expose) {damage_ = 1; continue;}
814 Fl_Window* wi = i->w;
815 if (!wi->visible_r()) continue;
816 if (wi->damage()) {i->flush(); wi->clear_damage();}
817 // destroy damage regions for windows that don't use them:
818 if (i->region) {XDestroyRegion(i->region); i->region = 0;}
819 }
820 }
821#if defined(USE_X11)
822 if (fl_display) XFlush(fl_display);
823#elif defined(WIN32)
824 GdiFlush();
825#elif defined (__APPLE_QUARTZ__)
826 if (fl_gc)
827 CGContextFlush(fl_gc);
828#else
829# error unsupported platform
830#endif
831}
832
833
834////////////////////////////////////////////////////////////////
835// Event handlers:
836
837
838struct handler_link {
839 int (*handle)(int);
840 handler_link *next;
841};
842
843
844static handler_link *handlers = 0;
845
846
847/**
848 Install a function to parse unrecognized events. If FLTK cannot
849 figure out what to do with an event, it calls each of these functions
850 (most recent first) until one of them returns non-zero. If none of
851 them returns non-zero then the event is ignored. Events that cause
852 this to be called are:
853
854 - FL_SHORTCUT events that are not recognized by any widget.
855 This lets you provide global shortcut keys.
856 - System events that FLTK does not recognize. See fl_xevent.
857 - \e Some other events when the widget FLTK selected returns
858 zero from its handle() method. Exactly which ones may change
859 in future versions, however.
860
861 \see Fl::remove_handler(Fl_Event_Handler)
862 \see Fl::event_dispatch(Fl_Event_Dispatch d)
863 \see Fl::handle(int, Fl_Window*)
864*/
865void Fl::add_handler(Fl_Event_Handler ha) {
866 handler_link *l = new handler_link;
867 l->handle = ha;
868 l->next = handlers;
869 handlers = l;
870}
871
872
873/**
874 Removes a previously added event handler.
875 \see Fl::handle(int, Fl_Window*)
876*/
877void Fl::remove_handler(Fl_Event_Handler ha) {
878 handler_link *l, *p;
879
880 // Search for the handler in the list...
881 for (l = handlers, p = 0; l && l->handle != ha; p = l, l = l->next);
882
883 if (l) {
884 // Found it, so remove it from the list...
885 if (p) p->next = l->next;
886 else handlers = l->next;
887
888 // And free the record...
889 delete l;
890 }
891}
892
893int (*fl_local_grab)(int); // used by fl_dnd.cxx
894
895static int send_handlers(int e) {
896 for (const handler_link *hl = handlers; hl; hl = hl->next)
897 if (hl->handle(e)) return 1;
898 return 0;
899}
900
901////////////////////////////////////////////////////////////////
902
903Fl_Widget* fl_oldfocus; // kludge for Fl_Group...
904
905/**
906 Sets the widget that will receive FL_KEYBOARD events.
907
908 If you change Fl::focus(), the previous widget and all
909 parents (that don't contain the new widget) are sent FL_UNFOCUS
910 events. Changing the focus does \e not send FL_FOCUS to
911 this or any widget, because sending FL_FOCUS is supposed to
912 \e test if the widget wants the focus (by it returning non-zero from
913 handle()).
914
915 \see Fl_Widget::take_focus()
916*/
917void Fl::focus(Fl_Widget *o) {
918 if (o && !o->visible_focus()) return;
919 if (grab()) return; // don't do anything while grab is on
920 Fl_Widget *p = focus_;
921 if (o != p) {
922 Fl::compose_reset();
923 focus_ = o;
924 // make sure that fl_xfocus is set to the top level window
925 // of this widget, or fl_fix_focus will clear our focus again
926 if (o) {
927 Fl_Window *win = 0, *w1 = o->as_window();
928 if (!w1) w1 = o->window();
929 while (w1) { win=w1; w1=win->window(); }
930 if (win) {
931#ifdef __APPLE__
932 if (fl_xfocus != win) {
933 Fl_X *x = Fl_X::i(win);
934 if (x) x->set_key_window();
935 }
936#endif
937 fl_xfocus = win;
938 }
939 }
940 // take focus from the old focused window
941 fl_oldfocus = 0;
942 int old_event = e_number;
943 e_number = FL_UNFOCUS;
944 for (; p; p = p->parent()) {
945 p->handle(FL_UNFOCUS);
946 fl_oldfocus = p;
947 }
948 e_number = old_event;
DRC685f17e2011-07-28 09:23:00 +0000949 // let the platform code do what it needs
950 fl_update_focus();
DRC2ff39b82011-07-28 08:38:59 +0000951 }
952}
953
954static char dnd_flag = 0; // make 'belowmouse' send DND_LEAVE instead of LEAVE
955
956/**
957 Sets the widget that is below the mouse. This is for
958 highlighting buttons. It is not used to send FL_PUSH or
959 FL_MOVE directly, for several obscure reasons, but those events
960 typically go to this widget. This is also the first widget tried for
961 FL_SHORTCUT events.
962
963 If you change the belowmouse widget, the previous one and all
964 parents (that don't contain the new widget) are sent FL_LEAVE
965 events. Changing this does \e not send FL_ENTER to this
966 or any widget, because sending FL_ENTER is supposed to \e test
967 if the widget wants the mouse (by it returning non-zero from
968 handle()).
969*/
970void Fl::belowmouse(Fl_Widget *o) {
971 if (grab()) return; // don't do anything while grab is on
972 Fl_Widget *p = belowmouse_;
973 if (o != p) {
974 belowmouse_ = o;
975 int old_event = e_number;
976 e_number = dnd_flag ? FL_DND_LEAVE : FL_LEAVE;
977 for (; p && !p->contains(o); p = p->parent()) {
978 p->handle(e_number);
979 }
980 e_number = old_event;
981 }
982}
983
984/**
985 Sets the widget that is being pushed. FL_DRAG or
986 FL_RELEASE (and any more FL_PUSH) events will be sent to
987 this widget.
988
989 If you change the pushed widget, the previous one and all parents
990 (that don't contain the new widget) are sent FL_RELEASE
991 events. Changing this does \e not send FL_PUSH to this
992 or any widget, because sending FL_PUSH is supposed to \e test
993 if the widget wants the mouse (by it returning non-zero from
994 handle()).
995*/
996 void Fl::pushed(Fl_Widget *o) {
997 pushed_ = o;
998}
999
1000static void nothing(Fl_Widget *) {}
1001void (*Fl_Tooltip::enter)(Fl_Widget *) = nothing;
1002void (*Fl_Tooltip::exit)(Fl_Widget *) = nothing;
1003
1004// Update modal(), focus() and other state according to system state,
1005// and send FL_ENTER, FL_LEAVE, FL_FOCUS, and/or FL_UNFOCUS events.
1006// This is the only function that produces these events in response
1007// to system activity.
1008// This is called whenever a window is added or hidden, and whenever
1009// X says the focus or mouse window have changed.
1010
1011void fl_fix_focus() {
1012#ifdef DEBUG
1013 puts("fl_fix_focus();");
1014#endif // DEBUG
1015
1016 if (Fl::grab()) return; // don't do anything while grab is on.
1017
1018 // set focus based on Fl::modal() and fl_xfocus
1019 Fl_Widget* w = fl_xfocus;
1020 if (w) {
1021 int saved = Fl::e_keysym;
1022 if (Fl::e_keysym < (FL_Button + FL_LEFT_MOUSE) ||
1023 Fl::e_keysym > (FL_Button + FL_RIGHT_MOUSE))
1024 Fl::e_keysym = 0; // make sure widgets don't think a keystroke moved focus
1025 while (w->parent()) w = w->parent();
1026 if (Fl::modal()) w = Fl::modal();
1027 if (!w->contains(Fl::focus()))
1028 if (!w->take_focus()) Fl::focus(w);
1029 Fl::e_keysym = saved;
1030 } else
1031 Fl::focus(0);
1032
1033// MRS: Originally we checked the button state, but a user reported that it
1034// broke click-to-focus in FLWM?!?
1035// if (!(Fl::event_state() & 0x7f00000 /*FL_BUTTONS*/)) {
1036 if (!Fl::pushed()) {
1037 // set belowmouse based on Fl::modal() and fl_xmousewin:
1038 w = fl_xmousewin;
1039 if (w) {
1040 if (Fl::modal()) w = Fl::modal();
1041 if (!w->contains(Fl::belowmouse())) {
1042 int old_event = Fl::e_number;
1043 w->handle(Fl::e_number = FL_ENTER);
1044 Fl::e_number = old_event;
1045 if (!w->contains(Fl::belowmouse())) Fl::belowmouse(w);
1046 } else {
1047 // send a FL_MOVE event so the enter/leave state is up to date
1048 Fl::e_x = Fl::e_x_root-fl_xmousewin->x();
1049 Fl::e_y = Fl::e_y_root-fl_xmousewin->y();
1050 int old_event = Fl::e_number;
1051 w->handle(Fl::e_number = FL_MOVE);
1052 Fl::e_number = old_event;
1053 }
1054 } else {
1055 Fl::belowmouse(0);
1056 Fl_Tooltip::enter(0);
1057 }
1058 }
1059}
1060
1061#if !(defined(WIN32) || defined(__APPLE__))
1062extern Fl_Widget *fl_selection_requestor; // from Fl_x.cxx
1063#endif
1064
1065// This function is called by ~Fl_Widget() and by Fl_Widget::deactivate()
1066// and by Fl_Widget::hide(). It indicates that the widget does not want
1067// to receive any more events, and also removes all global variables that
1068// point at the widget.
1069// I changed this from the 1.0.1 behavior, the older version could send
1070// FL_LEAVE or FL_UNFOCUS events to the widget. This appears to not be
1071// desirable behavior and caused flwm to crash.
1072
1073void fl_throw_focus(Fl_Widget *o) {
1074#ifdef DEBUG
1075 printf("fl_throw_focus(o=%p)\n", o);
1076#endif // DEBUG
1077
1078 if (o->contains(Fl::pushed())) Fl::pushed_ = 0;
1079#if !(defined(WIN32) || defined(__APPLE__))
1080 if (o->contains(fl_selection_requestor)) fl_selection_requestor = 0;
1081#endif
1082 if (o->contains(Fl::belowmouse())) Fl::belowmouse_ = 0;
1083 if (o->contains(Fl::focus())) Fl::focus_ = 0;
1084 if (o == fl_xfocus) fl_xfocus = 0;
1085 if (o == Fl_Tooltip::current()) Fl_Tooltip::current(0);
1086 if (o == fl_xmousewin) fl_xmousewin = 0;
1087 Fl_Tooltip::exit(o);
1088 fl_fix_focus();
1089}
1090
1091////////////////////////////////////////////////////////////////
1092
1093// Call to->handle(), but first replace the mouse x/y with the correct
1094// values to account for nested windows. 'window' is the outermost
1095// window the event was posted to by the system:
1096static int send(int event, Fl_Widget* to, Fl_Window* window) {
1097 int dx, dy;
1098 int old_event = Fl::e_number;
1099 if (window) {
1100 dx = window->x();
1101 dy = window->y();
1102 } else {
1103 dx = dy = 0;
1104 }
1105 for (const Fl_Widget* w = to; w; w = w->parent())
1106 if (w->type()>=FL_WINDOW) {dx -= w->x(); dy -= w->y();}
1107 int save_x = Fl::e_x; Fl::e_x += dx;
1108 int save_y = Fl::e_y; Fl::e_y += dy;
1109 int ret = to->handle(Fl::e_number = event);
1110 Fl::e_number = old_event;
1111 Fl::e_y = save_y;
1112 Fl::e_x = save_x;
1113 return ret;
1114}
1115
1116
1117/**
1118 \brief Set a new event dispatch function.
1119
1120 The event dispatch function is called after native events are converted to
1121 FLTK events, but before they are handled by FLTK. If the dispatch function
1122 Fl_Event_Dispatch \p d is set, it is up to the dispatch function to call
1123 Fl::handle_(int, Fl_Window*) or to ignore the event.
1124
1125 The dispatch function itself must return 0 if it ignored the event,
1126 or non-zero if it used the event. If you call Fl::handle_(), then
1127 this will return the correct value.
1128
1129 The event dispatch can be used to handle exceptions in FLTK events and
1130 callbacks before they reach the native event handler:
1131
1132 \code
1133 int myHandler(int e, Fl_Window *w) {
1134 try {
1135 return Fl::handle_(e, w);
1136 } catch () {
1137 ...
1138 }
1139 }
1140
1141 main() {
1142 Fl::event_dispatch(myHandler);
1143 ...
1144 Fl::run();
1145 }
1146 \endcode
1147
1148 \param d new dispatch function, or NULL
1149 \see Fl::add_handler(Fl_Event_Handler)
1150 \see Fl::handle(int, Fl_Window*)
1151 \see Fl::handle_(int, Fl_Window*)
1152 */
1153void Fl::event_dispatch(Fl_Event_Dispatch d)
1154{
1155 e_dispatch = d;
1156}
1157
1158
1159/**
1160 \brief Return the current event dispatch function.
1161 */
1162Fl_Event_Dispatch Fl::event_dispatch()
1163{
1164 return e_dispatch;
1165}
1166
1167
1168/**
1169 \brief Handle events from the window system.
1170
1171 This is called from the native event dispatch after native events have been
1172 converted to FLTK notation. This function calls Fl::handle_(int, Fl_Window*)
1173 unless the user sets a dispatch function. If a user dispatch function is set,
1174 the user must make sure that Fl::handle_() is called, or the event will be
1175 ignored.
1176
1177 \param e the event type (Fl::event_number() is not yet set)
1178 \param window the window that caused this event
1179 \return 0 if the event was not handled
1180
1181 \see Fl::add_handler(Fl_Event_Handler)
1182 \see Fl::event_dispatch(Fl_Event_Dispatch)
1183 */
1184int Fl::handle(int e, Fl_Window* window)
1185{
1186 if (e_dispatch) {
1187 return e_dispatch(e, window);
1188 } else {
1189 return handle_(e, window);
1190 }
1191}
1192
1193
1194/**
1195 \brief Handle events from the window system.
1196
1197 This function is called from the native event dispatch, unless the user sets
1198 another dispatch function. In that case, the user dispatch function must
1199 decide when to call Fl::handle_(int, Fl_Window*)
1200
1201 \param e the event type (Fl::event_number() is not yet set)
1202 \param window the window that caused this event
1203 \return 0 if the event was not handled
1204
1205 \see Fl::event_dispatch(Fl_Event_Dispatch)
1206 */
1207int Fl::handle_(int e, Fl_Window* window)
1208{
1209 e_number = e;
1210 if (fl_local_grab) return fl_local_grab(e);
1211
1212 Fl_Widget* wi = window;
1213
1214 switch (e) {
1215
1216 case FL_CLOSE:
1217 if ( grab() || (modal() && window != modal()) ) return 0;
1218 wi->do_callback();
1219 return 1;
1220
1221 case FL_SHOW:
1222 wi->Fl_Widget::show(); // this calls Fl_Widget::show(), not Fl_Window::show()
1223 return 1;
1224
1225 case FL_HIDE:
1226 wi->Fl_Widget::hide(); // this calls Fl_Widget::hide(), not Fl_Window::hide()
1227 return 1;
1228
1229 case FL_PUSH:
1230#ifdef DEBUG
1231 printf("Fl::handle(e=%d, window=%p);\n", e, window);
1232#endif // DEBUG
1233
1234 if (grab()) wi = grab();
1235 else if (modal() && wi != modal()) return 0;
1236 pushed_ = wi;
1237 Fl_Tooltip::current(wi);
1238 if (send(e, wi, window)) return 1;
1239 // raise windows that are clicked on:
1240 window->show();
1241 return 1;
1242
1243 case FL_DND_ENTER:
1244 case FL_DND_DRAG:
1245 dnd_flag = 1;
1246 break;
1247
1248 case FL_DND_LEAVE:
1249 dnd_flag = 1;
1250 belowmouse(0);
1251 dnd_flag = 0;
1252 return 1;
1253
1254 case FL_DND_RELEASE:
1255 wi = belowmouse();
1256 break;
1257
1258 case FL_MOVE:
1259 case FL_DRAG:
1260 fl_xmousewin = window; // this should already be set, but just in case.
1261 if (pushed()) {
1262 wi = pushed();
1263 if (grab()) wi = grab();
1264 e_number = e = FL_DRAG;
1265 break;
1266 }
1267 if (modal() && wi != modal()) wi = 0;
1268 if (grab()) wi = grab();
1269 { int ret;
1270 Fl_Widget* pbm = belowmouse();
1271#ifdef __APPLE__
1272 if (fl_mac_os_version < 100500) {
1273 // before 10.5, mouse moved events aren't sent to borderless windows such as tooltips
1274 Fl_Window *tooltip = Fl_Tooltip::current_window();
1275 int inside = 0;
1276 if (tooltip && tooltip->shown() ) { // check if a tooltip window is currently opened
1277 // check if mouse is inside the tooltip
1278 inside = (Fl::event_x_root() >= tooltip->x() && Fl::event_x_root() < tooltip->x() + tooltip->w() &&
1279 Fl::event_y_root() >= tooltip->y() && Fl::event_y_root() < tooltip->y() + tooltip->h() );
1280 }
1281 // if inside, send event to tooltip window instead of background window
1282 if (inside) ret = send(e, tooltip, window);
1283 else ret = (wi && send(e, wi, window));
1284 } else
1285#endif
1286 ret = (wi && send(e, wi, window));
1287 if (pbm != belowmouse()) {
1288#ifdef DEBUG
1289 printf("Fl::handle(e=%d, window=%p);\n", e, window);
1290#endif // DEBUG
1291 Fl_Tooltip::enter(belowmouse());
1292 }
1293 return ret;}
1294
1295 case FL_RELEASE: {
1296// printf("FL_RELEASE: window=%p, pushed() = %p, grab() = %p, modal() = %p\n",
1297// window, pushed(), grab(), modal());
1298
1299 if (grab()) {
1300 wi = grab();
1301 pushed_ = 0; // must be zero before callback is done!
1302 } else if (pushed()) {
1303 wi = pushed();
1304 pushed_ = 0; // must be zero before callback is done!
1305 } else if (modal() && wi != modal()) return 0;
1306 int r = send(e, wi, window);
1307 fl_fix_focus();
1308 return r;}
1309
1310 case FL_UNFOCUS:
1311 window = 0;
1312 case FL_FOCUS:
1313 fl_xfocus = window;
1314 fl_fix_focus();
1315 return 1;
1316
1317 case FL_KEYUP:
1318 // Send the key-up to the current focus widget. This is not
1319 // always the same widget that received the corresponding
1320 // FL_KEYBOARD event because focus may have changed.
1321 // Sending the KEYUP to the right KEYDOWN is possible, but
1322 // would require that we track the KEYDOWN for every possible
1323 // key stroke (users may hold down multiple keys!) and then
1324 // make sure that the widget still exists before sending
1325 // a KEYUP there. I believe that the current solution is
1326 // "close enough".
1327 for (wi = grab() ? grab() : focus(); wi; wi = wi->parent())
1328 if (send(FL_KEYUP, wi, window)) return 1;
1329 return 0;
1330
1331 case FL_KEYBOARD:
1332#ifdef DEBUG
1333 printf("Fl::handle(e=%d, window=%p);\n", e, window);
1334#endif // DEBUG
1335
1336 Fl_Tooltip::enter((Fl_Widget*)0);
1337
1338 fl_xfocus = window; // this should not happen! But maybe it does:
1339
1340 // Try it as keystroke, sending it to focus and all parents:
1341 for (wi = grab() ? grab() : focus(); wi; wi = wi->parent())
1342 if (send(FL_KEYBOARD, wi, window)) return 1;
1343
1344 // recursive call to try shortcut:
1345 if (handle(FL_SHORTCUT, window)) return 1;
1346
1347 // and then try a shortcut with the case of the text swapped, by
1348 // changing the text and falling through to FL_SHORTCUT case:
1349 {unsigned char* c = (unsigned char*)event_text(); // cast away const
1350 if (!isalpha(*c)) return 0;
1351 *c = isupper(*c) ? tolower(*c) : toupper(*c);}
1352 e_number = e = FL_SHORTCUT;
1353
1354 case FL_SHORTCUT:
1355 if (grab()) {wi = grab(); break;} // send it to grab window
1356
1357 // Try it as shortcut, sending to mouse widget and all parents:
1358 wi = belowmouse();
1359 if (!wi) {
1360 wi = modal();
1361 if (!wi) wi = window;
1362 } else if (wi->window() != first_window()) {
1363 if (send(FL_SHORTCUT, first_window(), first_window())) return 1;
1364 }
1365
1366 for (; wi; wi = wi->parent()) {
1367 if (send(FL_SHORTCUT, wi, wi->window())) return 1;
1368 }
1369
1370 // try using add_handle() functions:
1371 if (send_handlers(FL_SHORTCUT)) return 1;
1372
1373 // make Escape key close windows:
1374 if (event_key()==FL_Escape) {
1375 wi = modal(); if (!wi) wi = window;
1376 wi->do_callback();
1377 return 1;
1378 }
1379
1380 return 0;
1381
1382 case FL_ENTER:
1383#ifdef DEBUG
1384 printf("Fl::handle(e=%d, window=%p);\n", e, window);
1385#endif // DEBUG
1386
1387 fl_xmousewin = window;
1388 fl_fix_focus();
1389 Fl_Tooltip::enter(belowmouse());
1390 return 1;
1391
1392 case FL_LEAVE:
1393#ifdef DEBUG
1394 printf("Fl::handle(e=%d, window=%p);\n", e, window);
1395#endif // DEBUG
1396
1397 if (!pushed_) {
1398 belowmouse(0);
1399 Fl_Tooltip::enter(0);
1400 }
1401 if (window == fl_xmousewin) {fl_xmousewin = 0; fl_fix_focus();}
1402 return 1;
1403
1404 case FL_MOUSEWHEEL:
1405 fl_xfocus = window; // this should not happen! But maybe it does:
1406
1407 // Try sending it to the "grab" first
1408 if (grab() && grab()!=modal() && grab()!=window) {
1409 if (send(FL_MOUSEWHEEL, grab(), window)) return 1;
1410 }
1411 // Now try sending it to the "modal" window
1412 if (modal()) {
1413 send(FL_MOUSEWHEEL, modal(), window);
1414 return 1;
1415 }
1416 // Finally try sending it to the window, the event occured in
1417 if (send(FL_MOUSEWHEEL, window, window)) return 1;
1418 default:
1419 break;
1420 }
1421 if (wi && send(e, wi, window)) {
1422 dnd_flag = 0;
1423 return 1;
1424 }
1425 dnd_flag = 0;
1426 return send_handlers(e);
1427}
1428
1429////////////////////////////////////////////////////////////////
1430// hide() destroys the X window, it does not do unmap!
1431
DRC685f17e2011-07-28 09:23:00 +00001432#if defined(WIN32)
1433extern void fl_clipboard_notify_untarget(HWND wnd);
1434extern void fl_update_clipboard(void);
1435#elif USE_XFT
DRC2ff39b82011-07-28 08:38:59 +00001436extern void fl_destroy_xft_draw(Window);
1437#endif
1438
1439void Fl_Window::hide() {
1440 clear_visible();
1441
1442 if (!shown()) return;
1443
1444 // remove from the list of windows:
1445 Fl_X* ip = i;
1446 Fl_X** pp = &Fl_X::first;
1447 for (; *pp != ip; pp = &(*pp)->next) if (!*pp) return;
1448 *pp = ip->next;
1449#ifdef __APPLE__
1450 ip->unlink();
1451 // MacOS X manages a single pointer per application. Make sure that hiding
1452 // a toplevel window will not leave us with some random pointer shape, or
1453 // worst case, an invisible pointer
1454 if (!parent()) cursor(FL_CURSOR_DEFAULT);
1455#endif
1456 i = 0;
1457
1458 // recursively remove any subwindows:
1459 for (Fl_X *wi = Fl_X::first; wi;) {
1460 Fl_Window* W = wi->w;
1461 if (W->window() == this) {
1462 W->hide();
1463 W->set_visible();
1464 wi = Fl_X::first;
1465 } else wi = wi->next;
1466 }
1467
1468 if (this == Fl::modal_) { // we are closing the modal window, find next one:
1469 Fl_Window* W;
1470 for (W = Fl::first_window(); W; W = Fl::next_window(W))
1471 if (W->modal()) break;
1472 Fl::modal_ = W;
1473 }
1474
1475 // Make sure no events are sent to this window:
1476 fl_throw_focus(this);
1477 handle(FL_HIDE);
1478
1479#if defined(WIN32)
1480 // this little trick keeps the current clipboard alive, even if we are about
1481 // to destroy the window that owns the selection.
DRC685f17e2011-07-28 09:23:00 +00001482 if (GetClipboardOwner()==ip->xid)
1483 fl_update_clipboard();
1484 // Make sure we unlink this window from the clipboard chain
1485 fl_clipboard_notify_untarget(ip->xid);
DRC2ff39b82011-07-28 08:38:59 +00001486 // Send a message to myself so that I'll get out of the event loop...
1487 PostMessage(ip->xid, WM_APP, 0, 0);
1488 if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
1489 if (ip->xid == fl_window && fl_gc) {
1490 fl_release_dc(fl_window, fl_gc);
1491 fl_window = (HWND)-1;
1492 fl_gc = 0;
1493# ifdef FLTK_USE_CAIRO
1494 if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0);
1495# endif
1496 }
1497#elif defined(__APPLE_QUARTZ__)
1498 Fl_X::q_release_context(ip);
1499 if ( ip->xid == fl_window && !parent() )
1500 fl_window = 0;
1501#endif
1502
1503 if (ip->region) XDestroyRegion(ip->region);
1504
1505#if defined(USE_X11)
1506# if USE_XFT
1507 fl_destroy_xft_draw(ip->xid);
1508# endif
1509 // this test makes sure ip->xid has not been destroyed already
1510 if (ip->xid) XDestroyWindow(fl_display, ip->xid);
1511#elif defined(WIN32)
1512 // this little trickery seems to avoid the popup window stacking problem
1513 HWND p = GetForegroundWindow();
1514 if (p==GetParent(ip->xid)) {
1515 ShowWindow(ip->xid, SW_HIDE);
1516 ShowWindow(p, SW_SHOWNA);
1517 }
1518 XDestroyWindow(fl_display, ip->xid);
1519#elif defined(__APPLE_QUARTZ__)
1520 ip->destroy();
1521#else
1522# error unsupported platform
1523#endif
1524
1525#ifdef WIN32
1526 // Try to stop the annoying "raise another program" behavior
1527 if (non_modal() && Fl::first_window() && Fl::first_window()->shown())
1528 Fl::first_window()->show();
1529#endif
1530 delete ip;
1531}
1532
1533Fl_Window::~Fl_Window() {
1534 hide();
1535 if (xclass_) {
1536 free(xclass_);
1537 }
1538}
1539
1540// FL_SHOW and FL_HIDE are called whenever the visibility of this widget
1541// or any parent changes. We must correctly map/unmap the system's window.
1542
1543// For top-level windows it is assumed the window has already been
1544// mapped or unmapped!!! This is because this should only happen when
1545// Fl_Window::show() or Fl_Window::hide() is called, or in response to
1546// iconize/deiconize events from the system.
1547
1548int Fl_Window::handle(int ev)
1549{
1550 if (parent()) {
1551 switch (ev) {
1552 case FL_SHOW:
1553 if (!shown()) show();
1554 else {
1555#if defined(USE_X11) || defined(WIN32)
1556 XMapWindow(fl_display, fl_xid(this)); // extra map calls are harmless
1557#elif defined(__APPLE_QUARTZ__)
1558 i->map();
1559#else
1560# error unsupported platform
1561#endif // __APPLE__
1562 }
1563 break;
1564 case FL_HIDE:
1565 if (shown()) {
1566 // Find what really turned invisible, if it was a parent window
1567 // we do nothing. We need to avoid unnecessary unmap calls
1568 // because they cause the display to blink when the parent is
1569 // remapped. However if this or any intermediate non-window
1570 // widget has really had hide() called directly on it, we must
1571 // unmap because when the parent window is remapped we don't
1572 // want to reappear.
1573 if (visible()) {
1574 Fl_Widget* p = parent(); for (;p->visible();p = p->parent()) {}
1575 if (p->type() >= FL_WINDOW) break; // don't do the unmap
1576 }
1577#if defined(USE_X11) || defined(WIN32)
1578 XUnmapWindow(fl_display, fl_xid(this));
1579#elif defined(__APPLE_QUARTZ__)
1580 i->unmap();
1581#else
1582# error platform unsupported
1583#endif
1584 }
1585 break;
1586 }
1587// } else if (ev == FL_FOCUS || ev == FL_UNFOCUS) {
1588// Fl_Tooltip::exit(Fl_Tooltip::current());
1589 }
1590
1591 return Fl_Group::handle(ev);
1592}
1593
1594////////////////////////////////////////////////////////////////
1595// Back compatibility cut & paste functions for fltk 1.1 only:
1596
1597/** Back-compatibility only: The single-argument call can be used to
1598 move the selection to another widget or to set the owner to
1599 NULL, without changing the actual text of the
1600 selection. FL_SELECTIONCLEAR is sent to the previous
1601 selection owner, if any.
1602
1603 <i>Copying the buffer every time the selection is changed is
1604 obviously wasteful, especially for large selections. An interface will
1605 probably be added in a future version to allow the selection to be made
1606 by a callback function. The current interface will be emulated on top
1607 of this.</i>
1608*/
1609void Fl::selection_owner(Fl_Widget *owner) {selection_owner_ = owner;}
1610
1611/**
1612 Changes the current selection. The block of text is
1613 copied to an internal buffer by FLTK (be careful if doing this in
1614 response to an FL_PASTE as this \e may be the same buffer
1615 returned by event_text()). The selection_owner()
1616 widget is set to the passed owner.
1617*/
1618void Fl::selection(Fl_Widget &owner, const char* text, int len) {
1619 selection_owner_ = &owner;
1620 Fl::copy(text, len, 0);
1621}
1622
1623/** Backward compatibility only.
1624 This calls Fl::paste(receiver, 0);
1625 \see Fl::paste(Fl_Widget &receiver, int clipboard)
1626*/
1627void Fl::paste(Fl_Widget &receiver) {
1628 Fl::paste(receiver, 0);
1629}
1630
1631////////////////////////////////////////////////////////////////
1632
1633#include <FL/fl_draw.H>
1634
1635void Fl_Widget::redraw() {
1636 damage(FL_DAMAGE_ALL);
1637}
1638
1639void Fl_Widget::redraw_label() {
1640 if (window()) {
1641 if (box() == FL_NO_BOX) {
1642 // Widgets with the FL_NO_BOX boxtype need a parent to
1643 // redraw, since it is responsible for redrawing the
1644 // background...
1645 int X = x() > 0 ? x() - 1 : 0;
1646 int Y = y() > 0 ? y() - 1 : 0;
1647 window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2);
1648 }
1649
1650 if (align() && !(align() & FL_ALIGN_INSIDE) && window()->shown()) {
1651 // If the label is not inside the widget, compute the location of
1652 // the label and redraw the window within that bounding box...
1653 int W = 0, H = 0;
1654 label_.measure(W, H);
1655 W += 5; // Add a little to the size of the label to cover overflow
1656 H += 5;
1657
1658 // FIXME:
1659 // This assumes that measure() returns the correct outline, which it does
1660 // not in all possible cases of alignment combinedwith image and symbols.
1661 switch (align() & 0x0f) {
1662 case FL_ALIGN_TOP_LEFT:
1663 window()->damage(FL_DAMAGE_EXPOSE, x(), y()-H, W, H); break;
1664 case FL_ALIGN_TOP:
1665 window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()-H, W, H); break;
1666 case FL_ALIGN_TOP_RIGHT:
1667 window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()-H, W, H); break;
1668 case FL_ALIGN_LEFT_TOP:
1669 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y(), W, H); break;
1670 case FL_ALIGN_RIGHT_TOP:
1671 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y(), W, H); break;
1672 case FL_ALIGN_LEFT:
1673 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+(h()-H)/2, W, H); break;
1674 case FL_ALIGN_RIGHT:
1675 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+(h()-H)/2, W, H); break;
1676 case FL_ALIGN_LEFT_BOTTOM:
1677 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+h()-H, W, H); break;
1678 case FL_ALIGN_RIGHT_BOTTOM:
1679 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+h()-H, W, H); break;
1680 case FL_ALIGN_BOTTOM_LEFT:
1681 window()->damage(FL_DAMAGE_EXPOSE, x(), y()+h(), W, H); break;
1682 case FL_ALIGN_BOTTOM:
1683 window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()+h(), W, H); break;
1684 case FL_ALIGN_BOTTOM_RIGHT:
1685 window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()+h(), W, H); break;
1686 default:
1687 window()->damage(FL_DAMAGE_ALL); break;
1688 }
1689 } else {
1690 // The label is inside the widget, so just redraw the widget itself...
1691 damage(FL_DAMAGE_ALL);
1692 }
1693 }
1694}
1695
1696void Fl_Widget::damage(uchar fl) {
1697 if (type() < FL_WINDOW) {
1698 // damage only the rectangle covered by a child widget:
1699 damage(fl, x(), y(), w(), h());
1700 } else {
1701 // damage entire window by deleting the region:
1702 Fl_X* i = Fl_X::i((Fl_Window*)this);
1703 if (!i) return; // window not mapped, so ignore it
1704 if (i->region) {XDestroyRegion(i->region); i->region = 0;}
1705 damage_ |= fl;
1706 Fl::damage(FL_DAMAGE_CHILD);
1707 }
1708}
1709
1710void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
1711 Fl_Widget* wi = this;
1712 // mark all parent widgets between this and window with FL_DAMAGE_CHILD:
1713 while (wi->type() < FL_WINDOW) {
1714 wi->damage_ |= fl;
1715 wi = wi->parent();
1716 if (!wi) return;
1717 fl = FL_DAMAGE_CHILD;
1718 }
1719 Fl_X* i = Fl_X::i((Fl_Window*)wi);
1720 if (!i) return; // window not mapped, so ignore it
1721
1722 // clip the damage to the window and quit if none:
1723 if (X < 0) {W += X; X = 0;}
1724 if (Y < 0) {H += Y; Y = 0;}
1725 if (W > wi->w()-X) W = wi->w()-X;
1726 if (H > wi->h()-Y) H = wi->h()-Y;
1727 if (W <= 0 || H <= 0) return;
1728
1729 if (!X && !Y && W==wi->w() && H==wi->h()) {
1730 // if damage covers entire window delete region:
1731 wi->damage(fl);
1732 return;
1733 }
1734
1735 if (wi->damage()) {
1736 // if we already have damage we must merge with existing region:
1737 if (i->region) {
1738#if defined(USE_X11)
1739 XRectangle R;
1740 R.x = X; R.y = Y; R.width = W; R.height = H;
1741 XUnionRectWithRegion(&R, i->region, i->region);
1742#elif defined(WIN32)
1743 Fl_Region R = XRectangleRegion(X, Y, W, H);
1744 CombineRgn(i->region, i->region, R, RGN_OR);
1745 XDestroyRegion(R);
1746#elif defined(__APPLE_QUARTZ__)
1747 CGRect arg = fl_cgrectmake_cocoa(X, Y, W, H);
1748 int j; // don't add a rectangle totally inside the Fl_Region
1749 for(j = 0; j < i->region->count; j++) {
1750 if(CGRectContainsRect(i->region->rects[j], arg)) break;
1751 }
1752 if( j >= i->region->count) {
1753 i->region->rects = (CGRect*)realloc(i->region->rects, (++(i->region->count)) * sizeof(CGRect));
1754 i->region->rects[i->region->count - 1] = arg;
1755 }
1756#else
1757# error unsupported platform
1758#endif
1759 }
1760 wi->damage_ |= fl;
1761 } else {
1762 // create a new region:
1763 if (i->region) XDestroyRegion(i->region);
1764 i->region = XRectangleRegion(X,Y,W,H);
1765 wi->damage_ = fl;
1766 }
1767 Fl::damage(FL_DAMAGE_CHILD);
1768}
1769void Fl_Window::flush() {
1770 make_current();
1771//if (damage() == FL_DAMAGE_EXPOSE && can_boxcheat(box())) fl_boxcheat = this;
1772 fl_clip_region(i->region); i->region = 0;
1773 draw();
1774}
1775
1776#ifdef WIN32
1777# include "Fl_win32.cxx"
1778//#elif defined(__APPLE__)
1779#endif
1780
1781//
1782// The following methods allow callbacks to schedule the deletion of
1783// widgets at "safe" times.
1784//
1785
1786static int num_dwidgets = 0, alloc_dwidgets = 0;
1787static Fl_Widget **dwidgets = 0;
1788
1789/**
1790 Schedules a widget for deletion at the next call to the event loop.
1791 Use this method to delete a widget inside a callback function.
1792
1793 To avoid early deletion of widgets, this function should be called
1794 toward the end of a callback and only after any call to the event
1795 loop (Fl::wait(), Fl::flush(), Fl::check(), fl_ask(), etc.).
1796
1797 When deleting groups or windows, you must only delete the group or
1798 window widget and not the individual child widgets.
1799
1800 \since FLTK 1.3 it is not necessary to remove widgets from their parent
1801 groups or windows before calling this, because it will be done in the
1802 widget's destructor, but it is not a failure to do this nevertheless.
1803
1804 \note In FLTK 1.1 you \b must remove widgets from their parent group
1805 (or window) before deleting them.
1806
1807 \see Fl_Widget::~Fl_Widget()
1808*/
1809void Fl::delete_widget(Fl_Widget *wi) {
1810 if (!wi) return;
1811
1812 if (num_dwidgets >= alloc_dwidgets) {
1813 Fl_Widget **temp;
1814
1815 temp = new Fl_Widget *[alloc_dwidgets + 10];
1816 if (alloc_dwidgets) {
1817 memcpy(temp, dwidgets, alloc_dwidgets * sizeof(Fl_Widget *));
1818 delete[] dwidgets;
1819 }
1820
1821 dwidgets = temp;
1822 alloc_dwidgets += 10;
1823 }
1824
1825 dwidgets[num_dwidgets] = wi;
1826 num_dwidgets ++;
1827}
1828
1829/**
1830 Deletes widgets previously scheduled for deletion.
1831
1832 This is for internal use only. You should never call this directly.
1833
1834 Fl::do_widget_deletion() is called from the FLTK event loop or whenever
1835 you call Fl::wait(). The previously scheduled widgets are deleted in the
1836 same order they were scheduled by calling Fl::delete_widget().
1837
1838 \see Fl::delete_widget(Fl_Widget *wi)
1839*/
1840void Fl::do_widget_deletion() {
1841 if (!num_dwidgets) return;
1842
1843 for (int i = 0; i < num_dwidgets; i ++)
1844 delete dwidgets[i];
1845
1846 num_dwidgets = 0;
1847}
1848
1849static Fl_Widget ***widget_watch = 0;
1850static int num_widget_watch = 0;
1851static int max_widget_watch = 0;
1852
1853/**
1854 Adds a widget pointer to the widget watch list.
1855
1856 \note Internal use only, please use class Fl_Widget_Tracker instead.
1857
1858 This can be used, if it is possible that a widget might be deleted during
1859 a callback or similar function. The widget pointer must be added to the
1860 watch list before calling the callback. After the callback the widget
1861 pointer can be queried, if it is NULL. \e If it is NULL, then the widget has been
1862 deleted during the callback and must not be accessed anymore. If the widget
1863 pointer is \e not NULL, then the widget has not been deleted and can be accessed
1864 safely.
1865
1866 After accessing the widget, the widget pointer must be released from the
1867 watch list by calling Fl::release_widget_pointer().
1868
1869 Example for a button that is clicked (from its handle() method):
1870 \code
1871 Fl_Widget *wp = this; // save 'this' in a pointer variable
1872 Fl::watch_widget_pointer(wp); // add the pointer to the watch list
1873 set_changed(); // set the changed flag
1874 do_callback(); // call the callback
1875 if (!wp) { // the widget has been deleted
1876
1877 // DO NOT ACCESS THE DELETED WIDGET !
1878
1879 } else { // the widget still exists
1880 clear_changed(); // reset the changed flag
1881 }
1882
1883 Fl::release_widget_pointer(wp); // remove the pointer from the watch list
1884 \endcode
1885
1886 This works, because all widgets call Fl::clear_widget_pointer() in their
1887 destructors.
1888
1889 \see Fl::release_widget_pointer()
1890 \see Fl::clear_widget_pointer()
1891
1892 An easier and more convenient method to control widget deletion during
1893 callbacks is to use the class Fl_Widget_Tracker with a local (automatic)
1894 variable.
1895
1896 \see class Fl_Widget_Tracker
1897*/
1898void Fl::watch_widget_pointer(Fl_Widget *&w)
1899{
1900 Fl_Widget **wp = &w;
1901 int i;
1902 for (i=0; i<num_widget_watch; ++i) {
1903 if (widget_watch[i]==wp) return;
1904 }
1905 if (num_widget_watch==max_widget_watch) {
1906 max_widget_watch += 8;
1907 widget_watch = (Fl_Widget***)realloc(widget_watch, sizeof(Fl_Widget**)*max_widget_watch);
1908 }
1909 widget_watch[num_widget_watch++] = wp;
1910#ifdef DEBUG_WATCH
1911 printf ("\nwatch_widget_pointer: (%d/%d) %8p => %8p\n",
1912 num_widget_watch,num_widget_watch,wp,*wp);
1913 fflush(stdout);
1914#endif // DEBUG_WATCH
1915}
1916
1917/**
1918 Releases a widget pointer from the watch list.
1919
1920 This is used to remove a widget pointer that has been added to the watch list
1921 with Fl::watch_widget_pointer(), when it is not needed anymore.
1922
1923 \note Internal use only, please use class Fl_Widget_Tracker instead.
1924
1925 \see Fl::watch_widget_pointer()
1926*/
1927void Fl::release_widget_pointer(Fl_Widget *&w)
1928{
1929 Fl_Widget **wp = &w;
1930 int i,j=0;
1931 for (i=0; i<num_widget_watch; ++i) {
1932 if (widget_watch[i]!=wp) {
1933 if (j<i) widget_watch[j] = widget_watch[i]; // fill gap
1934 j++;
1935 }
1936#ifdef DEBUG_WATCH
1937 else { // found widget pointer
1938 printf ("release_widget_pointer: (%d/%d) %8p => %8p\n",
1939 i+1,num_widget_watch,wp,*wp);
1940 }
1941#endif //DEBUG_WATCH
1942 }
1943 num_widget_watch = j;
1944#ifdef DEBUG_WATCH
1945 printf (" num_widget_watch = %d\n\n",num_widget_watch);
1946 fflush(stdout);
1947#endif // DEBUG_WATCH
1948 return;
1949}
1950/**
1951 Clears a widget pointer \e in the watch list.
1952
1953 This is called when a widget is destroyed (by its destructor). You should never
1954 call this directly.
1955
1956 \note Internal use only !
1957
1958 This method searches the widget watch list for pointers to the widget and
1959 clears each pointer that points to it. Widget pointers can be added to the
1960 widget watch list by calling Fl::watch_widget_pointer() or by using the
1961 helper class Fl_Widget_Tracker (recommended).
1962
1963 \see Fl::watch_widget_pointer()
1964 \see class Fl_Widget_Tracker
1965*/
1966void Fl::clear_widget_pointer(Fl_Widget const *w)
1967{
1968 if (w==0L) return;
1969 int i;
1970 for (i=0; i<num_widget_watch; ++i) {
1971 if (widget_watch[i] && *widget_watch[i]==w) {
1972 *widget_watch[i] = 0L;
1973 }
1974 }
1975}
1976
1977
1978/**
1979 \brief FLTK library options management.
1980
1981 This function needs to be documented in more detail. It can be used for more
1982 optional settings, such as using a native file chooser instead of the FLTK one
1983 wherever possible, disabling tooltips, disabling visible focus, disabling
1984 FLTK file chooser preview, etc. .
1985
1986 There should be a command line option interface.
1987
1988 There should be an application that manages options system wide, per user, and
1989 per application.
1990
1991 \note As of FLTK 1.3.0, options can be managed within fluid, using the menu
1992 <i>Edit/Global FLTK Settings</i>.
1993
1994 \param opt which option
1995 \return true or false
1996 \see enum Fl::Fl_Option
1997 \see Fl::option(Fl_Option, bool)
1998
1999 \since FLTK 1.3.0
2000 */
2001bool Fl::option(Fl_Option opt)
2002{
2003 if (!options_read_) {
2004 int tmp;
2005 { // first, read the system wide preferences
2006 Fl_Preferences prefs(Fl_Preferences::SYSTEM, "fltk.org", "fltk");
2007 Fl_Preferences opt_prefs(prefs, "options");
2008 opt_prefs.get("ArrowFocus", tmp, 0); // default: off
2009 options_[OPTION_ARROW_FOCUS] = tmp;
2010 //opt_prefs.get("NativeFilechooser", tmp, 1); // default: on
2011 //options_[OPTION_NATIVE_FILECHOOSER] = tmp;
2012 //opt_prefs.get("FilechooserPreview", tmp, 1); // default: on
2013 //options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
2014 opt_prefs.get("VisibleFocus", tmp, 1); // default: on
2015 options_[OPTION_VISIBLE_FOCUS] = tmp;
2016 opt_prefs.get("DNDText", tmp, 1); // default: on
2017 options_[OPTION_DND_TEXT] = tmp;
2018 opt_prefs.get("ShowTooltips", tmp, 1); // default: on
2019 options_[OPTION_SHOW_TOOLTIPS] = tmp;
2020 }
2021 { // next, check the user preferences
2022 // override system options only, if the option is set ( >= 0 )
2023 Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "fltk");
2024 Fl_Preferences opt_prefs(prefs, "options");
2025 opt_prefs.get("ArrowFocus", tmp, -1);
2026 if (tmp >= 0) options_[OPTION_ARROW_FOCUS] = tmp;
2027 //opt_prefs.get("NativeFilechooser", tmp, -1);
2028 //if (tmp >= 0) options_[OPTION_NATIVE_FILECHOOSER] = tmp;
2029 //opt_prefs.get("FilechooserPreview", tmp, -1);
2030 //if (tmp >= 0) options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
2031 opt_prefs.get("VisibleFocus", tmp, -1);
2032 if (tmp >= 0) options_[OPTION_VISIBLE_FOCUS] = tmp;
2033 opt_prefs.get("DNDText", tmp, -1);
2034 if (tmp >= 0) options_[OPTION_DND_TEXT] = tmp;
2035 opt_prefs.get("ShowTooltips", tmp, -1);
2036 if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
2037 }
2038 { // now, if the developer has registered this app, we could as for per-application preferences
2039 }
2040 options_read_ = 1;
2041 }
2042 if (opt<0 || opt>=OPTION_LAST)
2043 return false;
2044 return (bool)(options_[opt]!=0);
2045}
2046
2047/**
2048 \brief Override an option while the application is running.
2049
2050 This function does not change any system or user settings.
2051
2052 \param opt which option
2053 \param val set to true or false
2054 \see enum Fl::Fl_Option
2055 \see bool Fl::option(Fl_Option)
2056 */
2057void Fl::option(Fl_Option opt, bool val)
2058{
2059 if (opt<0 || opt>=OPTION_LAST)
2060 return;
2061 if (!options_read_) {
2062 // first read this option, so we don't override our setting later
2063 option(opt);
2064 }
2065 options_[opt] = val;
2066}
2067
2068
2069// Helper class Fl_Widget_Tracker
2070
2071/**
2072 The constructor adds a widget to the watch list.
2073*/
2074Fl_Widget_Tracker::Fl_Widget_Tracker(Fl_Widget *wi)
2075{
2076 wp_ = wi;
2077 Fl::watch_widget_pointer(wp_); // add pointer to watch list
2078}
2079
2080/**
2081 The destructor removes a widget from the watch list.
2082*/
2083Fl_Widget_Tracker::~Fl_Widget_Tracker()
2084{
2085 Fl::release_widget_pointer(wp_); // remove pointer from watch list
2086}
2087
2088
2089//
2090// End of "$Id: Fl.cxx 8723 2011-05-23 16:49:02Z manolo $".
2091//