| *** fltk-1.3.0/CMakeLists.txt 2011-01-06 04:24:58.000000000 -0600 |
| --- fltk-1.3.0-new/CMakeLists.txt 2011-06-23 21:39:42.000000000 -0500 |
| *************** |
| *** 49,52 **** |
| --- 49,56 ---- |
| include_directories(${FLTK_BINARY_DIR} ${FLTK_SOURCE_DIR}) |
| |
| + if(NOT CMAKE_BUILD_TYPE) |
| + set(CMAKE_BUILD_TYPE Release) |
| + endif() |
| + |
| ####################################################################### |
| # platform dependent information |
| *************** |
| *** 62,65 **** |
| --- 66,70 ---- |
| set(HAVE_DIRENT_H 1) |
| set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Cocoa") |
| + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Carbon") |
| endif(APPLE) |
| |
| *************** |
| *** 68,71 **** |
| --- 73,86 ---- |
| add_definitions(-DWIN32_LEAN_AND_MEAN) |
| add_definitions(-D_CRT_SECURE_NO_WARNINGS) |
| + |
| + # Use the static C library for all build types |
| + foreach(var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE |
| + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO |
| + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE |
| + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) |
| + if(${var} MATCHES "/MD") |
| + string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}") |
| + endif() |
| + endforeach() |
| endif(MSVC) |
| if(CMAKE_C_COMPILER_ID STREQUAL GNU) |
| *** fltk-1.3.0/FL/Enumerations.H 2011-05-21 16:55:59.000000000 -0500 |
| --- fltk-1.3.0-new/FL/Enumerations.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 293,297 **** |
| following FL_PASTE event. |
| */ |
| ! FL_DND_RELEASE = 23 |
| }; |
| |
| --- 293,302 ---- |
| following FL_PASTE event. |
| */ |
| ! FL_DND_RELEASE = 23, |
| ! |
| ! /** The fullscreen state of the window has changed |
| ! */ |
| ! FL_FULLSCREEN = 24 |
| ! |
| }; |
| |
| *************** |
| *** 875,907 **** |
| /** 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. |
| |
| \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. */ |
| }; |
| /*@}*/ // group: Cursors |
| --- 880,913 ---- |
| /** The following constants define the mouse cursors that are available in FLTK. |
| |
| ! 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 = 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 |
| *** fltk-1.3.0/FL/Fl.H 2011-05-23 13:01:29.000000000 -0500 |
| --- fltk-1.3.0-new/FL/Fl.H 2011-06-22 22:35:31.000000000 -0500 |
| *************** |
| *** 109,112 **** |
| --- 109,115 ---- |
| 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 */ |
| |
| *************** |
| *** 745,748 **** |
| --- 748,764 ---- |
| 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 |
| *** fltk-1.3.0/FL/Fl_Image.H 2011-01-30 03:24:40.000000000 -0600 |
| --- fltk-1.3.0-new/FL/Fl_Image.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 35,38 **** |
| --- 35,39 ---- |
| |
| class Fl_Widget; |
| + class Fl_Pixmap; |
| struct Fl_Menu_Item; |
| struct Fl_Label; |
| *************** |
| *** 197,200 **** |
| --- 198,202 ---- |
| 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); |
| *** fltk-1.3.0/FL/Fl_Widget.H 2011-04-24 12:09:41.000000000 -0500 |
| --- fltk-1.3.0-new/FL/Fl_Widget.H 2011-06-22 22:41:26.000000000 -0500 |
| *************** |
| *** 109,112 **** |
| --- 109,113 ---- |
| class FL_EXPORT Fl_Widget { |
| friend class Fl_Group; |
| + friend class Fl_X; |
| |
| Fl_Group* parent_; |
| *************** |
| *** 180,183 **** |
| --- 181,186 ---- |
| 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 |
| + SIMPLE_KEYBOARD = 1<<18, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input) |
| + FULLSCREEN = 1<<19, ///< a fullscreen window (Fl_Window) |
| // (space for more flags) |
| USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions |
| *************** |
| *** 785,788 **** |
| --- 788,820 ---- |
| 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 |
| *************** |
| *** 853,856 **** |
| --- 885,891 ---- |
| /* Internal use only. */ |
| static int test_shortcut(const char*, const bool require_alt = false); |
| + /* Internal use only. */ |
| + void _set_fullscreen() {flags_ |= FULLSCREEN;} |
| + void _clear_fullscreen() {flags_ &= ~FULLSCREEN;} |
| |
| /** Checks if w is a child of this widget. |
| *** fltk-1.3.0/FL/Fl_Window.H 2011-04-15 16:38:05.000000000 -0500 |
| --- fltk-1.3.0-new/FL/Fl_Window.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 38,41 **** |
| --- 38,42 ---- |
| |
| class Fl_X; |
| + class Fl_RGB_Image; |
| |
| /** |
| *************** |
| *** 70,76 **** |
| int dw, dh, aspect; |
| uchar size_range_set; |
| // cursor stuff |
| Fl_Cursor cursor_default; |
| - Fl_Color cursor_fg, cursor_bg; |
| void size_range_(); |
| void _Fl_Window(); // constructor innards |
| --- 71,77 ---- |
| int dw, dh, aspect; |
| uchar size_range_set; |
| + int no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h; |
| // cursor stuff |
| Fl_Cursor cursor_default; |
| void size_range_(); |
| void _Fl_Window(); // constructor innards |
| *************** |
| *** 385,392 **** |
| Makes the window completely fill the screen, without any window |
| manager border visible. You must use fullscreen_off() to undo |
| ! this. This may not work with all window managers. |
| */ |
| void fullscreen(); |
| /** |
| Turns off any side effects of fullscreen() and does |
| resize(x,y,w,h). |
| --- 386,401 ---- |
| Makes the window completely fill the screen, 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. |
| */ |
| void fullscreen(); |
| /** |
| + Turns off any side effects of fullscreen() |
| + */ |
| + void fullscreen_off(); |
| + /** |
| Turns off any side effects of fullscreen() and does |
| resize(x,y,w,h). |
| *************** |
| *** 394,397 **** |
| --- 403,410 ---- |
| void fullscreen_off(int,int,int,int); |
| /** |
| + Returns non zero if FULLSCREEN flag is set, 0 otherwise. |
| + */ |
| + unsigned int fullscreen_active() const { return flags() & FULLSCREEN; } |
| + /** |
| Iconifies the window. If you call this when shown() is false |
| it will show() it as an icon. If the window is already |
| *************** |
| *** 435,446 **** |
| |
| The type Fl_Cursor is an enumeration defined in <FL/Enumerations.H>. |
| - (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. |
| */ |
| ! 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); |
| static void default_callback(Fl_Window*, void* v); |
| |
| --- 448,462 ---- |
| |
| The type Fl_Cursor is an enumeration defined in <FL/Enumerations.H>. |
| |
| ! \see cursor(const Fl_RGB_Image*, int, int), default_cursor() |
| */ |
| ! 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) { cursor(c); }; |
| ! void default_cursor(Fl_Cursor c, Fl_Color, Fl_Color=FL_WHITE) { default_cursor(c); }; |
| ! |
| static void default_callback(Fl_Window*, void* v); |
| |
| *** fltk-1.3.0/FL/fl_draw.H 2011-06-02 03:06:09.000000000 -0500 |
| --- fltk-1.3.0-new/FL/fl_draw.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 758,762 **** |
| 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 const char* fl_expand_text(const char* from, char* buf, int maxbuf, |
| double maxw, int& n, double &width, |
| --- 758,763 ---- |
| 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_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, |
| *** fltk-1.3.0/FL/mac.H 2011-05-12 06:50:43.000000000 -0500 |
| --- fltk-1.3.0-new/FL/mac.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 142,146 **** |
| WindowRef window_ref(void); |
| void set_key_window(void); |
| ! void set_cursor(Fl_Cursor); |
| 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); |
| --- 142,147 ---- |
| WindowRef window_ref(void); |
| void set_key_window(void); |
| ! 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); |
| *** fltk-1.3.0/FL/names.h 2010-11-28 15:06:39.000000000 -0600 |
| --- fltk-1.3.0-new/FL/names.h 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 76,79 **** |
| --- 76,80 ---- |
| "FL_DND_LEAVE", |
| "FL_DND_RELEASE", |
| + "FL_FULLSCREEN" |
| }; |
| |
| *** fltk-1.3.0/FL/win32.H 2011-05-23 13:32:47.000000000 -0500 |
| --- fltk-1.3.0-new/FL/win32.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 93,96 **** |
| --- 93,98 ---- |
| 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*); |
| }; |
| *** fltk-1.3.0/FL/x.H 2011-05-21 05:05:19.000000000 -0500 |
| --- fltk-1.3.0-new/FL/x.H 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 164,167 **** |
| --- 164,169 ---- |
| 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); |
| *** fltk-1.3.0/configh.in 2011-06-09 11:21:40.000000000 -0500 |
| --- fltk-1.3.0-new/configh.in 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 118,121 **** |
| --- 118,137 ---- |
| |
| /* |
| + * HAVE_XFIXES: |
| + * |
| + * Do we have the X fixes extension? |
| + */ |
| + |
| + #define HAVE_XFIXES 0 |
| + |
| + /* |
| + * HAVE_XCURSOR: |
| + * |
| + * Do we have the X cursor library? |
| + */ |
| + |
| + #define HAVE_XCURSOR 0 |
| + |
| + /* |
| * __APPLE_QUARTZ__: |
| * |
| *** fltk-1.3.0/configure.in 2011-03-06 10:54:58.000000000 -0600 |
| --- fltk-1.3.0-new/configure.in 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 875,878 **** |
| --- 875,880 ---- |
| # 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 |
| *************** |
| *** 1007,1010 **** |
| --- 1009,1032 ---- |
| 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 <X11/Xlib.h>]) |
| + AC_CHECK_LIB(Xfixes, XFixesQueryExtension, |
| + 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 <X11/Xlib.h>]) |
| + AC_CHECK_LIB(Xcursor, XcursorImageCreate, |
| + LIBS="-lXcursor $LIBS") |
| + fi |
| + |
| dnl Check for overlay visuals... |
| AC_PATH_PROG(XPROP, xprop) |
| *** fltk-1.3.0/documentation/src/enumerations.dox 2011-05-11 10:49:30.000000000 -0500 |
| --- fltk-1.3.0-new/documentation/src/enumerations.dox 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 58,61 **** |
| --- 58,62 ---- |
| data. |
| \li FL_DND_RELEASE - Dragged data is about to be dropped. |
| + \li FL_FULLSCREEN - The fullscreen state of the window has changed. |
| |
| |
| *** fltk-1.3.0/documentation/src/events.dox 2011-05-11 10:49:30.000000000 -0500 |
| --- fltk-1.3.0-new/documentation/src/events.dox 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 301,304 **** |
| --- 301,311 ---- |
| the immediately following \p FL_PASTE event. |
| |
| + \subsection events_fl_fullscreen FL_FULLSCREEN |
| + |
| + The application window has been changed from normal to fullscreen, or |
| + from fullscreen to normal. If you are using a X window manager which |
| + supports Extended Window Manager Hints, this event will not be |
| + delivered until the change has actually happened. |
| + |
| |
| \section events_event_xxx Fl::event_*() methods |
| *** fltk-1.3.0/src/Fl.cxx 2011-05-23 11:49:02.000000000 -0500 |
| --- fltk-1.3.0.new/src/Fl.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 80,83 **** |
| --- 80,85 ---- |
| #endif // WIN32 |
| |
| + extern void fl_update_focus(void); |
| + |
| // |
| // Globals... |
| *************** |
| *** 445,448 **** |
| --- 447,513 ---- |
| |
| //////////////////////////////////////////////////////////////// |
| + // 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_<platform>.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: |
| |
| *************** |
| *** 881,884 **** |
| --- 946,951 ---- |
| } |
| e_number = old_event; |
| + // let the platform code do what it needs |
| + fl_update_focus(); |
| } |
| } |
| *************** |
| *** 1362,1366 **** |
| // hide() destroys the X window, it does not do unmap! |
| |
| ! #if !defined(WIN32) && USE_XFT |
| extern void fl_destroy_xft_draw(Window); |
| #endif |
| --- 1429,1436 ---- |
| // 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); |
| #endif |
| *************** |
| *** 1409,1420 **** |
| // 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(); |
| ! } |
| ! } |
| // Send a message to myself so that I'll get out of the event loop... |
| PostMessage(ip->xid, WM_APP, 0, 0); |
| --- 1479,1486 ---- |
| // 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_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); |
| *** fltk-1.3.0/src/Fl_Image.cxx 2011-04-20 09:01:04.000000000 -0500 |
| --- fltk-1.3.0.new/src/Fl_Image.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 173,176 **** |
| --- 173,189 ---- |
| // RGB image class... |
| // |
| + |
| + 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. */ |
| + 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 free all memory and server resources that are used by the image. */ |
| Fl_RGB_Image::~Fl_RGB_Image() { |
| *** fltk-1.3.0/src/Fl_Window.cxx 2011-02-25 02:44:47.000000000 -0600 |
| --- fltk-1.3.0.new/src/Fl_Window.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 60,63 **** |
| --- 60,67 ---- |
| size_range_set = 0; |
| minw = maxw = minh = maxh = 0; |
| + no_fullscreen_x = 0; |
| + no_fullscreen_y = 0; |
| + no_fullscreen_w = w(); |
| + no_fullscreen_h = h(); |
| callback((Fl_Callback*)default_callback); |
| } |
| *************** |
| *** 66,71 **** |
| : Fl_Group(X, Y, W, H, l) { |
| cursor_default = FL_CURSOR_DEFAULT; |
| - cursor_fg = FL_BLACK; |
| - cursor_bg = FL_WHITE; |
| |
| _Fl_Window(); |
| --- 70,73 ---- |
| *************** |
| *** 77,82 **** |
| : 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(); |
| --- 79,82 ---- |
| *** fltk-1.3.0/src/Fl_Window_fullscreen.cxx 2011-03-12 15:36:21.000000000 -0600 |
| --- fltk-1.3.0.new/src/Fl_Window_fullscreen.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 61,97 **** |
| } |
| |
| void Fl_Window::fullscreen() { |
| ! #ifndef WIN32 |
| ! //this would clobber the fake wm, since it relies on the border flags to |
| ! //determine its thickness |
| ! border(0); |
| ! #endif |
| ! #if defined(__APPLE__) || defined(WIN32) || defined(USE_X11) |
| ! int sx, sy, sw, sh; |
| ! Fl::screen_xywh(sx, sy, sw, sh, x(), y(), w(), h()); |
| ! // if we are on the main screen, we will leave the system menu bar unobstructed |
| ! if (Fl::x()>=sx && Fl::y()>=sy && Fl::x()+Fl::w()<=sx+sw && Fl::y()+Fl::h()<=sy+sh) { |
| ! sx = Fl::x(); sy = Fl::y(); |
| ! sw = Fl::w(); sh = Fl::h(); |
| } |
| - if (x()==sx) x(sx+1); // make sure that we actually execute the resize |
| - #if defined(USE_X11) |
| - resize(0, 0, w(), h()); // work around some quirks in X11 |
| - #endif |
| - resize(sx, sy, sw, sh); |
| - #else |
| - if (!x()) x(1); // make sure that we actually execute the resize |
| - resize(0,0,Fl::w(),Fl::h()); |
| - #endif |
| } |
| |
| void Fl_Window::fullscreen_off(int X,int Y,int W,int H) { |
| ! // this order produces less blinking on IRIX: |
| ! resize(X,Y,W,H); |
| ! #ifndef WIN32 |
| ! border(1); |
| ! #endif |
| } |
| |
| // |
| // End of "$Id: Fl_Window_fullscreen.cxx 8515 2011-03-12 21:36:21Z manolo $". |
| --- 61,106 ---- |
| } |
| |
| + void fullscreen_x(Fl_Window *w); |
| + void fullscreen_off_x(); |
| + void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H); |
| + |
| + /* Note: The previous implementation toggled border(). With this new |
| + implementation this is not necessary. Additionally, if we do that, |
| + the application may lose focus when switching out of fullscreen |
| + mode with some window managers. Besides, the API does not say that |
| + the FLTK border state should be toggled; it only says that the |
| + borders should not be *visible*. |
| + */ |
| void Fl_Window::fullscreen() { |
| ! if (shown() && !(flags() & Fl_Widget::FULLSCREEN)) { |
| ! no_fullscreen_x = x(); |
| ! no_fullscreen_y = y(); |
| ! no_fullscreen_w = w(); |
| ! no_fullscreen_h = h(); |
| ! fullscreen_x(this); |
| ! } else { |
| ! set_flag(FULLSCREEN); |
| } |
| } |
| |
| void Fl_Window::fullscreen_off(int X,int Y,int W,int H) { |
| ! if (shown() && (flags() & Fl_Widget::FULLSCREEN)) { |
| ! fullscreen_off_x(this, X, Y, W, H); |
| ! } else { |
| ! clear_flag(FULLSCREEN); |
| ! } |
| ! no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0; |
| ! } |
| ! |
| ! void Fl_Window::fullscreen_off() { |
| ! if (!no_fullscreen_x && !no_fullscreen_y) { |
| ! // Window was initially created fullscreen - default to current monitor |
| ! no_fullscreen_x = x(); |
| ! no_fullscreen_y = y(); |
| ! } |
| ! fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h); |
| } |
| |
| + |
| // |
| // End of "$Id: Fl_Window_fullscreen.cxx 8515 2011-03-12 21:36:21Z manolo $". |
| *** fltk-1.3.0/src/Fl_cocoa.mm 2011-06-16 07:35:32.000000000 -0500 |
| --- fltk-1.3.0.new/src/Fl_cocoa.mm 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 62,65 **** |
| --- 62,66 ---- |
| |
| #import <Cocoa/Cocoa.h> |
| + #import <Carbon/Carbon.h> |
| |
| #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h |
| *************** |
| *** 108,112 **** |
| 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 |
| --- 109,112 ---- |
| *************** |
| *** 125,128 **** |
| --- 125,130 ---- |
| #endif |
| |
| + bool use_simple_keyboard = false; |
| + |
| enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; |
| |
| *************** |
| *** 141,144 **** |
| --- 143,179 ---- |
| } |
| |
| + // 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 |
| *************** |
| *** 615,618 **** |
| --- 650,657 ---- |
| containsGLsubwindow = contains; |
| } |
| + - (BOOL)canBecomeKeyWindow |
| + { |
| + return YES; |
| + } |
| @end |
| |
| *************** |
| *** 844,847 **** |
| --- 883,905 ---- |
| @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 |
| *************** |
| *** 1034,1037 **** |
| --- 1092,1099 ---- |
| FLWindow *nsw = (FLWindow*)[notif object]; |
| Fl_Window *window = [nsw getFl_Window]; |
| + /* Fullscreen windows obscure all other windows so we need to return |
| + to a "normal" level when the user switches to another window */ |
| + if (window->fullscreen_active()) |
| + [nsw setLevel:NSNormalWindowLevel]; |
| Fl::handle( FL_UNFOCUS, window); |
| fl_unlock_function(); |
| *************** |
| *** 1042,1045 **** |
| --- 1104,1110 ---- |
| FLWindow *nsw = (FLWindow*)[notif object]; |
| Fl_Window *w = [nsw getFl_Window]; |
| + /* Restore previous fullscreen level */ |
| + if (w->fullscreen_active()) |
| + [nsw setLevel:NSStatusWindowLevel]; |
| if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle( FL_FOCUS, w); |
| fl_unlock_function(); |
| *************** |
| *** 1229,1235 **** |
| --- 1294,1304 ---- |
| @end |
| |
| + static void clipboard_check(void); |
| + |
| @implementation FLApplication |
| + (void)sendEvent:(NSEvent *)theEvent |
| { |
| + // update clipboard status |
| + clipboard_check(); |
| NSEventType type = [theEvent type]; |
| if (type == NSLeftMouseDown) { |
| *************** |
| *** 1286,1291 **** |
| while (ign_event); |
| |
| - fl_default_cursor = [NSCursor arrowCursor]; |
| - |
| // bring the application into foreground without a 'CARB' resource |
| Boolean same_psn; |
| --- 1355,1358 ---- |
| *************** |
| *** 1587,1590 **** |
| --- 1654,1658 ---- |
| - (BOOL)acceptsFirstResponder; |
| - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; |
| + - (void)resetCursorRects; |
| - (BOOL)performKeyEquivalent:(NSEvent*)theEvent; |
| - (void)mouseUp:(NSEvent *)theEvent; |
| *************** |
| *** 1644,1647 **** |
| --- 1712,1725 ---- |
| 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); |
| *************** |
| *** 1703,1708 **** |
| } |
| } |
| if (!no_text_key && !(Fl::e_state & FL_META) ) { |
| ! // Don't send cmd-<key> to interpretKeyEvents because it beeps. |
| // Then we can let the OS have a stab at it and see if it thinks it |
| // should result in some text |
| --- 1781,1791 ---- |
| } |
| } |
| + // Don't send cmd-<key> to interpretKeyEvents because it beeps. |
| if (!no_text_key && !(Fl::e_state & FL_META) ) { |
| ! // 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) |
| ! [FLView prepareEtext:[theEvent charactersIgnoringModifiers]]; |
| ! |
| // Then we can let the OS have a stab at it and see if it thinks it |
| // should result in some text |
| *************** |
| *** 1883,1901 **** |
| |
| if (!in_key_event) fl_lock_function(); |
| [FLView prepareEtext:received]; |
| // We can get called outside of key events (e.g. from the character |
| ! // palette). Transform such actions to FL_PASTE events. |
| if (!in_key_event) { |
| Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; |
| ! Fl::handle(FL_PASTE, 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(); |
| } |
| if (!in_key_event) fl_unlock_function(); |
| } |
| |
| - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { |
| ! NSString *received; |
| if (newSelection.location == 0) { |
| [self unmarkText]; |
| --- 1966,1993 ---- |
| |
| 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). 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); |
| // 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, *current, *aggregate; |
| if (newSelection.location == 0) { |
| [self unmarkText]; |
| *************** |
| *** 1908,1916 **** |
| } |
| //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); |
| // This code creates the OS X behaviour of seeing dead keys as things |
| // are being composed. |
| 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); |
| } |
| |
| --- 2000,2044 ---- |
| } |
| //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; |
| ! 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(); |
| } |
| |
| *************** |
| *** 1982,1985 **** |
| --- 2110,2129 ---- |
| @end |
| |
| + void fullscreen_x(Fl_Window *w) { |
| + w->_set_fullscreen(); |
| + /* On OS X < 10.6, it is necessary to recreate the window. This is done |
| + with hide+show. */ |
| + w->hide(); |
| + w->show(); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| + |
| + void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) { |
| + w->_clear_fullscreen(); |
| + w->hide(); |
| + w->resize(X, Y, W, H); |
| + w->show(); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| |
| /* |
| *************** |
| *** 1997,2001 **** |
| x->region = 0; |
| x->subRegion = 0; |
| ! x->cursor = fl_default_cursor; |
| x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz |
| Fl_Window *win = w->window(); |
| --- 2141,2145 ---- |
| x->region = 0; |
| x->subRegion = 0; |
| ! x->cursor = NULL; |
| x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz |
| Fl_Window *win = w->window(); |
| *************** |
| *** 2099,2103 **** |
| x->region = 0; |
| x->subRegion = 0; |
| ! x->cursor = fl_default_cursor; |
| x->xidChildren = 0; |
| x->xidNext = 0; |
| --- 2243,2247 ---- |
| x->region = 0; |
| x->subRegion = 0; |
| ! x->cursor = NULL; |
| x->xidChildren = 0; |
| x->xidNext = 0; |
| *************** |
| *** 2105,2108 **** |
| --- 2249,2259 ---- |
| |
| NSRect srect = [[NSScreen mainScreen] frame]; |
| + if (w->flags() & Fl_Widget::FULLSCREEN) { |
| + 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); |
| + winstyle = NSBorderlessWindowMask; |
| + winlevel = NSStatusWindowLevel; |
| + } |
| NSRect crect; |
| crect.origin.x = w->x(); |
| *************** |
| *** 2553,2556 **** |
| --- 2704,2728 ---- |
| } |
| |
| + 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); |
| + } |
| + |
| void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data) |
| { |
| *************** |
| *** 2677,2680 **** |
| --- 2849,2856 ---- |
| [(NSWindow *)xid close]; |
| } |
| + if (cursor) { |
| + [(NSCursor*)cursor release]; |
| + cursor = NULL; |
| + } |
| } |
| |
| *************** |
| *** 2792,2857 **** |
| } |
| |
| ! static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() ) |
| { |
| ! 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]; |
| } |
| - 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; |
| } |
| ! [icrsr set]; |
| ! cursor = icrsr; |
| } |
| |
| --- 2968,3071 ---- |
| } |
| |
| ! int Fl_X::set_cursor(Fl_Cursor c) |
| { |
| ! if (cursor) { |
| ! [(NSCursor*)cursor release]; |
| ! cursor = NULL; |
| } |
| |
| switch (c) { |
| ! 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(); |
| } |
| ! |
| ! 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; |
| } |
| |
| *** fltk-1.3.0/src/Fl_grab.cxx 2010-12-18 16:31:01.000000000 -0600 |
| --- fltk-1.3.0.new/src/Fl_grab.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 39,42 **** |
| --- 39,43 ---- |
| |
| extern void fl_fix_focus(); // in Fl.cxx |
| + void fl_update_focus(void); |
| |
| #ifdef WIN32 |
| *************** |
| *** 51,55 **** |
| --- 52,68 ---- |
| #endif |
| |
| + #if !(defined(WIN32) || defined(__APPLE__)) |
| + extern int ewmh_supported(); // from Fl_x.cxx |
| + #endif |
| + |
| void Fl::grab(Fl_Window* win) { |
| + Fl_Window *fullscreen_win = NULL; |
| + for (Fl_Window *W = Fl::first_window(); W; W = Fl::next_window(W)) { |
| + if (W->fullscreen_active()) { |
| + fullscreen_win = W; |
| + break; |
| + } |
| + } |
| + |
| if (win) { |
| if (!grab_) { |
| *************** |
| *** 61,66 **** |
| Fl_X::i(first_window())->set_key_window(); |
| #else |
| XGrabPointer(fl_display, |
| ! fl_xid(first_window()), |
| 1, |
| ButtonPressMask|ButtonReleaseMask| |
| --- 74,80 ---- |
| Fl_X::i(first_window())->set_key_window(); |
| #else |
| + Window xid = fullscreen_win ? fl_xid(fullscreen_win) : fl_xid(first_window()); |
| XGrabPointer(fl_display, |
| ! xid, |
| 1, |
| ButtonPressMask|ButtonReleaseMask| |
| *************** |
| *** 72,76 **** |
| fl_event_time); |
| XGrabKeyboard(fl_display, |
| ! fl_xid(first_window()), |
| 1, |
| GrabModeAsync, |
| --- 86,90 ---- |
| fl_event_time); |
| XGrabKeyboard(fl_display, |
| ! xid, |
| 1, |
| GrabModeAsync, |
| *************** |
| *** 80,83 **** |
| --- 94,98 ---- |
| } |
| grab_ = win; |
| + fl_update_focus(); |
| } else { |
| if (grab_) { |
| *************** |
| *** 88,92 **** |
| --- 103,110 ---- |
| fl_capture = 0; |
| #else |
| + // We must keep the grab in the non-EWMH fullscreen case |
| + if (!fullscreen_win || ewmh_supported()) { |
| XUngrabKeyboard(fl_display, fl_event_time); |
| + } |
| XUngrabPointer(fl_display, fl_event_time); |
| // this flush is done in case the picked menu item goes into |
| *************** |
| *** 95,98 **** |
| --- 113,117 ---- |
| #endif |
| grab_ = 0; |
| + fl_update_focus(); |
| fl_fix_focus(); |
| } |
| *** fltk-1.3.0/src/Fl_win32.cxx 2011-05-30 07:33:51.000000000 -0500 |
| --- fltk-1.3.0.new/src/Fl_win32.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 99,102 **** |
| --- 99,104 ---- |
| 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) |
| *************** |
| *** 132,135 **** |
| --- 134,139 ---- |
| */ |
| 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; |
| *************** |
| *** 147,150 **** |
| --- 151,155 ---- |
| 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"); |
| *************** |
| *** 425,429 **** |
| } |
| |
| ! TranslateMessage(&fl_msg); |
| DispatchMessageW(&fl_msg); |
| have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); |
| --- 430,439 ---- |
| } |
| |
| ! // 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); |
| *************** |
| *** 543,546 **** |
| --- 553,586 ---- |
| }; |
| |
| + void fl_update_clipboard(void) { |
| + HWND hwnd = fl_xid(Fl::first_window()); |
| + |
| + if (!hwnd) |
| + return; |
| + |
| + 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) { |
| *************** |
| *** 560,582 **** |
| 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; |
| ! } |
| ! } |
| } |
| |
| --- 600,606 ---- |
| fl_selection_buffer[clipboard][len] = 0; // needed for direct paste |
| fl_selection_length[clipboard] = len; |
| ! fl_i_own_selection[clipboard] = 1; |
| ! if (clipboard) |
| ! fl_update_clipboard(); |
| } |
| |
| *************** |
| *** 631,634 **** |
| --- 655,690 ---- |
| } |
| |
| + 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; |
| *************** |
| *** 650,653 **** |
| --- 706,752 ---- |
| } |
| |
| + 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; |
| |
| *************** |
| *** 797,800 **** |
| --- 896,920 ---- |
| } |
| |
| + 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 |
| *************** |
| *** 858,861 **** |
| --- 978,983 ---- |
| //fl_msg.lPrivate = ??? |
| |
| + MSG fl_orig_msg = fl_msg; |
| + |
| Fl_Window *window = fl_find(hWnd); |
| |
| *************** |
| *** 1037,1057 **** |
| Fl::e_state = state; |
| static char buffer[1024]; |
| - 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 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; |
| switch (Fl::e_keysym) { |
| case FL_KP + '0' : |
| --- 1159,1238 ---- |
| Fl::e_state = state; |
| static char buffer[1024]; |
| |
| + 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] & (1<<31))) |
| + 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; |
| + } |
| |
| ! // 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' : |
| *************** |
| *** 1085,1112 **** |
| 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. |
| --- 1266,1273 ---- |
| Fl::e_keysym = FL_Delete; |
| break; |
| } |
| } |
| } |
| + |
| Fl::e_text = buffer; |
| if (lParam & (1<<31)) { // key up events. |
| *************** |
| *** 1126,1129 **** |
| --- 1287,1291 ---- |
| static int delta = 0; // running total of all motion |
| delta += (SHORT)(HIWORD(wParam)); |
| + Fl::e_dx = 0; |
| Fl::e_dy = -delta / WHEEL_DELTA; |
| delta += Fl::e_dy * WHEEL_DELTA; |
| *************** |
| *** 1132,1135 **** |
| --- 1294,1312 ---- |
| } |
| |
| + // This is only defined on Vista and upwards... |
| + #ifndef WM_MOUSEHWHEEL |
| + #define WM_MOUSEHWHEEL 0x020E |
| + #endif |
| + |
| + case WM_MOUSEHWHEEL: { |
| + static int delta = 0; // running total of all motion |
| + delta += (SHORT)(HIWORD(wParam)); |
| + Fl::e_dy = 0; |
| + Fl::e_dx = delta / WHEEL_DELTA; |
| + delta -= Fl::e_dx * WHEEL_DELTA; |
| + if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window); |
| + return 0; |
| + } |
| + |
| case WM_GETMINMAXINFO: |
| Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); |
| *************** |
| *** 1186,1216 **** |
| 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;} |
| |
| default: |
| --- 1363,1386 ---- |
| return 1; |
| |
| ! 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: |
| *************** |
| *** 1321,1324 **** |
| --- 1491,1499 ---- |
| Y+=yoff; |
| |
| + if (w->flags() & Fl_Widget::FULLSCREEN) { |
| + X = Y = 0; |
| + bx = by = bt = 0; |
| + } |
| + |
| return ret; |
| } |
| *************** |
| *** 1371,1374 **** |
| --- 1546,1601 ---- |
| } |
| |
| + static void make_fullscreen(Fl_Window *w, Window xid, int X, int Y, int W, int H) { |
| + int sx, sy, sw, sh; |
| + Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H); |
| + 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); |
| + } |
| + |
| + void fullscreen_x(Fl_Window *w) { |
| + w->_set_fullscreen(); |
| + make_fullscreen(w, fl_xid(w), w->x(), w->y(), w->w(), w->h()); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| + |
| + void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) { |
| + w->_clear_fullscreen(); |
| + DWORD style = GetWindowLong(fl_xid(w), GWL_STYLE); |
| + // Remove the xid temporarily so that Fl_X::fake_X_wm() behaves like it |
| + // does in Fl_X::make(). |
| + HWND xid = fl_xid(w); |
| + Fl_X::i(w)->xid = NULL; |
| + int x, y, bt, bx, by; |
| + switch (Fl_X::fake_X_wm(w, x, y, bt, bx, by)) { |
| + case 0: |
| + break; |
| + case 1: |
| + style |= WS_CAPTION; |
| + break; |
| + case 2: |
| + if (w->border()) { |
| + style |= WS_THICKFRAME | WS_CAPTION; |
| + } |
| + break; |
| + } |
| + Fl_X::i(w)->xid = xid; |
| + // Adjust for decorations (but not if that puts the decorations |
| + // outside the screen) |
| + if ((X != w->x()) || (Y != w->y())) { |
| + X -= bx; |
| + Y -= by+bt; |
| + } |
| + W += bx*2; |
| + H += by*2+bt; |
| + SetWindowLong(fl_xid(w), GWL_STYLE, style); |
| + SetWindowPos(fl_xid(w), 0, X, Y, W, H, |
| + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| + |
| + |
| //////////////////////////////////////////////////////////////// |
| |
| *************** |
| *** 1409,1413 **** |
| 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 |
| --- 1636,1639 ---- |
| *************** |
| *** 1457,1461 **** |
| w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); |
| wcw.hIcon = wcw.hIconSm = (HICON)w->icon(); |
| ! wcw.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); |
| //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); |
| //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); |
| --- 1683,1687 ---- |
| w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); |
| wcw.hIcon = wcw.hIconSm = (HICON)w->icon(); |
| ! 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)); |
| *************** |
| *** 1500,1515 **** |
| switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) { |
| // No border (used for menus) |
| ! case 0: style |= WS_POPUP; |
| ! styleEx |= WS_EX_TOOLWINDOW; |
| break; |
| |
| // Thin border and title bar |
| ! case 1: style |= WS_DLGFRAME | WS_CAPTION; break; |
| |
| // Thick, resizable border and title bar, with maximize button |
| ! case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break; |
| } |
| if (by+bt) { |
| - if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX; |
| wp += 2*bx; |
| hp += 2*by+bt; |
| --- 1726,1749 ---- |
| switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) { |
| // No border (used for menus) |
| ! case 0: |
| ! style |= WS_POPUP; |
| ! styleEx |= WS_EX_TOOLWINDOW; |
| break; |
| |
| // Thin border and title bar |
| ! case 1: |
| ! style |= WS_DLGFRAME | WS_CAPTION; |
| ! if (!w->modal()) |
| ! style |= WS_SYSMENU | WS_MINIMIZEBOX; |
| ! break; |
| |
| // Thick, resizable border and title bar, with maximize button |
| ! case 2: |
| ! style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION; |
| ! if (!w->modal()) |
| ! style |= WS_MINIMIZEBOX; |
| ! break; |
| } |
| if (by+bt) { |
| wp += 2*bx; |
| hp += 2*by+bt; |
| *************** |
| *** 1541,1545 **** |
| x->region = 0; |
| x->private_dc = 0; |
| ! x->cursor = fl_default_cursor; |
| if (!fl_codepage) fl_get_codepage(); |
| |
| --- 1775,1779 ---- |
| x->region = 0; |
| x->private_dc = 0; |
| ! x->cursor = LoadCursor(NULL, IDC_ARROW); |
| if (!fl_codepage) fl_get_codepage(); |
| |
| *************** |
| *** 1567,1573 **** |
| --- 1801,1821 ---- |
| if (lab) free(lab); |
| |
| + if (w->flags() & Fl_Widget::FULLSCREEN) { |
| + /* We need to make sure that the fullscreen is created on the |
| + default monitor, ie the desktop where the shortcut is located |
| + etc. This requires that CreateWindow is called with CW_USEDEFAULT |
| + for x and y. We can then use GetWindowRect to determine which |
| + 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->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;} |
| *************** |
| *** 1582,1586 **** |
| // other windows from the code, or we lose the capture. |
| ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : |
| ! (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); |
| |
| // Register all windows for potential drag'n'drop operations |
| --- 1830,1834 ---- |
| // other windows from the code, or we lose the capture. |
| ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : |
| ! (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); |
| |
| // Register all windows for potential drag'n'drop operations |
| *************** |
| *** 1778,1781 **** |
| --- 2026,2152 ---- |
| |
| //////////////////////////////////////////////////////////////// |
| + |
| + #ifndef IDC_HAND |
| + # define IDC_HAND MAKEINTRESOURCE(32649) |
| + #endif // !IDC_HAND |
| + |
| + int Fl_X::set_cursor(Fl_Cursor c) { |
| + LPSTR n; |
| + |
| + if (c == FL_CURSOR_NONE) |
| + 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; |
| + } |
| + |
| + cursor = LoadCursor(NULL, n); |
| + if (cursor == NULL) |
| + return 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; |
| + |
| + 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(); |
| + 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); |
| + |
| + 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); |
| + |
| + ICONINFO ii; |
| + |
| + ii.fIcon = FALSE; |
| + ii.xHotspot = hotx; |
| + ii.yHotspot = hoty; |
| + ii.hbmMask = mask; |
| + ii.hbmColor = bitmap; |
| + |
| + cursor = CreateIconIndirect(&ii); |
| + |
| + DeleteObject(bitmap); |
| + DeleteObject(mask); |
| + |
| + SetCursor(cursor); |
| + |
| + return 1; |
| + } |
| + |
| + //////////////////////////////////////////////////////////////// |
| // Implement the virtual functions for the base Fl_Window class: |
| |
| *** fltk-1.3.0/src/Fl_x.cxx 2011-05-30 11:47:48.000000000 -0500 |
| --- fltk-1.3.0.new/src/Fl_x.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 53,56 **** |
| --- 53,65 ---- |
| # include <X11/Xlib.h> |
| # include <X11/keysym.h> |
| + # include <X11/cursorfont.h> |
| + |
| + # if HAVE_XCURSOR |
| + # include <X11/Xcursor/Xcursor.h> |
| + # endif |
| + |
| + # ifdef HAVE_XFIXES |
| + # include <X11/extensions/Xfixes.h> |
| + # endif |
| |
| static Fl_Xlib_Graphics_Driver fl_xlib_driver; |
| *************** |
| *** 301,306 **** |
| --- 310,318 ---- |
| 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; |
| + static bool have_xfixes = false; |
| + static int xfixes_event_base = 0; |
| |
| static Atom WM_DELETE_WINDOW; |
| *************** |
| *** 309,312 **** |
| --- 321,327 ---- |
| static Atom TARGETS; |
| static Atom CLIPBOARD; |
| + static Atom TIMESTAMP; |
| + static Atom PRIMARY_TIMESTAMP; |
| + static Atom CLIPBOARD_TIMESTAMP; |
| Atom fl_XdndAware; |
| Atom fl_XdndSelection; |
| *************** |
| *** 329,332 **** |
| --- 344,350 ---- |
| Atom fl_NET_WM_NAME; // utf8 aware window label |
| Atom fl_NET_WM_ICON_NAME; // utf8 aware window icon name |
| + Atom fl_NET_SUPPORTING_WM_CHECK; |
| + Atom fl_NET_WM_STATE; |
| + Atom fl_NET_WM_STATE_FULLSCREEN; |
| |
| /* |
| *************** |
| *** 582,585 **** |
| --- 600,662 ---- |
| } |
| |
| + 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; |
| *************** |
| *** 605,608 **** |
| --- 682,688 ---- |
| 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); |
| *************** |
| *** 626,629 **** |
| --- 706,712 ---- |
| fl_NET_WM_NAME = XInternAtom(d, "_NET_WM_NAME", 0); |
| fl_NET_WM_ICON_NAME = XInternAtom(d, "_NET_WM_ICON_NAME", 0); |
| + 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); |
| |
| if (sizeof(Atom) < 4) |
| *************** |
| *** 647,650 **** |
| --- 730,741 ---- |
| Fl::visual(FL_RGB); |
| #endif |
| + |
| + #ifdef HAVE_XFIXES |
| + int error_base; |
| + if (XFixesQueryExtension(d, &xfixes_event_base, &error_base)) |
| + have_xfixes = true; |
| + else |
| + have_xfixes = false; |
| + #endif |
| } |
| |
| *************** |
| *** 769,772 **** |
| --- 860,888 ---- |
| } |
| |
| + |
| + /* |
| + Get window property value (32 bit format) |
| + Returns zero on success, -1 on error |
| + */ |
| + static int get_xwinprop(Window wnd, Atom prop, long max_length, |
| + unsigned long *nitems, unsigned long **data) { |
| + Atom actual; |
| + int format; |
| + unsigned long bytes_after; |
| + |
| + if (Success != XGetWindowProperty(fl_display, wnd, prop, 0, max_length, |
| + False, AnyPropertyType, &actual, &format, |
| + nitems, &bytes_after, (unsigned char**)data)) { |
| + return -1; |
| + } |
| + |
| + if (actual == None || format != 32) { |
| + return -1; |
| + } |
| + |
| + return 0; |
| + } |
| + |
| + |
| //////////////////////////////////////////////////////////////// |
| // Code for copying to clipboard and DnD out of the program: |
| *************** |
| *** 788,791 **** |
| --- 904,995 ---- |
| |
| //////////////////////////////////////////////////////////////// |
| + // 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; |
| + |
| + // No polling needed with Xfixes |
| + if (have_xfixes) |
| + return; |
| + |
| + // 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) { |
| + // Initial scan, just store the value |
| + if (*timestamp == (Time)-1) { |
| + *timestamp = time; |
| + return; |
| + } |
| + } |
| + |
| + // Same selection |
| + if (time == *timestamp) |
| + return; |
| + |
| + *timestamp = 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) { |
| + poll_clipboard_owner(); |
| + |
| + if (!Fl::has_timeout(clipboard_timeout)) |
| + Fl::add_timeout(0.5, clipboard_timeout); |
| + } |
| + } |
| + } |
| + |
| + //////////////////////////////////////////////////////////////// |
| |
| const XEvent* fl_xevent; // the current x event |
| *************** |
| *** 865,872 **** |
| 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)) |
| { |
| XIM xim_im; |
| --- 1069,1075 ---- |
| fl_xevent = &thisevent; |
| Window xid = xevent.xany.window; |
| |
| if (fl_xim_ic && xevent.type == DestroyNotify && |
| ! xid != fl_xim_win && !fl_find(xid)) |
| { |
| XIM xim_im; |
| *************** |
| *** 883,929 **** |
| } |
| |
| ! 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 ( XFilterEvent((XEvent *)&xevent, 0) ) |
| - return(1); |
| - |
| switch (xevent.type) { |
| |
| --- 1086,1094 ---- |
| } |
| |
| ! if (fl_xim_ic) { |
| ! if (XFilterEvent((XEvent *)&xevent, 0)) |
| ! return 1; |
| } |
| |
| switch (xevent.type) { |
| |
| *************** |
| *** 937,941 **** |
| |
| case SelectionNotify: { |
| - if (!fl_selection_requestor) return 0; |
| static unsigned char* buffer = 0; |
| if (buffer) {XFree(buffer); buffer = 0;} |
| --- 1102,1105 ---- |
| *************** |
| *** 953,956 **** |
| --- 1117,1133 ---- |
| &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; |
| *************** |
| *** 989,992 **** |
| --- 1166,1172 ---- |
| convert_crlf(buffer, bytesread); |
| } |
| + |
| + if (!fl_selection_requestor) return 0; |
| + |
| Fl::e_text = buffer ? (char*)buffer : (char *)""; |
| Fl::e_length = bytesread; |
| *************** |
| *** 1009,1012 **** |
| --- 1189,1193 ---- |
| int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD; |
| fl_i_own_selection[clipboard] = 0; |
| + poll_clipboard_owner(); |
| return 1;} |
| |
| *************** |
| *** 1221,1224 **** |
| --- 1402,1408 ---- |
| 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; |
| |
| *************** |
| *** 1261,1273 **** |
| 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); |
| ! } |
| } |
| // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not |
| --- 1445,1457 ---- |
| len = XLookupString((XKeyEvent*)&(xevent.xkey), |
| buffer, buffer_len, &keysym, 0/*&compose*/); |
| ! // 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 |
| *************** |
| *** 1441,1444 **** |
| --- 1625,1629 ---- |
| Fl::e_keysym = FL_Button + xevent.xbutton.button; |
| set_event_xy(); |
| + Fl::e_dx = Fl::e_dy = 0; |
| if (xevent.xbutton.button == Button4) { |
| Fl::e_dy = -1; // Up |
| *************** |
| *** 1447,1450 **** |
| --- 1632,1641 ---- |
| Fl::e_dy = +1; // Down |
| event = FL_MOUSEWHEEL; |
| + } else if (xevent.xbutton.button == 6) { |
| + Fl::e_dx = -1; // Left |
| + event = FL_MOUSEWHEEL; |
| + } else if (xevent.xbutton.button == 7) { |
| + Fl::e_dx = +1; // Right |
| + event = FL_MOUSEWHEEL; |
| } else { |
| Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); |
| *************** |
| *** 1457,1460 **** |
| --- 1648,1676 ---- |
| break; |
| |
| + case PropertyNotify: |
| + if (xevent.xproperty.atom == fl_NET_WM_STATE) { |
| + int fullscreen_state = 0; |
| + if (xevent.xproperty.state != PropertyDelete) { |
| + unsigned long nitems; |
| + unsigned long *words = 0; |
| + if (0 == get_xwinprop(xid, fl_NET_WM_STATE, 64, &nitems, &words) ) { |
| + for (unsigned long item = 0; item < nitems; item++) { |
| + if (words[item] == fl_NET_WM_STATE_FULLSCREEN) { |
| + fullscreen_state = 1; |
| + } |
| + } |
| + } |
| + } |
| + if (window->fullscreen_active() && !fullscreen_state) { |
| + window->_clear_fullscreen(); |
| + event = FL_FULLSCREEN; |
| + } |
| + if (!window->fullscreen_active() && fullscreen_state) { |
| + window->_set_fullscreen(); |
| + event = FL_FULLSCREEN; |
| + } |
| + } |
| + break; |
| + |
| case MotionNotify: |
| set_event_xy(); |
| *************** |
| *** 1557,1560 **** |
| --- 1773,1795 ---- |
| } |
| |
| + #ifdef 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); |
| } |
| *************** |
| *** 1596,1599 **** |
| --- 1831,1903 ---- |
| //////////////////////////////////////////////////////////////// |
| |
| + #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ |
| + #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) { |
| + XEvent e; |
| + e.xany.type = ClientMessage; |
| + e.xany.window = wnd; |
| + e.xclient.message_type = fl_NET_WM_STATE; |
| + 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; |
| + XSendEvent(fl_display, RootWindow(fl_display, fl_screen), |
| + 0, SubstructureNotifyMask | SubstructureRedirectMask, |
| + &e); |
| + } |
| + |
| + int ewmh_supported() { |
| + static int result = -1; |
| + |
| + if (result == -1) { |
| + result = 0; |
| + unsigned long nitems; |
| + unsigned long *words = 0; |
| + if (0 == get_xwinprop(XRootWindow(fl_display, fl_screen), fl_NET_SUPPORTING_WM_CHECK, 64, |
| + &nitems, &words) && nitems == 1) { |
| + Window child = words[0]; |
| + if (0 == get_xwinprop(child, fl_NET_SUPPORTING_WM_CHECK, 64, |
| + &nitems, &words) && nitems == 1) { |
| + result = (child == words[0]); |
| + } |
| + } |
| + } |
| + |
| + return result; |
| + } |
| + |
| + /* Change an existing window to fullscreen */ |
| + void fullscreen_x(Fl_Window *w) { |
| + if (ewmh_supported()) { |
| + send_wm_state_event(fl_xid(w), 1, fl_NET_WM_STATE_FULLSCREEN); |
| + } else { |
| + w->_set_fullscreen(); |
| + w->hide(); |
| + w->show(); |
| + /* We want to grab the window, not a widget, so we cannot use Fl::grab */ |
| + XGrabKeyboard(fl_display, fl_xid(w), 1, GrabModeAsync, GrabModeAsync, fl_event_time); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| + } |
| + |
| + void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) { |
| + if (ewmh_supported()) { |
| + send_wm_state_event(fl_xid(w), 0, fl_NET_WM_STATE_FULLSCREEN); |
| + } else { |
| + w->_clear_fullscreen(); |
| + /* The grab will be lost when the window is destroyed */ |
| + w->hide(); |
| + w->resize(X,Y,W,H); |
| + w->show(); |
| + Fl::handle(FL_FULLSCREEN, w); |
| + } |
| + } |
| + |
| + //////////////////////////////////////////////////////////////// |
| + |
| // A subclass of Fl_Window may call this to associate an X window it |
| // creates with the Fl_Window: |
| *************** |
| *** 1631,1634 **** |
| --- 1935,1939 ---- |
| |ButtonPressMask|ButtonReleaseMask |
| |EnterWindowMask|LeaveWindowMask |
| + |PropertyChangeMask |
| |PointerMotionMask; |
| |
| *************** |
| *** 1702,1705 **** |
| --- 2007,2020 ---- |
| if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;} |
| } |
| + // For the non-EWMH fullscreen case, we cannot use the code above, |
| + // since we do not want save_under, do not want to turn off the |
| + // border, and cannot grab without an existing window. Besides, |
| + // there is no clear_override(). |
| + if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) { |
| + attr.override_redirect = 1; |
| + mask |= CWOverrideRedirect; |
| + Fl::screen_xywh(X, Y, W, H, X, Y, W, H); |
| + } |
| + |
| if (fl_background_pixel >= 0) { |
| attr.background_pixel = fl_background_pixel; |
| *************** |
| *** 1761,1764 **** |
| --- 2076,2085 ---- |
| } |
| |
| + // If asked for, create fullscreen |
| + if (win->flags() & Fl_Widget::FULLSCREEN && ewmh_supported()) { |
| + XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32, |
| + PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1); |
| + } |
| + |
| // Make it receptive to DnD: |
| long version = 4; |
| *************** |
| *** 1790,1793 **** |
| --- 2111,2124 ---- |
| } |
| |
| + #ifdef 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) { |
| *************** |
| *** 1798,1801 **** |
| --- 2129,2138 ---- |
| win->redraw(); |
| } |
| + |
| + // non-EWMH fullscreen case, need grab |
| + if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) { |
| + XGrabKeyboard(fl_display, xp->xid, 1, GrabModeAsync, GrabModeAsync, fl_event_time); |
| + } |
| + |
| } |
| |
| *************** |
| *** 1884,1887 **** |
| --- 2221,2312 ---- |
| //////////////////////////////////////////////////////////////// |
| |
| + 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) { |
| *** fltk-1.3.0/src/fl_cursor.cxx 2010-12-18 16:31:01.000000000 -0600 |
| --- fltk-1.3.0.new/src/fl_cursor.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 34,331 **** |
| #include <FL/Fl.H> |
| #include <FL/Fl_Window.H> |
| #include <FL/x.H> |
| - #if !defined(WIN32) && !defined(__APPLE__) |
| - # include <X11/cursorfont.h> |
| - #endif |
| #include <FL/fl_draw.H> |
| |
| /** |
| Sets the cursor for the current window to the specified shape and colors. |
| The cursors are defined in the <FL/Enumerations.H> header file. |
| */ |
| void fl_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { |
| ! if (Fl::first_window()) Fl::first_window()->cursor(c,fg,bg); |
| } |
| /** |
| ! Sets the default window cursor as well as its color. |
| |
| ! For back compatibility only. |
| */ |
| ! void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { |
| ! // if (c == FL_CURSOR_DEFAULT) c = FL_CURSOR_ARROW; |
| ! |
| cursor_default = c; |
| ! cursor_fg = fg; |
| ! cursor_bg = bg; |
| |
| ! cursor(c, fg, bg); |
| } |
| |
| - #ifdef WIN32 |
| |
| ! # ifndef IDC_HAND |
| ! # define IDC_HAND MAKEINTRESOURCE(32649) |
| ! # endif // !IDC_HAND |
| |
| - 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); |
| } |
| - SetCursor(i->cursor); |
| - } |
| |
| ! #elif defined(__APPLE__) |
| |
| ! #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 |
| ! |
| ! extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h); |
| ! |
| ! |
| ! CGContextRef Fl_X::help_cursor_image(void) |
| ! { |
| ! int w = 20, h = 20; |
| ! Fl_Offscreen off = fl_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; |
| ! } |
| |
| ! CGContextRef Fl_X::none_cursor_image(void) |
| ! { |
| ! int w = 20, h = 20; |
| ! Fl_Offscreen off = fl_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; |
| ! } |
| |
| ! CGContextRef Fl_X::watch_cursor_image(void) |
| ! { |
| ! int w, h, r = 5; |
| ! w = 2*r+6; |
| ! h = 4*r; |
| ! Fl_Offscreen off = fl_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; |
| ! } |
| |
| ! CGContextRef Fl_X::nesw_cursor_image(void) |
| ! { |
| ! int c = 7, r = 2*c; |
| ! int w = r, h = r; |
| ! Fl_Offscreen off = fl_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; |
| } |
| |
| ! CGContextRef Fl_X::nwse_cursor_image(void) |
| ! { |
| ! int c = 7, r = 2*c; |
| ! int w = r, h = r; |
| ! Fl_Offscreen off = fl_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); |
| ! } |
| |
| ! #else |
| |
| ! // I like the MSWindows resize cursors, so I duplicate them here: |
| |
| ! #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 |
| ! }; |
| ! |
| ! 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; |
| } |
| |
| ! 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); |
| } |
| - XDefineCursor(fl_display, fl_xid(this), xc); |
| - if (deleteit) XFreeCursor(fl_display, xc); |
| - } |
| |
| ! #endif |
| |
| // |
| --- 34,186 ---- |
| #include <FL/Fl.H> |
| #include <FL/Fl_Window.H> |
| + #include <FL/Fl_Pixmap.H> |
| + #include <FL/Fl_RGB_Image.H> |
| #include <FL/x.H> |
| #include <FL/fl_draw.H> |
| |
| + #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 <FL/Enumerations.H> 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) { |
| ! fl_cursor(c); |
| } |
| + |
| + |
| /** |
| ! 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. |
| |
| ! \see cursor(const Fl_RGB_Image*, int, int), default_cursor() |
| */ |
| ! void Fl_Window::default_cursor(Fl_Cursor c) { |
| cursor_default = c; |
| ! 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; |
| ! } |
| ! |
| ! Fl_Pixmap pxm(xpm); |
| ! Fl_RGB_Image image(&pxm); |
| ! |
| ! w->cursor(&image, hotx, hoty); |
| } |
| |
| |
| ! void Fl_Window::cursor(Fl_Cursor c) { |
| ! int ret; |
| |
| // 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); |
| ! return; |
| ! } |
| |
| ! if (c == FL_CURSOR_DEFAULT) |
| ! c = cursor_default; |
| |
| ! if (!i) |
| ! return; |
| |
| ! ret = i->set_cursor(c); |
| ! if (ret) |
| ! return; |
| |
| ! fallback_cursor(this, 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. |
| |
| ! The default cursor will be used if the provided image cannot be used |
| ! as a cursor. |
| |
| ! \see cursor(Fl_Cursor), default_cursor() |
| ! */ |
| ! void Fl_Window::cursor(const Fl_RGB_Image *image, int hotx, int hoty) { |
| ! int ret; |
| |
| ! // 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(image, hotx, hoty); |
| ! return; |
| } |
| |
| ! if (!i) |
| ! return; |
| ! |
| ! ret = i->set_cursor(image, hotx, hoty); |
| ! if (ret) |
| ! return; |
| ! |
| ! cursor(FL_CURSOR_DEFAULT); |
| ! } |
| |
| // |
| *** fltk-1.3.0/src/fl_draw_pixmap.cxx 2011-02-02 12:39:34.000000000 -0600 |
| --- fltk-1.3.0.new/src/fl_draw_pixmap.cxx 2011-06-22 22:46:30.000000000 -0500 |
| *************** |
| *** 68,164 **** |
| } |
| |
| - #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 |
| |
| --- 68,71 ---- |
| *************** |
| *** 210,223 **** |
| #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; |
| const uchar*const* data = (const uchar*const*)(cdata+1); |
| int transparent_index = -1; |
| uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color |
| #ifdef WIN32 |
| color_count = 0; |
| --- 117,134 ---- |
| #endif |
| |
| ! 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; |
| uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color |
| + |
| + if (!fl_measure_pixmap(cdata, w, h)) |
| + return 0; |
| + |
| + if ((chars_per_pixel < 1) || (chars_per_pixel > 2)) |
| + return 0; |
| + |
| + uchar (*colors)[4] = new uchar [1<<(chars_per_pixel*8)][4]; |
| + |
| #ifdef WIN32 |
| color_count = 0; |
| *************** |
| *** 225,229 **** |
| #endif |
| |
| ! if (ncolors < 0) { // FLTK (non standard) compressed colormap |
| ncolors = -ncolors; |
| const uchar *p = *data++; |
| --- 136,141 ---- |
| #endif |
| |
| ! if (ncolors < 0) { |
| ! // FLTK (non standard) compressed colormap |
| ncolors = -ncolors; |
| const uchar *p = *data++; |
| *************** |
| *** 231,241 **** |
| // it not be transparent): |
| if (*p == ' ') { |
| ! uchar* c = (uchar*)&d.colors[(int)' ']; |
| ! #ifdef U64 |
| ! *(U64*)c = 0; |
| ! # if WORDS_BIGENDIAN |
| ! c += 4; |
| ! # endif |
| ! #endif |
| transparent_index = ' '; |
| Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0; |
| --- 143,147 ---- |
| // it not be transparent): |
| if (*p == ' ') { |
| ! uchar* c = colors[(int)' ']; |
| transparent_index = ' '; |
| Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0; |
| *************** |
| *** 246,256 **** |
| // 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 |
| #ifdef WIN32 |
| used_colors[3*color_count] = *p; |
| --- 152,156 ---- |
| // read all the rest of the colors: |
| for (int i=0; i < ncolors; i++) { |
| ! uchar* c = colors[*p++]; |
| #ifdef WIN32 |
| used_colors[3*color_count] = *p; |
| *************** |
| *** 262,273 **** |
| *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)); |
| for (int i=0; i<ncolors; i++) { |
| const uchar *p = *data++; |
| --- 162,169 ---- |
| *c++ = *p++; |
| *c++ = *p++; |
| *c = 255; |
| } |
| ! } else { |
| ! // normal XPM colormap with names |
| for (int i=0; i<ncolors; i++) { |
| const uchar *p = *data++; |
| *************** |
| *** 275,334 **** |
| int ind = *p++; |
| uchar* c; |
| ! if (chars_per_pixel>1) { |
| ! #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]; |
| ! } |
| // 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++; |
| } |
| - #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]); |
| 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++; |
| #endif |
| ! } |
| ! 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__ |
| c[3] = 0; |
| ! #endif |
| ! transparent_index = ind; |
| ! transparent_c = c; |
| } |
| } |
| } |
| - d.data = data; |
| #ifdef WIN32 |
| if (transparent_c) { |
| --- 171,208 ---- |
| int ind = *p++; |
| uchar* c; |
| ! 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++; |
| } |
| 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++; |
| #endif |
| ! } else { |
| // assume "None" or "#transparent" for any errors |
| ! // "bg" should be transparent... |
| ! Fl::get_color(bg, c[0], c[1], c[2]); |
| c[3] = 0; |
| ! transparent_index = ind; |
| ! transparent_c = c; |
| } |
| } |
| } |
| #ifdef WIN32 |
| if (transparent_c) { |
| *************** |
| *** 340,425 **** |
| } |
| #endif |
| |
| #ifdef __APPLE_QUARTZ__ |
| if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) { |
| - bool transparent = (transparent_index>=0); |
| - transparent = true; |
| - 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++]; |
| - } |
| - } |
| - } |
| CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); |
| ! CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L); |
| ! CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w, |
| ! lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast, |
| ! src, 0L, false, kCGRenderingIntentDefault); |
| CGColorSpaceRelease(lut); |
| CGDataProviderRelease(src); |
| ! CGRect rect = { { x, y} , { d.w, d.h } }; |
| ! Fl_X::q_begin_image(rect, 0, 0, d.w, d.h); |
| CGContextDrawImage(fl_gc, rect, img); |
| Fl_X::q_end_image(); |
| CGImageRelease(img); |
| ! delete[] array; |
| ! } |
| ! 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]; |
| *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; |
| ! *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; |
| ! } |
| ! } |
| ! |
| ! if (bit > 1) *bitmap++ = b; |
| } |
| } |
| } |
| |
| ! fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4); |
| #ifdef __APPLE_QUARTZ__ |
| } |
| #endif |
| |
| ! if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i]; |
| return 1; |
| } |
| --- 214,300 ---- |
| } |
| #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); |
| + } |
| + } |
| + } |
| |
| + delete [] colors; |
| + 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 = new uchar[w*h*4]; |
| + |
| + if (!fl_convert_pixmap(cdata, buffer, bg)) { |
| + delete buffer; |
| + return 0; |
| + } |
| + |
| + // FIXME: Hack until fl_draw_image() supports alpha properly |
| #ifdef __APPLE_QUARTZ__ |
| if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) { |
| CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); |
| ! CGDataProviderRef src = CGDataProviderCreateWithData( 0L, buffer, w * h * 4, 0L); |
| ! CGImageRef img = CGImageCreate(w, h, 8, 4*8, 4*w, |
| ! lut, kCGImageAlphaLast, |
| ! src, 0L, false, kCGRenderingIntentDefault); |
| CGColorSpaceRelease(lut); |
| CGDataProviderRelease(src); |
| ! CGRect rect = { { x, y }, { w, h } }; |
| ! Fl_X::q_begin_image(rect, 0, 0, w, h); |
| CGContextDrawImage(fl_gc, rect, img); |
| Fl_X::q_end_image(); |
| CGImageRelease(img); |
| ! } else { |
| #endif // __APPLE_QUARTZ__ |
| // build the mask bitmap used by Fl_Pixmap: |
| ! if (fl_mask_bitmap) { |
| ! int W = (w+7)/8; |
| ! uchar* bitmap = new uchar[W * h]; |
| *fl_mask_bitmap = bitmap; |
| ! const uchar *p = &buffer[3]; |
| ! for (int Y = 0; Y < h; Y++) { |
| ! int dw = w; |
| ! for (int X = 0; X < W; X++) { |
| ! uchar b = 0; |
| ! for (int bit = 0x01;bit <= 0x80;bit<<=1) { |
| ! if (dw-- < 0) |
| ! break; |
| ! if (*p > 127) |
| ! b |= bit; |
| ! p += 4; |
| ! } |
| ! *bitmap++ = b; |
| } |
| } |
| } |
| |
| ! fl_draw_image(buffer, x, y, w, h, 4); |
| ! |
| #ifdef __APPLE_QUARTZ__ |
| } |
| #endif |
| |
| ! delete buffer; |
| return 1; |
| } |
| *** fltk-1.3.0/src/xutf8/imKStoUCS.c 2009-03-13 17:43:43.000000000 -0500 |
| --- fltk-1.3.0.new/src/xutf8/imKStoUCS.c 2011-06-22 22:35:31.000000000 -0500 |
| *************** |
| *** 267,270 **** |
| --- 267,276 ---- |
| }; |
| |
| + 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) |
| *************** |
| *** 316,319 **** |
| --- 322,327 ---- |
| 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; |
| *** fltk-1.3.0/test/cursor.cxx 2010-12-08 08:00:35.000000000 -0600 |
| --- fltk-1.3.0.new/test/cursor.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 33,38 **** |
| #include <FL/Fl_Box.H> |
| |
| - Fl_Color fg = FL_BLACK; |
| - Fl_Color bg = FL_WHITE; |
| Fl_Cursor cursor = FL_CURSOR_DEFAULT; |
| |
| --- 33,36 ---- |
| *************** |
| *** 42,46 **** |
| cursor = (Fl_Cursor)(fl_intptr_t)v; |
| cursor_slider->value(cursor); |
| ! fl_cursor(cursor,fg,bg); |
| } |
| |
| --- 40,44 ---- |
| cursor = (Fl_Cursor)(fl_intptr_t)v; |
| cursor_slider->value(cursor); |
| ! fl_cursor(cursor); |
| } |
| |
| *************** |
| *** 58,63 **** |
| {"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}, |
| --- 56,59 ---- |
| *************** |
| *** 68,72 **** |
| {"FL_CURSOR_W",0,choice_cb,(void*)FL_CURSOR_W}, |
| {"FL_CURSOR_NW",0,choice_cb,(void*)FL_CURSOR_NW}, |
| ! #endif |
| {0} |
| }; |
| --- 64,68 ---- |
| {"FL_CURSOR_W",0,choice_cb,(void*)FL_CURSOR_W}, |
| {"FL_CURSOR_NW",0,choice_cb,(void*)FL_CURSOR_NW}, |
| ! {"FL_CURSOR_NONE",0,choice_cb,(void*)FL_CURSOR_NONE}, |
| {0} |
| }; |
| *************** |
| *** 75,91 **** |
| 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); |
| } |
| |
| --- 71,75 ---- |
| Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o; |
| cursor = Fl_Cursor((int)slider->value()); |
| ! fl_cursor(cursor); |
| } |
| |
| *************** |
| *** 113,139 **** |
| slider1.step(1); |
| slider1.precision(0); |
| ! slider1.bounds(0,100); |
| 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... |
| --- 97,105 ---- |
| slider1.step(1); |
| slider1.precision(0); |
| ! slider1.bounds(0,255); |
| slider1.value(0); |
| slider1.callback(setcursor); |
| slider1.value(cursor); |
| |
| #if 0 |
| // draw the manual's diagram of cursors... |
| *** fltk-1.3.0/test/fullscreen.cxx 2010-12-15 06:11:16.000000000 -0600 |
| --- fltk-1.3.0.new/test/fullscreen.cxx 2011-06-22 22:35:32.000000000 -0500 |
| *************** |
| *** 61,66 **** |
| --- 61,69 ---- |
| #include <FL/Fl_Single_Window.H> |
| #include <FL/Fl_Hor_Slider.H> |
| + #include <FL/Fl_Input.H> |
| + #include <FL/Fl_Menu_Button.H> |
| #include <FL/Fl_Toggle_Light_Button.H> |
| #include <FL/math.h> |
| + #include <FL/fl_ask.H> |
| #include <stdio.h> |
| |
| *************** |
| *** 125,128 **** |
| --- 128,153 ---- |
| #endif |
| |
| + class fullscreen_window : public Fl_Single_Window { |
| + |
| + public: |
| + fullscreen_window(int W, int H, const char *t=0); |
| + int handle (int e); |
| + Fl_Toggle_Light_Button *b3; |
| + |
| + }; |
| + |
| + fullscreen_window::fullscreen_window(int W, int H, const char *t) : Fl_Single_Window(W, H, t) { |
| + |
| + } |
| + |
| + int fullscreen_window::handle(int e) { |
| + if (e == FL_FULLSCREEN) { |
| + printf("Recieved FL_FULLSCREEN event\n"); |
| + b3->value(fullscreen_active()); |
| + } |
| + if (Fl_Single_Window::handle(e)) return 1; |
| + return 0; |
| + } |
| + |
| void sides_cb(Fl_Widget *o, void *p) { |
| shape_window *sw = (shape_window *)p; |
| *************** |
| *** 162,172 **** |
| pw = w->w(); |
| ph = w->h(); |
| - #ifndef WIN32//necessary because fullscreen removes border |
| - border_button->value(0); |
| - border_button->do_callback(); |
| - #endif |
| w->fullscreen(); |
| } else { |
| ! w->fullscreen_off(px,py,pw,ph); |
| } |
| } |
| --- 187,198 ---- |
| pw = w->w(); |
| ph = w->h(); |
| 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(); |
| } |
| } |
| *************** |
| *** 178,182 **** |
| } |
| |
| ! #define NUMB 5 |
| |
| int twowindow = 0; |
| --- 204,208 ---- |
| } |
| |
| ! #define NUMB 6 |
| |
| int twowindow = 0; |
| *************** |
| *** 194,198 **** |
| Fl::fatal("Options are:\n -2 = 2 windows\n -f = startup fullscreen\n%s",Fl::help); |
| |
| ! Fl_Single_Window window(300,300+30*NUMB); window.end(); |
| |
| shape_window sw(10,10,window.w()-20,window.h()-30*NUMB-20); |
| --- 220,224 ---- |
| Fl::fatal("Options are:\n -2 = 2 windows\n -f = startup fullscreen\n%s",Fl::help); |
| |
| ! fullscreen_window window(300,300+30*NUMB); window.end(); |
| |
| shape_window sw(10,10,window.w()-20,window.h()-30*NUMB-20); |
| *************** |
| *** 229,232 **** |
| --- 255,261 ---- |
| y+=30; |
| |
| + Fl_Input i1(50,y,window.w()-60,30, "Input"); |
| + y+=30; |
| + |
| Fl_Toggle_Light_Button b2(50,y,window.w()-60,30,"Border"); |
| b2.callback(border_cb,w); |
| *************** |
| *** 235,240 **** |
| y+=30; |
| |
| ! Fl_Toggle_Light_Button b3(50,y,window.w()-60,30,"FullScreen"); |
| ! b3.callback(fullscreen_cb,w); |
| y+=30; |
| |
| --- 264,269 ---- |
| y+=30; |
| |
| ! window.b3 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"FullScreen"); |
| ! window.b3->callback(fullscreen_cb,w); |
| y+=30; |
| |
| *************** |
| *** 243,247 **** |
| y+=30; |
| |
| ! if (initfull) {b3.set(); b3.do_callback();} |
| |
| window.end(); |
| --- 272,276 ---- |
| y+=30; |
| |
| ! if (initfull) {window.b3->set(); window.b3->do_callback();} |
| |
| window.end(); |