blob: 887c11fb5e7700267f8676d9422d8b7e4311b43b [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 }
Pierre Ossmanab8aeed2012-04-25 14:57:22 +00001538 free_icons();
1539 delete icon_;
DRC2ff39b82011-07-28 08:38:59 +00001540}
1541
1542// FL_SHOW and FL_HIDE are called whenever the visibility of this widget
1543// or any parent changes. We must correctly map/unmap the system's window.
1544
1545// For top-level windows it is assumed the window has already been
1546// mapped or unmapped!!! This is because this should only happen when
1547// Fl_Window::show() or Fl_Window::hide() is called, or in response to
1548// iconize/deiconize events from the system.
1549
1550int Fl_Window::handle(int ev)
1551{
1552 if (parent()) {
1553 switch (ev) {
1554 case FL_SHOW:
1555 if (!shown()) show();
1556 else {
1557#if defined(USE_X11) || defined(WIN32)
1558 XMapWindow(fl_display, fl_xid(this)); // extra map calls are harmless
1559#elif defined(__APPLE_QUARTZ__)
1560 i->map();
1561#else
1562# error unsupported platform
1563#endif // __APPLE__
1564 }
1565 break;
1566 case FL_HIDE:
1567 if (shown()) {
1568 // Find what really turned invisible, if it was a parent window
1569 // we do nothing. We need to avoid unnecessary unmap calls
1570 // because they cause the display to blink when the parent is
1571 // remapped. However if this or any intermediate non-window
1572 // widget has really had hide() called directly on it, we must
1573 // unmap because when the parent window is remapped we don't
1574 // want to reappear.
1575 if (visible()) {
1576 Fl_Widget* p = parent(); for (;p->visible();p = p->parent()) {}
1577 if (p->type() >= FL_WINDOW) break; // don't do the unmap
1578 }
1579#if defined(USE_X11) || defined(WIN32)
1580 XUnmapWindow(fl_display, fl_xid(this));
1581#elif defined(__APPLE_QUARTZ__)
1582 i->unmap();
1583#else
1584# error platform unsupported
1585#endif
1586 }
1587 break;
1588 }
1589// } else if (ev == FL_FOCUS || ev == FL_UNFOCUS) {
1590// Fl_Tooltip::exit(Fl_Tooltip::current());
1591 }
1592
1593 return Fl_Group::handle(ev);
1594}
1595
1596////////////////////////////////////////////////////////////////
1597// Back compatibility cut & paste functions for fltk 1.1 only:
1598
1599/** Back-compatibility only: The single-argument call can be used to
1600 move the selection to another widget or to set the owner to
1601 NULL, without changing the actual text of the
1602 selection. FL_SELECTIONCLEAR is sent to the previous
1603 selection owner, if any.
1604
1605 <i>Copying the buffer every time the selection is changed is
1606 obviously wasteful, especially for large selections. An interface will
1607 probably be added in a future version to allow the selection to be made
1608 by a callback function. The current interface will be emulated on top
1609 of this.</i>
1610*/
1611void Fl::selection_owner(Fl_Widget *owner) {selection_owner_ = owner;}
1612
1613/**
1614 Changes the current selection. The block of text is
1615 copied to an internal buffer by FLTK (be careful if doing this in
1616 response to an FL_PASTE as this \e may be the same buffer
1617 returned by event_text()). The selection_owner()
1618 widget is set to the passed owner.
1619*/
1620void Fl::selection(Fl_Widget &owner, const char* text, int len) {
1621 selection_owner_ = &owner;
1622 Fl::copy(text, len, 0);
1623}
1624
1625/** Backward compatibility only.
1626 This calls Fl::paste(receiver, 0);
1627 \see Fl::paste(Fl_Widget &receiver, int clipboard)
1628*/
1629void Fl::paste(Fl_Widget &receiver) {
1630 Fl::paste(receiver, 0);
1631}
1632
1633////////////////////////////////////////////////////////////////
1634
1635#include <FL/fl_draw.H>
1636
1637void Fl_Widget::redraw() {
1638 damage(FL_DAMAGE_ALL);
1639}
1640
1641void Fl_Widget::redraw_label() {
1642 if (window()) {
1643 if (box() == FL_NO_BOX) {
1644 // Widgets with the FL_NO_BOX boxtype need a parent to
1645 // redraw, since it is responsible for redrawing the
1646 // background...
1647 int X = x() > 0 ? x() - 1 : 0;
1648 int Y = y() > 0 ? y() - 1 : 0;
1649 window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2);
1650 }
1651
1652 if (align() && !(align() & FL_ALIGN_INSIDE) && window()->shown()) {
1653 // If the label is not inside the widget, compute the location of
1654 // the label and redraw the window within that bounding box...
1655 int W = 0, H = 0;
1656 label_.measure(W, H);
1657 W += 5; // Add a little to the size of the label to cover overflow
1658 H += 5;
1659
1660 // FIXME:
1661 // This assumes that measure() returns the correct outline, which it does
1662 // not in all possible cases of alignment combinedwith image and symbols.
1663 switch (align() & 0x0f) {
1664 case FL_ALIGN_TOP_LEFT:
1665 window()->damage(FL_DAMAGE_EXPOSE, x(), y()-H, W, H); break;
1666 case FL_ALIGN_TOP:
1667 window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()-H, W, H); break;
1668 case FL_ALIGN_TOP_RIGHT:
1669 window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()-H, W, H); break;
1670 case FL_ALIGN_LEFT_TOP:
1671 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y(), W, H); break;
1672 case FL_ALIGN_RIGHT_TOP:
1673 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y(), W, H); break;
1674 case FL_ALIGN_LEFT:
1675 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+(h()-H)/2, W, H); break;
1676 case FL_ALIGN_RIGHT:
1677 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+(h()-H)/2, W, H); break;
1678 case FL_ALIGN_LEFT_BOTTOM:
1679 window()->damage(FL_DAMAGE_EXPOSE, x()-W, y()+h()-H, W, H); break;
1680 case FL_ALIGN_RIGHT_BOTTOM:
1681 window()->damage(FL_DAMAGE_EXPOSE, x()+w(), y()+h()-H, W, H); break;
1682 case FL_ALIGN_BOTTOM_LEFT:
1683 window()->damage(FL_DAMAGE_EXPOSE, x(), y()+h(), W, H); break;
1684 case FL_ALIGN_BOTTOM:
1685 window()->damage(FL_DAMAGE_EXPOSE, x()+(w()-W)/2, y()+h(), W, H); break;
1686 case FL_ALIGN_BOTTOM_RIGHT:
1687 window()->damage(FL_DAMAGE_EXPOSE, x()+w()-W, y()+h(), W, H); break;
1688 default:
1689 window()->damage(FL_DAMAGE_ALL); break;
1690 }
1691 } else {
1692 // The label is inside the widget, so just redraw the widget itself...
1693 damage(FL_DAMAGE_ALL);
1694 }
1695 }
1696}
1697
1698void Fl_Widget::damage(uchar fl) {
1699 if (type() < FL_WINDOW) {
1700 // damage only the rectangle covered by a child widget:
1701 damage(fl, x(), y(), w(), h());
1702 } else {
1703 // damage entire window by deleting the region:
1704 Fl_X* i = Fl_X::i((Fl_Window*)this);
1705 if (!i) return; // window not mapped, so ignore it
1706 if (i->region) {XDestroyRegion(i->region); i->region = 0;}
1707 damage_ |= fl;
1708 Fl::damage(FL_DAMAGE_CHILD);
1709 }
1710}
1711
1712void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
1713 Fl_Widget* wi = this;
1714 // mark all parent widgets between this and window with FL_DAMAGE_CHILD:
1715 while (wi->type() < FL_WINDOW) {
1716 wi->damage_ |= fl;
1717 wi = wi->parent();
1718 if (!wi) return;
1719 fl = FL_DAMAGE_CHILD;
1720 }
1721 Fl_X* i = Fl_X::i((Fl_Window*)wi);
1722 if (!i) return; // window not mapped, so ignore it
1723
1724 // clip the damage to the window and quit if none:
1725 if (X < 0) {W += X; X = 0;}
1726 if (Y < 0) {H += Y; Y = 0;}
1727 if (W > wi->w()-X) W = wi->w()-X;
1728 if (H > wi->h()-Y) H = wi->h()-Y;
1729 if (W <= 0 || H <= 0) return;
1730
1731 if (!X && !Y && W==wi->w() && H==wi->h()) {
1732 // if damage covers entire window delete region:
1733 wi->damage(fl);
1734 return;
1735 }
1736
1737 if (wi->damage()) {
1738 // if we already have damage we must merge with existing region:
1739 if (i->region) {
1740#if defined(USE_X11)
1741 XRectangle R;
1742 R.x = X; R.y = Y; R.width = W; R.height = H;
1743 XUnionRectWithRegion(&R, i->region, i->region);
1744#elif defined(WIN32)
1745 Fl_Region R = XRectangleRegion(X, Y, W, H);
1746 CombineRgn(i->region, i->region, R, RGN_OR);
1747 XDestroyRegion(R);
1748#elif defined(__APPLE_QUARTZ__)
1749 CGRect arg = fl_cgrectmake_cocoa(X, Y, W, H);
1750 int j; // don't add a rectangle totally inside the Fl_Region
1751 for(j = 0; j < i->region->count; j++) {
1752 if(CGRectContainsRect(i->region->rects[j], arg)) break;
1753 }
1754 if( j >= i->region->count) {
1755 i->region->rects = (CGRect*)realloc(i->region->rects, (++(i->region->count)) * sizeof(CGRect));
1756 i->region->rects[i->region->count - 1] = arg;
1757 }
1758#else
1759# error unsupported platform
1760#endif
1761 }
1762 wi->damage_ |= fl;
1763 } else {
1764 // create a new region:
1765 if (i->region) XDestroyRegion(i->region);
1766 i->region = XRectangleRegion(X,Y,W,H);
1767 wi->damage_ = fl;
1768 }
1769 Fl::damage(FL_DAMAGE_CHILD);
1770}
1771void Fl_Window::flush() {
1772 make_current();
1773//if (damage() == FL_DAMAGE_EXPOSE && can_boxcheat(box())) fl_boxcheat = this;
1774 fl_clip_region(i->region); i->region = 0;
1775 draw();
1776}
1777
1778#ifdef WIN32
1779# include "Fl_win32.cxx"
1780//#elif defined(__APPLE__)
1781#endif
1782
1783//
1784// The following methods allow callbacks to schedule the deletion of
1785// widgets at "safe" times.
1786//
1787
1788static int num_dwidgets = 0, alloc_dwidgets = 0;
1789static Fl_Widget **dwidgets = 0;
1790
1791/**
1792 Schedules a widget for deletion at the next call to the event loop.
1793 Use this method to delete a widget inside a callback function.
1794
1795 To avoid early deletion of widgets, this function should be called
1796 toward the end of a callback and only after any call to the event
1797 loop (Fl::wait(), Fl::flush(), Fl::check(), fl_ask(), etc.).
1798
1799 When deleting groups or windows, you must only delete the group or
1800 window widget and not the individual child widgets.
1801
1802 \since FLTK 1.3 it is not necessary to remove widgets from their parent
1803 groups or windows before calling this, because it will be done in the
1804 widget's destructor, but it is not a failure to do this nevertheless.
1805
1806 \note In FLTK 1.1 you \b must remove widgets from their parent group
1807 (or window) before deleting them.
1808
1809 \see Fl_Widget::~Fl_Widget()
1810*/
1811void Fl::delete_widget(Fl_Widget *wi) {
1812 if (!wi) return;
1813
1814 if (num_dwidgets >= alloc_dwidgets) {
1815 Fl_Widget **temp;
1816
1817 temp = new Fl_Widget *[alloc_dwidgets + 10];
1818 if (alloc_dwidgets) {
1819 memcpy(temp, dwidgets, alloc_dwidgets * sizeof(Fl_Widget *));
1820 delete[] dwidgets;
1821 }
1822
1823 dwidgets = temp;
1824 alloc_dwidgets += 10;
1825 }
1826
1827 dwidgets[num_dwidgets] = wi;
1828 num_dwidgets ++;
1829}
1830
1831/**
1832 Deletes widgets previously scheduled for deletion.
1833
1834 This is for internal use only. You should never call this directly.
1835
1836 Fl::do_widget_deletion() is called from the FLTK event loop or whenever
1837 you call Fl::wait(). The previously scheduled widgets are deleted in the
1838 same order they were scheduled by calling Fl::delete_widget().
1839
1840 \see Fl::delete_widget(Fl_Widget *wi)
1841*/
1842void Fl::do_widget_deletion() {
1843 if (!num_dwidgets) return;
1844
1845 for (int i = 0; i < num_dwidgets; i ++)
1846 delete dwidgets[i];
1847
1848 num_dwidgets = 0;
1849}
1850
1851static Fl_Widget ***widget_watch = 0;
1852static int num_widget_watch = 0;
1853static int max_widget_watch = 0;
1854
1855/**
1856 Adds a widget pointer to the widget watch list.
1857
1858 \note Internal use only, please use class Fl_Widget_Tracker instead.
1859
1860 This can be used, if it is possible that a widget might be deleted during
1861 a callback or similar function. The widget pointer must be added to the
1862 watch list before calling the callback. After the callback the widget
1863 pointer can be queried, if it is NULL. \e If it is NULL, then the widget has been
1864 deleted during the callback and must not be accessed anymore. If the widget
1865 pointer is \e not NULL, then the widget has not been deleted and can be accessed
1866 safely.
1867
1868 After accessing the widget, the widget pointer must be released from the
1869 watch list by calling Fl::release_widget_pointer().
1870
1871 Example for a button that is clicked (from its handle() method):
1872 \code
1873 Fl_Widget *wp = this; // save 'this' in a pointer variable
1874 Fl::watch_widget_pointer(wp); // add the pointer to the watch list
1875 set_changed(); // set the changed flag
1876 do_callback(); // call the callback
1877 if (!wp) { // the widget has been deleted
1878
1879 // DO NOT ACCESS THE DELETED WIDGET !
1880
1881 } else { // the widget still exists
1882 clear_changed(); // reset the changed flag
1883 }
1884
1885 Fl::release_widget_pointer(wp); // remove the pointer from the watch list
1886 \endcode
1887
1888 This works, because all widgets call Fl::clear_widget_pointer() in their
1889 destructors.
1890
1891 \see Fl::release_widget_pointer()
1892 \see Fl::clear_widget_pointer()
1893
1894 An easier and more convenient method to control widget deletion during
1895 callbacks is to use the class Fl_Widget_Tracker with a local (automatic)
1896 variable.
1897
1898 \see class Fl_Widget_Tracker
1899*/
1900void Fl::watch_widget_pointer(Fl_Widget *&w)
1901{
1902 Fl_Widget **wp = &w;
1903 int i;
1904 for (i=0; i<num_widget_watch; ++i) {
1905 if (widget_watch[i]==wp) return;
1906 }
1907 if (num_widget_watch==max_widget_watch) {
1908 max_widget_watch += 8;
1909 widget_watch = (Fl_Widget***)realloc(widget_watch, sizeof(Fl_Widget**)*max_widget_watch);
1910 }
1911 widget_watch[num_widget_watch++] = wp;
1912#ifdef DEBUG_WATCH
1913 printf ("\nwatch_widget_pointer: (%d/%d) %8p => %8p\n",
1914 num_widget_watch,num_widget_watch,wp,*wp);
1915 fflush(stdout);
1916#endif // DEBUG_WATCH
1917}
1918
1919/**
1920 Releases a widget pointer from the watch list.
1921
1922 This is used to remove a widget pointer that has been added to the watch list
1923 with Fl::watch_widget_pointer(), when it is not needed anymore.
1924
1925 \note Internal use only, please use class Fl_Widget_Tracker instead.
1926
1927 \see Fl::watch_widget_pointer()
1928*/
1929void Fl::release_widget_pointer(Fl_Widget *&w)
1930{
1931 Fl_Widget **wp = &w;
1932 int i,j=0;
1933 for (i=0; i<num_widget_watch; ++i) {
1934 if (widget_watch[i]!=wp) {
1935 if (j<i) widget_watch[j] = widget_watch[i]; // fill gap
1936 j++;
1937 }
1938#ifdef DEBUG_WATCH
1939 else { // found widget pointer
1940 printf ("release_widget_pointer: (%d/%d) %8p => %8p\n",
1941 i+1,num_widget_watch,wp,*wp);
1942 }
1943#endif //DEBUG_WATCH
1944 }
1945 num_widget_watch = j;
1946#ifdef DEBUG_WATCH
1947 printf (" num_widget_watch = %d\n\n",num_widget_watch);
1948 fflush(stdout);
1949#endif // DEBUG_WATCH
1950 return;
1951}
1952/**
1953 Clears a widget pointer \e in the watch list.
1954
1955 This is called when a widget is destroyed (by its destructor). You should never
1956 call this directly.
1957
1958 \note Internal use only !
1959
1960 This method searches the widget watch list for pointers to the widget and
1961 clears each pointer that points to it. Widget pointers can be added to the
1962 widget watch list by calling Fl::watch_widget_pointer() or by using the
1963 helper class Fl_Widget_Tracker (recommended).
1964
1965 \see Fl::watch_widget_pointer()
1966 \see class Fl_Widget_Tracker
1967*/
1968void Fl::clear_widget_pointer(Fl_Widget const *w)
1969{
1970 if (w==0L) return;
1971 int i;
1972 for (i=0; i<num_widget_watch; ++i) {
1973 if (widget_watch[i] && *widget_watch[i]==w) {
1974 *widget_watch[i] = 0L;
1975 }
1976 }
1977}
1978
1979
1980/**
1981 \brief FLTK library options management.
1982
1983 This function needs to be documented in more detail. It can be used for more
1984 optional settings, such as using a native file chooser instead of the FLTK one
1985 wherever possible, disabling tooltips, disabling visible focus, disabling
1986 FLTK file chooser preview, etc. .
1987
1988 There should be a command line option interface.
1989
1990 There should be an application that manages options system wide, per user, and
1991 per application.
1992
1993 \note As of FLTK 1.3.0, options can be managed within fluid, using the menu
1994 <i>Edit/Global FLTK Settings</i>.
1995
1996 \param opt which option
1997 \return true or false
1998 \see enum Fl::Fl_Option
1999 \see Fl::option(Fl_Option, bool)
2000
2001 \since FLTK 1.3.0
2002 */
2003bool Fl::option(Fl_Option opt)
2004{
2005 if (!options_read_) {
2006 int tmp;
2007 { // first, read the system wide preferences
2008 Fl_Preferences prefs(Fl_Preferences::SYSTEM, "fltk.org", "fltk");
2009 Fl_Preferences opt_prefs(prefs, "options");
2010 opt_prefs.get("ArrowFocus", tmp, 0); // default: off
2011 options_[OPTION_ARROW_FOCUS] = tmp;
2012 //opt_prefs.get("NativeFilechooser", tmp, 1); // default: on
2013 //options_[OPTION_NATIVE_FILECHOOSER] = tmp;
2014 //opt_prefs.get("FilechooserPreview", tmp, 1); // default: on
2015 //options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
2016 opt_prefs.get("VisibleFocus", tmp, 1); // default: on
2017 options_[OPTION_VISIBLE_FOCUS] = tmp;
2018 opt_prefs.get("DNDText", tmp, 1); // default: on
2019 options_[OPTION_DND_TEXT] = tmp;
2020 opt_prefs.get("ShowTooltips", tmp, 1); // default: on
2021 options_[OPTION_SHOW_TOOLTIPS] = tmp;
2022 }
2023 { // next, check the user preferences
2024 // override system options only, if the option is set ( >= 0 )
2025 Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "fltk");
2026 Fl_Preferences opt_prefs(prefs, "options");
2027 opt_prefs.get("ArrowFocus", tmp, -1);
2028 if (tmp >= 0) options_[OPTION_ARROW_FOCUS] = tmp;
2029 //opt_prefs.get("NativeFilechooser", tmp, -1);
2030 //if (tmp >= 0) options_[OPTION_NATIVE_FILECHOOSER] = tmp;
2031 //opt_prefs.get("FilechooserPreview", tmp, -1);
2032 //if (tmp >= 0) options_[OPTION_FILECHOOSER_PREVIEW] = tmp;
2033 opt_prefs.get("VisibleFocus", tmp, -1);
2034 if (tmp >= 0) options_[OPTION_VISIBLE_FOCUS] = tmp;
2035 opt_prefs.get("DNDText", tmp, -1);
2036 if (tmp >= 0) options_[OPTION_DND_TEXT] = tmp;
2037 opt_prefs.get("ShowTooltips", tmp, -1);
2038 if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
2039 }
2040 { // now, if the developer has registered this app, we could as for per-application preferences
2041 }
2042 options_read_ = 1;
2043 }
2044 if (opt<0 || opt>=OPTION_LAST)
2045 return false;
2046 return (bool)(options_[opt]!=0);
2047}
2048
2049/**
2050 \brief Override an option while the application is running.
2051
2052 This function does not change any system or user settings.
2053
2054 \param opt which option
2055 \param val set to true or false
2056 \see enum Fl::Fl_Option
2057 \see bool Fl::option(Fl_Option)
2058 */
2059void Fl::option(Fl_Option opt, bool val)
2060{
2061 if (opt<0 || opt>=OPTION_LAST)
2062 return;
2063 if (!options_read_) {
2064 // first read this option, so we don't override our setting later
2065 option(opt);
2066 }
2067 options_[opt] = val;
2068}
2069
2070
2071// Helper class Fl_Widget_Tracker
2072
2073/**
2074 The constructor adds a widget to the watch list.
2075*/
2076Fl_Widget_Tracker::Fl_Widget_Tracker(Fl_Widget *wi)
2077{
2078 wp_ = wi;
2079 Fl::watch_widget_pointer(wp_); // add pointer to watch list
2080}
2081
2082/**
2083 The destructor removes a widget from the watch list.
2084*/
2085Fl_Widget_Tracker::~Fl_Widget_Tracker()
2086{
2087 Fl::release_widget_pointer(wp_); // remove pointer from watch list
2088}
2089
2090
2091//
2092// End of "$Id: Fl.cxx 8723 2011-05-23 16:49:02Z manolo $".
2093//