blob: aa5898ce94e7c373dee8396a797c22ff4bdd4988 [file] [log] [blame]
Pierre Ossman554b3ee2011-06-09 10:47:19 +00001diff -up fltk-1.3.x-r8732/src/Fl_win32.cxx.hwheel fltk-1.3.x-r8732/src/Fl_win32.cxx
2--- fltk-1.3.x-r8732/src/Fl_win32.cxx.hwheel 2011-05-21 23:55:59.000000000 +0200
3+++ fltk-1.3.x-r8732/src/Fl_win32.cxx 2011-05-24 13:37:31.109341034 +0200
4@@ -1125,12 +1286,28 @@ static LRESULT CALLBACK WndProc(HWND hWn
5 case WM_MOUSEWHEEL: {
6 static int delta = 0; // running total of all motion
7 delta += (SHORT)(HIWORD(wParam));
8+ Fl::e_dx = 0;
9 Fl::e_dy = -delta / WHEEL_DELTA;
10 delta += Fl::e_dy * WHEEL_DELTA;
11 if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window);
12 return 0;
13 }
14
15+// This is only defined on Vista and upwards...
16+#ifndef WM_MOUSEHWHEEL
17+#define WM_MOUSEHWHEEL 0x020E
18+#endif
19+
20+ case WM_MOUSEHWHEEL: {
21+ static int delta = 0; // running total of all motion
22+ delta += (SHORT)(HIWORD(wParam));
23+ Fl::e_dy = 0;
24+ Fl::e_dx = delta / WHEEL_DELTA;
25+ delta -= Fl::e_dx * WHEEL_DELTA;
26+ if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window);
27+ return 0;
28+ }
29+
30 case WM_GETMINMAXINFO:
31 Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
32 break;
33diff -up fltk-1.3.x-r8732/src/Fl_x.cxx.hwheel fltk-1.3.x-r8732/src/Fl_x.cxx
34--- fltk-1.3.x-r8732/src/Fl_x.cxx.hwheel 2011-05-23 21:40:23.000000000 +0200
35+++ fltk-1.3.x-r8732/src/Fl_x.cxx 2011-05-24 13:36:49.635113914 +0200
36@@ -1441,12 +1608,19 @@ int fl_handle(const XEvent& thisevent)
37 case ButtonPress:
38 Fl::e_keysym = FL_Button + xevent.xbutton.button;
39 set_event_xy();
40+ Fl::e_dx = Fl::e_dy = 0;
41 if (xevent.xbutton.button == Button4) {
42 Fl::e_dy = -1; // Up
43 event = FL_MOUSEWHEEL;
44 } else if (xevent.xbutton.button == Button5) {
45 Fl::e_dy = +1; // Down
46 event = FL_MOUSEWHEEL;
47+ } else if (xevent.xbutton.button == 6) {
48+ Fl::e_dx = -1; // Left
49+ event = FL_MOUSEWHEEL;
50+ } else if (xevent.xbutton.button == 7) {
51+ Fl::e_dx = +1; // Right
52+ event = FL_MOUSEWHEEL;
53 } else {
54 Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1));
55 event = FL_PUSH;
56--- fltk-1.3.x-r8744/src/screen_xywh.cxx.fullscreen 2011-05-26 15:48:00.000000000 +0200
57+++ fltk-1.3.x-r8744/src/screen_xywh.cxx 2011-06-01 14:00:08.256046579 +0200
58@@ -202,81 +202,21 @@ int Fl::screen_count() {
59 \param[in] mx, my the absolute screen position
60 */
61 void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my) {
62- if (num_screens < 0) screen_init();
63-
64-#ifdef WIN32
65- if (num_screens > 0) {
66- int i;
67-
68- for (i = 0; i < num_screens; i ++) {
69- if (mx >= screens[i].left && mx < screens[i].right &&
70- my >= screens[i].top && my < screens[i].bottom) {
71- X = screens[i].left;
72- Y = screens[i].top;
73- W = screens[i].right - screens[i].left;
74- H = screens[i].bottom - screens[i].top;
75- return;
76- }
77- }
78- }
79- // if all else fails:
80- X = Fl::x();
81- Y = Fl::y();
82- W = Fl::w();
83- H = Fl::h();
84-#elif defined(__APPLE__)
85- if (num_screens > 0) {
86- int i;
87+ int screen = 0;
88+ int i;
89
90- for (i = 0; i < num_screens; i ++) {
91- if (mx >= screens[i].x &&
92- mx < (screens[i].x + screens[i].width) &&
93- my >= screens[i].y &&
94- my < (screens[i].y + screens[i].height)) {
95- X = screens[i].x;
96- Y = screens[i].y;
97- W = screens[i].width;
98- H = screens[i].height;
99- return;
100- }
101- }
102- }
103- // if all else fails:
104- X = Fl::x();
105- Y = Fl::y();
106- W = Fl::w();
107- H = Fl::h();
108-#elif HAVE_XINERAMA
109- if (num_screens > 0 && screens) { // screens == NULL if !XineramaIsActive(fl_display)
110- int i;
111+ if (num_screens < 0) screen_init();
112
113- for (i = 0; i < num_screens; i ++) {
114- if (mx >= screens[i].x_org &&
115- mx < (screens[i].x_org + screens[i].width) &&
116- my >= screens[i].y_org &&
117- my < (screens[i].y_org + screens[i].height)) {
118- X = screens[i].x_org;
119- Y = screens[i].y_org;
120- W = screens[i].width;
121- H = screens[i].height;
122- return;
123- }
124+ for (i = 0; i < num_screens; i ++) {
125+ int sx, sy, sw, sh;
126+ Fl::screen_xywh(sx, sy, sw, sh, i);
127+ if ((mx >= sx) && (mx < (sx+sw)) && (my >= sy) && (my < (sy+sh))) {
128+ screen = i;
129+ break;
130 }
131 }
132- // if all else fails:
133- X = Fl::x();
134- Y = Fl::y();
135- W = Fl::w();
136- H = Fl::h();
137-#else
138- (void)mx;
139- (void)my;
140- X = 0;
141- Y = 0;
142- W = DisplayWidth(fl_display, fl_screen);
143- H = DisplayHeight(fl_display, fl_screen);
144-#endif // WIN32
145
146+ screen_xywh(X, Y, W, H, screen);
147 }
148
149 /**
150@@ -288,47 +228,51 @@ void Fl::screen_xywh(int &X, int &Y, int
151 void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int n) {
152 if (num_screens < 0) screen_init();
153
154+ if ((n < 0) || (n >= num_screens))
155+ n = 0;
156+
157 #ifdef WIN32
158- if (num_screens > 0 && n >= 0 && n < num_screens) {
159+ if (num_screens > 0) {
160 X = screens[n].left;
161 Y = screens[n].top;
162 W = screens[n].right - screens[n].left;
163 H = screens[n].bottom - screens[n].top;
164 } else {
165- X = Fl::x();
166- Y = Fl::y();
167- W = Fl::w();
168- H = Fl::h();
169+ /* Fallback if something is broken... */
170+ X = 0;
171+ Y = 0;
172+ W = GetSystemMetrics(SM_CXSCREEN);
173+ H = GetSystemMetrics(SM_CYSCREEN);
174 }
175 #elif defined(__APPLE__)
176- if (num_screens > 0 && n >= 0 && n < num_screens) {
177+ if (num_screens > 0) {
178 X = screens[n].x;
179 Y = screens[n].y;
180 W = screens[n].width;
181 H = screens[n].height;
182 } else {
183+ /* Fallback if something is broken... */
184 X = Fl::x();
185 Y = Fl::y();
186 W = Fl::w();
187 H = Fl::h();
188 }
189-#elif HAVE_XINERAMA
190- if (num_screens > 0 && n >= 0 && n < num_screens && screens) {
191+#else
192+#if HAVE_XINERAMA
193+ if (num_screens > 0) {
194 X = screens[n].x_org;
195 Y = screens[n].y_org;
196 W = screens[n].width;
197 H = screens[n].height;
198- } else {
199- X = Fl::x();
200- Y = Fl::y();
201- W = Fl::w();
202- H = Fl::h();
203+ } else
204+#endif // HAVE_XINERAMA
205+ {
206+ /* Fallback if something is broken (or no Xinerama)... */
207+ X = 0;
208+ Y = 0;
209+ W = DisplayWidth(fl_display, fl_screen);
210+ H = DisplayHeight(fl_display, fl_screen);
211 }
212-#else
213- X = 0;
214- Y = 0;
215- W = DisplayWidth(fl_display, fl_screen);
216- H = DisplayHeight(fl_display, fl_screen);
217 #endif // WIN32
218 }
219
220diff -up fltk-1.3.x-r8659/FL/Fl_Widget.H.kbd-x11 fltk-1.3.x-r8659/FL/Fl_Widget.H
221--- fltk-1.3.x-r8659/FL/Fl_Widget.H.kbd-x11 2011-04-24 19:09:41.000000000 +0200
222+++ fltk-1.3.x-r8659/FL/Fl_Widget.H 2011-05-13 13:51:26.307888360 +0200
223@@ -179,6 +179,7 @@ protected:
224 NO_OVERLAY = 1<<15, ///< window not using a hardware overlay plane (Fl_Menu_Window)
225 GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window
226 COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget
227+ SIMPLE_KEYBOARD = 1<<18, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input)
228 // (space for more flags)
229 USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions
230 USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions
231@@ -784,6 +785,35 @@ public:
232 */
233 void clear_changed() {flags_ &= ~CHANGED;}
234
235+ /**
236+ Returns if the widget sees a simplified keyboard model or not.
237+
238+ Normally widgets get a full-featured keyboard model that is geared
239+ towards text input. This includes support for compose sequences and
240+ advanced input methods, commonly used for asian writing system. This
241+ system however has downsides in that extra graphic can be presented
242+ to the user and that a physical key press doesn't correspond directly
243+ to a FLTK event.
244+
245+ Widgets that need a direct correspondence between actual key events
246+ and those seen by the widget can swith to the simplified keyboard
247+ model.
248+
249+ \retval 0 if the widget uses the normal keyboard model
250+ \see set_changed(), clear_changed()
251+ */
252+ unsigned int simple_keyboard() const {return flags_&SIMPLE_KEYBOARD;}
253+
254+ /** Marks a widget to use the simple keyboard model.
255+ \see changed(), clear_changed()
256+ */
257+ void set_simple_keyboard() {flags_ |= SIMPLE_KEYBOARD;}
258+
259+ /** Marks a widget to use the normal keyboard model.
260+ \see changed(), set_changed()
261+ */
262+ void set_normal_keyboard() {flags_ &= ~SIMPLE_KEYBOARD;}
263+
264 /** Gives the widget the keyboard focus.
265 Tries to make this widget be the Fl::focus() widget, by first sending
266 it an FL_FOCUS event, and if it returns non-zero, setting
267diff -up fltk-1.3.x-r8659/src/Fl.cxx.kbd-x11 fltk-1.3.x-r8659/src/Fl.cxx
268--- fltk-1.3.x-r8659/src/Fl.cxx.kbd-x11 2011-04-11 22:10:02.000000000 +0200
269+++ fltk-1.3.x-r8659/src/Fl.cxx 2011-05-13 13:51:26.308888510 +0200
270@@ -63,6 +63,8 @@ void fl_cleanup_dc_list(void);
271 extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle);
272 #endif // WIN32
273
274+extern void fl_update_focus(void);
275+
276 //
277 // Globals...
278 //
279@@ -864,6 +866,8 @@ void Fl::focus(Fl_Widget *o) {
280 fl_oldfocus = p;
281 }
282 e_number = old_event;
283+ // let the platform code do what it needs
284+ fl_update_focus();
285 }
286 }
287
288diff -up fltk-1.3.x-r8659/src/Fl_grab.cxx.kbd-x11 fltk-1.3.x-r8659/src/Fl_grab.cxx
289--- fltk-1.3.x-r8659/src/Fl_grab.cxx.kbd-x11 2010-12-18 23:31:01.000000000 +0100
290+++ fltk-1.3.x-r8659/src/Fl_grab.cxx 2011-05-13 13:51:26.309888660 +0200
291@@ -38,6 +38,7 @@
292 // override_redirect, it does similar things on WIN32.
293
294 extern void fl_fix_focus(); // in Fl.cxx
295+void fl_update_focus(void);
296
297 #ifdef WIN32
298 // We have to keep track of whether we have captured the mouse, since
299@@ -79,6 +80,7 @@ void Fl::grab(Fl_Window* win) {
300 #endif
301 }
302 grab_ = win;
303+ fl_update_focus();
304 } else {
305 if (grab_) {
306 #ifdef WIN32
307@@ -94,6 +96,7 @@ void Fl::grab(Fl_Window* win) {
308 XFlush(fl_display);
309 #endif
310 grab_ = 0;
311+ fl_update_focus();
312 fl_fix_focus();
313 }
314 }
315diff -up fltk-1.3.x-r8659/src/Fl_x.cxx.kbd-x11 fltk-1.3.x-r8659/src/Fl_x.cxx
316--- fltk-1.3.x-r8659/src/Fl_x.cxx.kbd-x11 2011-04-27 10:47:00.000000000 +0200
317+++ fltk-1.3.x-r8659/src/Fl_x.cxx 2011-05-13 13:54:28.813284014 +0200
318@@ -300,6 +300,7 @@ XVisualInfo *fl_visual;
319 Colormap fl_colormap;
320 XIM fl_xim_im = 0;
321 XIC fl_xim_ic = 0;
322+Window fl_xim_win = 0;
323 char fl_is_over_the_spot = 0;
324 static XRectangle status_area;
325
326@@ -581,6 +582,65 @@ void fl_init_xim() {
327 if(xim_styles) XFree(xim_styles);
328 }
329
330+void fl_xim_deactivate(void);
331+
332+void fl_xim_activate(Window xid)
333+{
334+ if (!fl_xim_im)
335+ return;
336+
337+ // If the focused window has changed, then use the brute force method
338+ // of completely recreating the input context.
339+ if (fl_xim_win != xid) {
340+ fl_xim_deactivate();
341+
342+ fl_new_ic();
343+ fl_xim_win = xid;
344+
345+ XSetICValues(fl_xim_ic,
346+ XNFocusWindow, fl_xim_win,
347+ XNClientWindow, fl_xim_win,
348+ NULL);
349+ }
350+
351+ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
352+}
353+
354+void fl_xim_deactivate(void)
355+{
356+ if (!fl_xim_ic)
357+ return;
358+
359+ XDestroyIC(fl_xim_ic);
360+ fl_xim_ic = NULL;
361+
362+ fl_xim_win = 0;
363+}
364+
365+extern Fl_Window *fl_xfocus;
366+
367+void fl_update_focus(void)
368+{
369+ Fl_Widget *focus;
370+
371+ focus = Fl::grab();
372+ if (!focus)
373+ focus = Fl::focus();
374+ if (!focus)
375+ return;
376+
377+ if (focus->simple_keyboard()) {
378+ fl_xim_deactivate();
379+ } else {
380+ // fl_xfocus should always be set if something has focus, but let's
381+ // play it safe
382+ if (!fl_xfocus || !fl_xid(fl_xfocus))
383+ return;
384+
385+ fl_xim_activate(fl_xid(fl_xfocus));
386+ }
387+}
388+
389 void fl_open_display() {
390 if (fl_display) return;
391
392@@ -864,10 +924,9 @@ int fl_handle(const XEvent& thisevent)
393 XEvent xevent = thisevent;
394 fl_xevent = &thisevent;
395 Window xid = xevent.xany.window;
396- static Window xim_win = 0;
397
398 if (fl_xim_ic && xevent.type == DestroyNotify &&
399- xid != xim_win && !fl_find(xid))
400+ xid != fl_xim_win && !fl_find(xid))
401 {
402 XIM xim_im;
403 xim_im = XOpenIM(fl_display, NULL, NULL, NULL);
404@@ -882,48 +941,10 @@ int fl_handle(const XEvent& thisevent)
405 return 0;
406 }
407
408- if (fl_xim_ic && (xevent.type == FocusIn))
409- {
410-#define POOR_XIM
411-#ifdef POOR_XIM
412- if (xim_win != xid)
413- {
414- xim_win = xid;
415- XDestroyIC(fl_xim_ic);
416- fl_xim_ic = NULL;
417- fl_new_ic();
418- XSetICValues(fl_xim_ic,
419- XNFocusWindow, xevent.xclient.window,
420- XNClientWindow, xid,
421- NULL);
422- }
423- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
424-#else
425- if (Fl::first_window() && Fl::first_window()->modal()) {
426- Window x = fl_xid(Fl::first_window());
427- if (x != xim_win) {
428- xim_win = x;
429- XSetICValues(fl_xim_ic,
430- XNFocusWindow, xim_win,
431- XNClientWindow, xim_win,
432- NULL);
433- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
434- }
435- } else if (xim_win != xid && xid) {
436- xim_win = xid;
437- XSetICValues(fl_xim_ic,
438- XNFocusWindow, xevent.xclient.window,
439- XNClientWindow, xid,
440- //XNFocusWindow, xim_win,
441- //XNClientWindow, xim_win,
442- NULL);
443- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
444- }
445-#endif
446- }
447-
448- if ( XFilterEvent((XEvent *)&xevent, 0) )
449- return(1);
450+ if (fl_xim_ic) {
451+ if (XFilterEvent((XEvent *)&xevent, 0))
452+ return 1;
453+ }
454
455 switch (xevent.type) {
456
457@@ -1248,15 +1269,15 @@ int fl_handle(const XEvent& thisevent)
458 //static XComposeStatus compose;
459 len = XLookupString((XKeyEvent*)&(xevent.xkey),
460 buffer, buffer_len, &keysym, 0/*&compose*/);
461- if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets
462- // force it to type a character (not sure if this ever is needed):
463- // if (!len) {buffer[0] = char(keysym); len = 1;}
464- len = fl_utf8encode(XKeysymToUcs(keysym), buffer);
465- if (len < 1) len = 1;
466- // ignore all effects of shift on the keysyms, which makes it a lot
467- // easier to program shortcuts and is Windoze-compatible:
468- keysym = XKeycodeToKeysym(fl_display, keycode, 0);
469- }
470+ // XLookupString() is only defined to return Latin-1 (although it
471+ // often gives you more). To be safe, use our own lookups based on
472+ // keysym.
473+ len = fl_utf8encode(XKeysymToUcs(keysym), buffer);
474+ if (len < 1)
475+ len = 1;
476+ // ignore all effects of shift on the keysyms, which makes it a lot
477+ // easier to program shortcuts and is Windoze-compatable:
478+ keysym = XKeycodeToKeysym(fl_display, keycode, 0);
479 }
480 // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not
481 // set until set_event_xy() is called later...
482diff -up fltk-1.3.x-r8659/src/xutf8/imKStoUCS.c.kbd-x11 fltk-1.3.x-r8659/src/xutf8/imKStoUCS.c
483--- fltk-1.3.x-r8659/src/xutf8/imKStoUCS.c.kbd-x11 2009-03-13 23:43:43.000000000 +0100
484+++ fltk-1.3.x-r8659/src/xutf8/imKStoUCS.c 2011-05-13 13:51:26.311888960 +0200
485@@ -266,6 +266,12 @@ static unsigned short const keysym_to_un
486 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */
487 };
488
489+static unsigned short const keysym_to_unicode_fe50_fe60[] = {
490+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, /* 0xfe50-0xfe57 */
491+ 0x030a, 0x030b, 0x030c, 0x0327, 0x0328, 0x1da5, 0x3099, 0x309a, /* 0xfe58-0xfe5f */
492+ 0x0323 /* 0xfe60-0xfe67 */
493+};
494+
495 unsigned int
496 KeySymToUcs4(KeySym keysym)
497 {
498@@ -315,6 +321,8 @@ KeySymToUcs4(KeySym keysym)
499 return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f];
500 else if (keysym > 0x209f && keysym < 0x20ad)
501 return keysym_to_unicode_20a0_20ac[keysym - 0x20a0];
502+ else if (keysym > 0xfe4f && keysym < 0xfe61)
503+ return keysym_to_unicode_fe50_fe60[keysym - 0xfe50];
504 else
505 return 0;
506 }
507diff -up fltk-1.3.x-r8617/src/Fl_win32.cxx.kbd-win32 fltk-1.3.x-r8617/src/Fl_win32.cxx
508--- fltk-1.3.x-r8617/src/Fl_win32.cxx.kbd-win32 2011-04-18 22:47:32.000000000 +0200
509+++ fltk-1.3.x-r8617/src/Fl_win32.cxx 2011-05-13 13:43:12.131708663 +0200
510@@ -98,6 +98,8 @@ FL_EXPORT Fl_Graphics_Driver *fl_graphic
511 Fl_Surface_Device* Fl_Surface_Device::_surface = (Fl_Surface_Device*)&fl_gdi_display; // the current target surface of graphics operations
512 Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display
513
514+bool use_simple_keyboard = false;
515+
516 // dynamic wsock dll handling api:
517 #if defined(__CYGWIN__) && !defined(SOCKET)
518 # define SOCKET int
519@@ -131,6 +133,8 @@ static HMODULE get_wsock_mod() {
520 * size and link dependencies.
521 */
522 static HMODULE s_imm_module = 0;
523+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD);
524+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0;
525 typedef HIMC (WINAPI* flTypeImmGetContext)(HWND);
526 static flTypeImmGetContext flImmGetContext = 0;
527 typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
528@@ -146,6 +150,7 @@ static HMODULE get_imm_module() {
529 if (!s_imm_module)
530 Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n"
531 "Please check your input method manager library accessibility.");
532+ flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx");
533 flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext");
534 flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow");
535 flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext");
536@@ -424,7 +429,12 @@ int fl_wait(double time_to_wait) {
537 }
538 }
539
540- TranslateMessage(&fl_msg);
541+ // Don't bother with key to character translation as we do
542+ // it manually for simpley keyboard widgets. In fact, calling
543+ // TranslateMessage() just makes it more difficult as it sets
544+ // a bunch of internal state.
545+ if (!use_simple_keyboard)
546+ TranslateMessage(&fl_msg);
547 DispatchMessageW(&fl_msg);
548 have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE);
549 }
550@@ -649,6 +659,49 @@ void fl_get_codepage()
551 }
552 }
553
554+void fl_update_focus(void)
555+{
556+ Fl_Widget *focus;
557+ Fl_Window *win;
558+
559+ get_imm_module();
560+
561+ focus = Fl::grab();
562+ if (!focus)
563+ focus = Fl::focus();
564+ if (!focus)
565+ return;
566+
567+ // Grabs are special in that events are sent to the first
568+ // available window
569+ if (focus == Fl::grab())
570+ win = Fl::first_window();
571+ else {
572+ win = focus->as_window();
573+ if (!win)
574+ win = focus->window();
575+ }
576+
577+ if (!win) {
578+ Fl::warning("Cannot find window for widget receiving focus");
579+ return;
580+ }
581+
582+ // No Win32 window created yet
583+ if (!Fl_X::i(win) || !fl_xid(win))
584+ return;
585+
586+ if (focus->simple_keyboard()) {
587+ use_simple_keyboard = true;
588+ if (flImmGetContext(fl_xid(win)) != 0)
589+ flImmAssociateContextEx(fl_xid(win), 0, 0);
590+ } else {
591+ use_simple_keyboard = false;
592+ if (flImmGetContext(fl_xid(win)) == 0)
593+ flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT);
594+ }
595+}
596+
597 HWND fl_capture;
598
599 static int mouse_event(Fl_Window *window, int what, int button,
600@@ -778,6 +831,27 @@ static int ms2fltk(int vk, int extended)
601 return extended ? extendedlut[vk] : vklut[vk];
602 }
603
604+static xchar msdead2fltk(xchar in)
605+{
606+ switch (in) {
607+ case 0x0060: // GRAVE ACCENT
608+ return 0x0300; // COMBINING GRAVE ACCENT
609+ case 0x00b4: // ACUTE ACCENT
610+ return 0x0301; // COMBINING ACUTE ACCENT
611+ case 0x005e: // CIRCUMFLEX ACCENT
612+ return 0x0302; // COMBINING CIRCUMFLEX ACCENT
613+ case 0x007e: // TILDE
614+ return 0x0303; // COMBINING TILDE
615+ case 0x00a8: // DIAERESIS
616+ return 0x0308; // COMBINING DIAERESIS
617+ // FIXME: Windows dead key behaviour isn't documented and I don't have
618+ // any more keyboards to test with...
619+ }
620+
621+ // hope that Windows gave us something proper to begin with
622+ return in;
623+}
624+
625 #if USE_COLORMAP
626 extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
627 #endif
628@@ -839,6 +913,8 @@ static LRESULT CALLBACK WndProc(HWND hWn
629 //fl_msg.pt = ???
630 //fl_msg.lPrivate = ???
631
632+ MSG fl_orig_msg = fl_msg;
633+
634 Fl_Window *window = fl_find(hWnd);
635
636 if (window) switch (uMsg) {
637@@ -1018,23 +1094,82 @@ static LRESULT CALLBACK WndProc(HWND hWn
638 if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
639 Fl::e_state = state;
640 static char buffer[1024];
641- if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
642
643+ if (use_simple_keyboard) {
644+ BYTE keystate[256];
645+ WCHAR wbuf[8];
646+ int ret;
647+
648+ // I'm not sure if we ever get WM_CHAR (& friends) without an initial
649+ // WM_KEYDOWN (& friends), but if we do then we should not send such
650+ // side band events to simple keyboard widgets.
651+ if ((fl_orig_msg.message != WM_KEYDOWN) &&
652+ (fl_orig_msg.message != WM_SYSKEYDOWN) &&
653+ (fl_orig_msg.message != WM_KEYUP) &&
654+ (fl_orig_msg.message != WM_SYSKEYUP))
655+ break;
656+
657+ GetKeyboardState(keystate);
658+
659+ // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off.
660+ // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is
661+ // active.
662+ if (!(keystate[VK_MENU] & (1<<31)))
663+ keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0;
664+
665+ // We cannot inspect or modify Windows' internal state of the keyboard
666+ // so we have to try to infer information from ToUnicode() and wedge
667+ // things into a known state.
668+ for (int i = 0;i < 2;i++) {
669+ ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf,
670+ sizeof(wbuf)/sizeof(wbuf[0]), 0);
671+
672+ // No symbol for this key (or unexpected length)
673+ if ((ret == 0) || (ret < -1)) {
674+ buffer[0] = 0;
675+ Fl::e_length = 0;
676+ break;
677+ }
678+
679+ // A dead key. Convert this to a Unicode combining character so
680+ // that the application can tell the difference between dead and
681+ // normal keys.
682+ if (ret == -1) {
683+ xchar u = (xchar) msdead2fltk(wbuf[0]);
684+ Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
685+ buffer[Fl::e_length] = 0;
686+ break;
687+ }
688+
689+ // If we have two characters (or more) from ToUnicode(), that's
690+ // an invalid sequence. One character chould mean a proper symbol,
691+ // or it could mean a composed one. In both cases we need to call
692+ // ToUnicode() again to get something sane.
693+ if (i == 0)
694+ continue;
695+
696+ // We should now have something sane. Give whatever we have to the
697+ // application.
698+ Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret);
699+ buffer[Fl::e_length] = 0;
700+ }
701+ } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
702 xchar u = (xchar) wParam;
703 // Fl::e_length = fl_unicode2utf(&u, 1, buffer);
704 Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
705 buffer[Fl::e_length] = 0;
706+ } else {
707+ buffer[0] = 0;
708+ Fl::e_length = 0;
709+ }
710
711-
712- } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
713- if (state & FL_NUM_LOCK) {
714- // Convert to regular keypress...
715- buffer[0] = Fl::e_keysym-FL_KP;
716- Fl::e_length = 1;
717- } else {
718- // Convert to special keypress...
719- buffer[0] = 0;
720- Fl::e_length = 0;
721+ // The keypad area is a bit odd in that we need to change the keysym
722+ // to properly indicate what the user meant, unlike other keys where
723+ // we normally change the text and keep keysym stable.
724+ if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
725+ // The initial mapping tables give us a keysym that corresponds to
726+ // numlock being on, so we only do something when it is off.
727+ if (!(state & FL_NUM_LOCK)) {
728 switch (Fl::e_keysym) {
729 case FL_KP + '0' :
730 Fl::e_keysym = FL_Insert;
731@@ -1066,30 +1201,10 @@ static LRESULT CALLBACK WndProc(HWND hWn
732 case FL_KP + '.' :
733 Fl::e_keysym = FL_Delete;
734 break;
735- case FL_KP + '/' :
736- case FL_KP + '*' :
737- case FL_KP + '-' :
738- case FL_KP + '+' :
739- buffer[0] = Fl::e_keysym-FL_KP;
740- Fl::e_length = 1;
741- break;
742 }
743 }
744- } else if ((lParam & (1<<31))==0) {
745-#ifdef FLTK_PREVIEW_DEAD_KEYS
746- if ((lParam & (1<<24))==0) { // clear if dead key (always?)
747- xchar u = (xchar) wParam;
748- Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
749- buffer[Fl::e_length] = 0;
750- } else { // set if "extended key" (never printable?)
751- buffer[0] = 0;
752- Fl::e_length = 0;
753- }
754-#else
755- buffer[0] = 0;
756- Fl::e_length = 0;
757-#endif
758 }
759+
760 Fl::e_text = buffer;
761 if (lParam & (1<<31)) { // key up events.
762 if (Fl::handle(FL_KEYUP, window)) return 0;
763diff -up fltk-1.3.x-r8695/configure.in.kbd-osx fltk-1.3.x-r8695/configure.in
764--- fltk-1.3.x-r8695/configure.in.kbd-osx 2011-03-06 17:54:58.000000000 +0100
765+++ fltk-1.3.x-r8695/configure.in 2011-05-20 12:16:49.545510571 +0200
766@@ -874,6 +874,8 @@ case $uname_GUI in
767 Darwin*)
768 # MacOS X uses Cocoa for graphics.
769 LIBS="$LIBS -framework Cocoa"
770+ # And some Carbon for keyboard handling
771+ LIBS="$LIBS -framework Carbon"
772
773 if test x$have_pthread = xyes; then
774 AC_DEFINE(HAVE_PTHREAD)
775diff -up fltk-1.3.x-r8695/src/Fl_cocoa.mm.kbd-osx fltk-1.3.x-r8695/src/Fl_cocoa.mm
776--- fltk-1.3.x-r8695/src/Fl_cocoa.mm.kbd-osx 2011-05-15 14:34:31.000000000 +0200
777+++ fltk-1.3.x-r8695/src/Fl_cocoa.mm 2011-05-20 12:21:01.376320373 +0200
778@@ -61,6 +61,7 @@ extern "C" {
779 #include <stdarg.h>
780
781 #import <Cocoa/Cocoa.h>
782+#import <Carbon/Carbon.h>
783
784 #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h
785 #if defined(__LP64__) && __LP64__
786@@ -124,6 +125,8 @@ static Fl_Window* send_motion;
787 extern Fl_Window* fl_xmousewin;
788 #endif
789
790+bool use_simple_keyboard = false;
791+
792 enum { FLTKTimerEvent = 1, FLTKDataReadyEvent };
793
794
795@@ -140,6 +143,39 @@ void fl_set_status(int x, int y, int w,
796 {
797 }
798
799+// Undocumented voodoo. Taken from Mozilla.
800+#define ENABLE_ROMAN_KYBDS_ONLY -23
801+
802+void fl_update_focus(void)
803+{
804+ Fl_Widget *focus;
805+
806+ focus = Fl::grab();
807+ if (!focus)
808+ focus = Fl::focus();
809+ if (!focus)
810+ return;
811+
812+ if (focus->simple_keyboard())
813+ use_simple_keyboard = true;
814+ else
815+ use_simple_keyboard = false;
816+
817+ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and
818+ // Safari people seem to think implies turning off advanced IME stuff
819+ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput
820+ // in Safari/Webcore). Should be good enough for us then...
821+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
822+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
823+ TSMSetDocumentProperty(TSMGetActiveDocument(),
824+ kTSMDocumentEnabledInputSourcesPropertyTag,
825+ sizeof(CFArrayRef), &inputSources);
826+ CFRelease(inputSources);
827+#else
828+ KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds);
829+#endif
830+}
831+
832 /*
833 * Mac keyboard lookup table
834 * See also the inverse converter vktab in Fl_get_key_mac.cxx
835@@ -842,6 +878,25 @@ static void cocoaMouseHandler(NSEvent *t
836 }
837 @end
838
839+static const char* cocoaDead2FLTK(const char *in)
840+{
841+ if (strcmp(in, "\140") == 0) // GRAVE ACCENT
842+ return "\314\200"; // COMBINING GRAVE ACCENT
843+ if (strcmp(in, "\302\264") == 0) // ACUTE ACCENT
844+ return "\314\201"; // COMBINING ACUTE ACCENT
845+ if (strcmp(in, "\136") == 0) // CIRCUMFLEX ACCENT
846+ return "\314\202"; // COMBINING CIRCUMFLEX ACCENT
847+ if (strcmp(in, "\176") == 0) // TILDE
848+ return "\314\203"; // COMBINING TILDE
849+ if (strcmp(in, "\302\250") == 0) // DIAERESIS
850+ return "\314\210"; // COMBINING DIAERESIS
851+ // FIXME: OS X dead key behaviour isn't documented and I don't have
852+ // any more keyboards to test with...
853+
854+ // hope that OS X gave us something proper to begin with
855+ return in;
856+}
857+
858 /*
859 Handle cocoa keyboard events
860 Events during a character composition sequence:
861@@ -1701,8 +1756,13 @@ static void q_set_window_title(NSWindow
862 break;
863 }
864 }
865+ // Don't send cmd-<key> to interpretKeyEvents because it beeps.
866 if (!no_text_key && !(Fl::e_state & FL_META) ) {
867- // Don't send cmd-<key> to interpretKeyEvents because it beeps.
868+ // The simple keyboard model will ignore insertText, so we need to grab
869+ // the symbol directly from the event. Note that we still use setMarkedText.
870+ if (use_simple_keyboard)
871+ [FLView prepareEtext:[theEvent charactersIgnoringModifiers]];
872+
873 // Then we can let the OS have a stab at it and see if it thinks it
874 // should result in some text
875 NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil];
876@@ -1879,21 +1939,30 @@ static void q_set_window_title(NSWindow
877 //NSLog(@"insertText: received=%@",received);
878
879 if (!in_key_event) fl_lock_function();
880+
881+ // Simple keyboard widgets do not want these side channel inputs.
882+ if (use_simple_keyboard)
883+ goto end;
884+
885 [FLView prepareEtext:received];
886+
887 // We can get called outside of key events (e.g. from the character
888- // palette). Transform such actions to FL_PASTE events.
889+ // palette). We need to fake our own key event at that point.
890 if (!in_key_event) {
891 Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
892- Fl::handle(FL_PASTE, target);
893+ Fl::e_keysym = Fl::e_original_keysym = 0;
894+ Fl::handle(FL_KEYDOWN, target);
895 // for some reason, the window does not redraw until the next mouse move or button push
896 // sending a 'redraw()' or 'awake()' does not solve the issue!
897 Fl::flush();
898 }
899+
900+end:
901 if (!in_key_event) fl_unlock_function();
902 }
903
904 - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection {
905- NSString *received;
906+ NSString *received, *current, *aggregate;
907 if (newSelection.location == 0) {
908 [self unmarkText];
909 return;
910@@ -1904,11 +1973,47 @@ static void q_set_window_title(NSWindow
911 received = (NSString*)aString;
912 }
913 //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length);
914+
915+ fl_lock_function();
916+
917+ // Simple keyboard widgets generally do not want these side channel
918+ // inputs, but we have no other way of getting dead keys so we make
919+ // an exception in that case.
920+ if (use_simple_keyboard) {
921+ if (in_key_event && (Fl::e_length == 0)) {
922+ [FLView prepareEtext:received];
923+
924+ Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text);
925+ Fl::e_length = strlen(Fl::e_text);
926+ }
927+ goto end;
928+ }
929+
930 // This code creates the OS X behaviour of seeing dead keys as things
931 // are being composed.
932+ //
933+ // Note: The concatenation thing is because of how OS X deals with
934+ // invalid sequences. At that point it will spit out one call
935+ // to insertText with the now aborted sequence, and one new
936+ // call to setMarkedText with the new sequence. Since we want
937+ // both to be visible, we need to concatenate.
938 next_compose_length = newSelection.location;
939- [FLView prepareEtext:received];
940- //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length);
941+ current = [NSString stringWithUTF8String:Fl::e_text];
942+ aggregate = [current stringByAppendingString:received];
943+
944+ [FLView prepareEtext:aggregate];
945+ //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length);
946+
947+ // We can get called outside of key events (e.g. from the character
948+ // palette). We need to fake our own key event at that point.
949+ if (!in_key_event) {
950+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
951+ Fl::e_keysym = Fl::e_original_keysym = 0;
952+ Fl::handle(FL_KEYDOWN, target);
953+ }
954+
955+end:
956+ fl_unlock_function();
957 }
958
959 - (void)unmarkText {
960diff -up fltk-1.3.x-r8659/FL/Fl.H.orig fltk-1.3.x-r8659/FL/Fl.H
961--- fltk-1.3.x-r8659/FL/Fl.H.orig 2011-05-17 16:25:56.671744548 +0200
962+++ fltk-1.3.x-r8659/FL/Fl.H 2011-05-17 16:26:05.709101536 +0200
963@@ -108,6 +108,9 @@ typedef int (*Fl_Args_Handler)(int argc,
964 \see Fl::event_dispatch(Fl_Event_Dispatch) */
965 typedef int (*Fl_Event_Dispatch)(int event, Fl_Window *w);
966
967+/** Signature of add_clipboard_notify functions passed as parameters */
968+typedef void (*Fl_Clipboard_Notify_Handler)(int source, void *data);
969+
970 /** @} */ /* group callback_functions */
971
972
973@@ -744,6 +747,19 @@ public:
974 */
975 static void paste(Fl_Widget &receiver, int source /*=0*/); // platform dependent
976 /**
977+ FLTK will call the registered callback whenever there is a change to the
978+ selection buffer or the clipboard. The source argument indicates which
979+ of the two has changed. Only changes by other applications are reported.
980+ \note Some systems require polling to monitor the clipboard and may
981+ therefore have some delay in detecting changes.
982+ */
983+ static void add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data);
984+ /**
985+ Stop calling the specified callback when there are changes to the selection
986+ buffer or the clipboard.
987+ */
988+ static void remove_clipboard_notify(Fl_Clipboard_Notify_Handler h);
989+ /**
990 Initiate a Drag And Drop operation. The selection buffer should be
991 filled with relevant data before calling this method. FLTK will
992 then initiate the system wide drag and drop handling. Dropped data
993diff -up fltk-1.3.x-r8659/src/Fl.cxx.orig fltk-1.3.x-r8659/src/Fl.cxx
994--- fltk-1.3.x-r8659/src/Fl.cxx.orig 2011-05-18 15:20:26.667291459 +0200
995+++ fltk-1.3.x-r8659/src/Fl.cxx 2011-05-18 16:31:15.522026086 +0200
996@@ -430,6 +430,69 @@ static char in_idle;
997 #endif
998
999 ////////////////////////////////////////////////////////////////
1000+// Clipboard notifications
1001+
1002+struct Clipboard_Notify {
1003+ Fl_Clipboard_Notify_Handler handler;
1004+ void *data;
1005+ struct Clipboard_Notify *next;
1006+};
1007+
1008+static struct Clipboard_Notify *clip_notify_list = NULL;
1009+
1010+extern void fl_clipboard_notify_change(); // in Fl_<platform>.cxx
1011+
1012+void Fl::add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data) {
1013+ struct Clipboard_Notify *node;
1014+
1015+ remove_clipboard_notify(h);
1016+
1017+ node = new Clipboard_Notify;
1018+
1019+ node->handler = h;
1020+ node->data = data;
1021+ node->next = clip_notify_list;
1022+
1023+ clip_notify_list = node;
1024+
1025+ fl_clipboard_notify_change();
1026+}
1027+
1028+void Fl::remove_clipboard_notify(Fl_Clipboard_Notify_Handler h) {
1029+ struct Clipboard_Notify *node, **prev;
1030+
1031+ node = clip_notify_list;
1032+ prev = &clip_notify_list;
1033+ while (node != NULL) {
1034+ if (node->handler == h) {
1035+ *prev = node->next;
1036+ delete node;
1037+
1038+ fl_clipboard_notify_change();
1039+
1040+ return;
1041+ }
1042+
1043+ prev = &node->next;
1044+ node = node->next;
1045+ }
1046+}
1047+
1048+bool fl_clipboard_notify_empty(void) {
1049+ return clip_notify_list == NULL;
1050+}
1051+
1052+void fl_trigger_clipboard_notify(int source) {
1053+ struct Clipboard_Notify *node;
1054+
1055+ node = clip_notify_list;
1056+ while (node != NULL) {
1057+ node->handler(source, node->data);
1058+ node = node->next;
1059+ }
1060+}
1061+
1062+////////////////////////////////////////////////////////////////
1063 // wait/run/check/ready:
1064
1065 void (*Fl::idle)(); // see Fl::add_idle.cxx for the add/remove functions
1066diff -up fltk-1.3.x-r8659/src/Fl_x.cxx.orig fltk-1.3.x-r8659/src/Fl_x.cxx
1067--- fltk-1.3.x-r8659/src/Fl_x.cxx.orig 2011-05-17 16:37:11.092011814 +0200
1068+++ fltk-1.3.x-r8659/src/Fl_x.cxx 2011-05-18 13:51:06.135475325 +0200
1069@@ -309,6 +309,9 @@ static Atom WM_PROTOCOLS;
1070 static Atom fl_MOTIF_WM_HINTS;
1071 static Atom TARGETS;
1072 static Atom CLIPBOARD;
1073+static Atom TIMESTAMP;
1074+static Atom PRIMARY_TIMESTAMP;
1075+static Atom CLIPBOARD_TIMESTAMP;
1076 Atom fl_XdndAware;
1077 Atom fl_XdndSelection;
1078 Atom fl_XdndEnter;
1079@@ -678,6 +681,9 @@ void fl_open_display(Display* d) {
1080 fl_MOTIF_WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", 0);
1081 TARGETS = XInternAtom(d, "TARGETS", 0);
1082 CLIPBOARD = XInternAtom(d, "CLIPBOARD", 0);
1083+ TIMESTAMP = XInternAtom(d, "TIMESTAMP", 0);
1084+ PRIMARY_TIMESTAMP = XInternAtom(d, "PRIMARY_TIMESTAMP", 0);
1085+ CLIPBOARD_TIMESTAMP = XInternAtom(d, "CLIPBOARD_TIMESTAMP", 0);
1086 fl_XdndAware = XInternAtom(d, "XdndAware", 0);
1087 fl_XdndSelection = XInternAtom(d, "XdndSelection", 0);
1088 fl_XdndEnter = XInternAtom(d, "XdndEnter", 0);
1089@@ -861,6 +881,86 @@ void Fl::copy(const char *stuff, int len
1090 }
1091
1092 ////////////////////////////////////////////////////////////////
1093+// Code for tracking clipboard changes:
1094+
1095+static Time primary_timestamp = -1;
1096+static Time clipboard_timestamp = -1;
1097+
1098+extern bool fl_clipboard_notify_empty(void);
1099+extern void fl_trigger_clipboard_notify(int source);
1100+
1101+static void poll_clipboard_owner(void) {
1102+ Window xid;
1103+
1104+ // No one is interested, so no point polling
1105+ if (fl_clipboard_notify_empty())
1106+ return;
1107+
1108+ // We need a window for this to work
1109+ if (!Fl::first_window())
1110+ return;
1111+ xid = fl_xid(Fl::first_window());
1112+ if (!xid)
1113+ return;
1114+
1115+ // Request an update of the selection time for both the primary and
1116+ // clipboard selections. Magic continues when we get a SelectionNotify.
1117+ if (!fl_i_own_selection[0])
1118+ XConvertSelection(fl_display, XA_PRIMARY, TIMESTAMP, PRIMARY_TIMESTAMP,
1119+ xid, fl_event_time);
1120+ if (!fl_i_own_selection[1])
1121+ XConvertSelection(fl_display, CLIPBOARD, TIMESTAMP, CLIPBOARD_TIMESTAMP,
1122+ xid, fl_event_time);
1123+}
1124+
1125+static void clipboard_timeout(void *data)
1126+{
1127+ // No one is interested, so stop polling
1128+ if (fl_clipboard_notify_empty())
1129+ return;
1130+
1131+ poll_clipboard_owner();
1132+
1133+ Fl::repeat_timeout(0.5, clipboard_timeout);
1134+}
1135+
1136+static void handle_clipboard_timestamp(int clipboard, Time time)
1137+{
1138+ Time *timestamp;
1139+
1140+ timestamp = clipboard ? &clipboard_timestamp : &primary_timestamp;
1141+
1142+ // Initial scan, just store the value
1143+ if (*timestamp == (Time)-1) {
1144+ *timestamp = time;
1145+ return;
1146+ }
1147+
1148+ // Same selection
1149+ if (time == *timestamp)
1150+ return;
1151+
1152+ *timestamp = time;
1153+
1154+ // Something happened! Let's tell someone!
1155+ fl_trigger_clipboard_notify(clipboard);
1156+}
1157+
1158+void fl_clipboard_notify_change() {
1159+ // Reset the timestamps if we've going idle so that you don't
1160+ // get a bogus immediate trigger next time they're activated.
1161+ if (fl_clipboard_notify_empty()) {
1162+ primary_timestamp = -1;
1163+ clipboard_timestamp = -1;
1164+ } else {
1165+ poll_clipboard_owner();
1166+
1167+ if (!Fl::has_timeout(clipboard_timeout))
1168+ Fl::add_timeout(0.5, clipboard_timeout);
1169+ }
1170+}
1171+
1172+////////////////////////////////////////////////////////////////
1173
1174 const XEvent* fl_xevent; // the current x event
1175 ulong fl_event_time; // the last timestamp from an x event
1176@@ -976,7 +1102,6 @@ int fl_handle(const XEvent& thisevent)
1177 return 0;
1178
1179 case SelectionNotify: {
1180- if (!fl_selection_requestor) return 0;
1181 static unsigned char* buffer = 0;
1182 if (buffer) {XFree(buffer); buffer = 0;}
1183 long bytesread = 0;
1184@@ -992,6 +1117,19 @@ int fl_handle(const XEvent& thisevent)
1185 bytesread/4, 65536, 1, 0,
1186 &actual, &format, &count, &remaining,
1187 &portion)) break; // quit on error
1188+
1189+ if ((fl_xevent->xselection.property == PRIMARY_TIMESTAMP) ||
1190+ (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)) {
1191+ if (portion && format == 32 && count == 1) {
1192+ Time t = *(unsigned int*)portion;
1193+ if (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)
1194+ handle_clipboard_timestamp(1, t);
1195+ else
1196+ handle_clipboard_timestamp(0, t);
1197+ }
1198+ return true;
1199+ }
1200+
1201 if (actual == TARGETS || actual == XA_ATOM) {
1202 Atom type = XA_STRING;
1203 for (unsigned i = 0; i<count; i++) {
1204@@ -1029,6 +1167,9 @@ int fl_handle(const XEvent& thisevent)
1205 buffer[bytesread] = 0;
1206 convert_crlf(buffer, bytesread);
1207 }
1208+
1209+ if (!fl_selection_requestor) return 0;
1210+
1211 Fl::e_text = buffer ? (char*)buffer : (char *)"";
1212 Fl::e_length = bytesread;
1213 int old_event = Fl::e_number;
1214@@ -1049,6 +1190,7 @@ int fl_handle(const XEvent& thisevent)
1215 case SelectionClear: {
1216 int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD;
1217 fl_i_own_selection[clipboard] = 0;
1218+ poll_clipboard_owner();
1219 return 1;}
1220
1221 case SelectionRequest: {
1222@@ -1248,6 +1390,9 @@ int fl_handle(const XEvent& thisevent)
1223 case FocusIn:
1224 if (fl_xim_ic) XSetICFocus(fl_xim_ic);
1225 event = FL_FOCUS;
1226+ // If the user has toggled from another application to this one,
1227+ // then it's a good time to check for clipboard changes.
1228+ poll_clipboard_owner();
1229 break;
1230
1231 case FocusOut:
1232diff -up fltk-1.3.x-r8659/configh.in.clp-xfixes fltk-1.3.x-r8659/configh.in
1233--- fltk-1.3.x-r8659/configh.in.clp-xfixes 2011-03-06 17:54:58.000000000 +0100
1234+++ fltk-1.3.x-r8659/configh.in 2011-05-19 16:55:27.986364764 +0200
1235@@ -117,6 +117,14 @@
1236 #define USE_XDBE HAVE_XDBE
1237
1238 /*
1239+ * HAVE_XFIXES:
1240+ *
1241+ * Do we have the X fixes extension?
1242+ */
1243+
1244+#define HAVE_XFIXES 0
1245+
1246+/*
1247 * __APPLE_QUARTZ__:
1248 *
1249 * All Apple implementations are now based on Quartz and Cocoa,
1250diff -up fltk-1.3.x-r8659/configure.in.clp-xfixes fltk-1.3.x-r8659/configure.in
1251--- fltk-1.3.x-r8659/configure.in.clp-xfixes 2011-05-19 16:55:27.976363265 +0200
1252+++ fltk-1.3.x-r8659/configure.in 2011-05-19 16:55:27.987364914 +0200
1253@@ -1008,6 +1008,16 @@ case $uname_GUI in
1254 LIBS="-lXext $LIBS")
1255 fi
1256
1257+ dnl Check for the Xfixes extension unless disabled...
1258+ AC_ARG_ENABLE(xfixes, [ --enable-xfixes turn on Xfixes support [default=yes]])
1259+
1260+ if test x$enable_xfixes != xno; then
1261+ AC_CHECK_HEADER(X11/extensions/Xfixes.h, AC_DEFINE(HAVE_XFIXES),,
1262+ [#include <X11/Xlib.h>])
1263+ AC_CHECK_LIB(Xfixes, XFixesQueryExtension,
1264+ LIBS="-lXfixes $LIBS")
1265+ fi
1266+
1267 dnl Check for overlay visuals...
1268 AC_PATH_PROG(XPROP, xprop)
1269 AC_CACHE_CHECK(for X overlay visuals, ac_cv_have_overlay,
1270diff -up fltk-1.3.x-r8659/src/Fl_x.cxx.clp-xfixes fltk-1.3.x-r8659/src/Fl_x.cxx
1271--- fltk-1.3.x-r8659/src/Fl_x.cxx.clp-xfixes 2011-05-19 16:55:27.984364466 +0200
1272+++ fltk-1.3.x-r8659/src/Fl_x.cxx 2011-05-19 16:58:06.156112039 +0200
1273@@ -53,6 +53,10 @@
1274 # include <X11/Xlib.h>
1275 # include <X11/keysym.h>
1276
1277+# ifdef HAVE_XFIXES
1278+# include <X11/extensions/Xfixes.h>
1279+# endif
1280+
1281 static Fl_Xlib_Graphics_Driver fl_xlib_driver;
1282 static Fl_Display_Device fl_xlib_display(&fl_xlib_driver);
1283 FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver = (Fl_Graphics_Driver*)&fl_xlib_driver; // the current target device of graphics operations
1284@@ -303,6 +307,8 @@ XIC fl_xim_ic = 0;
1285 Window fl_xim_win = 0;
1286 char fl_is_over_the_spot = 0;
1287 static XRectangle status_area;
1288+static bool have_xfixes = false;
1289+static int xfixes_event_base = 0;
1290
1291 static Atom WM_DELETE_WINDOW;
1292 static Atom WM_PROTOCOLS;
1293@@ -726,6 +732,14 @@ void fl_open_display(Display* d) {
1294 #if !USE_COLORMAP
1295 Fl::visual(FL_RGB);
1296 #endif
1297+
1298+#ifdef HAVE_XFIXES
1299+ int error_base;
1300+ if (XFixesQueryExtension(d, &xfixes_event_base, &error_base))
1301+ have_xfixes = true;
1302+ else
1303+ have_xfixes = false;
1304+#endif
1305 }
1306
1307 void fl_close_display() {
1308@@ -878,6 +892,10 @@ extern void fl_trigger_clipboard_notify(
1309 static void poll_clipboard_owner(void) {
1310 Window xid;
1311
1312+ // No polling needed with Xfixes
1313+ if (have_xfixes)
1314+ return;
1315+
1316 // No one is interested, so no point polling
1317 if (fl_clipboard_notify_empty())
1318 return;
1319@@ -916,10 +934,12 @@ static void handle_clipboard_timestamp(i
1320
1321 timestamp = clipboard ? &clipboard_timestamp : &primary_timestamp;
1322
1323- // Initial scan, just store the value
1324- if (*timestamp == (Time)-1) {
1325- *timestamp = time;
1326- return;
1327+ if (!have_xfixes) {
1328+ // Initial scan, just store the value
1329+ if (*timestamp == (Time)-1) {
1330+ *timestamp = time;
1331+ return;
1332+ }
1333 }
1334
1335 // Same selection
1336@@ -939,10 +959,12 @@ void fl_clipboard_notify_change() {
1337 primary_timestamp = -1;
1338 clipboard_timestamp = -1;
1339 } else {
1340- poll_clipboard_owner();
1341+ if (!have_xfixes) {
1342+ poll_clipboard_owner();
1343
1344- if (!Fl::has_timeout(clipboard_timeout))
1345- Fl::add_timeout(0.5, clipboard_timeout);
1346+ if (!Fl::has_timeout(clipboard_timeout))
1347+ Fl::add_timeout(0.5, clipboard_timeout);
1348+ }
1349 }
1350 }
1351
1352@@ -1638,6 +1660,25 @@ int fl_handle(const XEvent& thisevent)
1353 }
1354 }
1355
1356+#ifdef HAVE_XFIXES
1357+ switch (xevent.type - xfixes_event_base) {
1358+ case XFixesSelectionNotify: {
1359+ // Someone feeding us bogus events?
1360+ if (!have_xfixes)
1361+ return true;
1362+
1363+ XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)&xevent;
1364+
1365+ if ((selection_notify->selection == XA_PRIMARY) && !fl_i_own_selection[0])
1366+ handle_clipboard_timestamp(0, selection_notify->selection_timestamp);
1367+ else if ((selection_notify->selection == CLIPBOARD) && !fl_i_own_selection[1])
1368+ handle_clipboard_timestamp(1, selection_notify->selection_timestamp);
1369+
1370+ return true;
1371+ }
1372+ }
1373+#endif
1374+
1375 return Fl::handle(event, window);
1376 }
1377
1378@@ -1871,6 +1912,16 @@ void Fl_X::make_xid(Fl_Window* win, XVis
1379 XChangeProperty(fl_display, xp->xid, net_wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_type_kind, 1);
1380 }
1381
1382+#ifdef HAVE_XFIXES
1383+ // register for clipboard change notifications
1384+ if (have_xfixes && !win->parent()) {
1385+ XFixesSelectSelectionInput(fl_display, xp->xid, XA_PRIMARY,
1386+ XFixesSetSelectionOwnerNotifyMask);
1387+ XFixesSelectSelectionInput(fl_display, xp->xid, CLIPBOARD,
1388+ XFixesSetSelectionOwnerNotifyMask);
1389+ }
1390+#endif
1391+
1392 XMapWindow(fl_display, xp->xid);
1393 if (showit) {
1394 win->set_visible();
1395diff -up fltk-1.3.x-r8659/src/Fl.cxx.orig fltk-1.3.x-r8659/src/Fl.cxx
1396--- fltk-1.3.x-r8659/src/Fl.cxx.orig 2011-05-18 17:39:15.639513675 +0200
1397+++ fltk-1.3.x-r8659/src/Fl.cxx 2011-05-19 13:47:56.082954290 +0200
1398@@ -1412,7 +1412,9 @@ int Fl::handle_(int e, Fl_Window* window
1399 ////////////////////////////////////////////////////////////////
1400 // hide() destroys the X window, it does not do unmap!
1401
1402-#if !defined(WIN32) && USE_XFT
1403+#if defined(WIN32)
1404+extern void fl_update_clipboard(void);
1405+#elif USE_XFT
1406 extern void fl_destroy_xft_draw(Window);
1407 #endif
1408
1409@@ -1459,14 +1461,8 @@ void Fl_Window::hide() {
1410 #if defined(WIN32)
1411 // this little trick keeps the current clipboard alive, even if we are about
1412 // to destroy the window that owns the selection.
1413- if (GetClipboardOwner()==ip->xid) {
1414- Fl_Window *w1 = Fl::first_window();
1415- if (w1 && OpenClipboard(fl_xid(w1))) {
1416- EmptyClipboard();
1417- SetClipboardData(CF_TEXT, NULL);
1418- CloseClipboard();
1419- }
1420- }
1421+ if (GetClipboardOwner()==ip->xid)
1422+ fl_update_clipboard();
1423 // Send a message to myself so that I'll get out of the event loop...
1424 PostMessage(ip->xid, WM_APP, 0, 0);
1425 if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
1426diff -up fltk-1.3.x-r8659/src/Fl_win32.cxx.orig fltk-1.3.x-r8659/src/Fl_win32.cxx
1427--- fltk-1.3.x-r8659/src/Fl_win32.cxx.orig 2011-05-19 13:48:59.655499725 +0200
1428+++ fltk-1.3.x-r8659/src/Fl_win32.cxx 2011-05-19 13:49:31.147228227 +0200
1429@@ -552,6 +552,36 @@ public:
1430 const char* GetValue() const { return(out); }
1431 };
1432
1433+void fl_update_clipboard(void) {
1434+ HWND hwnd = fl_xid(Fl::first_window());
1435+
1436+ if (!hwnd)
1437+ return;
1438+
1439+ if (!OpenClipboard(hwnd))
1440+ return;
1441+
1442+ EmptyClipboard();
1443+
1444+ int utf16_len = fl_utf8toUtf16(fl_selection_buffer[1],
1445+ fl_selection_length[1], 0, 0);
1446+
1447+ HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc.
1448+ LPVOID memLock = GlobalLock(hMem);
1449+
1450+ fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1],
1451+ (unsigned short*) memLock, utf16_len + 1);
1452+
1453+ GlobalUnlock(hMem);
1454+ SetClipboardData(CF_UNICODETEXT, hMem);
1455+
1456+ CloseClipboard();
1457+
1458+ // In case Windows managed to lob of a WM_DESTROYCLIPBOARD during
1459+ // the above.
1460+ fl_i_own_selection[1] = 1;
1461+}
1462+
1463 // call this when you create a selection:
1464 void Fl::copy(const char *stuff, int len, int clipboard) {
1465 if (!stuff || len<0) return;
1466@@ -569,25 +599,9 @@ void Fl::copy(const char *stuff, int len
1467 memcpy(fl_selection_buffer[clipboard], stuff, len);
1468 fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
1469 fl_selection_length[clipboard] = len;
1470- if (clipboard) {
1471- // set up for "delayed rendering":
1472- if (OpenClipboard(NULL)) {
1473- // if the system clipboard works, use it
1474- int utf16_len = fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], 0, 0);
1475- EmptyClipboard();
1476- HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc.
1477- LPVOID memLock = GlobalLock(hMem);
1478- fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], (unsigned short*) memLock, utf16_len + 1);
1479- GlobalUnlock(hMem);
1480- SetClipboardData(CF_UNICODETEXT, hMem);
1481- CloseClipboard();
1482- GlobalFree(hMem);
1483- fl_i_own_selection[clipboard] = 0;
1484- } else {
1485- // only if it fails, instruct paste() to use the internal buffers
1486- fl_i_own_selection[clipboard] = 1;
1487- }
1488- }
1489+ fl_i_own_selection[clipboard] = 1;
1490+ if (clipboard)
1491+ fl_update_clipboard();
1492 }
1493
1494 // Call this when a "paste" operation happens:
1495@@ -1282,34 +1296,6 @@ static LRESULT CALLBACK WndProc(HWND hWn
1496 fl_i_own_selection[1] = 0;
1497 return 1;
1498
1499- case WM_RENDERALLFORMATS:
1500- fl_i_own_selection[1] = 0;
1501- // Windoze seems unhappy unless I do these two steps. Documentation
1502- // seems to vary on whether opening the clipboard is necessary or
1503- // is in fact wrong:
1504- CloseClipboard();
1505- OpenClipboard(NULL);
1506- // fall through...
1507- case WM_RENDERFORMAT: {
1508- HANDLE h;
1509-
1510-// int l = fl_utf_nb_char((unsigned char*)fl_selection_buffer[1], fl_selection_length[1]);
1511- int l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], NULL, 0); // Pass NULL buffer to query length required
1512- h = GlobalAlloc(GHND, (l+1) * sizeof(unsigned short));
1513- if (h) {
1514- unsigned short *g = (unsigned short*) GlobalLock(h);
1515-// fl_utf2unicode((unsigned char *)fl_selection_buffer[1], fl_selection_length[1], (xchar*)g);
1516- l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], g, (l+1));
1517- g[l] = 0;
1518- GlobalUnlock(h);
1519- SetClipboardData(CF_UNICODETEXT, h);
1520- }
1521-
1522- // Windoze also seems unhappy if I don't do this. Documentation very
1523- // unclear on what is correct:
1524- if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard();
1525- return 1;}
1526-
1527 default:
1528 if (Fl::handle(0,0)) return 0;
1529 break;
1530diff -up fltk-1.3.x-r8659/src/Fl.cxx.win32-fix fltk-1.3.x-r8659/src/Fl.cxx
1531--- fltk-1.3.x-r8659/src/Fl.cxx.win32-fix 2011-05-19 13:47:56.082954290 +0200
1532+++ fltk-1.3.x-r8659/src/Fl.cxx 2011-05-19 13:47:35.540869893 +0200
1533@@ -1413,6 +1413,7 @@ int Fl::handle_(int e, Fl_Window* window
1534 // hide() destroys the X window, it does not do unmap!
1535
1536 #if defined(WIN32)
1537+extern void fl_clipboard_notify_untarget(HWND wnd);
1538 extern void fl_update_clipboard(void);
1539 #elif USE_XFT
1540 extern void fl_destroy_xft_draw(Window);
1541@@ -1463,6 +1464,8 @@ void Fl_Window::hide() {
1542 // to destroy the window that owns the selection.
1543 if (GetClipboardOwner()==ip->xid)
1544 fl_update_clipboard();
1545+ // Make sure we unlink this window from the clipboard chain
1546+ fl_clipboard_notify_untarget(ip->xid);
1547 // Send a message to myself so that I'll get out of the event loop...
1548 PostMessage(ip->xid, WM_APP, 0, 0);
1549 if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
1550diff -up fltk-1.3.x-r8659/src/Fl_win32.cxx.win32-fix fltk-1.3.x-r8659/src/Fl_win32.cxx
1551--- fltk-1.3.x-r8659/src/Fl_win32.cxx.win32-fix 2011-05-19 13:49:31.147228227 +0200
1552+++ fltk-1.3.x-r8659/src/Fl_win32.cxx 2011-05-19 13:47:42.548922155 +0200
1553@@ -654,6 +654,38 @@ void Fl::paste(Fl_Widget &receiver, int
1554 }
1555 }
1556
1557+static HWND clipboard_wnd = 0;
1558+static HWND next_clipboard_wnd = 0;
1559+
1560+static bool initial_clipboard = true;
1561+
1562+void fl_clipboard_notify_change() {
1563+ // No need to do anything here...
1564+}
1565+
1566+void fl_clipboard_notify_target(HWND wnd) {
1567+ if (clipboard_wnd)
1568+ return;
1569+
1570+ // We get one fake WM_DRAWCLIPBOARD immediately, which we therefore
1571+ // need to ignore.
1572+ initial_clipboard = true;
1573+
1574+ clipboard_wnd = wnd;
1575+ next_clipboard_wnd = SetClipboardViewer(wnd);
1576+}
1577+
1578+void fl_clipboard_notify_untarget(HWND wnd) {
1579+ if (wnd != clipboard_wnd)
1580+ return;
1581+
1582+ ChangeClipboardChain(wnd, next_clipboard_wnd);
1583+ clipboard_wnd = next_clipboard_wnd = 0;
1584+
1585+ if (Fl::first_window())
1586+ fl_clipboard_notify_target(fl_xid(Fl::first_window()));
1587+}
1588+
1589 ////////////////////////////////////////////////////////////////
1590 char fl_is_ime = 0;
1591 void fl_get_codepage()
1592@@ -1296,6 +1328,27 @@ static LRESULT CALLBACK WndProc(HWND hWn
1593 fl_i_own_selection[1] = 0;
1594 return 1;
1595
1596+ case WM_CHANGECBCHAIN:
1597+ if ((hWnd == clipboard_wnd) &&
1598+ (next_clipboard_wnd == (HWND)wParam)) {
1599+ next_clipboard_wnd = (HWND)lParam;
1600+ return 0;
1601+ }
1602+ break;
1603+
1604+ case WM_DRAWCLIPBOARD:
1605+ // When the clipboard moves between two FLTK windows,
1606+ // fl_i_own_selection will temporarily be false as we are
1607+ // processing this message. Hence the need to use fl_find().
1608+ if (!initial_clipboard && !fl_find(GetClipboardOwner()))
1609+ fl_trigger_clipboard_notify(1);
1610+ initial_clipboard = false;
1611+
1612+ if (next_clipboard_wnd)
1613+ SendMessage(next_clipboard_wnd, WM_DRAWCLIPBOARD, wParam, lParam);
1614+
1615+ return 0;
1616+
1617 default:
1618 if (Fl::handle(0,0)) return 0;
1619 break;
1620@@ -1652,6 +1705,8 @@ Fl_X* Fl_X::make(Fl_Window* w) {
1621 x->next = Fl_X::first;
1622 Fl_X::first = x;
1623
1624+ fl_clipboard_notify_target(x->xid);
1625+
1626 x->wait_for_expose = 1;
1627 if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;}
1628 if (showit) {
1629diff -up fltk-1.3.x-r8659/src/Fl_cocoa.mm.orig fltk-1.3.x-r8659/src/Fl_cocoa.mm
1630--- fltk-1.3.x-r8659/src/Fl_cocoa.mm.orig 2011-05-19 14:22:48.558149919 +0200
1631+++ fltk-1.3.x-r8659/src/Fl_cocoa.mm 2011-05-19 14:23:49.938366416 +0200
1632@@ -1282,9 +1282,13 @@ extern "C" {
1633 }
1634 @end
1635
1636+static void clipboard_check(void);
1637+
1638 @implementation FLApplication
1639 + (void)sendEvent:(NSEvent *)theEvent
1640 {
1641+ // update clipboard status
1642+ clipboard_check();
1643 NSEventType type = [theEvent type];
1644 if (type == NSLeftMouseDown) {
1645 fl_lock_function();
1646@@ -2647,6 +2651,27 @@ void Fl::paste(Fl_Widget &receiver, int
1647 receiver.handle(FL_PASTE);
1648 }
1649
1650+extern void fl_trigger_clipboard_notify(int source);
1651+
1652+void fl_clipboard_notify_change() {
1653+ // No need to do anything here...
1654+}
1655+
1656+static void clipboard_check(void)
1657+{
1658+ PasteboardSyncFlags flags;
1659+
1660+ allocatePasteboard();
1661+ flags = PasteboardSynchronize(myPasteboard);
1662+
1663+ if (!(flags & kPasteboardModified))
1664+ return;
1665+ if (flags & kPasteboardClientIsOwner)
1666+ return;
1667+
1668+ fl_trigger_clipboard_notify(1);
1669+}
1670+
1671 void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
1672 {
1673 // check, if this timer slot exists already
1674diff -bur fltk-1.3.x-r8732.org/documentation/src/enumerations.dox fltk-1.3.x-r8732/documentation/src/enumerations.dox
1675--- fltk-1.3.x-r8732.org/documentation/src/enumerations.dox 2011-05-11 17:49:30.000000000 +0200
1676+++ fltk-1.3.x-r8732/documentation/src/enumerations.dox 2011-05-26 10:15:39.258959203 +0200
1677@@ -57,6 +57,7 @@
1678 \li FL_DND_LEAVE - The mouse pointer left a widget still dragging
1679 data.
1680 \li FL_DND_RELEASE - Dragged data is about to be dropped.
1681+\li FL_FULLSCREEN - The fullscreen state of the window has changed.
1682
1683
1684 \section enumerations_when Callback "When" Conditions
1685diff -bur fltk-1.3.x-r8732.org/documentation/src/events.dox fltk-1.3.x-r8732/documentation/src/events.dox
1686--- fltk-1.3.x-r8732.org/documentation/src/events.dox 2011-05-11 17:49:30.000000000 +0200
1687+++ fltk-1.3.x-r8732/documentation/src/events.dox 2011-05-26 10:15:39.259959029 +0200
1688@@ -300,6 +300,13 @@
1689 the widget. If the widget returns 1, it will receive the data in
1690 the immediately following \p FL_PASTE event.
1691
1692+\subsection events_fl_fullscreen FL_FULLSCREEN
1693+
1694+The application window has been changed from normal to fullscreen, or
1695+from fullscreen to normal. If you are using a X window manager which
1696+supports Extended Window Manager Hints, this event will not be
1697+delivered until the change has actually happened.
1698+
1699
1700 \section events_event_xxx Fl::event_*() methods
1701
1702diff -bur fltk-1.3.x-r8732.org/FL/Enumerations.H fltk-1.3.x-r8732/FL/Enumerations.H
1703--- fltk-1.3.x-r8732.org/FL/Enumerations.H 2011-05-21 23:55:59.000000000 +0200
1704+++ fltk-1.3.x-r8732/FL/Enumerations.H 2011-05-26 10:15:39.256959549 +0200
1705@@ -292,7 +292,12 @@
1706 If the widget returns 1, it will receive the data in the immediately
1707 following FL_PASTE event.
1708 */
1709- FL_DND_RELEASE = 23
1710+ FL_DND_RELEASE = 23,
1711+
1712+ /** The fullscreen state of the window has changed
1713+ */
1714+ FL_FULLSCREEN = 24
1715+
1716 };
1717
1718 /** \name When Conditions */
1719diff -bur fltk-1.3.x-r8732.org/FL/Fl_Widget.H fltk-1.3.x-r8732/FL/Fl_Widget.H
1720--- fltk-1.3.x-r8732.org/FL/Fl_Widget.H 2011-05-26 10:15:26.146232604 +0200
1721+++ fltk-1.3.x-r8732/FL/Fl_Widget.H 2011-05-26 10:15:53.701455256 +0200
1722@@ -180,6 +180,7 @@
1723 GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window
1724 COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget
1725 SIMPLE_KEYBOARD = 1<<18, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input)
1726+ FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window)
1727 // (space for more flags)
1728 USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions
1729 USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions
1730@@ -882,6 +883,9 @@
1731 static unsigned int label_shortcut(const char *t);
1732 /* Internal use only. */
1733 static int test_shortcut(const char*, const bool require_alt = false);
1734+ /* Internal use only. */
1735+ void _set_fullscreen() {flags_ |= FULLSCREEN;}
1736+ void _clear_fullscreen() {flags_ &= ~FULLSCREEN;}
1737
1738 /** Checks if w is a child of this widget.
1739 \param[in] w potential child widget
1740Endast i fltk-1.3.x-r8732/FL: Fl_Widget.H.orig
1741diff -bur fltk-1.3.x-r8732.org/FL/Fl_Window.H fltk-1.3.x-r8732/FL/Fl_Window.H
1742--- fltk-1.3.x-r8732.org/FL/Fl_Window.H 2011-04-15 23:38:05.000000000 +0200
1743+++ fltk-1.3.x-r8732/FL/Fl_Window.H 2011-05-26 10:15:39.258959203 +0200
1744@@ -69,6 +69,7 @@
1745 int minw, minh, maxw, maxh;
1746 int dw, dh, aspect;
1747 uchar size_range_set;
1748+ int no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h;
1749 // cursor stuff
1750 Fl_Cursor cursor_default;
1751 Fl_Color cursor_fg, cursor_bg;
1752@@ -384,15 +385,27 @@
1753 /**
1754 Makes the window completely fill the screen, without any window
1755 manager border visible. You must use fullscreen_off() to undo
1756- this. This may not work with all window managers.
1757+ this.
1758+
1759+ \note On some platforms, this can result in the keyboard being
1760+ grabbed. The window may also be recreated, meaning hide() and
1761+ show() will be called.
1762 */
1763 void fullscreen();
1764 /**
1765+ Turns off any side effects of fullscreen()
1766+ */
1767+ void fullscreen_off();
1768+ /**
1769 Turns off any side effects of fullscreen() and does
1770 resize(x,y,w,h).
1771 */
1772 void fullscreen_off(int,int,int,int);
1773 /**
1774+ Returns non zero if FULLSCREEN flag is set, 0 otherwise.
1775+ */
1776+ unsigned int fullscreen_active() const { return flags() & FULLSCREEN; }
1777+ /**
1778 Iconifies the window. If you call this when shown() is false
1779 it will show() it as an icon. If the window is already
1780 iconified this does nothing.
1781diff -bur fltk-1.3.x-r8732.org/FL/names.h fltk-1.3.x-r8732/FL/names.h
1782--- fltk-1.3.x-r8732.org/FL/names.h 2010-11-28 22:06:39.000000000 +0100
1783+++ fltk-1.3.x-r8732/FL/names.h 2011-05-26 10:15:39.257959376 +0200
1784@@ -75,6 +75,7 @@
1785 "FL_DND_DRAG",
1786 "FL_DND_LEAVE",
1787 "FL_DND_RELEASE",
1788+ "FL_FULLSCREEN"
1789 };
1790
1791 /**
1792diff -bur fltk-1.3.x-r8732.org/src/Fl_cocoa.mm fltk-1.3.x-r8732/src/Fl_cocoa.mm
1793--- fltk-1.3.x-r8732.org/src/Fl_cocoa.mm 2011-05-26 10:15:26.168228790 +0200
1794+++ fltk-1.3.x-r8732/src/Fl_cocoa.mm 2011-05-26 10:15:39.255959723 +0200
1795@@ -649,6 +649,10 @@
1796 {
1797 containsGLsubwindow = contains;
1798 }
1799+- (BOOL)canBecomeKeyWindow
1800+{
1801+ return YES;
1802+}
1803 @end
1804
1805 @interface FLApplication : NSObject
1806@@ -1087,6 +1091,10 @@
1807 fl_lock_function();
1808 FLWindow *nsw = (FLWindow*)[notif object];
1809 Fl_Window *window = [nsw getFl_Window];
1810+ /* Fullscreen windows obscure all other windows so we need to return
1811+ to a "normal" level when the user switches to another window */
1812+ if (window->fullscreen_active())
1813+ [nsw setLevel:NSNormalWindowLevel];
1814 Fl::handle( FL_UNFOCUS, window);
1815 fl_unlock_function();
1816 }
1817@@ -1095,6 +1103,9 @@
1818 fl_lock_function();
1819 FLWindow *nsw = (FLWindow*)[notif object];
1820 Fl_Window *w = [nsw getFl_Window];
1821+ /* Restore previous fullscreen level */
1822+ if (w->fullscreen_active())
1823+ [nsw setLevel:NSStatusWindowLevel];
1824 if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle( FL_FOCUS, w);
1825 fl_unlock_function();
1826 }
1827@@ -2087,6 +2098,22 @@
1828
1829 @end
1830
1831+void fullscreen_x(Fl_Window *w) {
1832+ w->_set_fullscreen();
1833+ /* On OS X < 10.6, it is necessary to recreate the window. This is done
1834+ with hide+show. */
1835+ w->hide();
1836+ w->show();
1837+ Fl::handle(FL_FULLSCREEN, w);
1838+}
1839+
1840+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
1841+ w->_clear_fullscreen();
1842+ w->hide();
1843+ w->resize(X, Y, W, H);
1844+ w->show();
1845+ Fl::handle(FL_FULLSCREEN, w);
1846+}
1847
1848 /*
1849 * go ahead, create that (sub)window
1850@@ -2210,6 +2237,13 @@
1851 x->gc = 0;
1852
1853 NSRect srect = [[NSScreen mainScreen] frame];
1854+ if (w->flags() & Fl_Widget::FULLSCREEN) {
1855+ int sx, sy, sw, sh;
1856+ Fl::screen_xywh(sx, sy, sw, sh, w->x(), w->y(), w->w(), w->h());
1857+ w->resize(sx, sy, sw, sh);
1858+ winstyle = NSBorderlessWindowMask;
1859+ winlevel = NSStatusWindowLevel;
1860+ }
1861 NSRect crect;
1862 crect.origin.x = w->x();
1863 crect.origin.y = srect.size.height - (w->y() + w->h());
1864Endast i fltk-1.3.x-r8732/src: Fl_cocoa.mm.orig
1865diff -bur fltk-1.3.x-r8732.org/src/Fl_grab.cxx fltk-1.3.x-r8732/src/Fl_grab.cxx
1866--- fltk-1.3.x-r8732.org/src/Fl_grab.cxx 2011-05-26 10:15:26.147232431 +0200
1867+++ fltk-1.3.x-r8732/src/Fl_grab.cxx 2011-05-26 10:15:39.250960589 +0200
1868@@ -51,7 +51,19 @@
1869 extern void *fl_capture;
1870 #endif
1871
1872+#if !(defined(WIN32) || defined(__APPLE__))
1873+extern int ewmh_supported(); // from Fl_x.cxx
1874+#endif
1875+
1876 void Fl::grab(Fl_Window* win) {
1877+ Fl_Window *fullscreen_win = NULL;
1878+ for (Fl_Window *W = Fl::first_window(); W; W = Fl::next_window(W)) {
1879+ if (W->fullscreen_active()) {
1880+ fullscreen_win = W;
1881+ break;
1882+ }
1883+ }
1884+
1885 if (win) {
1886 if (!grab_) {
1887 #ifdef WIN32
1888@@ -61,8 +73,9 @@
1889 fl_capture = Fl_X::i(first_window())->xid;
1890 Fl_X::i(first_window())->set_key_window();
1891 #else
1892+ Window xid = fullscreen_win ? fl_xid(fullscreen_win) : fl_xid(first_window());
1893 XGrabPointer(fl_display,
1894- fl_xid(first_window()),
1895+ xid,
1896 1,
1897 ButtonPressMask|ButtonReleaseMask|
1898 ButtonMotionMask|PointerMotionMask,
1899@@ -72,7 +85,7 @@
1900 0,
1901 fl_event_time);
1902 XGrabKeyboard(fl_display,
1903- fl_xid(first_window()),
1904+ xid,
1905 1,
1906 GrabModeAsync,
1907 GrabModeAsync,
1908@@ -89,7 +102,10 @@
1909 #elif defined(__APPLE__)
1910 fl_capture = 0;
1911 #else
1912+ // We must keep the grab in the non-EWMH fullscreen case
1913+ if (!fullscreen_win || ewmh_supported()) {
1914 XUngrabKeyboard(fl_display, fl_event_time);
1915+ }
1916 XUngrabPointer(fl_display, fl_event_time);
1917 // this flush is done in case the picked menu item goes into
1918 // an infinite loop, so we don't leave the X server locked up:
1919Endast i fltk-1.3.x-r8732/src: Fl_grab.cxx.orig
1920diff -bur fltk-1.3.x-r8732.org/src/Fl_win32.cxx fltk-1.3.x-r8732/src/Fl_win32.cxx
1921--- fltk-1.3.x-r8732.org/src/Fl_win32.cxx 2011-05-26 10:15:26.165229310 +0200
1922+++ fltk-1.3.x-r8732/src/Fl_win32.cxx 2011-05-26 10:15:39.252960243 +0200
1923@@ -1490,6 +1490,11 @@
1924 X+=xoff;
1925 Y+=yoff;
1926
1927+ if (w->flags() & Fl_Widget::FULLSCREEN) {
1928+ X = Y = 0;
1929+ bx = by = bt = 0;
1930+ }
1931+
1932 return ret;
1933 }
1934
1935@@ -1540,6 +1545,58 @@
1936 }
1937 }
1938
1939+static void make_fullscreen(Fl_Window *w, Window xid, int X, int Y, int W, int H) {
1940+ int sx, sy, sw, sh;
1941+ Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H);
1942+ DWORD flags = GetWindowLong(xid, GWL_STYLE);
1943+ flags = flags & ~(WS_THICKFRAME|WS_CAPTION);
1944+ SetWindowLong(xid, GWL_STYLE, flags);
1945+ // SWP_NOSENDCHANGING is so that we can override size limits
1946+ SetWindowPos(xid, HWND_TOP, sx, sy, sw, sh, SWP_NOSENDCHANGING | SWP_FRAMECHANGED);
1947+}
1948+
1949+void fullscreen_x(Fl_Window *w) {
1950+ w->_set_fullscreen();
1951+ make_fullscreen(w, fl_xid(w), w->x(), w->y(), w->w(), w->h());
1952+ Fl::handle(FL_FULLSCREEN, w);
1953+}
1954+
1955+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
1956+ w->_clear_fullscreen();
1957+ DWORD style = GetWindowLong(fl_xid(w), GWL_STYLE);
1958+ // Remove the xid temporarily so that Fl_X::fake_X_wm() behaves like it
1959+ // does in Fl_X::make().
1960+ HWND xid = fl_xid(w);
1961+ Fl_X::i(w)->xid = NULL;
1962+ int x, y, bt, bx, by;
1963+ switch (Fl_X::fake_X_wm(w, x, y, bt, bx, by)) {
1964+ case 0:
1965+ break;
1966+ case 1:
1967+ style |= WS_CAPTION;
1968+ break;
1969+ case 2:
1970+ if (w->border()) {
1971+ style |= WS_THICKFRAME | WS_CAPTION;
1972+ }
1973+ break;
1974+ }
1975+ Fl_X::i(w)->xid = xid;
1976+ // Adjust for decorations (but not if that puts the decorations
1977+ // outside the screen)
1978+ if ((X != w->x()) || (Y != w->y())) {
1979+ X -= bx;
1980+ Y -= by+bt;
1981+ }
1982+ W += bx*2;
1983+ H += by*2+bt;
1984+ SetWindowLong(fl_xid(w), GWL_STYLE, style);
1985+ SetWindowPos(fl_xid(w), 0, X, Y, W, H,
1986+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
1987+ Fl::handle(FL_FULLSCREEN, w);
1988+}
1989+
1990+
1991 ////////////////////////////////////////////////////////////////
1992
1993 /*
1994@@ -1669,18 +1726,26 @@ Fl_X* Fl_X::make(Fl_Window* w) {
1995 int xwm = xp , ywm = yp , bt, bx, by;
1996 switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) {
1997 // No border (used for menus)
1998- case 0: style |= WS_POPUP;
1999- styleEx |= WS_EX_TOOLWINDOW;
2000+ case 0:
2001+ style |= WS_POPUP;
2002+ styleEx |= WS_EX_TOOLWINDOW;
2003 break;
2004
2005 // Thin border and title bar
2006- case 1: style |= WS_DLGFRAME | WS_CAPTION; break;
2007+ case 1:
2008+ style |= WS_DLGFRAME | WS_CAPTION;
2009+ if (!w->modal())
2010+ style |= WS_SYSMENU | WS_MINIMIZEBOX;
2011+ break;
2012
2013 // Thick, resizable border and title bar, with maximize button
2014- case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break;
2015+ case 2:
2016+ style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION;
2017+ if (!w->modal())
2018+ style |= WS_MINIMIZEBOX;
2019+ break;
2020 }
2021 if (by+bt) {
2022- if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
2023 wp += 2*bx;
2024 hp += 2*by+bt;
2025 }
2026@@ -1736,6 +1801,18 @@
2027 );
2028 if (lab) free(lab);
2029
2030+ if (w->flags() & Fl_Widget::FULLSCREEN) {
2031+ /* We need to make sure that the fullscreen is created on the
2032+ default monitor, ie the desktop where the shortcut is located
2033+ etc. This requires that CreateWindow is called with CW_USEDEFAULT
2034+ for x and y. We can then use GetWindowRect to determine which
2035+ monitor the window was placed on. */
2036+ RECT rect;
2037+ GetWindowRect(x->xid, &rect);
2038+ make_fullscreen(w, x->xid, rect.left, rect.top,
2039+ rect.right - rect.left, rect.bottom - rect.top);
2040+ }
2041+
2042 x->next = Fl_X::first;
2043 Fl_X::first = x;
2044
2045@@ -1753,7 +1830,7 @@
2046 // If we've captured the mouse, we dont want to activate any
2047 // other windows from the code, or we lose the capture.
2048 ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
2049- (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
2050+ (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
2051
2052 // Register all windows for potential drag'n'drop operations
2053 fl_OleInitialize();
2054Endast i fltk-1.3.x-r8732/src: Fl_win32.cxx.orig
2055diff -bur fltk-1.3.x-r8732.org/src/Fl_Window.cxx fltk-1.3.x-r8732/src/Fl_Window.cxx
2056--- fltk-1.3.x-r8732.org/src/Fl_Window.cxx 2011-02-25 09:44:47.000000000 +0100
2057+++ fltk-1.3.x-r8732/src/Fl_Window.cxx 2011-05-26 10:15:39.250960589 +0200
2058@@ -59,6 +59,10 @@
2059 resizable(0);
2060 size_range_set = 0;
2061 minw = maxw = minh = maxh = 0;
2062+ no_fullscreen_x = 0;
2063+ no_fullscreen_y = 0;
2064+ no_fullscreen_w = w();
2065+ no_fullscreen_h = h();
2066 callback((Fl_Callback*)default_callback);
2067 }
2068
2069diff -bur fltk-1.3.x-r8732.org/src/Fl_Window_fullscreen.cxx fltk-1.3.x-r8732/src/Fl_Window_fullscreen.cxx
2070--- fltk-1.3.x-r8732.org/src/Fl_Window_fullscreen.cxx 2011-03-12 22:36:21.000000000 +0100
2071+++ fltk-1.3.x-r8732/src/Fl_Window_fullscreen.cxx 2011-05-26 10:15:39.249960763 +0200
2072@@ -60,39 +60,48 @@
2073 #endif
2074 }
2075
2076+void fullscreen_x(Fl_Window *w);
2077+void fullscreen_off_x();
2078+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H);
2079+
2080+/* Note: The previous implementation toggled border(). With this new
2081+ implementation this is not necessary. Additionally, if we do that,
2082+ the application may lose focus when switching out of fullscreen
2083+ mode with some window managers. Besides, the API does not say that
2084+ the FLTK border state should be toggled; it only says that the
2085+ borders should not be *visible*.
2086+*/
2087 void Fl_Window::fullscreen() {
2088-#ifndef WIN32
2089- //this would clobber the fake wm, since it relies on the border flags to
2090- //determine its thickness
2091- border(0);
2092-#endif
2093-#if defined(__APPLE__) || defined(WIN32) || defined(USE_X11)
2094- int sx, sy, sw, sh;
2095- Fl::screen_xywh(sx, sy, sw, sh, x(), y(), w(), h());
2096- // if we are on the main screen, we will leave the system menu bar unobstructed
2097- if (Fl::x()>=sx && Fl::y()>=sy && Fl::x()+Fl::w()<=sx+sw && Fl::y()+Fl::h()<=sy+sh) {
2098- sx = Fl::x(); sy = Fl::y();
2099- sw = Fl::w(); sh = Fl::h();
2100+ if (shown() && !(flags() & Fl_Widget::FULLSCREEN)) {
2101+ no_fullscreen_x = x();
2102+ no_fullscreen_y = y();
2103+ no_fullscreen_w = w();
2104+ no_fullscreen_h = h();
2105+ fullscreen_x(this);
2106+ } else {
2107+ set_flag(FULLSCREEN);
2108 }
2109- if (x()==sx) x(sx+1); // make sure that we actually execute the resize
2110-#if defined(USE_X11)
2111- resize(0, 0, w(), h()); // work around some quirks in X11
2112-#endif
2113- resize(sx, sy, sw, sh);
2114-#else
2115- if (!x()) x(1); // make sure that we actually execute the resize
2116- resize(0,0,Fl::w(),Fl::h());
2117-#endif
2118 }
2119
2120 void Fl_Window::fullscreen_off(int X,int Y,int W,int H) {
2121- // this order produces less blinking on IRIX:
2122- resize(X,Y,W,H);
2123-#ifndef WIN32
2124- border(1);
2125-#endif
2126+ if (shown() && (flags() & Fl_Widget::FULLSCREEN)) {
2127+ fullscreen_off_x(this, X, Y, W, H);
2128+ } else {
2129+ clear_flag(FULLSCREEN);
2130+ }
2131+ no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0;
2132 }
2133
2134+void Fl_Window::fullscreen_off() {
2135+ if (!no_fullscreen_x && !no_fullscreen_y) {
2136+ // Window was initially created fullscreen - default to current monitor
2137+ no_fullscreen_x = x();
2138+ no_fullscreen_y = y();
2139+ }
2140+ fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h);
2141+}
2142+
2143+
2144 //
2145 // End of "$Id: Fl_Window_fullscreen.cxx 8515 2011-03-12 21:36:21Z manolo $".
2146 //
2147Endast i fltk-1.3.x-r8732/src: Fl_Window_fullscreen.cxx.orig
2148diff -bur fltk-1.3.x-r8732.org/src/Fl_x.cxx fltk-1.3.x-r8732/src/Fl_x.cxx
2149--- fltk-1.3.x-r8732.org/src/Fl_x.cxx 2011-05-26 10:15:26.159230350 +0200
2150+++ fltk-1.3.x-r8732/src/Fl_x.cxx 2011-05-26 10:15:39.253960069 +0200
2151@@ -338,6 +338,9 @@
2152 Atom fl_XaTextUriList;
2153 Atom fl_NET_WM_NAME; // utf8 aware window label
2154 Atom fl_NET_WM_ICON_NAME; // utf8 aware window icon name
2155+Atom fl_NET_SUPPORTING_WM_CHECK;
2156+Atom fl_NET_WM_STATE;
2157+Atom fl_NET_WM_STATE_FULLSCREEN;
2158
2159 /*
2160 X defines 32-bit-entities to have a format value of max. 32,
2161@@ -711,6 +714,9 @@
2162 fl_XaTextUriList = XInternAtom(d, "text/uri-list", 0);
2163 fl_NET_WM_NAME = XInternAtom(d, "_NET_WM_NAME", 0);
2164 fl_NET_WM_ICON_NAME = XInternAtom(d, "_NET_WM_ICON_NAME", 0);
2165+ fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0);
2166+ fl_NET_WM_STATE = XInternAtom(d, "_NET_WM_STATE", 0);
2167+ fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0);
2168
2169 if (sizeof(Atom) < 4)
2170 atom_bits = sizeof(Atom) * 8;
2171@@ -862,6 +868,31 @@
2172 XSendEvent(fl_display, window, 0, 0, &e);
2173 }
2174
2175+
2176+/*
2177+ Get window property value (32 bit format)
2178+ Returns zero on success, -1 on error
2179+*/
2180+static int get_xwinprop(Window wnd, Atom prop, long max_length,
2181+ unsigned long *nitems, unsigned long **data) {
2182+ Atom actual;
2183+ int format;
2184+ unsigned long bytes_after;
2185+
2186+ if (Success != XGetWindowProperty(fl_display, wnd, prop, 0, max_length,
2187+ False, AnyPropertyType, &actual, &format,
2188+ nitems, &bytes_after, (unsigned char**)data)) {
2189+ return -1;
2190+ }
2191+
2192+ if (actual == None || format != 32) {
2193+ return -1;
2194+ }
2195+
2196+ return 0;
2197+}
2198+
2199+
2200 ////////////////////////////////////////////////////////////////
2201 // Code for copying to clipboard and DnD out of the program:
2202
2203@@ -1631,6 +1662,31 @@
2204 in_a_window = true;
2205 break;
2206
2207+ case PropertyNotify:
2208+ if (xevent.xproperty.atom == fl_NET_WM_STATE) {
2209+ int fullscreen_state = 0;
2210+ if (xevent.xproperty.state != PropertyDelete) {
2211+ unsigned long nitems;
2212+ unsigned long *words = 0;
2213+ if (0 == get_xwinprop(xid, fl_NET_WM_STATE, 64, &nitems, &words) ) {
2214+ for (unsigned long item = 0; item < nitems; item++) {
2215+ if (words[item] == fl_NET_WM_STATE_FULLSCREEN) {
2216+ fullscreen_state = 1;
2217+ }
2218+ }
2219+ }
2220+ }
2221+ if (window->fullscreen_active() && !fullscreen_state) {
2222+ window->_clear_fullscreen();
2223+ event = FL_FULLSCREEN;
2224+ }
2225+ if (!window->fullscreen_active() && fullscreen_state) {
2226+ window->_set_fullscreen();
2227+ event = FL_FULLSCREEN;
2228+ }
2229+ }
2230+ break;
2231+
2232 case MotionNotify:
2233 set_event_xy();
2234 # if CONSOLIDATE_MOTION
2235@@ -1789,6 +1845,75 @@
2236
2237 ////////////////////////////////////////////////////////////////
2238
2239+#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
2240+#define _NET_WM_STATE_ADD 1 /* add/set property */
2241+#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
2242+
2243+static void send_wm_state_event(Window wnd, int add, Atom prop) {
2244+ XEvent e;
2245+ e.xany.type = ClientMessage;
2246+ e.xany.window = wnd;
2247+ e.xclient.message_type = fl_NET_WM_STATE;
2248+ e.xclient.format = 32;
2249+ e.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
2250+ e.xclient.data.l[1] = prop;
2251+ e.xclient.data.l[2] = 0;
2252+ e.xclient.data.l[3] = 0;
2253+ e.xclient.data.l[4] = 0;
2254+ XSendEvent(fl_display, RootWindow(fl_display, fl_screen),
2255+ 0, SubstructureNotifyMask | SubstructureRedirectMask,
2256+ &e);
2257+}
2258+
2259+int ewmh_supported() {
2260+ static int result = -1;
2261+
2262+ if (result == -1) {
2263+ result = 0;
2264+ unsigned long nitems;
2265+ unsigned long *words = 0;
2266+ if (0 == get_xwinprop(XRootWindow(fl_display, fl_screen), fl_NET_SUPPORTING_WM_CHECK, 64,
2267+ &nitems, &words) && nitems == 1) {
2268+ Window child = words[0];
2269+ if (0 == get_xwinprop(child, fl_NET_SUPPORTING_WM_CHECK, 64,
2270+ &nitems, &words) && nitems == 1) {
2271+ result = (child == words[0]);
2272+ }
2273+ }
2274+ }
2275+
2276+ return result;
2277+}
2278+
2279+/* Change an existing window to fullscreen */
2280+void fullscreen_x(Fl_Window *w) {
2281+ if (ewmh_supported()) {
2282+ send_wm_state_event(fl_xid(w), 1, fl_NET_WM_STATE_FULLSCREEN);
2283+ } else {
2284+ w->_set_fullscreen();
2285+ w->hide();
2286+ w->show();
2287+ /* We want to grab the window, not a widget, so we cannot use Fl::grab */
2288+ XGrabKeyboard(fl_display, fl_xid(w), 1, GrabModeAsync, GrabModeAsync, fl_event_time);
2289+ Fl::handle(FL_FULLSCREEN, w);
2290+ }
2291+}
2292+
2293+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
2294+ if (ewmh_supported()) {
2295+ send_wm_state_event(fl_xid(w), 0, fl_NET_WM_STATE_FULLSCREEN);
2296+ } else {
2297+ w->_clear_fullscreen();
2298+ /* The grab will be lost when the window is destroyed */
2299+ w->hide();
2300+ w->resize(X,Y,W,H);
2301+ w->show();
2302+ Fl::handle(FL_FULLSCREEN, w);
2303+ }
2304+}
2305+
2306+////////////////////////////////////////////////////////////////
2307+
2308 // A subclass of Fl_Window may call this to associate an X window it
2309 // creates with the Fl_Window:
2310
2311@@ -1824,6 +1949,7 @@
2312 |KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask
2313 |ButtonPressMask|ButtonReleaseMask
2314 |EnterWindowMask|LeaveWindowMask
2315+|PropertyChangeMask
2316 |PointerMotionMask;
2317
2318 void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
2319@@ -1895,6 +2021,16 @@
2320 attr.save_under = 1; mask |= CWSaveUnder;
2321 if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;}
2322 }
2323+ // For the non-EWMH fullscreen case, we cannot use the code above,
2324+ // since we do not want save_under, do not want to turn off the
2325+ // border, and cannot grab without an existing window. Besides,
2326+ // there is no clear_override().
2327+ if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) {
2328+ attr.override_redirect = 1;
2329+ mask |= CWOverrideRedirect;
2330+ Fl::screen_xywh(X, Y, W, H, X, Y, W, H);
2331+ }
2332+
2333 if (fl_background_pixel >= 0) {
2334 attr.background_pixel = fl_background_pixel;
2335 fl_background_pixel = -1;
2336@@ -1954,6 +2090,12 @@
2337 PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1);
2338 }
2339
2340+ // If asked for, create fullscreen
2341+ if (win->flags() & Fl_Widget::FULLSCREEN && ewmh_supported()) {
2342+ XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32,
2343+ PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1);
2344+ }
2345+
2346 // Make it receptive to DnD:
2347 long version = 4;
2348 XChangeProperty(fl_display, xp->xid, fl_XdndAware,
2349@@ -2001,6 +2143,12 @@
2350 Fl::e_number = old_event;
2351 win->redraw();
2352 }
2353+
2354+ // non-EWMH fullscreen case, need grab
2355+ if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) {
2356+ XGrabKeyboard(fl_display, xp->xid, 1, GrabModeAsync, GrabModeAsync, fl_event_time);
2357+ }
2358+
2359 }
2360
2361 ////////////////////////////////////////////////////////////////
2362Endast i fltk-1.3.x-r8732/src: Fl_x.cxx.orig
2363diff -bur fltk-1.3.x-r8732.org/test/fullscreen.cxx fltk-1.3.x-r8732/test/fullscreen.cxx
2364--- fltk-1.3.x-r8732.org/test/fullscreen.cxx 2010-12-15 13:11:16.000000000 +0100
2365+++ fltk-1.3.x-r8732/test/fullscreen.cxx 2011-05-26 10:15:39.258959203 +0200
2366@@ -60,8 +60,11 @@
2367 #include <FL/Fl.H>
2368 #include <FL/Fl_Single_Window.H>
2369 #include <FL/Fl_Hor_Slider.H>
2370+#include <FL/Fl_Input.H>
2371+#include <FL/Fl_Menu_Button.H>
2372 #include <FL/Fl_Toggle_Light_Button.H>
2373 #include <FL/math.h>
2374+#include <FL/fl_ask.H>
2375 #include <stdio.h>
2376
2377 #if HAVE_GL
2378@@ -124,6 +127,28 @@
2379
2380 #endif
2381
2382+class fullscreen_window : public Fl_Single_Window {
2383+
2384+ public:
2385+ fullscreen_window(int W, int H, const char *t=0);
2386+ int handle (int e);
2387+ Fl_Toggle_Light_Button *b3;
2388+
2389+};
2390+
2391+fullscreen_window::fullscreen_window(int W, int H, const char *t) : Fl_Single_Window(W, H, t) {
2392+
2393+}
2394+
2395+int fullscreen_window::handle(int e) {
2396+ if (e == FL_FULLSCREEN) {
2397+ printf("Recieved FL_FULLSCREEN event\n");
2398+ b3->value(fullscreen_active());
2399+ }
2400+ if (Fl_Single_Window::handle(e)) return 1;
2401+ return 0;
2402+}
2403+
2404 void sides_cb(Fl_Widget *o, void *p) {
2405 shape_window *sw = (shape_window *)p;
2406 sw->sides = int(((Fl_Slider *)o)->value());
2407@@ -161,13 +186,14 @@
2408 py = w->y();
2409 pw = w->w();
2410 ph = w->h();
2411-#ifndef WIN32//necessary because fullscreen removes border
2412- border_button->value(0);
2413- border_button->do_callback();
2414-#endif
2415 w->fullscreen();
2416+ w->override();
2417+#ifndef WIN32 // update our border state in case border was turned off
2418+ border_button->value(w->border());
2419+#endif
2420 } else {
2421- w->fullscreen_off(px,py,pw,ph);
2422+ //w->fullscreen_off(px,py,pw,ph);
2423+ w->fullscreen_off();
2424 }
2425 }
2426
2427@@ -177,7 +203,7 @@
2428 exit(0);
2429 }
2430
2431-#define NUMB 5
2432+#define NUMB 6
2433
2434 int twowindow = 0;
2435 int initfull = 0;
2436@@ -193,7 +219,7 @@
2437 if (Fl::args(argc,argv,i,arg) < argc)
2438 Fl::fatal("Options are:\n -2 = 2 windows\n -f = startup fullscreen\n%s",Fl::help);
2439
2440- Fl_Single_Window window(300,300+30*NUMB); window.end();
2441+ fullscreen_window window(300,300+30*NUMB); window.end();
2442
2443 shape_window sw(10,10,window.w()-20,window.h()-30*NUMB-20);
2444 #if HAVE_GL
2445@@ -228,21 +254,24 @@
2446 b1.callback(double_cb,&sw);
2447 y+=30;
2448
2449+ Fl_Input i1(50,y,window.w()-60,30, "Input");
2450+ y+=30;
2451+
2452 Fl_Toggle_Light_Button b2(50,y,window.w()-60,30,"Border");
2453 b2.callback(border_cb,w);
2454 b2.set();
2455 border_button = &b2;
2456 y+=30;
2457
2458- Fl_Toggle_Light_Button b3(50,y,window.w()-60,30,"FullScreen");
2459- b3.callback(fullscreen_cb,w);
2460+ window.b3 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"FullScreen");
2461+ window.b3->callback(fullscreen_cb,w);
2462 y+=30;
2463
2464 Fl_Button eb(50,y,window.w()-60,30,"Exit");
2465 eb.callback(exit_cb);
2466 y+=30;
2467
2468- if (initfull) {b3.set(); b3.do_callback();}
2469+ if (initfull) {window.b3->set(); window.b3->do_callback();}
2470
2471 window.end();
2472 window.show(argc,argv);
2473Index: fltk-1.3.x-r8772/src/Fl_Image.cxx
2474===================================================================
2475--- fltk-1.3.x-r8772/src/Fl_Image.cxx (revision 8771)
2476+++ fltk-1.3.x-r8772/src/Fl_Image.cxx (working copy)
2477@@ -172,6 +172,19 @@
2478 //
2479 // RGB image class...
2480 //
2481+
2482+int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg);
2483+
2484+/** The constructor creates a new RGBA image from the specified Fl_Pixmap. */
2485+Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg):
2486+ Fl_Image(pxm->w(), pxm->h(), 4), id_(0), mask_(0)
2487+{
2488+ array = new uchar[w() * h() * d()];
2489+ alloc_array = 1;
2490+ fl_convert_pixmap(pxm->data(), (uchar*)array, bg);
2491+ data((const char **)&array, 1);
2492+}
2493+
2494 /** The destructor free all memory and server resources that are used by the image. */
2495 Fl_RGB_Image::~Fl_RGB_Image() {
2496 uncache();
2497Index: fltk-1.3.x-r8772/FL/Fl_Image.H
2498===================================================================
2499--- fltk-1.3.x-r8772/FL/Fl_Image.H (revision 8771)
2500+++ fltk-1.3.x-r8772/FL/Fl_Image.H (working copy)
2501@@ -34,6 +34,7 @@
2502 # include "Enumerations.H"
2503
2504 class Fl_Widget;
2505+class Fl_Pixmap;
2506 struct Fl_Menu_Item;
2507 struct Fl_Label;
2508
2509@@ -196,6 +197,7 @@
2510 /** The constructor creates a new image from the specified data. */
2511 Fl_RGB_Image(const uchar *bits, int W, int H, int D=3, int LD=0) :
2512 Fl_Image(W,H,D), array(bits), alloc_array(0), id_(0), mask_(0) {data((const char **)&array, 1); ld(LD);}
2513+ Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg=FL_GRAY);
2514 virtual ~Fl_RGB_Image();
2515 virtual Fl_Image *copy(int W, int H);
2516 Fl_Image *copy() { return copy(w(), h()); }
2517Index: fltk-1.3.x-r8772/src/fl_draw_pixmap.cxx
2518===================================================================
2519--- fltk-1.3.x-r8772/src/fl_draw_pixmap.cxx (revision 8771)
2520+++ fltk-1.3.x-r8772/src/fl_draw_pixmap.cxx (working copy)
2521@@ -67,99 +67,6 @@
2522 return 1;
2523 }
2524
2525-#ifdef U64
2526-
2527-// The callback from fl_draw_image to get a row of data passes this:
2528-struct pixmap_data {
2529- int w, h;
2530- const uchar*const* data;
2531- union {
2532- U64 colors[256];
2533- U64* byte1[256];
2534- };
2535-};
2536-
2537-// callback for 1 byte per pixel:
2538-static void cb1(void*v, int x, int y, int w, uchar* buf) {
2539- pixmap_data& d = *(pixmap_data*)v;
2540- const uchar* p = d.data[y]+x;
2541- U64* q = (U64*)buf;
2542- for (int X=w; X>0; X-=2, p += 2) {
2543- if (X>1) {
2544-# if WORDS_BIGENDIAN
2545- *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
2546-# else
2547- *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
2548-# endif
2549- } else {
2550-# if WORDS_BIGENDIAN
2551- *q++ = d.colors[p[0]]<<32;
2552-# else
2553- *q++ = d.colors[p[0]];
2554-# endif
2555- }
2556- }
2557-}
2558-
2559-// callback for 2 bytes per pixel:
2560-static void cb2(void*v, int x, int y, int w, uchar* buf) {
2561- pixmap_data& d = *(pixmap_data*)v;
2562- const uchar* p = d.data[y]+2*x;
2563- U64* q = (U64*)buf;
2564- for (int X=w; X>0; X-=2) {
2565- U64* colors = d.byte1[*p++];
2566- int index = *p++;
2567- if (X>1) {
2568- U64* colors1 = d.byte1[*p++];
2569- int index1 = *p++;
2570-# if WORDS_BIGENDIAN
2571- *q++ = (colors[index]<<32) | colors1[index1];
2572-# else
2573- *q++ = (colors1[index1]<<32) | colors[index];
2574-# endif
2575- } else {
2576-# if WORDS_BIGENDIAN
2577- *q++ = colors[index]<<32;
2578-# else
2579- *q++ = colors[index];
2580-# endif
2581- }
2582- }
2583-}
2584-
2585-#else // U32
2586-
2587-// The callback from fl_draw_image to get a row of data passes this:
2588-struct pixmap_data {
2589- int w, h;
2590- const uchar*const* data;
2591- union {
2592- U32 colors[256];
2593- U32* byte1[256];
2594- };
2595-};
2596-
2597-// callback for 1 byte per pixel:
2598-static void cb1(void*v, int x, int y, int w, uchar* buf) {
2599- pixmap_data& d = *(pixmap_data*)v;
2600- const uchar* p = d.data[y]+x;
2601- U32* q = (U32*)buf;
2602- for (int X=w; X--;) *q++ = d.colors[*p++];
2603-}
2604-
2605-// callback for 2 bytes per pixel:
2606-static void cb2(void*v, int x, int y, int w, uchar* buf) {
2607- pixmap_data& d = *(pixmap_data*)v;
2608- const uchar* p = d.data[y]+2*x;
2609- U32* q = (U32*)buf;
2610- for (int X=w; X--;) {
2611- U32* colors = d.byte1[*p++];
2612- *q++ = colors[*p++];
2613- }
2614-}
2615-
2616-#endif // U64 else U32
2617-
2618 uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
2619
2620 /**
2621@@ -209,34 +116,33 @@
2622 }
2623 #endif
2624
2625-/**
2626- Draw XPM image data, with the top-left corner at the given position.
2627- \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
2628- */
2629-int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
2630- pixmap_data d;
2631- if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0;
2632+int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg) {
2633+ int w, h;
2634 const uchar*const* data = (const uchar*const*)(cdata+1);
2635 int transparent_index = -1;
2636 uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
2637+
2638+ if (!fl_measure_pixmap(cdata, w, h))
2639+ return 0;
2640+
2641+ if ((chars_per_pixel < 1) || (chars_per_pixel > 2))
2642+ return 0;
2643+
2644+ uchar colors[1<<(chars_per_pixel*8)][4];
2645+
2646 #ifdef WIN32
2647 color_count = 0;
2648 used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
2649 #endif
2650
2651- if (ncolors < 0) { // FLTK (non standard) compressed colormap
2652+ if (ncolors < 0) {
2653+ // FLTK (non standard) compressed colormap
2654 ncolors = -ncolors;
2655 const uchar *p = *data++;
2656 // if first color is ' ' it is transparent (put it later to make
2657 // it not be transparent):
2658 if (*p == ' ') {
2659- uchar* c = (uchar*)&d.colors[(int)' '];
2660-#ifdef U64
2661- *(U64*)c = 0;
2662-# if WORDS_BIGENDIAN
2663- c += 4;
2664-# endif
2665-#endif
2666+ uchar* c = colors[(int)' '];
2667 transparent_index = ' ';
2668 Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
2669 transparent_c = c;
2670@@ -245,13 +151,7 @@
2671 }
2672 // read all the rest of the colors:
2673 for (int i=0; i < ncolors; i++) {
2674- uchar* c = (uchar*)&d.colors[*p++];
2675-#ifdef U64
2676- *(U64*)c = 0;
2677-# if WORDS_BIGENDIAN
2678- c += 4;
2679-# endif
2680-#endif
2681+ uchar* c = colors[*p++];
2682 #ifdef WIN32
2683 used_colors[3*color_count] = *p;
2684 used_colors[3*color_count+1] = *(p+1);
2685@@ -261,75 +161,49 @@
2686 *c++ = *p++;
2687 *c++ = *p++;
2688 *c++ = *p++;
2689-#ifdef __APPLE_QUARTZ__
2690 *c = 255;
2691-#else
2692- *c = 0;
2693-#endif
2694 }
2695- } else { // normal XPM colormap with names
2696- if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
2697+ } else {
2698+ // normal XPM colormap with names
2699 for (int i=0; i<ncolors; i++) {
2700 const uchar *p = *data++;
2701 // the first 1 or 2 characters are the color index:
2702 int ind = *p++;
2703 uchar* c;
2704- if (chars_per_pixel>1) {
2705-#ifdef U64
2706- U64* colors = d.byte1[ind];
2707- if (!colors) colors = d.byte1[ind] = new U64[256];
2708-#else
2709- U32* colors = d.byte1[ind];
2710- if (!colors) colors = d.byte1[ind] = new U32[256];
2711-#endif
2712- c = (uchar*)&colors[*p];
2713- ind = (ind<<8)|*p++;
2714- } else {
2715- c = (uchar *)&d.colors[ind];
2716- }
2717+ if (chars_per_pixel>1)
2718+ ind = (ind<<8)|*p++;
2719+ c = colors[ind];
2720 // look for "c word", or last word if none:
2721 const uchar *previous_word = p;
2722 for (;;) {
2723- while (*p && isspace(*p)) p++;
2724- uchar what = *p++;
2725- while (*p && !isspace(*p)) p++;
2726- while (*p && isspace(*p)) p++;
2727- if (!*p) {p = previous_word; break;}
2728- if (what == 'c') break;
2729- previous_word = p;
2730- while (*p && !isspace(*p)) p++;
2731+ while (*p && isspace(*p)) p++;
2732+ uchar what = *p++;
2733+ while (*p && !isspace(*p)) p++;
2734+ while (*p && isspace(*p)) p++;
2735+ if (!*p) {p = previous_word; break;}
2736+ if (what == 'c') break;
2737+ previous_word = p;
2738+ while (*p && !isspace(*p)) p++;
2739 }
2740-#ifdef U64
2741- *(U64*)c = 0;
2742-# if WORDS_BIGENDIAN
2743- c += 4;
2744-# endif
2745-#endif
2746-#ifdef __APPLE_QUARTZ__
2747- c[3] = 255;
2748-#endif
2749 int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
2750+ c[3] = 255;
2751 if (parse) {
2752 #ifdef WIN32
2753- used_colors[3*color_count] = c[0];
2754- used_colors[3*color_count+1] = c[1];
2755- used_colors[3*color_count+2] = c[2];
2756- color_count++;
2757+ used_colors[3*color_count] = c[0];
2758+ used_colors[3*color_count+1] = c[1];
2759+ used_colors[3*color_count+2] = c[2];
2760+ color_count++;
2761 #endif
2762- }
2763- else {
2764+ } else {
2765 // assume "None" or "#transparent" for any errors
2766- // "bg" should be transparent...
2767- Fl::get_color(bg, c[0], c[1], c[2]);
2768-#ifdef __APPLE_QUARTZ__
2769+ // "bg" should be transparent...
2770+ Fl::get_color(bg, c[0], c[1], c[2]);
2771 c[3] = 0;
2772-#endif
2773- transparent_index = ind;
2774- transparent_c = c;
2775+ transparent_index = ind;
2776+ transparent_c = c;
2777 }
2778 }
2779 }
2780- d.data = data;
2781 #ifdef WIN32
2782 if (transparent_c) {
2783 make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
2784@@ -339,88 +213,85 @@
2785 make_unused_color(r, g, b);
2786 }
2787 #endif
2788+
2789+ U32 *q = (U32*)out;
2790+ for (int Y = 0; Y < h; Y++) {
2791+ const uchar* p = data[Y];
2792+ if (chars_per_pixel <= 1) {
2793+ for (int X = 0; X < w; X++)
2794+ memcpy(q++, colors[*p++], 4);
2795+ } else {
2796+ for (int X = 0; X < w; X++) {
2797+ int ind = (*p++)<<8;
2798+ ind |= *p++;
2799+ memcpy(q++, colors[ind], 4);
2800+ }
2801+ }
2802+ }
2803
2804+ return 1;
2805+}
2806+
2807+/**
2808+ Draw XPM image data, with the top-left corner at the given position.
2809+ \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
2810+ */
2811+int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
2812+ int w, h;
2813+
2814+ if (!fl_measure_pixmap(cdata, w, h))
2815+ return 0;
2816+
2817+ uchar buffer[w*h*4];
2818+
2819+ if (!fl_convert_pixmap(cdata, buffer, bg))
2820+ return 0;
2821+
2822+ // FIXME: Hack until fl_draw_image() supports alpha properly
2823 #ifdef __APPLE_QUARTZ__
2824 if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
2825- bool transparent = (transparent_index>=0);
2826- transparent = true;
2827- U32 *array = new U32[d.w * d.h], *q = array;
2828- for (int Y = 0; Y < d.h; Y++) {
2829- const uchar* p = data[Y];
2830- if (chars_per_pixel <= 1) {
2831- for (int X = 0; X < d.w; X++) {
2832- *q++ = d.colors[*p++];
2833- }
2834- } else {
2835- for (int X = 0; X < d.w; X++) {
2836- U32* colors = (U32*)d.byte1[*p++];
2837- *q++ = colors[*p++];
2838- }
2839- }
2840- }
2841 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
2842- CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L);
2843- CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w,
2844- lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast,
2845- src, 0L, false, kCGRenderingIntentDefault);
2846+ CGDataProviderRef src = CGDataProviderCreateWithData( 0L, buffer, w * h * 4, 0L);
2847+ CGImageRef img = CGImageCreate(w, h, 8, 4*8, 4*w,
2848+ lut, kCGImageAlphaLast,
2849+ src, 0L, false, kCGRenderingIntentDefault);
2850 CGColorSpaceRelease(lut);
2851 CGDataProviderRelease(src);
2852- CGRect rect = { { x, y} , { d.w, d.h } };
2853- Fl_X::q_begin_image(rect, 0, 0, d.w, d.h);
2854+ CGRect rect = { { x, y }, { w, h } };
2855+ Fl_X::q_begin_image(rect, 0, 0, w, h);
2856 CGContextDrawImage(fl_gc, rect, img);
2857 Fl_X::q_end_image();
2858 CGImageRelease(img);
2859- delete[] array;
2860- }
2861- else {
2862+ } else {
2863 #endif // __APPLE_QUARTZ__
2864-
2865 // build the mask bitmap used by Fl_Pixmap:
2866- if (fl_mask_bitmap && transparent_index >= 0) {
2867- int W = (d.w+7)/8;
2868- uchar* bitmap = new uchar[W * d.h];
2869+ if (fl_mask_bitmap) {
2870+ int W = (w+7)/8;
2871+ uchar* bitmap = new uchar[W * h];
2872 *fl_mask_bitmap = bitmap;
2873- for (int Y = 0; Y < d.h; Y++) {
2874- const uchar* p = data[Y];
2875- if (chars_per_pixel <= 1) {
2876- int dw = d.w;
2877- for (int X = 0; X < W; X++) {
2878- uchar b = (dw-->0 && *p++ != transparent_index);
2879- if (dw-->0 && *p++ != transparent_index) b |= 2;
2880- if (dw-->0 && *p++ != transparent_index) b |= 4;
2881- if (dw-->0 && *p++ != transparent_index) b |= 8;
2882- if (dw-->0 && *p++ != transparent_index) b |= 16;
2883- if (dw-->0 && *p++ != transparent_index) b |= 32;
2884- if (dw-->0 && *p++ != transparent_index) b |= 64;
2885- if (dw-->0 && *p++ != transparent_index) b |= 128;
2886- *bitmap++ = b;
2887- }
2888- } else {
2889- uchar b = 0, bit = 1;
2890- for (int X = 0; X < d.w; X++) {
2891- int ind = *p++;
2892- ind = (ind<<8) | (*p++);
2893- if (ind != transparent_index) b |= bit;
2894-
2895- if (bit < 128) bit <<= 1;
2896- else {
2897- *bitmap++ = b;
2898- b = 0;
2899- bit = 1;
2900- }
2901- }
2902-
2903- if (bit > 1) *bitmap++ = b;
2904+ const uchar *p = &buffer[3];
2905+ for (int Y = 0; Y < h; Y++) {
2906+ int dw = w;
2907+ for (int X = 0; X < W; X++) {
2908+ uchar b = 0;
2909+ for (int bit = 0x01;bit <= 0x80;bit<<=1) {
2910+ if (dw-- < 0)
2911+ break;
2912+ if (*p > 127)
2913+ b |= bit;
2914+ p += 4;
2915+ }
2916+ *bitmap++ = b;
2917 }
2918 }
2919 }
2920
2921- fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
2922+ fl_draw_image(buffer, x, y, w, h, 4);
2923+
2924 #ifdef __APPLE_QUARTZ__
2925 }
2926 #endif
2927
2928- if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
2929 return 1;
2930 }
2931
2932diff -up fltk-1.3.x-r8772/configh.in.cursor fltk-1.3.x-r8772/configh.in
2933--- fltk-1.3.x-r8772/configh.in.cursor 2011-06-08 18:23:14.000000000 +0200
2934+++ fltk-1.3.x-r8772/configh.in 2011-06-08 18:24:34.373649514 +0200
2935@@ -125,6 +125,14 @@
2936 #define HAVE_XFIXES 0
2937
2938 /*
2939+ * HAVE_XCURSOR:
2940+ *
2941+ * Do we have the X cursor library?
2942+ */
2943+
2944+#define HAVE_XCURSOR 0
2945+
2946+/*
2947 * __APPLE_QUARTZ__:
2948 *
2949 * All Apple implementations are now based on Quartz and Cocoa,
2950diff -up fltk-1.3.x-r8772/configure.in.cursor fltk-1.3.x-r8772/configure.in
2951--- fltk-1.3.x-r8772/configure.in.cursor 2011-06-08 18:23:14.000000000 +0200
2952+++ fltk-1.3.x-r8772/configure.in 2011-06-08 18:25:06.681678402 +0200
2953@@ -1018,6 +1018,16 @@ case $uname_GUI in
2954 LIBS="-lXfixes $LIBS")
2955 fi
2956
2957+ dnl Check for the Xcursor library unless disabled...
2958+ AC_ARG_ENABLE(xcursor, [ --enable-xcursor turn on Xcursor support [default=yes]])
2959+
2960+ if test x$enable_xcursor != xno; then
2961+ AC_CHECK_HEADER(X11/Xcursor/Xcursor.h, AC_DEFINE(HAVE_XCURSOR),,
2962+ [#include <X11/Xlib.h>])
2963+ AC_CHECK_LIB(Xcursor, XcursorImageCreate,
2964+ LIBS="-lXcursor $LIBS")
2965+ fi
2966+
2967 dnl Check for overlay visuals...
2968 AC_PATH_PROG(XPROP, xprop)
2969 AC_CACHE_CHECK(for X overlay visuals, ac_cv_have_overlay,
2970diff -up fltk-1.3.x-r8772/FL/Enumerations.H.cursor fltk-1.3.x-r8772/FL/Enumerations.H
2971--- fltk-1.3.x-r8772/FL/Enumerations.H.cursor 2011-06-08 18:23:14.285141149 +0200
2972+++ fltk-1.3.x-r8772/FL/Enumerations.H 2011-06-08 18:23:14.308143306 +0200
2973@@ -879,35 +879,36 @@ inline Fl_Color fl_color_cube(int r, int
2974
2975 /** The following constants define the mouse cursors that are available in FLTK.
2976
2977- The double-headed arrows are bitmaps provided by FLTK on X, the others
2978- are provided by system-defined cursors.
2979+ Cursors are provided by the system when available, or bitmaps built into
2980+ FLTK as a fallback.
2981
2982 \todo enum Fl_Cursor needs maybe an image.
2983 */
2984 enum Fl_Cursor {
2985- FL_CURSOR_DEFAULT = 0, /**< the default cursor, usually an arrow. */
2986- FL_CURSOR_ARROW = 35, /**< an arrow pointer. */
2987- FL_CURSOR_CROSS = 66, /**< crosshair. */
2988- FL_CURSOR_WAIT = 76, /**< watch or hourglass. */
2989- FL_CURSOR_INSERT = 77, /**< I-beam. */
2990- FL_CURSOR_HAND = 31, /**< hand (uparrow on MSWindows). */
2991- FL_CURSOR_HELP = 47, /**< question mark. */
2992- FL_CURSOR_MOVE = 27, /**< 4-pointed arrow. */
2993- // fltk provides bitmaps for these:
2994- FL_CURSOR_NS = 78, /**< up/down arrow. */
2995- FL_CURSOR_WE = 79, /**< left/right arrow. */
2996- FL_CURSOR_NWSE = 80, /**< diagonal arrow. */
2997- FL_CURSOR_NESW = 81, /**< diagonal arrow. */
2998- FL_CURSOR_NONE =255, /**< invisible. */
2999- // for back compatibility (non MSWindows ones):
3000- FL_CURSOR_N = 70, /**< for back compatibility. */
3001- FL_CURSOR_NE = 69, /**< for back compatibility. */
3002- FL_CURSOR_E = 49, /**< for back compatibility. */
3003- FL_CURSOR_SE = 8, /**< for back compatibility. */
3004- FL_CURSOR_S = 9, /**< for back compatibility. */
3005- FL_CURSOR_SW = 7, /**< for back compatibility. */
3006- FL_CURSOR_W = 36, /**< for back compatibility. */
3007- FL_CURSOR_NW = 68 /**< for back compatibility. */
3008+ FL_CURSOR_DEFAULT = 0, /**< the default cursor, usually an arrow. */
3009+ FL_CURSOR_ARROW = 1, /**< an arrow pointer. */
3010+ FL_CURSOR_CROSS = 2, /**< crosshair. */
3011+ FL_CURSOR_WAIT = 3, /**< busy indicator (e.g. hourglass). */
3012+ FL_CURSOR_INSERT = 4, /**< I-beam. */
3013+ FL_CURSOR_HAND = 5, /**< pointing hand. */
3014+ FL_CURSOR_HELP = 6, /**< question mark pointer. */
3015+ FL_CURSOR_MOVE = 7, /**< 4-pointed arrow or hand. */
3016+
3017+ /* Resize indicators */
3018+ FL_CURSOR_NS = 101, /**< up/down resize. */
3019+ FL_CURSOR_WE = 102, /**< left/right resize. */
3020+ FL_CURSOR_NWSE = 103, /**< diagonal resize. */
3021+ FL_CURSOR_NESW = 104, /**< diagonal resize. */
3022+ FL_CURSOR_NE = 110, /**< upwards, right resize. */
3023+ FL_CURSOR_N = 111, /**< upwards resize. */
3024+ FL_CURSOR_NW = 112, /**< upwards, left resize. */
3025+ FL_CURSOR_E = 113, /**< leftwards resize. */
3026+ FL_CURSOR_W = 114, /**< rightwards resize. */
3027+ FL_CURSOR_SE = 115, /**< downwards, right resize. */
3028+ FL_CURSOR_S = 116, /**< downwards resize. */
3029+ FL_CURSOR_SW = 117, /**< downwards, left resize. */
3030+
3031+ FL_CURSOR_NONE = 255, /**< invisible. */
3032 };
3033 /*@}*/ // group: Cursors
3034
3035diff -up fltk-1.3.x-r8772/FL/fl_draw.H.cursor fltk-1.3.x-r8772/FL/fl_draw.H
3036--- fltk-1.3.x-r8772/FL/fl_draw.H.cursor 2011-06-02 10:06:09.000000000 +0200
3037+++ fltk-1.3.x-r8772/FL/fl_draw.H 2011-06-08 18:23:14.320144432 +0200
3038@@ -757,7 +757,8 @@ FL_EXPORT const char* fl_shortcut_label(
3039 FL_EXPORT unsigned int fl_old_shortcut(const char* s);
3040 FL_EXPORT void fl_overlay_rect(int x,int y,int w,int h);
3041 FL_EXPORT void fl_overlay_clear();
3042-FL_EXPORT void fl_cursor(Fl_Cursor, Fl_Color fg=FL_BLACK, Fl_Color bg=FL_WHITE);
3043+FL_EXPORT void fl_cursor(Fl_Cursor);
3044+FL_EXPORT void fl_cursor(Fl_Cursor, Fl_Color fg, Fl_Color bg=FL_WHITE);
3045 FL_EXPORT const char* fl_expand_text(const char* from, char* buf, int maxbuf,
3046 double maxw, int& n, double &width,
3047 int wrap, int draw_symbols = 0);
3048diff -up fltk-1.3.x-r8772/FL/Fl_Window.H.cursor fltk-1.3.x-r8772/FL/Fl_Window.H
3049--- fltk-1.3.x-r8772/FL/Fl_Window.H.cursor 2011-06-08 18:23:14.287141337 +0200
3050+++ fltk-1.3.x-r8772/FL/Fl_Window.H 2011-06-08 18:23:50.721557098 +0200
3051@@ -37,6 +37,7 @@
3052 #define FL_DOUBLE_WINDOW 0xF1 ///< double window type id
3053
3054 class Fl_X;
3055+class Fl_RGB_Image;
3056
3057 /**
3058 This widget produces an actual window. This can either be a main
3059@@ -72,7 +73,6 @@ class FL_EXPORT Fl_Window : public Fl_Gr
3060 int no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h;
3061 // cursor stuff
3062 Fl_Cursor cursor_default;
3063- Fl_Color cursor_fg, cursor_bg;
3064 void size_range_();
3065 void _Fl_Window(); // constructor innards
3066
3067@@ -447,14 +447,17 @@ public:
3068 is different.
3069
3070 The type Fl_Cursor is an enumeration defined in <FL/Enumerations.H>.
3071- (Under X you can get any XC_cursor value by passing
3072- Fl_Cursor((XC_foo/2)+1)). The colors only work on X, they are
3073- not implemented on WIN32.
3074
3075- For back compatibility only.
3076+ \see cursor(const Fl_RGB_Image*, int, int), default_cursor()
3077 */
3078- void cursor(Fl_Cursor, Fl_Color=FL_BLACK, Fl_Color=FL_WHITE); // platform dependent
3079- void default_cursor(Fl_Cursor, Fl_Color=FL_BLACK, Fl_Color=FL_WHITE);
3080+ void cursor(Fl_Cursor);
3081+ void cursor(const Fl_RGB_Image*, int, int);
3082+ void default_cursor(Fl_Cursor);
3083+
3084+ /* for legacy compatibility */
3085+ void cursor(Fl_Cursor c, Fl_Color, Fl_Color=FL_WHITE) { cursor(c); };
3086+ void default_cursor(Fl_Cursor c, Fl_Color, Fl_Color=FL_WHITE) { default_cursor(c); };
3087+
3088 static void default_callback(Fl_Window*, void* v);
3089
3090 /** Returns the window width including any frame added by the window manager.
3091diff -up fltk-1.3.x-r8772/FL/mac.H.cursor fltk-1.3.x-r8772/FL/mac.H
3092--- fltk-1.3.x-r8772/FL/mac.H.cursor 2011-05-12 13:50:43.000000000 +0200
3093+++ fltk-1.3.x-r8772/FL/mac.H 2011-06-08 18:23:14.330145367 +0200
3094@@ -141,7 +141,8 @@ public:
3095 void collapse(void);
3096 WindowRef window_ref(void);
3097 void set_key_window(void);
3098- void set_cursor(Fl_Cursor);
3099+ int set_cursor(Fl_Cursor);
3100+ int set_cursor(const Fl_RGB_Image*, int, int);
3101 static CGImageRef CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h);
3102 static unsigned char *bitmap_from_window_rect(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel);
3103 static Fl_Region intersect_region_and_rect(Fl_Region current, int x,int y,int w, int h);
3104diff -up fltk-1.3.x-r8772/FL/win32.H.cursor fltk-1.3.x-r8772/FL/win32.H
3105--- fltk-1.3.x-r8772/FL/win32.H.cursor 2011-05-23 20:32:47.000000000 +0200
3106+++ fltk-1.3.x-r8772/FL/win32.H 2011-06-08 18:23:14.331145463 +0200
3107@@ -92,6 +92,8 @@ public:
3108 void flush() {w->flush();}
3109 void set_minmax(LPMINMAXINFO minmax);
3110 void mapraise();
3111+ int set_cursor(Fl_Cursor);
3112+ int set_cursor(const Fl_RGB_Image*, int, int);
3113 static Fl_X* make(Fl_Window*);
3114 };
3115 extern FL_EXPORT HCURSOR fl_default_cursor;
3116diff -up fltk-1.3.x-r8772/FL/x.H.cursor fltk-1.3.x-r8772/FL/x.H
3117--- fltk-1.3.x-r8772/FL/x.H.cursor 2011-05-21 12:05:19.000000000 +0200
3118+++ fltk-1.3.x-r8772/FL/x.H 2011-06-08 18:23:14.331145463 +0200
3119@@ -163,6 +163,8 @@ public:
3120 static Fl_X* i(const Fl_Window* wi) {return wi->i;}
3121 void setwindow(Fl_Window* wi) {w=wi; wi->i=this;}
3122 void sendxjunk();
3123+ int set_cursor(Fl_Cursor);
3124+ int set_cursor(const Fl_RGB_Image*, int, int);
3125 static void make_xid(Fl_Window*,XVisualInfo* =fl_visual, Colormap=fl_colormap);
3126 static Fl_X* set_xid(Fl_Window*, Window);
3127 // kludges to get around protection:
3128diff -up fltk-1.3.x-r8772/src/Fl_cocoa.mm.cursor fltk-1.3.x-r8772/src/Fl_cocoa.mm
3129--- fltk-1.3.x-r8772/src/Fl_cocoa.mm.cursor 2011-06-08 18:23:14.290141618 +0200
3130+++ fltk-1.3.x-r8772/src/Fl_cocoa.mm 2011-06-08 18:23:14.334145743 +0200
3131@@ -108,7 +108,6 @@ int fl_screen;
3132 CGContextRef fl_gc = 0;
3133 void *fl_system_menu; // this is really a NSMenu*
3134 Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
3135-void *fl_default_cursor; // this is really a NSCursor*
3136 void *fl_capture = 0; // (NSWindow*) we need this to compensate for a missing(?) mouse capture
3137 bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state
3138 //int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
3139@@ -1355,8 +1354,6 @@ void fl_open_display() {
3140 dequeue:YES];
3141 while (ign_event);
3142
3143- fl_default_cursor = [NSCursor arrowCursor];
3144-
3145 // bring the application into foreground without a 'CARB' resource
3146 Boolean same_psn;
3147 ProcessSerialNumber cur_psn, front_psn;
3148@@ -1656,6 +1653,7 @@ static void q_set_window_title(NSWindow
3149 - (void)drawRect:(NSRect)rect;
3150 - (BOOL)acceptsFirstResponder;
3151 - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
3152+- (void)resetCursorRects;
3153 - (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
3154 - (void)mouseUp:(NSEvent *)theEvent;
3155 - (void)rightMouseUp:(NSEvent *)theEvent;
3156@@ -1713,6 +1711,16 @@ static void q_set_window_title(NSWindow
3157 Fl_Window *first = Fl::first_window();
3158 return (first == w || !first->modal());
3159 }
3160+- (void)resetCursorRects {
3161+ Fl_Window *w = [(FLWindow*)[self window] getFl_Window];
3162+ Fl_X *i = Fl_X::i(w);
3163+ // We have to have at least one cursor rect for invalidateCursorRectsForView
3164+ // to work, hence the "else" clause.
3165+ if (i->cursor)
3166+ [self addCursorRect:[self visibleRect] cursor:(NSCursor*)i->cursor];
3167+ else
3168+ [self addCursorRect:[self visibleRect] cursor:[NSCursor arrowCursor]];
3169+}
3170 - (void)mouseUp:(NSEvent *)theEvent {
3171 cocoaMouseHandler(theEvent);
3172 }
3173@@ -2130,7 +2138,7 @@ void Fl_X::make(Fl_Window* w)
3174 x->other_xid = 0;
3175 x->region = 0;
3176 x->subRegion = 0;
3177- x->cursor = fl_default_cursor;
3178+ x->cursor = NULL;
3179 x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz
3180 Fl_Window *win = w->window();
3181 Fl_X *xo = Fl_X::i(win);
3182@@ -2232,7 +2240,7 @@ void Fl_X::make(Fl_Window* w)
3183 x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows
3184 x->region = 0;
3185 x->subRegion = 0;
3186- x->cursor = fl_default_cursor;
3187+ x->cursor = NULL;
3188 x->xidChildren = 0;
3189 x->xidNext = 0;
3190 x->gc = 0;
3191@@ -2838,6 +2846,10 @@ void Fl_X::destroy() {
3192 [[(NSWindow *)xid contentView] release];
3193 [(NSWindow *)xid close];
3194 }
3195+ if (cursor) {
3196+ [(NSCursor*)cursor release];
3197+ cursor = NULL;
3198+ }
3199 }
3200
3201 void Fl_X::map() {
3202@@ -2953,68 +2965,106 @@ static NSImage *CGBitmapContextToNSImage
3203 return [image autorelease];
3204 }
3205
3206-static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() )
3207+int Fl_X::set_cursor(Fl_Cursor c)
3208 {
3209- if (cursor == nil) {
3210- CGContextRef c = f();
3211- NSImage *image = CGBitmapContextToNSImage(c);
3212- fl_delete_offscreen( (Fl_Offscreen)c );
3213- NSPoint pt = {[image size].width/2, [image size].height/2};
3214- cursor = [[NSCursor alloc] initWithImage:image hotSpot:pt];
3215+ if (cursor) {
3216+ [(NSCursor*)cursor release];
3217+ cursor = NULL;
3218 }
3219- return cursor;
3220-}
3221
3222-void Fl_X::set_cursor(Fl_Cursor c)
3223-{
3224- NSCursor *icrsr;
3225 switch (c) {
3226- case FL_CURSOR_CROSS: icrsr = [NSCursor crosshairCursor]; break;
3227- case FL_CURSOR_WAIT:
3228- static NSCursor *watch = nil;
3229- watch = PrepareCursor(watch, &Fl_X::watch_cursor_image);
3230- icrsr = watch;
3231- break;
3232- case FL_CURSOR_INSERT: icrsr = [NSCursor IBeamCursor]; break;
3233- case FL_CURSOR_N: icrsr = [NSCursor resizeUpCursor]; break;
3234- case FL_CURSOR_S: icrsr = [NSCursor resizeDownCursor]; break;
3235- case FL_CURSOR_NS: icrsr = [NSCursor resizeUpDownCursor]; break;
3236- case FL_CURSOR_HELP:
3237- static NSCursor *help = nil;
3238- help = PrepareCursor(help, &Fl_X::help_cursor_image);
3239- icrsr = help;
3240- break;
3241- case FL_CURSOR_HAND: icrsr = [NSCursor pointingHandCursor]; break;
3242- case FL_CURSOR_MOVE: icrsr = [NSCursor openHandCursor]; break;
3243- case FL_CURSOR_NE:
3244- case FL_CURSOR_SW:
3245- case FL_CURSOR_NESW:
3246- static NSCursor *nesw = nil;
3247- nesw = PrepareCursor(nesw, &Fl_X::nesw_cursor_image);
3248- icrsr = nesw;
3249- break;
3250- case FL_CURSOR_E: icrsr = [NSCursor resizeRightCursor]; break;
3251- case FL_CURSOR_W: icrsr = [NSCursor resizeLeftCursor]; break;
3252- case FL_CURSOR_WE: icrsr = [NSCursor resizeLeftRightCursor]; break;
3253- case FL_CURSOR_SE:
3254- case FL_CURSOR_NW:
3255- case FL_CURSOR_NWSE:
3256- static NSCursor *nwse = nil;
3257- nwse = PrepareCursor(nwse, &Fl_X::nwse_cursor_image);
3258- icrsr = nwse;
3259- break;
3260- case FL_CURSOR_NONE:
3261- static NSCursor *none = nil;
3262- none = PrepareCursor(none, &Fl_X::none_cursor_image);
3263- icrsr = none;
3264- break;
3265- case FL_CURSOR_ARROW:
3266- case FL_CURSOR_DEFAULT:
3267- default: icrsr = [NSCursor arrowCursor];
3268- break;
3269+ case FL_CURSOR_ARROW: cursor = [NSCursor arrowCursor]; break;
3270+ case FL_CURSOR_CROSS: cursor = [NSCursor crosshairCursor]; break;
3271+ case FL_CURSOR_INSERT: cursor = [NSCursor IBeamCursor]; break;
3272+ case FL_CURSOR_HAND: cursor = [NSCursor pointingHandCursor]; break;
3273+ case FL_CURSOR_MOVE: cursor = [NSCursor openHandCursor]; break;
3274+ case FL_CURSOR_NS: cursor = [NSCursor resizeUpDownCursor]; break;
3275+ case FL_CURSOR_WE: cursor = [NSCursor resizeLeftRightCursor]; break;
3276+ case FL_CURSOR_N: cursor = [NSCursor resizeUpCursor]; break;
3277+ case FL_CURSOR_E: cursor = [NSCursor resizeRightCursor]; break;
3278+ case FL_CURSOR_W: cursor = [NSCursor resizeLeftCursor]; break;
3279+ case FL_CURSOR_S: cursor = [NSCursor resizeDownCursor]; break;
3280+ default:
3281+ return 0;
3282+ }
3283+
3284+ [(NSCursor*)cursor retain];
3285+
3286+ [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]];
3287+
3288+ return 1;
3289+}
3290+
3291+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
3292+ if (cursor) {
3293+ [(NSCursor*)cursor release];
3294+ cursor = NULL;
3295+ }
3296+
3297+ if ((hotx < 0) || (hotx >= image->w()))
3298+ return 0;
3299+ if ((hoty < 0) || (hoty >= image->h()))
3300+ return 0;
3301+
3302+ // OS X >= 10.6 can create a NSImage from a CGImage, but we need to
3303+ // support older versions, hence this pesky handling.
3304+
3305+ NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc]
3306+ initWithBitmapDataPlanes:NULL
3307+ pixelsWide:image->w()
3308+ pixelsHigh:image->h()
3309+ bitsPerSample:8
3310+ samplesPerPixel:image->d()
3311+ hasAlpha:!(image->d() & 1)
3312+ isPlanar:NO
3313+ colorSpaceName:(image->d()<=2) ? NSDeviceWhiteColorSpace : NSDeviceRGBColorSpace
3314+ bytesPerRow:(image->w() * image->d())
3315+ bitsPerPixel:(image->d()*8)];
3316+
3317+ // Alpha needs to be premultiplied for this format
3318+
3319+ const uchar *i = (const uchar*)*image->data();
3320+ unsigned char *o = [bitmap bitmapData];
3321+ for (int y = 0;y < image->h();y++) {
3322+ if (image->d() & 1) {
3323+ for (int x = 0;x < image->w();x++) {
3324+ unsigned int alpha;
3325+ if (image->d() == 4) {
3326+ alpha = i[3];
3327+ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
3328+ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
3329+ }
3330+
3331+ alpha = i[1];
3332+ *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
3333+ *o++ = alpha;
3334+ i++;
3335+ }
3336+ } else {
3337+ // No alpha, so we can just copy everything directly.
3338+ int len = image->w() * image->d();
3339+ memcpy(o, i, len);
3340+ o += len;
3341+ i += len;
3342+ }
3343+ i += image->ld();
3344 }
3345- [icrsr set];
3346- cursor = icrsr;
3347+
3348+ NSImage *nsimage = [[NSImage alloc]
3349+ initWithSize:NSMakeSize(image->w(), image->h())];
3350+
3351+ [nsimage addRepresentation:bitmap];
3352+
3353+ cursor = [[NSCursor alloc]
3354+ initWithImage:nsimage
3355+ hotSpot:NSMakePoint(hotx, hoty)];
3356+
3357+ [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]];
3358+
3359+ [bitmap release];
3360+ [nsimage release];
3361+
3362+ return 1;
3363 }
3364
3365 @interface FLaboutItemTarget : NSObject
3366diff -up fltk-1.3.x-r8772/src/fl_cursor.cxx.cursor fltk-1.3.x-r8772/src/fl_cursor.cxx
3367--- fltk-1.3.x-r8772/src/fl_cursor.cxx.cursor 2010-12-18 23:31:01.000000000 +0100
3368+++ fltk-1.3.x-r8772/src/fl_cursor.cxx 2011-06-08 18:23:14.335145836 +0200
3369@@ -33,300 +33,155 @@
3370
3371 #include <FL/Fl.H>
3372 #include <FL/Fl_Window.H>
3373+#include <FL/Fl_Pixmap.H>
3374+#include <FL/Fl_RGB_Image.H>
3375 #include <FL/x.H>
3376-#if !defined(WIN32) && !defined(__APPLE__)
3377-# include <X11/cursorfont.h>
3378-#endif
3379 #include <FL/fl_draw.H>
3380
3381+#include "fl_cursor_wait.xpm"
3382+#include "fl_cursor_help.xpm"
3383+#include "fl_cursor_nwse.xpm"
3384+#include "fl_cursor_nesw.xpm"
3385+#include "fl_cursor_none.xpm"
3386+
3387 /**
3388 Sets the cursor for the current window to the specified shape and colors.
3389 The cursors are defined in the <FL/Enumerations.H> header file.
3390 */
3391+void fl_cursor(Fl_Cursor c) {
3392+ if (Fl::first_window()) Fl::first_window()->cursor(c);
3393+}
3394+
3395+/* For back compatibility only. */
3396 void fl_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
3397- if (Fl::first_window()) Fl::first_window()->cursor(c,fg,bg);
3398+ fl_cursor(c);
3399 }
3400+
3401+
3402 /**
3403- Sets the default window cursor as well as its color.
3404+ Sets the default window cursor. This is the cursor that will be used
3405+ after the mouse pointer leaves a widget with a custom cursor set.
3406
3407- For back compatibility only.
3408+ \see cursor(const Fl_RGB_Image*, int, int), default_cursor()
3409 */
3410-void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
3411-// if (c == FL_CURSOR_DEFAULT) c = FL_CURSOR_ARROW;
3412-
3413+void Fl_Window::default_cursor(Fl_Cursor c) {
3414 cursor_default = c;
3415- cursor_fg = fg;
3416- cursor_bg = bg;
3417+ cursor(c);
3418+}
3419+
3420
3421- cursor(c, fg, bg);
3422+void fallback_cursor(Fl_Window *w, Fl_Cursor c) {
3423+ const char **xpm;
3424+ int hotx, hoty;
3425+
3426+ // The standard arrow is our final fallback, so something is broken
3427+ // if we get called back here with that as an argument.
3428+ if (c == FL_CURSOR_ARROW)
3429+ return;
3430+
3431+ switch (c) {
3432+ case FL_CURSOR_WAIT:
3433+ xpm = (const char**)fl_cursor_wait_xpm;
3434+ hotx = 8;
3435+ hoty = 15;
3436+ break;
3437+ case FL_CURSOR_HELP:
3438+ xpm = (const char**)fl_cursor_help_xpm;
3439+ hotx = 1;
3440+ hoty = 3;
3441+ break;
3442+ case FL_CURSOR_NWSE:
3443+ xpm = (const char**)fl_cursor_nwse_xpm;
3444+ hotx = 7;
3445+ hoty = 7;
3446+ break;
3447+ case FL_CURSOR_NESW:
3448+ xpm = (const char**)fl_cursor_nesw_xpm;
3449+ hotx = 7;
3450+ hoty = 7;
3451+ break;
3452+ case FL_CURSOR_NONE:
3453+ xpm = (const char**)fl_cursor_none_xpm;
3454+ hotx = 0;
3455+ hoty = 0;
3456+ break;
3457+ default:
3458+ w->cursor(FL_CURSOR_ARROW);
3459+ return;
3460+ }
3461+
3462+ Fl_Pixmap pxm(xpm);
3463+ Fl_RGB_Image image(&pxm);
3464+
3465+ w->cursor(&image, hotx, hoty);
3466 }
3467
3468-#ifdef WIN32
3469
3470-# ifndef IDC_HAND
3471-# define IDC_HAND MAKEINTRESOURCE(32649)
3472-# endif // !IDC_HAND
3473+void Fl_Window::cursor(Fl_Cursor c) {
3474+ int ret;
3475
3476-void Fl_Window::cursor(Fl_Cursor c, Fl_Color c1, Fl_Color c2) {
3477- if (!shown()) return;
3478 // the cursor must be set for the top level window, not for subwindows
3479 Fl_Window *w = window(), *toplevel = this;
3480- while (w) { toplevel = w; w = w->window(); }
3481- if (toplevel != this) { toplevel->cursor(c, c1, c2); return; }
3482- // now set the actual cursor
3483- if (c == FL_CURSOR_DEFAULT) {
3484- c = cursor_default;
3485- }
3486- if (c > FL_CURSOR_NESW) {
3487- i->cursor = 0;
3488- } else if (c == FL_CURSOR_DEFAULT) {
3489- i->cursor = fl_default_cursor;
3490- } else {
3491- LPSTR n;
3492- switch (c) {
3493- case FL_CURSOR_ARROW: n = IDC_ARROW; break;
3494- case FL_CURSOR_CROSS: n = IDC_CROSS; break;
3495- case FL_CURSOR_WAIT: n = IDC_WAIT; break;
3496- case FL_CURSOR_INSERT: n = IDC_IBEAM; break;
3497- case FL_CURSOR_HELP: n = IDC_HELP; break;
3498- case FL_CURSOR_HAND: {
3499- OSVERSIONINFO osvi;
3500-
3501- // Get the OS version: Windows 98 and 2000 have a standard
3502- // hand cursor.
3503- memset(&osvi, 0, sizeof(OSVERSIONINFO));
3504- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
3505- GetVersionEx(&osvi);
3506-
3507- if (osvi.dwMajorVersion > 4 ||
3508- (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion > 0 &&
3509- osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) n = IDC_HAND;
3510- else n = IDC_UPARROW;
3511- } break;
3512- case FL_CURSOR_MOVE: n = IDC_SIZEALL; break;
3513- case FL_CURSOR_N:
3514- case FL_CURSOR_S:
3515- case FL_CURSOR_NS: n = IDC_SIZENS; break;
3516- case FL_CURSOR_NE:
3517- case FL_CURSOR_SW:
3518- case FL_CURSOR_NESW: n = IDC_SIZENESW; break;
3519- case FL_CURSOR_E:
3520- case FL_CURSOR_W:
3521- case FL_CURSOR_WE: n = IDC_SIZEWE; break;
3522- case FL_CURSOR_SE:
3523- case FL_CURSOR_NW:
3524- case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break;
3525- default: n = IDC_NO; break;
3526- }
3527- i->cursor = LoadCursor(NULL, n);
3528+
3529+ while (w) {
3530+ toplevel = w;
3531+ w = w->window();
3532 }
3533- SetCursor(i->cursor);
3534-}
3535
3536-#elif defined(__APPLE__)
3537+ if (toplevel != this) {
3538+ toplevel->cursor(c);
3539+ return;
3540+ }
3541
3542-#ifdef __BIG_ENDIAN__
3543-# define E(x) x
3544-#elif defined __LITTLE_ENDIAN__
3545-// Don't worry. This will be resolved at compile time
3546-# define E(x) (x>>8)|((x<<8)&0xff00)
3547-#else
3548-# error "Either __LITTLE_ENDIAN__ or __BIG_ENDIAN__ must be defined"
3549-#endif
3550-
3551-extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
3552-
3553-
3554-CGContextRef Fl_X::help_cursor_image(void)
3555-{
3556- int w = 20, h = 20;
3557- Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
3558- fl_begin_offscreen(off);
3559- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
3560- fl_rectf(0,0,w,h);
3561- fl_color(FL_BLACK);
3562- fl_font(FL_COURIER_BOLD, 20);
3563- fl_draw("?", 1, h-1);
3564- fl_end_offscreen();
3565- return (CGContextRef)off;
3566-}
3567+ if (c == FL_CURSOR_DEFAULT)
3568+ c = cursor_default;
3569
3570-CGContextRef Fl_X::none_cursor_image(void)
3571-{
3572- int w = 20, h = 20;
3573- Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
3574- fl_begin_offscreen(off);
3575- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
3576- fl_rectf(0,0,w,h);
3577- fl_end_offscreen();
3578- return (CGContextRef)off;
3579-}
3580+ if (!i)
3581+ return;
3582
3583-CGContextRef Fl_X::watch_cursor_image(void)
3584-{
3585- int w, h, r = 5;
3586- w = 2*r+6;
3587- h = 4*r;
3588- Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
3589- fl_begin_offscreen(off);
3590- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
3591- fl_rectf(0,0,w,h);
3592- CGContextTranslateCTM( (CGContextRef)off, w/2, h/2);
3593- fl_color(FL_WHITE);
3594- fl_circle(0, 0, r+1);
3595- fl_color(FL_BLACK);
3596- fl_rectf(int(-r*0.7), int(-r*1.7), int(1.4*r), int(3.4*r));
3597- fl_rectf(r-1, -1, 3, 3);
3598- fl_color(FL_WHITE);
3599- fl_pie(-r, -r, 2*r, 2*r, 0, 360);
3600- fl_color(FL_BLACK);
3601- fl_circle(0,0,r);
3602- fl_xyline(0, 0, int(-r*.7));
3603- fl_xyline(0, 0, 0, int(-r*.7));
3604- fl_end_offscreen();
3605- return (CGContextRef)off;
3606-}
3607+ ret = i->set_cursor(c);
3608+ if (ret)
3609+ return;
3610
3611-CGContextRef Fl_X::nesw_cursor_image(void)
3612-{
3613- int c = 7, r = 2*c;
3614- int w = r, h = r;
3615- Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
3616- fl_begin_offscreen(off);
3617- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
3618- fl_rectf(0,0,w,h);
3619- CGContextTranslateCTM( (CGContextRef)off, 0, h);
3620- CGContextScaleCTM( (CGContextRef)off, 1, -1);
3621- fl_color(FL_BLACK);
3622- fl_polygon(0, 0, c, 0, 0, c);
3623- fl_polygon(r, r, r, r-c, r-c, r);
3624- fl_line_style(FL_SOLID, 2, 0);
3625- fl_line(0,1, r,r+1);
3626- fl_line_style(FL_SOLID, 0, 0);
3627- fl_end_offscreen();
3628- return (CGContextRef)off;
3629+ fallback_cursor(this, c);
3630 }
3631
3632-CGContextRef Fl_X::nwse_cursor_image(void)
3633-{
3634- int c = 7, r = 2*c;
3635- int w = r, h = r;
3636- Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
3637- fl_begin_offscreen(off);
3638- CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
3639- fl_rectf(0,0,w,h);
3640- CGContextTranslateCTM( (CGContextRef)off, 0, h);
3641- CGContextScaleCTM( (CGContextRef)off, 1, -1);
3642- fl_color(FL_BLACK);
3643- fl_polygon(r-1, 0, r-1, c, r-1-c, 0);
3644- fl_polygon(-1, r, c-1, r, -1, r-c);
3645- fl_line_style(FL_SOLID, 2, 0);
3646- fl_line(r-1,1, -1,r+1);
3647- fl_line_style(FL_SOLID, 0, 0);
3648- fl_end_offscreen();
3649- return (CGContextRef)off;
3650-}
3651+/**
3652+ Changes the cursor for this window. This always calls the system, if
3653+ you are changing the cursor a lot you may want to keep track of how
3654+ you set it in a static variable and call this only if the new cursor
3655+ is different.
3656
3657-void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) {
3658- if (c == FL_CURSOR_DEFAULT) {
3659- c = cursor_default;
3660- }
3661- if (i) i->set_cursor(c);
3662-}
3663+ The default cursor will be used if the provided image cannot be used
3664+ as a cursor.
3665
3666-#else
3667+ \see cursor(Fl_Cursor), default_cursor()
3668+*/
3669+void Fl_Window::cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
3670+ int ret;
3671
3672-// I like the MSWindows resize cursors, so I duplicate them here:
3673+ // the cursor must be set for the top level window, not for subwindows
3674+ Fl_Window *w = window(), *toplevel = this;
3675
3676-#define CURSORSIZE 16
3677-#define HOTXY 7
3678-static struct TableEntry {
3679- uchar bits[CURSORSIZE*CURSORSIZE/8];
3680- uchar mask[CURSORSIZE*CURSORSIZE/8];
3681- Cursor cursor;
3682-} table[] = {
3683- {{ // FL_CURSOR_NS
3684- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01,
3685- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
3686- 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00},
3687- {
3688- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xc0, 0x03,
3689- 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xf0, 0x0f,
3690- 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}},
3691- {{ // FL_CURSOR_EW
3692- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10,
3693- 0x0c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0x0c, 0x30, 0x08, 0x10, 0x00, 0x00,
3694- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
3695- {
3696- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1c, 0x38,
3697- 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18,
3698- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
3699- {{ // FL_CURSOR_NWSE
3700- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x38, 0x00, 0x78, 0x00,
3701- 0xe8, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1c,
3702- 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
3703- {
3704- 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0xfc, 0x00,
3705- 0xfc, 0x01, 0xec, 0x03, 0xc0, 0x37, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x3e,
3706- 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00}},
3707- {{ // FL_CURSOR_NESW
3708- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1e,
3709- 0x00, 0x17, 0x80, 0x03, 0xc0, 0x01, 0xe8, 0x00, 0x78, 0x00, 0x38, 0x00,
3710- 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
3711- {
3712- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3f,
3713- 0x80, 0x3f, 0xc0, 0x37, 0xec, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0x7c, 0x00,
3714- 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}},
3715- {{0}, {0}} // FL_CURSOR_NONE & unknown
3716-};
3717-
3718-void Fl_Window::cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
3719- if (!shown()) return;
3720- Cursor xc;
3721- int deleteit = 0;
3722- if (c == FL_CURSOR_DEFAULT) {
3723- c = cursor_default;
3724- fg = cursor_fg;
3725- bg = cursor_bg;
3726+ while (w) {
3727+ toplevel = w;
3728+ w = w->window();
3729 }
3730
3731- if (!c) {
3732- xc = None;
3733- } else {
3734- if (c >= FL_CURSOR_NS) {
3735- TableEntry *q = (c > FL_CURSOR_NESW) ? table+4 : table+(c-FL_CURSOR_NS);
3736- if (!(q->cursor)) {
3737- XColor dummy = { 0 };
3738- Pixmap p = XCreateBitmapFromData(fl_display,
3739- RootWindow(fl_display, fl_screen), (const char*)(q->bits),
3740- CURSORSIZE, CURSORSIZE);
3741- Pixmap m = XCreateBitmapFromData(fl_display,
3742- RootWindow(fl_display, fl_screen), (const char*)(q->mask),
3743- CURSORSIZE, CURSORSIZE);
3744- q->cursor = XCreatePixmapCursor(fl_display, p,m,&dummy, &dummy,
3745- HOTXY, HOTXY);
3746- XFreePixmap(fl_display, m);
3747- XFreePixmap(fl_display, p);
3748- }
3749- xc = q->cursor;
3750- } else {
3751- xc = XCreateFontCursor(fl_display, (c-1)*2);
3752- deleteit = 1;
3753- }
3754- XColor fgc;
3755- uchar r,g,b;
3756- Fl::get_color(fg,r,g,b);
3757- fgc.red = r<<8; fgc.green = g<<8; fgc.blue = b<<8;
3758- XColor bgc;
3759- Fl::get_color(bg,r,g,b);
3760- bgc.red = r<<8; bgc.green = g<<8; bgc.blue = b<<8;
3761- XRecolorCursor(fl_display, xc, &fgc, &bgc);
3762+ if (toplevel != this) {
3763+ toplevel->cursor(image, hotx, hoty);
3764+ return;
3765 }
3766- XDefineCursor(fl_display, fl_xid(this), xc);
3767- if (deleteit) XFreeCursor(fl_display, xc);
3768-}
3769
3770-#endif
3771+ if (!i)
3772+ return;
3773+
3774+ ret = i->set_cursor(image, hotx, hoty);
3775+ if (ret)
3776+ return;
3777+
3778+ cursor(FL_CURSOR_DEFAULT);
3779+}
3780
3781 //
3782 // End of "$Id: fl_cursor.cxx 8055 2010-12-18 22:31:01Z manolo $".
3783diff -up fltk-1.3.x-r8772/src/fl_cursor_help.xpm.cursor fltk-1.3.x-r8772/src/fl_cursor_help.xpm
3784--- fltk-1.3.x-r8772/src/fl_cursor_help.xpm.cursor 2011-06-08 18:23:14.336145931 +0200
3785+++ fltk-1.3.x-r8772/src/fl_cursor_help.xpm 2011-06-08 18:23:14.336145931 +0200
3786@@ -0,0 +1,95 @@
3787+/* XPM */
3788+static const char * fl_cursor_help_xpm[] = {
3789+"16 27 65 1",
3790+" c None",
3791+". c #FFFFFF",
3792+"+ c #E2E2E2",
3793+"@ c #1C1C1C",
3794+"# c #E7E7E7",
3795+"$ c #000000",
3796+"% c #212121",
3797+"& c #EAEAEA",
3798+"* c #262626",
3799+"= c #EDEDED",
3800+"- c #2C2C2C",
3801+"; c #F0F0F0",
3802+"> c #333333",
3803+", c #F1F1F1",
3804+"' c #393939",
3805+") c #F3F3F3",
3806+"! c #404040",
3807+"~ c #484848",
3808+"{ c #F4F4F4",
3809+"] c #050505",
3810+"^ c #202020",
3811+"/ c #707070",
3812+"( c #F5F5F5",
3813+"_ c #040404",
3814+": c #E1E1E1",
3815+"< c #EEEEEE",
3816+"[ c #EFEFEF",
3817+"} c #FEFEFE",
3818+"| c #3D3D3D",
3819+"1 c #7E7E7E",
3820+"2 c #696969",
3821+"3 c #414141",
3822+"4 c #131313",
3823+"5 c #080808",
3824+"6 c #454545",
3825+"7 c #F2F2F2",
3826+"8 c #878787",
3827+"9 c #7D7D7D",
3828+"0 c #101010",
3829+"a c #111111",
3830+"b c #FDFDFD",
3831+"c c #8A8A8A",
3832+"d c #E6E6E6",
3833+"e c #7B7B7B",
3834+"f c #4C4C4C",
3835+"g c #5C5C5C",
3836+"h c #9F9F9F",
3837+"i c #F9F9F9",
3838+"j c #F7F7F7",
3839+"k c #B1B1B1",
3840+"l c #2E2E2E",
3841+"m c #767676",
3842+"n c #DCDCDC",
3843+"o c #DEDEDE",
3844+"p c #C7C7C7",
3845+"q c #1B1B1B",
3846+"r c #6B6B6B",
3847+"s c #575757",
3848+"t c #797979",
3849+"u c #020202",
3850+"v c #010101",
3851+"w c #FBFBFB",
3852+"x c #D7D7D7",
3853+"y c #D8D8D8",
3854+"z c #060606",
3855+" ",
3856+". ",
3857+".+ ",
3858+".@# ",
3859+".$%& ",
3860+".$$*= ",
3861+".$$$-; ",
3862+".$$$$>, ",
3863+".$$$$$') ",
3864+".$$$$$$!) ",
3865+".$$$$$$$~{ ",
3866+".$$$$]^^^/( ",
3867+".$$$$_:(<<[} ",
3868+".$$|1$2< ",
3869+".$3,(45[ ",
3870+".67 78$9, ",
3871+".7 {0a( .... ",
3872+"b ,c5[defgh, ",
3873+" )ijk_la$m.",
3874+" no.p$q.",
3875+" .r$s.",
3876+" .t$-= ",
3877+" 7uv+ ",
3878+" wxy. ",
3879+" :$z. ",
3880+" :$z. ",
3881+" .... "};
3882diff -up fltk-1.3.x-r8772/src/fl_cursor_nesw.xpm.cursor fltk-1.3.x-r8772/src/fl_cursor_nesw.xpm
3883--- fltk-1.3.x-r8772/src/fl_cursor_nesw.xpm.cursor 2011-06-08 18:23:14.336145931 +0200
3884+++ fltk-1.3.x-r8772/src/fl_cursor_nesw.xpm 2011-06-08 18:23:14.336145931 +0200
3885@@ -0,0 +1,46 @@
3886+/* XPM */
3887+static const char * fl_cursor_nesw_xpm[] = {
3888+"15 15 28 1",
3889+" c None",
3890+". c #FFFFFF",
3891+"+ c #767676",
3892+"@ c #000000",
3893+"# c #4E4E4E",
3894+"$ c #0C0C0C",
3895+"% c #494949",
3896+"& c #4D4D4D",
3897+"* c #1B1B1B",
3898+"= c #515151",
3899+"- c #646464",
3900+"; c #363636",
3901+"> c #6A6A6A",
3902+", c #545454",
3903+"' c #585858",
3904+") c #242424",
3905+"! c #797979",
3906+"~ c #2E2E2E",
3907+"{ c #444444",
3908+"] c #3B3B3B",
3909+"^ c #0A0A0A",
3910+"/ c #595959",
3911+"( c #F7F7F7",
3912+"_ c #080808",
3913+": c #6B6B6B",
3914+"< c #FDFDFD",
3915+"[ c #FCFCFC",
3916+"} c #FEFEFE",
3917+" ..........",
3918+" .+@@@@@@.",
3919+" .#@@@@@.",
3920+" .$@@@@.",
3921+" .%@@@@@.",
3922+". .&@@@*@@.",
3923+".. .=@@@-.;@.",
3924+".>. .,@@@'. .).",
3925+".@!.'@@@#. ..",
3926+".@@~@@@{. .",
3927+".@@@@@]. ",
3928+".@@@@^. ",
3929+".@@@@@/( ",
3930+".______:( ",
3931+"<[[[[[[[[} "};
3932diff -up fltk-1.3.x-r8772/src/fl_cursor_none.xpm.cursor fltk-1.3.x-r8772/src/fl_cursor_none.xpm
3933--- fltk-1.3.x-r8772/src/fl_cursor_none.xpm.cursor 2011-06-08 18:23:14.337146025 +0200
3934+++ fltk-1.3.x-r8772/src/fl_cursor_none.xpm 2011-06-08 18:23:14.337146025 +0200
3935@@ -0,0 +1,19 @@
3936+/* XPM */
3937+static const char * fl_cursor_none_xpm[] = {
3938+"15 15 1 1",
3939+" c None",
3940+" ",
3941+" ",
3942+" ",
3943+" ",
3944+" ",
3945+" ",
3946+" ",
3947+" ",
3948+" ",
3949+" ",
3950+" ",
3951+" ",
3952+" ",
3953+" ",
3954+" "};
3955diff -up fltk-1.3.x-r8772/src/fl_cursor_nwse.xpm.cursor fltk-1.3.x-r8772/src/fl_cursor_nwse.xpm
3956--- fltk-1.3.x-r8772/src/fl_cursor_nwse.xpm.cursor 2011-06-08 18:23:14.337146025 +0200
3957+++ fltk-1.3.x-r8772/src/fl_cursor_nwse.xpm 2011-06-08 18:23:14.337146025 +0200
3958@@ -0,0 +1,46 @@
3959+/* XPM */
3960+static const char * fl_cursor_nwse_xpm[] = {
3961+"15 15 28 1",
3962+" c None",
3963+". c #FFFFFF",
3964+"+ c #000000",
3965+"@ c #767676",
3966+"# c #4E4E4E",
3967+"$ c #0C0C0C",
3968+"% c #494949",
3969+"& c #1B1B1B",
3970+"* c #4D4D4D",
3971+"= c #363636",
3972+"- c #646464",
3973+"; c #515151",
3974+"> c #242424",
3975+", c #585858",
3976+"' c #545454",
3977+") c #6A6A6A",
3978+"! c #797979",
3979+"~ c #444444",
3980+"{ c #2E2E2E",
3981+"] c #3B3B3B",
3982+"^ c #0A0A0A",
3983+"/ c #F7F7F7",
3984+"( c #595959",
3985+"_ c #6B6B6B",
3986+": c #080808",
3987+"< c #FEFEFE",
3988+"[ c #FCFCFC",
3989+"} c #FDFDFD",
3990+".......... ",
3991+".++++++@. ",
3992+".+++++#. ",
3993+".++++$. ",
3994+".+++++%. ",
3995+".++&+++*. .",
3996+".+=.-+++;. ..",
3997+".>. .,+++'. .).",
3998+".. .#+++,.!+.",
3999+". .~+++{++.",
4000+" .]+++++.",
4001+" .^++++.",
4002+" /(+++++.",
4003+" /_::::::.",
4004+" <[[[[[[[[}"};
4005diff -up fltk-1.3.x-r8772/src/fl_cursor_wait.xpm.cursor fltk-1.3.x-r8772/src/fl_cursor_wait.xpm
4006--- fltk-1.3.x-r8772/src/fl_cursor_wait.xpm.cursor 2011-06-08 18:23:14.338146118 +0200
4007+++ fltk-1.3.x-r8772/src/fl_cursor_wait.xpm 2011-06-08 18:23:14.338146118 +0200
4008@@ -0,0 +1,72 @@
4009+/* XPM */
4010+static const char * fl_cursor_wait_xpm[] = {
4011+"17 32 37 1",
4012+" c None",
4013+". c #FFFFFF",
4014+"+ c #2E2E2E",
4015+"@ c #202020",
4016+"# c #F1F1F1",
4017+"$ c #2D2D2D",
4018+"% c #000000",
4019+"& c #EDEDED",
4020+"* c #585858",
4021+"= c #575757",
4022+"- c #FBFBFB",
4023+"; c #848484",
4024+"> c #B8B8B8",
4025+", c #E5E5E5",
4026+"' c #F7F7F7",
4027+") c #181818",
4028+"! c #F0F0F0",
4029+"~ c #616161",
4030+"{ c #B7B7B7",
4031+"] c #F5F5F5",
4032+"^ c #050505",
4033+"/ c #D4D4D4",
4034+"( c #EEEEEE",
4035+"_ c #595959",
4036+": c #7B7B7B",
4037+"< c #E9E9E9",
4038+"[ c #131313",
4039+"} c #E3E3E3",
4040+"| c #767676",
4041+"1 c #505050",
4042+"2 c #F3F3F3",
4043+"3 c #2A2A2A",
4044+"4 c #070707",
4045+"5 c #343434",
4046+"6 c #939393",
4047+"7 c #191919",
4048+"8 c #6A6A6A",
4049+".................",
4050+".+@@@@@@@@@@@@@+.",
4051+".................",
4052+" #$%%%%%%%%%%%$# ",
4053+" &*%%%%%%%%%%%=& ",
4054+" -;%%%%%%%%%%%;- ",
4055+" >%%%%%%%%%%%> ",
4056+" ,%%%%%%%%%%%, ",
4057+" ')%%%%%%%%%)' ",
4058+" !~%%%%%%%%%~! ",
4059+" {%%%%%%%%%{ ",
4060+" ]^/...../^] ",
4061+" (_:.....:_( ",
4062+" <[}...}[< ",
4063+" !|1...1|! ",
4064+" 2[3.3[2 ",
4065+" 2[%.%[2 ",
4066+" !|%%.%%|! ",
4067+" <4%%.%%4< ",
4068+" (_%%%.%%%_( ",
4069+" ]^%%%.%%%^] ",
4070+" {%%%%.%%%%{ ",
4071+" !~%%%%.%%%%~! ",
4072+" ')%%%%.%%%%)' ",
4073+" ,%%56{.{65%%, ",
4074+" >%*.......*%> ",
4075+" -;7&.......&7;- ",
4076+" &*8.........8=& ",
4077+" #$%%%%%%%%%%%$# ",
4078+".................",
4079+".+@@@@@@@@@@@@@+.",
4080+"................."};
4081diff -up fltk-1.3.x-r8772/src/Fl_win32.cxx.cursor fltk-1.3.x-r8772/src/Fl_win32.cxx
4082--- fltk-1.3.x-r8772/src/Fl_win32.cxx.cursor 2011-06-08 18:23:14.292141805 +0200
4083+++ fltk-1.3.x-r8772/src/Fl_win32.cxx 2011-06-08 18:23:14.339146212 +0200
4084@@ -1635,7 +1635,6 @@ void fl_fix_focus(); // in Fl.cxx
4085
4086 char fl_show_iconic; // hack for Fl_Window::iconic()
4087 // int fl_background_pixel = -1; // color to use for background
4088-HCURSOR fl_default_cursor;
4089 UINT fl_wake_msg = 0;
4090 int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
4091
4092@@ -1683,7 +1682,7 @@ Fl_X* Fl_X::make(Fl_Window* w) {
4093 if (!w->icon())
4094 w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
4095 wcw.hIcon = wcw.hIconSm = (HICON)w->icon();
4096- wcw.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
4097+ wcw.hCursor = LoadCursor(NULL, IDC_ARROW);
4098 //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
4099 //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
4100 wcw.hbrBackground = NULL;
4101@@ -1775,7 +1774,7 @@ Fl_X* Fl_X::make(Fl_Window* w) {
4102 x->setwindow(w);
4103 x->region = 0;
4104 x->private_dc = 0;
4105- x->cursor = fl_default_cursor;
4106+ x->cursor = LoadCursor(NULL, IDC_ARROW);
4107 if (!fl_codepage) fl_get_codepage();
4108
4109 WCHAR *lab = NULL;
4110@@ -2026,6 +2025,129 @@ void Fl_Window::label(const char *name,c
4111 }
4112
4113 ////////////////////////////////////////////////////////////////
4114+
4115+#ifndef IDC_HAND
4116+# define IDC_HAND MAKEINTRESOURCE(32649)
4117+#endif // !IDC_HAND
4118+
4119+int Fl_X::set_cursor(Fl_Cursor c) {
4120+ LPSTR n;
4121+
4122+ if (c == FL_CURSOR_NONE)
4123+ cursor = NULL;
4124+ else {
4125+ switch (c) {
4126+ case FL_CURSOR_ARROW: n = IDC_ARROW; break;
4127+ case FL_CURSOR_CROSS: n = IDC_CROSS; break;
4128+ case FL_CURSOR_WAIT: n = IDC_WAIT; break;
4129+ case FL_CURSOR_INSERT: n = IDC_IBEAM; break;
4130+ case FL_CURSOR_HAND: n = IDC_HAND; break;
4131+ case FL_CURSOR_HELP: n = IDC_HELP; break;
4132+ case FL_CURSOR_MOVE: n = IDC_SIZEALL; break;
4133+ case FL_CURSOR_N:
4134+ case FL_CURSOR_S:
4135+ // FIXME: Should probably have fallbacks for these instead
4136+ case FL_CURSOR_NS: n = IDC_SIZENS; break;
4137+ case FL_CURSOR_NE:
4138+ case FL_CURSOR_SW:
4139+ // FIXME: Dito.
4140+ case FL_CURSOR_NESW: n = IDC_SIZENESW; break;
4141+ case FL_CURSOR_E:
4142+ case FL_CURSOR_W:
4143+ // FIXME: Dito.
4144+ case FL_CURSOR_WE: n = IDC_SIZEWE; break;
4145+ case FL_CURSOR_SE:
4146+ case FL_CURSOR_NW:
4147+ // FIXME: Dito.
4148+ case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break;
4149+ default:
4150+ return 0;
4151+ }
4152+
4153+ cursor = LoadCursor(NULL, n);
4154+ if (cursor == NULL)
4155+ return 0;
4156+ }
4157+
4158+ SetCursor(cursor);
4159+
4160+ return 1;
4161+}
4162+
4163+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
4164+ BITMAPV5HEADER bi;
4165+ HBITMAP bitmap, mask;
4166+ DWORD *bits;
4167+
4168+ if ((hotx < 0) || (hotx >= image->w()))
4169+ return 0;
4170+ if ((hoty < 0) || (hoty >= image->h()))
4171+ return 0;
4172+
4173+ memset(&bi, 0, sizeof(BITMAPV5HEADER));
4174+
4175+ bi.bV5Size = sizeof(BITMAPV5HEADER);
4176+ bi.bV5Width = image->w();
4177+ bi.bV5Height = image->h();
4178+ bi.bV5Planes = 1;
4179+ bi.bV5BitCount = 32;
4180+ bi.bV5Compression = BI_BITFIELDS;
4181+ bi.bV5RedMask = 0x00FF0000;
4182+ bi.bV5GreenMask = 0x0000FF00;
4183+ bi.bV5BlueMask = 0x000000FF;
4184+ bi.bV5AlphaMask = 0xFF000000;
4185+
4186+ HDC hdc;
4187+
4188+ hdc = GetDC(NULL);
4189+ bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
4190+ ReleaseDC(NULL, hdc);
4191+
4192+ const uchar *i = (const uchar*)*image->data();
4193+ for (int y = 0;y < image->h();y++) {
4194+ for (int x = 0;x < image->w();x++) {
4195+ switch (image->d()) {
4196+ case 1:
4197+ *bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
4198+ break;
4199+ case 2:
4200+ *bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
4201+ break;
4202+ case 3:
4203+ *bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
4204+ break;
4205+ case 4:
4206+ *bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
4207+ break;
4208+ }
4209+ i += image->d();
4210+ bits++;
4211+ }
4212+ i += image->ld();
4213+ }
4214+
4215+ // A mask bitmap is still needed even though it isn't used
4216+ mask = CreateBitmap(image->w(),image->h(),1,1,NULL);
4217+
4218+ ICONINFO ii;
4219+
4220+ ii.fIcon = FALSE;
4221+ ii.xHotspot = hotx;
4222+ ii.yHotspot = hoty;
4223+ ii.hbmMask = mask;
4224+ ii.hbmColor = bitmap;
4225+
4226+ cursor = CreateIconIndirect(&ii);
4227+
4228+ DeleteObject(bitmap);
4229+ DeleteObject(mask);
4230+
4231+ SetCursor(cursor);
4232+
4233+ return 1;
4234+}
4235+
4236+////////////////////////////////////////////////////////////////
4237 // Implement the virtual functions for the base Fl_Window class:
4238
4239 // If the box is a filled rectangle, we can make the redisplay *look*
4240diff -up fltk-1.3.x-r8772/src/Fl_Window.cxx.cursor fltk-1.3.x-r8772/src/Fl_Window.cxx
4241--- fltk-1.3.x-r8772/src/Fl_Window.cxx.cursor 2011-06-08 18:23:14.293141899 +0200
4242+++ fltk-1.3.x-r8772/src/Fl_Window.cxx 2011-06-08 18:23:14.340146306 +0200
4243@@ -69,8 +69,6 @@ void Fl_Window::_Fl_Window() {
4244 Fl_Window::Fl_Window(int X,int Y,int W, int H, const char *l)
4245 : Fl_Group(X, Y, W, H, l) {
4246 cursor_default = FL_CURSOR_DEFAULT;
4247- cursor_fg = FL_BLACK;
4248- cursor_bg = FL_WHITE;
4249
4250 _Fl_Window();
4251 set_flag(FORCE_POSITION);
4252@@ -80,8 +78,6 @@ Fl_Window::Fl_Window(int W, int H, const
4253 // fix common user error of a missing end() with current(0):
4254 : Fl_Group((Fl_Group::current(0),0), 0, W, H, l) {
4255 cursor_default = FL_CURSOR_DEFAULT;
4256- cursor_fg = FL_BLACK;
4257- cursor_bg = FL_WHITE;
4258
4259 _Fl_Window();
4260 clear_visible();
4261diff -up fltk-1.3.x-r8772/src/Fl_x.cxx.cursor fltk-1.3.x-r8772/src/Fl_x.cxx
4262--- fltk-1.3.x-r8772/src/Fl_x.cxx.cursor 2011-06-08 18:23:14.296142181 +0200
4263+++ fltk-1.3.x-r8772/src/Fl_x.cxx 2011-06-08 18:27:42.302267800 +0200
4264@@ -52,6 +52,11 @@
4265 # include <X11/Xlocale.h>
4266 # include <X11/Xlib.h>
4267 # include <X11/keysym.h>
4268+# include <X11/cursorfont.h>
4269+
4270+# if HAVE_XCURSOR
4271+# include <X11/Xcursor/Xcursor.h>
4272+# endif
4273
4274 # ifdef HAVE_XFIXES
4275 # include <X11/extensions/Xfixes.h>
4276@@ -2215,6 +2220,94 @@ void Fl_Window::size_range_() {
4277
4278 ////////////////////////////////////////////////////////////////
4279
4280+int Fl_X::set_cursor(Fl_Cursor c) {
4281+ unsigned int shape;
4282+ Cursor xc;
4283+
4284+ switch (c) {
4285+ case FL_CURSOR_ARROW: shape = XC_left_ptr; break;
4286+ case FL_CURSOR_CROSS: shape = XC_tcross; break;
4287+ case FL_CURSOR_WAIT: shape = XC_watch; break;
4288+ case FL_CURSOR_INSERT: shape = XC_xterm; break;
4289+ case FL_CURSOR_HAND: shape = XC_hand2; break;
4290+ case FL_CURSOR_HELP: shape = XC_question_arrow; break;
4291+ case FL_CURSOR_MOVE: shape = XC_fleur; break;
4292+ case FL_CURSOR_NS: shape = XC_sb_v_double_arrow; break;
4293+ case FL_CURSOR_WE: shape = XC_sb_h_double_arrow; break;
4294+ case FL_CURSOR_NE: shape = XC_top_right_corner; break;
4295+ case FL_CURSOR_N: shape = XC_top_side; break;
4296+ case FL_CURSOR_NW: shape = XC_top_left_corner; break;
4297+ case FL_CURSOR_E: shape = XC_right_side; break;
4298+ case FL_CURSOR_W: shape = XC_left_side; break;
4299+ case FL_CURSOR_SE: shape = XC_bottom_right_corner; break;
4300+ case FL_CURSOR_S: shape = XC_bottom_side; break;
4301+ case FL_CURSOR_SW: shape = XC_bottom_left_corner; break;
4302+ default:
4303+ return 0;
4304+ }
4305+
4306+ xc = XCreateFontCursor(fl_display, shape);
4307+ XDefineCursor(fl_display, xid, xc);
4308+ XFreeCursor(fl_display, xc);
4309+
4310+ return 1;
4311+}
4312+
4313+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
4314+#if ! HAVE_XCURSOR
4315+ return 0;
4316+#else
4317+ XcursorImage *cursor;
4318+ Cursor xc;
4319+
4320+ if ((hotx < 0) || (hotx >= image->w()))
4321+ return 0;
4322+ if ((hoty < 0) || (hoty >= image->h()))
4323+ return 0;
4324+
4325+ cursor = XcursorImageCreate(image->w(), image->h());
4326+ if (!cursor)
4327+ return 0;
4328+
4329+ const uchar *i = (const uchar*)*image->data();
4330+ XcursorPixel *o = cursor->pixels;
4331+ for (int y = 0;y < image->h();y++) {
4332+ for (int x = 0;x < image->w();x++) {
4333+ switch (image->d()) {
4334+ case 1:
4335+ *o = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
4336+ break;
4337+ case 2:
4338+ *o = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
4339+ break;
4340+ case 3:
4341+ *o = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
4342+ break;
4343+ case 4:
4344+ *o = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
4345+ break;
4346+ }
4347+ i += image->d();
4348+ o++;
4349+ }
4350+ i += image->ld();
4351+ }
4352+
4353+ cursor->xhot = hotx;
4354+ cursor->yhot = hoty;
4355+
4356+ xc = XcursorImageLoadCursor(fl_display, cursor);
4357+ XDefineCursor(fl_display, xid, xc);
4358+ XFreeCursor(fl_display, xc);
4359+
4360+ XcursorImageDestroy(cursor);
4361+
4362+ return 1;
4363+#endif
4364+}
4365+
4366+////////////////////////////////////////////////////////////////
4367+
4368 // returns pointer to the filename, or null if name ends with '/'
4369 const char *fl_filename_name(const char *name) {
4370 const char *p,*q;
4371diff -up fltk-1.3.x-r8772/test/cursor.cxx.cursor fltk-1.3.x-r8772/test/cursor.cxx
4372--- fltk-1.3.x-r8772/test/cursor.cxx.cursor 2010-12-08 15:00:35.000000000 +0100
4373+++ fltk-1.3.x-r8772/test/cursor.cxx 2011-06-08 18:23:14.343146587 +0200
4374@@ -32,8 +32,6 @@
4375 #include <FL/fl_draw.H>
4376 #include <FL/Fl_Box.H>
4377
4378-Fl_Color fg = FL_BLACK;
4379-Fl_Color bg = FL_WHITE;
4380 Fl_Cursor cursor = FL_CURSOR_DEFAULT;
4381
4382 Fl_Hor_Value_Slider *cursor_slider;
4383@@ -41,7 +39,7 @@ Fl_Hor_Value_Slider *cursor_slider;
4384 void choice_cb(Fl_Widget *, void *v) {
4385 cursor = (Fl_Cursor)(fl_intptr_t)v;
4386 cursor_slider->value(cursor);
4387- fl_cursor(cursor,fg,bg);
4388+ fl_cursor(cursor);
4389 }
4390
4391 Fl_Menu_Item choices[] = {
4392@@ -57,8 +55,6 @@ Fl_Menu_Item choices[] = {
4393 {"FL_CURSOR_WE",0,choice_cb,(void*)FL_CURSOR_WE},
4394 {"FL_CURSOR_NWSE",0,choice_cb,(void*)FL_CURSOR_NWSE},
4395 {"FL_CURSOR_NESW",0,choice_cb,(void*)FL_CURSOR_NESW},
4396- {"FL_CURSOR_NONE",0,choice_cb,(void*)FL_CURSOR_NONE},
4397-#if 0
4398 {"FL_CURSOR_N",0,choice_cb,(void*)FL_CURSOR_N},
4399 {"FL_CURSOR_NE",0,choice_cb,(void*)FL_CURSOR_NE},
4400 {"FL_CURSOR_E",0,choice_cb,(void*)FL_CURSOR_E},
4401@@ -67,26 +63,14 @@ Fl_Menu_Item choices[] = {
4402 {"FL_CURSOR_SW",0,choice_cb,(void*)FL_CURSOR_SW},
4403 {"FL_CURSOR_W",0,choice_cb,(void*)FL_CURSOR_W},
4404 {"FL_CURSOR_NW",0,choice_cb,(void*)FL_CURSOR_NW},
4405-#endif
4406+ {"FL_CURSOR_NONE",0,choice_cb,(void*)FL_CURSOR_NONE},
4407 {0}
4408 };
4409
4410 void setcursor(Fl_Widget *o, void *) {
4411 Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o;
4412 cursor = Fl_Cursor((int)slider->value());
4413- fl_cursor(cursor,fg,bg);
4414-}
4415-
4416-void setfg(Fl_Widget *o, void *) {
4417- Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o;
4418- fg = Fl_Color((int)slider->value());
4419- fl_cursor(cursor,fg,bg);
4420-}
4421-
4422-void setbg(Fl_Widget *o, void *) {
4423- Fl_Hor_Value_Slider *slider = (Fl_Hor_Value_Slider *)o;
4424- bg = Fl_Color((int)slider->value());
4425- fl_cursor(cursor,fg,bg);
4426+ fl_cursor(cursor);
4427 }
4428
4429 // draw the label without any ^C or \nnn conversions:
4430@@ -112,29 +96,11 @@ int main(int argc, char **argv) {
4431 slider1.align(FL_ALIGN_LEFT);
4432 slider1.step(1);
4433 slider1.precision(0);
4434- slider1.bounds(0,100);
4435+ slider1.bounds(0,255);
4436 slider1.value(0);
4437 slider1.callback(setcursor);
4438 slider1.value(cursor);
4439
4440- Fl_Hor_Value_Slider slider2(80,220,310,30,"fgcolor:");
4441- slider2.align(FL_ALIGN_LEFT);
4442- slider2.step(1);
4443- slider2.precision(0);
4444- slider2.bounds(0,255);
4445- slider2.value(0);
4446- slider2.callback(setfg);
4447- slider2.value(fg);
4448-
4449- Fl_Hor_Value_Slider slider3(80,260,310,30,"bgcolor:");
4450- slider3.align(FL_ALIGN_LEFT);
4451- slider3.step(1);
4452- slider3.precision(0);
4453- slider3.bounds(0,255);
4454- slider3.value(0);
4455- slider3.callback(setbg);
4456- slider3.value(bg);
4457-
4458 #if 0
4459 // draw the manual's diagram of cursors...
4460 window.size(400,800);