Implement support for grabbing the keyboard when in full screen mode.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4449 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 5628142..ce9e9ab 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -22,11 +22,22 @@
#include <string.h>
#include <FL/Fl_Scroll.H>
+#include <FL/x.H>
#include <rfb/LogWriter.h>
#include "DesktopWindow.h"
+#include "OptionsDialog.h"
#include "i18n.h"
+#include "parameters.h"
+
+#ifdef WIN32
+#include "win32.h"
+#endif
+
+#ifdef __APPLE__
+#include "cocoa.h"
+#endif
using namespace rfb;
@@ -56,6 +67,8 @@
setName(name);
+ OptionsDialog::addCallback(handleOptions, this);
+
show();
// The window manager might give us an initial window size that is different
@@ -68,6 +81,12 @@
DesktopWindow::~DesktopWindow()
{
+ // Unregister all timeouts in case they get a change tro trigger
+ // again later when this object is already gone.
+ Fl::remove_timeout(handleGrab, this);
+
+ OptionsDialog::removeCallback(handleOptions);
+
// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
}
@@ -152,7 +171,132 @@
}
+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 (!fullscreenSystemKeys)
+ break;
+
+ if (fullscreen_active())
+ grabKeyboard();
+ 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:
+ // Sometimes the focus gets out of whack and we fall through to the
+ // shortcut dispatching. Try to make things sane again...
+ if (Fl::focus() == NULL) {
+ take_focus();
+ Fl::handle(FL_KEYDOWN, this);
+ }
+ return 1;
+ }
+
+ return Fl_Window::handle(event);
+}
+
+
+void DesktopWindow::grabKeyboard()
+{
+ // Grabbing the keyboard is fairly safe as FLTK reroutes events to the
+ // correct widget regardless of which low level window got the system
+ // event.
+
+ // FIXME: Push this stuff into FLTK.
+
+#if defined(WIN32)
+ int ret;
+
+ ret = win32_enable_lowlevel_keyboard(fl_xid(this));
+ if (ret != 0)
+ vlog.error(_("Failure grabbing keyboard"));
+#elif defined(__APPLE__)
+ int ret;
+
+ ret = cocoa_capture_display(this);
+ if (ret != 0)
+ vlog.error(_("Failure grabbing keyboard"));
+#else
+ int ret;
+
+ ret = XGrabKeyboard(fl_display, fl_xid(this), True,
+ GrabModeAsync, GrabModeAsync, fl_event_time);
+ if (ret) {
+ if (ret == AlreadyGrabbed) {
+ // It seems like we can race with the WM in some cases.
+ // Try again in a bit.
+ if (!Fl::has_timeout(handleGrab, this))
+ Fl::add_timeout(0.500, handleGrab, this);
+ } else {
+ vlog.error(_("Failure grabbing keyboard"));
+ }
+ }
+#endif
+}
+
+
+void DesktopWindow::ungrabKeyboard()
+{
+ Fl::remove_timeout(handleGrab, this);
+
+#if defined(WIN32)
+ win32_disable_lowlevel_keyboard(fl_xid(this));
+#elif defined(__APPLE__)
+ cocoa_release_display(this);
+#else
+ // FLTK has a grab so lets not mess with it
+ if (Fl::grab())
+ return;
+
+ XUngrabKeyboard(fl_display, fl_event_time);
+#endif
+}
+
+
+void DesktopWindow::handleGrab(void *data)
+{
+ DesktopWindow *self = (DesktopWindow*)data;
+
+ assert(self);
+
+#ifdef HAVE_FLTK_FULLSCREEN
+ if (!fullscreenSystemKeys)
+ return;
+ if (!self->fullscreen_active())
+ return;
+
+ self->grabKeyboard();
+#endif
+}
+
+
void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
{
exit_vncviewer();
}
+
+
+void DesktopWindow::handleOptions(void *data)
+{
+ DesktopWindow *self = (DesktopWindow*)data;
+
+#ifdef HAVE_FLTK_FULLSCREEN
+ if (self->fullscreen_active() && fullscreenSystemKeys)
+ self->grabKeyboard();
+ else
+ self->ungrabKeyboard();
+#endif
+}