From: Pierre Ossman Date: Tue, 14 Jun 2011 13:36:57 +0000 (+0000) Subject: Implement a more robust method to handle the keyboard grab/focus voodoo as X-Git-Tag: v1.1.90~286 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a4f0f181b3ed0a0906083c453632e39e19472135;p=tigervnc.git Implement a more robust method to handle the keyboard grab/focus voodoo as it didn't catch some cases on OS X. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4496 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 52725ed2..456e372f 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -69,6 +69,9 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name, OptionsDialog::addCallback(handleOptions, this); + // Hack. See below... + Fl::event_dispatch(&fltkHandle); + #ifdef HAVE_FLTK_FULLSCREEN if (fullScreen) fullscreen(); @@ -197,9 +200,6 @@ int DesktopWindow::handle(int event) { switch (event) { #ifdef HAVE_FLTK_FULLSCREEN - case FL_FOCUS: - // FIXME: We reassert the keyboard grabbing on focus/unfocus as FLTK - // releases the grab when someone calls Fl::grab(0) case FL_FULLSCREEN: if (event == FL_FULLSCREEN) fullScreen.setParam(fullscreen_active()); @@ -212,12 +212,6 @@ int DesktopWindow::handle(int event) else ungrabKeyboard(); - break; - case FL_UNFOCUS: - // FIXME: We need to relinquish control when the entire window loses - // focus as it seems to interfere with the WM:s ability to handle - // interactions with popups' window decorations. - ungrabKeyboard(); break; #endif case FL_SHORTCUT: @@ -234,6 +228,46 @@ int DesktopWindow::handle(int event) } +int DesktopWindow::fltkHandle(int event, Fl_Window *win) +{ + int ret; + + ret = Fl::handle_(event, win); + +#ifdef HAVE_FLTK_FULLSCREEN + // This is hackish and the result of the dodgy focus handling in FLTK. + // The basic problem is that FLTK's view of focus and the system's tend + // to differ, and as a result we do not see all the FL_FOCUS events we + // need. Fortunately we can grab them here... + + DesktopWindow *dw = dynamic_cast(win); + + if (dw && fullscreenSystemKeys) { + switch (event) { + case FL_FOCUS: + // FIXME: We reassert the keyboard grabbing on focus as FLTK there are + // some issues we need to work around: + // a) Fl::grab(0) on X11 will release the keyboard grab for us. + // b) Gaining focus on the system level causes FLTK to switch + // window level on OS X. + if (dw->fullscreen_active()) + dw->grabKeyboard(); + break; + + case FL_UNFOCUS: + // FIXME: We need to relinquish control when the entire window loses + // focus as it is very tied to this specific window on some + // platforms and we want to be able to open subwindows. + dw->ungrabKeyboard(); + break; + } + } +#endif + + return ret; +} + + void DesktopWindow::grabKeyboard() { // Grabbing the keyboard is fairly safe as FLTK reroutes events to the diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index 2be07680..08483066 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -72,6 +72,8 @@ public: int handle(int event); private: + static int fltkHandle(int event, Fl_Window *win); + void grabKeyboard(); void ungrabKeyboard(); diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 139eb9a4..ae9aa106 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -740,13 +740,6 @@ void Viewport::popupContextMenu() const Fl_Menu_Item *m; char buffer[1024]; - // FIXME: Hacky workaround for the fact that menus grab and ungrab the - // keyboard. Releasing focus here triggers some events on ungrab - // that DesktopWindow can catch and trigger some voodoo. - // See DesktopWindow::handle(). - if (window()->contains(Fl::focus())) - Fl::focus(NULL); - // Make sure the menu is reset to its initial state between goes or // it will start up highlighting the previously selected entry. contextMenu->value(-1); diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm index 589da2d9..6300d3c0 100644 --- a/vncviewer/cocoa.mm +++ b/vncviewer/cocoa.mm @@ -22,19 +22,24 @@ #import +static bool captured = false; + int cocoa_capture_display(Fl_Window *win) { NSWindow *nsw; nsw = (NSWindow*)fl_xid(win); - // Already captured? + if (!captured) { + if (CGDisplayCapture(kCGDirectMainDisplay) != kCGErrorSuccess) + return 1; + + captured = true; + } + if ([nsw level] == CGShieldingWindowLevel()) return 0; - if (CGDisplayCapture(kCGDirectMainDisplay) != kCGErrorSuccess) - return 1; - [nsw setLevel:CGShieldingWindowLevel()]; return 0; @@ -45,7 +50,10 @@ void cocoa_release_display(Fl_Window *win) NSWindow *nsw; int newlevel; - CGDisplayRelease(kCGDirectMainDisplay); + if (captured) + CGDisplayRelease(kCGDirectMainDisplay); + + captured = false; nsw = (NSWindow*)fl_xid(win);