DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: http://www.fltk.org/str.php?L2802
Version: 1.3-current


FLTK doesn't tell the local WM that a window is modal, which means that you
lack the visual clues normally associated with it. It is possible to do
better by interacting more with the local WM.

The attached patch does the following:

 - Sets _NET_WM_STATE_MODAL on X11

 - Redirects focus to the modal window on Win32

 - Makes all other windows refuse to become key or main on OS X

This gives an improved behaviour on all platforms in that the window
decorations will always indicate that the modal window has focus. IOW,
FLTK and the local WM now agree on who has focus.

Issues remaining (and I don't intend to address those on this bug):

 - X11: Windows are transient/modal for another window, not the entire
window group (this is almost impossible to solve as there are sooo many
bugs in the WMs in this area).

 - Win32/OS X: The proper way of doing modal/non-modal windows involves
releasing control of the main loop, so it isn't easily done in FLTK. We
can only try to emulate the native behaviour.

 - Win32: Proper behaviour is to blink or otherwise visually indicate that
focus is modal. Right now it simply just refuses to change focus.

 - OS X: Layering is off if you have multiple levels of modal/non-modal
windows.


Link: http://www.fltk.org/str.php?L2802
Version: 1.3-current
diff -up fltk-1.3.0/src/Fl_cocoa.mm.modal fltk-1.3.0/src/Fl_cocoa.mm
--- fltk-1.3.0/src/Fl_cocoa.mm.modal    2012-01-25 08:22:49.910577692 +0100
+++ fltk-1.3.0/src/Fl_cocoa.mm  2012-01-25 08:48:20.403135026 +0100
@@ -651,6 +651,14 @@ static void do_timer(CFRunLoopTimerRef t
 }
 - (BOOL)canBecomeKeyWindow
 {
+  if (Fl::modal_ && (Fl::modal_ != w))
+    return NO;
+  return YES;
+}
+- (BOOL)canBecomeMainWindow
+{
+  if (Fl::modal_ && (Fl::modal_ != w))
+    return NO;
   return YES;
 }
 @end
@@ -2456,6 +2464,7 @@ void Fl_X::make(Fl_Window* w)
     if ( w->border() || (!w->modal() && !w->tooltip_window()) ) {
       Fl_Tooltip::enter(0);
     }
+    if (w->modal()) { Fl::modal_ = w; }
     w->set_visible();
     if ( w->border() || (!w->modal() && !w->tooltip_window()) ) 
Fl::handle(FL_FOCUS, w);
     Fl::first_window(w);
@@ -2478,8 +2487,6 @@ void Fl_X::make(Fl_Window* w)
     int old_event = Fl::e_number;
     w->handle(Fl::e_number = FL_SHOW);
     Fl::e_number = old_event;
-    
-    if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); }
   }
 }
 
diff -up fltk-1.3.0/src/Fl_win32.cxx.modal fltk-1.3.0/src/Fl_win32.cxx
--- fltk-1.3.0/src/Fl_win32.cxx.modal   2012-01-24 21:49:46.778170605 +0100
+++ fltk-1.3.0/src/Fl_win32.cxx 2012-01-24 21:49:46.791170372 +0100
@@ -1075,6 +1075,10 @@ static LRESULT CALLBACK WndProc(HWND hWn
     break;
 
   case WM_SETFOCUS:
+    if ((Fl::modal_) && (Fl::modal_ != window)) {
+      SetFocus(fl_xid(Fl::modal_));
+      return 0;
+    }
     Fl::handle(FL_FOCUS, window);
     break;
 
@@ -1828,6 +1832,11 @@ Fl_X* Fl_X::make(Fl_Window* w) {
     Fl::e_number = old_event;
     w->redraw(); // force draw to happen
   }
+
+  // Needs to be done before ShowWindow() to get the correct behaviour
+  // when we get WM_SETFOCUS.
+  if (w->modal()) {Fl::modal_ = w; fl_fix_focus();}
+
   // If we've captured the mouse, we dont want to activate any
   // other windows from the code, or we lose the capture.
   ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
@@ -1845,7 +1854,6 @@ Fl_X* Fl_X::make(Fl_Window* w) {
     }
   }
 
-  if (w->modal()) {Fl::modal_ = w; fl_fix_focus();}
   return x;
 }
 
diff -up fltk-1.3.0/src/Fl_x.cxx.modal fltk-1.3.0/src/Fl_x.cxx
--- fltk-1.3.0/src/Fl_x.cxx.modal       2012-01-24 21:49:46.784170498 +0100
+++ fltk-1.3.0/src/Fl_x.cxx     2012-01-24 21:49:46.792170354 +0100
@@ -2066,6 +2066,12 @@ void Fl_X::make_xid(Fl_Window* win, XVis
       while (wp->parent()) wp = wp->window();
       XSetTransientForHint(fl_display, xp->xid, fl_xid(wp));
       if (!wp->visible()) showit = 0; // guess that wm will not show it
+      if (win->modal()) {
+        Atom net_wm_state = XInternAtom (fl_display, "_NET_WM_STATE", 0);
+        Atom net_wm_state_skip_taskbar = XInternAtom (fl_display, 
"_NET_WM_STATE_MODAL", 0);
+        XChangeProperty (fl_display, xp->xid, net_wm_state, XA_ATOM, 32,
+            PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1);
+      }
     }
 
     // Make sure that borderless windows do not show in the task bar
_______________________________________________
fltk-bugs mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-bugs

Reply via email to