From c92081e116509bab734040f4ccdb9586da7f5c60 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:10:03 +0200 Subject: [PATCH 01/19] Use printf constructor safely The input string might contain formatting marks, so make sure those are ignored. --- common/rdr/Exception.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/rdr/Exception.cxx b/common/rdr/Exception.cxx index d70cd9fc7d..964bc333b0 100644 --- a/common/rdr/Exception.cxx +++ b/common/rdr/Exception.cxx @@ -50,7 +50,7 @@ Exception::Exception(const char *format, ...) { } SystemException::SystemException(const char* s, int err_) - : Exception(s), err(err_) + : Exception("%s", s), err(err_) { strncat(str_, ": ", len-1-strlen(str_)); #ifdef _WIN32 From b662ffd4ac9b18ffacebb26d5a57680dd49788b2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:12:00 +0200 Subject: [PATCH 02/19] Make keysymtab static and const Static to avoid namespace polution, and const so that it can be shared among instances. --- vncviewer/keysym2ucs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vncviewer/keysym2ucs.c b/vncviewer/keysym2ucs.c index d12eb49116..4e3dca25a0 100644 --- a/vncviewer/keysym2ucs.c +++ b/vncviewer/keysym2ucs.c @@ -37,7 +37,9 @@ struct codepair { unsigned short keysym; unsigned short ucs; -} keysymtab[] = { +}; + +static const struct codepair keysymtab[] = { { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ From 7b8bff630ce2d98b87ffbf4843e71ca2c97df717 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:17:23 +0200 Subject: [PATCH 03/19] Use NoSymbol as the error code This is how the X11 API does things, so it's clearer if we use the same principle. --- vncviewer/Viewport.cxx | 10 +++++++--- vncviewer/keysym2ucs.c | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index cd8b1bc3d1..7d55168200 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -39,6 +39,10 @@ #include #endif +#ifndef NoSymbol +#define NoSymbol 0 +#endif + #include "Viewport.h" #include "CConn.h" #include "OptionsDialog.h" @@ -702,7 +706,7 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k // Unknown special key? if (keyText[0] == '\0') { vlog.error(_("Unknown FLTK key code %d (0x%04x)"), keyCode, keyCode); - return XK_VoidSymbol; + return NoSymbol; } // Look up the symbol the key produces and translate that from Unicode @@ -710,7 +714,7 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k if (fl_utf_nb_char((const unsigned char*)keyText, strlen(keyText)) != 1) { vlog.error(_("Multiple characters given for key code %d (0x%04x): '%s'"), keyCode, keyCode, keyText); - return XK_VoidSymbol; + return NoSymbol; } ucs = fl_utf8decode(keyText, NULL, NULL); @@ -754,7 +758,7 @@ void Viewport::handleKeyEvent(int keyCode, int origKeyCode, const char *keyText, } keySym = translateKeyEvent(keyCode, origKeyCode, keyText); - if (keySym == XK_VoidSymbol) + if (keySym == NoSymbol) return; #ifdef WIN32 diff --git a/vncviewer/keysym2ucs.c b/vncviewer/keysym2ucs.c index 4e3dca25a0..2fd5870655 100644 --- a/vncviewer/keysym2ucs.c +++ b/vncviewer/keysym2ucs.c @@ -34,6 +34,8 @@ #include "keysym2ucs.h" +#define NoSymbol 0 + struct codepair { unsigned short keysym; unsigned short ucs; @@ -886,5 +888,5 @@ unsigned ucs2keysym(unsigned ucs) return ucs | 0x01000000; /* no matching keysym value found */ - return 0xFFFFFF; + return NoSymbol; } From 4c6993223c193e2acbccf7d27488266c32e3ee72 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:22:43 +0200 Subject: [PATCH 04/19] Windows debug builds of vncviewer should have a console Makes it easier to debug it by having convenient access to the log output. --- vncviewer/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt index 9b815a390a..ca1fbafee5 100644 --- a/vncviewer/CMakeLists.txt +++ b/vncviewer/CMakeLists.txt @@ -41,7 +41,7 @@ else() set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} X11PixelBuffer.cxx) endif() -if(WIN32) +if(WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") add_executable(vncviewer WIN32 ${VNCVIEWER_SOURCES}) else() add_executable(vncviewer ${VNCVIEWER_SOURCES}) From 1d36ed801f089114c3256f0fd8546825747b56ef Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 22 Aug 2014 14:41:03 +0200 Subject: [PATCH 05/19] Update FLTK requirement We actually require FLTK 1.3.2 as we reference FL_SOCKET. --- BUILDING.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILDING.txt b/BUILDING.txt index 98c7c6b080..f5944d7509 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -84,8 +84,8 @@ Build Requirements (Java) Building FLTK ============= -TigerVNC requires FLTK 1.3.0 (or later). Although it will build and work -with plain 1.3.0, to get full functionality and the best behaviour you +TigerVNC requires FLTK 1.3.2 (or later). Although it will build and work +with plain 1.3.2, to get full functionality and the best behaviour you need to build a patched version: 1. Check out FLTK 1.3.2 using Subversion: From 2f11bd9a6afe160886e42081c2542b8b5b7caefc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 22 Aug 2014 14:43:33 +0200 Subject: [PATCH 06/19] Ship FLTK patches instead of referring a URI It makes things more self contained (although you still need to download FLTK itself), avoids the confusion of STR:s in varying states, and allows us to refer to patches that aren't available on an STR. --- BUILDING.txt | 52 +- .../01-str2599-fltk-1.3.x-keyboard-x11.patch | 286 +++ ...02-str2599-fltk-1.3.x-keyboard-win32.patch | 256 +++ .../03-str2599-fltk-1.3.x-keyboard-osx.patch | 375 ++++ .../04-str2636-fltk-1.3.x-clipboard.patch | 106 ++ .../05-str2636-fltk-1.3.x-clipboard-x11.patch | 355 ++++ ...r2636-fltk-1.3.x-clipboard-win32-fix.patch | 135 ++ ...7-str2636-fltk-1.3.x-clipboard-win32.patch | 99 + .../08-str2636-fltk-1.3.x-clipboard-osx.patch | 44 + contrib/fltk/09-str2659-pixmap.patch | 554 ++++++ .../fltk/10-str2660-fltk-1.3.x-cursor.patch | 1623 +++++++++++++++++ .../fltk/11-str2802-fltk-1.3.0-modal.patch | 75 + .../fltk/12-str2816-fltk-1.3.0-icons.patch | 645 +++++++ .../13-str2860-fltk-1.3.x-screen_num.patch | 131 ++ .../14-str2860-fltk-1.3.x-multihead.patch | 468 +++++ ...-feature-from-TigerVNC-to-optionally.patch | 0 ...nds-on-some-Carbon-functions-so-we-n.patch | 0 ...-CMAKE_REQUIRED_LIBRARIES-after-chec.patch | 0 ...str-2917-fix-macosx-10.6-build-issue.patch | 0 19 files changed, 5156 insertions(+), 48 deletions(-) create mode 100644 contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch create mode 100644 contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch create mode 100644 contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch create mode 100644 contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch create mode 100644 contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch create mode 100644 contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch create mode 100644 contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch create mode 100644 contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch create mode 100644 contrib/fltk/09-str2659-pixmap.patch create mode 100644 contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch create mode 100644 contrib/fltk/11-str2802-fltk-1.3.0-modal.patch create mode 100644 contrib/fltk/12-str2816-fltk-1.3.0-icons.patch create mode 100644 contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch create mode 100644 contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch rename contrib/{patches => fltk/fixes}/0001-Add-BUILD_STATIC-feature-from-TigerVNC-to-optionally.patch (100%) rename contrib/{patches => fltk/fixes}/0002-Fl_cocoa.mm-depends-on-some-Carbon-functions-so-we-n.patch (100%) rename contrib/{patches => fltk/fixes}/0003-We-need-to-unset-CMAKE_REQUIRED_LIBRARIES-after-chec.patch (100%) rename contrib/{patches => fltk/fixes}/0004-str-2917-fix-macosx-10.6-build-issue.patch (100%) diff --git a/BUILDING.txt b/BUILDING.txt index f5944d7509..897a51a300 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -91,54 +91,10 @@ need to build a patched version: 1. Check out FLTK 1.3.2 using Subversion: $ svn co http://svn.easysw.com/public/fltk/fltk/tags/release-1.3.2 fltk-1.3.2 -2. For full functionality, apply patches. Here's a shell script to do -that: - -#!/bin/bash -set -e -apply_patch() -{ - rm -f $2 - wget http://www.fltk.org/strfiles/$1/$2 - patch -p1 < $2 -} - -# Export dead key information from FLTK to the apps -# http://www.fltk.org/str.php?L2599 -apply_patch 2599 fltk-1_v4.3.x-keyboard-x11.patch -apply_patch 2599 fltk-1_v4.3.x-keyboard-win32.patch -apply_patch 2599 fltk-1_v6.3.x-keyboard-osx.patch - -# Notify applications of changes to the clipboard -# http://www.fltk.org/str.php?L2636 -apply_patch 2636 fltk-1.3.x-clipboard.patch -apply_patch 2636 fltk-1_v6.3.x-clipboard-x11.patch -apply_patch 2636 fltk-1_v3.3.x-clipboard-win32-fix.patch -apply_patch 2636 fltk-1_v2.3.x-clipboard-win32.patch -apply_patch 2636 fltk-1_v2.3.x-clipboard-osx.patch - -# Ability to convert a Fl_Pixmap to a Fl_RGB_Image -# http://www.fltk.org/str.php?L2659 -apply_patch 2659 pixmap_v2.patch - -# Support for custom cursors -# http://www.fltk.org/str.php?L2660 -apply_patch 2660 fltk-1_v5.3.x-cursor.patch - -# Improve modality interaction with WM -# http://www.fltk.org/str.php?L2802 -apply_patch 2802 fltk-1_v2.3.0-modal.patch - -# Window icons -# http://www.fltk.org/str.php?L2816 -apply_patch 2816 fltk-1_v3.3.0-icons.patch - -# Multihead -# http://fltk.org/str.php?L2860 -apply_patch 2860 fltk-1.3.x-screen_num.patch -apply_patch 2860 fltk-1_v3.3.x-multihead.patch - -### END SCRIPT ### +2. For full functionality, apply patches. All patches can be found in + the contrib/fltk/ directory. There are also some general fixes to + FLTK that can be found in the contrib/fltk/fixes/ directory that + might be useful. 3. Use CMake to build FLTK using the same procedures described below for building TigerVNC. The recipes in the "Build Recipes" section also apply. diff --git a/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch b/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch new file mode 100644 index 0000000000..cabc0f1cae --- /dev/null +++ b/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch @@ -0,0 +1,286 @@ +diff -ur fltk-1.3.0r9619.org/FL/Fl_Widget.H fltk-1.3.0r9619/FL/Fl_Widget.H +--- fltk-1.3.0r9619.org/FL/Fl_Widget.H 2012-04-23 22:12:06.000000000 +0200 ++++ fltk-1.3.0r9619/FL/Fl_Widget.H 2012-06-18 13:46:07.302320825 +0200 +@@ -171,6 +171,7 @@ + GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window + COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget + FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window) ++ SIMPLE_KEYBOARD = 1<<19, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input) + // (space for more flags) + USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions + USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions +@@ -776,6 +777,35 @@ + */ + void clear_changed() {flags_ &= ~CHANGED;} + ++ /** ++ Returns if the widget sees a simplified keyboard model or not. ++ ++ Normally widgets get a full-featured keyboard model that is geared ++ towards text input. This includes support for compose sequences and ++ advanced input methods, commonly used for asian writing system. This ++ system however has downsides in that extra graphic can be presented ++ to the user and that a physical key press doesn't correspond directly ++ to a FLTK event. ++ ++ Widgets that need a direct correspondence between actual key events ++ and those seen by the widget can swith to the simplified keyboard ++ model. ++ ++ \retval 0 if the widget uses the normal keyboard model ++ \see set_changed(), clear_changed() ++ */ ++ unsigned int simple_keyboard() const {return flags_&SIMPLE_KEYBOARD;} ++ ++ /** Marks a widget to use the simple keyboard model. ++ \see changed(), clear_changed() ++ */ ++ void set_simple_keyboard() {flags_ |= SIMPLE_KEYBOARD;} ++ ++ /** Marks a widget to use the normal keyboard model. ++ \see changed(), set_changed() ++ */ ++ void set_normal_keyboard() {flags_ &= ~SIMPLE_KEYBOARD;} ++ + /** Gives the widget the keyboard focus. + Tries to make this widget be the Fl::focus() widget, by first sending + it an FL_FOCUS event, and if it returns non-zero, setting +diff -ur fltk-1.3.0r9619.org/src/Fl.cxx fltk-1.3.0r9619/src/Fl.cxx +--- fltk-1.3.0r9619.org/src/Fl.cxx 2012-03-23 17:47:53.000000000 +0100 ++++ fltk-1.3.0r9619/src/Fl.cxx 2012-06-18 13:46:07.303320877 +0200 +@@ -70,6 +70,8 @@ + extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle); + #endif // WIN32 + ++extern void fl_update_focus(void); ++ + // + // Globals... + // +@@ -876,6 +878,8 @@ + fl_oldfocus = p; + } + e_number = old_event; ++ // let the platform code do what it needs ++ fl_update_focus(); + } + } + +diff -ur fltk-1.3.0r9619.org/src/Fl_grab.cxx fltk-1.3.0r9619/src/Fl_grab.cxx +--- fltk-1.3.0r9619.org/src/Fl_grab.cxx 2012-03-23 17:47:53.000000000 +0100 ++++ fltk-1.3.0r9619/src/Fl_grab.cxx 2012-06-18 13:46:07.303320877 +0200 +@@ -29,6 +29,7 @@ + // override_redirect, it does similar things on WIN32. + + extern void fl_fix_focus(); // in Fl.cxx ++void fl_update_focus(void); + + #ifdef WIN32 + // We have to keep track of whether we have captured the mouse, since +@@ -80,6 +81,7 @@ + #endif + } + grab_ = win; ++ fl_update_focus(); + } else { + if (grab_) { + #ifdef WIN32 +@@ -98,6 +100,7 @@ + XFlush(fl_display); + #endif + grab_ = 0; ++ fl_update_focus(); + fl_fix_focus(); + } + } +diff -ur fltk-1.3.0r9619.org/src/Fl_x.cxx fltk-1.3.0r9619/src/Fl_x.cxx +--- fltk-1.3.0r9619.org/src/Fl_x.cxx 2012-06-18 13:46:07.205316173 +0200 ++++ fltk-1.3.0r9619/src/Fl_x.cxx 2012-06-18 13:46:18.216844629 +0200 +@@ -298,6 +298,7 @@ + Colormap fl_colormap; + XIM fl_xim_im = 0; + XIC fl_xim_ic = 0; ++Window fl_xim_win = 0; + char fl_is_over_the_spot = 0; + static XRectangle status_area; + +@@ -583,6 +584,65 @@ + if(xim_styles) XFree(xim_styles); + } + ++void fl_xim_deactivate(void); ++ ++void fl_xim_activate(Window xid) ++{ ++ if (!fl_xim_im) ++ return; ++ ++ // If the focused window has changed, then use the brute force method ++ // of completely recreating the input context. ++ if (fl_xim_win != xid) { ++ fl_xim_deactivate(); ++ ++ fl_new_ic(); ++ fl_xim_win = xid; ++ ++ XSetICValues(fl_xim_ic, ++ XNFocusWindow, fl_xim_win, ++ XNClientWindow, fl_xim_win, ++ NULL); ++ } ++ ++ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); ++} ++ ++void fl_xim_deactivate(void) ++{ ++ if (!fl_xim_ic) ++ return; ++ ++ XDestroyIC(fl_xim_ic); ++ fl_xim_ic = NULL; ++ ++ fl_xim_win = 0; ++} ++ ++extern Fl_Window *fl_xfocus; ++ ++void fl_update_focus(void) ++{ ++ Fl_Widget *focus; ++ ++ focus = Fl::grab(); ++ if (!focus) ++ focus = Fl::focus(); ++ if (!focus) ++ return; ++ ++ if (focus->simple_keyboard()) { ++ fl_xim_deactivate(); ++ } else { ++ // fl_xfocus should always be set if something has focus, but let's ++ // play it safe ++ if (!fl_xfocus || !fl_xid(fl_xfocus)) ++ return; ++ ++ fl_xim_activate(fl_xid(fl_xfocus)); ++ } ++} ++ + void fl_open_display() { + if (fl_display) return; + +@@ -917,10 +977,9 @@ + XEvent xevent = thisevent; + fl_xevent = &thisevent; + Window xid = xevent.xany.window; +- static Window xim_win = 0; + + if (fl_xim_ic && xevent.type == DestroyNotify && +- xid != xim_win && !fl_find(xid)) ++ xid != fl_xim_win && !fl_find(xid)) + { + XIM xim_im; + xim_im = XOpenIM(fl_display, NULL, NULL, NULL); +@@ -935,48 +994,10 @@ + return 0; + } + +- if (fl_xim_ic && (xevent.type == FocusIn)) +- { +-#define POOR_XIM +-#ifdef POOR_XIM +- if (xim_win != xid) +- { +- xim_win = xid; +- XDestroyIC(fl_xim_ic); +- fl_xim_ic = NULL; +- fl_new_ic(); +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- NULL); +- } +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +-#else +- if (Fl::first_window() && Fl::first_window()->modal()) { +- Window x = fl_xid(Fl::first_window()); +- if (x != xim_win) { +- xim_win = x; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xim_win, +- XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +- } else if (xim_win != xid && xid) { +- xim_win = xid; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- //XNFocusWindow, xim_win, +- //XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +-#endif ++ if (fl_xim_ic) { ++ if (XFilterEvent((XEvent *)&xevent, 0)) ++ return 1; + } +- +- if ( XFilterEvent((XEvent *)&xevent, 0) ) +- return(1); + + #if USE_XRANDR + if( XRRUpdateConfiguration_f && xevent.type == randrEventBase + RRScreenChangeNotify) { +@@ -1326,15 +1347,15 @@ + //static XComposeStatus compose; + len = XLookupString((XKeyEvent*)&(xevent.xkey), + buffer, buffer_len, &keysym, 0/*&compose*/); +- if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets +- // force it to type a character (not sure if this ever is needed): +- // if (!len) {buffer[0] = char(keysym); len = 1;} +- len = fl_utf8encode(XKeysymToUcs(keysym), buffer); +- if (len < 1) len = 1; +- // ignore all effects of shift on the keysyms, which makes it a lot +- // easier to program shortcuts and is Windoze-compatible: +- keysym = XKeycodeToKeysym(fl_display, keycode, 0); +- } ++ // XLookupString() is only defined to return Latin-1 (although it ++ // often gives you more). To be safe, use our own lookups based on ++ // keysym. ++ len = fl_utf8encode(XKeysymToUcs(keysym), buffer); ++ if (len < 1) ++ len = 1; ++ // ignore all effects of shift on the keysyms, which makes it a lot ++ // easier to program shortcuts and is Windoze-compatable: ++ keysym = XKeycodeToKeysym(fl_display, keycode, 0); + } + // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not + // set until set_event_xy() is called later... +diff -ur fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c fltk-1.3.0r9619/src/xutf8/imKStoUCS.c +--- fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c 2009-03-13 23:43:43.000000000 +0100 ++++ fltk-1.3.0r9619/src/xutf8/imKStoUCS.c 2012-06-18 13:46:07.304320930 +0200 +@@ -266,6 +266,12 @@ + 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ + }; + ++static unsigned short const keysym_to_unicode_fe50_fe60[] = { ++ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, /* 0xfe50-0xfe57 */ ++ 0x030a, 0x030b, 0x030c, 0x0327, 0x0328, 0x1da5, 0x3099, 0x309a, /* 0xfe58-0xfe5f */ ++ 0x0323 /* 0xfe60-0xfe67 */ ++}; ++ + unsigned int + KeySymToUcs4(KeySym keysym) + { +@@ -315,6 +321,8 @@ + return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; + else if (keysym > 0x209f && keysym < 0x20ad) + return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; ++ else if (keysym > 0xfe4f && keysym < 0xfe61) ++ return keysym_to_unicode_fe50_fe60[keysym - 0xfe50]; + else + return 0; + } diff --git a/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch b/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch new file mode 100644 index 0000000000..c29d3b9744 --- /dev/null +++ b/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch @@ -0,0 +1,256 @@ +diff -ur fltk-1.3.0r9293.org/src/Fl_win32.cxx fltk-1.3.0r9293/src/Fl_win32.cxx +--- fltk-1.3.0r9293.org/src/Fl_win32.cxx 2012-06-18 09:07:56.522314557 +0200 ++++ fltk-1.3.0r9293/src/Fl_win32.cxx 2012-06-18 09:08:07.392836285 +0200 +@@ -87,6 +87,8 @@ + static Fl_Display_Device fl_gdi_display(&fl_gdi_driver); + Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display + ++bool use_simple_keyboard = false; ++ + // dynamic wsock dll handling api: + #if defined(__CYGWIN__) && !defined(SOCKET) + # define SOCKET int +@@ -120,6 +122,8 @@ + * size and link dependencies. + */ + static HMODULE s_imm_module = 0; ++typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD); ++static flTypeImmAssociateContextEx flImmAssociateContextEx = 0; + typedef HIMC (WINAPI* flTypeImmGetContext)(HWND); + static flTypeImmGetContext flImmGetContext = 0; + typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); +@@ -135,6 +139,7 @@ + if (!s_imm_module) + Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" + "Please check your input method manager library accessibility."); ++ flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx"); + flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); + flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); + flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); +@@ -413,7 +418,12 @@ + } + } + +- TranslateMessage(&fl_msg); ++ // Don't bother with key to character translation as we do ++ // it manually for simpley keyboard widgets. In fact, calling ++ // TranslateMessage() just makes it more difficult as it sets ++ // a bunch of internal state. ++ if (!use_simple_keyboard) ++ TranslateMessage(&fl_msg); + DispatchMessageW(&fl_msg); + have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); + } +@@ -638,6 +648,49 @@ + } + } + ++void fl_update_focus(void) ++{ ++ Fl_Widget *focus; ++ Fl_Window *win; ++ ++ get_imm_module(); ++ ++ focus = Fl::grab(); ++ if (!focus) ++ focus = Fl::focus(); ++ if (!focus) ++ return; ++ ++ // Grabs are special in that events are sent to the first ++ // available window ++ if (focus == Fl::grab()) ++ win = Fl::first_window(); ++ else { ++ win = focus->as_window(); ++ if (!win) ++ win = focus->window(); ++ } ++ ++ if (!win) { ++ Fl::warning("Cannot find window for widget receiving focus"); ++ return; ++ } ++ ++ // No Win32 window created yet ++ if (!Fl_X::i(win) || !fl_xid(win)) ++ return; ++ ++ if (focus->simple_keyboard()) { ++ use_simple_keyboard = true; ++ if (flImmGetContext(fl_xid(win)) != 0) ++ flImmAssociateContextEx(fl_xid(win), 0, 0); ++ } else { ++ use_simple_keyboard = false; ++ if (flImmGetContext(fl_xid(win)) == 0) ++ flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT); ++ } ++} ++ + HWND fl_capture; + + static int mouse_event(Fl_Window *window, int what, int button, +@@ -785,6 +838,27 @@ + return extended ? extendedlut[vk] : vklut[vk]; + } + ++static xchar msdead2fltk(xchar in) ++{ ++ switch (in) { ++ case 0x0060: // GRAVE ACCENT ++ return 0x0300; // COMBINING GRAVE ACCENT ++ case 0x00b4: // ACUTE ACCENT ++ return 0x0301; // COMBINING ACUTE ACCENT ++ case 0x005e: // CIRCUMFLEX ACCENT ++ return 0x0302; // COMBINING CIRCUMFLEX ACCENT ++ case 0x007e: // TILDE ++ return 0x0303; // COMBINING TILDE ++ case 0x00a8: // DIAERESIS ++ return 0x0308; // COMBINING DIAERESIS ++ // FIXME: Windows dead key behaviour isn't documented and I don't have ++ // any more keyboards to test with... ++ } ++ ++ // hope that Windows gave us something proper to begin with ++ return in; ++} ++ + #if USE_COLORMAP + extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx + #endif +@@ -846,6 +920,8 @@ + //fl_msg.pt = ??? + //fl_msg.lPrivate = ??? + ++ MSG fl_orig_msg = fl_msg; ++ + Fl_Window *window = fl_find(hWnd); + + if (window) switch (uMsg) { +@@ -1025,23 +1101,82 @@ + if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; + Fl::e_state = state; + static char buffer[1024]; +- if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { + ++ if (use_simple_keyboard) { ++ BYTE keystate[256]; ++ WCHAR wbuf[8]; ++ int ret; ++ ++ // I'm not sure if we ever get WM_CHAR (& friends) without an initial ++ // WM_KEYDOWN (& friends), but if we do then we should not send such ++ // side band events to simple keyboard widgets. ++ if ((fl_orig_msg.message != WM_KEYDOWN) && ++ (fl_orig_msg.message != WM_SYSKEYDOWN) && ++ (fl_orig_msg.message != WM_KEYUP) && ++ (fl_orig_msg.message != WM_SYSKEYUP)) ++ break; ++ ++ GetKeyboardState(keystate); ++ ++ // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off. ++ // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is ++ // active. ++ if (!(keystate[VK_MENU] & 0x80)) ++ keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0; ++ ++ // We cannot inspect or modify Windows' internal state of the keyboard ++ // so we have to try to infer information from ToUnicode() and wedge ++ // things into a known state. ++ for (int i = 0;i < 2;i++) { ++ ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf, ++ sizeof(wbuf)/sizeof(wbuf[0]), 0); ++ ++ // No symbol for this key (or unexpected length) ++ if ((ret == 0) || (ret < -1)) { ++ buffer[0] = 0; ++ Fl::e_length = 0; ++ break; ++ } ++ ++ // A dead key. Convert this to a Unicode combining character so ++ // that the application can tell the difference between dead and ++ // normal keys. ++ if (ret == -1) { ++ xchar u = (xchar) msdead2fltk(wbuf[0]); ++ Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); ++ buffer[Fl::e_length] = 0; ++ break; ++ } ++ ++ // If we have two characters (or more) from ToUnicode(), that's ++ // an invalid sequence. One character chould mean a proper symbol, ++ // or it could mean a composed one. In both cases we need to call ++ // ToUnicode() again to get something sane. ++ if (i == 0) ++ continue; ++ ++ // We should now have something sane. Give whatever we have to the ++ // application. ++ Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret); ++ buffer[Fl::e_length] = 0; ++ } ++ } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { + xchar u = (xchar) wParam; + // Fl::e_length = fl_unicode2utf(&u, 1, buffer); + Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); + buffer[Fl::e_length] = 0; ++ } else { ++ buffer[0] = 0; ++ Fl::e_length = 0; ++ } + +- +- } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { +- if (state & FL_NUM_LOCK) { +- // Convert to regular keypress... +- buffer[0] = Fl::e_keysym-FL_KP; +- Fl::e_length = 1; +- } else { +- // Convert to special keypress... +- buffer[0] = 0; +- Fl::e_length = 0; ++ // The keypad area is a bit odd in that we need to change the keysym ++ // to properly indicate what the user meant, unlike other keys where ++ // we normally change the text and keep keysym stable. ++ if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { ++ // The initial mapping tables give us a keysym that corresponds to ++ // numlock being on, so we only do something when it is off. ++ if (!(state & FL_NUM_LOCK)) { + switch (Fl::e_keysym) { + case FL_KP + '0' : + Fl::e_keysym = FL_Insert; +@@ -1073,30 +1208,10 @@ + case FL_KP + '.' : + Fl::e_keysym = FL_Delete; + break; +- case FL_KP + '/' : +- case FL_KP + '*' : +- case FL_KP + '-' : +- case FL_KP + '+' : +- buffer[0] = Fl::e_keysym-FL_KP; +- Fl::e_length = 1; +- break; + } + } +- } else if ((lParam & (1<<31))==0) { +-#ifdef FLTK_PREVIEW_DEAD_KEYS +- if ((lParam & (1<<24))==0) { // clear if dead key (always?) +- xchar u = (xchar) wParam; +- Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); +- buffer[Fl::e_length] = 0; +- } else { // set if "extended key" (never printable?) +- buffer[0] = 0; +- Fl::e_length = 0; +- } +-#else +- buffer[0] = 0; +- Fl::e_length = 0; +-#endif + } ++ + Fl::e_text = buffer; + if (lParam & (1<<31)) { // key up events. + if (Fl::handle(FL_KEYUP, window)) return 0; diff --git a/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch b/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch new file mode 100644 index 0000000000..cf13aad74b --- /dev/null +++ b/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch @@ -0,0 +1,375 @@ +diff -ur fltk-1.3.0r9619.org/configure.in fltk-1.3.0r9619/configure.in +--- fltk-1.3.0r9619.org/configure.in 2012-04-22 04:45:09.000000000 +0200 ++++ fltk-1.3.0r9619/configure.in 2012-06-18 13:47:33.290447462 +0200 +@@ -865,6 +865,8 @@ + Darwin*) + # MacOS X uses Cocoa for graphics. + LIBS="$LIBS -framework Cocoa" ++ # And some Carbon for keyboard handling ++ LIBS="$LIBS -framework Carbon" + + if test x$have_pthread = xyes; then + AC_DEFINE(HAVE_PTHREAD) +diff -ur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm +--- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-16 10:49:52.000000000 +0200 ++++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-18 13:47:42.944910782 +0200 +@@ -53,6 +53,7 @@ + #include + + #import ++#import + + #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h + #if defined(__LP64__) && __LP64__ +@@ -114,6 +115,8 @@ + extern Fl_Window* fl_xmousewin; + #endif + ++bool use_simple_keyboard = false; ++ + enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; + + +@@ -130,6 +133,39 @@ + { + } + ++// Undocumented voodoo. Taken from Mozilla. ++#define ENABLE_ROMAN_KYBDS_ONLY -23 ++ ++void fl_update_focus(void) ++{ ++ Fl_Widget *focus; ++ ++ focus = Fl::grab(); ++ if (!focus) ++ focus = Fl::focus(); ++ if (!focus) ++ return; ++ ++ if (focus->simple_keyboard()) ++ use_simple_keyboard = true; ++ else ++ use_simple_keyboard = false; ++ ++ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and ++ // Safari people seem to think implies turning off advanced IME stuff ++ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput ++ // in Safari/Webcore). Should be good enough for us then... ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); ++ TSMSetDocumentProperty(TSMGetActiveDocument(), ++ kTSMDocumentEnabledInputSourcesPropertyTag, ++ sizeof(CFArrayRef), &inputSources); ++ CFRelease(inputSources); ++#else ++ KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds); ++#endif ++} ++ + /* + * Mac keyboard lookup table + */ +@@ -908,6 +944,25 @@ + } + @end + ++static const char* cocoaDead2FLTK(const char *in) ++{ ++ if (strcmp(in, "\140") == 0) // GRAVE ACCENT ++ return "\314\200"; // COMBINING GRAVE ACCENT ++ if (strcmp(in, "\302\264") == 0) // ACUTE ACCENT ++ return "\314\201"; // COMBINING ACUTE ACCENT ++ if (strcmp(in, "\136") == 0) // CIRCUMFLEX ACCENT ++ return "\314\202"; // COMBINING CIRCUMFLEX ACCENT ++ if (strcmp(in, "\176") == 0) // TILDE ++ return "\314\203"; // COMBINING TILDE ++ if (strcmp(in, "\302\250") == 0) // DIAERESIS ++ return "\314\210"; // COMBINING DIAERESIS ++ // FIXME: OS X dead key behaviour isn't documented and I don't have ++ // any more keyboards to test with... ++ ++ // hope that OS X gave us something proper to begin with ++ return in; ++} ++ + /* + Handle cocoa keyboard events + Events during a character composition sequence: +@@ -1648,6 +1703,7 @@ + - (void)rightMouseDragged:(NSEvent *)theEvent; + - (void)otherMouseDragged:(NSEvent *)theEvent; + - (void)scrollWheel:(NSEvent *)theEvent; +++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags; + - (BOOL)handleKeyDown:(NSEvent *)theEvent; + - (void)keyDown:(NSEvent *)theEvent; + - (void)keyUp:(NSEvent *)theEvent; +@@ -1726,6 +1782,130 @@ + - (void)scrollWheel:(NSEvent *)theEvent { + cocoaMouseWheelHandler(theEvent); + } +++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags { ++ const UCKeyboardLayout *layout; ++ OSStatus err; ++ ++ layout = NULL; ++ ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ TISInputSourceRef keyboard; ++ CFDataRef uchr; ++ ++ keyboard = TISCopyCurrentKeyboardInputSource(); ++ uchr = (CFDataRef)TISGetInputSourceProperty(keyboard, ++ kTISPropertyUnicodeKeyLayoutData); ++ if (uchr == NULL) ++ return nil; ++ ++ layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); ++#else ++ KeyboardLayoutRef old_layout; ++ int kind; ++ ++ err = KLGetCurrentKeyboardLayout(&old_layout); ++ if (err != noErr) ++ return nil; ++ ++ err = KLGetKeyboardLayoutProperty(old_layout, kKLKind, ++ (const void**)&kind); ++ if (err != noErr) ++ return nil; ++ ++ // Old, crufty layout format? ++ if (kind == kKLKCHRKind) { ++ void *kchr_layout; ++ ++ UInt32 chars, state; ++ char buf[3]; ++ ++ unichar result[16]; ++ ByteCount in_len, out_len; ++ ++ err = KLGetKeyboardLayoutProperty(old_layout, kKLKCHRData, ++ (const void**)&kchr_layout); ++ if (err != noErr) ++ return nil; ++ ++ state = 0; ++ ++ keyCode &= 0x7f; ++ modifierFlags &= 0xff00; ++ ++ chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); ++ ++ buf[0] = (chars >> 16) & 0xff; ++ buf[1] = chars & 0xff; ++ buf[2] = '\0'; ++ ++ if (buf[0] == '\0') { ++ buf[0] = buf[1]; ++ buf[1] = '\0'; ++ } ++ ++ // The data is now in some layout specific encoding. Need to convert ++ // this to unicode. ++ ++ ScriptCode script; ++ TextEncoding encoding; ++ TECObjectRef converter; ++ ++ script = (ScriptCode)GetScriptManagerVariable(smKeyScript); ++ ++ err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, ++ kTextRegionDontCare, NULL, ++ &encoding); ++ if (err != noErr) ++ return nil; ++ ++ err = TECCreateConverter(&converter, encoding, kTextEncodingUnicodeV4_0); ++ if (err != noErr) ++ return nil; ++ ++ in_len = strlen(buf); ++ out_len = sizeof(result); ++ ++ err = TECConvertText(converter, (ConstTextPtr)buf, in_len, &in_len, ++ (TextPtr)result, out_len, &out_len); ++ ++ TECDisposeConverter(converter); ++ ++ if (err != noErr) ++ return nil; ++ ++ return [NSString stringWithCharacters:result ++ length:(out_len / sizeof(unichar))]; ++ } ++ ++ if ((kind != kKLKCHRuchrKind) && (kind != kKLuchrKind)) ++ return nil; ++ ++ err = KLGetKeyboardLayoutProperty(old_layout, kKLuchrData, ++ (const void**)&layout); ++ if (err != noErr) ++ return nil; ++#endif ++ ++ if (layout == NULL) ++ return nil; ++ ++ UInt32 dead_state; ++ UniCharCount max_len, actual_len; ++ UniChar string[255]; ++ ++ dead_state = 0; ++ max_len = sizeof(string)/sizeof(*string); ++ ++ modifierFlags = (modifierFlags >> 8) & 0xff; ++ ++ err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, ++ LMGetKbdType(), 0, &dead_state, max_len, &actual_len, ++ string); ++ if (err != noErr) ++ return nil; ++ ++ return [NSString stringWithCharacters:string length:actual_len]; ++} + - (BOOL)handleKeyDown:(NSEvent *)theEvent { + //NSLog(@"handleKeyDown"); + fl_lock_function(); +@@ -1752,14 +1932,47 @@ + break; + } + } +- if (!no_text_key && !(Fl::e_state & FL_META) ) { +- // Don't send cmd- to interpretKeyEvents because it beeps. ++ if (!no_text_key) { ++ // The simple keyboard model will ignore insertText, so we need to grab ++ // the symbol directly from the event. Note that we still use setMarkedText. ++ if (use_simple_keyboard) { ++ NSString *simple_chars; ++ UInt32 modifiers; ++ ++ // We want a "normal" symbol out of the event, which basically means ++ // we only respect the shift and alt/altgr modifiers. Cocoa can help ++ // us if we only wanted shift, but as we also want alt/altgr, we'll ++ // have to do some lookup ourselves. This matches our behaviour on ++ // other platforms. ++ ++ modifiers = 0; ++ if ([theEvent modifierFlags] & NSAlphaShiftKeyMask) ++ modifiers |= alphaLock; ++ if ([theEvent modifierFlags] & NSShiftKeyMask) ++ modifiers |= shiftKey; ++ if ([theEvent modifierFlags] & NSAlternateKeyMask) ++ modifiers |= optionKey; ++ ++ simple_chars = [FLView keyTranslate:[theEvent keyCode] ++ withModifierFlags:modifiers]; ++ if (simple_chars == nil) { ++ // Something went wrong. Fall back to what Cocoa gave us... ++ simple_chars = [theEvent charactersIgnoringModifiers]; ++ } ++ ++ [FLView prepareEtext:simple_chars]; ++ } ++ + // Then we can let the OS have a stab at it and see if it thinks it + // should result in some text +- NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; +- in_key_event = true; +- [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; +- in_key_event = false; ++ ++ // Don't send cmd- to interpretKeyEvents because it beeps. ++ if (!(Fl::e_state & FL_META)) { ++ NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; ++ in_key_event = true; ++ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; ++ in_key_event = false; ++ } + } + //NSLog(@"to text=%@ l=%d", [NSString stringWithUTF8String:Fl::e_text], Fl::e_length); + int handled = Fl::handle(FL_KEYDOWN, window); +@@ -1937,21 +2150,30 @@ + //NSLog(@"insertText: received=%@",received); + + if (!in_key_event) fl_lock_function(); ++ ++ // Simple keyboard widgets do not want these side channel inputs. ++ if (use_simple_keyboard) ++ goto end; ++ + [FLView prepareEtext:received]; ++ + // We can get called outside of key events (e.g. from the character +- // palette). Transform such actions to FL_PASTE events. ++ // palette). We need to fake our own key event at that point. + if (!in_key_event) { + Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; +- Fl::handle(FL_PASTE, target); ++ Fl::e_keysym = Fl::e_original_keysym = 0; ++ Fl::handle(FL_KEYDOWN, target); + // for some reason, the window does not redraw until the next mouse move or button push + // sending a 'redraw()' or 'awake()' does not solve the issue! + Fl::flush(); + } ++ ++end: + if (!in_key_event) fl_unlock_function(); + } + + - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { +- NSString *received; ++ NSString *received, *current, *aggregate; + if (newSelection.location == 0) { + [self unmarkText]; + return; +@@ -1962,11 +2184,47 @@ + received = (NSString*)aString; + } + //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); ++ ++ fl_lock_function(); ++ ++ // Simple keyboard widgets generally do not want these side channel ++ // inputs, but we have no other way of getting dead keys so we make ++ // an exception in that case. ++ if (use_simple_keyboard) { ++ if (in_key_event && (Fl::e_length == 0)) { ++ [FLView prepareEtext:received]; ++ ++ Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text); ++ Fl::e_length = strlen(Fl::e_text); ++ } ++ goto end; ++ } ++ + // This code creates the OS X behaviour of seeing dead keys as things + // are being composed. ++ // ++ // Note: The concatenation thing is because of how OS X deals with ++ // invalid sequences. At that point it will spit out one call ++ // to insertText with the now aborted sequence, and one new ++ // call to setMarkedText with the new sequence. Since we want ++ // both to be visible, we need to concatenate. + next_compose_length = newSelection.location; +- [FLView prepareEtext:received]; +- //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length); ++ current = [NSString stringWithUTF8String:Fl::e_text]; ++ aggregate = [current stringByAppendingString:received]; ++ ++ [FLView prepareEtext:aggregate]; ++ //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length); ++ ++ // We can get called outside of key events (e.g. from the character ++ // palette). We need to fake our own key event at that point. ++ if (!in_key_event) { ++ Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; ++ Fl::e_keysym = Fl::e_original_keysym = 0; ++ Fl::handle(FL_KEYDOWN, target); ++ } ++ ++end: ++ fl_unlock_function(); + } + + - (void)unmarkText { diff --git a/contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch b/contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch new file mode 100644 index 0000000000..3f12bc53a6 --- /dev/null +++ b/contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch @@ -0,0 +1,106 @@ +diff -up fltk-1.3.x-r8659/FL/Fl.H.orig fltk-1.3.x-r8659/FL/Fl.H +--- fltk-1.3.x-r8659/FL/Fl.H.orig 2011-05-17 16:25:56.671744548 +0200 ++++ fltk-1.3.x-r8659/FL/Fl.H 2011-05-17 16:26:05.709101536 +0200 +@@ -108,6 +108,9 @@ typedef int (*Fl_Args_Handler)(int argc, + \see Fl::event_dispatch(Fl_Event_Dispatch) */ + typedef int (*Fl_Event_Dispatch)(int event, Fl_Window *w); + ++/** Signature of add_clipboard_notify functions passed as parameters */ ++typedef void (*Fl_Clipboard_Notify_Handler)(int source, void *data); ++ + /** @} */ /* group callback_functions */ + + +@@ -744,6 +747,19 @@ public: + */ + static void paste(Fl_Widget &receiver, int source /*=0*/); // platform dependent + /** ++ FLTK will call the registered callback whenever there is a change to the ++ selection buffer or the clipboard. The source argument indicates which ++ of the two has changed. Only changes by other applications are reported. ++ \note Some systems require polling to monitor the clipboard and may ++ therefore have some delay in detecting changes. ++ */ ++ static void add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data); ++ /** ++ Stop calling the specified callback when there are changes to the selection ++ buffer or the clipboard. ++ */ ++ static void remove_clipboard_notify(Fl_Clipboard_Notify_Handler h); ++ /** + Initiate a Drag And Drop operation. The selection buffer should be + filled with relevant data before calling this method. FLTK will + then initiate the system wide drag and drop handling. Dropped data +diff -up fltk-1.3.x-r8659/src/Fl.cxx.orig fltk-1.3.x-r8659/src/Fl.cxx +--- fltk-1.3.x-r8659/src/Fl.cxx.orig 2011-05-18 15:20:26.667291459 +0200 ++++ fltk-1.3.x-r8659/src/Fl.cxx 2011-05-18 16:31:15.522026086 +0200 +@@ -430,6 +430,69 @@ static char in_idle; + #endif + + //////////////////////////////////////////////////////////////// ++// Clipboard notifications ++ ++struct Clipboard_Notify { ++ Fl_Clipboard_Notify_Handler handler; ++ void *data; ++ struct Clipboard_Notify *next; ++}; ++ ++static struct Clipboard_Notify *clip_notify_list = NULL; ++ ++extern void fl_clipboard_notify_change(); // in Fl_.cxx ++ ++void Fl::add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data) { ++ struct Clipboard_Notify *node; ++ ++ remove_clipboard_notify(h); ++ ++ node = new Clipboard_Notify; ++ ++ node->handler = h; ++ node->data = data; ++ node->next = clip_notify_list; ++ ++ clip_notify_list = node; ++ ++ fl_clipboard_notify_change(); ++} ++ ++void Fl::remove_clipboard_notify(Fl_Clipboard_Notify_Handler h) { ++ struct Clipboard_Notify *node, **prev; ++ ++ node = clip_notify_list; ++ prev = &clip_notify_list; ++ while (node != NULL) { ++ if (node->handler == h) { ++ *prev = node->next; ++ delete node; ++ ++ fl_clipboard_notify_change(); ++ ++ return; ++ } ++ ++ prev = &node->next; ++ node = node->next; ++ } ++} ++ ++bool fl_clipboard_notify_empty(void) { ++ return clip_notify_list == NULL; ++} ++ ++void fl_trigger_clipboard_notify(int source) { ++ struct Clipboard_Notify *node; ++ ++ node = clip_notify_list; ++ while (node != NULL) { ++ node->handler(source, node->data); ++ node = node->next; ++ } ++} ++ ++//////////////////////////////////////////////////////////////// + // wait/run/check/ready: + + void (*Fl::idle)(); // see Fl::add_idle.cxx for the add/remove functions diff --git a/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch b/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch new file mode 100644 index 0000000000..9e253a3f99 --- /dev/null +++ b/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch @@ -0,0 +1,355 @@ +diff -up fltk-1.3.2/CMakeLists.txt.clp-x11 fltk-1.3.2/CMakeLists.txt +--- fltk-1.3.2/CMakeLists.txt.clp-x11 2012-09-13 16:19:01.000000000 +0200 ++++ fltk-1.3.2/CMakeLists.txt 2013-01-30 15:56:25.810663430 +0100 +@@ -515,6 +515,20 @@ else() + endif(OPTION_USE_XINERAMA) + + ####################################################################### ++if(X11_Xfixes_FOUND) ++ option(OPTION_USE_XFIXES "use lib XFIXES" ON) ++endif(X11_Xfixes_FOUND) ++ ++if(OPTION_USE_XFIXES) ++ set(HAVE_XFIXES ${X11_Xfixes_FOUND}) ++ include_directories(${X11_Xfixes_INCLUDE_PATH}) ++ list(APPEND FLTK_LDLIBS -lXfixes) ++ set(FLTK_XFIXES_FOUND TRUE) ++else() ++ set(FLTK_XFIXES_FOUND FALSE) ++endif(OPTION_USE_XFIXES) ++ ++####################################################################### + if(X11_Xft_FOUND) + option(OPTION_USE_XFT "use lib Xft" ON) + endif(X11_Xft_FOUND) +diff -up fltk-1.3.2/configh.cmake.in.clp-x11 fltk-1.3.2/configh.cmake.in +--- fltk-1.3.2/configh.cmake.in.clp-x11 2011-07-19 06:49:30.000000000 +0200 ++++ fltk-1.3.2/configh.cmake.in 2013-01-30 15:56:25.810663430 +0100 +@@ -108,6 +108,14 @@ + #define USE_XDBE HAVE_XDBE + + /* ++ * HAVE_XFIXES: ++ * ++ * Do we have the X fixes extension? ++ */ ++ ++#cmakedefine01 HAVE_XFIXES ++ ++/* + * __APPLE_QUARTZ__: + * + * If __APPLE_QUARTZ__ is defined, FLTK will be +diff -up fltk-1.3.2/configh.in.clp-x11 fltk-1.3.2/configh.in +--- fltk-1.3.2/configh.in.clp-x11 2011-10-04 11:21:47.000000000 +0200 ++++ fltk-1.3.2/configh.in 2013-01-30 15:56:25.810663430 +0100 +@@ -108,6 +108,14 @@ + #define USE_XDBE HAVE_XDBE + + /* ++ * HAVE_XFIXES: ++ * ++ * Do we have the X fixes extension? ++ */ ++ ++#define HAVE_XFIXES 0 ++ ++/* + * __APPLE_QUARTZ__: + * + * All Apple implementations are now based on Quartz and Cocoa, +diff -up fltk-1.3.2/configure.in.clp-x11 fltk-1.3.2/configure.in +--- fltk-1.3.2/configure.in.clp-x11 2013-01-30 15:56:25.802663573 +0100 ++++ fltk-1.3.2/configure.in 2013-01-30 15:56:25.810663430 +0100 +@@ -999,6 +999,16 @@ case $uname_GUI in + LIBS="-lXext $LIBS") + fi + ++ dnl Check for the Xfixes extension unless disabled... ++ AC_ARG_ENABLE(xfixes, [ --enable-xfixes turn on Xfixes support [default=yes]]) ++ ++ if test x$enable_xfixes != xno; then ++ AC_CHECK_HEADER(X11/extensions/Xfixes.h, AC_DEFINE(HAVE_XFIXES),, ++ [#include ]) ++ AC_CHECK_LIB(Xfixes, XFixesQueryExtension, ++ LIBS="-lXfixes $LIBS") ++ fi ++ + dnl Check for overlay visuals... + AC_PATH_PROG(XPROP, xprop) + AC_CACHE_CHECK(for X overlay visuals, ac_cv_have_overlay, +diff -up fltk-1.3.2/fluid/CMakeLists.txt.clp-x11 fltk-1.3.2/fluid/CMakeLists.txt +diff -up fltk-1.3.2/src/CMakeLists.txt.clp-x11 fltk-1.3.2/src/CMakeLists.txt +--- fltk-1.3.2/src/CMakeLists.txt.clp-x11 2013-01-30 16:06:00.785430590 +0100 ++++ fltk-1.3.2/src/CMakeLists.txt 2013-01-30 16:06:17.883126642 +0100 +@@ -243,6 +243,10 @@ if(HAVE_XINERAMA) + target_link_libraries(fltk ${X11_Xinerama_LIB}) + endif(HAVE_XINERAMA) + ++if(HAVE_XFIXES) ++ target_link_libraries(fltk ${X11_Xfixes_LIB}) ++endif(HAVE_XFIXES) ++ + if(USE_XFT) + target_link_libraries(fltk ${X11_Xft_LIB}) + endif(USE_XFT) +diff -up fltk-1.3.2/src/Fl_x.cxx.clp-x11 fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.clp-x11 2013-01-30 15:56:25.793663733 +0100 ++++ fltk-1.3.2/src/Fl_x.cxx 2013-01-30 16:03:37.355981103 +0100 +@@ -53,6 +53,12 @@ static XRRUpdateConfiguration_type XRRUp + static int randrEventBase; // base of RandR-defined events + #endif + ++# if HAVE_XFIXES ++# include ++static int xfixes_event_base = 0; ++static bool have_xfixes = false; ++# endif ++ + static Fl_Xlib_Graphics_Driver fl_xlib_driver; + static Fl_Display_Device fl_xlib_display(&fl_xlib_driver); + Fl_Display_Device *Fl_Display_Device::_display = &fl_xlib_display;// the platform display +@@ -307,6 +313,9 @@ static Atom WM_PROTOCOLS; + static Atom fl_MOTIF_WM_HINTS; + static Atom TARGETS; + static Atom CLIPBOARD; ++static Atom TIMESTAMP; ++static Atom PRIMARY_TIMESTAMP; ++static Atom CLIPBOARD_TIMESTAMP; + Atom fl_XdndAware; + Atom fl_XdndSelection; + Atom fl_XdndEnter; +@@ -667,6 +676,9 @@ void fl_open_display(Display* d) { + fl_MOTIF_WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", 0); + TARGETS = XInternAtom(d, "TARGETS", 0); + CLIPBOARD = XInternAtom(d, "CLIPBOARD", 0); ++ TIMESTAMP = XInternAtom(d, "TIMESTAMP", 0); ++ PRIMARY_TIMESTAMP = XInternAtom(d, "PRIMARY_TIMESTAMP", 0); ++ CLIPBOARD_TIMESTAMP = XInternAtom(d, "CLIPBOARD_TIMESTAMP", 0); + fl_XdndAware = XInternAtom(d, "XdndAware", 0); + fl_XdndSelection = XInternAtom(d, "XdndSelection", 0); + fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); +@@ -713,6 +725,15 @@ void fl_open_display(Display* d) { + #if !USE_COLORMAP + Fl::visual(FL_RGB); + #endif ++ ++#if HAVE_XFIXES ++ int error_base; ++ if (XFixesQueryExtension(fl_display, &xfixes_event_base, &error_base)) ++ have_xfixes = true; ++ else ++ have_xfixes = false; ++#endif ++ + #if USE_XRANDR + void *libxrandr_addr = dlopen("libXrandr.so.2", RTLD_LAZY); + if (!libxrandr_addr) libxrandr_addr = dlopen("libXrandr.so", RTLD_LAZY); +@@ -901,6 +922,107 @@ void Fl::copy(const char *stuff, int len + } + + //////////////////////////////////////////////////////////////// ++// Code for tracking clipboard changes: ++ ++static Time primary_timestamp = -1; ++static Time clipboard_timestamp = -1; ++ ++extern bool fl_clipboard_notify_empty(void); ++extern void fl_trigger_clipboard_notify(int source); ++ ++static void poll_clipboard_owner(void) { ++ Window xid; ++ ++#if HAVE_XFIXES ++ // No polling needed with Xfixes ++ if (have_xfixes) ++ return; ++#endif ++ ++ // No one is interested, so no point polling ++ if (fl_clipboard_notify_empty()) ++ return; ++ ++ // We need a window for this to work ++ if (!Fl::first_window()) ++ return; ++ xid = fl_xid(Fl::first_window()); ++ if (!xid) ++ return; ++ ++ // Request an update of the selection time for both the primary and ++ // clipboard selections. Magic continues when we get a SelectionNotify. ++ if (!fl_i_own_selection[0]) ++ XConvertSelection(fl_display, XA_PRIMARY, TIMESTAMP, PRIMARY_TIMESTAMP, ++ xid, fl_event_time); ++ if (!fl_i_own_selection[1]) ++ XConvertSelection(fl_display, CLIPBOARD, TIMESTAMP, CLIPBOARD_TIMESTAMP, ++ xid, fl_event_time); ++} ++ ++static void clipboard_timeout(void *data) ++{ ++ // No one is interested, so stop polling ++ if (fl_clipboard_notify_empty()) ++ return; ++ ++ poll_clipboard_owner(); ++ ++ Fl::repeat_timeout(0.5, clipboard_timeout); ++} ++ ++static void handle_clipboard_timestamp(int clipboard, Time time) ++{ ++ Time *timestamp; ++ ++ timestamp = clipboard ? &clipboard_timestamp : &primary_timestamp; ++ ++#if HAVE_XFIXES ++ if (!have_xfixes) ++#endif ++ { ++ // Initial scan, just store the value ++ if (*timestamp == (Time)-1) { ++ *timestamp = time; ++ return; ++ } ++ } ++ ++ // Same selection ++ if (time == *timestamp) ++ return; ++ ++ *timestamp = time; ++ ++ // The clipboard change is the event that caused us to request ++ // the clipboard data, so use that time as the latest event. ++ if (time > fl_event_time) ++ fl_event_time = time; ++ ++ // Something happened! Let's tell someone! ++ fl_trigger_clipboard_notify(clipboard); ++} ++ ++void fl_clipboard_notify_change() { ++ // Reset the timestamps if we've going idle so that you don't ++ // get a bogus immediate trigger next time they're activated. ++ if (fl_clipboard_notify_empty()) { ++ primary_timestamp = -1; ++ clipboard_timestamp = -1; ++ } else { ++#if HAVE_XFIXES ++ if (!have_xfixes) ++#endif ++ { ++ poll_clipboard_owner(); ++ ++ if (!Fl::has_timeout(clipboard_timeout)) ++ Fl::add_timeout(0.5, clipboard_timeout); ++ } ++ } ++} ++ ++//////////////////////////////////////////////////////////////// + + const XEvent* fl_xevent; // the current x event + ulong fl_event_time; // the last timestamp from an x event +@@ -1024,7 +1141,6 @@ int fl_handle(const XEvent& thisevent) + return 0; + + case SelectionNotify: { +- if (!fl_selection_requestor) return 0; + static unsigned char* buffer = 0; + if (buffer) {XFree(buffer); buffer = 0;} + long bytesread = 0; +@@ -1040,6 +1156,19 @@ int fl_handle(const XEvent& thisevent) + bytesread/4, 65536, 1, 0, + &actual, &format, &count, &remaining, + &portion)) break; // quit on error ++ ++ if ((fl_xevent->xselection.property == PRIMARY_TIMESTAMP) || ++ (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)) { ++ if (portion && format == 32 && count == 1) { ++ Time t = *(unsigned int*)portion; ++ if (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP) ++ handle_clipboard_timestamp(1, t); ++ else ++ handle_clipboard_timestamp(0, t); ++ } ++ return true; ++ } ++ + if (actual == TARGETS || actual == XA_ATOM) { + Atom type = XA_STRING; + for (unsigned i = 0; ixselectionclear.selection == CLIPBOARD; + fl_i_own_selection[clipboard] = 0; ++ poll_clipboard_owner(); + return 1;} + + case SelectionRequest: { +@@ -1308,6 +1441,9 @@ int fl_handle(const XEvent& thisevent) + case FocusIn: + if (fl_xim_ic) XSetICFocus(fl_xim_ic); + event = FL_FOCUS; ++ // If the user has toggled from another application to this one, ++ // then it's a good time to check for clipboard changes. ++ poll_clipboard_owner(); + break; + + case FocusOut: +@@ -1676,6 +1812,25 @@ int fl_handle(const XEvent& thisevent) + } + } + ++#if HAVE_XFIXES ++ switch (xevent.type - xfixes_event_base) { ++ case XFixesSelectionNotify: { ++ // Someone feeding us bogus events? ++ if (!have_xfixes) ++ return true; ++ ++ XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)&xevent; ++ ++ if ((selection_notify->selection == XA_PRIMARY) && !fl_i_own_selection[0]) ++ handle_clipboard_timestamp(0, selection_notify->selection_timestamp); ++ else if ((selection_notify->selection == CLIPBOARD) && !fl_i_own_selection[1]) ++ handle_clipboard_timestamp(1, selection_notify->selection_timestamp); ++ ++ return true; ++ } ++ } ++#endif ++ + return Fl::handle(event, window); + } + +@@ -1995,6 +2150,16 @@ void Fl_X::make_xid(Fl_Window* win, XVis + XChangeProperty(fl_display, xp->xid, net_wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_type_kind, 1); + } + ++#if HAVE_XFIXES ++ // register for clipboard change notifications ++ if (have_xfixes && !win->parent()) { ++ XFixesSelectSelectionInput(fl_display, xp->xid, XA_PRIMARY, ++ XFixesSetSelectionOwnerNotifyMask); ++ XFixesSelectSelectionInput(fl_display, xp->xid, CLIPBOARD, ++ XFixesSetSelectionOwnerNotifyMask); ++ } ++#endif ++ + XMapWindow(fl_display, xp->xid); + if (showit) { + win->set_visible(); +diff -up fltk-1.3.2/test/CMakeLists.txt.clp-x11 fltk-1.3.2/test/CMakeLists.txt diff --git a/contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch b/contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch new file mode 100644 index 0000000000..b41af794e3 --- /dev/null +++ b/contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch @@ -0,0 +1,135 @@ +diff -ur fltk-1.3.0r9110.org/src/Fl_win32.cxx fltk-1.3.0r9110/src/Fl_win32.cxx +--- fltk-1.3.0r9110.org/src/Fl_win32.cxx 2012-06-17 19:42:02.169422400 +0200 ++++ fltk-1.3.0r9110/src/Fl_win32.cxx 2012-06-17 19:43:38.286031455 +0200 +@@ -543,6 +543,37 @@ + const char* GetValue() const { return(out); } + }; + ++void fl_update_clipboard(void) { ++ Fl_Window *w1 = Fl::first_window(); ++ if (!w1) ++ return; ++ ++ HWND hwnd = fl_xid(w1); ++ ++ if (!OpenClipboard(hwnd)) ++ return; ++ ++ EmptyClipboard(); ++ ++ int utf16_len = fl_utf8toUtf16(fl_selection_buffer[1], ++ fl_selection_length[1], 0, 0); ++ ++ HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc. ++ LPVOID memLock = GlobalLock(hMem); ++ ++ fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], ++ (unsigned short*) memLock, utf16_len + 1); ++ ++ GlobalUnlock(hMem); ++ SetClipboardData(CF_UNICODETEXT, hMem); ++ ++ CloseClipboard(); ++ ++ // In case Windows managed to lob of a WM_DESTROYCLIPBOARD during ++ // the above. ++ fl_i_own_selection[1] = 1; ++} ++ + // call this when you create a selection: + void Fl::copy(const char *stuff, int len, int clipboard) { + if (!stuff || len<0) return; +@@ -560,25 +591,9 @@ + memcpy(fl_selection_buffer[clipboard], stuff, len); + fl_selection_buffer[clipboard][len] = 0; // needed for direct paste + fl_selection_length[clipboard] = len; +- if (clipboard) { +- // set up for "delayed rendering": +- if (OpenClipboard(NULL)) { +- // if the system clipboard works, use it +- int utf16_len = fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], 0, 0); +- EmptyClipboard(); +- HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc. +- LPVOID memLock = GlobalLock(hMem); +- fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], (unsigned short*) memLock, utf16_len + 1); +- GlobalUnlock(hMem); +- SetClipboardData(CF_UNICODETEXT, hMem); +- CloseClipboard(); +- GlobalFree(hMem); +- fl_i_own_selection[clipboard] = 0; +- } else { +- // only if it fails, instruct paste() to use the internal buffers +- fl_i_own_selection[clipboard] = 1; +- } +- } ++ fl_i_own_selection[clipboard] = 1; ++ if (clipboard) ++ fl_update_clipboard(); + } + + // Call this when a "paste" operation happens: +@@ -1307,33 +1322,6 @@ + fl_i_own_selection[1] = 0; + return 1; + +- case WM_RENDERALLFORMATS: +- fl_i_own_selection[1] = 0; +- // Windoze seems unhappy unless I do these two steps. Documentation +- // seems to vary on whether opening the clipboard is necessary or +- // is in fact wrong: +- CloseClipboard(); +- OpenClipboard(NULL); +- // fall through... +- case WM_RENDERFORMAT: { +- HANDLE h; +- +-// int l = fl_utf_nb_char((unsigned char*)fl_selection_buffer[1], fl_selection_length[1]); +- int l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], NULL, 0); // Pass NULL buffer to query length required +- h = GlobalAlloc(GHND, (l+1) * sizeof(unsigned short)); +- if (h) { +- unsigned short *g = (unsigned short*) GlobalLock(h); +-// fl_utf2unicode((unsigned char *)fl_selection_buffer[1], fl_selection_length[1], (xchar*)g); +- l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], g, (l+1)); +- g[l] = 0; +- GlobalUnlock(h); +- SetClipboardData(CF_UNICODETEXT, h); +- } +- +- // Windoze also seems unhappy if I don't do this. Documentation very +- // unclear on what is correct: +- if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard(); +- return 1;} + case WM_DISPLAYCHANGE: // occurs when screen configuration (number, position) changes + Fl::call_screen_init(); + Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); +diff -ur fltk-1.3.0r9110.org/src/Fl.cxx fltk-1.3.0r9110/src/Fl.cxx +--- fltk-1.3.0r9110.org/src/Fl.cxx 2012-06-17 19:42:02.173422595 +0200 ++++ fltk-1.3.0r9110/src/Fl.cxx 2012-06-17 19:42:02.317429497 +0200 +@@ -1420,7 +1420,9 @@ + //////////////////////////////////////////////////////////////// + // hide() destroys the X window, it does not do unmap! + +-#if !defined(WIN32) && USE_XFT ++#if defined(WIN32) ++extern void fl_update_clipboard(void); ++#elif USE_XFT + extern void fl_destroy_xft_draw(Window); + #endif + +@@ -1467,14 +1469,8 @@ + #if defined(WIN32) + // this little trick keeps the current clipboard alive, even if we are about + // to destroy the window that owns the selection. +- if (GetClipboardOwner()==ip->xid) { +- Fl_Window *w1 = Fl::first_window(); +- if (w1 && OpenClipboard(fl_xid(w1))) { +- EmptyClipboard(); +- SetClipboardData(CF_TEXT, NULL); +- CloseClipboard(); +- } +- } ++ if (GetClipboardOwner()==ip->xid) ++ fl_update_clipboard(); + // Send a message to myself so that I'll get out of the event loop... + PostMessage(ip->xid, WM_APP, 0, 0); + if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc); diff --git a/contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch b/contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch new file mode 100644 index 0000000000..ac94779c6b --- /dev/null +++ b/contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch @@ -0,0 +1,99 @@ +diff -ur fltk-1.3.0r9110.org/src/Fl.cxx fltk-1.3.0r9110/src/Fl.cxx +--- fltk-1.3.0r9110.org/src/Fl.cxx 2012-06-17 19:47:09.988183253 +0200 ++++ fltk-1.3.0r9110/src/Fl.cxx 2012-06-17 19:47:10.127189919 +0200 +@@ -1421,6 +1421,7 @@ + // hide() destroys the X window, it does not do unmap! + + #if defined(WIN32) ++extern void fl_clipboard_notify_untarget(HWND wnd); + extern void fl_update_clipboard(void); + #elif USE_XFT + extern void fl_destroy_xft_draw(Window); +@@ -1471,6 +1472,8 @@ + // to destroy the window that owns the selection. + if (GetClipboardOwner()==ip->xid) + fl_update_clipboard(); ++ // Make sure we unlink this window from the clipboard chain ++ fl_clipboard_notify_untarget(ip->xid); + // Send a message to myself so that I'll get out of the event loop... + PostMessage(ip->xid, WM_APP, 0, 0); + if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc); +diff -ur fltk-1.3.0r9110.org/src/Fl_win32.cxx fltk-1.3.0r9110/src/Fl_win32.cxx +--- fltk-1.3.0r9110.org/src/Fl_win32.cxx 2012-06-17 19:47:09.987183205 +0200 ++++ fltk-1.3.0r9110/src/Fl_win32.cxx 2012-06-17 19:47:19.069618739 +0200 +@@ -646,6 +646,38 @@ + } + } + ++static HWND clipboard_wnd = 0; ++static HWND next_clipboard_wnd = 0; ++ ++static bool initial_clipboard = true; ++ ++void fl_clipboard_notify_change() { ++ // No need to do anything here... ++} ++ ++void fl_clipboard_notify_target(HWND wnd) { ++ if (clipboard_wnd) ++ return; ++ ++ // We get one fake WM_DRAWCLIPBOARD immediately, which we therefore ++ // need to ignore. ++ initial_clipboard = true; ++ ++ clipboard_wnd = wnd; ++ next_clipboard_wnd = SetClipboardViewer(wnd); ++} ++ ++void fl_clipboard_notify_untarget(HWND wnd) { ++ if (wnd != clipboard_wnd) ++ return; ++ ++ ChangeClipboardChain(wnd, next_clipboard_wnd); ++ clipboard_wnd = next_clipboard_wnd = 0; ++ ++ if (Fl::first_window()) ++ fl_clipboard_notify_target(fl_xid(Fl::first_window())); ++} ++ + //////////////////////////////////////////////////////////////// + char fl_is_ime = 0; + void fl_get_codepage() +@@ -1327,6 +1359,27 @@ + Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); + return 0; + ++ case WM_CHANGECBCHAIN: ++ if ((hWnd == clipboard_wnd) && ++ (next_clipboard_wnd == (HWND)wParam)) { ++ next_clipboard_wnd = (HWND)lParam; ++ return 0; ++ } ++ break; ++ ++ case WM_DRAWCLIPBOARD: ++ // When the clipboard moves between two FLTK windows, ++ // fl_i_own_selection will temporarily be false as we are ++ // processing this message. Hence the need to use fl_find(). ++ if (!initial_clipboard && !fl_find(GetClipboardOwner())) ++ fl_trigger_clipboard_notify(1); ++ initial_clipboard = false; ++ ++ if (next_clipboard_wnd) ++ SendMessage(next_clipboard_wnd, WM_DRAWCLIPBOARD, wParam, lParam); ++ ++ return 0; ++ + default: + if (Fl::handle(0,0)) return 0; + break; +@@ -1685,6 +1738,8 @@ + x->next = Fl_X::first; + Fl_X::first = x; + ++ fl_clipboard_notify_target(x->xid); ++ + x->wait_for_expose = 1; + if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;} + if (showit) { diff --git a/contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch b/contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch new file mode 100644 index 0000000000..22e693962e --- /dev/null +++ b/contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch @@ -0,0 +1,44 @@ +diff -bur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm +--- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-18 19:24:30.971688769 +0200 ++++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-18 19:25:25.700310375 +0200 +@@ -1319,9 +1319,13 @@ + } + @end + ++static void clipboard_check(void); ++ + @implementation FLApplication + + (void)sendEvent:(NSEvent *)theEvent + { ++ // update clipboard status ++ clipboard_check(); + NSEventType type = [theEvent type]; + if (type == NSLeftMouseDown) { + fl_lock_function(); +@@ -2790,6 +2794,26 @@ + PasteboardCreate(kPasteboardClipboard, &myPasteboard); + } + ++extern void fl_trigger_clipboard_notify(int source); ++ ++void fl_clipboard_notify_change() { ++ // No need to do anything here... ++} ++ ++static void clipboard_check(void) ++{ ++ PasteboardSyncFlags flags; ++ ++ allocatePasteboard(); ++ flags = PasteboardSynchronize(myPasteboard); ++ ++ if (!(flags & kPasteboardModified)) ++ return; ++ if (flags & kPasteboardClientIsOwner) ++ return; ++ ++ fl_trigger_clipboard_notify(1); ++} + + /* + * create a selection diff --git a/contrib/fltk/09-str2659-pixmap.patch b/contrib/fltk/09-str2659-pixmap.patch new file mode 100644 index 0000000000..303151388f --- /dev/null +++ b/contrib/fltk/09-str2659-pixmap.patch @@ -0,0 +1,554 @@ +diff -ur fltk-1.3.2.org/FL/Fl_Image.H fltk-1.3.2/FL/Fl_Image.H +--- fltk-1.3.2.org/FL/Fl_Image.H 2012-11-09 17:02:08.000000000 +0100 ++++ fltk-1.3.2/FL/Fl_Image.H 2013-01-16 14:40:51.543230638 +0100 +@@ -26,6 +26,7 @@ + #include + + class Fl_Widget; ++class Fl_Pixmap; + struct Fl_Menu_Item; + struct Fl_Label; + +@@ -203,6 +204,7 @@ + */ + Fl_RGB_Image(const uchar *bits, int W, int H, int D=3, int LD=0) : + Fl_Image(W,H,D), array(bits), alloc_array(0), id_(0), mask_(0) {data((const char **)&array, 1); ld(LD);} ++ Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg=FL_GRAY); + virtual ~Fl_RGB_Image(); + virtual Fl_Image *copy(int W, int H); + Fl_Image *copy() { return copy(w(), h()); } +diff -ur fltk-1.3.2.org/src/fl_draw_pixmap.cxx fltk-1.3.2/src/fl_draw_pixmap.cxx +--- fltk-1.3.2.org/src/fl_draw_pixmap.cxx 2012-04-22 05:09:31.000000000 +0200 ++++ fltk-1.3.2/src/fl_draw_pixmap.cxx 2013-01-16 14:40:51.542230588 +0100 +@@ -58,99 +58,6 @@ + return 1; + } + +-#ifdef U64 +- +-// The callback from fl_draw_image to get a row of data passes this: +-struct pixmap_data { +- int w, h; +- const uchar*const* data; +- union { +- U64 colors[256]; +- U64* byte1[256]; +- }; +-}; +- +-// callback for 1 byte per pixel: +-static void cb1(void*v, int x, int y, int w, uchar* buf) { +- pixmap_data& d = *(pixmap_data*)v; +- const uchar* p = d.data[y]+x; +- U64* q = (U64*)buf; +- for (int X=w; X>0; X-=2, p += 2) { +- if (X>1) { +-# if WORDS_BIGENDIAN +- *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]]; +-# else +- *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]]; +-# endif +- } else { +-# if WORDS_BIGENDIAN +- *q++ = d.colors[p[0]]<<32; +-# else +- *q++ = d.colors[p[0]]; +-# endif +- } +- } +-} +- +-// callback for 2 bytes per pixel: +-static void cb2(void*v, int x, int y, int w, uchar* buf) { +- pixmap_data& d = *(pixmap_data*)v; +- const uchar* p = d.data[y]+2*x; +- U64* q = (U64*)buf; +- for (int X=w; X>0; X-=2) { +- U64* colors = d.byte1[*p++]; +- int index = *p++; +- if (X>1) { +- U64* colors1 = d.byte1[*p++]; +- int index1 = *p++; +-# if WORDS_BIGENDIAN +- *q++ = (colors[index]<<32) | colors1[index1]; +-# else +- *q++ = (colors1[index1]<<32) | colors[index]; +-# endif +- } else { +-# if WORDS_BIGENDIAN +- *q++ = colors[index]<<32; +-# else +- *q++ = colors[index]; +-# endif +- } +- } +-} +- +-#else // U32 +- +-// The callback from fl_draw_image to get a row of data passes this: +-struct pixmap_data { +- int w, h; +- const uchar*const* data; +- union { +- U32 colors[256]; +- U32* byte1[256]; +- }; +-}; +- +-// callback for 1 byte per pixel: +-static void cb1(void*v, int x, int y, int w, uchar* buf) { +- pixmap_data& d = *(pixmap_data*)v; +- const uchar* p = d.data[y]+x; +- U32* q = (U32*)buf; +- for (int X=w; X--;) *q++ = d.colors[*p++]; +-} +- +-// callback for 2 bytes per pixel: +-static void cb2(void*v, int x, int y, int w, uchar* buf) { +- pixmap_data& d = *(pixmap_data*)v; +- const uchar* p = d.data[y]+2*x; +- U32* q = (U32*)buf; +- for (int X=w; X--;) { +- U32* colors = d.byte1[*p++]; +- *q++ = colors[*p++]; +- } +-} +- +-#endif // U64 else U32 +- + uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here + + /** +@@ -200,34 +107,33 @@ + } + #endif + +-/** +- Draw XPM image data, with the top-left corner at the given position. +- \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg) +- */ +-int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) { +- pixmap_data d; +- if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0; ++int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg) { ++ int w, h; + const uchar*const* data = (const uchar*const*)(cdata+1); + int transparent_index = -1; ++ ++ if (!fl_measure_pixmap(cdata, w, h)) ++ return 0; ++ ++ if ((chars_per_pixel < 1) || (chars_per_pixel > 2)) ++ return 0; ++ ++ uchar colors[1<<(chars_per_pixel*8)][4]; ++ + #ifdef WIN32 + uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color + color_count = 0; + used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar)); + #endif + +- if (ncolors < 0) { // FLTK (non standard) compressed colormap ++ if (ncolors < 0) { ++ // FLTK (non standard) compressed colormap + ncolors = -ncolors; + const uchar *p = *data++; + // if first color is ' ' it is transparent (put it later to make + // it not be transparent): + if (*p == ' ') { +- uchar* c = (uchar*)&d.colors[(int)' ']; +-#ifdef U64 +- *(U64*)c = 0; +-# if WORDS_BIGENDIAN +- c += 4; +-# endif +-#endif ++ uchar* c = colors[(int)' ']; + transparent_index = ' '; + Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0; + #ifdef WIN32 +@@ -238,13 +144,7 @@ + } + // read all the rest of the colors: + for (int i=0; i < ncolors; i++) { +- uchar* c = (uchar*)&d.colors[*p++]; +-#ifdef U64 +- *(U64*)c = 0; +-# if WORDS_BIGENDIAN +- c += 4; +-# endif +-#endif ++ uchar* c = colors[*p++]; + #ifdef WIN32 + used_colors[3*color_count] = *p; + used_colors[3*color_count+1] = *(p+1); +@@ -254,69 +154,44 @@ + *c++ = *p++; + *c++ = *p++; + *c++ = *p++; +-#ifdef __APPLE_QUARTZ__ + *c = 255; +-#else +- *c = 0; +-#endif + } +- } else { // normal XPM colormap with names +- if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1)); ++ } else { ++ // normal XPM colormap with names + for (int i=0; i1) { +-#ifdef U64 +- U64* colors = d.byte1[ind]; +- if (!colors) colors = d.byte1[ind] = new U64[256]; +-#else +- U32* colors = d.byte1[ind]; +- if (!colors) colors = d.byte1[ind] = new U32[256]; +-#endif +- c = (uchar*)&colors[*p]; +- ind = (ind<<8)|*p++; +- } else { +- c = (uchar *)&d.colors[ind]; +- } ++ if (chars_per_pixel>1) ++ ind = (ind<<8)|*p++; ++ c = colors[ind]; + // look for "c word", or last word if none: + const uchar *previous_word = p; + for (;;) { +- while (*p && isspace(*p)) p++; +- uchar what = *p++; +- while (*p && !isspace(*p)) p++; +- while (*p && isspace(*p)) p++; +- if (!*p) {p = previous_word; break;} +- if (what == 'c') break; +- previous_word = p; +- while (*p && !isspace(*p)) p++; ++ while (*p && isspace(*p)) p++; ++ uchar what = *p++; ++ while (*p && !isspace(*p)) p++; ++ while (*p && isspace(*p)) p++; ++ if (!*p) {p = previous_word; break;} ++ if (what == 'c') break; ++ previous_word = p; ++ while (*p && !isspace(*p)) p++; + } +-#ifdef U64 +- *(U64*)c = 0; +-# if WORDS_BIGENDIAN +- c += 4; +-# endif +-#endif +-#ifdef __APPLE_QUARTZ__ +- c[3] = 255; +-#endif + int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]); ++ c[3] = 255; + if (parse) { + #ifdef WIN32 +- used_colors[3*color_count] = c[0]; +- used_colors[3*color_count+1] = c[1]; +- used_colors[3*color_count+2] = c[2]; +- color_count++; ++ used_colors[3*color_count] = c[0]; ++ used_colors[3*color_count+1] = c[1]; ++ used_colors[3*color_count+2] = c[2]; ++ color_count++; + #endif +- } +- else { ++ } else { + // assume "None" or "#transparent" for any errors +- // "bg" should be transparent... +- Fl::get_color(bg, c[0], c[1], c[2]); +-#ifdef __APPLE_QUARTZ__ ++ // "bg" should be transparent... ++ Fl::get_color(bg, c[0], c[1], c[2]); + c[3] = 0; +-#endif + transparent_index = ind; + #ifdef WIN32 + transparent_c = c; +@@ -324,7 +199,6 @@ + } + } + } +- d.data = data; + #ifdef WIN32 + if (transparent_c) { + make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]); +@@ -334,77 +208,76 @@ + make_unused_color(r, g, b); + } + #endif ++ ++ U32 *q = (U32*)out; ++ for (int Y = 0; Y < h; Y++) { ++ const uchar* p = data[Y]; ++ if (chars_per_pixel <= 1) { ++ for (int X = 0; X < w; X++) ++ memcpy(q++, colors[*p++], 4); ++ } else { ++ for (int X = 0; X < w; X++) { ++ int ind = (*p++)<<8; ++ ind |= *p++; ++ memcpy(q++, colors[ind], 4); ++ } ++ } ++ } + ++ return 1; ++} ++ ++/** ++ Draw XPM image data, with the top-left corner at the given position. ++ \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg) ++ */ ++int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) { ++ int w, h; ++ ++ if (!fl_measure_pixmap(cdata, w, h)) ++ return 0; ++ ++ uchar buffer[w*h*4]; ++ ++ if (!fl_convert_pixmap(cdata, buffer, bg)) ++ return 0; ++ ++ // FIXME: Hack until fl_draw_image() supports alpha properly + #ifdef __APPLE_QUARTZ__ + if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) { +- U32 *array = new U32[d.w * d.h], *q = array; +- for (int Y = 0; Y < d.h; Y++) { +- const uchar* p = data[Y]; +- if (chars_per_pixel <= 1) { +- for (int X = 0; X < d.w; X++) { +- *q++ = d.colors[*p++]; +- } +- } else { +- for (int X = 0; X < d.w; X++) { +- U32* colors = (U32*)d.byte1[*p++]; +- *q++ = colors[*p++]; +- } +- } +- } +- Fl_RGB_Image* rgb = new Fl_RGB_Image((uchar*)array, d.w, d.h, 4); ++ Fl_RGB_Image* rgb = new Fl_RGB_Image(buffer, w, h, 4); + rgb->draw(x, y); + delete rgb; +- delete[] array; +- } +- else { ++ } else { + #endif // __APPLE_QUARTZ__ +- + // build the mask bitmap used by Fl_Pixmap: +- if (fl_mask_bitmap && transparent_index >= 0) { +- int W = (d.w+7)/8; +- uchar* bitmap = new uchar[W * d.h]; ++ if (fl_mask_bitmap) { ++ int W = (w+7)/8; ++ uchar* bitmap = new uchar[W * h]; + *fl_mask_bitmap = bitmap; +- for (int Y = 0; Y < d.h; Y++) { +- const uchar* p = data[Y]; +- if (chars_per_pixel <= 1) { +- int dw = d.w; +- for (int X = 0; X < W; X++) { +- uchar b = (dw-->0 && *p++ != transparent_index); +- if (dw-->0 && *p++ != transparent_index) b |= 2; +- if (dw-->0 && *p++ != transparent_index) b |= 4; +- if (dw-->0 && *p++ != transparent_index) b |= 8; +- if (dw-->0 && *p++ != transparent_index) b |= 16; +- if (dw-->0 && *p++ != transparent_index) b |= 32; +- if (dw-->0 && *p++ != transparent_index) b |= 64; +- if (dw-->0 && *p++ != transparent_index) b |= 128; ++ const uchar *p = &buffer[3]; ++ uchar b = 0; ++ for (int Y = 0; Y < h; Y++) { ++ b = 0; ++ for (int X = 0, bit = 1; X < w; X++, p += 4) { ++ if (*p > 127) b |= bit; ++ bit <<= 1; ++ if (bit > 0x80 || X == w-1) { + *bitmap++ = b; +- } +- } else { +- uchar b = 0, bit = 1; +- for (int X = 0; X < d.w; X++) { +- int ind = *p++; +- ind = (ind<<8) | (*p++); +- if (ind != transparent_index) b |= bit; +- +- if (bit < 128) bit <<= 1; +- else { +- *bitmap++ = b; +- b = 0; +- bit = 1; ++ bit = 1; ++ b = 0; + } + } +- +- if (bit > 1) *bitmap++ = b; + } +- } ++ + } + +- fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4); ++ fl_draw_image(buffer, x, y, w, h, 4); ++ + #ifdef __APPLE_QUARTZ__ + } + #endif + +- if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i]; + return 1; + } + +diff -ur fltk-1.3.2.org/src/Fl_Image.cxx fltk-1.3.2/src/Fl_Image.cxx +--- fltk-1.3.2.org/src/Fl_Image.cxx 2012-11-09 17:02:08.000000000 +0100 ++++ fltk-1.3.2/src/Fl_Image.cxx 2013-01-16 14:41:38.404162795 +0100 +@@ -165,7 +165,22 @@ + // + size_t Fl_RGB_Image::max_size_ = ~((size_t)0); + +-/** The destructor free all memory and server resources that are used by the image. */ ++int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg); ++ ++/** The constructor creates a new RGBA image from the specified Fl_Pixmap. ++ ++ The RGBA image is built fully opaque except for the transparent area ++ of the pixmap that is assigned the \par bg color with full transparency */ ++Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg): ++ Fl_Image(pxm->w(), pxm->h(), 4), id_(0), mask_(0) ++{ ++ array = new uchar[w() * h() * d()]; ++ alloc_array = 1; ++ fl_convert_pixmap(pxm->data(), (uchar*)array, bg); ++ data((const char **)&array, 1); ++} ++ ++/** The destructor frees all memory and server resources that are used by the image. */ + Fl_RGB_Image::~Fl_RGB_Image() { + uncache(); + if (alloc_array) delete[] (uchar *)array; +diff -ur fltk-1.3.2.org/src/ps_image.cxx fltk-1.3.2/src/ps_image.cxx +--- fltk-1.3.2.org/src/ps_image.cxx 2011-07-19 06:49:30.000000000 +0200 ++++ fltk-1.3.2/src/ps_image.cxx 2013-01-16 14:40:51.541228080 +0100 +@@ -185,72 +185,38 @@ + + extern uchar **fl_mask_bitmap; + ++struct callback_data { ++ const uchar *data; ++ int D, LD; ++}; + +-void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { +- double x = ix, y = iy, w = iw, h = ih; + +- if (D<3){ //mono +- draw_image_mono(data, ix, iy, iw, ih, D, LD); +- return; +- } ++static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) { ++ struct callback_data *cb_data; ++ const uchar *curdata; + ++ cb_data = (struct callback_data*)data; ++ curdata = cb_data->data + x*cb_data->D + y*cb_data->LD; + +- int i,j, k; ++ memcpy(buf, curdata, w*cb_data->D); ++} + +- fprintf(output,"save\n"); + +- const char * interpol; +- if (lang_level_>1){ +- if (interpolate_) +- interpol="true"; +- else +- interpol="false"; +- if (mask && lang_level_>2) +- fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol); +- else +- fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol); +- } else +- fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih); ++void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { ++ if (D<3){ //mono ++ draw_image_mono(data, ix, iy, iw, ih, D, LD); ++ return; ++ } + ++ struct callback_data cb_data; + + if (!LD) LD = iw*D; +- uchar *curmask=mask; +- +- for (j=0; j3) { //can do mixing using bg_* colors) +- unsigned int a2 = curdata[3]; //must be int +- unsigned int a = 255-a2; +- r = (a2 * r + bg_r * a)/255; +- g = (a2 * g + bg_g * a)/255; +- b = (a2 * b + bg_b * a)/255; +- } +- if (!(i%40)) fprintf(output, "\n"); +- fprintf(output, "%.2x%.2x%.2x", r, g, b); +- curdata +=D; +- } +- fprintf(output,"\n"); +- +- } +- +- fprintf(output," >\nrestore\n" ); + ++ cb_data.data = data; ++ cb_data.D = D; ++ cb_data.LD = LD; + ++ draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D); + } + + void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) { +@@ -325,6 +291,14 @@ + uchar g = curdata[1]; + uchar b = curdata[2]; + ++ if (lang_level_<3 && D>3) { //can do mixing using bg_* colors) ++ unsigned int a2 = curdata[3]; //must be int ++ unsigned int a = 255-a2; ++ r = (a2 * r + bg_r * a)/255; ++ g = (a2 * g + bg_g * a)/255; ++ b = (a2 * b + bg_b * a)/255; ++ } ++ + if (!(i%40)) fputs("\n", output); + fprintf(output, "%.2x%.2x%.2x", r, g, b); + diff --git a/contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch b/contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch new file mode 100644 index 0000000000..8e990505d3 --- /dev/null +++ b/contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch @@ -0,0 +1,1623 @@ +diff -up fltk-1.3.2/CMakeLists.txt.cursor fltk-1.3.2/CMakeLists.txt +--- fltk-1.3.2/CMakeLists.txt.cursor 2013-01-30 16:07:59.510320246 +0100 ++++ fltk-1.3.2/CMakeLists.txt 2013-01-30 16:07:59.528319926 +0100 +@@ -529,6 +529,20 @@ else() + endif(OPTION_USE_XFIXES) + + ####################################################################### ++if(X11_Xcursor_FOUND) ++ option(OPTION_USE_XCURSOR "use lib XCURSOR" ON) ++endif(X11_Xcursor_FOUND) ++ ++if(OPTION_USE_XCURSOR) ++ set(HAVE_XCURSOR ${X11_Xcursor_FOUND}) ++ include_directories(${X11_Xcursor_INCLUDE_PATH}) ++ list(APPEND FLTK_LDLIBS -lXcursor) ++ set(FLTK_XCURSOR_FOUND TRUE) ++else() ++ set(FLTK_XCURSOR_FOUND FALSE) ++endif(OPTION_USE_XCURSOR) ++ ++####################################################################### + if(X11_Xft_FOUND) + option(OPTION_USE_XFT "use lib Xft" ON) + endif(X11_Xft_FOUND) +diff -up fltk-1.3.2/configh.cmake.in.cursor fltk-1.3.2/configh.cmake.in +--- fltk-1.3.2/configh.cmake.in.cursor 2013-01-30 16:07:59.510320246 +0100 ++++ fltk-1.3.2/configh.cmake.in 2013-01-30 16:07:59.529319908 +0100 +@@ -116,6 +116,14 @@ + #cmakedefine01 HAVE_XFIXES + + /* ++ * HAVE_XCURSOR: ++ * ++ * Do we have the X cursor library? ++ */ ++ ++#cmakedefine01 HAVE_XCURSOR ++ ++/* + * __APPLE_QUARTZ__: + * + * If __APPLE_QUARTZ__ is defined, FLTK will be +diff -up fltk-1.3.2/configh.in.cursor fltk-1.3.2/configh.in +--- fltk-1.3.2/configh.in.cursor 2013-01-30 16:07:59.510320246 +0100 ++++ fltk-1.3.2/configh.in 2013-01-30 16:07:59.529319908 +0100 +@@ -116,6 +116,14 @@ + #define HAVE_XFIXES 0 + + /* ++ * HAVE_XCURSOR: ++ * ++ * Do we have the X cursor library? ++ */ ++ ++#define HAVE_XCURSOR 0 ++ ++/* + * __APPLE_QUARTZ__: + * + * All Apple implementations are now based on Quartz and Cocoa, +diff -up fltk-1.3.2/configure.in.cursor fltk-1.3.2/configure.in +--- fltk-1.3.2/configure.in.cursor 2013-01-30 16:07:59.511320228 +0100 ++++ fltk-1.3.2/configure.in 2013-01-30 16:07:59.529319908 +0100 +@@ -1009,6 +1009,16 @@ case $uname_GUI in + LIBS="-lXfixes $LIBS") + fi + ++ dnl Check for the Xcursor library unless disabled... ++ AC_ARG_ENABLE(xcursor, [ --enable-xcursor turn on Xcursor support [default=yes]]) ++ ++ if test x$enable_xcursor != xno; then ++ AC_CHECK_HEADER(X11/Xcursor/Xcursor.h, AC_DEFINE(HAVE_XCURSOR),, ++ [#include ]) ++ AC_CHECK_LIB(Xcursor, XcursorImageCreate, ++ LIBS="-lXcursor $LIBS") ++ fi ++ + dnl Check for overlay visuals... + AC_PATH_PROG(XPROP, xprop) + AC_CACHE_CHECK(for X overlay visuals, ac_cv_have_overlay, +diff -up fltk-1.3.2/FL/Enumerations.H.cursor fltk-1.3.2/FL/Enumerations.H +--- fltk-1.3.2/FL/Enumerations.H.cursor 2013-01-30 16:07:59.486320673 +0100 ++++ fltk-1.3.2/FL/Enumerations.H 2013-01-30 16:07:59.530319891 +0100 +@@ -879,35 +879,36 @@ inline Fl_Color fl_color_cube(int r, int + + /** The following constants define the mouse cursors that are available in FLTK. + +- The double-headed arrows are bitmaps provided by FLTK on X, the others +- are provided by system-defined cursors. ++ Cursors are provided by the system when available, or bitmaps built into ++ FLTK as a fallback. + + \todo enum Fl_Cursor needs maybe an image. + */ + enum Fl_Cursor { + FL_CURSOR_DEFAULT = 0, /**< the default cursor, usually an arrow. */ +- FL_CURSOR_ARROW = 35, /**< an arrow pointer. */ +- FL_CURSOR_CROSS = 66, /**< crosshair. */ +- FL_CURSOR_WAIT = 76, /**< watch or hourglass. */ +- FL_CURSOR_INSERT = 77, /**< I-beam. */ +- FL_CURSOR_HAND = 31, /**< hand (uparrow on MSWindows). */ +- FL_CURSOR_HELP = 47, /**< question mark. */ +- FL_CURSOR_MOVE = 27, /**< 4-pointed arrow. */ +- // fltk provides bitmaps for these: +- FL_CURSOR_NS = 78, /**< up/down arrow. */ +- FL_CURSOR_WE = 79, /**< left/right arrow. */ +- FL_CURSOR_NWSE = 80, /**< diagonal arrow. */ +- FL_CURSOR_NESW = 81, /**< diagonal arrow. */ +- FL_CURSOR_NONE =255, /**< invisible. */ +- // for back compatibility (non MSWindows ones): +- FL_CURSOR_N = 70, /**< for back compatibility. */ +- FL_CURSOR_NE = 69, /**< for back compatibility. */ +- FL_CURSOR_E = 49, /**< for back compatibility. */ +- FL_CURSOR_SE = 8, /**< for back compatibility. */ +- FL_CURSOR_S = 9, /**< for back compatibility. */ +- FL_CURSOR_SW = 7, /**< for back compatibility. */ +- FL_CURSOR_W = 36, /**< for back compatibility. */ +- FL_CURSOR_NW = 68 /**< for back compatibility. */ ++ FL_CURSOR_ARROW = 1, /**< an arrow pointer. */ ++ FL_CURSOR_CROSS = 2, /**< crosshair. */ ++ FL_CURSOR_WAIT = 3, /**< busy indicator (e.g. hourglass). */ ++ FL_CURSOR_INSERT = 4, /**< I-beam. */ ++ FL_CURSOR_HAND = 5, /**< pointing hand. */ ++ FL_CURSOR_HELP = 6, /**< question mark pointer. */ ++ FL_CURSOR_MOVE = 7, /**< 4-pointed arrow or hand. */ ++ ++ /* Resize indicators */ ++ FL_CURSOR_NS = 101, /**< up/down resize. */ ++ FL_CURSOR_WE = 102, /**< left/right resize. */ ++ FL_CURSOR_NWSE = 103, /**< diagonal resize. */ ++ FL_CURSOR_NESW = 104, /**< diagonal resize. */ ++ FL_CURSOR_NE = 110, /**< upwards, right resize. */ ++ FL_CURSOR_N = 111, /**< upwards resize. */ ++ FL_CURSOR_NW = 112, /**< upwards, left resize. */ ++ FL_CURSOR_E = 113, /**< leftwards resize. */ ++ FL_CURSOR_W = 114, /**< rightwards resize. */ ++ FL_CURSOR_SE = 115, /**< downwards, right resize. */ ++ FL_CURSOR_S = 116, /**< downwards resize. */ ++ FL_CURSOR_SW = 117, /**< downwards, left resize. */ ++ ++ FL_CURSOR_NONE = 255, /**< invisible. */ + }; + /*@}*/ // group: Cursors + +diff -up fltk-1.3.2/FL/fl_draw.H.cursor fltk-1.3.2/FL/fl_draw.H +--- fltk-1.3.2/FL/fl_draw.H.cursor 2012-05-08 18:15:34.000000000 +0200 ++++ fltk-1.3.2/FL/fl_draw.H 2013-01-30 16:07:59.530319891 +0100 +@@ -751,7 +751,8 @@ FL_EXPORT const char* fl_shortcut_label( + FL_EXPORT unsigned int fl_old_shortcut(const char* s); + FL_EXPORT void fl_overlay_rect(int x,int y,int w,int h); + FL_EXPORT void fl_overlay_clear(); +-FL_EXPORT void fl_cursor(Fl_Cursor, Fl_Color fg=FL_BLACK, Fl_Color bg=FL_WHITE); ++FL_EXPORT void fl_cursor(Fl_Cursor); ++FL_EXPORT void fl_cursor(Fl_Cursor, Fl_Color fg, Fl_Color bg=FL_WHITE); + FL_EXPORT const char* fl_expand_text(const char* from, char* buf, int maxbuf, + double maxw, int& n, double &width, + int wrap, int draw_symbols = 0); +diff -up fltk-1.3.2/FL/Fl_Window.H.cursor fltk-1.3.2/FL/Fl_Window.H +--- fltk-1.3.2/FL/Fl_Window.H.cursor 2012-11-06 21:46:14.000000000 +0100 ++++ fltk-1.3.2/FL/Fl_Window.H 2013-01-30 16:07:59.531319873 +0100 +@@ -28,6 +28,7 @@ + #define FL_DOUBLE_WINDOW 0xF1 ///< double window type id + + class Fl_X; ++class Fl_RGB_Image; + + /** + This widget produces an actual window. This can either be a main +@@ -81,7 +82,6 @@ class FL_EXPORT Fl_Window : public Fl_Gr + uchar size_range_set; + // cursor stuff + Fl_Cursor cursor_default; +- Fl_Color cursor_fg, cursor_bg; + void size_range_(); + void _Fl_Window(); // constructor innards + void fullscreen_x(); // platform-specific part of sending a window to full screen +@@ -466,14 +466,17 @@ public: + is different. + + The type Fl_Cursor is an enumeration defined in . +- (Under X you can get any XC_cursor value by passing +- Fl_Cursor((XC_foo/2)+1)). The colors only work on X, they are +- not implemented on WIN32. + +- For back compatibility only. ++ \see cursor(const Fl_RGB_Image*, int, int), default_cursor() + */ +- void cursor(Fl_Cursor, Fl_Color=FL_BLACK, Fl_Color=FL_WHITE); // platform dependent +- void default_cursor(Fl_Cursor, Fl_Color=FL_BLACK, Fl_Color=FL_WHITE); ++ void cursor(Fl_Cursor); ++ void cursor(const Fl_RGB_Image*, int, int); ++ void default_cursor(Fl_Cursor); ++ ++ /* for legacy compatibility */ ++ void cursor(Fl_Cursor c, Fl_Color, Fl_Color=FL_WHITE); ++ void default_cursor(Fl_Cursor c, Fl_Color, Fl_Color=FL_WHITE); ++ + static void default_callback(Fl_Window*, void* v); + + /** Returns the window width including any frame added by the window manager. +diff -up fltk-1.3.2/FL/mac.H.cursor fltk-1.3.2/FL/mac.H +--- fltk-1.3.2/FL/mac.H.cursor 2012-11-13 15:45:42.000000000 +0100 ++++ fltk-1.3.2/FL/mac.H 2013-01-30 16:07:59.531319873 +0100 +@@ -120,7 +120,8 @@ public: + void collapse(void); + WindowRef window_ref(void); + void set_key_window(void); +- void set_cursor(Fl_Cursor); ++ int set_cursor(Fl_Cursor); ++ int set_cursor(const Fl_RGB_Image*, int, int); + static CGImageRef CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h); + static unsigned char *bitmap_from_window_rect(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel); + static Fl_Region intersect_region_and_rect(Fl_Region current, int x,int y,int w, int h); +diff -up fltk-1.3.2/FL/win32.H.cursor fltk-1.3.2/FL/win32.H +--- fltk-1.3.2/FL/win32.H.cursor 2012-03-12 12:55:50.000000000 +0100 ++++ fltk-1.3.2/FL/win32.H 2013-01-30 16:07:59.531319873 +0100 +@@ -73,6 +73,7 @@ public: + int wait_for_expose; + HDC private_dc; // used for OpenGL + HCURSOR cursor; ++ int custom_cursor; + HDC saved_hdc; // saves the handle of the DC currently loaded + // static variables, static functions and member functions + static Fl_X* first; +@@ -83,6 +84,8 @@ public: + void flush() {w->flush();} + void set_minmax(LPMINMAXINFO minmax); + void mapraise(); ++ int set_cursor(Fl_Cursor); ++ int set_cursor(const Fl_RGB_Image*, int, int); + static Fl_X* make(Fl_Window*); + }; + extern FL_EXPORT HCURSOR fl_default_cursor; +diff -up fltk-1.3.2/FL/x.H.cursor fltk-1.3.2/FL/x.H +--- fltk-1.3.2/FL/x.H.cursor 2012-03-23 17:47:53.000000000 +0100 ++++ fltk-1.3.2/FL/x.H 2013-01-30 16:07:59.532319855 +0100 +@@ -154,6 +154,8 @@ public: + static Fl_X* i(const Fl_Window* wi) {return wi->i;} + void setwindow(Fl_Window* wi) {w=wi; wi->i=this;} + void sendxjunk(); ++ int set_cursor(Fl_Cursor); ++ int set_cursor(const Fl_RGB_Image*, int, int); + static void make_xid(Fl_Window*,XVisualInfo* =fl_visual, Colormap=fl_colormap); + static Fl_X* set_xid(Fl_Window*, Window); + // kludges to get around protection: +diff -up fltk-1.3.2/src/CMakeLists.txt.cursor fltk-1.3.2/src/CMakeLists.txt +--- fltk-1.3.2/src/CMakeLists.txt.cursor 2013-01-30 16:09:11.981032475 +0100 ++++ fltk-1.3.2/src/CMakeLists.txt 2013-01-30 16:09:26.497774461 +0100 +@@ -247,6 +247,10 @@ if(HAVE_XFIXES) + target_link_libraries(fltk ${X11_Xfixes_LIB}) + endif(HAVE_XFIXES) + ++if(HAVE_XCURSOR) ++ target_link_libraries(fltk ${X11_Xcursor_LIB}) ++endif(HAVE_XCURSOR) ++ + if(USE_XFT) + target_link_libraries(fltk ${X11_Xft_LIB}) + endif(USE_XFT) +diff -up fltk-1.3.2/src/Fl_cocoa.mm.cursor fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2/src/Fl_cocoa.mm.cursor 2013-01-30 16:07:59.522320033 +0100 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2013-01-30 16:07:59.533319837 +0100 +@@ -98,7 +98,6 @@ Fl_Display_Device *Fl_Display_Device::_d + CGContextRef fl_gc = 0; + void *fl_system_menu; // this is really a NSMenu* + Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0; +-void *fl_default_cursor; // this is really a NSCursor* + void *fl_capture = 0; // (NSWindow*) we need this to compensate for a missing(?) mouse capture + bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state + //int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR +@@ -1392,8 +1391,6 @@ void fl_open_display() { + dequeue:YES]; + while (ign_event); + +- fl_default_cursor = [NSCursor arrowCursor]; +- + // bring the application into foreground without a 'CARB' resource + Boolean same_psn; + ProcessSerialNumber cur_psn, front_psn; +@@ -1698,6 +1695,7 @@ static void q_set_window_title(NSWindow + - (void)drawRect:(NSRect)rect; + - (BOOL)acceptsFirstResponder; + - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; ++- (void)resetCursorRects; + - (BOOL)performKeyEquivalent:(NSEvent*)theEvent; + - (void)mouseUp:(NSEvent *)theEvent; + - (void)rightMouseUp:(NSEvent *)theEvent; +@@ -1756,6 +1754,16 @@ static void q_set_window_title(NSWindow + Fl_Window *first = Fl::first_window(); + return (first == w || !first->modal()); + } ++- (void)resetCursorRects { ++ Fl_Window *w = [(FLWindow*)[self window] getFl_Window]; ++ Fl_X *i = Fl_X::i(w); ++ // We have to have at least one cursor rect for invalidateCursorRectsForView ++ // to work, hence the "else" clause. ++ if (i->cursor) ++ [self addCursorRect:[self visibleRect] cursor:(NSCursor*)i->cursor]; ++ else ++ [self addCursorRect:[self visibleRect] cursor:[NSCursor arrowCursor]]; ++} + - (void)mouseUp:(NSEvent *)theEvent { + cocoaMouseHandler(theEvent); + } +@@ -2331,7 +2339,7 @@ void Fl_X::make(Fl_Window* w) + x->other_xid = 0; + x->region = 0; + x->subRegion = 0; +- x->cursor = fl_default_cursor; ++ x->cursor = NULL; + x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz + Fl_Window *win = w->window(); + Fl_X *xo = Fl_X::i(win); +@@ -2427,7 +2435,7 @@ void Fl_X::make(Fl_Window* w) + x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows + x->region = 0; + x->subRegion = 0; +- x->cursor = fl_default_cursor; ++ x->cursor = NULL; + x->xidChildren = 0; + x->xidNext = 0; + x->gc = 0; +@@ -2974,6 +2982,10 @@ void Fl_X::map() { + Fl_X::relink(w, w->window() ); + w->redraw(); + } ++ if (cursor) { ++ [(NSCursor*)cursor release]; ++ cursor = NULL; ++ } + } + + void Fl_X::unmap() { +@@ -3078,68 +3090,106 @@ static NSImage *CGBitmapContextToNSImage + return [image autorelease]; + } + +-static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() ) ++int Fl_X::set_cursor(Fl_Cursor c) + { +- if (cursor == nil) { +- CGContextRef c = f(); +- NSImage *image = CGBitmapContextToNSImage(c); +- fl_delete_offscreen( (Fl_Offscreen)c ); +- NSPoint pt = {[image size].width/2, [image size].height/2}; +- cursor = [[NSCursor alloc] initWithImage:image hotSpot:pt]; ++ if (cursor) { ++ [(NSCursor*)cursor release]; ++ cursor = NULL; + } +- return cursor; +-} + +-void Fl_X::set_cursor(Fl_Cursor c) +-{ +- NSCursor *icrsr; + switch (c) { +- case FL_CURSOR_CROSS: icrsr = [NSCursor crosshairCursor]; break; +- case FL_CURSOR_WAIT: +- static NSCursor *watch = nil; +- watch = PrepareCursor(watch, &Fl_X::watch_cursor_image); +- icrsr = watch; +- break; +- case FL_CURSOR_INSERT: icrsr = [NSCursor IBeamCursor]; break; +- case FL_CURSOR_N: icrsr = [NSCursor resizeUpCursor]; break; +- case FL_CURSOR_S: icrsr = [NSCursor resizeDownCursor]; break; +- case FL_CURSOR_NS: icrsr = [NSCursor resizeUpDownCursor]; break; +- case FL_CURSOR_HELP: +- static NSCursor *help = nil; +- help = PrepareCursor(help, &Fl_X::help_cursor_image); +- icrsr = help; +- break; +- case FL_CURSOR_HAND: icrsr = [NSCursor pointingHandCursor]; break; +- case FL_CURSOR_MOVE: icrsr = [NSCursor openHandCursor]; break; +- case FL_CURSOR_NE: +- case FL_CURSOR_SW: +- case FL_CURSOR_NESW: +- static NSCursor *nesw = nil; +- nesw = PrepareCursor(nesw, &Fl_X::nesw_cursor_image); +- icrsr = nesw; +- break; +- case FL_CURSOR_E: icrsr = [NSCursor resizeRightCursor]; break; +- case FL_CURSOR_W: icrsr = [NSCursor resizeLeftCursor]; break; +- case FL_CURSOR_WE: icrsr = [NSCursor resizeLeftRightCursor]; break; +- case FL_CURSOR_SE: +- case FL_CURSOR_NW: +- case FL_CURSOR_NWSE: +- static NSCursor *nwse = nil; +- nwse = PrepareCursor(nwse, &Fl_X::nwse_cursor_image); +- icrsr = nwse; +- break; +- case FL_CURSOR_NONE: +- static NSCursor *none = nil; +- none = PrepareCursor(none, &Fl_X::none_cursor_image); +- icrsr = none; +- break; +- case FL_CURSOR_ARROW: +- case FL_CURSOR_DEFAULT: +- default: icrsr = [NSCursor arrowCursor]; +- break; ++ case FL_CURSOR_ARROW: cursor = [NSCursor arrowCursor]; break; ++ case FL_CURSOR_CROSS: cursor = [NSCursor crosshairCursor]; break; ++ case FL_CURSOR_INSERT: cursor = [NSCursor IBeamCursor]; break; ++ case FL_CURSOR_HAND: cursor = [NSCursor pointingHandCursor]; break; ++ case FL_CURSOR_MOVE: cursor = [NSCursor openHandCursor]; break; ++ case FL_CURSOR_NS: cursor = [NSCursor resizeUpDownCursor]; break; ++ case FL_CURSOR_WE: cursor = [NSCursor resizeLeftRightCursor]; break; ++ case FL_CURSOR_N: cursor = [NSCursor resizeUpCursor]; break; ++ case FL_CURSOR_E: cursor = [NSCursor resizeRightCursor]; break; ++ case FL_CURSOR_W: cursor = [NSCursor resizeLeftCursor]; break; ++ case FL_CURSOR_S: cursor = [NSCursor resizeDownCursor]; break; ++ default: ++ return 0; ++ } ++ ++ [(NSCursor*)cursor retain]; ++ ++ [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]]; ++ ++ return 1; ++} ++ ++int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++ if (cursor) { ++ [(NSCursor*)cursor release]; ++ cursor = NULL; ++ } ++ ++ if ((hotx < 0) || (hotx >= image->w())) ++ return 0; ++ if ((hoty < 0) || (hoty >= image->h())) ++ return 0; ++ ++ // OS X >= 10.6 can create a NSImage from a CGImage, but we need to ++ // support older versions, hence this pesky handling. ++ ++ NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] ++ initWithBitmapDataPlanes:NULL ++ pixelsWide:image->w() ++ pixelsHigh:image->h() ++ bitsPerSample:8 ++ samplesPerPixel:image->d() ++ hasAlpha:!(image->d() & 1) ++ isPlanar:NO ++ colorSpaceName:(image->d()<=2) ? NSDeviceWhiteColorSpace : NSDeviceRGBColorSpace ++ bytesPerRow:(image->w() * image->d()) ++ bitsPerPixel:(image->d()*8)]; ++ ++ // Alpha needs to be premultiplied for this format ++ ++ const uchar *i = (const uchar*)*image->data(); ++ unsigned char *o = [bitmap bitmapData]; ++ for (int y = 0;y < image->h();y++) { ++ if (image->d() & 1) { ++ for (int x = 0;x < image->w();x++) { ++ unsigned int alpha; ++ if (image->d() == 4) { ++ alpha = i[3]; ++ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); ++ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); ++ } ++ ++ alpha = i[1]; ++ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255); ++ *o++ = alpha; ++ i++; ++ } ++ } else { ++ // No alpha, so we can just copy everything directly. ++ int len = image->w() * image->d(); ++ memcpy(o, i, len); ++ o += len; ++ i += len; ++ } ++ i += image->ld(); + } +- [icrsr set]; +- cursor = icrsr; ++ ++ NSImage *nsimage = [[NSImage alloc] ++ initWithSize:NSMakeSize(image->w(), image->h())]; ++ ++ [nsimage addRepresentation:bitmap]; ++ ++ cursor = [[NSCursor alloc] ++ initWithImage:nsimage ++ hotSpot:NSMakePoint(hotx, hoty)]; ++ ++ [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]]; ++ ++ [bitmap release]; ++ [nsimage release]; ++ ++ return 1; + } + + @interface FLaboutItemTarget : NSObject +diff -up fltk-1.3.2/src/fl_cursor.cxx.cursor fltk-1.3.2/src/fl_cursor.cxx +--- fltk-1.3.2/src/fl_cursor.cxx.cursor 2012-03-12 12:55:50.000000000 +0100 ++++ fltk-1.3.2/src/fl_cursor.cxx 2013-01-30 16:07:59.534319820 +0100 +@@ -24,297 +24,165 @@ + + #include + #include ++#include ++#include + #include +-#if !defined(WIN32) && !defined(__APPLE__) +-# include +-#endif + #include + ++#include "fl_cursor_wait.xpm" ++#include "fl_cursor_help.xpm" ++#include "fl_cursor_nwse.xpm" ++#include "fl_cursor_nesw.xpm" ++#include "fl_cursor_none.xpm" ++ + /** + Sets the cursor for the current window to the specified shape and colors. + The cursors are defined in the header file. + */ ++void fl_cursor(Fl_Cursor c) { ++ if (Fl::first_window()) Fl::first_window()->cursor(c); ++} ++ ++/* For back compatibility only. */ + void fl_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { +- if (Fl::first_window()) Fl::first_window()->cursor(c,fg,bg); ++ fl_cursor(c); + } ++ ++ + /** +- Sets the default window cursor as well as its color. ++ Sets the default window cursor. This is the cursor that will be used ++ after the mouse pointer leaves a widget with a custom cursor set. + +- For back compatibility only. ++ \see cursor(const Fl_RGB_Image*, int, int), default_cursor() + */ +-void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { +-// if (c == FL_CURSOR_DEFAULT) c = FL_CURSOR_ARROW; +- ++void Fl_Window::default_cursor(Fl_Cursor c) { + cursor_default = c; +- cursor_fg = fg; +- cursor_bg = bg; ++ cursor(c); ++} ++ ++ ++void fallback_cursor(Fl_Window *w, Fl_Cursor c) { ++ const char **xpm; ++ int hotx, hoty; ++ ++ // The standard arrow is our final fallback, so something is broken ++ // if we get called back here with that as an argument. ++ if (c == FL_CURSOR_ARROW) ++ return; ++ ++ switch (c) { ++ case FL_CURSOR_WAIT: ++ xpm = (const char**)fl_cursor_wait_xpm; ++ hotx = 8; ++ hoty = 15; ++ break; ++ case FL_CURSOR_HELP: ++ xpm = (const char**)fl_cursor_help_xpm; ++ hotx = 1; ++ hoty = 3; ++ break; ++ case FL_CURSOR_NWSE: ++ xpm = (const char**)fl_cursor_nwse_xpm; ++ hotx = 7; ++ hoty = 7; ++ break; ++ case FL_CURSOR_NESW: ++ xpm = (const char**)fl_cursor_nesw_xpm; ++ hotx = 7; ++ hoty = 7; ++ break; ++ case FL_CURSOR_NONE: ++ xpm = (const char**)fl_cursor_none_xpm; ++ hotx = 0; ++ hoty = 0; ++ break; ++ default: ++ w->cursor(FL_CURSOR_ARROW); ++ return; ++ } + +- cursor(c, fg, bg); ++ Fl_Pixmap pxm(xpm); ++ Fl_RGB_Image image(&pxm); ++ ++ w->cursor(&image, hotx, hoty); + } + +-#ifdef WIN32 + +-# ifndef IDC_HAND +-# define IDC_HAND MAKEINTRESOURCE(32649) +-# endif // !IDC_HAND ++void Fl_Window::cursor(Fl_Cursor c) { ++ int ret; + +-void Fl_Window::cursor(Fl_Cursor c, Fl_Color c1, Fl_Color c2) { +- if (!shown()) return; + // the cursor must be set for the top level window, not for subwindows + Fl_Window *w = window(), *toplevel = this; +- while (w) { toplevel = w; w = w->window(); } +- if (toplevel != this) { toplevel->cursor(c, c1, c2); return; } +- // now set the actual cursor +- if (c == FL_CURSOR_DEFAULT) { +- c = cursor_default; +- } +- if (c > FL_CURSOR_NESW) { +- i->cursor = 0; +- } else if (c == FL_CURSOR_DEFAULT) { +- i->cursor = fl_default_cursor; +- } else { +- LPSTR n; +- switch (c) { +- case FL_CURSOR_ARROW: n = IDC_ARROW; break; +- case FL_CURSOR_CROSS: n = IDC_CROSS; break; +- case FL_CURSOR_WAIT: n = IDC_WAIT; break; +- case FL_CURSOR_INSERT: n = IDC_IBEAM; break; +- case FL_CURSOR_HELP: n = IDC_HELP; break; +- case FL_CURSOR_HAND: { +- OSVERSIONINFO osvi; +- +- // Get the OS version: Windows 98 and 2000 have a standard +- // hand cursor. +- memset(&osvi, 0, sizeof(OSVERSIONINFO)); +- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); +- GetVersionEx(&osvi); +- +- if (osvi.dwMajorVersion > 4 || +- (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion > 0 && +- osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) n = IDC_HAND; +- else n = IDC_UPARROW; +- } break; +- case FL_CURSOR_MOVE: n = IDC_SIZEALL; break; +- case FL_CURSOR_N: +- case FL_CURSOR_S: +- case FL_CURSOR_NS: n = IDC_SIZENS; break; +- case FL_CURSOR_NE: +- case FL_CURSOR_SW: +- case FL_CURSOR_NESW: n = IDC_SIZENESW; break; +- case FL_CURSOR_E: +- case FL_CURSOR_W: +- case FL_CURSOR_WE: n = IDC_SIZEWE; break; +- case FL_CURSOR_SE: +- case FL_CURSOR_NW: +- case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break; +- default: n = IDC_NO; break; +- } +- i->cursor = LoadCursor(NULL, n); ++ ++ while (w) { ++ toplevel = w; ++ w = w->window(); + } +- SetCursor(i->cursor); +-} + +-#elif defined(__APPLE__) ++ if (toplevel != this) { ++ toplevel->cursor(c); ++ return; ++ } + +-#ifdef __BIG_ENDIAN__ +-# define E(x) x +-#elif defined __LITTLE_ENDIAN__ +-// Don't worry. This will be resolved at compile time +-# define E(x) (x>>8)|((x<<8)&0xff00) +-#else +-# error "Either __LITTLE_ENDIAN__ or __BIG_ENDIAN__ must be defined" +-#endif +- +-CGContextRef Fl_X::help_cursor_image(void) +-{ +- int w = 20, h = 20; +- Fl_Offscreen off = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h); +- fl_begin_offscreen(off); +- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0); +- fl_rectf(0,0,w,h); +- fl_color(FL_BLACK); +- fl_font(FL_COURIER_BOLD, 20); +- fl_draw("?", 1, h-1); +- fl_end_offscreen(); +- return (CGContextRef)off; +-} ++ if (c == FL_CURSOR_DEFAULT) ++ c = cursor_default; + +-CGContextRef Fl_X::none_cursor_image(void) +-{ +- int w = 20, h = 20; +- Fl_Offscreen off = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h); +- fl_begin_offscreen(off); +- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0); +- fl_rectf(0,0,w,h); +- fl_end_offscreen(); +- return (CGContextRef)off; +-} ++ if (!i) ++ return; + +-CGContextRef Fl_X::watch_cursor_image(void) +-{ +- int w, h, r = 5; +- w = 2*r+6; +- h = 4*r; +- Fl_Offscreen off = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h); +- fl_begin_offscreen(off); +- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0); +- fl_rectf(0,0,w,h); +- CGContextTranslateCTM( (CGContextRef)off, w/2, h/2); +- fl_color(FL_WHITE); +- fl_circle(0, 0, r+1); +- fl_color(FL_BLACK); +- fl_rectf(int(-r*0.7), int(-r*1.7), int(1.4*r), int(3.4*r)); +- fl_rectf(r-1, -1, 3, 3); +- fl_color(FL_WHITE); +- fl_pie(-r, -r, 2*r, 2*r, 0, 360); +- fl_color(FL_BLACK); +- fl_circle(0,0,r); +- fl_xyline(0, 0, int(-r*.7)); +- fl_xyline(0, 0, 0, int(-r*.7)); +- fl_end_offscreen(); +- return (CGContextRef)off; +-} ++ ret = i->set_cursor(c); ++ if (ret) ++ return; + +-CGContextRef Fl_X::nesw_cursor_image(void) +-{ +- int c = 7, r = 2*c; +- int w = r, h = r; +- Fl_Offscreen off = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h); +- fl_begin_offscreen(off); +- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0); +- fl_rectf(0,0,w,h); +- CGContextTranslateCTM( (CGContextRef)off, 0, h); +- CGContextScaleCTM( (CGContextRef)off, 1, -1); +- fl_color(FL_BLACK); +- fl_polygon(0, 0, c, 0, 0, c); +- fl_polygon(r, r, r, r-c, r-c, r); +- fl_line_style(FL_SOLID, 2, 0); +- fl_line(0,1, r,r+1); +- fl_line_style(FL_SOLID, 0, 0); +- fl_end_offscreen(); +- return (CGContextRef)off; ++ fallback_cursor(this, c); + } + +-CGContextRef Fl_X::nwse_cursor_image(void) +-{ +- int c = 7, r = 2*c; +- int w = r, h = r; +- Fl_Offscreen off = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h); +- fl_begin_offscreen(off); +- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0); +- fl_rectf(0,0,w,h); +- CGContextTranslateCTM( (CGContextRef)off, 0, h); +- CGContextScaleCTM( (CGContextRef)off, 1, -1); +- fl_color(FL_BLACK); +- fl_polygon(r-1, 0, r-1, c, r-1-c, 0); +- fl_polygon(-1, r, c-1, r, -1, r-c); +- fl_line_style(FL_SOLID, 2, 0); +- fl_line(r-1,1, -1,r+1); +- fl_line_style(FL_SOLID, 0, 0); +- fl_end_offscreen(); +- return (CGContextRef)off; +-} +- +-void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) { +- if (c == FL_CURSOR_DEFAULT) { +- c = cursor_default; +- } +- if (i) i->set_cursor(c); +-} ++/** ++ Changes the cursor for this window. This always calls the system, if ++ you are changing the cursor a lot you may want to keep track of how ++ you set it in a static variable and call this only if the new cursor ++ is different. + +-#else ++ The default cursor will be used if the provided image cannot be used ++ as a cursor. + +-// I like the MSWindows resize cursors, so I duplicate them here: ++ \see cursor(Fl_Cursor), default_cursor() ++*/ ++void Fl_Window::cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++ int ret; + +-#define CURSORSIZE 16 +-#define HOTXY 7 +-static struct TableEntry { +- uchar bits[CURSORSIZE*CURSORSIZE/8]; +- uchar mask[CURSORSIZE*CURSORSIZE/8]; +- Cursor cursor; +-} table[] = { +- {{ // FL_CURSOR_NS +- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01, +- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, +- 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00}, +- { +- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xc0, 0x03, +- 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xf0, 0x0f, +- 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}}, +- {{ // FL_CURSOR_EW +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, +- 0x0c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0x0c, 0x30, 0x08, 0x10, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +- { +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1c, 0x38, +- 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, +- {{ // FL_CURSOR_NWSE +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x38, 0x00, 0x78, 0x00, +- 0xe8, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1c, +- 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +- { +- 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0xfc, 0x00, +- 0xfc, 0x01, 0xec, 0x03, 0xc0, 0x37, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x3e, +- 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00}}, +- {{ // FL_CURSOR_NESW +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1e, +- 0x00, 0x17, 0x80, 0x03, 0xc0, 0x01, 0xe8, 0x00, 0x78, 0x00, 0x38, 0x00, +- 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +- { +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3f, +- 0x80, 0x3f, 0xc0, 0x37, 0xec, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0x7c, 0x00, +- 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}}, +- {{0}, {0}} // FL_CURSOR_NONE & unknown +-}; ++ // the cursor must be set for the top level window, not for subwindows ++ Fl_Window *w = window(), *toplevel = this; + +-void Fl_Window::cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { +- if (!shown()) return; +- Cursor xc; +- int deleteit = 0; +- if (c == FL_CURSOR_DEFAULT) { +- c = cursor_default; +- fg = cursor_fg; +- bg = cursor_bg; ++ while (w) { ++ toplevel = w; ++ w = w->window(); + } + +- if (!c) { +- xc = None; +- } else { +- if (c >= FL_CURSOR_NS) { +- TableEntry *q = (c > FL_CURSOR_NESW) ? table+4 : table+(c-FL_CURSOR_NS); +- if (!(q->cursor)) { +- XColor dummy = { 0 }; +- Pixmap p = XCreateBitmapFromData(fl_display, +- RootWindow(fl_display, fl_screen), (const char*)(q->bits), +- CURSORSIZE, CURSORSIZE); +- Pixmap m = XCreateBitmapFromData(fl_display, +- RootWindow(fl_display, fl_screen), (const char*)(q->mask), +- CURSORSIZE, CURSORSIZE); +- q->cursor = XCreatePixmapCursor(fl_display, p,m,&dummy, &dummy, +- HOTXY, HOTXY); +- XFreePixmap(fl_display, m); +- XFreePixmap(fl_display, p); +- } +- xc = q->cursor; +- } else { +- xc = XCreateFontCursor(fl_display, (c-1)*2); +- deleteit = 1; +- } +- XColor fgc; +- uchar r,g,b; +- Fl::get_color(fg,r,g,b); +- fgc.red = r<<8; fgc.green = g<<8; fgc.blue = b<<8; +- XColor bgc; +- Fl::get_color(bg,r,g,b); +- bgc.red = r<<8; bgc.green = g<<8; bgc.blue = b<<8; +- XRecolorCursor(fl_display, xc, &fgc, &bgc); ++ if (toplevel != this) { ++ toplevel->cursor(image, hotx, hoty); ++ return; + } +- XDefineCursor(fl_display, fl_xid(this), xc); +- if (deleteit) XFreeCursor(fl_display, xc); ++ ++ if (!i) ++ return; ++ ++ ret = i->set_cursor(image, hotx, hoty); ++ if (ret) ++ return; ++ ++ cursor(FL_CURSOR_DEFAULT); + } + +-#endif ++/* For back compatibility only. */ ++void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) { ++ cursor(c); ++}; ++ ++void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color, Fl_Color) { ++ default_cursor(c); ++}; ++ + + // + // End of "$Id: fl_cursor.cxx 9278 2012-03-12 11:55:50Z manolo $". +diff -up fltk-1.3.2/src/fl_cursor_help.xpm.cursor fltk-1.3.2/src/fl_cursor_help.xpm +--- fltk-1.3.2/src/fl_cursor_help.xpm.cursor 2013-01-30 16:07:59.534319820 +0100 ++++ fltk-1.3.2/src/fl_cursor_help.xpm 2013-01-30 16:07:59.534319820 +0100 +@@ -0,0 +1,95 @@ ++/* XPM */ ++static const char * fl_cursor_help_xpm[] = { ++"16 27 65 1", ++" c None", ++". c #FFFFFF", ++"+ c #E2E2E2", ++"@ c #1C1C1C", ++"# c #E7E7E7", ++"$ c #000000", ++"% c #212121", ++"& c #EAEAEA", ++"* c #262626", ++"= c #EDEDED", ++"- c #2C2C2C", ++"; c #F0F0F0", ++"> c #333333", ++", c #F1F1F1", ++"' c #393939", ++") c #F3F3F3", ++"! c #404040", ++"~ c #484848", ++"{ c #F4F4F4", ++"] c #050505", ++"^ c #202020", ++"/ c #707070", ++"( c #F5F5F5", ++"_ c #040404", ++": c #E1E1E1", ++"< c #EEEEEE", ++"[ c #EFEFEF", ++"} c #FEFEFE", ++"| c #3D3D3D", ++"1 c #7E7E7E", ++"2 c #696969", ++"3 c #414141", ++"4 c #131313", ++"5 c #080808", ++"6 c #454545", ++"7 c #F2F2F2", ++"8 c #878787", ++"9 c #7D7D7D", ++"0 c #101010", ++"a c #111111", ++"b c #FDFDFD", ++"c c #8A8A8A", ++"d c #E6E6E6", ++"e c #7B7B7B", ++"f c #4C4C4C", ++"g c #5C5C5C", ++"h c #9F9F9F", ++"i c #F9F9F9", ++"j c #F7F7F7", ++"k c #B1B1B1", ++"l c #2E2E2E", ++"m c #767676", ++"n c #DCDCDC", ++"o c #DEDEDE", ++"p c #C7C7C7", ++"q c #1B1B1B", ++"r c #6B6B6B", ++"s c #575757", ++"t c #797979", ++"u c #020202", ++"v c #010101", ++"w c #FBFBFB", ++"x c #D7D7D7", ++"y c #D8D8D8", ++"z c #060606", ++" ", ++". ", ++".+ ", ++".@# ", ++".$%& ", ++".$$*= ", ++".$$$-; ", ++".$$$$>, ", ++".$$$$$') ", ++".$$$$$$!) ", ++".$$$$$$$~{ ", ++".$$$$]^^^/( ", ++".$$$$_:(<<[} ", ++".$$|1$2< ", ++".$3,(45[ ", ++".67 78$9, ", ++".7 {0a( .... ", ++"b ,c5[defgh, ", ++" )ijk_la$m.", ++" no.p$q.", ++" .r$s.", ++" .t$-= ", ++" 7uv+ ", ++" wxy. ", ++" :$z. ", ++" :$z. ", ++" .... "}; +diff -up fltk-1.3.2/src/fl_cursor_nesw.xpm.cursor fltk-1.3.2/src/fl_cursor_nesw.xpm +--- fltk-1.3.2/src/fl_cursor_nesw.xpm.cursor 2013-01-30 16:07:59.534319820 +0100 ++++ fltk-1.3.2/src/fl_cursor_nesw.xpm 2013-01-30 16:07:59.534319820 +0100 +@@ -0,0 +1,46 @@ ++/* XPM */ ++static const char * fl_cursor_nesw_xpm[] = { ++"15 15 28 1", ++" c None", ++". c #FFFFFF", ++"+ c #767676", ++"@ c #000000", ++"# c #4E4E4E", ++"$ c #0C0C0C", ++"% c #494949", ++"& c #4D4D4D", ++"* c #1B1B1B", ++"= c #515151", ++"- c #646464", ++"; c #363636", ++"> c #6A6A6A", ++", c #545454", ++"' c #585858", ++") c #242424", ++"! c #797979", ++"~ c #2E2E2E", ++"{ c #444444", ++"] c #3B3B3B", ++"^ c #0A0A0A", ++"/ c #595959", ++"( c #F7F7F7", ++"_ c #080808", ++": c #6B6B6B", ++"< c #FDFDFD", ++"[ c #FCFCFC", ++"} c #FEFEFE", ++" ..........", ++" .+@@@@@@.", ++" .#@@@@@.", ++" .$@@@@.", ++" .%@@@@@.", ++". .&@@@*@@.", ++".. .=@@@-.;@.", ++".>. .,@@@'. .).", ++".@!.'@@@#. ..", ++".@@~@@@{. .", ++".@@@@@]. ", ++".@@@@^. ", ++".@@@@@/( ", ++".______:( ", ++"<[[[[[[[[} "}; +diff -up fltk-1.3.2/src/fl_cursor_none.xpm.cursor fltk-1.3.2/src/fl_cursor_none.xpm +--- fltk-1.3.2/src/fl_cursor_none.xpm.cursor 2013-01-30 16:07:59.534319820 +0100 ++++ fltk-1.3.2/src/fl_cursor_none.xpm 2013-01-30 16:07:59.534319820 +0100 +@@ -0,0 +1,19 @@ ++/* XPM */ ++static const char * fl_cursor_none_xpm[] = { ++"15 15 1 1", ++" c None", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" ", ++" "}; +diff -up fltk-1.3.2/src/fl_cursor_nwse.xpm.cursor fltk-1.3.2/src/fl_cursor_nwse.xpm +--- fltk-1.3.2/src/fl_cursor_nwse.xpm.cursor 2013-01-30 16:07:59.534319820 +0100 ++++ fltk-1.3.2/src/fl_cursor_nwse.xpm 2013-01-30 16:07:59.535319802 +0100 +@@ -0,0 +1,46 @@ ++/* XPM */ ++static const char * fl_cursor_nwse_xpm[] = { ++"15 15 28 1", ++" c None", ++". c #FFFFFF", ++"+ c #000000", ++"@ c #767676", ++"# c #4E4E4E", ++"$ c #0C0C0C", ++"% c #494949", ++"& c #1B1B1B", ++"* c #4D4D4D", ++"= c #363636", ++"- c #646464", ++"; c #515151", ++"> c #242424", ++", c #585858", ++"' c #545454", ++") c #6A6A6A", ++"! c #797979", ++"~ c #444444", ++"{ c #2E2E2E", ++"] c #3B3B3B", ++"^ c #0A0A0A", ++"/ c #F7F7F7", ++"( c #595959", ++"_ c #6B6B6B", ++": c #080808", ++"< c #FEFEFE", ++"[ c #FCFCFC", ++"} c #FDFDFD", ++".......... ", ++".++++++@. ", ++".+++++#. ", ++".++++$. ", ++".+++++%. ", ++".++&+++*. .", ++".+=.-+++;. ..", ++".>. .,+++'. .).", ++".. .#+++,.!+.", ++". .~+++{++.", ++" .]+++++.", ++" .^++++.", ++" /(+++++.", ++" /_::::::.", ++" <[[[[[[[[}"}; +diff -up fltk-1.3.2/src/fl_cursor_wait.xpm.cursor fltk-1.3.2/src/fl_cursor_wait.xpm +--- fltk-1.3.2/src/fl_cursor_wait.xpm.cursor 2013-01-30 16:07:59.535319802 +0100 ++++ fltk-1.3.2/src/fl_cursor_wait.xpm 2013-01-30 16:07:59.535319802 +0100 +@@ -0,0 +1,72 @@ ++/* XPM */ ++static const char * fl_cursor_wait_xpm[] = { ++"17 32 37 1", ++" c None", ++". c #FFFFFF", ++"+ c #2E2E2E", ++"@ c #202020", ++"# c #F1F1F1", ++"$ c #2D2D2D", ++"% c #000000", ++"& c #EDEDED", ++"* c #585858", ++"= c #575757", ++"- c #FBFBFB", ++"; c #848484", ++"> c #B8B8B8", ++", c #E5E5E5", ++"' c #F7F7F7", ++") c #181818", ++"! c #F0F0F0", ++"~ c #616161", ++"{ c #B7B7B7", ++"] c #F5F5F5", ++"^ c #050505", ++"/ c #D4D4D4", ++"( c #EEEEEE", ++"_ c #595959", ++": c #7B7B7B", ++"< c #E9E9E9", ++"[ c #131313", ++"} c #E3E3E3", ++"| c #767676", ++"1 c #505050", ++"2 c #F3F3F3", ++"3 c #2A2A2A", ++"4 c #070707", ++"5 c #343434", ++"6 c #939393", ++"7 c #191919", ++"8 c #6A6A6A", ++".................", ++".+@@@@@@@@@@@@@+.", ++".................", ++" #$%%%%%%%%%%%$# ", ++" &*%%%%%%%%%%%=& ", ++" -;%%%%%%%%%%%;- ", ++" >%%%%%%%%%%%> ", ++" ,%%%%%%%%%%%, ", ++" ')%%%%%%%%%)' ", ++" !~%%%%%%%%%~! ", ++" {%%%%%%%%%{ ", ++" ]^/...../^] ", ++" (_:.....:_( ", ++" <[}...}[< ", ++" !|1...1|! ", ++" 2[3.3[2 ", ++" 2[%.%[2 ", ++" !|%%.%%|! ", ++" <4%%.%%4< ", ++" (_%%%.%%%_( ", ++" ]^%%%.%%%^] ", ++" {%%%%.%%%%{ ", ++" !~%%%%.%%%%~! ", ++" ')%%%%.%%%%)' ", ++" ,%%56{.{65%%, ", ++" >%*.......*%> ", ++" -;7&.......&7;- ", ++" &*8.........8=& ", ++" #$%%%%%%%%%%%$# ", ++".................", ++".+@@@@@@@@@@@@@+.", ++"................."}; +diff -up fltk-1.3.2/src/Fl_win32.cxx.cursor fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2/src/Fl_win32.cxx.cursor 2013-01-30 16:07:59.519320086 +0100 ++++ fltk-1.3.2/src/Fl_win32.cxx 2013-01-30 16:07:59.536319784 +0100 +@@ -1633,7 +1633,6 @@ void fl_fix_focus(); // in Fl.cxx + + char fl_show_iconic; // hack for Fl_Window::iconic() + // int fl_background_pixel = -1; // color to use for background +-HCURSOR fl_default_cursor; + UINT fl_wake_msg = 0; + int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR + +@@ -1682,7 +1681,7 @@ Fl_X* Fl_X::make(Fl_Window* w) { + if (!w->icon()) + w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); + wcw.hIcon = wcw.hIconSm = (HICON)w->icon(); +- wcw.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); ++ wcw.hCursor = LoadCursor(NULL, IDC_ARROW); + //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); + //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); + wcw.hbrBackground = NULL; +@@ -1774,7 +1773,8 @@ Fl_X* Fl_X::make(Fl_Window* w) { + x->setwindow(w); + x->region = 0; + x->private_dc = 0; +- x->cursor = fl_default_cursor; ++ x->cursor = LoadCursor(NULL, IDC_ARROW); ++ x->custom_cursor = 0; + if (!fl_codepage) fl_get_codepage(); + + WCHAR *lab = NULL; +@@ -2025,6 +2025,153 @@ void Fl_Window::label(const char *name,c + } + + //////////////////////////////////////////////////////////////// ++ ++#ifndef IDC_HAND ++# define IDC_HAND MAKEINTRESOURCE(32649) ++#endif // !IDC_HAND ++ ++int Fl_X::set_cursor(Fl_Cursor c) { ++ LPSTR n; ++ HCURSOR new_cursor; ++ ++ if (c == FL_CURSOR_NONE) ++ new_cursor = NULL; ++ else { ++ switch (c) { ++ case FL_CURSOR_ARROW: n = IDC_ARROW; break; ++ case FL_CURSOR_CROSS: n = IDC_CROSS; break; ++ case FL_CURSOR_WAIT: n = IDC_WAIT; break; ++ case FL_CURSOR_INSERT: n = IDC_IBEAM; break; ++ case FL_CURSOR_HAND: n = IDC_HAND; break; ++ case FL_CURSOR_HELP: n = IDC_HELP; break; ++ case FL_CURSOR_MOVE: n = IDC_SIZEALL; break; ++ case FL_CURSOR_N: ++ case FL_CURSOR_S: ++ // FIXME: Should probably have fallbacks for these instead ++ case FL_CURSOR_NS: n = IDC_SIZENS; break; ++ case FL_CURSOR_NE: ++ case FL_CURSOR_SW: ++ // FIXME: Dito. ++ case FL_CURSOR_NESW: n = IDC_SIZENESW; break; ++ case FL_CURSOR_E: ++ case FL_CURSOR_W: ++ // FIXME: Dito. ++ case FL_CURSOR_WE: n = IDC_SIZEWE; break; ++ case FL_CURSOR_SE: ++ case FL_CURSOR_NW: ++ // FIXME: Dito. ++ case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break; ++ default: ++ return 0; ++ } ++ ++ new_cursor = LoadCursor(NULL, n); ++ if (new_cursor == NULL) ++ return 0; ++ } ++ ++ if ((cursor != NULL) && custom_cursor) ++ DestroyIcon(cursor); ++ ++ cursor = new_cursor; ++ custom_cursor = 0; ++ ++ SetCursor(cursor); ++ ++ return 1; ++} ++ ++int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++ BITMAPV5HEADER bi; ++ HBITMAP bitmap, mask; ++ DWORD *bits; ++ HCURSOR new_cursor; ++ ++ if ((hotx < 0) || (hotx >= image->w())) ++ return 0; ++ if ((hoty < 0) || (hoty >= image->h())) ++ return 0; ++ ++ memset(&bi, 0, sizeof(BITMAPV5HEADER)); ++ ++ bi.bV5Size = sizeof(BITMAPV5HEADER); ++ bi.bV5Width = image->w(); ++ bi.bV5Height = -image->h(); // Negative for top-down ++ bi.bV5Planes = 1; ++ bi.bV5BitCount = 32; ++ bi.bV5Compression = BI_BITFIELDS; ++ bi.bV5RedMask = 0x00FF0000; ++ bi.bV5GreenMask = 0x0000FF00; ++ bi.bV5BlueMask = 0x000000FF; ++ bi.bV5AlphaMask = 0xFF000000; ++ ++ HDC hdc; ++ ++ hdc = GetDC(NULL); ++ bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); ++ ReleaseDC(NULL, hdc); ++ ++ if (bits == NULL) ++ return 0; ++ ++ const uchar *i = (const uchar*)*image->data(); ++ for (int y = 0;y < image->h();y++) { ++ for (int x = 0;x < image->w();x++) { ++ switch (image->d()) { ++ case 1: ++ *bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0]; ++ break; ++ case 2: ++ *bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0]; ++ break; ++ case 3: ++ *bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2]; ++ break; ++ case 4: ++ *bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2]; ++ break; ++ } ++ i += image->d(); ++ bits++; ++ } ++ i += image->ld(); ++ } ++ ++ // A mask bitmap is still needed even though it isn't used ++ mask = CreateBitmap(image->w(),image->h(),1,1,NULL); ++ if (mask == NULL) { ++ DeleteObject(bitmap); ++ return 0; ++ } ++ ++ ICONINFO ii; ++ ++ ii.fIcon = FALSE; ++ ii.xHotspot = hotx; ++ ii.yHotspot = hoty; ++ ii.hbmMask = mask; ++ ii.hbmColor = bitmap; ++ ++ new_cursor = CreateIconIndirect(&ii); ++ ++ DeleteObject(bitmap); ++ DeleteObject(mask); ++ ++ if (new_cursor == NULL) ++ return 0; ++ ++ if ((cursor != NULL) && custom_cursor) ++ DestroyIcon(cursor); ++ ++ cursor = new_cursor; ++ custom_cursor = 1; ++ ++ SetCursor(cursor); ++ ++ return 1; ++} ++ ++//////////////////////////////////////////////////////////////// + // Implement the virtual functions for the base Fl_Window class: + + // If the box is a filled rectangle, we can make the redisplay *look* +diff -up fltk-1.3.2/src/Fl_Window.cxx.cursor fltk-1.3.2/src/Fl_Window.cxx +--- fltk-1.3.2/src/Fl_Window.cxx.cursor 2012-11-06 21:46:14.000000000 +0100 ++++ fltk-1.3.2/src/Fl_Window.cxx 2013-01-30 16:07:59.536319784 +0100 +@@ -62,8 +62,6 @@ void Fl_Window::_Fl_Window() { + Fl_Window::Fl_Window(int X,int Y,int W, int H, const char *l) + : Fl_Group(X, Y, W, H, l) { + cursor_default = FL_CURSOR_DEFAULT; +- cursor_fg = FL_BLACK; +- cursor_bg = FL_WHITE; + + _Fl_Window(); + set_flag(FORCE_POSITION); +@@ -73,8 +71,6 @@ Fl_Window::Fl_Window(int W, int H, const + // fix common user error of a missing end() with current(0): + : Fl_Group((Fl_Group::current(0),0), 0, W, H, l) { + cursor_default = FL_CURSOR_DEFAULT; +- cursor_fg = FL_BLACK; +- cursor_bg = FL_WHITE; + + _Fl_Window(); + clear_visible(); +diff -up fltk-1.3.2/src/Fl_x.cxx.cursor fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.cursor 2013-01-30 16:07:59.512320211 +0100 ++++ fltk-1.3.2/src/Fl_x.cxx 2013-01-30 16:07:59.537319766 +0100 +@@ -59,6 +59,11 @@ static int xfixes_event_base = 0; + static bool have_xfixes = false; + # endif + ++# include ++ ++# if HAVE_XCURSOR ++# include ++# endif + static Fl_Xlib_Graphics_Driver fl_xlib_driver; + static Fl_Display_Device fl_xlib_display(&fl_xlib_driver); + Fl_Display_Device *Fl_Display_Device::_display = &fl_xlib_display;// the platform display +@@ -2259,6 +2264,94 @@ void Fl_Window::size_range_() { + } + + //////////////////////////////////////////////////////////////// ++ ++int Fl_X::set_cursor(Fl_Cursor c) { ++ unsigned int shape; ++ Cursor xc; ++ ++ switch (c) { ++ case FL_CURSOR_ARROW: shape = XC_left_ptr; break; ++ case FL_CURSOR_CROSS: shape = XC_tcross; break; ++ case FL_CURSOR_WAIT: shape = XC_watch; break; ++ case FL_CURSOR_INSERT: shape = XC_xterm; break; ++ case FL_CURSOR_HAND: shape = XC_hand2; break; ++ case FL_CURSOR_HELP: shape = XC_question_arrow; break; ++ case FL_CURSOR_MOVE: shape = XC_fleur; break; ++ case FL_CURSOR_NS: shape = XC_sb_v_double_arrow; break; ++ case FL_CURSOR_WE: shape = XC_sb_h_double_arrow; break; ++ case FL_CURSOR_NE: shape = XC_top_right_corner; break; ++ case FL_CURSOR_N: shape = XC_top_side; break; ++ case FL_CURSOR_NW: shape = XC_top_left_corner; break; ++ case FL_CURSOR_E: shape = XC_right_side; break; ++ case FL_CURSOR_W: shape = XC_left_side; break; ++ case FL_CURSOR_SE: shape = XC_bottom_right_corner; break; ++ case FL_CURSOR_S: shape = XC_bottom_side; break; ++ case FL_CURSOR_SW: shape = XC_bottom_left_corner; break; ++ default: ++ return 0; ++ } ++ ++ xc = XCreateFontCursor(fl_display, shape); ++ XDefineCursor(fl_display, xid, xc); ++ XFreeCursor(fl_display, xc); ++ ++ return 1; ++} ++ ++int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++#if ! HAVE_XCURSOR ++ return 0; ++#else ++ XcursorImage *cursor; ++ Cursor xc; ++ ++ if ((hotx < 0) || (hotx >= image->w())) ++ return 0; ++ if ((hoty < 0) || (hoty >= image->h())) ++ return 0; ++ ++ cursor = XcursorImageCreate(image->w(), image->h()); ++ if (!cursor) ++ return 0; ++ ++ const uchar *i = (const uchar*)*image->data(); ++ XcursorPixel *o = cursor->pixels; ++ for (int y = 0;y < image->h();y++) { ++ for (int x = 0;x < image->w();x++) { ++ switch (image->d()) { ++ case 1: ++ *o = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0]; ++ break; ++ case 2: ++ *o = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0]; ++ break; ++ case 3: ++ *o = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2]; ++ break; ++ case 4: ++ *o = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2]; ++ break; ++ } ++ i += image->d(); ++ o++; ++ } ++ i += image->ld(); ++ } ++ ++ cursor->xhot = hotx; ++ cursor->yhot = hoty; ++ ++ xc = XcursorImageLoadCursor(fl_display, cursor); ++ XDefineCursor(fl_display, xid, xc); ++ XFreeCursor(fl_display, xc); ++ ++ XcursorImageDestroy(cursor); ++ ++ return 1; ++#endif ++} ++ ++//////////////////////////////////////////////////////////////// + + // returns pointer to the filename, or null if name ends with '/' + const char *fl_filename_name(const char *name) { +diff -up fltk-1.3.2/test/cursor.cxx.cursor fltk-1.3.2/test/cursor.cxx +--- fltk-1.3.2/test/cursor.cxx.cursor 2011-07-19 06:49:30.000000000 +0200 ++++ fltk-1.3.2/test/cursor.cxx 2013-01-30 16:07:59.537319766 +0100 +@@ -23,8 +23,6 @@ + #include + #include + +-Fl_Color fg = FL_BLACK; +-Fl_Color bg = FL_WHITE; + Fl_Cursor cursor = FL_CURSOR_DEFAULT; + + Fl_Hor_Value_Slider *cursor_slider; +@@ -32,7 +30,7 @@ Fl_Hor_Value_Slider *cursor_slider; + void choice_cb(Fl_Widget *, void *v) { + cursor = (Fl_Cursor)(fl_intptr_t)v; + cursor_slider->value(cursor); +- fl_cursor(cursor,fg,bg); ++ fl_cursor(cursor); + } + + Fl_Menu_Item choices[] = { +@@ -48,8 +46,6 @@ Fl_Menu_Item choices[] = { + {"FL_CURSOR_WE",0,choice_cb,(void*)FL_CURSOR_WE}, + {"FL_CURSOR_NWSE",0,choice_cb,(void*)FL_CURSOR_NWSE}, + {"FL_CURSOR_NESW",0,choice_cb,(void*)FL_CURSOR_NESW}, +- {"FL_CURSOR_NONE",0,choice_cb,(void*)FL_CURSOR_NONE}, +-#if 0 + {"FL_CURSOR_N",0,choice_cb,(void*)FL_CURSOR_N}, + {"FL_CURSOR_NE",0,choice_cb,(void*)FL_CURSOR_NE}, + {"FL_CURSOR_E",0,choice_cb,(void*)FL_CURSOR_E}, +@@ -58,26 +54,14 @@ Fl_Menu_Item choices[] = { + {"FL_CURSOR_SW",0,choice_cb,(void*)FL_CURSOR_SW}, + {"FL_CURSOR_W",0,choice_cb,(void*)FL_CURSOR_W}, + {"FL_CURSOR_NW",0,choice_cb,(void*)FL_CURSOR_NW}, +-#endif ++ {"FL_CURSOR_NONE",0,choice_cb,(void*)FL_CURSOR_NONE}, + {0} + }; + + void setcursor(Fl_Widget *o, void *) { + Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o; + cursor = Fl_Cursor((int)slider->value()); +- fl_cursor(cursor,fg,bg); +-} +- +-void setfg(Fl_Widget *o, void *) { +- Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o; +- fg = Fl_Color((int)slider->value()); +- fl_cursor(cursor,fg,bg); +-} +- +-void setbg(Fl_Widget *o, void *) { +- Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o; +- bg = Fl_Color((int)slider->value()); +- fl_cursor(cursor,fg,bg); ++ fl_cursor(cursor); + } + + // draw the label without any ^C or \nnn conversions: +@@ -103,29 +87,11 @@ int main(int argc, char **argv) { + slider1.align(FL_ALIGN_LEFT); + slider1.step(1); + slider1.precision(0); +- slider1.bounds(0,100); ++ slider1.bounds(0,255); + slider1.value(0); + slider1.callback(setcursor); + slider1.value(cursor); + +- Fl_Hor_Value_Slider slider2(80,220,310,30,"fgcolor:"); +- slider2.align(FL_ALIGN_LEFT); +- slider2.step(1); +- slider2.precision(0); +- slider2.bounds(0,255); +- slider2.value(0); +- slider2.callback(setfg); +- slider2.value(fg); +- +- Fl_Hor_Value_Slider slider3(80,260,310,30,"bgcolor:"); +- slider3.align(FL_ALIGN_LEFT); +- slider3.step(1); +- slider3.precision(0); +- slider3.bounds(0,255); +- slider3.value(0); +- slider3.callback(setbg); +- slider3.value(bg); +- + #if 0 + // draw the manual's diagram of cursors... + window.size(400,800); diff --git a/contrib/fltk/11-str2802-fltk-1.3.0-modal.patch b/contrib/fltk/11-str2802-fltk-1.3.0-modal.patch new file mode 100644 index 0000000000..7b1b7913e0 --- /dev/null +++ b/contrib/fltk/11-str2802-fltk-1.3.0-modal.patch @@ -0,0 +1,75 @@ +diff -bur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm +--- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-19 12:54:43.694231638 +0200 ++++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-19 12:57:05.899048602 +0200 +@@ -697,12 +697,9 @@ + return NO; // prevent the caption to be redrawn as active on click + // when another modal window is currently the key win + +- return !(w->tooltip_window() || w->menu_window()); ++ return !w->tooltip_window(); + } + +-// TODO see if we really need a canBecomeMainWindow ... +-#if 0 +- + - (BOOL)canBecomeMainWindow + { + if (Fl::modal_ && (Fl::modal_ != w)) +@@ -711,7 +708,6 @@ + + return !(w->tooltip_window() || w->menu_window()); + } +-#endif + + @end + +diff -bur fltk-1.3.0r9619.org/src/Fl_win32.cxx fltk-1.3.0r9619/src/Fl_win32.cxx +--- fltk-1.3.0r9619.org/src/Fl_win32.cxx 2012-06-19 12:54:43.696231735 +0200 ++++ fltk-1.3.0r9619/src/Fl_win32.cxx 2012-06-19 12:54:43.803236862 +0200 +@@ -1065,6 +1065,10 @@ + break; + + case WM_SETFOCUS: ++ if ((Fl::modal_) && (Fl::modal_ != window)) { ++ SetFocus(fl_xid(Fl::modal_)); ++ return 0; ++ } + Fl::handle(FL_FOCUS, window); + break; + +@@ -1826,6 +1830,11 @@ + 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 : +@@ -1843,7 +1852,6 @@ + } + } + +- if (w->modal()) {Fl::modal_ = w; fl_fix_focus();} + return x; + } + +diff -bur fltk-1.3.0r9619.org/src/Fl_x.cxx fltk-1.3.0r9619/src/Fl_x.cxx +--- fltk-1.3.0r9619.org/src/Fl_x.cxx 2012-06-19 12:54:43.697231783 +0200 ++++ fltk-1.3.0r9619/src/Fl_x.cxx 2012-06-19 12:54:43.804236911 +0200 +@@ -2101,6 +2101,12 @@ + 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 diff --git a/contrib/fltk/12-str2816-fltk-1.3.0-icons.patch b/contrib/fltk/12-str2816-fltk-1.3.0-icons.patch new file mode 100644 index 0000000000..20b30b8b8d --- /dev/null +++ b/contrib/fltk/12-str2816-fltk-1.3.0-icons.patch @@ -0,0 +1,645 @@ +diff -ur fltk-1.3.2.org/FL/Fl_Window.H fltk-1.3.2/FL/Fl_Window.H +--- fltk-1.3.2.org/FL/Fl_Window.H 2013-01-16 10:49:40.904228200 +0100 ++++ fltk-1.3.2/FL/Fl_Window.H 2013-01-16 10:49:55.554353925 +0100 +@@ -22,6 +22,10 @@ + #ifndef Fl_Window_H + #define Fl_Window_H + ++#ifdef WIN32 ++#include ++#endif ++ + #include "Fl_Group.H" + + #define FL_WINDOW 0xF0 ///< window type id all subclasses have type() >= this +@@ -73,9 +77,19 @@ + friend class Fl_X; + Fl_X *i; // points at the system-specific stuff + ++ struct icon_data { ++ const void *legacy_icon; ++ Fl_RGB_Image **icons; ++ int count; ++#ifdef WIN32 ++ HICON big_icon; ++ HICON small_icon; ++#endif ++ }; ++ + const char* iconlabel_; + char* xclass_; +- const void* icon_; ++ struct icon_data *icon_; + // size_range stuff: + int minw, minh, maxw, maxh; + int dw, dh, aspect; +@@ -121,6 +135,8 @@ + */ + int force_position() const { return ((flags() & FORCE_POSITION)?1:0); } + ++ void free_icons(); ++ + public: + + /** +@@ -350,6 +366,18 @@ + static const char *default_xclass(); + const char* xclass() const; + void xclass(const char* c); ++ ++ static void default_icon(const Fl_RGB_Image*); ++ static void default_icons(const Fl_RGB_Image*[], int); ++ void icon(const Fl_RGB_Image*); ++ void icons(const Fl_RGB_Image*[], int); ++ ++#ifdef WIN32 ++ static void default_icons(HICON big_icon, HICON small_icon); ++ void icons(HICON big_icon, HICON small_icon); ++#endif ++ ++ /* for legacy compatibility */ + const void* icon() const; + void icon(const void * ic); + +diff -ur fltk-1.3.2.org/FL/mac.H fltk-1.3.2/FL/mac.H +--- fltk-1.3.2.org/FL/mac.H 2013-01-16 10:49:40.904228200 +0100 ++++ fltk-1.3.2/FL/mac.H 2013-01-16 10:49:55.554353925 +0100 +@@ -120,6 +120,9 @@ + void collapse(void); + WindowRef window_ref(void); + void set_key_window(void); ++ // OS X doesn't have per window icons ++ static void set_default_icons(const Fl_RGB_Image*[], int) {}; ++ void set_icons() {}; + int set_cursor(Fl_Cursor); + int set_cursor(const Fl_RGB_Image*, int, int); + static CGImageRef CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h); +diff -ur fltk-1.3.2.org/FL/win32.H fltk-1.3.2/FL/win32.H +--- fltk-1.3.2.org/FL/win32.H 2013-01-16 10:49:40.904228200 +0100 ++++ fltk-1.3.2/FL/win32.H 2013-01-16 10:49:55.555355617 +0100 +@@ -84,6 +84,9 @@ + void flush() {w->flush();} + void set_minmax(LPMINMAXINFO minmax); + void mapraise(); ++ static void set_default_icons(const Fl_RGB_Image*[], int); ++ static void set_default_icons(HICON, HICON); ++ void set_icons(); + int set_cursor(Fl_Cursor); + int set_cursor(const Fl_RGB_Image*, int, int); + static Fl_X* make(Fl_Window*); +diff -ur fltk-1.3.2.org/FL/x.H fltk-1.3.2/FL/x.H +--- fltk-1.3.2.org/FL/x.H 2013-01-16 10:49:40.904228200 +0100 ++++ fltk-1.3.2/FL/x.H 2013-01-16 10:49:55.555355617 +0100 +@@ -154,6 +154,8 @@ + static Fl_X* i(const Fl_Window* wi) {return wi->i;} + void setwindow(Fl_Window* wi) {w=wi; wi->i=this;} + void sendxjunk(); ++ static void set_default_icons(const Fl_RGB_Image*[], int); ++ void set_icons(); + int set_cursor(Fl_Cursor); + int set_cursor(const Fl_RGB_Image*, int, int); + static void make_xid(Fl_Window*,XVisualInfo* =fl_visual, Colormap=fl_colormap); +diff -ur fltk-1.3.2.org/src/Fl.cxx fltk-1.3.2/src/Fl.cxx +--- fltk-1.3.2.org/src/Fl.cxx 2013-01-16 10:49:40.895228113 +0100 ++++ fltk-1.3.2/src/Fl.cxx 2013-01-16 10:49:55.556137979 +0100 +@@ -1530,6 +1530,8 @@ + if (xclass_) { + free(xclass_); + } ++ free_icons(); ++ delete icon_; + } + + // FL_SHOW and FL_HIDE are called whenever the visibility of this widget +diff -ur fltk-1.3.2.org/src/Fl_win32.cxx fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2.org/src/Fl_win32.cxx 2013-01-16 10:49:40.911227539 +0100 ++++ fltk-1.3.2/src/Fl_win32.cxx 2013-01-16 10:49:55.556137979 +0100 +@@ -1804,6 +1804,8 @@ + ); + if (lab) free(lab); + ++ x->set_icons(); ++ + if (w->fullscreen_active()) { + /* We need to make sure that the fullscreen is created on the + default monitor, ie the desktop where the shortcut is located +@@ -2034,71 +2036,19 @@ + + //////////////////////////////////////////////////////////////// + +-#ifndef IDC_HAND +-# define IDC_HAND MAKEINTRESOURCE(32649) +-#endif // !IDC_HAND +- +-int Fl_X::set_cursor(Fl_Cursor c) { +- LPSTR n; +- HCURSOR new_cursor; +- +- if (c == FL_CURSOR_NONE) +- new_cursor = NULL; +- else { +- switch (c) { +- case FL_CURSOR_ARROW: n = IDC_ARROW; break; +- case FL_CURSOR_CROSS: n = IDC_CROSS; break; +- case FL_CURSOR_WAIT: n = IDC_WAIT; break; +- case FL_CURSOR_INSERT: n = IDC_IBEAM; break; +- case FL_CURSOR_HAND: n = IDC_HAND; break; +- case FL_CURSOR_HELP: n = IDC_HELP; break; +- case FL_CURSOR_MOVE: n = IDC_SIZEALL; break; +- case FL_CURSOR_N: +- case FL_CURSOR_S: +- // FIXME: Should probably have fallbacks for these instead +- case FL_CURSOR_NS: n = IDC_SIZENS; break; +- case FL_CURSOR_NE: +- case FL_CURSOR_SW: +- // FIXME: Dito. +- case FL_CURSOR_NESW: n = IDC_SIZENESW; break; +- case FL_CURSOR_E: +- case FL_CURSOR_W: +- // FIXME: Dito. +- case FL_CURSOR_WE: n = IDC_SIZEWE; break; +- case FL_CURSOR_SE: +- case FL_CURSOR_NW: +- // FIXME: Dito. +- case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break; +- default: +- return 0; +- } +- +- new_cursor = LoadCursor(NULL, n); +- if (new_cursor == NULL) +- return 0; +- } +- +- if ((cursor != NULL) && custom_cursor) +- DestroyIcon(cursor); +- +- cursor = new_cursor; +- custom_cursor = 0; +- +- SetCursor(cursor); +- +- return 1; +-} +- +-int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++static HICON image_to_icon(const Fl_RGB_Image *image, bool is_icon=true, ++ int hotx = 0, int hoty = 0) { + BITMAPV5HEADER bi; + HBITMAP bitmap, mask; + DWORD *bits; +- HCURSOR new_cursor; ++ HICON icon; + ++ if (!is_icon) { + if ((hotx < 0) || (hotx >= image->w())) +- return 0; ++ return NULL; + if ((hoty < 0) || (hoty >= image->h())) +- return 0; ++ return NULL; ++ } + + memset(&bi, 0, sizeof(BITMAPV5HEADER)); + +@@ -2120,7 +2070,7 @@ + ReleaseDC(NULL, hdc); + + if (bits == NULL) +- return 0; ++ return NULL; + + const uchar *i = (const uchar*)*image->data(); + for (int y = 0;y < image->h();y++) { +@@ -2149,22 +2099,206 @@ + mask = CreateBitmap(image->w(),image->h(),1,1,NULL); + if (mask == NULL) { + DeleteObject(bitmap); +- return 0; ++ return NULL; + } + + ICONINFO ii; + +- ii.fIcon = FALSE; ++ ii.fIcon = is_icon; + ii.xHotspot = hotx; + ii.yHotspot = hoty; + ii.hbmMask = mask; + ii.hbmColor = bitmap; + +- new_cursor = CreateIconIndirect(&ii); ++ icon = CreateIconIndirect(&ii); + + DeleteObject(bitmap); + DeleteObject(mask); + ++ if (icon == NULL) ++ return NULL; ++ ++ return icon; ++} ++ ++//////////////////////////////////////////////////////////////// ++ ++static HICON default_big_icon = NULL; ++static HICON default_small_icon = NULL; ++ ++const Fl_RGB_Image *find_best_icon(int ideal_width, ++ const Fl_RGB_Image *icons[], int count) { ++ const Fl_RGB_Image *best; ++ ++ best = NULL; ++ ++ for (int i = 0;i < count;i++) { ++ if (best == NULL) ++ best = icons[i]; ++ else { ++ if (best->w() < ideal_width) { ++ if (icons[i]->w() > best->w()) ++ best = icons[i]; ++ } else { ++ if ((icons[i]->w() >= ideal_width) && ++ (icons[i]->w() < best->w())) ++ best = icons[i]; ++ } ++ } ++ } ++ ++ return best; ++} ++ ++void Fl_X::set_default_icons(const Fl_RGB_Image *icons[], int count) { ++ const Fl_RGB_Image *best_big, *best_small; ++ ++ if (default_big_icon != NULL) ++ DestroyIcon(default_big_icon); ++ if (default_small_icon != NULL) ++ DestroyIcon(default_small_icon); ++ ++ best_big = find_best_icon(GetSystemMetrics(SM_CXICON), icons, count); ++ best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), icons, count); ++ ++ if (best_big != NULL) ++ default_big_icon = image_to_icon(best_big); ++ else ++ default_big_icon = NULL; ++ ++ if (best_small != NULL) ++ default_small_icon = image_to_icon(best_small); ++ else ++ default_small_icon = NULL; ++} ++ ++void Fl_X::set_default_icons(HICON big_icon, HICON small_icon) { ++ if (default_big_icon != NULL) ++ DestroyIcon(default_big_icon); ++ if (default_small_icon != NULL) ++ DestroyIcon(default_small_icon); ++ ++ if (big_icon != NULL) ++ default_big_icon = CopyIcon(big_icon); ++ if (small_icon != NULL) ++ default_small_icon = CopyIcon(small_icon); ++} ++ ++void Fl_X::set_icons() { ++ HICON big_icon, small_icon; ++ ++ big_icon = NULL; ++ small_icon = NULL; ++ ++ if (w->icon_->count) { ++ const Fl_RGB_Image *best_big, *best_small; ++ ++ best_big = find_best_icon(GetSystemMetrics(SM_CXICON), ++ (const Fl_RGB_Image **)w->icon_->icons, ++ w->icon_->count); ++ best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), ++ (const Fl_RGB_Image **)w->icon_->icons, ++ w->icon_->count); ++ ++ if (best_big != NULL) ++ big_icon = image_to_icon(best_big); ++ if (best_small != NULL) ++ small_icon = image_to_icon(best_small); ++ } else { ++ big_icon = default_big_icon; ++ small_icon = default_small_icon; ++ } ++ ++ if (big_icon != NULL) ++ SendMessage(xid, WM_SETICON, ICON_BIG, (LPARAM)big_icon); ++ if (small_icon != NULL) ++ SendMessage(xid, WM_SETICON, ICON_SMALL, (LPARAM)small_icon); ++ ++ if (w->icon_->count) { ++ if (big_icon != NULL) ++ DestroyIcon(big_icon); ++ if (small_icon != NULL) ++ DestroyIcon(small_icon); ++ } ++} ++ ++void Fl_Window::default_icons(HICON big_icon, HICON small_icon) { ++ Fl_X::set_default_icons(big_icon, small_icon); ++} ++ ++void Fl_Window::icons(HICON big_icon, HICON small_icon) { ++ free_icons(); ++ ++ if (big_icon != NULL) ++ icon_->big_icon = CopyIcon(big_icon); ++ if (small_icon != NULL) ++ icon_->small_icon = CopyIcon(small_icon); ++ ++ if (i) ++ i->set_icons(); ++} ++ ++//////////////////////////////////////////////////////////////// ++ ++#ifndef IDC_HAND ++# define IDC_HAND MAKEINTRESOURCE(32649) ++#endif // !IDC_HAND ++ ++int Fl_X::set_cursor(Fl_Cursor c) { ++ LPSTR n; ++ HCURSOR new_cursor; ++ ++ if (c == FL_CURSOR_NONE) ++ new_cursor = NULL; ++ else { ++ switch (c) { ++ case FL_CURSOR_ARROW: n = IDC_ARROW; break; ++ case FL_CURSOR_CROSS: n = IDC_CROSS; break; ++ case FL_CURSOR_WAIT: n = IDC_WAIT; break; ++ case FL_CURSOR_INSERT: n = IDC_IBEAM; break; ++ case FL_CURSOR_HAND: n = IDC_HAND; break; ++ case FL_CURSOR_HELP: n = IDC_HELP; break; ++ case FL_CURSOR_MOVE: n = IDC_SIZEALL; break; ++ case FL_CURSOR_N: ++ case FL_CURSOR_S: ++ // FIXME: Should probably have fallbacks for these instead ++ case FL_CURSOR_NS: n = IDC_SIZENS; break; ++ case FL_CURSOR_NE: ++ case FL_CURSOR_SW: ++ // FIXME: Dito. ++ case FL_CURSOR_NESW: n = IDC_SIZENESW; break; ++ case FL_CURSOR_E: ++ case FL_CURSOR_W: ++ // FIXME: Dito. ++ case FL_CURSOR_WE: n = IDC_SIZEWE; break; ++ case FL_CURSOR_SE: ++ case FL_CURSOR_NW: ++ // FIXME: Dito. ++ case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break; ++ default: ++ return 0; ++ } ++ ++ new_cursor = LoadCursor(NULL, n); ++ if (new_cursor == NULL) ++ return 0; ++ } ++ ++ if ((cursor != NULL) && custom_cursor) ++ DestroyIcon(cursor); ++ ++ cursor = new_cursor; ++ custom_cursor = 0; ++ ++ SetCursor(cursor); ++ ++ return 1; ++} ++ ++int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) { ++ HCURSOR new_cursor; ++ ++ new_cursor = image_to_icon(image, false, hotx, hoty); + if (new_cursor == NULL) + return 0; + +diff -ur fltk-1.3.2.org/src/Fl_Window.cxx fltk-1.3.2/src/Fl_Window.cxx +--- fltk-1.3.2.org/src/Fl_Window.cxx 2013-01-16 10:49:40.908130903 +0100 ++++ fltk-1.3.2/src/Fl_Window.cxx 2013-01-16 10:49:55.557353865 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include "flstring.h" +@@ -45,7 +46,8 @@ + } + i = 0; + xclass_ = 0; +- icon_ = 0; ++ icon_ = new icon_data; ++ memset(icon_, 0, sizeof(*icon_)); + iconlabel_ = 0; + resizable(0); + size_range_set = 0; +@@ -264,16 +266,68 @@ + } + } + ++void Fl_Window::default_icon(const Fl_RGB_Image *icon) { ++ default_icons(&icon, 1); ++} ++ ++void Fl_Window::default_icons(const Fl_RGB_Image **icons, int count) { ++ Fl_X::set_default_icons(icons, count); ++} ++ ++void Fl_Window::icon(const Fl_RGB_Image *icon) { ++ icons(&icon, 1); ++} ++ ++void Fl_Window::icons(const Fl_RGB_Image **icons, int count) { ++ free_icons(); ++ ++ if (count > 0) { ++ icon_->icons = new Fl_RGB_Image*[count]; ++ icon_->count = count; ++ // FIXME: Fl_RGB_Image lacks const modifiers on methods ++ for (int i = 0;i < count;i++) ++ icon_->icons[i] = (Fl_RGB_Image*)((Fl_RGB_Image*)icons[i])->copy(); ++ } ++ ++ if (i) ++ i->set_icons(); ++} ++ + /** Gets the current icon window target dependent data. */ + const void *Fl_Window::icon() const { +- return icon_; ++ return icon_->legacy_icon; + } + + /** Sets the current icon window target dependent data. */ + void Fl_Window::icon(const void * ic) { +- icon_ = ic; ++ free_icons(); ++ icon_->legacy_icon = ic; + } + ++void Fl_Window::free_icons() { ++ int i; ++ ++ icon_->legacy_icon = 0L; ++ ++ if (icon_->icons) { ++ for (i = 0;i < icon_->count;i++) ++ delete icon_->icons[i]; ++ delete [] icon_->icons; ++ icon_->icons = 0L; ++ } ++ ++ icon_->count = 0; ++ ++#ifdef WIN32 ++ if (icon_->big_icon) ++ DestroyIcon(icon_->big_icon); ++ if (icon_->small_icon) ++ DestroyIcon(icon_->small_icon); ++ ++ icon_->big_icon = NULL; ++ icon_->small_icon = NULL; ++#endif ++} + + // + // End of "$Id: Fl_Window.cxx 9706 2012-11-06 20:46:14Z matt $". +diff -ur fltk-1.3.2.org/src/Fl_x.cxx fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2.org/src/Fl_x.cxx 2013-01-16 10:49:40.912227213 +0100 ++++ fltk-1.3.2/src/Fl_x.cxx 2013-01-16 10:49:55.558137113 +0100 +@@ -345,6 +345,7 @@ + Atom fl_NET_WM_STATE; + Atom fl_NET_WM_STATE_FULLSCREEN; + Atom fl_NET_WORKAREA; ++Atom fl_NET_WM_ICON; + + /* + X defines 32-bit-entities to have a format value of max. 32, +@@ -709,6 +710,7 @@ + fl_NET_WM_STATE = XInternAtom(d, "_NET_WM_STATE", 0); + fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0); + fl_NET_WORKAREA = XInternAtom(d, "_NET_WORKAREA", 0); ++ fl_NET_WM_ICON = XInternAtom(d, "_NET_WM_ICON", 0); + + if (sizeof(Atom) < 4) + atom_bits = sizeof(Atom) * 8; +@@ -2138,12 +2140,14 @@ + fl_show_iconic = 0; + showit = 0; + } +- if (win->icon()) { +- hints->icon_pixmap = (Pixmap)win->icon(); ++ if (win->icon_->legacy_icon) { ++ hints->icon_pixmap = (Pixmap)win->icon_->legacy_icon; + hints->flags |= IconPixmapHint; + } + XSetWMHints(fl_display, xp->xid, hints); + XFree(hints); ++ ++ xp->set_icons(); + } + + // set the window type for menu and tooltip windows to avoid animations (compiz) +@@ -2263,6 +2267,93 @@ + + //////////////////////////////////////////////////////////////// + ++static unsigned long *default_net_wm_icons = 0L; ++static size_t default_net_wm_icons_size = 0; ++ ++void icons_to_property(const Fl_RGB_Image *icons[], int count, ++ unsigned long **property, size_t *len) { ++ size_t sz; ++ unsigned long *data; ++ ++ sz = 0; ++ for (int i = 0;i < count;i++) ++ sz += 2 + icons[i]->w() * icons[i]->h(); ++ ++ // FIXME: Might want to sort the icons ++ ++ *property = data = new unsigned long[sz]; ++ *len = sz; ++ ++ for (int i = 0;i < count;i++) { ++ const Fl_RGB_Image *image; ++ ++ image = icons[i]; ++ ++ data[0] = image->w(); ++ data[1] = image->h(); ++ data += 2; ++ ++ const uchar *in = (const uchar*)*image->data(); ++ for (int y = 0;y < image->h();y++) { ++ for (int x = 0;x < image->w();x++) { ++ switch (image->d()) { ++ case 1: ++ *data = ( 0xff<<24) | (in[0]<<16) | (in[0]<<8) | in[0]; ++ break; ++ case 2: ++ *data = (in[1]<<24) | (in[0]<<16) | (in[0]<<8) | in[0]; ++ break; ++ case 3: ++ *data = ( 0xff<<24) | (in[0]<<16) | (in[1]<<8) | in[2]; ++ break; ++ case 4: ++ *data = (in[3]<<24) | (in[0]<<16) | (in[1]<<8) | in[2]; ++ break; ++ } ++ in += image->d(); ++ data++; ++ } ++ in += image->ld(); ++ } ++ } ++} ++ ++void Fl_X::set_default_icons(const Fl_RGB_Image *icons[], int count) { ++ if (default_net_wm_icons) { ++ delete [] default_net_wm_icons; ++ default_net_wm_icons = 0L; ++ default_net_wm_icons_size = 0; ++ } ++ ++ if (count > 0) ++ icons_to_property(icons, count, ++ &default_net_wm_icons, &default_net_wm_icons_size); ++} ++ ++void Fl_X::set_icons() { ++ unsigned long *net_wm_icons; ++ size_t net_wm_icons_size; ++ ++ if (w->icon_->count) { ++ icons_to_property((const Fl_RGB_Image **)w->icon_->icons, w->icon_->count, ++ &net_wm_icons, &net_wm_icons_size); ++ } else { ++ net_wm_icons = default_net_wm_icons; ++ net_wm_icons_size = default_net_wm_icons_size; ++ } ++ ++ XChangeProperty (fl_display, xid, fl_NET_WM_ICON, XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char*) net_wm_icons, net_wm_icons_size); ++ ++ if (w->icon_->count) { ++ delete [] net_wm_icons; ++ net_wm_icons = 0L; ++ net_wm_icons_size = 0; ++ } ++} ++ ++//////////////////////////////////////////////////////////////// ++ + int Fl_X::set_cursor(Fl_Cursor c) { + unsigned int shape; + Cursor xc; diff --git a/contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch b/contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch new file mode 100644 index 0000000000..c157af6120 --- /dev/null +++ b/contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch @@ -0,0 +1,131 @@ +diff -up fltk-1.3.0r9619/FL/Fl.H.screen_num fltk-1.3.0r9619/FL/Fl.H +--- fltk-1.3.0r9619/FL/Fl.H.screen_num 2012-07-03 13:49:28.663085580 +0200 ++++ fltk-1.3.0r9619/FL/Fl.H 2012-07-03 13:49:28.731084402 +0200 +@@ -806,6 +806,8 @@ public: + static void screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my); + static void screen_xywh(int &X, int &Y, int &W, int &H, int n); + static void screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my, int mw, int mh); ++ static int screen_num(int x, int y); ++ static int screen_num(int x, int y, int w, int h); + static void screen_dpi(float &h, float &v, int n=0); + static void screen_work_area(int &X, int &Y, int &W, int &H, int mx, int my); + static void screen_work_area(int &X, int &Y, int &W, int &H, int n); +diff -up fltk-1.3.0r9619/src/screen_xywh.cxx.screen_num fltk-1.3.0r9619/src/screen_xywh.cxx +--- fltk-1.3.0r9619/src/screen_xywh.cxx.screen_num 2012-03-23 17:47:53.000000000 +0100 ++++ fltk-1.3.0r9619/src/screen_xywh.cxx 2012-07-03 13:58:01.947195396 +0200 +@@ -215,21 +215,6 @@ int Fl::screen_count() { + return num_screens ? num_screens : 1; + } + +-static int find_screen_with_point(int mx, int my) { +- int screen = 0; +- if (num_screens < 0) screen_init(); +- +- for (int i = 0; i < num_screens; i ++) { +- int sx, sy, sw, sh; +- Fl::screen_xywh(sx, sy, sw, sh, i); +- if ((mx >= sx) && (mx < (sx+sw)) && (my >= sy) && (my < (sy+sh))) { +- screen = i; +- break; +- } +- } +- return screen; +-} +- + /** + Gets the bounding box of a screen + that contains the specified screen position \p mx, \p my +@@ -237,7 +222,7 @@ static int find_screen_with_point(int mx + \param[in] mx, my the absolute screen position + */ + void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my) { +- screen_xywh(X, Y, W, H, find_screen_with_point(mx, my)); ++ screen_xywh(X, Y, W, H, screen_num(mx, my)); + } + + +@@ -248,7 +233,7 @@ void Fl::screen_xywh(int &X, int &Y, int + \param[in] mx, my the absolute screen position + */ + void Fl::screen_work_area(int &X, int &Y, int &W, int &H, int mx, int my) { +- screen_work_area(X, Y, W, H, find_screen_with_point(mx, my)); ++ screen_work_area(X, Y, W, H, screen_num(mx, my)); + } + + /** +@@ -321,6 +306,38 @@ void Fl::screen_xywh(int &X, int &Y, int + #endif // WIN32 + } + ++/** ++ Gets the screen bounding rect for the screen ++ which intersects the most with the rectangle ++ defined by \p mx, \p my, \p mw, \p mh. ++ \param[out] X,Y,W,H the corresponding screen bounding box ++ \param[in] mx, my, mw, mh the rectangle to search for intersection with ++ \see void screen_xywh(int &X, int &Y, int &W, int &H, int n) ++ */ ++void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my, int mw, int mh) { ++ screen_xywh(X, Y, W, H, screen_num(mx, my, mw, mh)); ++} ++ ++/** ++ Gets the screen number of a screen ++ that contains the specified screen position \p x, \p y ++ \param[in] x, y the absolute screen position ++*/ ++int Fl::screen_num(int x, int y) { ++ int screen = 0; ++ if (num_screens < 0) screen_init(); ++ ++ for (int i = 0; i < num_screens; i ++) { ++ int sx, sy, sw, sh; ++ Fl::screen_xywh(sx, sy, sw, sh, i); ++ if ((x >= sx) && (x < (sx+sw)) && (y >= sy) && (y < (sy+sh))) { ++ screen = i; ++ break; ++ } ++ } ++ return screen; ++} ++ + static inline float fl_intersection(int x1, int y1, int w1, int h1, + int x2, int y2, int w2, int h2) { + if(x1+w1 < x2 || x2+w2 < x1 || y1+h1 < y2 || y2+h2 < y1) +@@ -333,30 +350,27 @@ static inline float fl_intersection(int + } + + /** +- Gets the screen bounding rect for the screen ++ Gets the screen number for the screen + which intersects the most with the rectangle +- defined by \p mx, \p my, \p mw, \p mh. +- \param[out] X,Y,W,H the corresponding screen bounding box +- \param[in] mx, my, mw, mh the rectangle to search for intersection with +- \see void screen_xywh(int &X, int &Y, int &W, int &H, int n) ++ defined by \p x, \p y, \p w, \p h. ++ \param[in] x, y, w, h the rectangle to search for intersection with + */ +-void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my, int mw, int mh) { ++int Fl::screen_num(int x, int y, int w, int h) { + int best_screen = 0; + float best_intersection = 0.; + for(int i = 0; i < Fl::screen_count(); i++) { + int sx, sy, sw, sh; + Fl::screen_xywh(sx, sy, sw, sh, i); +- float sintersection = fl_intersection(mx, my, mw, mh, sx, sy, sw, sh); ++ float sintersection = fl_intersection(x, y, w, h, sx, sy, sw, sh); + if(sintersection > best_intersection) { + best_screen = i; + best_intersection = sintersection; + } + } +- screen_xywh(X, Y, W, H, best_screen); ++ return best_screen; + } + + +- + /** + Gets the screen resolution in dots-per-inch for the given screen. + \param[out] h, v horizontal and vertical resolution diff --git a/contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch b/contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch new file mode 100644 index 0000000000..e4a010aaeb --- /dev/null +++ b/contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch @@ -0,0 +1,468 @@ +diff -urp fltk-1.3.2.org/FL/Fl_Window.H fltk-1.3.2/FL/Fl_Window.H +--- fltk-1.3.2.org/FL/Fl_Window.H 2013-01-16 10:52:33.017228122 +0100 ++++ fltk-1.3.2/FL/Fl_Window.H 2013-01-16 10:52:47.876478968 +0100 +@@ -54,7 +54,7 @@ class Fl_RGB_Image; + class FL_EXPORT Fl_Window : public Fl_Group { + + static char *default_xclass_; +- // Note: we must use separate statements for each of the following 4 variables, ++ // Note: we must use separate statements for each of the following 8 variables, + // with the static attribute, otherwise MS VC++ 2008/2010 complains :-( + // AlbrechtS 04/2012 + #if FLTK_ABI_VERSION < 10301 +@@ -73,6 +73,22 @@ class FL_EXPORT Fl_Window : public Fl_Gr + static // when these members are static, ABI compatibility with 1.3.0 is respected + #endif + int no_fullscreen_h; ++#if FLTK_ABI_VERSION < 10302 ++ static // when these members are static, ABI compatibility with 1.3.0 is respected ++#endif ++ int fullscreen_screen_top; ++#if FLTK_ABI_VERSION < 10302 ++ static // when these members are static, ABI compatibility with 1.3.0 is respected ++#endif ++ int fullscreen_screen_bottom; ++#if FLTK_ABI_VERSION < 10302 ++ static // when these members are static, ABI compatibility with 1.3.0 is respected ++#endif ++ int fullscreen_screen_left; ++#if FLTK_ABI_VERSION < 10302 ++ static // when these members are static, ABI compatibility with 1.3.0 is respected ++#endif ++ int fullscreen_screen_right; + + friend class Fl_X; + Fl_X *i; // points at the system-specific stuff +@@ -430,13 +446,15 @@ public: + */ + void show(int argc, char **argv); + /** +- Makes the window completely fill the screen, without any window +- manager border visible. You must use fullscreen_off() to undo +- this. ++ Makes the window completely fill one or more screens, without any ++ window manager border visible. You must use fullscreen_off() to ++ undo this. + + \note On some platforms, this can result in the keyboard being + grabbed. The window may also be recreated, meaning hide() and + show() will be called. ++ ++ \see void Fl_Window::fullscreen_screens() + */ + void fullscreen(); + /** +@@ -453,6 +471,17 @@ public: + */ + unsigned int fullscreen_active() const { return flags() & FULLSCREEN; } + /** ++ Sets which screens should be used when this window is in fullscreen ++ mode. The window will be resized to the top of the screen with index ++ \p top, the bottom of the screen with index \p bottom, etc. ++ ++ If this method is never called, or if any argument is < 0, then the ++ window will be resized to fill the screen it is currently on. ++ ++ \see void Fl_Window::fullscreen() ++ */ ++ void fullscreen_screens(int top, int bottom, int left, int right); ++ /** + Iconifies the window. If you call this when shown() is false + it will show() it as an icon. If the window is already + iconified this does nothing. +diff -urp fltk-1.3.2.org/FL/win32.H fltk-1.3.2/FL/win32.H +--- fltk-1.3.2.org/FL/win32.H 2013-01-16 10:52:33.017228122 +0100 ++++ fltk-1.3.2/FL/win32.H 2013-01-16 10:52:47.876478968 +0100 +@@ -80,6 +80,7 @@ public: + static Fl_X* i(const Fl_Window* w) {return w->i;} + static int fake_X_wm(const Fl_Window* w,int &X, int &Y, + int &bt,int &bx,int &by); ++ void make_fullscreen(int X, int Y, int W, int H); + void setwindow(Fl_Window* wi) {w=wi; wi->i=this;} + void flush() {w->flush();} + void set_minmax(LPMINMAXINFO minmax); +diff -urp fltk-1.3.2.org/src/Fl_cocoa.mm fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2.org/src/Fl_cocoa.mm 2013-01-16 10:52:33.014229574 +0100 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2013-01-16 10:52:47.877480606 +0100 +@@ -2438,9 +2438,32 @@ void Fl_X::make(Fl_Window* w) + + NSRect crect; + if (w->fullscreen_active()) { +- int sx, sy, sw, sh; +- Fl::screen_xywh(sx, sy, sw, sh, w->x(), w->y(), w->w(), w->h()); +- w->resize(sx, sy, sw, sh); ++ int top, bottom, left, right; ++ int sx, sy, sw, sh, X, Y, W, H; ++ ++ top = w->fullscreen_screen_top; ++ bottom = w->fullscreen_screen_bottom; ++ left = w->fullscreen_screen_left; ++ right = w->fullscreen_screen_right; ++ ++ if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { ++ top = Fl::screen_num(w->x(), w->y(), w->w(), w->h()); ++ bottom = top; ++ left = top; ++ right = top; ++ } ++ ++ Fl::screen_xywh(sx, sy, sw, sh, top); ++ Y = sy; ++ Fl::screen_xywh(sx, sy, sw, sh, bottom); ++ H = sy + sh - Y; ++ Fl::screen_xywh(sx, sy, sw, sh, left); ++ X = sx; ++ Fl::screen_xywh(sx, sy, sw, sh, right); ++ W = sx + sw - X; ++ ++ w->resize(X, Y, W, H); ++ + winstyle = NSBorderlessWindowMask; + winlevel = NSStatusWindowLevel; + } +diff -urp fltk-1.3.2.org/src/Fl_win32.cxx fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2.org/src/Fl_win32.cxx 2013-01-16 10:52:33.019230734 +0100 ++++ fltk-1.3.2/src/Fl_win32.cxx 2013-01-16 10:52:47.878480504 +0100 +@@ -1493,7 +1493,6 @@ int Fl_X::fake_X_wm(const Fl_Window* w,i + Y+=yoff; + + if (w->fullscreen_active()) { +- X = Y = 0; + bx = by = bt = 0; + } + +@@ -1547,19 +1546,42 @@ void Fl_Window::resize(int X,int Y,int W + } + } + +-static void make_fullscreen(Fl_Window *w, Window xid, int X, int Y, int W, int H) { ++void Fl_X::make_fullscreen(int X, int Y, int W, int H) { ++ int top, bottom, left, right; + int sx, sy, sw, sh; +- Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H); ++ ++ top = w->fullscreen_screen_top; ++ bottom = w->fullscreen_screen_bottom; ++ left = w->fullscreen_screen_left; ++ right = w->fullscreen_screen_right; ++ ++ if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { ++ top = Fl::screen_num(X, Y, W, H); ++ bottom = top; ++ left = top; ++ right = top; ++ } ++ ++ Fl::screen_xywh(sx, sy, sw, sh, top); ++ Y = sy; ++ Fl::screen_xywh(sx, sy, sw, sh, bottom); ++ H = sy + sh - Y; ++ Fl::screen_xywh(sx, sy, sw, sh, left); ++ X = sx; ++ Fl::screen_xywh(sx, sy, sw, sh, right); ++ W = sx + sw - X; ++ + DWORD flags = GetWindowLong(xid, GWL_STYLE); + flags = flags & ~(WS_THICKFRAME|WS_CAPTION); + SetWindowLong(xid, GWL_STYLE, flags); ++ + // SWP_NOSENDCHANGING is so that we can override size limits +- SetWindowPos(xid, HWND_TOP, sx, sy, sw, sh, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); ++ SetWindowPos(xid, HWND_TOP, X, Y, W, H, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); + } + + void Fl_Window::fullscreen_x() { + _set_fullscreen(); +- make_fullscreen(this, fl_xid(this), x(), y(), w(), h()); ++ i->make_fullscreen(x(), y(), w(), h()); + Fl::handle(FL_FULLSCREEN, this); + } + +@@ -1814,8 +1836,8 @@ Fl_X* Fl_X::make(Fl_Window* w) { + monitor the window was placed on. */ + RECT rect; + GetWindowRect(x->xid, &rect); +- make_fullscreen(w, x->xid, rect.left, rect.top, +- rect.right - rect.left, rect.bottom - rect.top); ++ x->make_fullscreen(rect.left, rect.top, ++ rect.right - rect.left, rect.bottom - rect.top); + } + + x->next = Fl_X::first; +diff -urp fltk-1.3.2.org/src/Fl_Window_fullscreen.cxx fltk-1.3.2/src/Fl_Window_fullscreen.cxx +--- fltk-1.3.2.org/src/Fl_Window_fullscreen.cxx 2012-11-06 21:46:14.000000000 +0100 ++++ fltk-1.3.2/src/Fl_Window_fullscreen.cxx 2013-01-16 10:52:47.879480608 +0100 +@@ -36,6 +36,10 @@ int Fl_Window::no_fullscreen_x = 0; + int Fl_Window::no_fullscreen_y = 0; + int Fl_Window::no_fullscreen_w = 0; + int Fl_Window::no_fullscreen_h = 0; ++int Fl_Window::fullscreen_screen_top = -1; ++int Fl_Window::fullscreen_screen_bottom = -1; ++int Fl_Window::fullscreen_screen_left = -1; ++int Fl_Window::fullscreen_screen_right = -1; + #endif + + void Fl_Window::border(int b) { +@@ -95,6 +99,23 @@ void Fl_Window::fullscreen_off() { + fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h); + } + ++void Fl_Window::fullscreen_screens(int top, int bottom, int left, int right) { ++ if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { ++ fullscreen_screen_top = -1; ++ fullscreen_screen_bottom = -1; ++ fullscreen_screen_left = -1; ++ fullscreen_screen_right = -1; ++ } else { ++ fullscreen_screen_top = top; ++ fullscreen_screen_bottom = bottom; ++ fullscreen_screen_left = left; ++ fullscreen_screen_right = right; ++ } ++ ++ if (shown() && (flags() & Fl_Widget::FULLSCREEN)) ++ fullscreen_x(); ++} ++ + + // + // End of "$Id: Fl_Window_fullscreen.cxx 9706 2012-11-06 20:46:14Z matt $". +diff -urp fltk-1.3.2.org/src/Fl_x.cxx fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2.org/src/Fl_x.cxx 2013-01-16 10:52:33.020228202 +0100 ++++ fltk-1.3.2/src/Fl_x.cxx 2013-01-16 10:52:47.880480556 +0100 +@@ -344,6 +344,7 @@ Atom fl_NET_WM_ICON_NAME; // utf8 aware + Atom fl_NET_SUPPORTING_WM_CHECK; + Atom fl_NET_WM_STATE; + Atom fl_NET_WM_STATE_FULLSCREEN; ++Atom fl_NET_WM_FULLSCREEN_MONITORS; + Atom fl_NET_WORKAREA; + Atom fl_NET_WM_ICON; + +@@ -709,6 +710,7 @@ void fl_open_display(Display* d) { + fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0); + fl_NET_WM_STATE = XInternAtom(d, "_NET_WM_STATE", 0); + fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0); ++ fl_NET_WM_FULLSCREEN_MONITORS = XInternAtom(d, "_NET_WM_FULLSCREEN_MONITORS", 0); + fl_NET_WORKAREA = XInternAtom(d, "_NET_WORKAREA", 0); + fl_NET_WM_ICON = XInternAtom(d, "_NET_WM_ICON", 0); + +@@ -1872,22 +1874,30 @@ void Fl_Window::resize(int X,int Y,int W + #define _NET_WM_STATE_ADD 1 /* add/set property */ + #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +-static void send_wm_state_event(Window wnd, int add, Atom prop) { ++static void send_wm_event(Window wnd, Atom message, ++ unsigned long d0, unsigned long d1=0, ++ unsigned long d2=0, unsigned long d3=0, ++ unsigned long d4=0) { + XEvent e; + e.xany.type = ClientMessage; + e.xany.window = wnd; +- e.xclient.message_type = fl_NET_WM_STATE; ++ e.xclient.message_type = message; + e.xclient.format = 32; +- e.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; +- e.xclient.data.l[1] = prop; +- e.xclient.data.l[2] = 0; +- e.xclient.data.l[3] = 0; +- e.xclient.data.l[4] = 0; ++ e.xclient.data.l[0] = d0; ++ e.xclient.data.l[1] = d1; ++ e.xclient.data.l[2] = d2; ++ e.xclient.data.l[3] = d3; ++ e.xclient.data.l[4] = d4; + XSendEvent(fl_display, RootWindow(fl_display, fl_screen), + 0, SubstructureNotifyMask | SubstructureRedirectMask, + &e); + } + ++static void send_wm_state_event(Window wnd, int add, Atom prop) { ++ send_wm_event(wnd, fl_NET_WM_STATE, ++ add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE, prop); ++} ++ + int Fl_X::ewmh_supported() { + static int result = -1; + +@@ -1911,6 +1921,22 @@ int Fl_X::ewmh_supported() { + /* Change an existing window to fullscreen */ + void Fl_Window::fullscreen_x() { + if (Fl_X::ewmh_supported()) { ++ int top, bottom, left, right; ++ ++ top = fullscreen_screen_top; ++ bottom = fullscreen_screen_bottom; ++ left = fullscreen_screen_left; ++ right = fullscreen_screen_right; ++ ++ if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { ++ top = Fl::screen_num(x(), y(), w(), h()); ++ bottom = top; ++ left = top; ++ right = top; ++ } ++ ++ send_wm_event(fl_xid(this), fl_NET_WM_FULLSCREEN_MONITORS, ++ top, bottom, left, right); + send_wm_state_event(fl_xid(this), 1, fl_NET_WM_STATE_FULLSCREEN); + } else { + _set_fullscreen(); +@@ -1997,7 +2023,7 @@ void Fl_X::make_xid(Fl_Window* win, XVis + // force the window to be on-screen. Usually the X window manager + // does this, but a few don't, so we do it here for consistency: + int scr_x, scr_y, scr_w, scr_h; +- Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); ++ Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y, W, H); + + if (win->border()) { + // ensure border is on screen: +@@ -2026,6 +2052,23 @@ void Fl_X::make_xid(Fl_Window* win, XVis + return; + } + ++ // Compute which screen(s) we should be on if we want to go fullscreen ++ int fullscreen_top, fullscreen_bottom, fullscreen_left, fullscreen_right; ++ ++ fullscreen_top = win->fullscreen_screen_top; ++ fullscreen_bottom = win->fullscreen_screen_bottom; ++ fullscreen_left = win->fullscreen_screen_left; ++ fullscreen_right = win->fullscreen_screen_right; ++ ++ if ((fullscreen_top < 0) || (fullscreen_bottom < 0) || ++ (fullscreen_left < 0) || (fullscreen_right < 0)) { ++ fullscreen_top = Fl::screen_num(X, Y, W, H); ++ fullscreen_bottom = fullscreen_top; ++ fullscreen_left = fullscreen_top; ++ fullscreen_right = fullscreen_top; ++ } ++ ++ + ulong root = win->parent() ? + fl_xid(win->window()) : RootWindow(fl_display, fl_screen); + +@@ -2049,9 +2092,17 @@ void Fl_X::make_xid(Fl_Window* win, XVis + // border, and cannot grab without an existing window. Besides, + // there is no clear_override(). + if (win->flags() & Fl_Widget::FULLSCREEN && !Fl_X::ewmh_supported()) { ++ int sx, sy, sw, sh; + attr.override_redirect = 1; + mask |= CWOverrideRedirect; +- Fl::screen_xywh(X, Y, W, H, X, Y, W, H); ++ Fl::screen_xywh(sx, sy, sw, sh, fullscreen_left); ++ X = sx; ++ Fl::screen_xywh(sx, sy, sw, sh, fullscreen_right); ++ W = sx + sw - X; ++ Fl::screen_xywh(sx, sy, sw, sh, fullscreen_top); ++ Y = sy; ++ Fl::screen_xywh(sx, sy, sw, sh, fullscreen_bottom); ++ H = sy + sh - Y; + } + + if (fl_background_pixel >= 0) { +@@ -2122,6 +2173,13 @@ void Fl_X::make_xid(Fl_Window* win, XVis + + // If asked for, create fullscreen + if (win->flags() & Fl_Widget::FULLSCREEN && Fl_X::ewmh_supported()) { ++ unsigned long data[4]; ++ data[0] = fullscreen_top; ++ data[1] = fullscreen_bottom; ++ data[2] = fullscreen_left; ++ data[3] = fullscreen_right; ++ XChangeProperty (fl_display, xp->xid, fl_NET_WM_FULLSCREEN_MONITORS, XA_ATOM, 32, ++ PropModeReplace, (unsigned char*) data, 4); + XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1); + } +diff -urp fltk-1.3.2.org/test/fullscreen.cxx fltk-1.3.2/test/fullscreen.cxx +--- fltk-1.3.2.org/test/fullscreen.cxx 2012-06-14 17:09:46.000000000 +0200 ++++ fltk-1.3.2/test/fullscreen.cxx 2013-01-16 10:52:47.881104801 +0100 +@@ -127,7 +127,7 @@ class fullscreen_window : public Fl_Sing + fullscreen_window(int W, int H, const char *t=0); + int handle (int e); + Fl_Toggle_Light_Button *b3; +- ++ Fl_Toggle_Light_Button *b4; + }; + + fullscreen_window::fullscreen_window(int W, int H, const char *t) : Fl_Single_Window(W, H, t) { +@@ -170,23 +170,54 @@ void border_cb(Fl_Widget *o, void *p) { + #endif + } + +-int px,py,pw,ph; + Fl_Button *border_button; + void fullscreen_cb(Fl_Widget *o, void *p) { + Fl_Window *w = (Fl_Window *)p; + int d = ((Fl_Button *)o)->value(); + if (d) { +- px = w->x(); +- py = w->y(); +- pw = w->w(); +- ph = w->h(); ++ if (((fullscreen_window*)w)->b4->value()) { ++ int top, bottom, left, right; ++ int top_y, bottom_y, left_x, right_x; ++ ++ int sx, sy, sw, sh; ++ ++ top = bottom = left = right = 0; ++ ++ Fl::screen_xywh(sx, sy, sw, sh, 0); ++ top_y = sy; ++ bottom_y = sy + sh; ++ left_x = sx; ++ right_x = sx + sw; ++ ++ for (int i = 1;i < Fl::screen_count();i++) { ++ Fl::screen_xywh(sx, sy, sw, sh, i); ++ if (sy < top_y) { ++ top = i; ++ top_y = sy; ++ } ++ if ((sy + sh) > bottom_y) { ++ bottom = i; ++ bottom_y = sy + sh; ++ } ++ if (sx < left_x) { ++ left = i; ++ left_x = sx; ++ } ++ if ((sx + sw) > right_x) { ++ right = i; ++ right_x = sx + sw; ++ } ++ } ++ ++ w->fullscreen_screens(top, bottom, left, right); ++ } else { ++ w->fullscreen_screens(-1, -1, -1, -1); ++ } + w->fullscreen(); +- w->override(); + #ifndef WIN32 // update our border state in case border was turned off + border_button->value(w->border()); + #endif + } else { +- //w->fullscreen_off(px,py,pw,ph); + w->fullscreen_off(); + } + } +@@ -219,7 +250,7 @@ void exit_cb(Fl_Widget *, void *) { + exit(0); + } + +-#define NUMB 7 ++#define NUMB 8 + + int twowindow = 0; + int initfull = 0; +@@ -284,6 +315,9 @@ int main(int argc, char **argv) { + window.b3->callback(fullscreen_cb,w); + y+=30; + ++ window.b4 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"All Screens"); ++ y+=30; ++ + Fl_Button eb(50,y,window.w()-60,30,"Exit"); + eb.callback(exit_cb); + y+=30; diff --git a/contrib/patches/0001-Add-BUILD_STATIC-feature-from-TigerVNC-to-optionally.patch b/contrib/fltk/fixes/0001-Add-BUILD_STATIC-feature-from-TigerVNC-to-optionally.patch similarity index 100% rename from contrib/patches/0001-Add-BUILD_STATIC-feature-from-TigerVNC-to-optionally.patch rename to contrib/fltk/fixes/0001-Add-BUILD_STATIC-feature-from-TigerVNC-to-optionally.patch diff --git a/contrib/patches/0002-Fl_cocoa.mm-depends-on-some-Carbon-functions-so-we-n.patch b/contrib/fltk/fixes/0002-Fl_cocoa.mm-depends-on-some-Carbon-functions-so-we-n.patch similarity index 100% rename from contrib/patches/0002-Fl_cocoa.mm-depends-on-some-Carbon-functions-so-we-n.patch rename to contrib/fltk/fixes/0002-Fl_cocoa.mm-depends-on-some-Carbon-functions-so-we-n.patch diff --git a/contrib/patches/0003-We-need-to-unset-CMAKE_REQUIRED_LIBRARIES-after-chec.patch b/contrib/fltk/fixes/0003-We-need-to-unset-CMAKE_REQUIRED_LIBRARIES-after-chec.patch similarity index 100% rename from contrib/patches/0003-We-need-to-unset-CMAKE_REQUIRED_LIBRARIES-after-chec.patch rename to contrib/fltk/fixes/0003-We-need-to-unset-CMAKE_REQUIRED_LIBRARIES-after-chec.patch diff --git a/contrib/patches/0004-str-2917-fix-macosx-10.6-build-issue.patch b/contrib/fltk/fixes/0004-str-2917-fix-macosx-10.6-build-issue.patch similarity index 100% rename from contrib/patches/0004-str-2917-fix-macosx-10.6-build-issue.patch rename to contrib/fltk/fixes/0004-str-2917-fix-macosx-10.6-build-issue.patch From 25188c448cef7c802b8e27e13d643a7c95aaa840 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:30:08 +0200 Subject: [PATCH 07/19] Remove simple keyboard model Remove the FLTK simple keyboard system and reorganise things in preparation for a more direct approach. --- CMakeLists.txt | 3 - config.h.in | 1 - .../01-str2599-fltk-1.3.x-keyboard-x11.patch | 286 ------------- ... => 01-str2636-fltk-1.3.x-clipboard.patch} | 0 ...02-str2599-fltk-1.3.x-keyboard-win32.patch | 256 ------------ ...02-str2636-fltk-1.3.x-clipboard-x11.patch} | 0 .../03-str2599-fltk-1.3.x-keyboard-osx.patch | 375 ------------------ ...2636-fltk-1.3.x-clipboard-win32-fix.patch} | 0 ...-str2636-fltk-1.3.x-clipboard-win32.patch} | 0 ...05-str2636-fltk-1.3.x-clipboard-osx.patch} | 0 ...9-pixmap.patch => 06-str2659-pixmap.patch} | 0 ...tch => 07-str2660-fltk-1.3.x-cursor.patch} | 0 ...atch => 08-str2802-fltk-1.3.0-modal.patch} | 0 ...atch => 09-str2816-fltk-1.3.0-icons.patch} | 0 ...=> 10-str2860-fltk-1.3.x-screen_num.patch} | 0 ... => 11-str2860-fltk-1.3.x-multihead.patch} | 0 vncviewer/Viewport.cxx | 325 ++++++++------- vncviewer/Viewport.h | 8 +- vncviewer/menukey.cxx | 68 ++-- vncviewer/menukey.h | 5 +- 20 files changed, 224 insertions(+), 1103 deletions(-) delete mode 100644 contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch rename contrib/fltk/{04-str2636-fltk-1.3.x-clipboard.patch => 01-str2636-fltk-1.3.x-clipboard.patch} (100%) delete mode 100644 contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch rename contrib/fltk/{05-str2636-fltk-1.3.x-clipboard-x11.patch => 02-str2636-fltk-1.3.x-clipboard-x11.patch} (100%) delete mode 100644 contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch rename contrib/fltk/{06-str2636-fltk-1.3.x-clipboard-win32-fix.patch => 03-str2636-fltk-1.3.x-clipboard-win32-fix.patch} (100%) rename contrib/fltk/{07-str2636-fltk-1.3.x-clipboard-win32.patch => 04-str2636-fltk-1.3.x-clipboard-win32.patch} (100%) rename contrib/fltk/{08-str2636-fltk-1.3.x-clipboard-osx.patch => 05-str2636-fltk-1.3.x-clipboard-osx.patch} (100%) rename contrib/fltk/{09-str2659-pixmap.patch => 06-str2659-pixmap.patch} (100%) rename contrib/fltk/{10-str2660-fltk-1.3.x-cursor.patch => 07-str2660-fltk-1.3.x-cursor.patch} (100%) rename contrib/fltk/{11-str2802-fltk-1.3.0-modal.patch => 08-str2802-fltk-1.3.0-modal.patch} (100%) rename contrib/fltk/{12-str2816-fltk-1.3.0-icons.patch => 09-str2816-fltk-1.3.0-icons.patch} (100%) rename contrib/fltk/{13-str2860-fltk-1.3.x-screen_num.patch => 10-str2860-fltk-1.3.x-screen_num.patch} (100%) rename contrib/fltk/{14-str2860-fltk-1.3.x-multihead.patch => 11-str2860-fltk-1.3.x-multihead.patch} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0a00afa5..30520a51d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,9 +279,6 @@ if(FLTK_FOUND) set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES}) - # FLTK STR #2599 - check_cxx_source_compiles("#include \nint main(int c, char** v) { void (Fl_Widget::*foo)() = &Fl_Widget::set_simple_keyboard; return 0; }" HAVE_FLTK_DEAD_KEYS) - # FLTK STR #2636 check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_clipboard_notify(NULL, NULL); return 0; }" HAVE_FLTK_CLIPBOARD) diff --git a/config.h.in b/config.h.in index 0c9e71a5ff..a88c31c591 100644 --- a/config.h.in +++ b/config.h.in @@ -10,7 +10,6 @@ #cmakedefine HAVE_GNUTLS_DATUM_T #cmakedefine HAVE_GNUTLS_PK_ALGORITHM_T #cmakedefine HAVE_GNUTLS_SIGN_ALGORITHM_T -#cmakedefine HAVE_FLTK_DEAD_KEYS #cmakedefine HAVE_FLTK_CLIPBOARD #cmakedefine HAVE_FLTK_MEDIAKEYS #cmakedefine HAVE_FLTK_FULLSCREEN diff --git a/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch b/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch deleted file mode 100644 index cabc0f1cae..0000000000 --- a/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch +++ /dev/null @@ -1,286 +0,0 @@ -diff -ur fltk-1.3.0r9619.org/FL/Fl_Widget.H fltk-1.3.0r9619/FL/Fl_Widget.H ---- fltk-1.3.0r9619.org/FL/Fl_Widget.H 2012-04-23 22:12:06.000000000 +0200 -+++ fltk-1.3.0r9619/FL/Fl_Widget.H 2012-06-18 13:46:07.302320825 +0200 -@@ -171,6 +171,7 @@ - GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window - COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget - FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window) -+ SIMPLE_KEYBOARD = 1<<19, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input) - // (space for more flags) - USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions - USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions -@@ -776,6 +777,35 @@ - */ - void clear_changed() {flags_ &= ~CHANGED;} - -+ /** -+ Returns if the widget sees a simplified keyboard model or not. -+ -+ Normally widgets get a full-featured keyboard model that is geared -+ towards text input. This includes support for compose sequences and -+ advanced input methods, commonly used for asian writing system. This -+ system however has downsides in that extra graphic can be presented -+ to the user and that a physical key press doesn't correspond directly -+ to a FLTK event. -+ -+ Widgets that need a direct correspondence between actual key events -+ and those seen by the widget can swith to the simplified keyboard -+ model. -+ -+ \retval 0 if the widget uses the normal keyboard model -+ \see set_changed(), clear_changed() -+ */ -+ unsigned int simple_keyboard() const {return flags_&SIMPLE_KEYBOARD;} -+ -+ /** Marks a widget to use the simple keyboard model. -+ \see changed(), clear_changed() -+ */ -+ void set_simple_keyboard() {flags_ |= SIMPLE_KEYBOARD;} -+ -+ /** Marks a widget to use the normal keyboard model. -+ \see changed(), set_changed() -+ */ -+ void set_normal_keyboard() {flags_ &= ~SIMPLE_KEYBOARD;} -+ - /** Gives the widget the keyboard focus. - Tries to make this widget be the Fl::focus() widget, by first sending - it an FL_FOCUS event, and if it returns non-zero, setting -diff -ur fltk-1.3.0r9619.org/src/Fl.cxx fltk-1.3.0r9619/src/Fl.cxx ---- fltk-1.3.0r9619.org/src/Fl.cxx 2012-03-23 17:47:53.000000000 +0100 -+++ fltk-1.3.0r9619/src/Fl.cxx 2012-06-18 13:46:07.303320877 +0200 -@@ -70,6 +70,8 @@ - extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle); - #endif // WIN32 - -+extern void fl_update_focus(void); -+ - // - // Globals... - // -@@ -876,6 +878,8 @@ - fl_oldfocus = p; - } - e_number = old_event; -+ // let the platform code do what it needs -+ fl_update_focus(); - } - } - -diff -ur fltk-1.3.0r9619.org/src/Fl_grab.cxx fltk-1.3.0r9619/src/Fl_grab.cxx ---- fltk-1.3.0r9619.org/src/Fl_grab.cxx 2012-03-23 17:47:53.000000000 +0100 -+++ fltk-1.3.0r9619/src/Fl_grab.cxx 2012-06-18 13:46:07.303320877 +0200 -@@ -29,6 +29,7 @@ - // override_redirect, it does similar things on WIN32. - - extern void fl_fix_focus(); // in Fl.cxx -+void fl_update_focus(void); - - #ifdef WIN32 - // We have to keep track of whether we have captured the mouse, since -@@ -80,6 +81,7 @@ - #endif - } - grab_ = win; -+ fl_update_focus(); - } else { - if (grab_) { - #ifdef WIN32 -@@ -98,6 +100,7 @@ - XFlush(fl_display); - #endif - grab_ = 0; -+ fl_update_focus(); - fl_fix_focus(); - } - } -diff -ur fltk-1.3.0r9619.org/src/Fl_x.cxx fltk-1.3.0r9619/src/Fl_x.cxx ---- fltk-1.3.0r9619.org/src/Fl_x.cxx 2012-06-18 13:46:07.205316173 +0200 -+++ fltk-1.3.0r9619/src/Fl_x.cxx 2012-06-18 13:46:18.216844629 +0200 -@@ -298,6 +298,7 @@ - Colormap fl_colormap; - XIM fl_xim_im = 0; - XIC fl_xim_ic = 0; -+Window fl_xim_win = 0; - char fl_is_over_the_spot = 0; - static XRectangle status_area; - -@@ -583,6 +584,65 @@ - if(xim_styles) XFree(xim_styles); - } - -+void fl_xim_deactivate(void); -+ -+void fl_xim_activate(Window xid) -+{ -+ if (!fl_xim_im) -+ return; -+ -+ // If the focused window has changed, then use the brute force method -+ // of completely recreating the input context. -+ if (fl_xim_win != xid) { -+ fl_xim_deactivate(); -+ -+ fl_new_ic(); -+ fl_xim_win = xid; -+ -+ XSetICValues(fl_xim_ic, -+ XNFocusWindow, fl_xim_win, -+ XNClientWindow, fl_xim_win, -+ NULL); -+ } -+ -+ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -+} -+ -+void fl_xim_deactivate(void) -+{ -+ if (!fl_xim_ic) -+ return; -+ -+ XDestroyIC(fl_xim_ic); -+ fl_xim_ic = NULL; -+ -+ fl_xim_win = 0; -+} -+ -+extern Fl_Window *fl_xfocus; -+ -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ if (focus->simple_keyboard()) { -+ fl_xim_deactivate(); -+ } else { -+ // fl_xfocus should always be set if something has focus, but let's -+ // play it safe -+ if (!fl_xfocus || !fl_xid(fl_xfocus)) -+ return; -+ -+ fl_xim_activate(fl_xid(fl_xfocus)); -+ } -+} -+ - void fl_open_display() { - if (fl_display) return; - -@@ -917,10 +977,9 @@ - XEvent xevent = thisevent; - fl_xevent = &thisevent; - Window xid = xevent.xany.window; -- static Window xim_win = 0; - - if (fl_xim_ic && xevent.type == DestroyNotify && -- xid != xim_win && !fl_find(xid)) -+ xid != fl_xim_win && !fl_find(xid)) - { - XIM xim_im; - xim_im = XOpenIM(fl_display, NULL, NULL, NULL); -@@ -935,48 +994,10 @@ - return 0; - } - -- if (fl_xim_ic && (xevent.type == FocusIn)) -- { --#define POOR_XIM --#ifdef POOR_XIM -- if (xim_win != xid) -- { -- xim_win = xid; -- XDestroyIC(fl_xim_ic); -- fl_xim_ic = NULL; -- fl_new_ic(); -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xevent.xclient.window, -- XNClientWindow, xid, -- NULL); -- } -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); --#else -- if (Fl::first_window() && Fl::first_window()->modal()) { -- Window x = fl_xid(Fl::first_window()); -- if (x != xim_win) { -- xim_win = x; -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xim_win, -- XNClientWindow, xim_win, -- NULL); -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -- } -- } else if (xim_win != xid && xid) { -- xim_win = xid; -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xevent.xclient.window, -- XNClientWindow, xid, -- //XNFocusWindow, xim_win, -- //XNClientWindow, xim_win, -- NULL); -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -- } --#endif -+ if (fl_xim_ic) { -+ if (XFilterEvent((XEvent *)&xevent, 0)) -+ return 1; - } -- -- if ( XFilterEvent((XEvent *)&xevent, 0) ) -- return(1); - - #if USE_XRANDR - if( XRRUpdateConfiguration_f && xevent.type == randrEventBase + RRScreenChangeNotify) { -@@ -1326,15 +1347,15 @@ - //static XComposeStatus compose; - len = XLookupString((XKeyEvent*)&(xevent.xkey), - buffer, buffer_len, &keysym, 0/*&compose*/); -- if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets -- // force it to type a character (not sure if this ever is needed): -- // if (!len) {buffer[0] = char(keysym); len = 1;} -- len = fl_utf8encode(XKeysymToUcs(keysym), buffer); -- if (len < 1) len = 1; -- // ignore all effects of shift on the keysyms, which makes it a lot -- // easier to program shortcuts and is Windoze-compatible: -- keysym = XKeycodeToKeysym(fl_display, keycode, 0); -- } -+ // XLookupString() is only defined to return Latin-1 (although it -+ // often gives you more). To be safe, use our own lookups based on -+ // keysym. -+ len = fl_utf8encode(XKeysymToUcs(keysym), buffer); -+ if (len < 1) -+ len = 1; -+ // ignore all effects of shift on the keysyms, which makes it a lot -+ // easier to program shortcuts and is Windoze-compatable: -+ keysym = XKeycodeToKeysym(fl_display, keycode, 0); - } - // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not - // set until set_event_xy() is called later... -diff -ur fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c fltk-1.3.0r9619/src/xutf8/imKStoUCS.c ---- fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c 2009-03-13 23:43:43.000000000 +0100 -+++ fltk-1.3.0r9619/src/xutf8/imKStoUCS.c 2012-06-18 13:46:07.304320930 +0200 -@@ -266,6 +266,12 @@ - 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ - }; - -+static unsigned short const keysym_to_unicode_fe50_fe60[] = { -+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, /* 0xfe50-0xfe57 */ -+ 0x030a, 0x030b, 0x030c, 0x0327, 0x0328, 0x1da5, 0x3099, 0x309a, /* 0xfe58-0xfe5f */ -+ 0x0323 /* 0xfe60-0xfe67 */ -+}; -+ - unsigned int - KeySymToUcs4(KeySym keysym) - { -@@ -315,6 +321,8 @@ - return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; - else if (keysym > 0x209f && keysym < 0x20ad) - return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; -+ else if (keysym > 0xfe4f && keysym < 0xfe61) -+ return keysym_to_unicode_fe50_fe60[keysym - 0xfe50]; - else - return 0; - } diff --git a/contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch b/contrib/fltk/01-str2636-fltk-1.3.x-clipboard.patch similarity index 100% rename from contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch rename to contrib/fltk/01-str2636-fltk-1.3.x-clipboard.patch diff --git a/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch b/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch deleted file mode 100644 index c29d3b9744..0000000000 --- a/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch +++ /dev/null @@ -1,256 +0,0 @@ -diff -ur fltk-1.3.0r9293.org/src/Fl_win32.cxx fltk-1.3.0r9293/src/Fl_win32.cxx ---- fltk-1.3.0r9293.org/src/Fl_win32.cxx 2012-06-18 09:07:56.522314557 +0200 -+++ fltk-1.3.0r9293/src/Fl_win32.cxx 2012-06-18 09:08:07.392836285 +0200 -@@ -87,6 +87,8 @@ - static Fl_Display_Device fl_gdi_display(&fl_gdi_driver); - Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display - -+bool use_simple_keyboard = false; -+ - // dynamic wsock dll handling api: - #if defined(__CYGWIN__) && !defined(SOCKET) - # define SOCKET int -@@ -120,6 +122,8 @@ - * size and link dependencies. - */ - static HMODULE s_imm_module = 0; -+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD); -+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0; - typedef HIMC (WINAPI* flTypeImmGetContext)(HWND); - static flTypeImmGetContext flImmGetContext = 0; - typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); -@@ -135,6 +139,7 @@ - if (!s_imm_module) - Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" - "Please check your input method manager library accessibility."); -+ flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx"); - flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); - flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); - flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); -@@ -413,7 +418,12 @@ - } - } - -- TranslateMessage(&fl_msg); -+ // Don't bother with key to character translation as we do -+ // it manually for simpley keyboard widgets. In fact, calling -+ // TranslateMessage() just makes it more difficult as it sets -+ // a bunch of internal state. -+ if (!use_simple_keyboard) -+ TranslateMessage(&fl_msg); - DispatchMessageW(&fl_msg); - have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); - } -@@ -638,6 +648,49 @@ - } - } - -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ Fl_Window *win; -+ -+ get_imm_module(); -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ // Grabs are special in that events are sent to the first -+ // available window -+ if (focus == Fl::grab()) -+ win = Fl::first_window(); -+ else { -+ win = focus->as_window(); -+ if (!win) -+ win = focus->window(); -+ } -+ -+ if (!win) { -+ Fl::warning("Cannot find window for widget receiving focus"); -+ return; -+ } -+ -+ // No Win32 window created yet -+ if (!Fl_X::i(win) || !fl_xid(win)) -+ return; -+ -+ if (focus->simple_keyboard()) { -+ use_simple_keyboard = true; -+ if (flImmGetContext(fl_xid(win)) != 0) -+ flImmAssociateContextEx(fl_xid(win), 0, 0); -+ } else { -+ use_simple_keyboard = false; -+ if (flImmGetContext(fl_xid(win)) == 0) -+ flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT); -+ } -+} -+ - HWND fl_capture; - - static int mouse_event(Fl_Window *window, int what, int button, -@@ -785,6 +838,27 @@ - return extended ? extendedlut[vk] : vklut[vk]; - } - -+static xchar msdead2fltk(xchar in) -+{ -+ switch (in) { -+ case 0x0060: // GRAVE ACCENT -+ return 0x0300; // COMBINING GRAVE ACCENT -+ case 0x00b4: // ACUTE ACCENT -+ return 0x0301; // COMBINING ACUTE ACCENT -+ case 0x005e: // CIRCUMFLEX ACCENT -+ return 0x0302; // COMBINING CIRCUMFLEX ACCENT -+ case 0x007e: // TILDE -+ return 0x0303; // COMBINING TILDE -+ case 0x00a8: // DIAERESIS -+ return 0x0308; // COMBINING DIAERESIS -+ // FIXME: Windows dead key behaviour isn't documented and I don't have -+ // any more keyboards to test with... -+ } -+ -+ // hope that Windows gave us something proper to begin with -+ return in; -+} -+ - #if USE_COLORMAP - extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx - #endif -@@ -846,6 +920,8 @@ - //fl_msg.pt = ??? - //fl_msg.lPrivate = ??? - -+ MSG fl_orig_msg = fl_msg; -+ - Fl_Window *window = fl_find(hWnd); - - if (window) switch (uMsg) { -@@ -1025,23 +1101,82 @@ - if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; - Fl::e_state = state; - static char buffer[1024]; -- if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - -+ if (use_simple_keyboard) { -+ BYTE keystate[256]; -+ WCHAR wbuf[8]; -+ int ret; -+ -+ // I'm not sure if we ever get WM_CHAR (& friends) without an initial -+ // WM_KEYDOWN (& friends), but if we do then we should not send such -+ // side band events to simple keyboard widgets. -+ if ((fl_orig_msg.message != WM_KEYDOWN) && -+ (fl_orig_msg.message != WM_SYSKEYDOWN) && -+ (fl_orig_msg.message != WM_KEYUP) && -+ (fl_orig_msg.message != WM_SYSKEYUP)) -+ break; -+ -+ GetKeyboardState(keystate); -+ -+ // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off. -+ // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is -+ // active. -+ if (!(keystate[VK_MENU] & 0x80)) -+ keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0; -+ -+ // We cannot inspect or modify Windows' internal state of the keyboard -+ // so we have to try to infer information from ToUnicode() and wedge -+ // things into a known state. -+ for (int i = 0;i < 2;i++) { -+ ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf, -+ sizeof(wbuf)/sizeof(wbuf[0]), 0); -+ -+ // No symbol for this key (or unexpected length) -+ if ((ret == 0) || (ret < -1)) { -+ buffer[0] = 0; -+ Fl::e_length = 0; -+ break; -+ } -+ -+ // A dead key. Convert this to a Unicode combining character so -+ // that the application can tell the difference between dead and -+ // normal keys. -+ if (ret == -1) { -+ xchar u = (xchar) msdead2fltk(wbuf[0]); -+ Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); -+ buffer[Fl::e_length] = 0; -+ break; -+ } -+ -+ // If we have two characters (or more) from ToUnicode(), that's -+ // an invalid sequence. One character chould mean a proper symbol, -+ // or it could mean a composed one. In both cases we need to call -+ // ToUnicode() again to get something sane. -+ if (i == 0) -+ continue; -+ -+ // We should now have something sane. Give whatever we have to the -+ // application. -+ Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret); -+ buffer[Fl::e_length] = 0; -+ } -+ } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - xchar u = (xchar) wParam; - // Fl::e_length = fl_unicode2utf(&u, 1, buffer); - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); - buffer[Fl::e_length] = 0; -+ } else { -+ buffer[0] = 0; -+ Fl::e_length = 0; -+ } - -- -- } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { -- if (state & FL_NUM_LOCK) { -- // Convert to regular keypress... -- buffer[0] = Fl::e_keysym-FL_KP; -- Fl::e_length = 1; -- } else { -- // Convert to special keypress... -- buffer[0] = 0; -- Fl::e_length = 0; -+ // The keypad area is a bit odd in that we need to change the keysym -+ // to properly indicate what the user meant, unlike other keys where -+ // we normally change the text and keep keysym stable. -+ if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { -+ // The initial mapping tables give us a keysym that corresponds to -+ // numlock being on, so we only do something when it is off. -+ if (!(state & FL_NUM_LOCK)) { - switch (Fl::e_keysym) { - case FL_KP + '0' : - Fl::e_keysym = FL_Insert; -@@ -1073,30 +1208,10 @@ - case FL_KP + '.' : - Fl::e_keysym = FL_Delete; - break; -- case FL_KP + '/' : -- case FL_KP + '*' : -- case FL_KP + '-' : -- case FL_KP + '+' : -- buffer[0] = Fl::e_keysym-FL_KP; -- Fl::e_length = 1; -- break; - } - } -- } else if ((lParam & (1<<31))==0) { --#ifdef FLTK_PREVIEW_DEAD_KEYS -- if ((lParam & (1<<24))==0) { // clear if dead key (always?) -- xchar u = (xchar) wParam; -- Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); -- buffer[Fl::e_length] = 0; -- } else { // set if "extended key" (never printable?) -- buffer[0] = 0; -- Fl::e_length = 0; -- } --#else -- buffer[0] = 0; -- Fl::e_length = 0; --#endif - } -+ - Fl::e_text = buffer; - if (lParam & (1<<31)) { // key up events. - if (Fl::handle(FL_KEYUP, window)) return 0; diff --git a/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch b/contrib/fltk/02-str2636-fltk-1.3.x-clipboard-x11.patch similarity index 100% rename from contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch rename to contrib/fltk/02-str2636-fltk-1.3.x-clipboard-x11.patch diff --git a/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch b/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch deleted file mode 100644 index cf13aad74b..0000000000 --- a/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch +++ /dev/null @@ -1,375 +0,0 @@ -diff -ur fltk-1.3.0r9619.org/configure.in fltk-1.3.0r9619/configure.in ---- fltk-1.3.0r9619.org/configure.in 2012-04-22 04:45:09.000000000 +0200 -+++ fltk-1.3.0r9619/configure.in 2012-06-18 13:47:33.290447462 +0200 -@@ -865,6 +865,8 @@ - Darwin*) - # MacOS X uses Cocoa for graphics. - LIBS="$LIBS -framework Cocoa" -+ # And some Carbon for keyboard handling -+ LIBS="$LIBS -framework Carbon" - - if test x$have_pthread = xyes; then - AC_DEFINE(HAVE_PTHREAD) -diff -ur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm ---- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-16 10:49:52.000000000 +0200 -+++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-18 13:47:42.944910782 +0200 -@@ -53,6 +53,7 @@ - #include - - #import -+#import - - #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h - #if defined(__LP64__) && __LP64__ -@@ -114,6 +115,8 @@ - extern Fl_Window* fl_xmousewin; - #endif - -+bool use_simple_keyboard = false; -+ - enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; - - -@@ -130,6 +133,39 @@ - { - } - -+// Undocumented voodoo. Taken from Mozilla. -+#define ENABLE_ROMAN_KYBDS_ONLY -23 -+ -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ if (focus->simple_keyboard()) -+ use_simple_keyboard = true; -+ else -+ use_simple_keyboard = false; -+ -+ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and -+ // Safari people seem to think implies turning off advanced IME stuff -+ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput -+ // in Safari/Webcore). Should be good enough for us then... -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); -+ TSMSetDocumentProperty(TSMGetActiveDocument(), -+ kTSMDocumentEnabledInputSourcesPropertyTag, -+ sizeof(CFArrayRef), &inputSources); -+ CFRelease(inputSources); -+#else -+ KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds); -+#endif -+} -+ - /* - * Mac keyboard lookup table - */ -@@ -908,6 +944,25 @@ - } - @end - -+static const char* cocoaDead2FLTK(const char *in) -+{ -+ if (strcmp(in, "\140") == 0) // GRAVE ACCENT -+ return "\314\200"; // COMBINING GRAVE ACCENT -+ if (strcmp(in, "\302\264") == 0) // ACUTE ACCENT -+ return "\314\201"; // COMBINING ACUTE ACCENT -+ if (strcmp(in, "\136") == 0) // CIRCUMFLEX ACCENT -+ return "\314\202"; // COMBINING CIRCUMFLEX ACCENT -+ if (strcmp(in, "\176") == 0) // TILDE -+ return "\314\203"; // COMBINING TILDE -+ if (strcmp(in, "\302\250") == 0) // DIAERESIS -+ return "\314\210"; // COMBINING DIAERESIS -+ // FIXME: OS X dead key behaviour isn't documented and I don't have -+ // any more keyboards to test with... -+ -+ // hope that OS X gave us something proper to begin with -+ return in; -+} -+ - /* - Handle cocoa keyboard events - Events during a character composition sequence: -@@ -1648,6 +1703,7 @@ - - (void)rightMouseDragged:(NSEvent *)theEvent; - - (void)otherMouseDragged:(NSEvent *)theEvent; - - (void)scrollWheel:(NSEvent *)theEvent; -++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags; - - (BOOL)handleKeyDown:(NSEvent *)theEvent; - - (void)keyDown:(NSEvent *)theEvent; - - (void)keyUp:(NSEvent *)theEvent; -@@ -1726,6 +1782,130 @@ - - (void)scrollWheel:(NSEvent *)theEvent { - cocoaMouseWheelHandler(theEvent); - } -++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags { -+ const UCKeyboardLayout *layout; -+ OSStatus err; -+ -+ layout = NULL; -+ -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ TISInputSourceRef keyboard; -+ CFDataRef uchr; -+ -+ keyboard = TISCopyCurrentKeyboardInputSource(); -+ uchr = (CFDataRef)TISGetInputSourceProperty(keyboard, -+ kTISPropertyUnicodeKeyLayoutData); -+ if (uchr == NULL) -+ return nil; -+ -+ layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); -+#else -+ KeyboardLayoutRef old_layout; -+ int kind; -+ -+ err = KLGetCurrentKeyboardLayout(&old_layout); -+ if (err != noErr) -+ return nil; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLKind, -+ (const void**)&kind); -+ if (err != noErr) -+ return nil; -+ -+ // Old, crufty layout format? -+ if (kind == kKLKCHRKind) { -+ void *kchr_layout; -+ -+ UInt32 chars, state; -+ char buf[3]; -+ -+ unichar result[16]; -+ ByteCount in_len, out_len; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLKCHRData, -+ (const void**)&kchr_layout); -+ if (err != noErr) -+ return nil; -+ -+ state = 0; -+ -+ keyCode &= 0x7f; -+ modifierFlags &= 0xff00; -+ -+ chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); -+ -+ buf[0] = (chars >> 16) & 0xff; -+ buf[1] = chars & 0xff; -+ buf[2] = '\0'; -+ -+ if (buf[0] == '\0') { -+ buf[0] = buf[1]; -+ buf[1] = '\0'; -+ } -+ -+ // The data is now in some layout specific encoding. Need to convert -+ // this to unicode. -+ -+ ScriptCode script; -+ TextEncoding encoding; -+ TECObjectRef converter; -+ -+ script = (ScriptCode)GetScriptManagerVariable(smKeyScript); -+ -+ err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, -+ kTextRegionDontCare, NULL, -+ &encoding); -+ if (err != noErr) -+ return nil; -+ -+ err = TECCreateConverter(&converter, encoding, kTextEncodingUnicodeV4_0); -+ if (err != noErr) -+ return nil; -+ -+ in_len = strlen(buf); -+ out_len = sizeof(result); -+ -+ err = TECConvertText(converter, (ConstTextPtr)buf, in_len, &in_len, -+ (TextPtr)result, out_len, &out_len); -+ -+ TECDisposeConverter(converter); -+ -+ if (err != noErr) -+ return nil; -+ -+ return [NSString stringWithCharacters:result -+ length:(out_len / sizeof(unichar))]; -+ } -+ -+ if ((kind != kKLKCHRuchrKind) && (kind != kKLuchrKind)) -+ return nil; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLuchrData, -+ (const void**)&layout); -+ if (err != noErr) -+ return nil; -+#endif -+ -+ if (layout == NULL) -+ return nil; -+ -+ UInt32 dead_state; -+ UniCharCount max_len, actual_len; -+ UniChar string[255]; -+ -+ dead_state = 0; -+ max_len = sizeof(string)/sizeof(*string); -+ -+ modifierFlags = (modifierFlags >> 8) & 0xff; -+ -+ err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, -+ LMGetKbdType(), 0, &dead_state, max_len, &actual_len, -+ string); -+ if (err != noErr) -+ return nil; -+ -+ return [NSString stringWithCharacters:string length:actual_len]; -+} - - (BOOL)handleKeyDown:(NSEvent *)theEvent { - //NSLog(@"handleKeyDown"); - fl_lock_function(); -@@ -1752,14 +1932,47 @@ - break; - } - } -- if (!no_text_key && !(Fl::e_state & FL_META) ) { -- // Don't send cmd- to interpretKeyEvents because it beeps. -+ if (!no_text_key) { -+ // The simple keyboard model will ignore insertText, so we need to grab -+ // the symbol directly from the event. Note that we still use setMarkedText. -+ if (use_simple_keyboard) { -+ NSString *simple_chars; -+ UInt32 modifiers; -+ -+ // We want a "normal" symbol out of the event, which basically means -+ // we only respect the shift and alt/altgr modifiers. Cocoa can help -+ // us if we only wanted shift, but as we also want alt/altgr, we'll -+ // have to do some lookup ourselves. This matches our behaviour on -+ // other platforms. -+ -+ modifiers = 0; -+ if ([theEvent modifierFlags] & NSAlphaShiftKeyMask) -+ modifiers |= alphaLock; -+ if ([theEvent modifierFlags] & NSShiftKeyMask) -+ modifiers |= shiftKey; -+ if ([theEvent modifierFlags] & NSAlternateKeyMask) -+ modifiers |= optionKey; -+ -+ simple_chars = [FLView keyTranslate:[theEvent keyCode] -+ withModifierFlags:modifiers]; -+ if (simple_chars == nil) { -+ // Something went wrong. Fall back to what Cocoa gave us... -+ simple_chars = [theEvent charactersIgnoringModifiers]; -+ } -+ -+ [FLView prepareEtext:simple_chars]; -+ } -+ - // Then we can let the OS have a stab at it and see if it thinks it - // should result in some text -- NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; -- in_key_event = true; -- [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; -- in_key_event = false; -+ -+ // Don't send cmd- to interpretKeyEvents because it beeps. -+ if (!(Fl::e_state & FL_META)) { -+ NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; -+ in_key_event = true; -+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; -+ in_key_event = false; -+ } - } - //NSLog(@"to text=%@ l=%d", [NSString stringWithUTF8String:Fl::e_text], Fl::e_length); - int handled = Fl::handle(FL_KEYDOWN, window); -@@ -1937,21 +2150,30 @@ - //NSLog(@"insertText: received=%@",received); - - if (!in_key_event) fl_lock_function(); -+ -+ // Simple keyboard widgets do not want these side channel inputs. -+ if (use_simple_keyboard) -+ goto end; -+ - [FLView prepareEtext:received]; -+ - // We can get called outside of key events (e.g. from the character -- // palette). Transform such actions to FL_PASTE events. -+ // palette). We need to fake our own key event at that point. - if (!in_key_event) { - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; -- Fl::handle(FL_PASTE, target); -+ Fl::e_keysym = Fl::e_original_keysym = 0; -+ Fl::handle(FL_KEYDOWN, target); - // for some reason, the window does not redraw until the next mouse move or button push - // sending a 'redraw()' or 'awake()' does not solve the issue! - Fl::flush(); - } -+ -+end: - if (!in_key_event) fl_unlock_function(); - } - - - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { -- NSString *received; -+ NSString *received, *current, *aggregate; - if (newSelection.location == 0) { - [self unmarkText]; - return; -@@ -1962,11 +2184,47 @@ - received = (NSString*)aString; - } - //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); -+ -+ fl_lock_function(); -+ -+ // Simple keyboard widgets generally do not want these side channel -+ // inputs, but we have no other way of getting dead keys so we make -+ // an exception in that case. -+ if (use_simple_keyboard) { -+ if (in_key_event && (Fl::e_length == 0)) { -+ [FLView prepareEtext:received]; -+ -+ Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text); -+ Fl::e_length = strlen(Fl::e_text); -+ } -+ goto end; -+ } -+ - // This code creates the OS X behaviour of seeing dead keys as things - // are being composed. -+ // -+ // Note: The concatenation thing is because of how OS X deals with -+ // invalid sequences. At that point it will spit out one call -+ // to insertText with the now aborted sequence, and one new -+ // call to setMarkedText with the new sequence. Since we want -+ // both to be visible, we need to concatenate. - next_compose_length = newSelection.location; -- [FLView prepareEtext:received]; -- //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length); -+ current = [NSString stringWithUTF8String:Fl::e_text]; -+ aggregate = [current stringByAppendingString:received]; -+ -+ [FLView prepareEtext:aggregate]; -+ //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length); -+ -+ // We can get called outside of key events (e.g. from the character -+ // palette). We need to fake our own key event at that point. -+ if (!in_key_event) { -+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; -+ Fl::e_keysym = Fl::e_original_keysym = 0; -+ Fl::handle(FL_KEYDOWN, target); -+ } -+ -+end: -+ fl_unlock_function(); - } - - - (void)unmarkText { diff --git a/contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch b/contrib/fltk/03-str2636-fltk-1.3.x-clipboard-win32-fix.patch similarity index 100% rename from contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch rename to contrib/fltk/03-str2636-fltk-1.3.x-clipboard-win32-fix.patch diff --git a/contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch b/contrib/fltk/04-str2636-fltk-1.3.x-clipboard-win32.patch similarity index 100% rename from contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch rename to contrib/fltk/04-str2636-fltk-1.3.x-clipboard-win32.patch diff --git a/contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch b/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-osx.patch similarity index 100% rename from contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch rename to contrib/fltk/05-str2636-fltk-1.3.x-clipboard-osx.patch diff --git a/contrib/fltk/09-str2659-pixmap.patch b/contrib/fltk/06-str2659-pixmap.patch similarity index 100% rename from contrib/fltk/09-str2659-pixmap.patch rename to contrib/fltk/06-str2659-pixmap.patch diff --git a/contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch b/contrib/fltk/07-str2660-fltk-1.3.x-cursor.patch similarity index 100% rename from contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch rename to contrib/fltk/07-str2660-fltk-1.3.x-cursor.patch diff --git a/contrib/fltk/11-str2802-fltk-1.3.0-modal.patch b/contrib/fltk/08-str2802-fltk-1.3.0-modal.patch similarity index 100% rename from contrib/fltk/11-str2802-fltk-1.3.0-modal.patch rename to contrib/fltk/08-str2802-fltk-1.3.0-modal.patch diff --git a/contrib/fltk/12-str2816-fltk-1.3.0-icons.patch b/contrib/fltk/09-str2816-fltk-1.3.0-icons.patch similarity index 100% rename from contrib/fltk/12-str2816-fltk-1.3.0-icons.patch rename to contrib/fltk/09-str2816-fltk-1.3.0-icons.patch diff --git a/contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch b/contrib/fltk/10-str2860-fltk-1.3.x-screen_num.patch similarity index 100% rename from contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch rename to contrib/fltk/10-str2860-fltk-1.3.x-screen_num.patch diff --git a/contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch b/contrib/fltk/11-str2860-fltk-1.3.x-multihead.patch similarity index 100% rename from contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch rename to contrib/fltk/11-str2860-fltk-1.3.x-multihead.patch diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 7d55168200..2209fe5863 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -86,16 +86,14 @@ enum { ID_EXIT, ID_FULLSCREEN, ID_RESIZE, ID_CTRL, ID_ALT, ID_MENUKEY, ID_CTRLALTDEL, ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS }; +// Fake key presses use this value and above +static const int fakeKeyBase = 0x200; + Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), lastPointerPos(0, 0), lastButtonMask(0), cursor(NULL), menuCtrlKey(false), menuAltKey(false) { -// FLTK STR #2599 must be fixed for proper dead keys support -#ifdef HAVE_FLTK_DEAD_KEYS - set_simple_keyboard(); -#endif - // FLTK STR #2636 gives us the ability to monitor clipboard changes #ifdef HAVE_FLTK_CLIPBOARD Fl::add_clipboard_notify(handleClipboardChange, this); @@ -399,26 +397,15 @@ int Viewport::handle(int event) // Release all keys that were pressed as that generally makes most // sense (e.g. Alt+Tab where we only see the Alt press) while (!downKeySym.empty()) - handleKeyEvent(downKeySym.begin()->first, downKeySym.begin()->first, - "", false); + handleKeyRelease(downKeySym.begin()->first); return 1; case FL_KEYDOWN: - if (menuKeyCode && (Fl::event_key() == menuKeyCode)) { - popupContextMenu(); - return 1; - } - - handleKeyEvent(Fl::event_key(), Fl::event_original_key(), - Fl::event_text(), true); + handleFLTKKeyPress(); return 1; case FL_KEYUP: - if (menuKeyCode && (Fl::event_key() == menuKeyCode)) - return 1; - - handleKeyEvent(Fl::event_key(), Fl::event_original_key(), - Fl::event_text(), false); + handleKeyRelease(Fl::event_original_key()); return 1; } @@ -495,9 +482,156 @@ void Viewport::handlePointerTimeout(void *data) } -rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *keyText) +void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) +{ + static bool menuRecursion = false; + + // Prevent recursion if the menu wants to send its own + // activation key. + if (menuKeySym && (keySym == menuKeySym) && !menuRecursion) { + menuRecursion = true; + popupContextMenu(); + menuRecursion = false; + return; + } + + if (viewOnly) + return; + +#ifdef __APPLE__ + // Alt on OS X behaves more like AltGr on other systems, and to get + // sane behaviour we should translate things in that manner for the + // remote VNC server. However that means we lose the ability to use + // Alt as a shortcut modifier. Do what RealVNC does and hijack the + // left command key as an Alt replacement. + switch (keySym) { + case XK_Super_L: + keySym = XK_Alt_L; + break; + case XK_Super_R: + keySym = XK_Super_L; + break; + case XK_Alt_L: + case XK_Alt_R: + keySym = XK_ISO_Level3_Shift; + break; + } +#endif + +#ifdef WIN32 + // Ugly hack alert! + // + // Windows doesn't have a proper AltGr, but handles it using fake + // Ctrl+Alt. Unfortunately X11 doesn't generally like the combination + // Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to + // get everything in the correct state. Cheat and temporarily release + // Ctrl and Alt when we send some other symbol. + bool ctrlPressed, altPressed; + DownMap::iterator iter; + + ctrlPressed = false; + altPressed = false; + for (iter = downKeySym.begin();iter != downKeySym.end();++iter) { + if (iter->second == XK_Control_L) + ctrlPressed = true; + else if (iter->second == XK_Alt_R) + altPressed = true; + } + + if (ctrlPressed && altPressed) { + vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)"); + try { + cc->writer()->keyEvent(XK_Control_L, false); + cc->writer()->keyEvent(XK_Alt_R, false); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + } +#endif + + // Because of the way keyboards work, we cannot expect to have the same + // symbol on release as when pressed. This breaks the VNC protocol however, + // so we need to keep track of what keysym a key _code_ generated on press + // and send the same on release. + downKeySym[keyCode] = keySym; + +#if defined(WIN32) || defined(__APPLE__) + vlog.debug("Key pressed: 0x%04x => 0x%04x", keyCode, keySym); +#else + vlog.debug("Key pressed: 0x%04x => XK_%s (0x%04x)", + keyCode, XKeysymToString(keySym), keySym); +#endif + + try { + cc->writer()->keyEvent(keySym, true); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + +#ifdef WIN32 + // Ugly hack continued... + if (ctrlPressed && altPressed) { + vlog.debug("Restoring AltGr state"); + try { + cc->writer()->keyEvent(XK_Control_L, true); + cc->writer()->keyEvent(XK_Alt_R, true); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + } +#endif +} + + +void Viewport::handleKeyRelease(int keyCode) +{ + DownMap::iterator iter; + + if (viewOnly) + return; + + iter = downKeySym.find(keyCode); + if (iter == downKeySym.end()) { + // These occur somewhat frequently so let's not spam them unless + // logging is turned up. + vlog.debug("Unexpected release of key code %d", keyCode); + return; + } + +#if defined(WIN32) || defined(__APPLE__) + vlog.debug("Key released: 0x%04x => 0x%04x", keyCode, iter->second); +#else + vlog.debug("Key released: 0x%04x => XK_%s (0x%04x)", + keyCode, XKeysymToString(iter->second), iter->second); +#endif + + try { + cc->writer()->keyEvent(iter->second, false); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + + downKeySym.erase(iter); +} + + +rdr::U32 Viewport::translateKeyEvent(void) { unsigned ucs; + int keyCode, origKeyCode; + const char *keyText; + int keyTextLen; + + keyCode = Fl::event_key(); + origKeyCode = Fl::event_original_key(); + keyText = Fl::event_text(); + keyTextLen = Fl::event_length(); + + vlog.debug("FLTK key %d (%d) '%s'[%d]", origKeyCode, keyCode, keyText, keyTextLen); // First check for function keys if ((keyCode > FL_F) && (keyCode <= FL_F_Last)) @@ -541,23 +675,6 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k } } -#ifdef __APPLE__ - // Alt on OS X behaves more like AltGr on other systems, and to get - // sane behaviour we should translate things in that manner for the - // remote VNC server. However that means we lose the ability to use - // Alt as a shortcut modifier. Do what RealVNC does and hijack the - // left command key as an Alt replacement. - switch (keyCode) { - case FL_Meta_L: - return XK_Alt_L; - case FL_Meta_R: - return XK_Super_L; - case FL_Alt_L: - case FL_Alt_R: - return XK_ISO_Level3_Shift; - } -#endif - #if defined(WIN32) || defined(__APPLE__) // X11 fairly consistently uses XK_KP_Separator for comma and // XK_KP_Decimal for period. Windows and OS X are a different matter @@ -722,113 +839,15 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k } -void Viewport::handleKeyEvent(int keyCode, int origKeyCode, const char *keyText, bool down) +void Viewport::handleFLTKKeyPress(void) { rdr::U32 keySym; - if (viewOnly) - return; - - // Because of the way keyboards work, we cannot expect to have the same - // symbol on release as when pressed. This breaks the VNC protocol however, - // so we need to keep track of what keysym a key _code_ generated on press - // and send the same on release. - if (!down) { - DownMap::iterator iter; - - iter = downKeySym.find(origKeyCode); - if (iter == downKeySym.end()) { - vlog.error(_("Unexpected release of FLTK key code %d (0x%04x)"), - origKeyCode, origKeyCode); - return; - } - - vlog.debug("Key released: 0x%04x => 0x%04x", origKeyCode, iter->second); - - try { - cc->writer()->keyEvent(iter->second, false); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - - downKeySym.erase(iter); - - return; - } - - keySym = translateKeyEvent(keyCode, origKeyCode, keyText); + keySym = translateKeyEvent(); if (keySym == NoSymbol) return; -#ifdef WIN32 - // Ugly hack alert! - // - // Windows doesn't have a proper AltGr, but handles it using fake - // Ctrl+Alt. Unfortunately X11 doesn't generally like the combination - // Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to - // get everything in the correct state. Cheat and temporarily release - // Ctrl and Alt whenever we get a key with a symbol. - bool need_cheat = true; - - if (keyText[0] == '\0') - need_cheat = false; - else if ((downKeySym.find(FL_Control_L) == downKeySym.end()) && - (downKeySym.find(FL_Control_R) == downKeySym.end())) - need_cheat = false; - else if ((downKeySym.find(FL_Alt_L) == downKeySym.end()) && - (downKeySym.find(FL_Alt_R) == downKeySym.end())) - need_cheat = false; - - if (need_cheat) { - vlog.debug("Faking release of AltGr (Ctrl+Alt)"); - try { - if (downKeySym.find(FL_Control_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_L, false); - if (downKeySym.find(FL_Control_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_R, false); - if (downKeySym.find(FL_Alt_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_L, false); - if (downKeySym.find(FL_Alt_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_R, false); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - } -#endif - - vlog.debug("Key pressed: 0x%04x (0x%04x) '%s' => 0x%04x", - origKeyCode, keyCode, keyText, keySym); - - downKeySym[origKeyCode] = keySym; - - try { - cc->writer()->keyEvent(keySym, down); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - -#ifdef WIN32 - // Ugly hack continued... - if (need_cheat) { - vlog.debug("Restoring AltGr state"); - try { - if (downKeySym.find(FL_Control_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_L, true); - if (downKeySym.find(FL_Control_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_R, true); - if (downKeySym.find(FL_Alt_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_L, true); - if (downKeySym.find(FL_Alt_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_R, true); - } catch (rdr::Exception& e) { - vlog.error(e.str()); - exit_vncviewer(e.str()); - } - } -#endif + handleKeyPress(Fl::event_original_key(), keySym); } @@ -853,7 +872,7 @@ void Viewport::initContextMenu() contextMenu->add(_("Alt"), 0, NULL, (void*)ID_ALT, FL_MENU_TOGGLE | (menuAltKey?FL_MENU_VALUE:0)); - if (menuKeyCode) { + if (menuKeySym) { char sendMenuKey[64]; snprintf(sendMenuKey, 64, _("Send %s"), (const char *)menuKey); contextMenu->add(sendMenuKey, 0, NULL, (void*)ID_MENUKEY, 0); @@ -922,25 +941,31 @@ void Viewport::popupContextMenu() window()->size(w(), h()); break; case ID_CTRL: - handleKeyEvent(FL_Control_L, FL_Control_L, "", m->value()); + if (m->value()) + handleKeyPress(fakeKeyBase + 0, XK_Control_L); + else + handleKeyRelease(fakeKeyBase + 0); menuCtrlKey = !menuCtrlKey; break; case ID_ALT: - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", m->value()); + if (m->value()) + handleKeyPress(fakeKeyBase + 1, XK_Alt_L); + else + handleKeyRelease(fakeKeyBase + 1); menuAltKey = !menuAltKey; break; case ID_MENUKEY: - handleKeyEvent(menuKeyCode, menuKeyCode, "", true); - handleKeyEvent(menuKeyCode, menuKeyCode, "", false); + handleKeyPress(fakeKeyBase + 2, menuKeySym); + handleKeyRelease(fakeKeyBase + 2); break; case ID_CTRLALTDEL: - handleKeyEvent(FL_Control_L, FL_Control_L, "", true); - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", true); - handleKeyEvent(FL_Delete, FL_Delete, "", true); + handleKeyPress(fakeKeyBase + 3, XK_Control_L); + handleKeyPress(fakeKeyBase + 4, XK_Alt_L); + handleKeyPress(fakeKeyBase + 5, XK_Delete); - handleKeyEvent(FL_Delete, FL_Delete, "", false); - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", false); - handleKeyEvent(FL_Control_L, FL_Control_L, "", false); + handleKeyRelease(fakeKeyBase + 5); + handleKeyRelease(fakeKeyBase + 4); + handleKeyRelease(fakeKeyBase + 3); break; case ID_REFRESH: cc->refreshFramebuffer(); @@ -966,7 +991,7 @@ void Viewport::popupContextMenu() void Viewport::setMenuKey() { - menuKeyCode = getMenuKeyCode(); + getMenuKey(&menuKeyCode, &menuKeySym); } diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index 0523cd1412..d9eea353ba 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -70,8 +70,11 @@ class Viewport : public Fl_Widget { void handlePointerEvent(const rfb::Point& pos, int buttonMask); static void handlePointerTimeout(void *data); - rdr::U32 translateKeyEvent(int keyCode, int origKeyCode, const char *keyText); - void handleKeyEvent(int keyCode, int origKeyCode, const char *keyText, bool down); + void handleKeyPress(int keyCode, rdr::U32 keySym); + void handleKeyRelease(int keyCode); + + rdr::U32 translateKeyEvent(void); + void handleFLTKKeyPress(void); void initContextMenu(); void popupContextMenu(); @@ -91,6 +94,7 @@ class Viewport : public Fl_Widget { typedef std::map DownMap; DownMap downKeySym; + rdr::U32 menuKeySym; int menuKeyCode; Fl_Menu_Button *contextMenu; diff --git a/vncviewer/menukey.cxx b/vncviewer/menukey.cxx index 2e3a568a0a..9c52f5e729 100644 --- a/vncviewer/menukey.cxx +++ b/vncviewer/menukey.cxx @@ -20,31 +20,37 @@ #include #include +// FLTK can pull in the X11 headers on some systems +#ifndef XK_VoidSymbol +#define XK_MISCELLANY +#include +#endif + #include "menukey.h" #include "parameters.h" static const MenuKeySymbol menuSymbols[] = { - {"F1", FL_F + 1}, - {"F2", FL_F + 2}, - {"F3", FL_F + 3}, - {"F4", FL_F + 4}, - {"F5", FL_F + 5}, - {"F6", FL_F + 6}, - {"F7", FL_F + 7}, - {"F8", FL_F + 8}, - {"F9", FL_F + 9}, - {"F10", FL_F + 10}, - {"F11", FL_F + 11}, - {"F12", FL_F + 12}, - {"Pause", FL_Pause}, - {"Print", FL_Print}, - {"Scroll_Lock", FL_Scroll_Lock}, - {"Escape", FL_Escape}, - {"Insert", FL_Insert}, - {"Delete", FL_Delete}, - {"Home", FL_Home}, - {"Page_Up", FL_Page_Up}, - {"Page_Down", FL_Page_Down}, + {"F1", FL_F + 1, XK_F1}, + {"F2", FL_F + 2, XK_F2}, + {"F3", FL_F + 3, XK_F3}, + {"F4", FL_F + 4, XK_F4}, + {"F5", FL_F + 5, XK_F5}, + {"F6", FL_F + 6, XK_F6}, + {"F7", FL_F + 7, XK_F7}, + {"F8", FL_F + 8, XK_F8}, + {"F9", FL_F + 9, XK_F9}, + {"F10", FL_F + 10, XK_F10}, + {"F11", FL_F + 11, XK_F11}, + {"F12", FL_F + 12, XK_F12}, + {"Pause", FL_Pause, XK_Pause}, + {"Print", FL_Print, XK_Print}, + {"Scroll_Lock", FL_Scroll_Lock, XK_Scroll_Lock}, + {"Escape", FL_Escape, XK_Escape}, + {"Insert", FL_Insert, XK_Insert}, + {"Delete", FL_Delete, XK_Delete}, + {"Home", FL_Home, XK_Home}, + {"Page_Up", FL_Page_Up, XK_Page_Up}, + {"Page_Down", FL_Page_Down, XK_Page_Down}, }; int getMenuKeySymbolCount() @@ -57,15 +63,19 @@ const MenuKeySymbol* getMenuKeySymbols() return menuSymbols; } -int getMenuKeyCode() +void getMenuKey(int *keycode, rdr::U32 *keysym) { - const char *menuKeyStr; - int menuKeyCode = 0; + const char *menuKeyStr; - menuKeyStr = menuKey; - for(int i = 0; i < getMenuKeySymbolCount(); i++) - if (!strcmp(menuSymbols[i].name, menuKeyStr)) - menuKeyCode = menuSymbols[i].keycode; + menuKeyStr = menuKey; + for(int i = 0; i < getMenuKeySymbolCount(); i++) { + if (!strcmp(menuSymbols[i].name, menuKeyStr)) { + *keycode = menuSymbols[i].keycode; + *keysym = menuSymbols[i].keysym; + return; + } + } - return menuKeyCode; + *keycode = 0; + *keysym = 0; } diff --git a/vncviewer/menukey.h b/vncviewer/menukey.h index ecb46ed656..fcc5135323 100644 --- a/vncviewer/menukey.h +++ b/vncviewer/menukey.h @@ -18,12 +18,15 @@ #ifndef __KEYSYM_H__ #define __KEYSYM_H__ +#include + typedef struct { const char* name; int keycode; + rdr::U32 keysym; } MenuKeySymbol; -int getMenuKeyCode(); +void getMenuKey(int *keycode, rdr::U32 *keysym); int getMenuKeySymbolCount(); const MenuKeySymbol* getMenuKeySymbols(); From 13a809a6baca9572ab4a9cb992121fbc4e4ffba6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 22 Aug 2014 15:09:54 +0200 Subject: [PATCH 08/19] Attempt to handle Ctrl+key Hacky attempt to try to figure out the actual key pressed when FLTK is giving us control codes. --- vncviewer/Viewport.cxx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 2209fe5863..16b34e6cb1 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -30,6 +30,7 @@ // FLTK can pull in the X11 headers on some systems #ifndef XK_VoidSymbol +#define XK_LATIN1 #define XK_MISCELLANY #define XK_XKB_KEYS #include @@ -821,11 +822,26 @@ rdr::U32 Viewport::translateKeyEvent(void) } // Unknown special key? - if (keyText[0] == '\0') { + if (keyTextLen == 0) { vlog.error(_("Unknown FLTK key code %d (0x%04x)"), keyCode, keyCode); return NoSymbol; } + // Control character? + if ((keyTextLen == 1) && ((keyText[0] < 0x20) | (keyText[0] == 0x7f))) { + if (keyText[0] == 0x00) + return XK_2; + else if (keyText[0] < 0x1b) { + if (!!Fl::event_state(FL_SHIFT) != !!Fl::event_state(FL_CAPS_LOCK)) + return keyText[0] + XK_A - 0x01; + else + return keyText[0] + XK_a - 0x01; + } else if (keyText[0] < 0x20) + return keyText[0] + XK_3 - 0x1b; + else + return XK_8; + } + // Look up the symbol the key produces and translate that from Unicode // to a X11 keysym. if (fl_utf_nb_char((const unsigned char*)keyText, strlen(keyText)) != 1) { From 827892aba229e49d20a98a17ec8eae78591738e3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:35:51 +0200 Subject: [PATCH 09/19] Better codepoint for combining ypogegrammeni (dead iota) --- vncviewer/keysym2ucs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vncviewer/keysym2ucs.c b/vncviewer/keysym2ucs.c index 2fd5870655..d82d8c6a8e 100644 --- a/vncviewer/keysym2ucs.c +++ b/vncviewer/keysym2ucs.c @@ -827,7 +827,7 @@ static const struct codepair keysymtab[] = { { 0xfe5a, 0x030c }, /* COMBINING CARON */ { 0xfe5b, 0x0327 }, /* COMBINING CEDILLA */ { 0xfe5c, 0x0328 }, /* COMBINING OGONEK */ - { 0xfe5d, 0x1da5 }, /* MODIFIER LETTER SMALL IOTA */ + { 0xfe5d, 0x0345 }, /* COMBINING GREEK YPOGEGRAMMENI */ { 0xfe5e, 0x3099 }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK */ { 0xfe5f, 0x309a }, /* COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ { 0xfe60, 0x0323 }, /* COMBINING DOT BELOW */ From 796580af8791db18cf95f32784c0270085f0b361 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:36:50 +0200 Subject: [PATCH 10/19] Add helper to get combining codepoint from a spacing character --- vncviewer/keysym2ucs.c | 46 ++++++++++++++++++++++++++++++++++++++++++ vncviewer/keysym2ucs.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/vncviewer/keysym2ucs.c b/vncviewer/keysym2ucs.c index d82d8c6a8e..d91df677ca 100644 --- a/vncviewer/keysym2ucs.c +++ b/vncviewer/keysym2ucs.c @@ -41,6 +41,11 @@ struct codepair { unsigned short ucs; }; +struct combiningpair { + unsigned short spacing; + unsigned short combining; +}; + static const struct codepair keysymtab[] = { { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ @@ -833,6 +838,31 @@ static const struct codepair keysymtab[] = { { 0xfe60, 0x0323 }, /* COMBINING DOT BELOW */ }; +static const struct combiningpair combinetab[] = { + { 0x0060, 0x0300 }, /* GRAVE ACCENT ` COMBINING GRAVE ACCENT */ + { 0x00b4, 0x0301 }, /* ACUTE ACCENT ´ COMBINING ACUTE ACCENT */ + { 0x0027, 0x0301 }, /* APOSTROPHE ' COMBINING ACUTE ACCENT */ + { 0x0384, 0x0301 }, /* GREEK TONOS ΄ COMBINING ACUTE ACCENT */ + { 0x005e, 0x0302 }, /* CIRCUMFLEX ACCENT ^ COMBINING CIRCUMFLEX ACCENT */ + { 0x007e, 0x0303 }, /* TILDE ~ COMBINING TILDE */ + { 0x00af, 0x0304 }, /* MACRON ¯ COMBINING MACRON */ + { 0x02d8, 0x0306 }, /* BREVE ˘ COMBINING BREVE */ + { 0x02d9, 0x0307 }, /* DOT ABOVE ˙ COMBINING DOT ABOVE */ + { 0x00a8, 0x0308 }, /* DIAERESIS ¨ COMBINING DIAERESIS */ + { 0x0022, 0x0308 }, /* QUOTATION MARK " COMBINING DIAERESIS */ + { 0x02da, 0x030a }, /* RING ABOVE ˚ COMBINING RING ABOVE */ + { 0x00b0, 0x030a }, /* DEGREE SIGN ° COMBINING RING ABOVE */ + { 0x02dd, 0x030b }, /* DOUBLE ACUTE ACCENT ˝ COMBINING DOUBLE ACUTE ACCENT */ + { 0x02c7, 0x030c }, /* CARON ˇ COMBINING CARON */ + { 0x00b8, 0x0327 }, /* CEDILLA ¸ COMBINING CEDILLA */ + { 0x02db, 0x0328 }, /* OGONEK ¸ COMBINING OGONEK */ + { 0x037a, 0x0345 }, /* GREEK YPOGEGRAMMENI ͺ COMBINING GREEK YPOGEGRAMMENI */ + { 0x309b, 0x3099 }, /* KATAKANA-HIRAGANA VOICED SOUND MARK ゛COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x309c, 0x309a }, /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK ゜COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x002e, 0x0323 }, /* FULL STOP . COMBINING DOT BELOW */ + { 0x0385, 0x0344 }, /* GREEK DIALYTIKA TONOS ΅ COMBINING GREEK DIALYTIKA TONOS */ +}; + unsigned keysym2ucs(unsigned keysym) { int min = 0; @@ -890,3 +920,19 @@ unsigned ucs2keysym(unsigned ucs) /* no matching keysym value found */ return NoSymbol; } + +unsigned ucs2combining(unsigned spacing) +{ + int cur = 0; + int max = sizeof(combinetab) / sizeof(struct combiningpair) - 1; + + /* linear search in table */ + while (cur <= max) { + if (combinetab[cur].spacing == spacing) + return combinetab[cur].combining; + cur++; + } + + /* no matching Unicode value found */ + return -1; +} diff --git a/vncviewer/keysym2ucs.h b/vncviewer/keysym2ucs.h index a09165b9b4..01a7ddb0f4 100644 --- a/vncviewer/keysym2ucs.h +++ b/vncviewer/keysym2ucs.h @@ -10,6 +10,8 @@ extern "C" { unsigned keysym2ucs(unsigned keysym); unsigned ucs2keysym(unsigned ucs); +unsigned ucs2combining(unsigned spacing); + #ifdef __cplusplus } #endif From 4f3ac69a11b98aa7eea88a6336140bced4c66eae Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 22 Aug 2014 15:10:22 +0200 Subject: [PATCH 11/19] Add xhandler hook Boiler plate code to intercept system events from FLTK so that we can generate proper keyboard messages. --- CMakeLists.txt | 3 + config.h.in | 1 + contrib/fltk/12-fltk-1.3.2-xhandlers.patch | 194 +++++++++++++++++++++ vncviewer/Viewport.cxx | 31 ++++ vncviewer/Viewport.h | 2 + 5 files changed, 231 insertions(+) create mode 100644 contrib/fltk/12-fltk-1.3.2-xhandlers.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index 30520a51d8..f5a016ace3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,9 @@ if(FLTK_FOUND) # FLTK STR #2860 check_cxx_source_compiles("#include \nint main(int c, char** v) { void (Fl_Window::*foo)(int,int,int,int) = &Fl_Window::fullscreen_screens; return 0; }" HAVE_FLTK_FULLSCREEN_SCREENS) + # FLTK STR #xxxx + check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_xhandler(NULL, NULL); return 0; }" HAVE_FLTK_XHANDLERS) + set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) endif() diff --git a/config.h.in b/config.h.in index a88c31c591..bac626b7f6 100644 --- a/config.h.in +++ b/config.h.in @@ -17,6 +17,7 @@ #cmakedefine HAVE_FLTK_CURSOR #cmakedefine HAVE_FLTK_WORK_AREA #cmakedefine HAVE_FLTK_ICONS +#cmakedefine HAVE_FLTK_XHANDLERS #cmakedefine HAVE_ACTIVE_DESKTOP_H #cmakedefine HAVE_ACTIVE_DESKTOP_L #cmakedefine ENABLE_NLS 1 diff --git a/contrib/fltk/12-fltk-1.3.2-xhandlers.patch b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch new file mode 100644 index 0000000000..cf6cefbfe6 --- /dev/null +++ b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch @@ -0,0 +1,194 @@ +diff -up fltk-1.3.2/FL/Fl.H.xhandlers fltk-1.3.2/FL/Fl.H +--- fltk-1.3.2/FL/Fl.H.xhandlers 2014-07-22 15:23:18.087334467 +0200 ++++ fltk-1.3.2/FL/Fl.H 2014-07-22 15:23:18.094334589 +0200 +@@ -96,6 +96,9 @@ typedef void (*Fl_FD_Handler)(FL_SOCKET + /** Signature of add_handler functions passed as parameters */ + typedef int (*Fl_Event_Handler)(int event); + ++/** Signature of add_xhandler functions passed as parameters */ ++typedef bool (*Fl_XEvent_Handler)(void *event, void *data); ++ + /** Signature of set_abort functions passed as parameters */ + typedef void (*Fl_Abort_Handler)(const char *format,...); + +@@ -712,6 +715,8 @@ public: + static void focus(Fl_Widget*); + static void add_handler(Fl_Event_Handler h); + static void remove_handler(Fl_Event_Handler h); ++ static void add_xhandler(Fl_XEvent_Handler h, void *data); ++ static void remove_xhandler(Fl_XEvent_Handler h); + static void event_dispatch(Fl_Event_Dispatch d); + static Fl_Event_Dispatch event_dispatch(); + /** @} */ +diff -up fltk-1.3.2/src/Fl_cocoa.mm.xhandlers fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2/src/Fl_cocoa.mm.xhandlers 2014-07-22 15:23:18.089334502 +0200 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2014-07-22 15:23:18.095334607 +0200 +@@ -1269,6 +1269,8 @@ void fl_open_callback(void (*cb)(const c + } + @end + ++extern bool fl_send_xhandlers(void *e); ++ + static void clipboard_check(void); + + @implementation FLApplication +@@ -1276,6 +1278,10 @@ static void clipboard_check(void); + { + // update clipboard status + clipboard_check(); ++ ++ if (fl_send_xhandlers(theEvent)) ++ return; ++ + NSEventType type = [theEvent type]; + if (type == NSLeftMouseDown) { + fl_lock_function(); +diff -up fltk-1.3.2/src/Fl.cxx.xhandlers fltk-1.3.2/src/Fl.cxx +--- fltk-1.3.2/src/Fl.cxx.xhandlers 2014-07-22 15:23:18.085334432 +0200 ++++ fltk-1.3.2/src/Fl.cxx 2014-07-22 15:23:18.095334607 +0200 +@@ -891,6 +891,67 @@ static int send_handlers(int e) { + return 0; + } + ++ ++//////////////////////////////////////////////////////////////// ++// System event handlers: ++ ++ ++struct xhandler_link { ++ Fl_XEvent_Handler handle; ++ void *data; ++ xhandler_link *next; ++}; ++ ++ ++static xhandler_link *xhandlers = 0; ++ ++ ++/** ++ Install a function to intercept system events. FLTK calls each of ++ these functions as soon as a new system event is received. The ++ processing will stop at the first function to return true. If all ++ functions return false then the event is passed on for normal ++ handling by FLTK. ++ ++ \see Fl::remove_xhandler(Fl_XEvent_Handler) ++*/ ++void Fl::add_xhandler(Fl_XEvent_Handler ha, void *data) { ++ xhandler_link *l = new xhandler_link; ++ l->handle = ha; ++ l->data = data; ++ l->next = xhandlers; ++ xhandlers = l; ++} ++ ++ ++/** ++ Removes a previously added system event handler. ++*/ ++void Fl::remove_xhandler(Fl_XEvent_Handler ha) { ++ xhandler_link *l, *p; ++ ++ // Search for the handler in the list... ++ for (l = xhandlers, p = 0; l && l->handle != ha; p = l, l = l->next); ++ ++ if (l) { ++ // Found it, so remove it from the list... ++ if (p) p->next = l->next; ++ else xhandlers = l->next; ++ ++ // And free the record... ++ delete l; ++ } ++} ++ ++bool fl_send_xhandlers(void *e) { ++ for (const xhandler_link *hl = xhandlers; hl; hl = hl->next) { ++ if (hl->handle(e, hl->data)) ++ return true; ++ } ++ return false; ++} ++ ++ + //////////////////////////////////////////////////////////////// + + Fl_Widget* fl_oldfocus; // kludge for Fl_Group... +diff -up fltk-1.3.2/src/Fl_win32.cxx.xhandlers fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2/src/Fl_win32.cxx.xhandlers 2014-07-22 15:23:18.092334554 +0200 ++++ fltk-1.3.2/src/Fl_win32.cxx 2014-07-22 15:24:44.682843610 +0200 +@@ -336,6 +336,8 @@ void* Fl::thread_message() { + return r; + } + ++extern bool fl_send_xhandlers(void *e); ++ + IActiveIMMApp *fl_aimm = NULL; + MSG fl_msg; + +@@ -401,26 +403,25 @@ int fl_wait(double time_to_wait) { + + // Execute the message we got, and all other pending messages: + // have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); +- have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); +- if (have_message > 0) { +- while (have_message != 0 && have_message != -1) { +- // Let applications treat WM_QUIT identical to SIGTERM on *nix +- if (fl_msg.message == WM_QUIT) +- raise(SIGTERM); +- if (fl_msg.message == fl_wake_msg) { +- // Used for awaking wait() from another thread +- thread_message_ = (void*)fl_msg.wParam; +- Fl_Awake_Handler func; +- void *data; +- while (Fl::get_awake_handler_(func, data)==0) { +- func(data); +- } +- } +- +- TranslateMessage(&fl_msg); +- DispatchMessageW(&fl_msg); +- have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); ++ while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) { ++ if (fl_send_xhandlers(&fl_msg)) ++ continue; ++ ++ // Let applications treat WM_QUIT identical to SIGTERM on *nix ++ if (fl_msg.message == WM_QUIT) ++ raise(SIGTERM); ++ ++ if (fl_msg.message == fl_wake_msg) { ++ // Used for awaking wait() from another thread ++ thread_message_ = (void*)fl_msg.wParam; ++ Fl_Awake_Handler func; ++ void *data; ++ while (Fl::get_awake_handler_(func, data)==0) ++ func(data); + } ++ ++ TranslateMessage(&fl_msg); ++ DispatchMessageW(&fl_msg); + } + Fl::flush(); + +diff -up fltk-1.3.2/src/Fl_x.cxx.xhandlers fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.xhandlers 2014-07-22 15:23:18.093334572 +0200 ++++ fltk-1.3.2/src/Fl_x.cxx 2014-07-22 15:23:18.096334624 +0200 +@@ -188,6 +188,8 @@ void Fl::remove_fd(int n) { + remove_fd(n, -1); + } + ++extern bool fl_send_xhandlers(void *e); ++ + #if CONSOLIDATE_MOTION + static Fl_Window* send_motion; + extern Fl_Window* fl_xmousewin; +@@ -198,6 +200,8 @@ static void do_queued_events() { + while (XEventsQueued(fl_display,QueuedAfterReading)) { + XEvent xevent; + XNextEvent(fl_display, &xevent); ++ if (fl_send_xhandlers(&xevent)) ++ continue; + fl_handle(xevent); + } + // we send FL_LEAVE only if the mouse did not enter some other window: diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 16b34e6cb1..2b22a97387 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -100,6 +100,11 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) Fl::add_clipboard_notify(handleClipboardChange, this); #endif +#ifdef HAVE_FLTK_XHANDLERS + // We need to intercept keyboard events early + Fl::add_xhandler(handleXEvent, this); +#endif + frameBuffer = createFramebuffer(w, h); assert(frameBuffer); @@ -132,6 +137,10 @@ Viewport::~Viewport() // again later when this object is already gone. Fl::remove_timeout(handlePointerTimeout, this); +#ifdef HAVE_FLTK_XHANDLERS + Fl::remove_xhandler(handleXEvent); +#endif + #ifdef HAVE_FLTK_CLIPBOARD Fl::remove_clipboard_notify(handleClipboardChange); #endif @@ -620,6 +629,28 @@ void Viewport::handleKeyRelease(int keyCode) } +bool Viewport::handleXEvent(void *event, void *data) +{ + Viewport *self = (Viewport *)data; + Fl_Widget *focus; + + assert(self); + + focus = Fl::grab(); + if (!focus) + focus = Fl::focus(); + if (!focus) + return false; + + if (focus != self) + return false; + + assert(event); + + return false; +} + + rdr::U32 Viewport::translateKeyEvent(void) { unsigned ucs; diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index d9eea353ba..30dacad453 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -73,6 +73,8 @@ class Viewport : public Fl_Widget { void handleKeyPress(int keyCode, rdr::U32 keySym); void handleKeyRelease(int keyCode); + static bool handleXEvent(void *event, void *data); + rdr::U32 translateKeyEvent(void); void handleFLTKKeyPress(void); From 6b9622db86bf4e35f8e5baf1be2321401659a42d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:42:12 +0200 Subject: [PATCH 12/19] Add X11 keyboard handler --- vncviewer/Viewport.cxx | 41 +++++++++++++++++++++++++++++++++++++++++ vncviewer/vncviewer.cxx | 10 ++++++++++ 2 files changed, 51 insertions(+) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 2b22a97387..0f627229b4 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -647,6 +647,47 @@ bool Viewport::handleXEvent(void *event, void *data) assert(event); +#if !defined(WIN32) && !defined(__APPLE__) + XEvent *xevent = (XEvent*)event; + + if (xevent->type == KeyPress) { + char str; + KeySym keysym; + + XLookupString(&xevent->xkey, &str, 1, &keysym, NULL); + if (keysym == NoSymbol) { + vlog.error(_("No symbol for key code %d (in the current state)"), + (int)xevent->xkey.keycode); + return true; + } + + switch (keysym) { + // For the first few years, there wasn't a good consensus on what the + // Windows keys should be mapped to for X11. So we need to help out a + // bit and map all variants to the same key... + case XK_Meta_L: + case XK_Hyper_L: + keysym = XK_Super_L; + break; + case XK_Meta_R: + case XK_Hyper_R: + keysym = XK_Super_R; + break; + // There has been several variants for Shift-Tab over the years. + // RFB states that we should always send a normal tab. + case XK_ISO_Left_Tab: + keysym = XK_Tab; + break; + } + + self->handleKeyPress(xevent->xkey.keycode, keysym); + return true; + } else if (xevent->type == KeyRelease) { + self->handleKeyRelease(xevent->xkey.keycode); + return true; + } +#endif + return false; } diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx index 3f0393793f..82286ab89f 100644 --- a/vncviewer/vncviewer.cxx +++ b/vncviewer/vncviewer.cxx @@ -36,6 +36,11 @@ #define mkdir(path, mode) _mkdir(path) #endif +#if !defined(WIN32) && !defined(__APPLE__) +#include +#include +#endif + #include #include #include @@ -386,6 +391,11 @@ int main(int argc, char** argv) init_fltk(); +#if !defined(WIN32) && !defined(__APPLE__) + fl_open_display(); + XkbSetDetectableAutoRepeat(fl_display, True, NULL); +#endif + Configuration::enableViewerParams(); /* Load the default parameter settings */ From 2e9684f12b106a1304121ca22aef5df0688e1bbf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:46:22 +0200 Subject: [PATCH 13/19] Add Windows keyboard handler --- vncviewer/Viewport.cxx | 63 +++++++++++++- vncviewer/win32.c | 186 +++++++++++++++++++++++++++++++++++++++++ vncviewer/win32.h | 2 + 3 files changed, 250 insertions(+), 1 deletion(-) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 0f627229b4..e183939dfb 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -44,6 +44,11 @@ #define NoSymbol 0 #endif +// Missing in at least some versions of MinGW +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + #include "Viewport.h" #include "CConn.h" #include "OptionsDialog.h" @@ -647,7 +652,63 @@ bool Viewport::handleXEvent(void *event, void *data) assert(event); -#if !defined(WIN32) && !defined(__APPLE__) +#if defined(WIN32) + MSG *msg = (MSG*)event; + + if ((msg->message == WM_KEYDOWN) || (msg->message == WM_SYSKEYDOWN)) { + UINT vKey; + bool isExtended; + int keyCode; + rdr::U32 keySym; + + vKey = msg->wParam; + isExtended = (msg->lParam & (1 << 24)) != 0; + + keyCode = ((msg->lParam >> 16) & 0xff); + + // Windows sets the scan code to 0x00 for multimedia keys, so we + // have to do a reverse lookup based on the vKey. + if (keyCode == 0x00) { + keyCode = MapVirtualKey(vKey, MAPVK_VK_TO_VSC); + if (keyCode == 0x00) { + vlog.error(_("No scan code for %svirtual key 0x%02x"), + isExtended?"extended ":"", (int)vKey); + return true; + } + } + + if (isExtended) + keyCode |= 0x100; + + keySym = win32_vkey_to_keysym(vKey, isExtended); + if (keySym == NoSymbol) { + vlog.error(_("No symbol for %svirtual key 0x%02x"), + isExtended?"extended ":"", (int)vKey); + return true; + } + + self->handleKeyPress(keyCode, keySym); + + return true; + } else if ((msg->message == WM_KEYUP) || (msg->message == WM_SYSKEYUP)) { + UINT vKey; + bool isExtended; + int keyCode; + + vKey = msg->wParam; + isExtended = (msg->lParam & (1 << 24)) != 0; + + keyCode = ((msg->lParam >> 16) & 0xff); + if (keyCode == 0x00) + keyCode = MapVirtualKey(vKey, MAPVK_VK_TO_VSC); + if (isExtended) + keyCode |= 0x100; + + self->handleKeyRelease(keyCode); + + return true; + } +#elif !defined(__APPLE__) XEvent *xevent = (XEvent*)event; if (xevent->type == KeyPress) { diff --git a/vncviewer/win32.c b/vncviewer/win32.c index d75cc57898..cf4dc49a68 100644 --- a/vncviewer/win32.c +++ b/vncviewer/win32.c @@ -19,6 +19,20 @@ #include +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include +#include + +#include "keysym2ucs.h" + +#define NoSymbol 0 + +// Missing in at least some versions of MinGW +#ifndef MAPVK_VK_TO_CHAR +#define MAPVK_VK_TO_CHAR 2 +#endif + static HANDLE thread; static DWORD thread_id; @@ -113,3 +127,175 @@ void win32_disable_lowlevel_keyboard(HWND hwnd) CloseHandle(thread); thread = NULL; } + +static const int vkey_map[][3] = { + { VK_BACK, XK_BackSpace, NoSymbol }, + { VK_TAB, XK_Tab, NoSymbol }, + { VK_CLEAR, XK_Clear, NoSymbol }, + { VK_RETURN, XK_Return, XK_KP_Enter }, + { VK_SHIFT, XK_Shift_L, NoSymbol }, + { VK_CONTROL, XK_Control_L, XK_Control_R }, + { VK_MENU, XK_Alt_L, XK_Alt_R }, + { VK_PAUSE, XK_Pause, NoSymbol }, + { VK_CAPITAL, XK_Caps_Lock, NoSymbol }, + /* FIXME: IME keys */ + { VK_ESCAPE, XK_Escape, NoSymbol }, + { VK_PRIOR, XK_KP_Prior, XK_Prior }, + { VK_NEXT, XK_KP_Next, XK_Next }, + { VK_END, XK_KP_End, XK_End }, + { VK_HOME, XK_KP_Home, XK_Home }, + { VK_LEFT, XK_KP_Left, XK_Left }, + { VK_UP, XK_KP_Up, XK_Up }, + { VK_RIGHT, XK_KP_Right, XK_Right }, + { VK_DOWN, XK_KP_Down, XK_Down }, + { VK_SNAPSHOT, XK_Print, NoSymbol }, + { VK_INSERT, XK_KP_Insert, XK_Insert }, + { VK_DELETE, XK_KP_Delete, XK_Delete }, + { VK_LWIN, NoSymbol, XK_Super_L }, + { VK_RWIN, NoSymbol, XK_Super_R }, + { VK_APPS, NoSymbol, XK_Menu }, + { VK_SLEEP, NoSymbol, XF86XK_Sleep }, + { VK_NUMPAD0, XK_KP_0, NoSymbol }, + { VK_NUMPAD1, XK_KP_1, NoSymbol }, + { VK_NUMPAD2, XK_KP_2, NoSymbol }, + { VK_NUMPAD3, XK_KP_3, NoSymbol }, + { VK_NUMPAD4, XK_KP_4, NoSymbol }, + { VK_NUMPAD5, XK_KP_5, NoSymbol }, + { VK_NUMPAD6, XK_KP_6, NoSymbol }, + { VK_NUMPAD7, XK_KP_7, NoSymbol }, + { VK_NUMPAD8, XK_KP_8, NoSymbol }, + { VK_NUMPAD9, XK_KP_9, NoSymbol }, + { VK_MULTIPLY, XK_KP_Multiply, NoSymbol }, + { VK_ADD, XK_KP_Add, NoSymbol }, + { VK_SUBTRACT, XK_KP_Subtract, NoSymbol }, + { VK_DIVIDE, NoSymbol, XK_KP_Divide }, + /* VK_SEPARATOR and VK_DECIMAL left out on purpose. See further down. */ + { VK_F1, XK_F1, NoSymbol }, + { VK_F2, XK_F2, NoSymbol }, + { VK_F3, XK_F3, NoSymbol }, + { VK_F4, XK_F4, NoSymbol }, + { VK_F5, XK_F5, NoSymbol }, + { VK_F6, XK_F6, NoSymbol }, + { VK_F7, XK_F7, NoSymbol }, + { VK_F8, XK_F8, NoSymbol }, + { VK_F9, XK_F9, NoSymbol }, + { VK_F10, XK_F10, NoSymbol }, + { VK_F11, XK_F11, NoSymbol }, + { VK_F12, XK_F12, NoSymbol }, + { VK_F13, XK_F13, NoSymbol }, + { VK_F14, XK_F14, NoSymbol }, + { VK_F15, XK_F15, NoSymbol }, + { VK_F16, XK_F16, NoSymbol }, + { VK_F17, XK_F17, NoSymbol }, + { VK_F18, XK_F18, NoSymbol }, + { VK_F19, XK_F19, NoSymbol }, + { VK_F20, XK_F20, NoSymbol }, + { VK_F21, XK_F21, NoSymbol }, + { VK_F22, XK_F22, NoSymbol }, + { VK_F23, XK_F23, NoSymbol }, + { VK_F24, XK_F24, NoSymbol }, + { VK_NUMLOCK, NoSymbol, XK_Num_Lock }, + { VK_SCROLL, XK_Scroll_Lock, NoSymbol }, + { VK_BROWSER_BACK, NoSymbol, XF86XK_Back }, + { VK_BROWSER_FORWARD, NoSymbol, XF86XK_Forward }, + { VK_BROWSER_REFRESH, NoSymbol, XF86XK_Refresh }, + { VK_BROWSER_STOP, NoSymbol, XF86XK_Stop }, + { VK_BROWSER_SEARCH, NoSymbol, XF86XK_Search }, + { VK_BROWSER_FAVORITES, NoSymbol, XF86XK_Favorites }, + { VK_BROWSER_HOME, NoSymbol, XF86XK_HomePage }, + { VK_VOLUME_MUTE, NoSymbol, XF86XK_AudioMute }, + { VK_VOLUME_DOWN, NoSymbol, XF86XK_AudioLowerVolume }, + { VK_VOLUME_UP, NoSymbol, XF86XK_AudioRaiseVolume }, + { VK_MEDIA_NEXT_TRACK, NoSymbol, XF86XK_AudioNext }, + { VK_MEDIA_PREV_TRACK, NoSymbol, XF86XK_AudioPrev }, + { VK_MEDIA_STOP, NoSymbol, XF86XK_AudioStop }, + { VK_MEDIA_PLAY_PAUSE, NoSymbol, XF86XK_AudioPlay }, + { VK_LAUNCH_MAIL, NoSymbol, XF86XK_Mail }, + { VK_LAUNCH_APP2, NoSymbol, XF86XK_Calculator }, +}; + +int win32_vkey_to_keysym(UINT vkey, int extended) +{ + int i; + + BYTE state[256]; + int ret; + WCHAR wstr[10]; + + // Start with keys that either don't generate a symbol, or + // generate the same symbol as some other key. + for (i = 0;i < sizeof(vkey_map)/sizeof(vkey_map[0]);i++) { + if (vkey == vkey_map[i][0]) { + if (extended) + return vkey_map[i][2]; + else + return vkey_map[i][1]; + } + } + + // Windows is not consistent in which virtual key it uses for + // the numpad decimal key, and this is not likely to be fixed: + // http://blogs.msdn.com/michkap/archive/2006/09/13/752377.aspx + // + // To get X11 behaviour, we instead look at the text generated + // by they key. + if ((vkey == VK_DECIMAL) || (vkey == VK_SEPARATOR)) { + UINT ch; + + ch = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR); + switch (ch) { + case ',': + return XK_KP_Separator; + case '.': + return XK_KP_Decimal; + default: + return NoSymbol; + } + } + + // MapVirtualKey() doesn't look at modifiers, so it is + // insufficient for mapping most keys to a symbol. ToUnicode() + // does what we want though. Unfortunately it keeps state, so + // we have to be careful around dead characters. + + GetKeyboardState(state); + + // Pressing Ctrl wreaks havoc with the symbol lookup, so turn + // that off. But AltGr shows up as Ctrl+Alt in Windows, so keep + // Ctrl if Alt is active. + if (!(state[VK_LCONTROL] & 0x80) || !(state[VK_RMENU] & 0x80)) + state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0; + + // FIXME: Multi character results, like U+0644 U+0627 + // on Arabic layout + ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0); + + if (ret == 0) { + // Most Ctrl+Alt combinations will fail to produce a symbol, so + // try it again with Ctrl unconditionally disabled. + state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0; + ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0); + } + + if (ret == 1) + return ucs2keysym(wstr[0]); + + if (ret == -1) { + WCHAR dead_char; + + dead_char = wstr[0]; + + // Need to clear out the state that the dead key has caused. + // This is the recommended method by Microsoft's engineers: + // http://blogs.msdn.com/b/michkap/archive/2007/10/27/5717859.aspx + do { + ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0); + } while (ret < 0); + + // Dead keys are represented by their spacing equivalent + // (or something similar depending on the layout) + return ucs2keysym(ucs2combining(dead_char)); + } + + return NoSymbol; +} diff --git a/vncviewer/win32.h b/vncviewer/win32.h index 35be77b5d1..014870859f 100644 --- a/vncviewer/win32.h +++ b/vncviewer/win32.h @@ -30,6 +30,8 @@ extern "C" { int win32_enable_lowlevel_keyboard(HWND hwnd); void win32_disable_lowlevel_keyboard(HWND hwnd); +int win32_vkey_to_keysym(UINT vkey, int extended); + }; #endif From 6b743d0c1bf1fe9e11b0ac2cb51ede39fda87362 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:48:43 +0200 Subject: [PATCH 14/19] Add OS X keyboard handler --- vncviewer/Viewport.cxx | 35 +++- vncviewer/cocoa.h | 7 + vncviewer/cocoa.mm | 382 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+), 1 deletion(-) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index e183939dfb..027ca54cce 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -77,10 +77,15 @@ #include #include +#ifdef __APPLE__ +#include "cocoa.h" +#endif + #ifdef WIN32 #include "win32.h" #endif + using namespace rfb; using namespace rdr; @@ -708,7 +713,35 @@ bool Viewport::handleXEvent(void *event, void *data) return true; } -#elif !defined(__APPLE__) +#elif defined(__APPLE__) + if (cocoa_is_keyboard_event(event)) { + int keyCode; + + keyCode = cocoa_event_keycode(event); + + if (cocoa_is_key_press(event)) { + rdr::U32 keySym; + + keySym = cocoa_event_keysym(event); + if (keySym == NoSymbol) { + vlog.error(_("No symbol for key code 0x%02x (in the current state)"), + (int)keyCode); + return true; + } + + self->handleKeyPress(keyCode, keySym); + + // We don't get any release events for CapsLock, so we have to + // send the release right away. + if (keySym == XK_Caps_Lock) + self->handleKeyRelease(keyCode); + } else { + self->handleKeyRelease(keyCode); + } + + return true; + } +#else XEvent *xevent = (XEvent*)event; if (xevent->type == KeyPress) { diff --git a/vncviewer/cocoa.h b/vncviewer/cocoa.h index 8798082339..e9101f34ca 100644 --- a/vncviewer/cocoa.h +++ b/vncviewer/cocoa.h @@ -22,4 +22,11 @@ int cocoa_capture_display(Fl_Window *win, bool all_displays); void cocoa_release_display(Fl_Window *win); +int cocoa_is_keyboard_event(const void *event); + +int cocoa_is_key_press(const void *event); + +int cocoa_event_keycode(const void *event); +int cocoa_event_keysym(const void *event); + #endif diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm index 2b50ecfea1..e9e0968368 100644 --- a/vncviewer/cocoa.mm +++ b/vncviewer/cocoa.mm @@ -25,6 +25,17 @@ #include #import +#import + +#define XK_LATIN1 +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include +#include + +#include "keysym2ucs.h" + +#define NoSymbol 0 static bool captured = false; @@ -100,3 +111,374 @@ void cocoa_release_display(Fl_Window *win) if ([nsw level] != newlevel) [nsw setLevel:newlevel]; } + +int cocoa_is_keyboard_event(const void *event) +{ + NSEvent *nsevent; + + nsevent = (NSEvent*)event; + + switch ([nsevent type]) { + case NSKeyDown: + case NSKeyUp: + case NSFlagsChanged: + return 1; + default: + return 0; + } +} + +int cocoa_is_key_press(const void *event) +{ + NSEvent *nsevent; + + nsevent = (NSEvent*)event; + + if ([nsevent type] == NSKeyDown) + return 1; + + if ([nsevent type] == NSFlagsChanged) { + UInt32 mask; + + // We don't see any event on release of CapsLock + if ([nsevent keyCode] == 0x39) + return 1; + + // These are entirely undocumented, but I cannot find any other way + // of differentiating between left and right keys + switch ([nsevent keyCode]) { + case 0x36: + mask = 0x0010; + break; + case 0x37: + mask = 0x0008; + break; + case 0x38: + mask = 0x0002; + break; + case 0x39: + // We don't see any event on release of CapsLock + return 1; + case 0x3A: + mask = 0x0020; + break; + case 0x3B: + mask = 0x0001; + break; + case 0x3C: + mask = 0x0004; + break; + case 0x3D: + mask = 0x0040; + break; + case 0x3E: + mask = 0x2000; + break; + default: + return 0; + } + + if ([nsevent modifierFlags] & mask) + return 1; + else + return 0; + } + + return 0; +} + +int cocoa_event_keycode(const void *event) +{ + NSEvent *nsevent; + + nsevent = (NSEvent*)event; + + return [nsevent keyCode]; +} + +static NSString *key_translate(UInt16 keyCode, UInt32 modifierFlags) +{ + const UCKeyboardLayout *layout; + OSStatus err; + + layout = NULL; + +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) + TISInputSourceRef keyboard; + CFDataRef uchr; + + keyboard = TISCopyCurrentKeyboardInputSource(); + uchr = (CFDataRef)TISGetInputSourceProperty(keyboard, + kTISPropertyUnicodeKeyLayoutData); + if (uchr == NULL) + return nil; + + layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); +#else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + KeyboardLayoutRef old_layout; + int kind; + + err = KLGetCurrentKeyboardLayout(&old_layout); + if (err != noErr) + return nil; + + err = KLGetKeyboardLayoutProperty(old_layout, kKLKind, + (const void**)&kind); + if (err != noErr) + return nil; + + // Old, crufty layout format? + if (kind == kKLKCHRKind) { + void *kchr_layout; + + UInt32 chars, state; + char buf[3]; + + unichar result[16]; + ByteCount in_len, out_len; + + err = KLGetKeyboardLayoutProperty(old_layout, kKLKCHRData, + (const void**)&kchr_layout); + if (err != noErr) + return nil; + + state = 0; + + keyCode &= 0x7f; + modifierFlags &= 0xff00; + + chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); + + // Dead key? + if (state != 0) { + // We have no fool proof way of asking what dead key this is. + // Assume we get a spacing equivalent if we press the + // same key again, and try to deduce something from that. + chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); + } + + buf[0] = (chars >> 16) & 0xff; + buf[1] = chars & 0xff; + buf[2] = '\0'; + + if (buf[0] == '\0') { + buf[0] = buf[1]; + buf[1] = '\0'; + } + + // The data is now in some layout specific encoding. Need to convert + // this to unicode. + + ScriptCode script; + TextEncoding encoding; + TECObjectRef converter; + + script = (ScriptCode)GetScriptManagerVariable(smKeyScript); + + err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, + &encoding); + if (err != noErr) + return nil; + + err = TECCreateConverter(&converter, encoding, kTextEncodingUnicodeV4_0); + if (err != noErr) + return nil; + + in_len = strlen(buf); + out_len = sizeof(result); + + err = TECConvertText(converter, (ConstTextPtr)buf, in_len, &in_len, + (TextPtr)result, out_len, &out_len); + + TECDisposeConverter(converter); + + if (err != noErr) + return nil; + + return [NSString stringWithCharacters:result + length:(out_len / sizeof(unichar))]; + } + + if ((kind != kKLKCHRuchrKind) && (kind != kKLuchrKind)) + return nil; + + err = KLGetKeyboardLayoutProperty(old_layout, kKLuchrData, + (const void**)&layout); + if (err != noErr) + return nil; +#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + + if (layout == NULL) + return nil; + + UInt32 dead_state; + UniCharCount max_len, actual_len; + UniChar string[255]; + + dead_state = 0; + max_len = sizeof(string)/sizeof(*string); + + modifierFlags = (modifierFlags >> 8) & 0xff; + + err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, + LMGetKbdType(), 0, &dead_state, max_len, &actual_len, + string); + if (err != noErr) + return nil; + + // Dead key? + if (dead_state != 0) { + // We have no fool proof way of asking what dead key this is. + // Assume we get a spacing equivalent if we press the + // same key again, and try to deduce something from that. + err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, + LMGetKbdType(), 0, &dead_state, max_len, &actual_len, + string); + if (err != noErr) + return nil; + } + + return [NSString stringWithCharacters:string length:actual_len]; +} + +// FIXME: We use hard coded values here as the constants didn't appear +// in the OS X headers until 10.5. +static const int kvk_map[][2] = { + { 0x24, XK_Return }, + { 0x30, XK_Tab }, + { 0x31, XK_space }, + { 0x33, XK_BackSpace }, + { 0x35, XK_Escape }, + // This one is undocumented for unknown reasons + { 0x36, XK_Super_R }, + { 0x37, XK_Super_L }, + { 0x38, XK_Shift_L }, + { 0x39, XK_Caps_Lock }, + { 0x3A, XK_Alt_L }, + { 0x3B, XK_Control_L }, + { 0x3C, XK_Shift_R }, + { 0x3D, XK_Alt_R }, + { 0x3E, XK_Control_R }, + { 0x40, XK_F17 }, + { 0x48, XF86XK_AudioRaiseVolume }, + { 0x49, XF86XK_AudioLowerVolume }, + { 0x4A, XF86XK_AudioMute }, + { 0x4F, XK_F18 }, + { 0x50, XK_F19 }, + { 0x5A, XK_F20 }, + { 0x60, XK_F5 }, + { 0x61, XK_F6 }, + { 0x62, XK_F7 }, + { 0x63, XK_F3 }, + { 0x64, XK_F8 }, + { 0x65, XK_F9 }, + { 0x67, XK_F11 }, + { 0x69, XK_F13 }, + { 0x6A, XK_F16 }, + { 0x6B, XK_F14 }, + { 0x6D, XK_F10 }, + // Also undocumented + { 0x6E, XK_Menu }, + { 0x6F, XK_F12 }, + { 0x71, XK_F15 }, + // Should we send Insert here? + { 0x72, XK_Help }, + { 0x73, XK_Home }, + { 0x74, XK_Page_Up }, + { 0x75, XK_Delete }, + { 0x76, XK_F4 }, + { 0x77, XK_End }, + { 0x78, XK_F2 }, + { 0x79, XK_Page_Down }, + { 0x7A, XK_F1 }, + { 0x7B, XK_Left }, + { 0x7C, XK_Right }, + { 0x7D, XK_Down }, + { 0x7E, XK_Up }, + // The OS X headers claim these keys are not layout independent. + // Could it be because of the state of the decimal key? + /* { 0x41, XK_KP_Decimal }, */ // see below + { 0x43, XK_KP_Multiply }, + { 0x45, XK_KP_Add }, + // OS X doesn't have NumLock, so is this really correct? + { 0x47, XK_Num_Lock }, + { 0x4B, XK_KP_Divide }, + { 0x4C, XK_KP_Enter }, + { 0x4E, XK_KP_Subtract }, + { 0x51, XK_KP_Equal }, + { 0x52, XK_KP_0 }, + { 0x53, XK_KP_1 }, + { 0x54, XK_KP_2 }, + { 0x55, XK_KP_3 }, + { 0x56, XK_KP_4 }, + { 0x57, XK_KP_5 }, + { 0x58, XK_KP_6 }, + { 0x59, XK_KP_7 }, + { 0x5B, XK_KP_8 }, + { 0x5C, XK_KP_9 }, +}; + +int cocoa_event_keysym(const void *event) +{ + NSEvent *nsevent; + + UInt16 key_code; + int i; + + NSString *chars; + UInt32 modifiers; + + nsevent = (NSEvent*)event; + + key_code = [nsevent keyCode]; + + // Start with keys that either don't generate a symbol, or + // generate the same symbol as some other key. + for (i = 0;i < sizeof(kvk_map)/sizeof(kvk_map[0]);i++) { + if (key_code == kvk_map[i][0]) + return kvk_map[i][1]; + } + + // OS X always sends the same key code for the decimal key on the + // num pad, but X11 wants different keysyms depending on if it should + // be a comma or full stop. + if (key_code == 0x41) { + switch ([[nsevent charactersIgnoringModifiers] UTF8String][0]) { + case ',': + return XK_KP_Separator; + case '.': + return XK_KP_Decimal; + default: + return NoSymbol; + } + } + + // We want a "normal" symbol out of the event, which basically means + // we only respect the shift and alt/altgr modifiers. Cocoa can help + // us if we only wanted shift, but as we also want alt/altgr, we'll + // have to do some lookup ourselves. This matches our behaviour on + // other platforms. + + modifiers = 0; + if ([nsevent modifierFlags] & NSAlphaShiftKeyMask) + modifiers |= alphaLock; + if ([nsevent modifierFlags] & NSShiftKeyMask) + modifiers |= shiftKey; + if ([nsevent modifierFlags] & NSAlternateKeyMask) + modifiers |= optionKey; + + chars = key_translate(key_code, modifiers); + if (chars == nil) + return NoSymbol; + + // FIXME: Some dead keys are given as NBSP + combining character + if ([chars length] != 1) + return NoSymbol; + + // Dead key? + if ([[nsevent characters] length] == 0) + return ucs2keysym(ucs2combining([chars characterAtIndex:0])); + + return ucs2keysym([chars characterAtIndex:0]); +} From a83c88d513cc639cdf79a1cd7e97cb978001b2ed Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 19 Aug 2014 14:06:53 +0200 Subject: [PATCH 15/19] Ignore FLTK events when we have low level hooks Some events can sneak through, e.g. from some virtual keyboards. We need to ignore these to avoid confusion. --- vncviewer/Viewport.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 027ca54cce..917a981783 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -1025,6 +1025,10 @@ void Viewport::handleFLTKKeyPress(void) { rdr::U32 keySym; +#ifdef HAVE_FLTK_XHANDLERS + return; +#endif + keySym = translateKeyEvent(); if (keySym == NoSymbol) return; From 48ef54d59b7abbc06d660dbfe431708b10d8e3dc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 19 Aug 2014 14:08:04 +0200 Subject: [PATCH 16/19] Disable input methods when the viewport is focused Input methods are way too complex for us to map them to the VNC protocol in any sane manner. Best just to disable them and rely on simple keyboard behaviour when the viewport is active. --- contrib/fltk/13-fltk-1.3.2-im.patch | 466 ++++++++++++++++++++++++++++ vncviewer/Viewport.cxx | 2 + 2 files changed, 468 insertions(+) create mode 100644 contrib/fltk/13-fltk-1.3.2-im.patch diff --git a/contrib/fltk/13-fltk-1.3.2-im.patch b/contrib/fltk/13-fltk-1.3.2-im.patch new file mode 100644 index 0000000000..fbdcd78530 --- /dev/null +++ b/contrib/fltk/13-fltk-1.3.2-im.patch @@ -0,0 +1,466 @@ +diff -up fltk-1.3.2/FL/Fl.H.im fltk-1.3.2/FL/Fl.H +--- fltk-1.3.2/FL/Fl.H.im 2014-07-25 14:28:52.771417210 +0200 ++++ fltk-1.3.2/FL/Fl.H 2014-07-25 14:28:52.774417261 +0200 +@@ -699,6 +699,17 @@ public: + static int event_inside(const Fl_Widget*); + static int test_shortcut(Fl_Shortcut); + ++ /** ++ Enables the system input methods facilities. This is the default. ++ \see disable_im() ++ */ ++ static void enable_im(); ++ /** ++ Disables the system input methods facilities. ++ \see enable_im() ++ */ ++ static void disable_im(); ++ + // event destinations: + static int handle(int, Fl_Window*); + static int handle_(int, Fl_Window*); +diff -up fltk-1.3.2/FL/win32.H.im fltk-1.3.2/FL/win32.H +--- fltk-1.3.2/FL/win32.H.im 2014-07-25 14:28:52.765417109 +0200 ++++ fltk-1.3.2/FL/win32.H 2014-07-25 14:28:52.774417261 +0200 +@@ -102,6 +102,8 @@ extern FL_EXPORT void fl_save_dc( HWND w + + inline Window fl_xid(const Fl_Window* w) { Fl_X *temp = Fl_X::i(w); return temp ? temp->xid : 0; } + ++extern FL_EXPORT void fl_open_display(); ++ + #else + FL_EXPORT Window fl_xid_(const Fl_Window* w); + #define fl_xid(w) fl_xid_(w) +diff -up fltk-1.3.2/src/Fl_cocoa.mm.im fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2/src/Fl_cocoa.mm.im 2014-07-25 14:37:30.656153283 +0200 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2014-07-25 14:38:03.540708006 +0200 +@@ -53,6 +53,7 @@ extern "C" { + #include + + #import ++#import + + #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h + #if defined(__LP64__) && __LP64__ +@@ -1391,6 +1392,35 @@ void fl_close_display() { + } + + ++// Undocumented voodoo. Taken from Mozilla. ++#define ENABLE_ROMAN_KYBDS_ONLY -23 ++ ++void Fl::enable_im() { ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ TSMRemoveDocumentProperty(TSMGetActiveDocument(), ++ kTSMDocumentEnabledInputSourcesPropertyTag); ++#else ++ KeyScript(smKeyEnableKybds); ++#endif ++} ++ ++void Fl::disable_im() { ++ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and ++ // Safari people seem to think implies turning off advanced IME stuff ++ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput ++ // in Safari/Webcore). Should be good enough for us then... ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); ++ TSMSetDocumentProperty(TSMGetActiveDocument(), ++ kTSMDocumentEnabledInputSourcesPropertyTag, ++ sizeof(CFArrayRef), &inputSources); ++ CFRelease(inputSources); ++#else ++ KeyScript(ENABLE_ROMAN_KYBDS_ONLY); ++#endif ++} ++ ++ + // Gets the border sizes and the titlebar size + static void get_window_frame_sizes(int &bx, int &by, int &bt) { + static bool first = true; +diff -up fltk-1.3.2/src/Fl.cxx.im fltk-1.3.2/src/Fl.cxx +--- fltk-1.3.2/src/Fl.cxx.im 2014-07-25 14:28:52.772417227 +0200 ++++ fltk-1.3.2/src/Fl.cxx 2014-07-25 14:28:52.774417261 +0200 +@@ -593,45 +593,6 @@ int Fl::run() { + return 0; + } + +-#ifdef WIN32 +- +-// Function to initialize COM/OLE for usage. This must be done only once. +-// We define a flag to register whether we called it: +-static char oleInitialized = 0; +- +-// This calls the Windows function OleInitialize() exactly once. +-void fl_OleInitialize() { +- if (!oleInitialized) { +- OleInitialize(0L); +- oleInitialized = 1; +- } +-} +- +-// This calls the Windows function OleUninitialize() only, if +-// OleInitialize has been called before. +-void fl_OleUninitialize() { +- if (oleInitialized) { +- OleUninitialize(); +- oleInitialized = 0; +- } +-} +- +-class Fl_Win32_At_Exit { +-public: +- Fl_Win32_At_Exit() { } +- ~Fl_Win32_At_Exit() { +- fl_free_fonts(); // do some WIN32 cleanup +- fl_cleanup_pens(); +- fl_OleUninitialize(); +- fl_brush_action(1); +- fl_cleanup_dc_list(); +- } +-}; +-static Fl_Win32_At_Exit win32_at_exit; +-#endif +- +- +- + /** + Waits until "something happens" and then returns. Call this + repeatedly to "run" your program. You can also check what happened +diff -up fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx +--- fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im 2012-06-26 09:03:46.000000000 +0200 ++++ fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx 2014-07-25 14:28:52.774417261 +0200 +@@ -34,6 +34,7 @@ LPCWSTR utf8towchar(const char *in); //M + char *wchartoutf8(LPCWSTR in); //MG + + #include ++#include + + #define LCURLY_CHR '{' + #define RCURLY_CHR '}' +@@ -41,8 +42,6 @@ char *wchartoutf8(LPCWSTR in); //MG + #define RBRACKET_CHR ']' + #define MAXFILTERS 80 + +-void fl_OleInitialize(); // in Fl.cxx (Windows only) +- + // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG) + #ifdef DEBUG + static void dnullprint(char *wp) { +@@ -471,7 +470,7 @@ int CALLBACK Fl_Native_File_Chooser::Dir + // SHOW DIRECTORY BROWSER + int Fl_Native_File_Chooser::showdir() { + // initialize OLE only once +- fl_OleInitialize(); // init needed by BIF_USENEWUI ++ fl_open_display(); // init needed by BIF_USENEWUI + ClearBINF(); + clear_pathnames(); + // PARENT WINDOW +diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2/src/Fl_win32.cxx.im 2014-07-25 14:28:52.772417227 +0200 ++++ fltk-1.3.2/src/Fl_win32.cxx 2014-07-25 14:28:52.775417277 +0200 +@@ -60,8 +60,6 @@ + #include + #include + +-#include "aimm.h" +- + // + // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... + // USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons: +@@ -121,27 +119,24 @@ static HMODULE get_wsock_mod() { + * size and link dependencies. + */ + static HMODULE s_imm_module = 0; ++typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD); ++static flTypeImmAssociateContextEx flImmAssociateContextEx = 0; + typedef HIMC (WINAPI* flTypeImmGetContext)(HWND); + static flTypeImmGetContext flImmGetContext = 0; + typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); + static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0; + typedef BOOL (WINAPI* flTypeImmReleaseContext)(HWND, HIMC); + static flTypeImmReleaseContext flImmReleaseContext = 0; +-typedef BOOL (WINAPI* flTypeImmIsIME)(HKL); +-static flTypeImmIsIME flImmIsIME = 0; + +-static HMODULE get_imm_module() { +- if (!s_imm_module) { +- s_imm_module = LoadLibrary("IMM32.DLL"); +- if (!s_imm_module) +- Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" +- "Please check your input method manager library accessibility."); +- flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); +- flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); +- flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); +- flImmIsIME = (flTypeImmIsIME)GetProcAddress(s_imm_module, "ImmIsIME"); +- } +- return s_imm_module; ++static void get_imm_module() { ++ s_imm_module = LoadLibrary("IMM32.DLL"); ++ if (!s_imm_module) ++ Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" ++ "Please check your input method manager library accessibility."); ++ flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx"); ++ flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); ++ flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); ++ flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); + } + + // USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have +@@ -259,7 +254,9 @@ void fl_set_spot(int font, int size, int + Fl_Window* tw = win; + while (tw->parent()) tw = tw->window(); // find top level window + +- get_imm_module(); ++ if (!tw->shown()) ++ return; ++ + HIMC himc = flImmGetContext(fl_xid(tw)); + + if (himc) { +@@ -338,7 +335,6 @@ void* Fl::thread_message() { + + extern bool fl_send_xhandlers(void *e); + +-IActiveIMMApp *fl_aimm = NULL; + MSG fl_msg; + + // This is never called with time_to_wait < 0.0. +@@ -441,6 +437,58 @@ int fl_ready() { + return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0; + } + ++void fl_open_display() { ++ static char beenHereDoneThat = 0; ++ ++ if (beenHereDoneThat) ++ return; ++ ++ beenHereDoneThat = 1; ++ ++ OleInitialize(0L); ++ ++ get_imm_module(); ++} ++ ++class Fl_Win32_At_Exit { ++public: ++ Fl_Win32_At_Exit() { } ++ ~Fl_Win32_At_Exit() { ++ fl_free_fonts(); // do some WIN32 cleanup ++ fl_cleanup_pens(); ++ OleUninitialize(); ++ fl_brush_action(1); ++ fl_cleanup_dc_list(); ++ } ++}; ++static Fl_Win32_At_Exit win32_at_exit; ++ ++static char im_enabled = 1; ++ ++void Fl::enable_im() { ++ fl_open_display(); ++ ++ Fl_X* i = Fl_X::first; ++ while (i) { ++ flImmAssociateContextEx(i->xid, 0, IACE_DEFAULT); ++ i = i->next; ++ } ++ ++ im_enabled = 1; ++} ++ ++void Fl::disable_im() { ++ fl_open_display(); ++ ++ Fl_X* i = Fl_X::first; ++ while (i) { ++ flImmAssociateContextEx(i->xid, 0, 0); ++ i = i->next; ++ } ++ ++ im_enabled = 0; ++} ++ + //////////////////////////////////////////////////////////////// + + int Fl::x() +@@ -683,7 +731,6 @@ void fl_clipboard_notify_untarget(HWND w + } + + //////////////////////////////////////////////////////////////// +-char fl_is_ime = 0; + void fl_get_codepage() + { + HKL hkl = GetKeyboardLayout(0); +@@ -691,14 +738,8 @@ void fl_get_codepage() + + GetLocaleInfo (LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6); + DWORD ccp = atol(ld); +- fl_is_ime = 0; + + fl_codepage = ccp; +- if (fl_aimm) { +- fl_aimm->GetCodePageA(GetKeyboardLayout(0), &fl_codepage); +- } else if (get_imm_module() && flImmIsIME(hkl)) { +- fl_is_ime = 1; +- } + } + + HWND fl_capture; +@@ -1564,6 +1605,8 @@ int fl_disable_transient_for; // secret + Fl_X* Fl_X::make(Fl_Window* w) { + Fl_Group::current(0); // get rid of very common user bug: forgot end() + ++ fl_open_display(); ++ + // if the window is a subwindow and our parent is not mapped yet, we + // mark this window visible, so that mapping the parent at a later + // point in time will call this function again to finally map the subwindow. +@@ -1767,16 +1810,10 @@ Fl_X* Fl_X::make(Fl_Window* w) { + (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); + + // Register all windows for potential drag'n'drop operations +- fl_OleInitialize(); + RegisterDragDrop(x->xid, flIDropTarget); + +- if (!fl_aimm) { +- CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, +- IID_IActiveIMMApp, (void**) &fl_aimm); +- if (fl_aimm) { +- fl_aimm->Activate(TRUE); +- } +- } ++ if (!im_enabled) ++ flImmAssociateContextEx(x->xid, 0, 0); + + return x; + } +diff -up fltk-1.3.2/src/Fl_x.cxx.im fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.im 2014-07-25 14:28:52.773417244 +0200 ++++ fltk-1.3.2/src/Fl_x.cxx 2014-07-25 14:28:52.775417277 +0200 +@@ -313,6 +313,7 @@ XVisualInfo *fl_visual; + Colormap fl_colormap; + XIM fl_xim_im = 0; + XIC fl_xim_ic = 0; ++Window fl_xim_win = 0; + char fl_is_over_the_spot = 0; + static XRectangle status_area; + +@@ -603,6 +604,55 @@ void fl_init_xim() { + if(xim_styles) XFree(xim_styles); + } + ++void fl_xim_deactivate(void); ++ ++void fl_xim_activate(Window xid) { ++ if (!fl_xim_im) ++ return; ++ ++ // If the focused window has changed, then use the brute force method ++ // of completely recreating the input context. ++ if (fl_xim_win != xid) { ++ fl_xim_deactivate(); ++ ++ fl_new_ic(); ++ fl_xim_win = xid; ++ ++ XSetICValues(fl_xim_ic, ++ XNFocusWindow, fl_xim_win, ++ XNClientWindow, fl_xim_win, ++ NULL); ++ } ++ ++ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); ++} ++ ++void fl_xim_deactivate(void) { ++ if (!fl_xim_ic) ++ return; ++ ++ XDestroyIC(fl_xim_ic); ++ fl_xim_ic = NULL; ++ ++ fl_xim_win = 0; ++} ++ ++void Fl::enable_im() { ++ Fl_Window *win; ++ ++ win = Fl::first_window(); ++ if (win && win->shown()) { ++ fl_xim_activate(fl_xid(win)); ++ XSetICFocus(fl_xim_ic); ++ } else { ++ fl_new_ic(); ++ } ++} ++ ++void Fl::disable_im() { ++ fl_xim_deactivate(); ++} ++ + void fl_open_display() { + if (fl_display) return; + +@@ -1053,10 +1103,9 @@ int fl_handle(const XEvent& thisevent) + XEvent xevent = thisevent; + fl_xevent = &thisevent; + Window xid = xevent.xany.window; +- static Window xim_win = 0; + + if (fl_xim_ic && xevent.type == DestroyNotify && +- xid != xim_win && !fl_find(xid)) ++ xid != fl_xim_win && !fl_find(xid)) + { + XIM xim_im; + xim_im = XOpenIM(fl_display, NULL, NULL, NULL); +@@ -1072,46 +1121,9 @@ int fl_handle(const XEvent& thisevent) + } + + if (fl_xim_ic && (xevent.type == FocusIn)) +- { +-#define POOR_XIM +-#ifdef POOR_XIM +- if (xim_win != xid) +- { +- xim_win = xid; +- XDestroyIC(fl_xim_ic); +- fl_xim_ic = NULL; +- fl_new_ic(); +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- NULL); +- } +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +-#else +- if (Fl::first_window() && Fl::first_window()->modal()) { +- Window x = fl_xid(Fl::first_window()); +- if (x != xim_win) { +- xim_win = x; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xim_win, +- XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +- } else if (xim_win != xid && xid) { +- xim_win = xid; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- //XNFocusWindow, xim_win, +- //XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +-#endif +- } ++ fl_xim_activate(xid); + +- if ( XFilterEvent((XEvent *)&xevent, 0) ) ++ if (fl_xim_ic && XFilterEvent((XEvent *)&xevent, 0)) + return(1); + + #if USE_XRANDR diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 917a981783..81dc7ac009 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -410,6 +410,7 @@ int Viewport::handle(int event) return 1; case FL_FOCUS: + Fl::disable_im(); // Yes, we would like some focus please! return 1; @@ -418,6 +419,7 @@ int Viewport::handle(int event) // sense (e.g. Alt+Tab where we only see the Alt press) while (!downKeySym.empty()) handleKeyRelease(downKeySym.begin()->first); + Fl::enable_im(); return 1; case FL_KEYDOWN: From 38fcebbb00d849d46158f66793ae0f7f3c7c7ec4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 21 Aug 2014 13:44:28 +0200 Subject: [PATCH 17/19] Use different keysyms for left and right alt on OS X The server will get them confused otherwise if they are pressed at the same time. --- vncviewer/Viewport.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 81dc7ac009..ec48b02ee1 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -534,6 +534,8 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) keySym = XK_Super_L; break; case XK_Alt_L: + keySym = XK_Mode_switch; + break; case XK_Alt_R: keySym = XK_ISO_Level3_Shift; break; From 6d66d6deb790545dd475f3e74cf817be97d23cea Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 Sep 2014 10:46:12 +0200 Subject: [PATCH 18/19] Protect the optional IM disabling calls with #ifdef:s --- CMakeLists.txt | 3 +++ config.h.in | 1 + vncviewer/Viewport.cxx | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5a016ace3..a3e0931a79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,6 +303,9 @@ if(FLTK_FOUND) # FLTK STR #xxxx check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_xhandler(NULL, NULL); return 0; }" HAVE_FLTK_XHANDLERS) + # FLTK STR #xxxx + check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::disable_im(); return 0; }" HAVE_FLTK_IM) + set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) endif() diff --git a/config.h.in b/config.h.in index bac626b7f6..a50e723d1f 100644 --- a/config.h.in +++ b/config.h.in @@ -18,6 +18,7 @@ #cmakedefine HAVE_FLTK_WORK_AREA #cmakedefine HAVE_FLTK_ICONS #cmakedefine HAVE_FLTK_XHANDLERS +#cmakedefine HAVE_FLTK_IM #cmakedefine HAVE_ACTIVE_DESKTOP_H #cmakedefine HAVE_ACTIVE_DESKTOP_L #cmakedefine ENABLE_NLS 1 diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index ec48b02ee1..595a4aa854 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -410,7 +410,9 @@ int Viewport::handle(int event) return 1; case FL_FOCUS: +#ifdef HAVE_FLTK_IM Fl::disable_im(); +#endif // Yes, we would like some focus please! return 1; @@ -419,7 +421,9 @@ int Viewport::handle(int event) // sense (e.g. Alt+Tab where we only see the Alt press) while (!downKeySym.empty()) handleKeyRelease(downKeySym.begin()->first); +#ifdef HAVE_FLTK_IM Fl::enable_im(); +#endif return 1; case FL_KEYDOWN: From 64ff1ca14f595d0eb7f6b1b47facf5f4147eae51 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 Sep 2014 10:48:29 +0200 Subject: [PATCH 19/19] Update FLTK patches based on feeback from upstream --- CMakeLists.txt | 2 +- contrib/fltk/12-fltk-1.3.2-xhandlers.patch | 82 ++++---- contrib/fltk/13-fltk-1.3.2-im.patch | 210 ++++++++++++++++----- vncviewer/Viewport.cxx | 30 +-- vncviewer/Viewport.h | 2 +- 5 files changed, 229 insertions(+), 97 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e0931a79..5f4ccd488a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -301,7 +301,7 @@ if(FLTK_FOUND) check_cxx_source_compiles("#include \nint main(int c, char** v) { void (Fl_Window::*foo)(int,int,int,int) = &Fl_Window::fullscreen_screens; return 0; }" HAVE_FLTK_FULLSCREEN_SCREENS) # FLTK STR #xxxx - check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_xhandler(NULL, NULL); return 0; }" HAVE_FLTK_XHANDLERS) + check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_system_handler(NULL, NULL); return 0; }" HAVE_FLTK_XHANDLERS) # FLTK STR #xxxx check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::disable_im(); return 0; }" HAVE_FLTK_IM) diff --git a/contrib/fltk/12-fltk-1.3.2-xhandlers.patch b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch index cf6cefbfe6..0ac3fe4b5a 100644 --- a/contrib/fltk/12-fltk-1.3.2-xhandlers.patch +++ b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch @@ -5,8 +5,8 @@ diff -up fltk-1.3.2/FL/Fl.H.xhandlers fltk-1.3.2/FL/Fl.H /** Signature of add_handler functions passed as parameters */ typedef int (*Fl_Event_Handler)(int event); -+/** Signature of add_xhandler functions passed as parameters */ -+typedef bool (*Fl_XEvent_Handler)(void *event, void *data); ++/** Signature of add_system_handler functions passed as parameters */ ++typedef int (*Fl_System_Handler)(void *event, void *data); + /** Signature of set_abort functions passed as parameters */ typedef void (*Fl_Abort_Handler)(const char *format,...); @@ -15,8 +15,8 @@ diff -up fltk-1.3.2/FL/Fl.H.xhandlers fltk-1.3.2/FL/Fl.H static void focus(Fl_Widget*); static void add_handler(Fl_Event_Handler h); static void remove_handler(Fl_Event_Handler h); -+ static void add_xhandler(Fl_XEvent_Handler h, void *data); -+ static void remove_xhandler(Fl_XEvent_Handler h); ++ static void add_system_handler(Fl_System_Handler h, void *data); ++ static void remove_system_handler(Fl_System_Handler h); static void event_dispatch(Fl_Event_Dispatch d); static Fl_Event_Dispatch event_dispatch(); /** @} */ @@ -27,7 +27,7 @@ diff -up fltk-1.3.2/src/Fl_cocoa.mm.xhandlers fltk-1.3.2/src/Fl_cocoa.mm } @end -+extern bool fl_send_xhandlers(void *e); ++extern int fl_send_system_handlers(void *e); + static void clipboard_check(void); @@ -37,7 +37,7 @@ diff -up fltk-1.3.2/src/Fl_cocoa.mm.xhandlers fltk-1.3.2/src/Fl_cocoa.mm // update clipboard status clipboard_check(); + -+ if (fl_send_xhandlers(theEvent)) ++ if (fl_send_system_handlers(theEvent)) + return; + NSEventType type = [theEvent type]; @@ -46,7 +46,7 @@ diff -up fltk-1.3.2/src/Fl_cocoa.mm.xhandlers fltk-1.3.2/src/Fl_cocoa.mm diff -up fltk-1.3.2/src/Fl.cxx.xhandlers fltk-1.3.2/src/Fl.cxx --- fltk-1.3.2/src/Fl.cxx.xhandlers 2014-07-22 15:23:18.085334432 +0200 +++ fltk-1.3.2/src/Fl.cxx 2014-07-22 15:23:18.095334607 +0200 -@@ -891,6 +891,67 @@ static int send_handlers(int e) { +@@ -891,6 +891,83 @@ static int send_handlers(int e) { return 0; } @@ -55,59 +55,75 @@ diff -up fltk-1.3.2/src/Fl.cxx.xhandlers fltk-1.3.2/src/Fl.cxx +// System event handlers: + + -+struct xhandler_link { -+ Fl_XEvent_Handler handle; ++struct system_handler_link { ++ Fl_System_Handler handle; + void *data; -+ xhandler_link *next; ++ system_handler_link *next; +}; + + -+static xhandler_link *xhandlers = 0; ++static system_handler_link *sys_handlers = 0; + + +/** -+ Install a function to intercept system events. FLTK calls each of -+ these functions as soon as a new system event is received. The -+ processing will stop at the first function to return true. If all -+ functions return false then the event is passed on for normal -+ handling by FLTK. ++ \brief Install a function to intercept system events. + -+ \see Fl::remove_xhandler(Fl_XEvent_Handler) ++ FLTK calls each of these functions as soon as a new system event is ++ received. The processing will stop at the first function to return ++ non-zero. If all functions return zero then the event is passed on ++ for normal handling by FLTK. ++ ++ Each function will be called with a pointer to the system event as ++ the first argument and \p data as the second argument. The system ++ event pointer will always be void *, but will point to different ++ objects depending on the platform: ++ - X11: XEvent ++ - Windows: MSG ++ - OS X: NSEvent ++ ++ \param ha The event handler function to register ++ \param data User data to include on each call ++ ++ \see Fl::remove_system_handler(Fl_System_Handler) +*/ -+void Fl::add_xhandler(Fl_XEvent_Handler ha, void *data) { -+ xhandler_link *l = new xhandler_link; ++void Fl::add_system_handler(Fl_System_Handler ha, void *data) { ++ system_handler_link *l = new system_handler_link; + l->handle = ha; + l->data = data; -+ l->next = xhandlers; -+ xhandlers = l; ++ l->next = sys_handlers; ++ sys_handlers = l; +} + + +/** + Removes a previously added system event handler. ++ ++ \param ha The event handler function to remove ++ ++ \see Fl::add_system_handler(Fl_System_Handler) +*/ -+void Fl::remove_xhandler(Fl_XEvent_Handler ha) { -+ xhandler_link *l, *p; ++void Fl::remove_system_handler(Fl_System_Handler ha) { ++ system_handler_link *l, *p; + + // Search for the handler in the list... -+ for (l = xhandlers, p = 0; l && l->handle != ha; p = l, l = l->next); ++ for (l = sys_handlers, p = 0; l && l->handle != ha; p = l, l = l->next); + + if (l) { + // Found it, so remove it from the list... + if (p) p->next = l->next; -+ else xhandlers = l->next; ++ else sys_handlers = l->next; + + // And free the record... + delete l; + } +} + -+bool fl_send_xhandlers(void *e) { -+ for (const xhandler_link *hl = xhandlers; hl; hl = hl->next) { ++int fl_send_system_handlers(void *e) { ++ for (const system_handler_link *hl = sys_handlers; hl; hl = hl->next) { + if (hl->handle(e, hl->data)) -+ return true; ++ return 1; + } -+ return false; ++ return 0; +} + + @@ -121,7 +137,7 @@ diff -up fltk-1.3.2/src/Fl_win32.cxx.xhandlers fltk-1.3.2/src/Fl_win32.cxx return r; } -+extern bool fl_send_xhandlers(void *e); ++extern int fl_send_system_handlers(void *e); + IActiveIMMApp *fl_aimm = NULL; MSG fl_msg; @@ -150,7 +166,7 @@ diff -up fltk-1.3.2/src/Fl_win32.cxx.xhandlers fltk-1.3.2/src/Fl_win32.cxx - DispatchMessageW(&fl_msg); - have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); + while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) { -+ if (fl_send_xhandlers(&fl_msg)) ++ if (fl_send_system_handlers(&fl_msg)) + continue; + + // Let applications treat WM_QUIT identical to SIGTERM on *nix @@ -178,7 +194,7 @@ diff -up fltk-1.3.2/src/Fl_x.cxx.xhandlers fltk-1.3.2/src/Fl_x.cxx remove_fd(n, -1); } -+extern bool fl_send_xhandlers(void *e); ++extern int fl_send_system_handlers(void *e); + #if CONSOLIDATE_MOTION static Fl_Window* send_motion; @@ -187,7 +203,7 @@ diff -up fltk-1.3.2/src/Fl_x.cxx.xhandlers fltk-1.3.2/src/Fl_x.cxx while (XEventsQueued(fl_display,QueuedAfterReading)) { XEvent xevent; XNextEvent(fl_display, &xevent); -+ if (fl_send_xhandlers(&xevent)) ++ if (fl_send_system_handlers(&xevent)) + continue; fl_handle(xevent); } diff --git a/contrib/fltk/13-fltk-1.3.2-im.patch b/contrib/fltk/13-fltk-1.3.2-im.patch index fbdcd78530..efacc42be6 100644 --- a/contrib/fltk/13-fltk-1.3.2-im.patch +++ b/contrib/fltk/13-fltk-1.3.2-im.patch @@ -1,6 +1,6 @@ diff -up fltk-1.3.2/FL/Fl.H.im fltk-1.3.2/FL/Fl.H ---- fltk-1.3.2/FL/Fl.H.im 2014-07-25 14:28:52.771417210 +0200 -+++ fltk-1.3.2/FL/Fl.H 2014-07-25 14:28:52.774417261 +0200 +--- fltk-1.3.2/FL/Fl.H.im 2014-09-10 14:40:05.193265424 +0200 ++++ fltk-1.3.2/FL/Fl.H 2014-09-10 14:40:05.196265471 +0200 @@ -699,6 +699,17 @@ public: static int event_inside(const Fl_Widget*); static int test_shortcut(Fl_Shortcut); @@ -20,8 +20,8 @@ diff -up fltk-1.3.2/FL/Fl.H.im fltk-1.3.2/FL/Fl.H static int handle(int, Fl_Window*); static int handle_(int, Fl_Window*); diff -up fltk-1.3.2/FL/win32.H.im fltk-1.3.2/FL/win32.H ---- fltk-1.3.2/FL/win32.H.im 2014-07-25 14:28:52.765417109 +0200 -+++ fltk-1.3.2/FL/win32.H 2014-07-25 14:28:52.774417261 +0200 +--- fltk-1.3.2/FL/win32.H.im 2014-09-10 14:40:05.186265315 +0200 ++++ fltk-1.3.2/FL/win32.H 2014-09-10 14:40:05.196265471 +0200 @@ -102,6 +102,8 @@ extern FL_EXPORT void fl_save_dc( HWND w inline Window fl_xid(const Fl_Window* w) { Fl_X *temp = Fl_X::i(w); return temp ? temp->xid : 0; } @@ -32,55 +32,171 @@ diff -up fltk-1.3.2/FL/win32.H.im fltk-1.3.2/FL/win32.H FL_EXPORT Window fl_xid_(const Fl_Window* w); #define fl_xid(w) fl_xid_(w) diff -up fltk-1.3.2/src/Fl_cocoa.mm.im fltk-1.3.2/src/Fl_cocoa.mm ---- fltk-1.3.2/src/Fl_cocoa.mm.im 2014-07-25 14:37:30.656153283 +0200 -+++ fltk-1.3.2/src/Fl_cocoa.mm 2014-07-25 14:38:03.540708006 +0200 -@@ -53,6 +53,7 @@ extern "C" { - #include - - #import -+#import - - #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h - #if defined(__LP64__) && __LP64__ -@@ -1391,6 +1392,35 @@ void fl_close_display() { +--- fltk-1.3.2/src/Fl_cocoa.mm.im 2014-09-10 14:40:05.193265424 +0200 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2014-09-10 14:43:41.103642243 +0200 +@@ -88,6 +88,7 @@ static void createAppleMenu(void); + static Fl_Region MacRegionMinusRect(Fl_Region r, int x,int y,int w,int h); + static void cocoaMouseHandler(NSEvent *theEvent); + static int calc_mac_os_version(); ++static void im_update(void); + + static Fl_Quartz_Graphics_Driver fl_quartz_driver; + static Fl_Display_Device fl_quartz_display(&fl_quartz_driver); +@@ -108,6 +109,30 @@ int fl_mac_os_version = calc_mac_os_vers + static int got_events = 0; + static Fl_Window* resize_from_system; + static int main_screen_height; // height of menubar-containing screen used to convert between Cocoa and FLTK global screen coordinates ++static int im_enabled = -1; ++ ++// Carbon functions and definitions ++ ++typedef void *TSMDocumentID; ++ ++extern "C" enum { ++ kTSMDocumentEnabledInputSourcesPropertyTag = 'enis' // from Carbon/TextServices.h ++}; ++ ++// Undocumented voodoo. Taken from Mozilla. ++static const int smEnableRomanKybdsOnly = -23; ++ ++typedef TSMDocumentID (*TSMGetActiveDocument_type)(void); ++static TSMGetActiveDocument_type TSMGetActiveDocument; ++typedef OSStatus (*TSMSetDocumentProperty_type)(TSMDocumentID, OSType, UInt32, void*); ++static TSMSetDocumentProperty_type TSMSetDocumentProperty; ++typedef OSStatus (*TSMRemoveDocumentProperty_type)(TSMDocumentID, OSType); ++static TSMRemoveDocumentProperty_type TSMRemoveDocumentProperty; ++typedef CFArrayRef (*TISCreateASCIICapableInputSourceList_type)(void); ++static TISCreateASCIICapableInputSourceList_type TISCreateASCIICapableInputSourceList; ++ ++typedef void (*KeyScript_type)(short); ++static KeyScript_type KeyScript; + + #if CONSOLIDATE_MOTION + static Fl_Window* send_motion; +@@ -978,6 +1003,7 @@ void fl_open_callback(void (*cb)(const c + #endif + { + BOOL seen_open_file; ++ TSMDocumentID currentDoc; + } + - (void)windowDidMove:(NSNotification *)notif; + - (void)windowDidResize:(NSNotification *)notif; +@@ -991,6 +1017,7 @@ void fl_open_callback(void (*cb)(const c + - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; + - (void)applicationDidBecomeActive:(NSNotification *)notify; + - (void)applicationDidChangeScreenParameters:(NSNotification *)aNotification; ++- (void)applicationDidUpdate:(NSNotification *)aNotification; + - (void)applicationWillResignActive:(NSNotification *)notify; + - (void)applicationWillHide:(NSNotification *)notify; + - (void)applicationWillUnhide:(NSNotification *)notify; +@@ -1175,6 +1202,23 @@ void fl_open_callback(void (*cb)(const c + } + Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); + } ++- (void)applicationDidUpdate:(NSNotification *)aNotification ++{ ++ if ((fl_mac_os_version >= 100500) && (im_enabled != -1) && ++ (TSMGetActiveDocument != NULL)) { ++ TSMDocumentID newDoc; ++ // It is extremely unclear when Cocoa decides to create/update ++ // the input context, but debugging reveals that it is done ++ // by NSApplication:updateWindows. So check if the input context ++ // has shifted after each such run so that we can update our ++ // input methods status. ++ newDoc = TSMGetActiveDocument(); ++ if (newDoc != currentDoc) { ++ im_update(); ++ currentDoc = newDoc; ++ } ++ } ++} + - (void)applicationWillResignActive:(NSNotification *)notify + { + fl_lock_function(); +@@ -1322,6 +1365,13 @@ void fl_open_display() { + static char beenHereDoneThat = 0; + if ( !beenHereDoneThat ) { + beenHereDoneThat = 1; ++ ++ TSMGetActiveDocument = (TSMGetActiveDocument_type)Fl_X::get_carbon_function("TSMGetActiveDocument"); ++ TSMSetDocumentProperty = (TSMSetDocumentProperty_type)Fl_X::get_carbon_function("TSMSetDocumentProperty"); ++ TSMRemoveDocumentProperty = (TSMRemoveDocumentProperty_type)Fl_X::get_carbon_function("TSMRemoveDocumentProperty"); ++ TISCreateASCIICapableInputSourceList = (TISCreateASCIICapableInputSourceList_type)Fl_X::get_carbon_function("TISCreateASCIICapableInputSourceList"); ++ ++ KeyScript = (KeyScript_type)Fl_X::get_carbon_function("KeyScript"); + + BOOL need_new_nsapp = (NSApp == nil); + if (need_new_nsapp) [NSApplication sharedApplication]; +@@ -1390,6 +1440,66 @@ void fl_open_display() { + void fl_close_display() { } - -+// Undocumented voodoo. Taken from Mozilla. -+#define ENABLE_ROMAN_KYBDS_ONLY -23 ++// Force a "Roman" or "ASCII" keyboard, which both the Mozilla and ++// Safari people seem to think implies turning off advanced IME stuff ++// (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput ++// in Safari/Webcore). Should be good enough for us then... ++ ++static void im_update(void) { ++ if (fl_mac_os_version >= 100500) { ++ TSMDocumentID doc; ++ ++ if ((TSMGetActiveDocument == NULL) || ++ (TSMSetDocumentProperty == NULL) || ++ (TSMRemoveDocumentProperty == NULL) || ++ (TISCreateASCIICapableInputSourceList == NULL)) ++ return; ++ ++ doc = TSMGetActiveDocument(); ++ ++ if (im_enabled) ++ TSMRemoveDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag); ++ else { ++ CFArrayRef inputSources; ++ ++ inputSources = TISCreateASCIICapableInputSourceList(); ++ TSMSetDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag, ++ sizeof(CFArrayRef), &inputSources); ++ CFRelease(inputSources); ++ } ++ } else { ++ if (KeyScript == NULL) ++ return; ++ ++ if (im_enabled) ++ KeyScript(smKeyEnableKybds); ++ else ++ KeyScript(smEnableRomanKybdsOnly); ++ } ++} + +void Fl::enable_im() { -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ TSMRemoveDocumentProperty(TSMGetActiveDocument(), -+ kTSMDocumentEnabledInputSourcesPropertyTag); -+#else -+ KeyScript(smKeyEnableKybds); -+#endif ++ fl_open_display(); ++ ++ im_enabled = 1; ++ ++ if (fl_mac_os_version >= 100500) ++ [NSApp updateWindows]; ++ else ++ im_update(); +} + +void Fl::disable_im() { -+ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and -+ // Safari people seem to think implies turning off advanced IME stuff -+ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput -+ // in Safari/Webcore). Should be good enough for us then... -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); -+ TSMSetDocumentProperty(TSMGetActiveDocument(), -+ kTSMDocumentEnabledInputSourcesPropertyTag, -+ sizeof(CFArrayRef), &inputSources); -+ CFRelease(inputSources); -+#else -+ KeyScript(ENABLE_ROMAN_KYBDS_ONLY); -+#endif -+} ++ fl_open_display(); ++ ++ im_enabled = 0; + ++ if (fl_mac_os_version >= 100500) ++ [NSApp updateWindows]; ++ else ++ im_update(); ++} + + // Gets the border sizes and the titlebar size static void get_window_frame_sizes(int &bx, int &by, int &bt) { - static bool first = true; diff -up fltk-1.3.2/src/Fl.cxx.im fltk-1.3.2/src/Fl.cxx ---- fltk-1.3.2/src/Fl.cxx.im 2014-07-25 14:28:52.772417227 +0200 -+++ fltk-1.3.2/src/Fl.cxx 2014-07-25 14:28:52.774417261 +0200 +--- fltk-1.3.2/src/Fl.cxx.im 2014-09-10 14:40:05.194265440 +0200 ++++ fltk-1.3.2/src/Fl.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -593,45 +593,6 @@ int Fl::run() { return 0; } @@ -129,7 +245,7 @@ diff -up fltk-1.3.2/src/Fl.cxx.im fltk-1.3.2/src/Fl.cxx repeatedly to "run" your program. You can also check what happened diff -up fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx --- fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im 2012-06-26 09:03:46.000000000 +0200 -+++ fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx 2014-07-25 14:28:52.774417261 +0200 ++++ fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -34,6 +34,7 @@ LPCWSTR utf8towchar(const char *in); //M char *wchartoutf8(LPCWSTR in); //MG @@ -157,8 +273,8 @@ diff -up fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im fltk-1.3.2/src/Fl_Na clear_pathnames(); // PARENT WINDOW diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx ---- fltk-1.3.2/src/Fl_win32.cxx.im 2014-07-25 14:28:52.772417227 +0200 -+++ fltk-1.3.2/src/Fl_win32.cxx 2014-07-25 14:28:52.775417277 +0200 +--- fltk-1.3.2/src/Fl_win32.cxx.im 2014-09-10 14:40:05.194265440 +0200 ++++ fltk-1.3.2/src/Fl_win32.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -60,8 +60,6 @@ #include #include @@ -220,7 +336,7 @@ diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx if (himc) { @@ -338,7 +335,6 @@ void* Fl::thread_message() { - extern bool fl_send_xhandlers(void *e); + extern int fl_send_system_handlers(void *e); -IActiveIMMApp *fl_aimm = NULL; MSG fl_msg; @@ -337,8 +453,8 @@ diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx return x; } diff -up fltk-1.3.2/src/Fl_x.cxx.im fltk-1.3.2/src/Fl_x.cxx ---- fltk-1.3.2/src/Fl_x.cxx.im 2014-07-25 14:28:52.773417244 +0200 -+++ fltk-1.3.2/src/Fl_x.cxx 2014-07-25 14:28:52.775417277 +0200 +--- fltk-1.3.2/src/Fl_x.cxx.im 2014-09-10 14:40:05.194265440 +0200 ++++ fltk-1.3.2/src/Fl_x.cxx 2014-09-10 14:40:05.198265502 +0200 @@ -313,6 +313,7 @@ XVisualInfo *fl_visual; Colormap fl_colormap; XIM fl_xim_im = 0; diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 595a4aa854..32ed543cf9 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -112,7 +112,7 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) #ifdef HAVE_FLTK_XHANDLERS // We need to intercept keyboard events early - Fl::add_xhandler(handleXEvent, this); + Fl::add_system_handler(handleSystemEvent, this); #endif frameBuffer = createFramebuffer(w, h); @@ -148,7 +148,7 @@ Viewport::~Viewport() Fl::remove_timeout(handlePointerTimeout, this); #ifdef HAVE_FLTK_XHANDLERS - Fl::remove_xhandler(handleXEvent); + Fl::remove_system_handler(handleSystemEvent); #endif #ifdef HAVE_FLTK_CLIPBOARD @@ -647,7 +647,7 @@ void Viewport::handleKeyRelease(int keyCode) } -bool Viewport::handleXEvent(void *event, void *data) +int Viewport::handleSystemEvent(void *event, void *data) { Viewport *self = (Viewport *)data; Fl_Widget *focus; @@ -658,10 +658,10 @@ bool Viewport::handleXEvent(void *event, void *data) if (!focus) focus = Fl::focus(); if (!focus) - return false; + return 0; if (focus != self) - return false; + return 0; assert(event); @@ -686,7 +686,7 @@ bool Viewport::handleXEvent(void *event, void *data) if (keyCode == 0x00) { vlog.error(_("No scan code for %svirtual key 0x%02x"), isExtended?"extended ":"", (int)vKey); - return true; + return 1; } } @@ -697,12 +697,12 @@ bool Viewport::handleXEvent(void *event, void *data) if (keySym == NoSymbol) { vlog.error(_("No symbol for %svirtual key 0x%02x"), isExtended?"extended ":"", (int)vKey); - return true; + return 1; } self->handleKeyPress(keyCode, keySym); - return true; + return 1; } else if ((msg->message == WM_KEYUP) || (msg->message == WM_SYSKEYUP)) { UINT vKey; bool isExtended; @@ -719,7 +719,7 @@ bool Viewport::handleXEvent(void *event, void *data) self->handleKeyRelease(keyCode); - return true; + return 1; } #elif defined(__APPLE__) if (cocoa_is_keyboard_event(event)) { @@ -734,7 +734,7 @@ bool Viewport::handleXEvent(void *event, void *data) if (keySym == NoSymbol) { vlog.error(_("No symbol for key code 0x%02x (in the current state)"), (int)keyCode); - return true; + return 1; } self->handleKeyPress(keyCode, keySym); @@ -747,7 +747,7 @@ bool Viewport::handleXEvent(void *event, void *data) self->handleKeyRelease(keyCode); } - return true; + return 1; } #else XEvent *xevent = (XEvent*)event; @@ -760,7 +760,7 @@ bool Viewport::handleXEvent(void *event, void *data) if (keysym == NoSymbol) { vlog.error(_("No symbol for key code %d (in the current state)"), (int)xevent->xkey.keycode); - return true; + return 1; } switch (keysym) { @@ -783,14 +783,14 @@ bool Viewport::handleXEvent(void *event, void *data) } self->handleKeyPress(xevent->xkey.keycode, keysym); - return true; + return 1; } else if (xevent->type == KeyRelease) { self->handleKeyRelease(xevent->xkey.keycode); - return true; + return 1; } #endif - return false; + return 0; } diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index 30dacad453..8e60da6561 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -73,7 +73,7 @@ class Viewport : public Fl_Widget { void handleKeyPress(int keyCode, rdr::U32 keySym); void handleKeyRelease(int keyCode); - static bool handleXEvent(void *event, void *data); + static int handleSystemEvent(void *event, void *data); rdr::U32 translateKeyEvent(void); void handleFLTKKeyPress(void);