2 // "$Id: Fl_x.cxx 8764 2011-05-30 16:47:48Z manolo $"
4 // X specific code for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2011 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 //# include "Fl_win32.cxx"
30 #elif defined(__APPLE__)
31 //# include "Fl_mac.cxx"
32 #elif !defined(FL_DOXYGEN)
34 # define CONSOLIDATE_MOTION 1
35 /**** Define this if your keyboard lacks a backspace key... ****/
36 /* #define BACKSPACE_HACK 1 */
41 # include <FL/Fl_Window.H>
42 # include <FL/fl_utf8.h>
43 # include <FL/Fl_Tooltip.H>
44 # include <FL/fl_draw.H>
45 # include <FL/Fl_Paged_Device.H>
48 # include "flstring.h"
50 # include <sys/time.h>
52 # include <X11/Xlocale.h>
53 # include <X11/Xlib.h>
54 # include <X11/keysym.h>
55 #include <FL/Fl_Socket_Window.H>
57 #include <FL/themes.H>
59 static Fl_Cairo_Graphics_Driver fl_cairo_driver
;
60 static Fl_Display_Device
fl_cairo_display(&fl_cairo_driver
);
62 static Fl_Xlib_Graphics_Driver fl_xlib_driver
;
63 static Fl_Display_Device
fl_xlib_display(&fl_xlib_driver
);
65 FL_EXPORT Fl_Graphics_Driver
*fl_graphics_driver
= (Fl_Graphics_Driver
*)&fl_cairo_driver
; // the current target device of graphics operations
66 Fl_Surface_Device
* Fl_Surface_Device::_surface
= (Fl_Surface_Device
*)&fl_cairo_display
; // the current target surface of graphics operations
67 Fl_Display_Device
*Fl_Display_Device::_display
= &fl_cairo_display
;// the platform display
70 fl_offscreen_get_dimensions ( Fl_Offscreen p
, unsigned int *w
, unsigned int *h
)
75 XGetGeometry( fl_display
, p
, &rr
, &x
, &y
, w
, h
, &br
, &dr
);
78 ////////////////////////////////////////////////////////////////
79 // interface to poll/select call:
84 static pollfd
*pollfds
= 0;
87 # if HAVE_SYS_SELECT_H
88 # include <sys/select.h>
89 # endif /* HAVE_SYS_SELECT_H */
91 // The following #define is only needed for HP-UX 9.x and earlier:
92 //#define select(a,b,c,d,e) select((a),(int *)(b),(int *)(c),(int *)(d),(e))
94 static fd_set fdsets
[3];
100 # endif /* USE_POLL */
103 static int fd_array_size
= 0;
109 void (*cb
)(int, void*);
115 /* XEMBED messages */
116 #define XEMBED_EMBEDDED_NOTIFY 0
117 #define XEMBED_WINDOW_ACTIVATE 1
118 #define XEMBED_WINDOW_DEACTIVATE 2
119 #define XEMBED_REQUEST_FOCUS 3
120 #define XEMBED_FOCUS_IN 4
121 #define XEMBED_FOCUS_OUT 5
122 #define XEMBED_FOCUS_NEXT 6
123 #define XEMBED_FOCUS_PREV 7
124 /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
125 #define XEMBED_MODALITY_ON 10
126 #define XEMBED_MODALITY_OFF 11
127 #define XEMBED_REGISTER_ACCELERATOR 12
128 #define XEMBED_UNREGISTER_ACCELERATOR 13
129 #define XEMBED_ACTIVATE_ACCELERATOR 14
131 /* Details for XEMBED_FOCUS_IN: */
132 #define XEMBED_FOCUS_CURRENT 0
133 #define XEMBED_FOCUS_FIRST 1
134 #define XEMBED_FOCUS_LAST 2
136 #define XEMBED_MAPPED (1<<0)
138 Window fl_parent_window
= 0; /* hack into Fl_X::make_xid() */
140 void Fl::add_fd(int n
, int events
, void (*cb
)(int, void*), void *v
) {
143 if (i
>= fd_array_size
) {
145 fd_array_size
= 2*fd_array_size
+1;
147 if (!fd
) temp
= (FD
*)malloc(fd_array_size
*sizeof(FD
));
148 else temp
= (FD
*)realloc(fd
, fd_array_size
*sizeof(FD
));
156 if (!pollfds
) tpoll
= (pollfd
*)malloc(fd_array_size
*sizeof(pollfd
));
157 else tpoll
= (pollfd
*)realloc(pollfds
, fd_array_size
*sizeof(pollfd
));
167 pollfds
[i
].events
= events
;
170 fd
[i
].events
= events
;
171 if (events
& POLLIN
) FD_SET(n
, &fdsets
[0]);
172 if (events
& POLLOUT
) FD_SET(n
, &fdsets
[1]);
173 if (events
& POLLERR
) FD_SET(n
, &fdsets
[2]);
174 if (n
> maxfd
) maxfd
= n
;
178 void Fl::add_fd(int n
, void (*cb
)(int, void*), void* v
) {
179 Fl::add_fd(n
, POLLIN
, cb
, v
);
182 void Fl::remove_fd(int n
, int events
) {
185 maxfd
= -1; // recalculate maxfd on the fly
187 for (i
=j
=0; i
<nfds
; i
++) {
189 if (pollfds
[i
].fd
== n
) {
190 int e
= pollfds
[i
].events
& ~events
;
191 if (!e
) continue; // if no events left, delete this fd
192 pollfds
[j
].events
= e
;
196 int e
= fd
[i
].events
& ~events
;
197 if (!e
) continue; // if no events left, delete this fd
200 if (fd
[i
].fd
> maxfd
) maxfd
= fd
[i
].fd
;
202 // move it down in the array if necessary:
206 pollfds
[j
] = pollfds
[i
];
213 if (events
& POLLIN
) FD_CLR(n
, &fdsets
[0]);
214 if (events
& POLLOUT
) FD_CLR(n
, &fdsets
[1]);
215 if (events
& POLLERR
) FD_CLR(n
, &fdsets
[2]);
219 void Fl::remove_fd(int n
) {
223 #if CONSOLIDATE_MOTION
224 static Fl_Window
* send_motion
;
225 extern Fl_Window
* fl_xmousewin
;
227 static bool in_a_window
; // true if in any of our windows, even destroyed ones
228 static void do_queued_events() {
230 while (XEventsQueued(fl_display
,QueuedAfterReading
)) {
232 XNextEvent(fl_display
, &xevent
);
235 // we send FL_LEAVE only if the mouse did not enter some other window:
236 if (!in_a_window
) Fl::handle(FL_LEAVE
, 0);
237 #if CONSOLIDATE_MOTION
238 else if (send_motion
== fl_xmousewin
) {
240 Fl::handle(FL_MOVE
, fl_xmousewin
);
245 // these pointers are set by the Fl::lock() function:
246 static void nothing() {}
247 void (*fl_lock_function
)() = nothing
;
248 void (*fl_unlock_function
)() = nothing
;
250 // This is never called with time_to_wait < 0.0:
251 // It should return negative on error, 0 if nothing happens before
252 // timeout, and >0 if any callbacks were done.
253 int fl_wait(double time_to_wait
) {
255 // OpenGL and other broken libraries call XEventsQueued
256 // unnecessarily and thus cause the file descriptor to not be ready,
257 // so we must check for already-read events:
258 if (fl_display
&& XQLength(fl_display
)) {do_queued_events(); return 1;}
268 fl_unlock_function();
270 if (time_to_wait
< 2147483.648) {
272 n
= ::poll(pollfds
, nfds
, int(time_to_wait
*1000 + .5));
275 t
.tv_sec
= int(time_to_wait
);
276 t
.tv_usec
= int(1000000 * (time_to_wait
-t
.tv_sec
));
277 n
= ::select(maxfd
+1,&fdt
[0],&fdt
[1],&fdt
[2],&t
);
281 n
= ::poll(pollfds
, nfds
, -1);
283 n
= ::select(maxfd
+1,&fdt
[0],&fdt
[1],&fdt
[2],0);
290 for (int i
=0; i
<nfds
; i
++) {
292 if (pollfds
[i
].revents
) fd
[i
].cb(pollfds
[i
].fd
, fd
[i
].arg
);
296 if (FD_ISSET(f
,&fdt
[0])) revents
|= POLLIN
;
297 if (FD_ISSET(f
,&fdt
[1])) revents
|= POLLOUT
;
298 if (FD_ISSET(f
,&fdt
[2])) revents
|= POLLERR
;
299 if (fd
[i
].events
& revents
) fd
[i
].cb(f
, fd
[i
].arg
);
306 // fl_ready() is just like fl_wait(0.0) except no callbacks are done:
308 if (XQLength(fl_display
)) return 1;
309 if (!nfds
) return 0; // nothing to select or poll
311 return ::poll(pollfds
, nfds
, 0);
320 return ::select(maxfd
+1,&fdt
[0],&fdt
[1],&fdt
[2],&t
);
324 // replace \r\n by \n
325 static void convert_crlf(unsigned char *string
, long& len
) {
326 unsigned char *a
, *b
;
329 if (*a
== '\r' && a
[1] == '\n') { a
++; len
--; }
335 ////////////////////////////////////////////////////////////////
338 Window fl_message_window
= 0;
340 XVisualInfo
*fl_visual
;
341 Colormap fl_colormap
;
344 char fl_is_over_the_spot
= 0;
345 static XRectangle status_area
;
347 static Atom WM_DELETE_WINDOW
;
348 static Atom WM_PROTOCOLS
;
349 static Atom fl_MOTIF_WM_HINTS
;
351 static Atom CLIPBOARD
;
353 Atom fl_XdndSelection
;
355 Atom fl_XdndTypeList
;
356 Atom fl_XdndPosition
;
360 Atom fl_XdndActionCopy
;
361 Atom fl_XdndFinished
;
364 Atom fl_Xatextplainutf
;
366 static Atom fl_XaText
;
367 Atom fl_XaCompoundText
;
368 Atom fl_XaUtf8String
;
369 Atom fl_XaTextUriList
;
370 Atom fl_NET_WM_NAME
; // utf8 aware window label
371 Atom fl_NET_WM_ICON_NAME
; // utf8 aware window icon name
376 X defines 32-bit-entities to have a format value of max. 32,
377 although sizeof(atom) can be 8 (64 bits) on a 64-bit OS.
378 See also fl_open_display() for sizeof(atom) < 4.
379 Used for XChangeProperty (see STR #2419).
381 static int atom_bits
= 32;
383 static void fd_callback(int,void *) {
388 static int io_error_handler(Display
*) {
389 Fl::fatal("X I/O error");
393 static int xerror_handler(Display
* d
, XErrorEvent
* e
) {
394 char buf1
[128], buf2
[128];
395 sprintf(buf1
, "XRequest.%d", e
->request_code
);
396 XGetErrorDatabaseText(d
,"",buf1
,buf1
,buf2
,128);
397 XGetErrorText(d
, e
->error_code
, buf1
, 128);
398 Fl::warning("%s: %s 0x%lx", buf2
, buf1
, e
->resourceid
);
403 extern char *fl_get_font_xfld(int fnum
, int size
);
407 XVaNestedList preedit_attr
= NULL
;
408 XVaNestedList status_attr
= NULL
;
409 static XFontSet fs
= NULL
;
414 static XRectangle spot
;
417 XIMStyles
* xim_styles
= NULL
;
421 #if defined(__GNUC__)
422 // FIXME: warning XFT support here
426 fnt
= (char*)"-misc-fixed-*";
427 fs
= XCreateFontSet(fl_display
, fnt
, &missing_list
,
428 &missing_count
, &def_string
);
432 bool must_free_fnt
= true;
433 fnt
= fl_get_font_xfld(0, 14);
434 if (!fnt
) {fnt
= (char*)"-misc-fixed-*";must_free_fnt
=false;}
435 fs
= XCreateFontSet(fl_display
, fnt
, &missing_list
,
436 &missing_count
, &def_string
);
437 if (must_free_fnt
) free(fnt
);
440 preedit_attr
= XVaCreateNestedList(0,
441 XNSpotLocation
, &spot
,
442 XNFontSet
, fs
, NULL
);
443 status_attr
= XVaCreateNestedList(0,
444 XNAreaNeeded
, &status_area
,
445 XNFontSet
, fs
, NULL
);
447 if (!XGetIMValues(fl_xim_im
, XNQueryInputStyle
,
448 &xim_styles
, NULL
, NULL
)) {
451 for (i
= 0, style
= xim_styles
->supported_styles
;
452 i
< xim_styles
->count_styles
; i
++, style
++) {
453 if (*style
== (XIMPreeditPosition
| XIMStatusArea
)) {
456 } else if (*style
== (XIMPreeditPosition
| XIMStatusNothing
)) {
464 fl_xim_ic
= XCreateIC(fl_xim_im
,
465 XNInputStyle
, (XIMPreeditPosition
| XIMStatusArea
),
466 XNPreeditAttributes
, preedit_attr
,
467 XNStatusAttributes
, status_attr
,
471 if (!fl_xim_ic
&& predit
) {
472 fl_xim_ic
= XCreateIC(fl_xim_im
,
473 XNInputStyle
, (XIMPreeditPosition
| XIMStatusNothing
),
474 XNPreeditAttributes
, preedit_attr
,
480 fl_is_over_the_spot
= 0;
481 fl_xim_ic
= XCreateIC(fl_xim_im
,
482 XNInputStyle
, (XIMPreeditNothing
| XIMStatusNothing
),
485 fl_is_over_the_spot
= 1;
486 XVaNestedList status_attr
= NULL
;
487 status_attr
= XVaCreateNestedList(0, XNAreaNeeded
, &status_area
, NULL
);
489 XGetICValues(fl_xim_ic
, XNStatusAttributes
, status_attr
, NULL
);
495 static XRectangle spot
;
496 static int spotf
= -1;
497 static int spots
= -1;
499 void fl_reset_spot(void)
503 //if (fl_xim_ic) XUnsetICFocus(fl_xim_ic);
506 void fl_set_spot(int font
, int size
, int X
, int Y
, int W
, int H
, Fl_Window
*win
)
509 XVaNestedList preedit_attr
;
510 static XFontSet fs
= NULL
;
515 bool must_free_fnt
=true;
517 static XIC ic
= NULL
;
519 if (!fl_xim_ic
|| !fl_is_over_the_spot
) return;
520 //XSetICFocus(fl_xim_ic);
521 if (X
!= spot
.x
|| Y
!= spot
.y
) {
528 if (font
!= spotf
|| size
!= spots
) {
533 XFreeFontSet(fl_display
, fs
);
537 #if defined(__GNUC__)
538 // FIXME: warning XFT support here
541 fnt
= NULL
; // fl_get_font_xfld(font, size);
542 if (!fnt
) {fnt
= (char*)"-misc-fixed-*";must_free_fnt
=false;}
543 fs
= XCreateFontSet(fl_display
, fnt
, &missing_list
,
544 &missing_count
, &def_string
);
546 fnt
= fl_get_font_xfld(font
, size
);
547 if (!fnt
) {fnt
= (char*)"-misc-fixed-*";must_free_fnt
=false;}
548 fs
= XCreateFontSet(fl_display
, fnt
, &missing_list
,
549 &missing_count
, &def_string
);
552 if (fl_xim_ic
!= ic
) {
557 if (fnt
&& must_free_fnt
) free(fnt
);
561 preedit_attr
= XVaCreateNestedList(0,
562 XNSpotLocation
, &spot
,
563 XNFontSet
, fs
, NULL
);
564 XSetICValues(fl_xim_ic
, XNPreeditAttributes
, preedit_attr
, NULL
);
568 void fl_set_status(int x
, int y
, int w
, int h
)
570 XVaNestedList status_attr
;
573 status_area
.width
= w
;
574 status_area
.height
= h
;
575 if (!fl_xim_ic
) return;
576 status_attr
= XVaCreateNestedList(0, XNArea
, &status_area
, NULL
);
578 XSetICValues(fl_xim_ic
, XNStatusAttributes
, status_attr
, NULL
);
583 static int xim_warning
= 2;
584 if (xim_warning
> 0) xim_warning
--;
587 XIMStyles
*xim_styles
;
588 if (!fl_display
) return;
589 if (fl_xim_im
) return;
591 fl_xim_im
= XOpenIM(fl_display
, NULL
, NULL
, NULL
);
596 XGetIMValues (fl_xim_im
, XNQueryInputStyle
,
597 &xim_styles
, NULL
, NULL
);
600 Fl::warning("XOpenIM() failed");
601 // if xim_styles is allocated, free it now
602 if (xim_styles
) XFree(xim_styles
);
606 if (xim_styles
&& xim_styles
->count_styles
) {
610 Fl::warning("No XIM style found");
613 // if xim_styles is allocated, free it now
614 if (xim_styles
) XFree(xim_styles
);
619 Fl::warning("XCreateIC() failed");
623 // if xim_styles is still allocated, free it now
624 if(xim_styles
) XFree(xim_styles
);
627 void fl_open_display() {
628 if (fl_display
) return;
630 setlocale(LC_CTYPE
, "");
631 XSetLocaleModifiers("");
633 XSetIOErrorHandler(io_error_handler
);
634 XSetErrorHandler(xerror_handler
);
636 Display
*d
= XOpenDisplay(0);
637 if (!d
) Fl::fatal("Can't open display: %s",XDisplayName(0));
642 void fl_open_display(Display
* d
) {
645 WM_DELETE_WINDOW
= XInternAtom(d
, "WM_DELETE_WINDOW", 0);
646 WM_PROTOCOLS
= XInternAtom(d
, "WM_PROTOCOLS", 0);
647 fl_MOTIF_WM_HINTS
= XInternAtom(d
, "_MOTIF_WM_HINTS", 0);
648 TARGETS
= XInternAtom(d
, "TARGETS", 0);
649 CLIPBOARD
= XInternAtom(d
, "CLIPBOARD", 0);
650 fl_XdndAware
= XInternAtom(d
, "XdndAware", 0);
651 fl_XdndSelection
= XInternAtom(d
, "XdndSelection", 0);
652 fl_XdndEnter
= XInternAtom(d
, "XdndEnter", 0);
653 fl_XdndTypeList
= XInternAtom(d
, "XdndTypeList", 0);
654 fl_XdndPosition
= XInternAtom(d
, "XdndPosition", 0);
655 fl_XdndLeave
= XInternAtom(d
, "XdndLeave", 0);
656 fl_XdndDrop
= XInternAtom(d
, "XdndDrop", 0);
657 fl_XdndStatus
= XInternAtom(d
, "XdndStatus", 0);
658 fl_XdndActionCopy
= XInternAtom(d
, "XdndActionCopy", 0);
659 fl_XdndFinished
= XInternAtom(d
, "XdndFinished", 0);
660 //fl_XdndProxy = XInternAtom(d, "XdndProxy", 0);
661 fl_XdndEnter
= XInternAtom(d
, "XdndEnter", 0);
662 fl_XdndURIList
= XInternAtom(d
, "text/uri-list", 0);
663 fl_Xatextplainutf
= XInternAtom(d
, "text/plain;charset=UTF-8",0);
664 fl_Xatextplain
= XInternAtom(d
, "text/plain", 0);
665 fl_XaText
= XInternAtom(d
, "TEXT", 0);
666 fl_XaCompoundText
= XInternAtom(d
, "COMPOUND_TEXT", 0);
667 fl_XaUtf8String
= XInternAtom(d
, "UTF8_STRING", 0);
668 fl_XaTextUriList
= XInternAtom(d
, "text/uri-list", 0);
669 fl_NET_WM_NAME
= XInternAtom(d
, "_NET_WM_NAME", 0);
670 fl_NET_WM_ICON_NAME
= XInternAtom(d
, "_NET_WM_ICON_NAME", 0);
671 fl_XEMBED
= XInternAtom(d
, "_XEMBED", 0);
672 fl_XEMBED_INFO
= XInternAtom(d
, "_XEMBED_INFO", 0);
674 if (sizeof(Atom
) < 4)
675 atom_bits
= sizeof(Atom
) * 8;
677 Fl::add_fd(ConnectionNumber(d
), POLLIN
, fd_callback
);
679 fl_screen
= DefaultScreen(d
);
682 XCreateSimpleWindow(d
, RootWindow(d
,fl_screen
), 0,0,1,1,0, 0, 0);
684 // construct an XVisualInfo that matches the default Visual:
685 XVisualInfo templt
; int num
;
686 templt
.visualid
= XVisualIDFromVisual(DefaultVisual(d
, fl_screen
));
687 fl_visual
= XGetVisualInfo(d
, VisualIDMask
, &templt
, &num
);
688 fl_colormap
= DefaultColormap(d
, fl_screen
);
695 Fl::get_system_colors();
697 fl_register_themes();
699 Fl_Theme::load_default();
702 void fl_close_display() {
703 Fl::remove_fd(ConnectionNumber(fl_display
));
704 XCloseDisplay(fl_display
);
707 static int fl_workarea_xywh
[4] = { -1, -1, -1, -1 };
709 static void fl_init_workarea() {
712 Atom _NET_WORKAREA
= XInternAtom(fl_display
, "_NET_WORKAREA", 0);
714 unsigned long count
, remaining
;
718 if (XGetWindowProperty(fl_display
, RootWindow(fl_display
, fl_screen
),
719 _NET_WORKAREA
, 0, 4 * sizeof(unsigned), False
,
720 XA_CARDINAL
, &actual
, &format
, &count
, &remaining
,
721 (unsigned char **)&xywh
) || !xywh
|| !xywh
[2] ||
724 fl_workarea_xywh
[0] = 0;
725 fl_workarea_xywh
[1] = 0;
726 fl_workarea_xywh
[2] = DisplayWidth(fl_display
, fl_screen
);
727 fl_workarea_xywh
[3] = DisplayHeight(fl_display
, fl_screen
);
731 fl_workarea_xywh
[0] = (int)xywh
[0];
732 fl_workarea_xywh
[1] = (int)xywh
[1];
733 fl_workarea_xywh
[2] = (int)xywh
[2];
734 fl_workarea_xywh
[3] = (int)xywh
[3];
740 if (fl_workarea_xywh
[0] < 0) fl_init_workarea();
741 return fl_workarea_xywh
[0];
745 if (fl_workarea_xywh
[0] < 0) fl_init_workarea();
746 return fl_workarea_xywh
[1];
750 if (fl_workarea_xywh
[0] < 0) fl_init_workarea();
751 return fl_workarea_xywh
[2];
755 if (fl_workarea_xywh
[0] < 0) fl_init_workarea();
756 return fl_workarea_xywh
[3];
759 void Fl::get_mouse(int &xx
, int &yy
) {
761 Window root
= RootWindow(fl_display
, fl_screen
);
762 Window c
; int mx
,my
,cx
,cy
; unsigned int mask
;
763 XQueryPointer(fl_display
,root
,&root
,&c
,&mx
,&my
,&cx
,&cy
,&mask
);
768 void Fl::set_mouse(int x
, int y
) {
770 Window root
= RootWindow(fl_display
, fl_screen
);
771 XWarpPointer(fl_display
,None
,root
,0,0,0,0,x
,y
);
775 ////////////////////////////////////////////////////////////////
776 // Code used for paste and DnD into the program:
778 Fl_Widget
*fl_selection_requestor
;
779 char *fl_selection_buffer
[2];
780 int fl_selection_length
[2];
781 int fl_selection_buffer_length
[2];
782 char fl_i_own_selection
[2] = {0,0};
784 // Call this when a "paste" operation happens:
785 void Fl::paste(Fl_Widget
&receiver
, int clipboard
) {
786 if (fl_i_own_selection
[clipboard
]) {
787 // We already have it, do it quickly without window server.
788 // Notice that the text is clobbered if set_selection is
789 // called in response to FL_PASTE!
790 Fl::e_text
= fl_selection_buffer
[clipboard
];
791 Fl::e_length
= fl_selection_length
[clipboard
];
792 if (!Fl::e_text
) Fl::e_text
= (char *)"";
793 receiver
.handle(FL_PASTE
);
796 // otherwise get the window server to return it:
797 fl_selection_requestor
= &receiver
;
798 Atom property
= clipboard
? CLIPBOARD
: XA_PRIMARY
;
799 XConvertSelection(fl_display
, property
, TARGETS
, property
,
800 fl_xid(Fl::first_window()), fl_event_time
);
803 Window fl_dnd_source_window
;
804 Atom
*fl_dnd_source_types
; // null-terminated list of data types being supplied
806 Atom fl_dnd_source_action
;
809 void fl_sendClientMessage(Window window
, Atom message
,
817 e
.xany
.type
= ClientMessage
;
818 e
.xany
.window
= window
;
819 e
.xclient
.message_type
= message
;
820 e
.xclient
.format
= 32;
821 e
.xclient
.data
.l
[0] = (long)d0
;
822 e
.xclient
.data
.l
[1] = (long)d1
;
823 e
.xclient
.data
.l
[2] = (long)d2
;
824 e
.xclient
.data
.l
[3] = (long)d3
;
825 e
.xclient
.data
.l
[4] = (long)d4
;
826 XSendEvent(fl_display
, window
, 0, 0, &e
);
829 ////////////////////////////////////////////////////////////////
830 // Code for copying to clipboard and DnD out of the program:
832 void Fl::copy(const char *stuff
, int len
, int clipboard
) {
833 if (!stuff
|| len
<0) return;
834 if (len
+1 > fl_selection_buffer_length
[clipboard
]) {
835 delete[] fl_selection_buffer
[clipboard
];
836 fl_selection_buffer
[clipboard
] = new char[len
+100];
837 fl_selection_buffer_length
[clipboard
] = len
+100;
839 memcpy(fl_selection_buffer
[clipboard
], stuff
, len
);
840 fl_selection_buffer
[clipboard
][len
] = 0; // needed for direct paste
841 fl_selection_length
[clipboard
] = len
;
842 fl_i_own_selection
[clipboard
] = 1;
843 Atom property
= clipboard
? CLIPBOARD
: XA_PRIMARY
;
844 XSetSelectionOwner(fl_display
, property
, fl_message_window
, fl_event_time
);
847 ////////////////////////////////////////////////////////////////
849 const XEvent
* fl_xevent
; // the current x event
850 ulong fl_event_time
; // the last timestamp from an x event
852 char fl_key_vector
[32]; // used by Fl::get_key()
854 // Record event mouse position and state from an XEvent:
859 static void set_event_xy() {
860 # if CONSOLIDATE_MOTION
863 Fl::e_x_root
= fl_xevent
->xbutton
.x_root
;
864 Fl::e_x
= fl_xevent
->xbutton
.x
;
865 Fl::e_y_root
= fl_xevent
->xbutton
.y_root
;
866 Fl::e_y
= fl_xevent
->xbutton
.y
;
867 Fl::e_state
= fl_xevent
->xbutton
.state
<< 16;
868 fl_event_time
= fl_xevent
->xbutton
.time
;
870 // get the meta key off PC keyboards:
871 if (fl_key_vector
[18]&0x18) Fl::e_state
|= FL_META
;
873 // turn off is_click if enough time or mouse movement has passed:
874 if (abs(Fl::e_x_root
-px
)+abs(Fl::e_y_root
-py
) > 3 ||
875 fl_event_time
>= ptime
+1000)
879 // if this is same event as last && is_click, increment click count:
880 static inline void checkdouble() {
881 if (Fl::e_is_click
== Fl::e_keysym
)
885 Fl::e_is_click
= Fl::e_keysym
;
889 ptime
= fl_event_time
;
892 static Fl_Window
* resize_bug_fix
;
894 ////////////////////////////////////////////////////////////////
896 static char unknown
[] = "<unknown>";
897 const int unknown_len
= 10;
901 static int xerror
= 0;
903 static int ignoreXEvents(Display
*display
, XErrorEvent
*event
) {
908 static XErrorHandler
catchXExceptions() {
910 return ignoreXEvents
;
913 static int wasXExceptionRaised() {
919 bool fl_embed_called
= false;
921 void fl_embed ( Fl_Window
*w
, Window parent
)
923 fl_embed_called
= true;
924 /* this destroys the existing window */
926 /* embedded windows don't need borders */
929 fl_parent_window
= parent
;
930 Fl_X::make_xid( w
, fl_visual
, fl_colormap
);
931 fl_parent_window
= 0;
933 /* mark this window as wanting to be embedded */
934 unsigned long buffer
[2];
936 buffer
[0] = 1; /* protocol version */
940 XChangeProperty (fl_display
,
942 fl_XEMBED_INFO
, fl_XEMBED_INFO
, 32,
944 (unsigned char *)buffer
, 2);
946 XSync(fl_display
, False
);
951 xembed_send_configure_event ( Fl_Socket_Window
*w
)
953 /* printf( "NTK: Sending synthetic configure event to embedded window\n" ); */
957 memset( &xc
, 0, sizeof( xc
) );
959 xc
.type
= ConfigureNotify
;
960 xc
.event
= w
->plug_xid();
961 xc
.window
= w
->plug_xid();
972 xc
.override_redirect
= False
;
974 XSendEvent( fl_display
, w
->plug_xid(), False
, NoEventMask
, (XEvent
*)&xc
);
978 xembed_get_info ( Window window
, unsigned long *version
, unsigned long *flags
)
984 unsigned long nitems
, bytes_after
;
986 unsigned long *data_long
;
988 r
= XGetWindowProperty( fl_display
, window
, fl_XEMBED_INFO
, 0, 2, False
, fl_XEMBED_INFO
, &type
, &format
, &nitems
, &bytes_after
, &data
);
990 if ( r
!= Success
|| type
!= fl_XEMBED_INFO
)
999 data_long
= (unsigned long*)data
;
1002 *version
= data_long
[0];
1004 *flags
= data_long
[1] & XEMBED_MAPPED
;
1012 xembed_maybe_embed_window ( Window parent
, Window window
)
1014 if ( parent
!= window
)
1016 Fl_Socket_Window
*p
= (Fl_Socket_Window
*)fl_find( parent
);
1020 if ( Fl_Socket_Window::is_socket( p
) )
1022 if ( p
->plug_xid() )
1024 // error, already embedded.
1028 /* printf( "NTK: Got embed request... Replying with XEMBED_EMBEDDED_NOTIFY\n" ); */
1030 fl_sendClientMessage(window
, fl_XEMBED
, CurrentTime
, XEMBED_EMBEDDED_NOTIFY
, 0, window
, 0 );
1031 fl_sendClientMessage(window
, fl_XEMBED
, CurrentTime
, XEMBED_WINDOW_ACTIVATE
);
1032 p
->plug_xid( window
);
1035 XMapWindow( fl_display
, window
);
1037 xembed_send_configure_event( p
);
1047 static int fl_handle_xembed ( const XEvent
&xevent
)
1049 switch (xevent
.type
) {
1052 /* printf( "Got destroy notify\n" ); */
1054 Fl_Socket_Window
*p
= (Fl_Socket_Window
*)fl_find( xevent
.xdestroywindow
.event
);
1056 if ( p
&& Fl_Socket_Window::is_socket( p
) )
1058 /* printf( "Ending embedding\n" ); */
1068 /* printf( "Got map request\n" ); */
1070 return xembed_maybe_embed_window( xevent
.xmaprequest
.parent
, xevent
.xmaprequest
.window
);
1075 /* printf( "Got create notify\n" ); */
1076 const XCreateWindowEvent
*cw
= &fl_xevent
->xcreatewindow
;
1078 return xembed_maybe_embed_window( cw
->parent
, cw
->window
);
1081 case ReparentNotify
:
1082 /* printf( "Got reparent notify\n" ); */
1083 return xembed_maybe_embed_window( xevent
.xreparent
.parent
, xevent
.xreparent
.window
);
1085 case ConfigureRequest
:
1087 /* printf( "Got configure request\n" ); */
1088 XConfigureRequestEvent
*xe
= (XConfigureRequestEvent
*)&fl_xevent
->xconfigurerequest
;
1090 xembed_maybe_embed_window( xe
->parent
, xe
->window
);
1092 printf( "Got configure request for %ix%i... Not gonna happen.\n", xe
->width
, xe
->height
);
1094 Fl_Socket_Window
*p
= (Fl_Socket_Window
*)fl_find( xe
->parent
);
1095 if ( p
&& Fl_Socket_Window::is_socket( p
) )
1097 xembed_send_configure_event( p
);
1103 case PropertyNotify
:
1105 /* printf( "Got property notify.\n" ); */
1106 if ( xevent
.xproperty
.atom
== fl_XEMBED_INFO
)
1108 unsigned long version
= 0;
1109 unsigned long flags
= 0;
1111 xembed_get_info( xevent
.xproperty
.window
, &version
, &flags
);
1113 if ( (flags
& XEMBED_MAPPED
) )
1115 XMapWindow( fl_display
, xevent
.xproperty
.window
);
1123 case ClientMessage
: {
1124 Fl_Window
* window
= fl_find(fl_xevent
->xclient
.window
);
1125 Atom message
= fl_xevent
->xclient
.message_type
;
1126 const long* data
= fl_xevent
->xclient
.data
.l
;
1128 if ( message
== fl_XEMBED
)
1132 case XEMBED_EMBEDDED_NOTIFY
:
1133 /* printf( "NTK: Got XEMBED_EMBEDDED_NOTIFY\n" ); */
1134 window
->resize( 0, 0, window
->w(), window
->h() );
1136 case XEMBED_WINDOW_ACTIVATE
:
1137 /* printf( "NTK: Got XEMBED_WINDOW_ACTIVATE\n" ); */
1138 /* window->resize( 0, 0, window->w(), window->h() ); */
1140 case XEMBED_WINDOW_DEACTIVATE
:
1141 /* printf( "NTK: Got XEMBED_WINDOW_DEACTIVATE\n" ); */
1144 /* unsupported message */
1160 int fl_handle(const XEvent
& thisevent
)
1162 XEvent xevent
= thisevent
;
1163 fl_xevent
= &thisevent
;
1164 Window xid
= xevent
.xany
.window
;
1165 static Window xim_win
= 0;
1167 if (fl_xim_ic
&& xevent
.type
== DestroyNotify
&&
1168 xid
!= xim_win
&& !fl_find(xid
))
1171 xim_im
= XOpenIM(fl_display
, NULL
, NULL
, NULL
);
1173 /* XIM server has crashed */
1174 XSetLocaleModifiers("@im=");
1178 XCloseIM(xim_im
); // see STR 2185 for comment
1183 if (fl_xim_ic
&& (xevent
.type
== FocusIn
))
1190 XDestroyIC(fl_xim_ic
);
1193 XSetICValues(fl_xim_ic
,
1194 XNFocusWindow
, xevent
.xclient
.window
,
1195 XNClientWindow
, xid
,
1198 fl_set_spot(spotf
, spots
, spot
.x
, spot
.y
, spot
.width
, spot
.height
);
1200 if (Fl::first_window() && Fl::first_window()->modal()) {
1201 Window x
= fl_xid(Fl::first_window());
1204 XSetICValues(fl_xim_ic
,
1205 XNFocusWindow
, xim_win
,
1206 XNClientWindow
, xim_win
,
1208 fl_set_spot(spotf
, spots
, spot
.x
, spot
.y
, spot
.width
, spot
.height
);
1210 } else if (xim_win
!= xid
&& xid
) {
1212 XSetICValues(fl_xim_ic
,
1213 XNFocusWindow
, xevent
.xclient
.window
,
1214 XNClientWindow
, xid
,
1215 //XNFocusWindow, xim_win,
1216 //XNClientWindow, xim_win,
1218 fl_set_spot(spotf
, spots
, spot
.x
, spot
.y
, spot
.width
, spot
.height
);
1223 if ( XFilterEvent((XEvent
*)&xevent
, 0) )
1226 if ( fl_handle_xembed( xevent
) )
1229 switch (xevent
.type
) {
1232 memcpy(fl_key_vector
, xevent
.xkeymap
.key_vector
, 32);
1236 XRefreshKeyboardMapping((XMappingEvent
*)&xevent
.xmapping
);
1239 case SelectionNotify
: {
1240 if (!fl_selection_requestor
) return 0;
1241 static unsigned char* buffer
= 0;
1242 if (buffer
) {XFree(buffer
); buffer
= 0;}
1244 if (fl_xevent
->xselection
.property
) for (;;) {
1245 // The Xdnd code pastes 64K chunks together, possibly to avoid
1246 // bugs in X servers, or maybe to avoid an extra round-trip to
1247 // get the property length. I copy this here:
1248 Atom actual
; int format
; unsigned long count
, remaining
;
1249 unsigned char* portion
= NULL
;
1250 if (XGetWindowProperty(fl_display
,
1251 fl_xevent
->xselection
.requestor
,
1252 fl_xevent
->xselection
.property
,
1253 bytesread
/4, 65536, 1, 0,
1254 &actual
, &format
, &count
, &remaining
,
1255 &portion
)) break; // quit on error
1256 if (actual
== TARGETS
|| actual
== XA_ATOM
) {
1257 Atom type
= XA_STRING
;
1258 for (unsigned i
= 0; i
<count
; i
++) {
1259 Atom t
= ((Atom
*)portion
)[i
];
1260 if (t
== fl_Xatextplainutf
||
1261 t
== fl_Xatextplain
||
1262 t
== fl_XaUtf8String
) {type
= t
; break;}
1263 // rest are only used if no utf-8 available:
1264 if (t
== fl_XaText
||
1265 t
== fl_XaTextUriList
||
1266 t
== fl_XaCompoundText
) type
= t
;
1269 Atom property
= xevent
.xselection
.property
;
1270 XConvertSelection(fl_display
, property
, type
, property
,
1271 fl_xid(Fl::first_window()),
1275 // Make sure we got something sane...
1276 if ((portion
== NULL
) || (format
!= 8) || (count
== 0)) {
1277 if (portion
) XFree(portion
);
1280 buffer
= (unsigned char*)realloc(buffer
, bytesread
+count
+remaining
+1);
1281 memcpy(buffer
+bytesread
, portion
, count
);
1284 // Cannot trust data to be null terminated
1285 buffer
[bytesread
] = '\0';
1286 if (!remaining
) break;
1289 buffer
[bytesread
] = 0;
1290 convert_crlf(buffer
, bytesread
);
1292 Fl::e_text
= buffer
? (char*)buffer
: (char *)"";
1293 Fl::e_length
= bytesread
;
1294 int old_event
= Fl::e_number
;
1295 fl_selection_requestor
->handle(Fl::e_number
= FL_PASTE
);
1296 Fl::e_number
= old_event
;
1297 // Detect if this paste is due to Xdnd by the property name (I use
1298 // XA_SECONDARY for that) and send an XdndFinished message. It is not
1299 // clear if this has to be delayed until now or if it can be done
1300 // immediatly after calling XConvertSelection.
1301 if (fl_xevent
->xselection
.property
== XA_SECONDARY
&&
1302 fl_dnd_source_window
) {
1303 fl_sendClientMessage(fl_dnd_source_window
, fl_XdndFinished
,
1304 fl_xevent
->xselection
.requestor
);
1305 fl_dnd_source_window
= 0; // don't send a second time
1309 case SelectionClear
: {
1310 int clipboard
= fl_xevent
->xselectionclear
.selection
== CLIPBOARD
;
1311 fl_i_own_selection
[clipboard
] = 0;
1314 case SelectionRequest
: {
1316 e
.type
= SelectionNotify
;
1317 e
.requestor
= fl_xevent
->xselectionrequest
.requestor
;
1318 e
.selection
= fl_xevent
->xselectionrequest
.selection
;
1319 int clipboard
= e
.selection
== CLIPBOARD
;
1320 e
.target
= fl_xevent
->xselectionrequest
.target
;
1321 e
.time
= fl_xevent
->xselectionrequest
.time
;
1322 e
.property
= fl_xevent
->xselectionrequest
.property
;
1323 if (e
.target
== TARGETS
) {
1324 Atom a
[3] = {fl_XaUtf8String
, XA_STRING
, fl_XaText
};
1325 XChangeProperty(fl_display
, e
.requestor
, e
.property
,
1326 XA_ATOM
, atom_bits
, 0, (unsigned char*)a
, 3);
1327 } else if (/*e.target == XA_STRING &&*/ fl_selection_length
[clipboard
]) {
1328 if (e
.target
== fl_XaUtf8String
||
1329 e
.target
== XA_STRING
||
1330 e
.target
== fl_XaCompoundText
||
1331 e
.target
== fl_XaText
||
1332 e
.target
== fl_Xatextplain
||
1333 e
.target
== fl_Xatextplainutf
) {
1334 // clobber the target type, this seems to make some applications
1335 // behave that insist on asking for XA_TEXT instead of UTF8_STRING
1336 // Does not change XA_STRING as that breaks xclipboard.
1337 if (e
.target
!= XA_STRING
) e
.target
= fl_XaUtf8String
;
1338 XChangeProperty(fl_display
, e
.requestor
, e
.property
,
1340 (unsigned char *)fl_selection_buffer
[clipboard
],
1341 fl_selection_length
[clipboard
]);
1344 // char* x = XGetAtomName(fl_display,e.target);
1345 // fprintf(stderr,"selection request of %s\n",x);
1349 XSendEvent(fl_display
, e
.requestor
, 0, 0, (XEvent
*)&e
);}
1352 // events where interesting window id is in a different place:
1353 case CirculateNotify
:
1354 case CirculateRequest
:
1355 case ConfigureNotify
:
1356 case ConfigureRequest
:
1362 case ReparentNotify
:
1364 xid
= xevent
.xmaprequest
.window
;
1369 Fl_Window
* window
= fl_find(xid
);
1371 if (window
) switch (xevent
.type
) {
1373 case DestroyNotify
: { // an X11 window was closed externally from the program
1374 Fl::handle(FL_CLOSE
, window
);
1375 Fl_X
* X
= Fl_X::i(window
);
1376 if (X
) { // indicates the FLTK window was not closed
1377 X
->xid
= (Window
)0; // indicates the X11 window was already destroyed
1379 int oldx
= window
->x(), oldy
= window
->y();
1380 window
->position(0, 0);
1381 window
->position(oldx
, oldy
);
1382 window
->show(); // recreate the X11 window in support of the FLTK window
1386 case ClientMessage
: {
1387 Atom message
= fl_xevent
->xclient
.message_type
;
1388 const long* data
= fl_xevent
->xclient
.data
.l
;
1389 if ((Atom
)(data
[0]) == WM_DELETE_WINDOW
) {
1391 } else if (message
== fl_XdndEnter
) {
1392 fl_xmousewin
= window
;
1394 fl_dnd_source_window
= data
[0];
1395 // version number is data[1]>>24
1396 // printf("XdndEnter, version %ld\n", data[1] >> 24);
1398 // get list of data types:
1399 Atom actual
; int format
; unsigned long count
, remaining
;
1400 unsigned char *buffer
= 0;
1401 XGetWindowProperty(fl_display
, fl_dnd_source_window
, fl_XdndTypeList
,
1402 0, 0x8000000L
, False
, XA_ATOM
, &actual
, &format
,
1403 &count
, &remaining
, &buffer
);
1404 if (actual
!= XA_ATOM
|| format
!= 32 || count
<4 || !buffer
)
1406 delete [] fl_dnd_source_types
;
1407 fl_dnd_source_types
= new Atom
[count
+1];
1408 for (unsigned i
= 0; i
< count
; i
++) {
1409 fl_dnd_source_types
[i
] = ((Atom
*)buffer
)[i
];
1411 fl_dnd_source_types
[count
] = 0;
1414 // less than four data types, or if the above messes up:
1415 if (!fl_dnd_source_types
) fl_dnd_source_types
= new Atom
[4];
1416 fl_dnd_source_types
[0] = data
[2];
1417 fl_dnd_source_types
[1] = data
[3];
1418 fl_dnd_source_types
[2] = data
[4];
1419 fl_dnd_source_types
[3] = 0;
1422 // Loop through the source types and pick the first text type...
1425 for (i
= 0; fl_dnd_source_types
[i
]; i
++)
1427 // printf("fl_dnd_source_types[%d] = %ld (%s)\n", i,
1428 // fl_dnd_source_types[i],
1429 // XGetAtomName(fl_display, fl_dnd_source_types[i]));
1431 if (!strncmp(XGetAtomName(fl_display
, fl_dnd_source_types
[i
]),
1436 if (fl_dnd_source_types
[i
])
1437 fl_dnd_type
= fl_dnd_source_types
[i
];
1439 fl_dnd_type
= fl_dnd_source_types
[0];
1441 event
= FL_DND_ENTER
;
1442 Fl::e_text
= unknown
;
1443 Fl::e_length
= unknown_len
;
1446 } else if (message
== fl_XdndPosition
) {
1447 fl_xmousewin
= window
;
1449 fl_dnd_source_window
= data
[0];
1450 Fl::e_x_root
= data
[2]>>16;
1451 Fl::e_y_root
= data
[2]&0xFFFF;
1453 Fl::e_x
= Fl::e_x_root
-window
->x();
1454 Fl::e_y
= Fl::e_y_root
-window
->y();
1456 fl_event_time
= data
[3];
1457 fl_dnd_source_action
= data
[4];
1458 fl_dnd_action
= fl_XdndActionCopy
;
1459 Fl::e_text
= unknown
;
1460 Fl::e_length
= unknown_len
;
1461 int accept
= Fl::handle(FL_DND_DRAG
, window
);
1462 fl_sendClientMessage(data
[0], fl_XdndStatus
,
1463 fl_xevent
->xclient
.window
,
1465 0, // used for xy rectangle to not send position inside
1466 0, // used for width+height of rectangle
1467 accept
? fl_dnd_action
: None
);
1470 } else if (message
== fl_XdndLeave
) {
1471 fl_dnd_source_window
= 0; // don't send a finished message to it
1472 event
= FL_DND_LEAVE
;
1473 Fl::e_text
= unknown
;
1474 Fl::e_length
= unknown_len
;
1477 } else if (message
== fl_XdndDrop
) {
1478 fl_xmousewin
= window
;
1480 fl_dnd_source_window
= data
[0];
1481 fl_event_time
= data
[2];
1482 Window to_window
= fl_xevent
->xclient
.window
;
1483 Fl::e_text
= unknown
;
1484 Fl::e_length
= unknown_len
;
1485 if (Fl::handle(FL_DND_RELEASE
, window
)) {
1486 fl_selection_requestor
= Fl::belowmouse();
1487 XConvertSelection(fl_display
, fl_XdndSelection
,
1488 fl_dnd_type
, XA_SECONDARY
,
1489 to_window
, fl_event_time
);
1491 // Send the finished message if I refuse the drop.
1492 // It is not clear whether I can just send finished always,
1493 // or if I have to wait for the SelectionNotify event as the
1494 // code is currently doing.
1495 fl_sendClientMessage(fl_dnd_source_window
, fl_XdndFinished
, to_window
);
1496 fl_dnd_source_window
= 0;
1508 Fl_X::i(window
)->wait_for_expose
= 0;
1510 // try to keep windows on top even if WM_TRANSIENT_FOR does not work:
1511 // opaque move/resize window managers do not like this, so I disabled it.
1512 if (Fl::first_window()->non_modal() && window
!= Fl::first_window())
1513 Fl::first_window()->show();
1516 case GraphicsExpose
:
1517 window
->damage(FL_DAMAGE_EXPOSE
, xevent
.xexpose
.x
, xevent
.xexpose
.y
,
1518 xevent
.xexpose
.width
, xevent
.xexpose
.height
);
1522 if (fl_xim_ic
) XSetICFocus(fl_xim_ic
);
1527 if (fl_xim_ic
) XUnsetICFocus(fl_xim_ic
);
1534 int keycode
= xevent
.xkey
.keycode
;
1535 fl_key_vector
[keycode
/8] |= (1 << (keycode
%8));
1536 static char *buffer
= NULL
;
1537 static int buffer_len
= 0;
1540 if (buffer_len
== 0) {
1542 buffer
= (char*) malloc(buffer_len
);
1544 if (xevent
.type
== KeyPress
) {
1550 len
= XUtf8LookupString(fl_xim_ic
, (XKeyPressedEvent
*)&xevent
.xkey
,
1551 buffer
, buffer_len
, &keysym
, &status
);
1553 while (status
== XBufferOverflow
&& buffer_len
< 50000) {
1554 buffer_len
= buffer_len
* 5 + 1;
1555 buffer
= (char*)realloc(buffer
, buffer_len
);
1556 len
= XUtf8LookupString(fl_xim_ic
, (XKeyPressedEvent
*)&xevent
.xkey
,
1557 buffer
, buffer_len
, &keysym
, &status
);
1559 keysym
= XKeycodeToKeysym(fl_display
, keycode
, 0);
1561 //static XComposeStatus compose;
1562 len
= XLookupString((XKeyEvent
*)&(xevent
.xkey
),
1563 buffer
, buffer_len
, &keysym
, 0/*&compose*/);
1564 if (keysym
&& keysym
< 0x400) { // a character in latin-1,2,3,4 sets
1565 // force it to type a character (not sure if this ever is needed):
1566 // if (!len) {buffer[0] = char(keysym); len = 1;}
1567 len
= fl_utf8encode(XKeysymToUcs(keysym
), buffer
);
1568 if (len
< 1) len
= 1;
1569 // ignore all effects of shift on the keysyms, which makes it a lot
1570 // easier to program shortcuts and is Windoze-compatible:
1571 keysym
= XKeycodeToKeysym(fl_display
, keycode
, 0);
1574 // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not
1575 // set until set_event_xy() is called later...
1576 if ((xevent
.xkey
.state
& ControlMask
) && keysym
== '-') buffer
[0] = 0x1f; // ^_
1578 Fl::e_text
= buffer
;
1581 // Stupid X sends fake key-up events when a repeating key is held
1582 // down, probably due to some back compatibility problem. Fortunately
1583 // we can detect this because the repeating KeyPress event is in
1584 // the queue, get it and execute it instead:
1586 // Bool XkbSetDetectableAutorepeat ( display, detectable, supported_rtrn )
1587 // Display * display ;
1588 // Bool detectable ;
1589 // Bool * supported_rtrn ;
1590 // ...would be the easy way to corrct this isuue. Unfortunatly, this call is also
1591 // broken on many Unix distros including Ubuntu and Solaris (as of Dec 2009)
1593 // Bogus KeyUp events are generated by repeated KeyDown events. One
1594 // neccessary condition is an identical key event pending right after
1596 // The new code introduced Dec 2009 differs in that it only check the very
1597 // next event in the queue, not the entire queue of events.
1598 // This function wrongly detects a repeat key if a software keyboard
1599 // sends a burst of events containing two consecutive equal keys. However,
1600 // in every non-gaming situation, this is no problem because both KeyPress
1601 // events will cause the expected behavior.
1603 if (XPending(fl_display
)) {
1604 XPeekEvent(fl_display
, &peekevent
);
1605 if ( (peekevent
.type
== KeyPress
) // must be a KeyPress event
1606 && (peekevent
.xkey
.keycode
== xevent
.xkey
.keycode
) // must be the same key
1607 && (peekevent
.xkey
.time
== xevent
.xkey
.time
) // must be sent at the exact same time
1609 XNextEvent(fl_display
, &xevent
);
1615 fl_key_vector
[keycode
/8] &= ~(1 << (keycode
%8));
1616 // keyup events just get the unshifted keysym:
1617 keysym
= XKeycodeToKeysym(fl_display
, keycode
, 0);
1620 // You can plug a microsoft keyboard into an sgi but the extra shift
1621 // keys are not translated. Make them translate like XFree86 does:
1622 if (!keysym
) switch(keycode
) {
1623 case 147: keysym
= FL_Meta_L
; break;
1624 case 148: keysym
= FL_Meta_R
; break;
1625 case 149: keysym
= FL_Menu
; break;
1629 // Attempt to fix keyboards that send "delete" for the key in the
1630 // upper-right corner of the main keyboard. But it appears that
1631 // very few of these remain?
1632 static int got_backspace
= 0;
1633 if (!got_backspace
) {
1634 if (keysym
== FL_Delete
) keysym
= FL_BackSpace
;
1635 else if (keysym
== FL_BackSpace
) got_backspace
= 1;
1638 // For the first few years, there wasn't a good consensus on what the
1639 // Windows keys should be mapped to for X11. So we need to help out a
1640 // bit and map all variants to the same FLTK key...
1653 // Convert the multimedia keys to safer, portable values
1654 switch (keysym
) { // XF names come from X11/XF86keysym.h
1655 case 0x1008FF11: // XF86XK_AudioLowerVolume:
1656 keysym
= FL_Volume_Down
;
1658 case 0x1008FF12: // XF86XK_AudioMute:
1659 keysym
= FL_Volume_Mute
;
1661 case 0x1008FF13: // XF86XK_AudioRaiseVolume:
1662 keysym
= FL_Volume_Up
;
1664 case 0x1008FF14: // XF86XK_AudioPlay:
1665 keysym
= FL_Media_Play
;
1667 case 0x1008FF15: // XF86XK_AudioStop:
1668 keysym
= FL_Media_Stop
;
1670 case 0x1008FF16: // XF86XK_AudioPrev:
1671 keysym
= FL_Media_Prev
;
1673 case 0x1008FF17: // XF86XK_AudioNext:
1674 keysym
= FL_Media_Next
;
1676 case 0x1008FF18: // XF86XK_HomePage:
1677 keysym
= FL_Home_Page
;
1679 case 0x1008FF19: // XF86XK_Mail:
1682 case 0x1008FF1B: // XF86XK_Search:
1685 case 0x1008FF26: // XF86XK_Back:
1688 case 0x1008FF27: // XF86XK_Forward:
1689 keysym
= FL_Forward
;
1691 case 0x1008FF28: // XF86XK_Stop:
1694 case 0x1008FF29: // XF86XK_Refresh:
1695 keysym
= FL_Refresh
;
1697 case 0x1008FF2F: // XF86XK_Sleep:
1700 case 0x1008FF30: // XF86XK_Favorites:
1701 keysym
= FL_Favorites
;
1704 // We have to get rid of the XK_KP_function keys, because they are
1705 // not produced on Windoze and thus case statements tend not to check
1706 // for them. There are 15 of these in the range 0xff91 ... 0xff9f
1707 if (keysym
>= 0xff91 && keysym
<= 0xff9f) {
1708 // Map keypad keysym to character or keysym depending on
1710 unsigned long keysym1
= XKeycodeToKeysym(fl_display
, keycode
, 1);
1711 if (keysym1
<= 0x7f || (keysym1
> 0xff9f && keysym1
<= FL_KP_Last
))
1712 Fl::e_original_keysym
= (int)(keysym1
| FL_KP
);
1713 if ((xevent
.xkey
.state
& Mod2Mask
) &&
1714 (keysym1
<= 0x7f || (keysym1
> 0xff9f && keysym1
<= FL_KP_Last
))) {
1715 // Store ASCII numeric keypad value...
1716 keysym
= keysym1
| FL_KP
;
1717 buffer
[0] = char(keysym1
) & 0x7F;
1720 // Map keypad to special key...
1721 static const unsigned short table
[15] = {
1722 FL_F
+1, FL_F
+2, FL_F
+3, FL_F
+4,
1723 FL_Home
, FL_Left
, FL_Up
, FL_Right
,
1724 FL_Down
, FL_Page_Up
, FL_Page_Down
, FL_End
,
1725 0xff0b/*XK_Clear*/, FL_Insert
, FL_Delete
};
1726 keysym
= table
[keysym
-0xff91];
1729 // Store this so we can later know if the KP was used
1730 Fl::e_original_keysym
= (int)keysym
;
1732 Fl::e_keysym
= int(keysym
);
1734 // replace XK_ISO_Left_Tab (Shift-TAB) with FL_Tab (modifier flags are set correctly by X11)
1735 if (Fl::e_keysym
== 0xfe20) Fl::e_keysym
= FL_Tab
;
1742 Fl::e_keysym
= FL_Button
+ xevent
.xbutton
.button
;
1744 if (xevent
.xbutton
.button
== Button4
) {
1745 Fl::e_dy
= -1; // Up
1747 event
= FL_MOUSEWHEEL
;
1748 } else if (xevent
.xbutton
.button
== Button5
) {
1749 Fl::e_dy
= +1; // Down
1751 event
= FL_MOUSEWHEEL
;
1752 } else if (xevent
.xbutton
.button
== 6) {
1754 Fl::e_dx
= -1; // Left
1755 event
= FL_MOUSEWHEEL
;
1756 } else if (xevent
.xbutton
.button
== 7) {
1758 Fl::e_dx
= +1; // Right
1759 event
= FL_MOUSEWHEEL
;
1761 Fl::e_state
|= (FL_BUTTON1
<< (xevent
.xbutton
.button
-1));
1766 fl_xmousewin
= window
;
1772 # if CONSOLIDATE_MOTION
1773 send_motion
= fl_xmousewin
= window
;
1778 fl_xmousewin
= window
;
1784 Fl::e_keysym
= FL_Button
+ xevent
.xbutton
.button
;
1786 Fl::e_state
&= ~(FL_BUTTON1
<< (xevent
.xbutton
.button
-1));
1787 if (xevent
.xbutton
.button
== Button4
||
1788 xevent
.xbutton
.button
== Button5
||
1789 xevent
.xbutton
.button
== 6 ||
1790 xevent
.xbutton
.button
== 7) return 0;
1793 fl_xmousewin
= window
;
1798 if (xevent
.xcrossing
.detail
== NotifyInferior
) break;
1799 // XInstallColormap(fl_display, Fl_X::i(window)->colormap);
1801 Fl::e_state
= xevent
.xcrossing
.state
<< 16;
1804 fl_xmousewin
= window
;
1806 { XIMStyles
*xim_styles
= NULL
;
1807 if(!fl_xim_im
|| XGetIMValues(fl_xim_im
, XNQueryInputStyle
, &xim_styles
, NULL
, NULL
)) {
1810 if (xim_styles
) XFree(xim_styles
);
1815 if (xevent
.xcrossing
.detail
== NotifyInferior
) break;
1817 Fl::e_state
= xevent
.xcrossing
.state
<< 16;
1819 in_a_window
= false; // make do_queued_events produce FL_LEAVE event
1822 // We cannot rely on the x,y position in the configure notify event.
1823 // I now think this is an unavoidable problem with X: it is impossible
1824 // for a window manager to prevent the "real" notify event from being
1825 // sent when it resizes the contents, even though it can send an
1826 // artificial event with the correct position afterwards (and some
1827 // window managers do not send this fake event anyway)
1828 // So anyway, do a round trip to find the correct x,y:
1833 case ConfigureNotify
: {
1834 if (window
->parent()) break; // ignore child windows
1836 // figure out where OS really put window
1837 XWindowAttributes actual
;
1838 XGetWindowAttributes(fl_display
, fl_xid(window
), &actual
);
1839 Window cr
; int X
, Y
, W
= actual
.width
, H
= actual
.height
;
1840 XTranslateCoordinates(fl_display
, fl_xid(window
), actual
.root
,
1843 // tell Fl_Window about it and set flag to prevent echoing:
1844 resize_bug_fix
= window
;
1845 window
->resize(X
, Y
, W
, H
);
1846 break; // allow add_handler to do something too
1849 case ReparentNotify
: {
1853 // on some systems, the ReparentNotify event is not handled as we would expect.
1854 XErrorHandler oldHandler
= XSetErrorHandler(catchXExceptions());
1856 //ReparentNotify gives the new position of the window relative to
1857 //the new parent. FLTK cares about the position on the root window.
1858 XTranslateCoordinates(fl_display
, xevent
.xreparent
.parent
,
1859 XRootWindow(fl_display
, fl_screen
),
1860 xevent
.xreparent
.x
, xevent
.xreparent
.y
,
1861 &xpos
, &ypos
, &junk
);
1862 XSetErrorHandler(oldHandler
);
1864 // tell Fl_Window about it and set flag to prevent echoing:
1865 if ( !wasXExceptionRaised() ) {
1866 resize_bug_fix
= window
;
1867 window
->position(xpos
, ypos
);
1873 return Fl::handle(event
, window
);
1876 ////////////////////////////////////////////////////////////////
1878 void Fl_Window::resize(int X
,int Y
,int W
,int H
) {
1879 int is_a_move
= (X
!= x() || Y
!= y());
1880 int is_a_resize
= (W
!= w() || H
!= h());
1881 int is_a_enlarge
= (W
> w() || H
> h());
1882 int resize_from_program
= (this != resize_bug_fix
);
1883 if (!resize_from_program
) resize_bug_fix
= 0;
1884 if (is_a_move
&& resize_from_program
) set_flag(FORCE_POSITION
);
1885 else if (!is_a_resize
&& !is_a_move
) return;
1887 Fl_Group::resize(X
,Y
,W
,H
);
1888 if (shown()) {redraw(); if(is_a_enlarge
) i
->wait_for_expose
= 1;}
1893 if (resize_from_program
&& is_a_resize
&& !resizable()) {
1894 size_range(w(), h(), w(), h());
1897 if (resize_from_program
&& shown()) {
1899 if (!resizable()) size_range(w(),h(),w(),h());
1901 XMoveResizeWindow(fl_display
, i
->xid
, X
, Y
, W
>0 ? W
: 1, H
>0 ? H
: 1);
1903 XResizeWindow(fl_display
, i
->xid
, W
>0 ? W
: 1, H
>0 ? H
: 1);
1906 XMoveWindow(fl_display
, i
->xid
, X
, Y
);
1909 if ( is_a_resize
&& i
)
1910 i
->cairo_surface_invalid
= 1;
1913 ////////////////////////////////////////////////////////////////
1915 // A subclass of Fl_Window may call this to associate an X window it
1916 // creates with the Fl_Window:
1918 void fl_fix_focus(); // in Fl.cxx
1920 Fl_X
* Fl_X::set_xid(Fl_Window
* win
, Window winxid
) {
1921 Fl_X
* xp
= new Fl_X
;
1924 cairo_surface_t
*cs
= Fl::cairo_create_surface( winxid
, win
->w(), win
->h() );
1925 xp
->cc
= cairo_create( cs
);
1926 cairo_surface_destroy( cs
);
1927 xp
->cairo_surface_invalid
= 0;
1930 xp
->next
= Fl_X::first
;
1932 xp
->wait_for_expose
= 1;
1933 // xp->backbuffer_bad = 1;
1935 if (win
->modal()) {Fl::modal_
= win
; fl_fix_focus();}
1939 // More commonly a subclass calls this, because it hides the really
1940 // ugly parts of X and sets all the stuff for a window that is set
1941 // normally. The global variables like fl_show_iconic are so that
1942 // subclasses of *that* class may change the behavior...
1944 char fl_show_iconic
; // hack for iconize()
1945 int fl_background_pixel
= -1; // hack to speed up bg box drawing
1946 int fl_disable_transient_for
; // secret method of removing TRANSIENT_FOR
1948 static const int childEventMask
= ExposureMask
;
1950 static const int XEventMask
=
1951 ExposureMask
|StructureNotifyMask
1952 |KeyPressMask
|KeyReleaseMask
|KeymapStateMask
|FocusChangeMask
1953 |ButtonPressMask
|ButtonReleaseMask
1954 |EnterWindowMask
|LeaveWindowMask
1957 static const int XEmbedEventMask
= XEventMask
|
1958 SubstructureRedirectMask
|
1959 SubstructureNotifyMask
|
1962 void Fl_X::make_xid(Fl_Window
* win
, XVisualInfo
*visual
, Colormap colormap
)
1964 Fl_Group::current(0); // get rid of very common user bug: forgot end()
1969 if (W
<= 0) W
= 1; // X don't like zero...
1971 if (H
<= 0) H
= 1; // X don't like zero...
1972 if (!win
->parent() && !Fl::grab()) {
1973 // center windows in case window manager does not do anything:
1974 #ifdef FL_CENTER_WINDOWS
1975 if (!(win
->flags() & Fl_Widget::FORCE_POSITION
)) {
1976 win
->x(X
= scr_x
+(scr_w
-W
)/2);
1977 win
->y(Y
= scr_y
+(scr_h
-H
)/2);
1979 #endif // FL_CENTER_WINDOWS
1981 // force the window to be on-screen. Usually the X window manager
1982 // does this, but a few don't, so we do it here for consistency:
1983 int scr_x
, scr_y
, scr_w
, scr_h
;
1984 Fl::screen_xywh(scr_x
, scr_y
, scr_w
, scr_h
, X
, Y
);
1986 if (win
->border()) {
1987 // ensure border is on screen:
1988 // (assume extremely minimal dimensions for this border)
1991 const int right
= 1;
1992 const int bottom
= 1;
1993 if (X
+W
+right
> scr_x
+scr_w
) X
= scr_x
+scr_w
-right
-W
;
1994 if (X
-left
< scr_x
) X
= scr_x
+left
;
1995 if (Y
+H
+bottom
> scr_y
+scr_h
) Y
= scr_y
+scr_h
-bottom
-H
;
1996 if (Y
-top
< scr_y
) Y
= scr_y
+top
;
1998 // now insure contents are on-screen (more important than border):
1999 if (X
+W
> scr_x
+scr_w
) X
= scr_x
+scr_w
-W
;
2000 if (X
< scr_x
) X
= scr_x
;
2001 if (Y
+H
> scr_y
+scr_h
) Y
= scr_y
+scr_h
-H
;
2002 if (Y
< scr_y
) Y
= scr_y
;
2005 // if the window is a subwindow and our parent is not mapped yet, we
2006 // mark this window visible, so that mapping the parent at a later
2007 // point in time will call this function again to finally map the subwindow.
2008 if (win
->parent() && !Fl_X::i(win
->window())) {
2013 ulong root
= win
->parent() ?
2014 fl_xid(win
->window()) : RootWindow(fl_display
, fl_screen
);
2016 if ( fl_parent_window
)
2017 root
= fl_parent_window
;
2019 XSetWindowAttributes attr
;
2020 int mask
= CWBorderPixel
|CWColormap
|CWEventMask
|CWBitGravity
;
2021 attr
.event_mask
= win
->parent() ? childEventMask
: XEventMask
;
2023 if ( Fl_Socket_Window::is_socket( win
) )
2024 attr
.event_mask
= XEmbedEventMask
;
2026 attr
.colormap
= colormap
;
2027 attr
.border_pixel
= 0;
2028 attr
.bit_gravity
= 0; // StaticGravity;
2029 if (win
->override()) {
2030 attr
.override_redirect
= 1;
2031 attr
.save_under
= 1;
2032 mask
|= CWOverrideRedirect
| CWSaveUnder
;
2033 } else attr
.override_redirect
= 0;
2035 attr
.save_under
= 1; mask
|= CWSaveUnder
;
2036 if (!win
->border()) {attr
.override_redirect
= 1; mask
|= CWOverrideRedirect
;}
2038 if (fl_background_pixel
>= 0) {
2039 attr
.background_pixel
= fl_background_pixel
;
2040 fl_background_pixel
= -1;
2041 mask
|= CWBackPixel
;
2045 set_xid(win
, XCreateWindow(fl_display
,
2055 if (!win
->parent() && !attr
.override_redirect
) {
2056 // Communicate all kinds 'o junk to the X Window Manager:
2058 win
->label(win
->label(), win
->iconlabel());
2060 XChangeProperty(fl_display
, xp
->xid
, WM_PROTOCOLS
,
2061 XA_ATOM
, 32, 0, (uchar
*)&WM_DELETE_WINDOW
, 1);
2063 // send size limits and border:
2066 // set the class property, which controls the icon used:
2067 if (win
->xclass()) {
2069 char *p
; const char *q
;
2070 // replace punctuation with underscores, because it breaks XResource lookup
2071 for (p
= buffer
, q
= win
->xclass(); *q
|| (*q
&128); q
++)
2072 *p
++ = isalnum(*q
) || *q
== '-' || *q
== ' ' ? *q
: '_';
2074 // create the capitalized version:
2076 *p
= toupper(*q
++); if (*p
++ == 'X') *p
++ = toupper(*q
++);
2077 while ((*p
++ = *q
++));
2078 XChangeProperty(fl_display
, xp
->xid
, XA_WM_CLASS
, XA_STRING
, 8, 0,
2079 (unsigned char *)buffer
, p
-buffer
-1);
2082 if (win
->non_modal() && xp
->next
&& !fl_disable_transient_for
) {
2083 // find some other window to be "transient for":
2084 Fl_Window
* wp
= xp
->next
->w
;
2085 while (wp
->parent()) wp
= wp
->window();
2086 XSetTransientForHint(fl_display
, xp
->xid
, fl_xid(wp
));
2087 if (!wp
->visible()) showit
= 0; // guess that wm will not show it
2090 // Make sure that borderless windows do not show in the task bar
2091 if (!win
->border()) {
2092 Atom net_wm_state
= XInternAtom (fl_display
, "_NET_WM_STATE", 0);
2093 Atom net_wm_state_skip_taskbar
= XInternAtom (fl_display
, "_NET_WM_STATE_SKIP_TASKBAR", 0);
2094 XChangeProperty (fl_display
, xp
->xid
, net_wm_state
, XA_ATOM
, 32,
2095 PropModeAppend
, (unsigned char*) &net_wm_state_skip_taskbar
, 1);
2098 // Make it receptive to DnD:
2100 XChangeProperty(fl_display
, xp
->xid
, fl_XdndAware
,
2101 XA_ATOM
, sizeof(int)*8, 0, (unsigned char*)&version
, 1);
2103 XWMHints
*hints
= XAllocWMHints();
2104 hints
->input
= True
;
2105 hints
->flags
= InputHint
;
2106 if (fl_show_iconic
) {
2107 hints
->flags
|= StateHint
;
2108 hints
->initial_state
= IconicState
;
2113 hints
->icon_pixmap
= (Pixmap
)win
->icon();
2114 hints
->flags
|= IconPixmapHint
;
2116 XSetWMHints(fl_display
, xp
->xid
, hints
);
2120 // set the window type for menu and tooltip windows to avoid animations (compiz)
2121 if (win
->menu_window() || win
->tooltip_window()) {
2122 Atom net_wm_type
= XInternAtom(fl_display
, "_NET_WM_WINDOW_TYPE", False
);
2123 Atom net_wm_type_kind
= XInternAtom(fl_display
, "_NET_WM_WINDOW_TYPE_MENU", False
);
2124 XChangeProperty(fl_display
, xp
->xid
, net_wm_type
, XA_ATOM
, 32, PropModeReplace
, (unsigned char*)&net_wm_type_kind
, 1);
2127 XMapWindow(fl_display
, xp
->xid
);
2130 int old_event
= Fl::e_number
;
2131 win
->handle(Fl::e_number
= FL_SHOW
); // get child windows to appear
2132 Fl::e_number
= old_event
;
2137 ////////////////////////////////////////////////////////////////
2138 // Send X window stuff that can be changed over time:
2140 void Fl_X::sendxjunk() {
2141 if (w
->parent() || w
->override()) return; // it's not a window manager window!
2143 if (!w
->size_range_set
) { // default size_range based on resizable():
2144 if (w
->resizable()) {
2145 Fl_Widget
*o
= w
->resizable();
2146 int minw
= o
->w(); if (minw
> 100) minw
= 100;
2147 int minh
= o
->h(); if (minh
> 100) minh
= 100;
2148 w
->size_range(w
->w() - o
->w() + minw
, w
->h() - o
->h() + minh
, 0, 0);
2150 w
->size_range(w
->w(), w
->h(), w
->w(), w
->h());
2152 return; // because this recursively called here
2155 XSizeHints
*hints
= XAllocSizeHints();
2156 // memset(&hints, 0, sizeof(hints)); jreiser suggestion to fix purify?
2157 hints
->min_width
= w
->minw
;
2158 hints
->min_height
= w
->minh
;
2159 hints
->max_width
= w
->maxw
;
2160 hints
->max_height
= w
->maxh
;
2161 hints
->width_inc
= w
->dw
;
2162 hints
->height_inc
= w
->dh
;
2163 hints
->win_gravity
= StaticGravity
;
2165 // see the file /usr/include/X11/Xm/MwmUtil.h:
2166 // fill all fields to avoid bugs in kwm and perhaps other window managers:
2167 // 0, MWM_FUNC_ALL, MWM_DECOR_ALL
2168 long prop
[5] = {0, 1, 1, 0, 0};
2170 if (hints
->min_width
!= hints
->max_width
||
2171 hints
->min_height
!= hints
->max_height
) { // resizable
2172 hints
->flags
= PMinSize
|PWinGravity
;
2173 if (hints
->max_width
>= hints
->min_width
||
2174 hints
->max_height
>= hints
->min_height
) {
2175 hints
->flags
= PMinSize
|PMaxSize
|PWinGravity
;
2176 // unfortunately we can't set just one maximum size. Guess a
2177 // value for the other one. Some window managers will make the
2178 // window fit on screen when maximized, others will put it off screen:
2179 if (hints
->max_width
< hints
->min_width
) hints
->max_width
= Fl::w();
2180 if (hints
->max_height
< hints
->min_height
) hints
->max_height
= Fl::h();
2182 if (hints
->width_inc
&& hints
->height_inc
) hints
->flags
|= PResizeInc
;
2184 // stupid X! It could insist that the corner go on the
2185 // straight line between min and max...
2186 hints
->min_aspect
.x
= hints
->max_aspect
.x
= hints
->min_width
;
2187 hints
->min_aspect
.y
= hints
->max_aspect
.y
= hints
->min_height
;
2188 hints
->flags
|= PAspect
;
2190 } else { // not resizable:
2191 hints
->flags
= PMinSize
|PMaxSize
|PWinGravity
;
2192 prop
[0] = 1; // MWM_HINTS_FUNCTIONS
2193 prop
[1] = 1|2|16; // MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE
2196 if (w
->flags() & Fl_Widget::FORCE_POSITION
) {
2197 hints
->flags
|= USPosition
;
2203 prop
[0] |= 2; // MWM_HINTS_DECORATIONS
2204 prop
[2] = 0; // no decorations
2207 XSetWMNormalHints(fl_display
, xid
, hints
);
2208 XChangeProperty(fl_display
, xid
,
2209 fl_MOTIF_WM_HINTS
, fl_MOTIF_WM_HINTS
,
2210 32, 0, (unsigned char *)prop
, 5);
2214 void Fl_Window::size_range_() {
2216 if (shown()) i
->sendxjunk();
2219 ////////////////////////////////////////////////////////////////
2221 // returns pointer to the filename, or null if name ends with '/'
2222 const char *fl_filename_name(const char *name
) {
2224 if (!name
) return (0);
2225 for (p
=q
=name
; *p
;) if (*p
++ == '/') q
= p
;
2229 void Fl_Window::label(const char *name
,const char *iname
) {
2230 Fl_Widget::label(name
);
2232 if (shown() && !parent()) {
2233 if (!name
) name
= "";
2234 int namelen
= strlen(name
);
2235 if (!iname
) iname
= fl_filename_name(name
);
2236 int inamelen
= strlen(iname
);
2237 XChangeProperty(fl_display
, i
->xid
, fl_NET_WM_NAME
, fl_XaUtf8String
, 8, 0, (uchar
*)name
, namelen
); // utf8
2238 XChangeProperty(fl_display
, i
->xid
, XA_WM_NAME
, XA_STRING
, 8, 0, (uchar
*)name
, namelen
); // non-utf8
2239 XChangeProperty(fl_display
, i
->xid
, fl_NET_WM_ICON_NAME
, fl_XaUtf8String
, 8, 0, (uchar
*)iname
, inamelen
); // utf8
2240 XChangeProperty(fl_display
, i
->xid
, XA_WM_ICON_NAME
, XA_STRING
, 8, 0, (uchar
*)iname
, inamelen
); // non-utf8
2244 ////////////////////////////////////////////////////////////////
2245 // Implement the virtual functions for the base Fl_Window class:
2247 // If the box is a filled rectangle, we can make the redisplay *look*
2248 // faster by using X's background pixel erasing. We can make it
2249 // actually *be* faster by drawing the frame only, this is done by
2250 // setting fl_boxcheat, which is seen by code in fl_drawbox.cxx:
2252 // On XFree86 (and prehaps all X's) this has a problem if the window
2253 // is resized while a save-behind window is atop it. The previous
2254 // contents are restored to the area, but this assumes the area
2255 // is cleared to background color. So this is disabled in this version.
2256 // Fl_Window *fl_boxcheat;
2257 static inline int can_boxcheat(uchar b
) {return (b
==1 || ((b
&2) && b
<=15));}
2259 void Fl_Window::show() {
2260 image(Fl::scheme_bg_
);
2261 if (Fl::scheme_bg_
) {
2262 // labeltype(FL_NORMAL_LABEL);
2263 align(FL_ALIGN_IMAGE_BACKDROP
);
2266 labeltype(FL_NO_LABEL
);
2268 Fl_Tooltip::exit(this);
2272 /* // Don't set background pixel for double-buffered windows... */
2273 /* if (type() == FL_WINDOW && can_boxcheat(box())) { */
2274 /* fl_background_pixel = int(fl_xpixel(color())); */
2277 Fl_X::make_xid(this);
2279 XMapRaised(fl_display
, i
->xid
);
2281 #ifdef USE_PRINT_BUTTON
2282 void preparePrintFront(void);
2283 preparePrintFront();
2288 Fl_Window
*Fl_Window::current_
;
2291 // make X drawing go into this window (called by subclass flush() impl.)
2292 void Fl_Window::make_current() {
2293 static GC gc
; // the GC used by all X windows
2294 if (!gc
) gc
= XCreateGC(fl_display
, i
->xid
, 0, 0);
2298 if ( i
->cairo_surface_invalid
&& i
->cc
)
2300 cairo_destroy( i
->cc
); i
->cc
= 0;
2305 cairo_surface_t
*cs
= Fl::cairo_create_surface( i
->xid
, w(), h() );
2306 i
->cc
= cairo_create( cs
);
2307 cairo_surface_destroy( cs
);
2310 Fl::cairo_make_current( i
->cc
);
2314 fl_clip_region(i
->region
);
2317 Window
fl_xid_(const Fl_Window
*w
) {
2318 Fl_X
*temp
= Fl_X::i(w
);
2319 return temp
? temp
->xid
: 0;
2322 static void decorated_win_size(Fl_Window
*win
, int &w
, int &h
)
2326 if (!win
->shown() || win
->parent() || !win
->border() || !win
->visible()) return;
2327 Window root
, parent
, *children
;
2329 Status status
= XQueryTree(fl_display
, Fl_X::i(win
)->xid
, &root
, &parent
, &children
, &n
);
2330 if (status
!= 0 && n
) XFree(children
);
2331 // when compiz is used, root and parent are the same window
2332 // and I don't know where to find the window decoration
2333 if (status
== 0 || root
== parent
) return;
2334 XWindowAttributes attributes
;
2335 XGetWindowAttributes(fl_display
, parent
, &attributes
);
2336 w
= attributes
.width
;
2337 h
= attributes
.height
;
2340 int Fl_Window::decorated_h()
2343 decorated_win_size(this, w
, h
);
2347 int Fl_Window::decorated_w()
2350 decorated_win_size(this, w
, h
);
2354 void Fl_Paged_Device::print_window(Fl_Window
*win
, int x_offset
, int y_offset
)
2356 if (!win
->shown() || win
->parent() || !win
->border() || !win
->visible()) {
2357 this->print_widget(win
, x_offset
, y_offset
);
2360 Fl_Display_Device::display_device()->set_current();
2363 win
->make_current();
2364 Window root
, parent
, *children
, child_win
, from
;
2368 do_it
= (XQueryTree(fl_display
, fl_window
, &root
, &parent
, &children
, &n
) != 0 &&
2369 XTranslateCoordinates(fl_display
, fl_window
, parent
, 0, 0, &bx
, &bt
, &child_win
) == True
);
2370 if (n
) XFree(children
);
2371 // hack to bypass STR #2648: when compiz is used, root and parent are the same window
2372 // and I don't know where to find the window decoration
2373 if (do_it
&& root
== parent
) do_it
= 0;
2375 this->set_current();
2376 this->print_widget(win
, x_offset
, y_offset
);
2380 uchar
*top_image
= 0, *left_image
= 0, *right_image
= 0, *bottom_image
= 0;
2381 top_image
= fl_read_image(NULL
, 0, 0, - (win
->w() + 2 * bx
), bt
);
2383 left_image
= fl_read_image(NULL
, 0, bt
, -bx
, win
->h() + bx
);
2384 right_image
= fl_read_image(NULL
, win
->w() + bx
, bt
, -bx
, win
->h() + bx
);
2385 bottom_image
= fl_read_image(NULL
, 0, bt
+ win
->h(), -(win
->w() + 2*bx
), bx
);
2388 this->set_current();
2390 fl_draw_image(top_image
, x_offset
, y_offset
, win
->w() + 2 * bx
, bt
, 3);
2394 if (left_image
) fl_draw_image(left_image
, x_offset
, y_offset
+ bt
, bx
, win
->h() + bx
, 3);
2395 if (right_image
) fl_draw_image(right_image
, x_offset
+ win
->w() + bx
, y_offset
+ bt
, bx
, win
->h() + bx
, 3);
2396 if (bottom_image
) fl_draw_image(bottom_image
, x_offset
, y_offset
+ bt
+ win
->h(), win
->w() + 2*bx
, bx
, 3);
2397 if (left_image
) delete[] left_image
;
2398 if (right_image
) delete[] right_image
;
2399 if (bottom_image
) delete[] bottom_image
;
2401 this->print_widget( win
, x_offset
+ bx
, y_offset
+ bt
);
2404 #ifdef USE_PRINT_BUTTON
2405 // to test the Fl_Printer class creating a "Print front window" button in a separate window
2406 // contains also preparePrintFront call above
2407 #include <FL/Fl_Printer.H>
2408 #include <FL/Fl_Button.H>
2409 void printFront(Fl_Widget
*o
, void *data
)
2412 o
->window()->hide();
2413 Fl_Window
*win
= Fl::first_window();
2416 if( printer
.start_job(1) ) { o
->window()->show(); return; }
2417 if( printer
.start_page() ) { o
->window()->show(); return; }
2418 printer
.printable_rect(&w
,&h
);
2419 // scale the printer device so that the window fits on the page
2421 int ww
= win
->decorated_w();
2422 int wh
= win
->decorated_h();
2423 if (ww
> w
|| wh
> h
) {
2424 scale
= (float)w
/ww
;
2425 if ((float)h
/wh
< scale
) scale
= (float)h
/wh
;
2426 printer
.scale(scale
, scale
);
2429 // #define ROTATE 20.0
2431 printer
.scale(scale
* 0.8, scale
* 0.8);
2432 printer
.printable_rect(&w
, &h
);
2433 printer
.origin(w
/2, h
/2 );
2434 printer
.rotate(ROTATE
);
2435 printer
.print_widget( win
, - win
->w()/2, - win
->h()/2 );
2436 //printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 );
2438 printer
.print_window(win
);
2443 o
->window()->show();
2446 void preparePrintFront(void)
2451 static Fl_Window
w(0,0,150,30);
2452 static Fl_Button
b(0,0,w
.w(),w
.h(), "Print front window");
2453 b
.callback(printFront
);
2457 #endif // USE_PRINT_BUTTON
2462 // End of "$Id: Fl_x.cxx 8764 2011-05-30 16:47:48Z manolo $".