diff --git a/CHANGES b/CHANGES index 8d47a7ff7..a6e9b03d9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,20 +1,20 @@ CHANGES IN FLTK 1.1.10 - - improved test/subwindow.cxx (STR #2079) + - Fixed a problem with TrackMouseEvent() (Windows only) that would + generate wrong FL_LEAVE events with subwindows. TrackMouseEvent + is now enabled by default (it was disabled for GNU compilers). + It can be disabled by defining NO_TRACK_MOUSE. + Improved test/subwindow.cxx (STR #2079) - Fixed RGB colors for round box (STR #2097) - - Fixed documentation (added missing COMCTRL32.LIB - dependency) + - Fixed documentation (added missing COMCTRL32.LIB dependency) - Fl_Group::clip_children() is now public (STR #2017) - Fixed first modifier key event (STR #1952) - - Fixed wrong default value of Fl_Spinner in - Fluid (STR #1991) + - Fixed wrong default value of Fl_Spinner in Fluid (STR #1991) - Fixed Fluid textcolor output (STR #1992) - - Added clarification to Fl_GL_Window mode - function (STR #1945) + - Added clarification to Fl_GL_Window mode function (STR #1945) - Fl_Group and Fl_Scroll now resize themselves before resizing their children (STR #2032) - - Fixed adding an idle handler during - a draw() call (STR #1950) + - Fixed adding an idle handler during a draw() call (STR #1950) - Improved stability of fl_read_image (STR #2021) - Fixed menu position close to screen border (STR #2057) diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 23b90e1fc..de09cc291 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -64,22 +64,46 @@ //#define USE_ASYNC_SELECT - +// USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have +// TrackMouseEvent()... // -// USE_TRACK_MOUSE - define it if you have TrackMouseEvent()... +// Now (Dec. 2008) we can assume that current Cygwin/MinGW versions +// support the TrackMouseEvent() function, but WinCE obviously doesn't +// support it (STR 2095). Therefore, USE_TRACK_MOUSE is enabled by +// default, but you can disable it by defining NO_TRACK_MOUSE. // -// Apparently, at least some versions of Cygwin/MingW don't provide -// the TrackMouseEvent() function. You can define this by hand -// if you have it - this is only needed to support subwindow -// enter/leave notification under Windows. +// TrackMouseEvent is only used to support window leave notifications +// under Windows. It can be used to get FL_LEAVE events, when the +// mouse leaves the _main_ application window (FLTK detects subwindow +// leave events by using normal move events). // +// Implementation note: If the mouse cursor leaves one subwindow and +// enters another window, then Windows sends a WM_MOUSEMOVE message to +// the new window before it sends a WM_MOUSELEAVE message to the old +// (just left) window. We save the current mouse window in a static variable, +// and if we get a WM_MOUSELEAVE event for the current mouse window, this +// means that the top level window has been left (otherwise we would have +// got another WM_MOUSEMOVE message before). -//#define USE_TRACK_MOUSE +// #define NO_TRACK_MOUSE -#if !defined(__GNUC__) -# define USE_TRACK_MOUSE -#endif // !__GNUC__ +#if !defined(NO_TRACK_MOUSE) +# define USE_TRACK_MOUSE +#endif // NO_TRACK_MOUSE +static Fl_Window *track_mouse_win=0; // current TrackMouseEvent() window + +// USE_CAPTURE_MOUSE_WIN - this must be defined for TrackMouseEvent to work +// correctly with subwindows - otherwise a single mouse click and release +// (without a move) would generate phantom leave events. +// This defines, if the current mouse window (maybe a subwindow) or the +// main window should get mouse events after pushing (and holding) a mouse +// button, i.e. when dragging the mouse. This is done by calling SetCapture +// (see below). + +#ifdef USE_TRACK_MOUSE +#define USE_CAPTURE_MOUSE_WIN +#endif // USE_TRACK_MOUSE // // WM_SYNCPAINT is an "undocumented" message, which is finally defined in @@ -512,6 +536,9 @@ static int mouse_event(Fl_Window *window, int what, int button, ClientToScreen(fl_xid(window), &pt); Fl::e_x_root = pt.x; Fl::e_y_root = pt.y; +#ifdef USE_CAPTURE_MOUSE_WIN + Fl_Window *mouse_window = window; // save "mouse window" +#endif while (window->parent()) { Fl::e_x += window->x(); Fl::e_y += window->y(); @@ -535,7 +562,11 @@ static int mouse_event(Fl_Window *window, int what, int button, case 0: // single-click Fl::e_clicks = 0; J1: - if (!fl_capture) SetCapture(fl_xid(window)); +#ifdef USE_CAPTURE_MOUSE_WIN + if (!fl_capture) SetCapture(fl_xid(mouse_window)); // use mouse window +#else + if (!fl_capture) SetCapture(fl_xid(window)); // use main window +#endif Fl::e_keysym = FL_Button + button; Fl::e_is_click = 1; px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; @@ -755,20 +786,26 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_MOUSEMOVE: #ifdef USE_TRACK_MOUSE - if (Fl::belowmouse() != window) { + if (track_mouse_win != window) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; _TrackMouseEvent(&tme); + track_mouse_win = window; } #endif // USE_TRACK_MOUSE mouse_event(window, 3, 0, wParam, lParam); return 0; case WM_MOUSELEAVE: - Fl::belowmouse(0); - if (!window->parent()) Fl::handle(FL_LEAVE, window); + if (track_mouse_win == window) { // we left the top level window ! + Fl_Window *tw = window; + while (tw->parent()) tw = tw->window(); // find top level window + Fl::belowmouse(0); + Fl::handle(FL_LEAVE, tw); + } + track_mouse_win = 0; // force TrackMouseEvent() restart break; case WM_SETFOCUS: