|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_x.cxx 8198 2011-01-06 10:24:58Z manolo $" 00003 // 00004 // X specific code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #ifdef WIN32 00029 //# include "Fl_win32.cxx" 00030 #elif defined(__APPLE__) 00031 //# include "Fl_mac.cxx" 00032 #elif !defined(FL_DOXYGEN) 00033 00034 # define CONSOLIDATE_MOTION 1 00035 /**** Define this if your keyboard lacks a backspace key... ****/ 00036 /* #define BACKSPACE_HACK 1 */ 00037 00038 # include <config.h> 00039 # include <FL/Fl.H> 00040 # include <FL/x.H> 00041 # include <FL/Fl_Window.H> 00042 # include <FL/fl_utf8.h> 00043 # include <FL/Fl_Tooltip.H> 00044 # include <FL/fl_draw.H> 00045 # include <stdio.h> 00046 # include <stdlib.h> 00047 # include "flstring.h" 00048 # include <unistd.h> 00049 # include <sys/time.h> 00050 # include <X11/Xmd.h> 00051 # include <X11/Xlocale.h> 00052 # include <X11/Xlib.h> 00053 00054 static Fl_Xlib_Graphics_Driver fl_xlib_driver; 00055 static Fl_Display_Device fl_xlib_display(&fl_xlib_driver); 00056 FL_EXPORT Fl_Display_Device *fl_display_device = (Fl_Display_Device*)&fl_xlib_display; // does not change 00057 FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver = (Fl_Graphics_Driver*)&fl_xlib_driver; // the current target device of graphics operations 00058 FL_EXPORT Fl_Surface_Device *fl_surface = (Fl_Surface_Device*)fl_display_device; // the current target surface of graphics operations 00059 00061 // interface to poll/select call: 00062 00063 # if USE_POLL 00064 00065 # include <poll.h> 00066 static pollfd *pollfds = 0; 00067 00068 # else 00069 # if HAVE_SYS_SELECT_H 00070 # include <sys/select.h> 00071 # endif /* HAVE_SYS_SELECT_H */ 00072 00073 // The following #define is only needed for HP-UX 9.x and earlier: 00074 //#define select(a,b,c,d,e) select((a),(int *)(b),(int *)(c),(int *)(d),(e)) 00075 00076 static fd_set fdsets[3]; 00077 static int maxfd; 00078 # define POLLIN 1 00079 # define POLLOUT 4 00080 # define POLLERR 8 00081 00082 # endif /* USE_POLL */ 00083 00084 static int nfds = 0; 00085 static int fd_array_size = 0; 00086 struct FD { 00087 # if !USE_POLL 00088 int fd; 00089 short events; 00090 # endif 00091 void (*cb)(int, void*); 00092 void* arg; 00093 }; 00094 00095 static FD *fd = 0; 00096 00097 void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { 00098 remove_fd(n,events); 00099 int i = nfds++; 00100 if (i >= fd_array_size) { 00101 FD *temp; 00102 fd_array_size = 2*fd_array_size+1; 00103 00104 if (!fd) temp = (FD*)malloc(fd_array_size*sizeof(FD)); 00105 else temp = (FD*)realloc(fd, fd_array_size*sizeof(FD)); 00106 00107 if (!temp) return; 00108 fd = temp; 00109 00110 # if USE_POLL 00111 pollfd *tpoll; 00112 00113 if (!pollfds) tpoll = (pollfd*)malloc(fd_array_size*sizeof(pollfd)); 00114 else tpoll = (pollfd*)realloc(pollfds, fd_array_size*sizeof(pollfd)); 00115 00116 if (!tpoll) return; 00117 pollfds = tpoll; 00118 # endif 00119 } 00120 fd[i].cb = cb; 00121 fd[i].arg = v; 00122 # if USE_POLL 00123 pollfds[i].fd = n; 00124 pollfds[i].events = events; 00125 # else 00126 fd[i].fd = n; 00127 fd[i].events = events; 00128 if (events & POLLIN) FD_SET(n, &fdsets[0]); 00129 if (events & POLLOUT) FD_SET(n, &fdsets[1]); 00130 if (events & POLLERR) FD_SET(n, &fdsets[2]); 00131 if (n > maxfd) maxfd = n; 00132 # endif 00133 } 00134 00135 void Fl::add_fd(int n, void (*cb)(int, void*), void* v) { 00136 Fl::add_fd(n, POLLIN, cb, v); 00137 } 00138 00139 void Fl::remove_fd(int n, int events) { 00140 int i,j; 00141 # if !USE_POLL 00142 maxfd = -1; // recalculate maxfd on the fly 00143 # endif 00144 for (i=j=0; i<nfds; i++) { 00145 # if USE_POLL 00146 if (pollfds[i].fd == n) { 00147 int e = pollfds[i].events & ~events; 00148 if (!e) continue; // if no events left, delete this fd 00149 pollfds[j].events = e; 00150 } 00151 # else 00152 if (fd[i].fd == n) { 00153 int e = fd[i].events & ~events; 00154 if (!e) continue; // if no events left, delete this fd 00155 fd[i].events = e; 00156 } 00157 if (fd[i].fd > maxfd) maxfd = fd[i].fd; 00158 # endif 00159 // move it down in the array if necessary: 00160 if (j<i) { 00161 fd[j] = fd[i]; 00162 # if USE_POLL 00163 pollfds[j] = pollfds[i]; 00164 # endif 00165 } 00166 j++; 00167 } 00168 nfds = j; 00169 # if !USE_POLL 00170 if (events & POLLIN) FD_CLR(n, &fdsets[0]); 00171 if (events & POLLOUT) FD_CLR(n, &fdsets[1]); 00172 if (events & POLLERR) FD_CLR(n, &fdsets[2]); 00173 # endif 00174 } 00175 00176 void Fl::remove_fd(int n) { 00177 remove_fd(n, -1); 00178 } 00179 00180 #if CONSOLIDATE_MOTION 00181 static Fl_Window* send_motion; 00182 extern Fl_Window* fl_xmousewin; 00183 #endif 00184 static bool in_a_window; // true if in any of our windows, even destroyed ones 00185 static void do_queued_events() { 00186 in_a_window = true; 00187 while (XEventsQueued(fl_display,QueuedAfterReading)) { 00188 XEvent xevent; 00189 XNextEvent(fl_display, &xevent); 00190 fl_handle(xevent); 00191 } 00192 // we send FL_LEAVE only if the mouse did not enter some other window: 00193 if (!in_a_window) Fl::handle(FL_LEAVE, 0); 00194 #if CONSOLIDATE_MOTION 00195 else if (send_motion == fl_xmousewin) { 00196 send_motion = 0; 00197 Fl::handle(FL_MOVE, fl_xmousewin); 00198 } 00199 #endif 00200 } 00201 00202 // these pointers are set by the Fl::lock() function: 00203 static void nothing() {} 00204 void (*fl_lock_function)() = nothing; 00205 void (*fl_unlock_function)() = nothing; 00206 00207 // This is never called with time_to_wait < 0.0: 00208 // It should return negative on error, 0 if nothing happens before 00209 // timeout, and >0 if any callbacks were done. 00210 int fl_wait(double time_to_wait) { 00211 00212 // OpenGL and other broken libraries call XEventsQueued 00213 // unnecessarily and thus cause the file descriptor to not be ready, 00214 // so we must check for already-read events: 00215 if (fl_display && XQLength(fl_display)) {do_queued_events(); return 1;} 00216 00217 # if !USE_POLL 00218 fd_set fdt[3]; 00219 fdt[0] = fdsets[0]; 00220 fdt[1] = fdsets[1]; 00221 fdt[2] = fdsets[2]; 00222 # endif 00223 int n; 00224 00225 fl_unlock_function(); 00226 00227 if (time_to_wait < 2147483.648) { 00228 # if USE_POLL 00229 n = ::poll(pollfds, nfds, int(time_to_wait*1000 + .5)); 00230 # else 00231 timeval t; 00232 t.tv_sec = int(time_to_wait); 00233 t.tv_usec = int(1000000 * (time_to_wait-t.tv_sec)); 00234 n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); 00235 # endif 00236 } else { 00237 # if USE_POLL 00238 n = ::poll(pollfds, nfds, -1); 00239 # else 00240 n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); 00241 # endif 00242 } 00243 00244 fl_lock_function(); 00245 00246 if (n > 0) { 00247 for (int i=0; i<nfds; i++) { 00248 # if USE_POLL 00249 if (pollfds[i].revents) fd[i].cb(pollfds[i].fd, fd[i].arg); 00250 # else 00251 int f = fd[i].fd; 00252 short revents = 0; 00253 if (FD_ISSET(f,&fdt[0])) revents |= POLLIN; 00254 if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT; 00255 if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; 00256 if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); 00257 # endif 00258 } 00259 } 00260 return n; 00261 } 00262 00263 // fl_ready() is just like fl_wait(0.0) except no callbacks are done: 00264 int fl_ready() { 00265 if (XQLength(fl_display)) return 1; 00266 if (!nfds) return 0; // nothing to select or poll 00267 # if USE_POLL 00268 return ::poll(pollfds, nfds, 0); 00269 # else 00270 timeval t; 00271 t.tv_sec = 0; 00272 t.tv_usec = 0; 00273 fd_set fdt[3]; 00274 fdt[0] = fdsets[0]; 00275 fdt[1] = fdsets[1]; 00276 fdt[2] = fdsets[2]; 00277 return ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); 00278 # endif 00279 } 00280 00281 // replace \r\n by \n 00282 static void convert_crlf(unsigned char *string, long& len) { 00283 unsigned char *a, *b; 00284 a = b = string; 00285 while (*a) { 00286 if (*a == '\r' && a[1] == '\n') { a++; len--; } 00287 else *b++ = *a++; 00288 } 00289 *b = 0; 00290 } 00291 00293 00294 Display *fl_display; 00295 Window fl_message_window = 0; 00296 int fl_screen; 00297 XVisualInfo *fl_visual; 00298 Colormap fl_colormap; 00299 XIM fl_xim_im = 0; 00300 XIC fl_xim_ic = 0; 00301 char fl_is_over_the_spot = 0; 00302 static XRectangle status_area; 00303 00304 static Atom WM_DELETE_WINDOW; 00305 static Atom WM_PROTOCOLS; 00306 static Atom fl_MOTIF_WM_HINTS; 00307 static Atom TARGETS; 00308 static Atom CLIPBOARD; 00309 Atom fl_XdndAware; 00310 Atom fl_XdndSelection; 00311 Atom fl_XdndEnter; 00312 Atom fl_XdndTypeList; 00313 Atom fl_XdndPosition; 00314 Atom fl_XdndLeave; 00315 Atom fl_XdndDrop; 00316 Atom fl_XdndStatus; 00317 Atom fl_XdndActionCopy; 00318 Atom fl_XdndFinished; 00319 //Atom fl_XdndProxy; 00320 Atom fl_XdndURIList; 00321 Atom fl_Xatextplainutf; 00322 Atom fl_Xatextplain; 00323 static Atom fl_XaText; 00324 Atom fl_XaCompoundText; 00325 Atom fl_XaUtf8String; 00326 Atom fl_XaTextUriList; 00327 Atom fl_NET_WM_NAME; // utf8 aware window label 00328 Atom fl_NET_WM_ICON_NAME; // utf8 aware window icon name 00329 00330 /* 00331 X defines 32-bit-entities to have a format value of max. 32, 00332 although sizeof(atom) can be 8 (64 bits) on a 64-bit OS. 00333 See also fl_open_display() for sizeof(atom) < 4. 00334 Used for XChangeProperty (see STR #2419). 00335 */ 00336 static int atom_bits = 32; 00337 00338 static void fd_callback(int,void *) { 00339 do_queued_events(); 00340 } 00341 00342 extern "C" { 00343 static int io_error_handler(Display*) { 00344 Fl::fatal("X I/O error"); 00345 return 0; 00346 } 00347 00348 static int xerror_handler(Display* d, XErrorEvent* e) { 00349 char buf1[128], buf2[128]; 00350 sprintf(buf1, "XRequest.%d", e->request_code); 00351 XGetErrorDatabaseText(d,"",buf1,buf1,buf2,128); 00352 XGetErrorText(d, e->error_code, buf1, 128); 00353 Fl::warning("%s: %s 0x%lx", buf2, buf1, e->resourceid); 00354 return 0; 00355 } 00356 } 00357 00358 extern char *fl_get_font_xfld(int fnum, int size); 00359 00360 void fl_new_ic() 00361 { 00362 XVaNestedList preedit_attr = NULL; 00363 XVaNestedList status_attr = NULL; 00364 static XFontSet fs = NULL; 00365 char *fnt; 00366 bool must_free_fnt = true; 00367 char **missing_list; 00368 int missing_count; 00369 char *def_string; 00370 static XRectangle spot; 00371 int predit = 0; 00372 int sarea = 0; 00373 XIMStyles* xim_styles = NULL; 00374 00375 #if USE_XFT 00376 00377 #if defined(__GNUC__) 00378 // FIXME: warning XFT support here 00379 #endif /*__GNUC__*/ 00380 00381 if (!fs) { 00382 fnt = NULL;//fl_get_font_xfld(0, 14); 00383 if (!fnt) {fnt = (char*)"-misc-fixed-*";must_free_fnt=false;} 00384 fs = XCreateFontSet(fl_display, fnt, &missing_list, 00385 &missing_count, &def_string); 00386 } 00387 #else 00388 if (!fs) { 00389 fnt = fl_get_font_xfld(0, 14); 00390 if (!fnt) {fnt = (char*)"-misc-fixed-*";must_free_fnt=false;} 00391 fs = XCreateFontSet(fl_display, fnt, &missing_list, 00392 &missing_count, &def_string); 00393 } 00394 #endif 00395 preedit_attr = XVaCreateNestedList(0, 00396 XNSpotLocation, &spot, 00397 XNFontSet, fs, NULL); 00398 status_attr = XVaCreateNestedList(0, 00399 XNAreaNeeded, &status_area, 00400 XNFontSet, fs, NULL); 00401 00402 if (!XGetIMValues(fl_xim_im, XNQueryInputStyle, 00403 &xim_styles, NULL, NULL)) { 00404 int i; 00405 XIMStyle *style; 00406 for (i = 0, style = xim_styles->supported_styles; 00407 i < xim_styles->count_styles; i++, style++) { 00408 if (*style == (XIMPreeditPosition | XIMStatusArea)) { 00409 sarea = 1; 00410 predit = 1; 00411 } else if (*style == (XIMPreeditPosition | XIMStatusNothing)) { 00412 predit = 1; 00413 } 00414 } 00415 } 00416 XFree(xim_styles); 00417 00418 if (sarea) { 00419 fl_xim_ic = XCreateIC(fl_xim_im, 00420 XNInputStyle, (XIMPreeditPosition | XIMStatusArea), 00421 XNPreeditAttributes, preedit_attr, 00422 XNStatusAttributes, status_attr, 00423 NULL); 00424 } 00425 00426 if (!fl_xim_ic && predit) { 00427 fl_xim_ic = XCreateIC(fl_xim_im, 00428 XNInputStyle, (XIMPreeditPosition | XIMStatusNothing), 00429 XNPreeditAttributes, preedit_attr, 00430 NULL); 00431 } 00432 XFree(preedit_attr); 00433 XFree(status_attr); 00434 if (!fl_xim_ic) { 00435 fl_is_over_the_spot = 0; 00436 fl_xim_ic = XCreateIC(fl_xim_im, 00437 XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), 00438 NULL); 00439 } else { 00440 fl_is_over_the_spot = 1; 00441 XVaNestedList status_attr = NULL; 00442 status_attr = XVaCreateNestedList(0, XNAreaNeeded, &status_area, NULL); 00443 00444 XGetICValues(fl_xim_ic, XNStatusAttributes, status_attr, NULL); 00445 XFree(status_attr); 00446 } 00447 } 00448 00449 00450 static XRectangle spot; 00451 static int spotf = -1; 00452 static int spots = -1; 00453 00454 void fl_reset_spot(void) 00455 { 00456 spot.x = -1; 00457 spot.y = -1; 00458 //if (fl_xim_ic) XUnsetICFocus(fl_xim_ic); 00459 } 00460 00461 void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) 00462 { 00463 int change = 0; 00464 XVaNestedList preedit_attr; 00465 static XFontSet fs = NULL; 00466 char **missing_list; 00467 int missing_count; 00468 char *def_string; 00469 char *fnt = NULL; 00470 bool must_free_fnt =true; 00471 00472 static XIC ic = NULL; 00473 00474 if (!fl_xim_ic || !fl_is_over_the_spot) return; 00475 //XSetICFocus(fl_xim_ic); 00476 if (X != spot.x || Y != spot.y) { 00477 spot.x = X; 00478 spot.y = Y; 00479 spot.height = H; 00480 spot.width = W; 00481 change = 1; 00482 } 00483 if (font != spotf || size != spots) { 00484 spotf = font; 00485 spots = size; 00486 change = 1; 00487 if (fs) { 00488 XFreeFontSet(fl_display, fs); 00489 } 00490 #if USE_XFT 00491 00492 #if defined(__GNUC__) 00493 // FIXME: warning XFT support here 00494 #endif /*__GNUC__*/ 00495 00496 fnt = NULL; // fl_get_font_xfld(font, size); 00497 if (!fnt) {fnt = (char*)"-misc-fixed-*";must_free_fnt=false;} 00498 fs = XCreateFontSet(fl_display, fnt, &missing_list, 00499 &missing_count, &def_string); 00500 #else 00501 fnt = fl_get_font_xfld(font, size); 00502 if (!fnt) {fnt = (char*)"-misc-fixed-*";must_free_fnt=false;} 00503 fs = XCreateFontSet(fl_display, fnt, &missing_list, 00504 &missing_count, &def_string); 00505 #endif 00506 } 00507 if (fl_xim_ic != ic) { 00508 ic = fl_xim_ic; 00509 change = 1; 00510 } 00511 00512 if (fnt && must_free_fnt) free(fnt); 00513 if (!change) return; 00514 00515 00516 preedit_attr = XVaCreateNestedList(0, 00517 XNSpotLocation, &spot, 00518 XNFontSet, fs, NULL); 00519 XSetICValues(fl_xim_ic, XNPreeditAttributes, preedit_attr, NULL); 00520 XFree(preedit_attr); 00521 } 00522 00523 void fl_set_status(int x, int y, int w, int h) 00524 { 00525 XVaNestedList status_attr; 00526 status_area.x = x; 00527 status_area.y = y; 00528 status_area.width = w; 00529 status_area.height = h; 00530 if (!fl_xim_ic) return; 00531 status_attr = XVaCreateNestedList(0, XNArea, &status_area, NULL); 00532 00533 XSetICValues(fl_xim_ic, XNStatusAttributes, status_attr, NULL); 00534 XFree(status_attr); 00535 } 00536 00537 void fl_init_xim() 00538 { 00539 //XIMStyle *style; 00540 XIMStyles *xim_styles; 00541 if (!fl_display) return; 00542 if (fl_xim_im) return; 00543 00544 fl_xim_im = XOpenIM(fl_display, NULL, NULL, NULL); 00545 xim_styles = NULL; 00546 fl_xim_ic = NULL; 00547 00548 if (fl_xim_im) { 00549 XGetIMValues (fl_xim_im, XNQueryInputStyle, 00550 &xim_styles, NULL, NULL); 00551 } else { 00552 Fl::warning("XOpenIM() failed\n"); 00553 return; 00554 } 00555 00556 if (xim_styles && xim_styles->count_styles) { 00557 fl_new_ic(); 00558 } else { 00559 Fl::warning("No XIM style found\n"); 00560 XCloseIM(fl_xim_im); 00561 fl_xim_im = NULL; 00562 return; 00563 } 00564 if (!fl_xim_ic) { 00565 Fl::warning("XCreateIC() failed\n"); 00566 XCloseIM(fl_xim_im); 00567 XFree(xim_styles); 00568 fl_xim_im = NULL; 00569 } 00570 } 00571 00572 void fl_open_display() { 00573 if (fl_display) return; 00574 00575 setlocale(LC_CTYPE, ""); 00576 XSetLocaleModifiers(""); 00577 00578 XSetIOErrorHandler(io_error_handler); 00579 XSetErrorHandler(xerror_handler); 00580 00581 Display *d = XOpenDisplay(0); 00582 if (!d) Fl::fatal("Can't open display: %s",XDisplayName(0)); 00583 00584 fl_open_display(d); 00585 } 00586 00587 void fl_open_display(Display* d) { 00588 fl_display = d; 00589 00590 WM_DELETE_WINDOW = XInternAtom(d, "WM_DELETE_WINDOW", 0); 00591 WM_PROTOCOLS = XInternAtom(d, "WM_PROTOCOLS", 0); 00592 fl_MOTIF_WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", 0); 00593 TARGETS = XInternAtom(d, "TARGETS", 0); 00594 CLIPBOARD = XInternAtom(d, "CLIPBOARD", 0); 00595 fl_XdndAware = XInternAtom(d, "XdndAware", 0); 00596 fl_XdndSelection = XInternAtom(d, "XdndSelection", 0); 00597 fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); 00598 fl_XdndTypeList = XInternAtom(d, "XdndTypeList", 0); 00599 fl_XdndPosition = XInternAtom(d, "XdndPosition", 0); 00600 fl_XdndLeave = XInternAtom(d, "XdndLeave", 0); 00601 fl_XdndDrop = XInternAtom(d, "XdndDrop", 0); 00602 fl_XdndStatus = XInternAtom(d, "XdndStatus", 0); 00603 fl_XdndActionCopy = XInternAtom(d, "XdndActionCopy", 0); 00604 fl_XdndFinished = XInternAtom(d, "XdndFinished", 0); 00605 //fl_XdndProxy = XInternAtom(d, "XdndProxy", 0); 00606 fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); 00607 fl_XdndURIList = XInternAtom(d, "text/uri-list", 0); 00608 fl_Xatextplainutf = XInternAtom(d, "text/plain;charset=UTF-8",0); 00609 fl_Xatextplain = XInternAtom(d, "text/plain", 0); 00610 fl_XaText = XInternAtom(d, "TEXT", 0); 00611 fl_XaCompoundText = XInternAtom(d, "COMPOUND_TEXT", 0); 00612 fl_XaUtf8String = XInternAtom(d, "UTF8_STRING", 0); 00613 fl_XaTextUriList = XInternAtom(d, "text/uri-list", 0); 00614 fl_NET_WM_NAME = XInternAtom(d, "_NET_WM_NAME", 0); 00615 fl_NET_WM_ICON_NAME = XInternAtom(d, "_NET_WM_ICON_NAME", 0); 00616 00617 if (sizeof(Atom) < 4) 00618 atom_bits = sizeof(Atom) * 8; 00619 00620 Fl::add_fd(ConnectionNumber(d), POLLIN, fd_callback); 00621 00622 fl_screen = DefaultScreen(d); 00623 00624 fl_message_window = 00625 XCreateSimpleWindow(d, RootWindow(d,fl_screen), 0,0,1,1,0, 0, 0); 00626 00627 // construct an XVisualInfo that matches the default Visual: 00628 XVisualInfo templt; int num; 00629 templt.visualid = XVisualIDFromVisual(DefaultVisual(d, fl_screen)); 00630 fl_visual = XGetVisualInfo(d, VisualIDMask, &templt, &num); 00631 fl_colormap = DefaultColormap(d, fl_screen); 00632 fl_init_xim(); 00633 00634 #if !USE_COLORMAP 00635 Fl::visual(FL_RGB); 00636 #endif 00637 } 00638 00639 void fl_close_display() { 00640 Fl::remove_fd(ConnectionNumber(fl_display)); 00641 XCloseDisplay(fl_display); 00642 } 00643 00644 static int fl_workarea_xywh[4] = { -1, -1, -1, -1 }; 00645 00646 static void fl_init_workarea() { 00647 fl_open_display(); 00648 00649 Atom _NET_WORKAREA = XInternAtom(fl_display, "_NET_WORKAREA", 0); 00650 Atom actual; 00651 unsigned long count, remaining; 00652 int format; 00653 unsigned *xywh; 00654 00655 if (XGetWindowProperty(fl_display, RootWindow(fl_display, fl_screen), 00656 _NET_WORKAREA, 0, 4 * sizeof(unsigned), False, 00657 XA_CARDINAL, &actual, &format, &count, &remaining, 00658 (unsigned char **)&xywh) || !xywh || !xywh[2] || 00659 !xywh[3]) 00660 { 00661 fl_workarea_xywh[0] = 0; 00662 fl_workarea_xywh[1] = 0; 00663 fl_workarea_xywh[2] = DisplayWidth(fl_display, fl_screen); 00664 fl_workarea_xywh[3] = DisplayHeight(fl_display, fl_screen); 00665 } 00666 else 00667 { 00668 fl_workarea_xywh[0] = (int)xywh[0]; 00669 fl_workarea_xywh[1] = (int)xywh[1]; 00670 fl_workarea_xywh[2] = (int)xywh[2]; 00671 fl_workarea_xywh[3] = (int)xywh[3]; 00672 XFree(xywh); 00673 } 00674 } 00675 00676 int Fl::x() { 00677 if (fl_workarea_xywh[0] < 0) fl_init_workarea(); 00678 return fl_workarea_xywh[0]; 00679 } 00680 00681 int Fl::y() { 00682 if (fl_workarea_xywh[0] < 0) fl_init_workarea(); 00683 return fl_workarea_xywh[1]; 00684 } 00685 00686 int Fl::w() { 00687 if (fl_workarea_xywh[0] < 0) fl_init_workarea(); 00688 return fl_workarea_xywh[2]; 00689 } 00690 00691 int Fl::h() { 00692 if (fl_workarea_xywh[0] < 0) fl_init_workarea(); 00693 return fl_workarea_xywh[3]; 00694 } 00695 00696 void Fl::get_mouse(int &xx, int &yy) { 00697 fl_open_display(); 00698 Window root = RootWindow(fl_display, fl_screen); 00699 Window c; int mx,my,cx,cy; unsigned int mask; 00700 XQueryPointer(fl_display,root,&root,&c,&mx,&my,&cx,&cy,&mask); 00701 xx = mx; 00702 yy = my; 00703 } 00704 00706 // Code used for paste and DnD into the program: 00707 00708 Fl_Widget *fl_selection_requestor; 00709 char *fl_selection_buffer[2]; 00710 int fl_selection_length[2]; 00711 int fl_selection_buffer_length[2]; 00712 char fl_i_own_selection[2] = {0,0}; 00713 00714 // Call this when a "paste" operation happens: 00715 void Fl::paste(Fl_Widget &receiver, int clipboard) { 00716 if (fl_i_own_selection[clipboard]) { 00717 // We already have it, do it quickly without window server. 00718 // Notice that the text is clobbered if set_selection is 00719 // called in response to FL_PASTE! 00720 Fl::e_text = fl_selection_buffer[clipboard]; 00721 Fl::e_length = fl_selection_length[clipboard]; 00722 if (!Fl::e_text) Fl::e_text = (char *)""; 00723 receiver.handle(FL_PASTE); 00724 return; 00725 } 00726 // otherwise get the window server to return it: 00727 fl_selection_requestor = &receiver; 00728 Atom property = clipboard ? CLIPBOARD : XA_PRIMARY; 00729 XConvertSelection(fl_display, property, TARGETS, property, 00730 fl_xid(Fl::first_window()), fl_event_time); 00731 } 00732 00733 Window fl_dnd_source_window; 00734 Atom *fl_dnd_source_types; // null-terminated list of data types being supplied 00735 Atom fl_dnd_type; 00736 Atom fl_dnd_source_action; 00737 Atom fl_dnd_action; 00738 00739 void fl_sendClientMessage(Window window, Atom message, 00740 unsigned long d0, 00741 unsigned long d1=0, 00742 unsigned long d2=0, 00743 unsigned long d3=0, 00744 unsigned long d4=0) 00745 { 00746 XEvent e; 00747 e.xany.type = ClientMessage; 00748 e.xany.window = window; 00749 e.xclient.message_type = message; 00750 e.xclient.format = 32; 00751 e.xclient.data.l[0] = (long)d0; 00752 e.xclient.data.l[1] = (long)d1; 00753 e.xclient.data.l[2] = (long)d2; 00754 e.xclient.data.l[3] = (long)d3; 00755 e.xclient.data.l[4] = (long)d4; 00756 XSendEvent(fl_display, window, 0, 0, &e); 00757 } 00758 00760 // Code for copying to clipboard and DnD out of the program: 00761 00762 void Fl::copy(const char *stuff, int len, int clipboard) { 00763 if (!stuff || len<0) return; 00764 if (len+1 > fl_selection_buffer_length[clipboard]) { 00765 delete[] fl_selection_buffer[clipboard]; 00766 fl_selection_buffer[clipboard] = new char[len+100]; 00767 fl_selection_buffer_length[clipboard] = len+100; 00768 } 00769 memcpy(fl_selection_buffer[clipboard], stuff, len); 00770 fl_selection_buffer[clipboard][len] = 0; // needed for direct paste 00771 fl_selection_length[clipboard] = len; 00772 fl_i_own_selection[clipboard] = 1; 00773 Atom property = clipboard ? CLIPBOARD : XA_PRIMARY; 00774 XSetSelectionOwner(fl_display, property, fl_message_window, fl_event_time); 00775 } 00776 00778 00779 const XEvent* fl_xevent; // the current x event 00780 ulong fl_event_time; // the last timestamp from an x event 00781 00782 char fl_key_vector[32]; // used by Fl::get_key() 00783 00784 // Record event mouse position and state from an XEvent: 00785 00786 static int px, py; 00787 static ulong ptime; 00788 00789 static void set_event_xy() { 00790 # if CONSOLIDATE_MOTION 00791 send_motion = 0; 00792 # endif 00793 Fl::e_x_root = fl_xevent->xbutton.x_root; 00794 Fl::e_x = fl_xevent->xbutton.x; 00795 Fl::e_y_root = fl_xevent->xbutton.y_root; 00796 Fl::e_y = fl_xevent->xbutton.y; 00797 Fl::e_state = fl_xevent->xbutton.state << 16; 00798 fl_event_time = fl_xevent->xbutton.time; 00799 # ifdef __sgi 00800 // get the meta key off PC keyboards: 00801 if (fl_key_vector[18]&0x18) Fl::e_state |= FL_META; 00802 # endif 00803 // turn off is_click if enough time or mouse movement has passed: 00804 if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 || 00805 fl_event_time >= ptime+1000) 00806 Fl::e_is_click = 0; 00807 } 00808 00809 // if this is same event as last && is_click, increment click count: 00810 static inline void checkdouble() { 00811 if (Fl::e_is_click == Fl::e_keysym) 00812 Fl::e_clicks++; 00813 else { 00814 Fl::e_clicks = 0; 00815 Fl::e_is_click = Fl::e_keysym; 00816 } 00817 px = Fl::e_x_root; 00818 py = Fl::e_y_root; 00819 ptime = fl_event_time; 00820 } 00821 00822 static Fl_Window* resize_bug_fix; 00823 00825 00826 static char unknown[] = "<unknown>"; 00827 const int unknown_len = 10; 00828 00829 extern "C" { 00830 00831 static int xerror = 0; 00832 00833 static int ignoreXEvents(Display *display, XErrorEvent *event) { 00834 xerror = 1; 00835 return 0; 00836 } 00837 00838 static XErrorHandler catchXExceptions() { 00839 xerror = 0; 00840 return ignoreXEvents; 00841 } 00842 00843 static int wasXExceptionRaised() { 00844 return xerror; 00845 } 00846 00847 } 00848 00849 00850 int fl_handle(const XEvent& thisevent) 00851 { 00852 XEvent xevent = thisevent; 00853 fl_xevent = &thisevent; 00854 Window xid = xevent.xany.window; 00855 static Window xim_win = 0; 00856 00857 if (fl_xim_ic && xevent.type == DestroyNotify && 00858 xid != xim_win && !fl_find(xid)) 00859 { 00860 XIM xim_im; 00861 xim_im = XOpenIM(fl_display, NULL, NULL, NULL); 00862 if (!xim_im) { 00863 /* XIM server has crashed */ 00864 XSetLocaleModifiers("@im="); 00865 fl_xim_im = NULL; 00866 fl_init_xim(); 00867 } else { 00868 XCloseIM(xim_im); // see STR 2185 for comment 00869 } 00870 return 0; 00871 } 00872 00873 if (fl_xim_ic && (xevent.type == FocusIn)) 00874 { 00875 #define POOR_XIM 00876 #ifdef POOR_XIM 00877 if (xim_win != xid) 00878 { 00879 xim_win = xid; 00880 XDestroyIC(fl_xim_ic); 00881 fl_xim_ic = NULL; 00882 fl_new_ic(); 00883 XSetICValues(fl_xim_ic, 00884 XNFocusWindow, xevent.xclient.window, 00885 XNClientWindow, xid, 00886 NULL); 00887 } 00888 fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); 00889 #else 00890 if (Fl::first_window() && Fl::first_window()->modal()) { 00891 Window x = fl_xid(Fl::first_window()); 00892 if (x != xim_win) { 00893 xim_win = x; 00894 XSetICValues(fl_xim_ic, 00895 XNFocusWindow, xim_win, 00896 XNClientWindow, xim_win, 00897 NULL); 00898 fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); 00899 } 00900 } else if (xim_win != xid && xid) { 00901 xim_win = xid; 00902 XSetICValues(fl_xim_ic, 00903 XNFocusWindow, xevent.xclient.window, 00904 XNClientWindow, xid, 00905 //XNFocusWindow, xim_win, 00906 //XNClientWindow, xim_win, 00907 NULL); 00908 fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); 00909 } 00910 #endif 00911 } 00912 00913 if ( XFilterEvent((XEvent *)&xevent, 0) ) 00914 return(1); 00915 00916 switch (xevent.type) { 00917 00918 case KeymapNotify: 00919 memcpy(fl_key_vector, xevent.xkeymap.key_vector, 32); 00920 return 0; 00921 00922 case MappingNotify: 00923 XRefreshKeyboardMapping((XMappingEvent*)&xevent.xmapping); 00924 return 0; 00925 00926 case SelectionNotify: { 00927 if (!fl_selection_requestor) return 0; 00928 static unsigned char* buffer = 0; 00929 if (buffer) {XFree(buffer); buffer = 0;} 00930 long bytesread = 0; 00931 if (fl_xevent->xselection.property) for (;;) { 00932 // The Xdnd code pastes 64K chunks together, possibly to avoid 00933 // bugs in X servers, or maybe to avoid an extra round-trip to 00934 // get the property length. I copy this here: 00935 Atom actual; int format; unsigned long count, remaining; 00936 unsigned char* portion; 00937 if (XGetWindowProperty(fl_display, 00938 fl_xevent->xselection.requestor, 00939 fl_xevent->xselection.property, 00940 bytesread/4, 65536, 1, 0, 00941 &actual, &format, &count, &remaining, 00942 &portion)) break; // quit on error 00943 if (actual == TARGETS || actual == XA_ATOM) { 00944 Atom type = XA_STRING; 00945 for (unsigned i = 0; i<count; i++) { 00946 Atom t = ((Atom*)portion)[i]; 00947 if (t == fl_Xatextplainutf || 00948 t == fl_Xatextplain || 00949 t == fl_XaUtf8String) {type = t; break;} 00950 // rest are only used if no utf-8 available: 00951 if (t == fl_XaText || 00952 t == fl_XaTextUriList || 00953 t == fl_XaCompoundText) type = t; 00954 } 00955 XFree(portion); 00956 Atom property = xevent.xselection.property; 00957 XConvertSelection(fl_display, property, type, property, 00958 fl_xid(Fl::first_window()), 00959 fl_event_time); 00960 return true; 00961 } 00962 XTextProperty text_prop; 00963 text_prop.value=portion; 00964 text_prop.format=format; 00965 text_prop.encoding=actual; 00966 text_prop.nitems=count; 00967 char **text_list; 00968 text_list = (char**)&portion; 00969 int bytesnew = strlen(*text_list)+1; 00970 buffer = (unsigned char*)realloc(buffer, bytesread+bytesnew+remaining); 00971 memcpy(buffer+bytesread, *text_list, bytesnew); 00972 XFree(portion); 00973 bytesread += bytesnew - 1; 00974 if (!remaining) break; 00975 } 00976 if (buffer) { 00977 buffer[bytesread] = 0; 00978 convert_crlf(buffer, bytesread); 00979 } 00980 Fl::e_text = buffer ? (char*)buffer : (char *)""; 00981 Fl::e_length = bytesread; 00982 int old_event = Fl::e_number; 00983 fl_selection_requestor->handle(Fl::e_number = FL_PASTE); 00984 Fl::e_number = old_event; 00985 // Detect if this paste is due to Xdnd by the property name (I use 00986 // XA_SECONDARY for that) and send an XdndFinished message. It is not 00987 // clear if this has to be delayed until now or if it can be done 00988 // immediatly after calling XConvertSelection. 00989 if (fl_xevent->xselection.property == XA_SECONDARY && 00990 fl_dnd_source_window) { 00991 fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, 00992 fl_xevent->xselection.requestor); 00993 fl_dnd_source_window = 0; // don't send a second time 00994 } 00995 return 1;} 00996 00997 case SelectionClear: { 00998 int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD; 00999 fl_i_own_selection[clipboard] = 0; 01000 return 1;} 01001 01002 case SelectionRequest: { 01003 XSelectionEvent e; 01004 e.type = SelectionNotify; 01005 e.requestor = fl_xevent->xselectionrequest.requestor; 01006 e.selection = fl_xevent->xselectionrequest.selection; 01007 int clipboard = e.selection == CLIPBOARD; 01008 e.target = fl_xevent->xselectionrequest.target; 01009 e.time = fl_xevent->xselectionrequest.time; 01010 e.property = fl_xevent->xselectionrequest.property; 01011 if (e.target == TARGETS) { 01012 Atom a[3] = {fl_XaUtf8String, XA_STRING, fl_XaText}; 01013 XChangeProperty(fl_display, e.requestor, e.property, 01014 XA_ATOM, atom_bits, 0, (unsigned char*)a, 3); 01015 } else if (/*e.target == XA_STRING &&*/ fl_selection_length[clipboard]) { 01016 if (e.target == fl_XaUtf8String || 01017 e.target == XA_STRING || 01018 e.target == fl_XaCompoundText || 01019 e.target == fl_XaText || 01020 e.target == fl_Xatextplain || 01021 e.target == fl_Xatextplainutf) { 01022 // clobber the target type, this seems to make some applications 01023 // behave that insist on asking for XA_TEXT instead of UTF8_STRING 01024 // Does not change XA_STRING as that breaks xclipboard. 01025 if (e.target != XA_STRING) e.target = fl_XaUtf8String; 01026 XChangeProperty(fl_display, e.requestor, e.property, 01027 e.target, 8, 0, 01028 (unsigned char *)fl_selection_buffer[clipboard], 01029 fl_selection_length[clipboard]); 01030 } 01031 } else { 01032 // char* x = XGetAtomName(fl_display,e.target); 01033 // fprintf(stderr,"selection request of %s\n",x); 01034 // XFree(x); 01035 e.property = 0; 01036 } 01037 XSendEvent(fl_display, e.requestor, 0, 0, (XEvent *)&e);} 01038 return 1; 01039 01040 // events where interesting window id is in a different place: 01041 case CirculateNotify: 01042 case CirculateRequest: 01043 case ConfigureNotify: 01044 case ConfigureRequest: 01045 case CreateNotify: 01046 case DestroyNotify: 01047 case GravityNotify: 01048 case MapNotify: 01049 case MapRequest: 01050 case ReparentNotify: 01051 case UnmapNotify: 01052 xid = xevent.xmaprequest.window; 01053 break; 01054 } 01055 01056 int event = 0; 01057 Fl_Window* window = fl_find(xid); 01058 01059 if (window) switch (xevent.type) { 01060 01061 case ClientMessage: { 01062 Atom message = fl_xevent->xclient.message_type; 01063 const long* data = fl_xevent->xclient.data.l; 01064 if ((Atom)(data[0]) == WM_DELETE_WINDOW) { 01065 event = FL_CLOSE; 01066 } else if (message == fl_XdndEnter) { 01067 fl_xmousewin = window; 01068 in_a_window = true; 01069 fl_dnd_source_window = data[0]; 01070 // version number is data[1]>>24 01071 // printf("XdndEnter, version %ld\n", data[1] >> 24); 01072 if (data[1]&1) { 01073 // get list of data types: 01074 Atom actual; int format; unsigned long count, remaining; 01075 unsigned char *buffer = 0; 01076 XGetWindowProperty(fl_display, fl_dnd_source_window, fl_XdndTypeList, 01077 0, 0x8000000L, False, XA_ATOM, &actual, &format, 01078 &count, &remaining, &buffer); 01079 if (actual != XA_ATOM || format != 32 || count<4 || !buffer) 01080 goto FAILED; 01081 delete [] fl_dnd_source_types; 01082 fl_dnd_source_types = new Atom[count+1]; 01083 for (unsigned i = 0; i < count; i++) { 01084 fl_dnd_source_types[i] = ((Atom*)buffer)[i]; 01085 } 01086 fl_dnd_source_types[count] = 0; 01087 } else { 01088 FAILED: 01089 // less than four data types, or if the above messes up: 01090 if (!fl_dnd_source_types) fl_dnd_source_types = new Atom[4]; 01091 fl_dnd_source_types[0] = data[2]; 01092 fl_dnd_source_types[1] = data[3]; 01093 fl_dnd_source_types[2] = data[4]; 01094 fl_dnd_source_types[3] = 0; 01095 } 01096 01097 // Loop through the source types and pick the first text type... 01098 int i; 01099 01100 for (i = 0; fl_dnd_source_types[i]; i ++) 01101 { 01102 // printf("fl_dnd_source_types[%d] = %ld (%s)\n", i, 01103 // fl_dnd_source_types[i], 01104 // XGetAtomName(fl_display, fl_dnd_source_types[i])); 01105 01106 if (!strncmp(XGetAtomName(fl_display, fl_dnd_source_types[i]), 01107 "text/", 5)) 01108 break; 01109 } 01110 01111 if (fl_dnd_source_types[i]) 01112 fl_dnd_type = fl_dnd_source_types[i]; 01113 else 01114 fl_dnd_type = fl_dnd_source_types[0]; 01115 01116 event = FL_DND_ENTER; 01117 Fl::e_text = unknown; 01118 Fl::e_length = unknown_len; 01119 break; 01120 01121 } else if (message == fl_XdndPosition) { 01122 fl_xmousewin = window; 01123 in_a_window = true; 01124 fl_dnd_source_window = data[0]; 01125 Fl::e_x_root = data[2]>>16; 01126 Fl::e_y_root = data[2]&0xFFFF; 01127 if (window) { 01128 Fl::e_x = Fl::e_x_root-window->x(); 01129 Fl::e_y = Fl::e_y_root-window->y(); 01130 } 01131 fl_event_time = data[3]; 01132 fl_dnd_source_action = data[4]; 01133 fl_dnd_action = fl_XdndActionCopy; 01134 Fl::e_text = unknown; 01135 Fl::e_length = unknown_len; 01136 int accept = Fl::handle(FL_DND_DRAG, window); 01137 fl_sendClientMessage(data[0], fl_XdndStatus, 01138 fl_xevent->xclient.window, 01139 accept ? 1 : 0, 01140 0, // used for xy rectangle to not send position inside 01141 0, // used for width+height of rectangle 01142 accept ? fl_dnd_action : None); 01143 return 1; 01144 01145 } else if (message == fl_XdndLeave) { 01146 fl_dnd_source_window = 0; // don't send a finished message to it 01147 event = FL_DND_LEAVE; 01148 Fl::e_text = unknown; 01149 Fl::e_length = unknown_len; 01150 break; 01151 01152 } else if (message == fl_XdndDrop) { 01153 fl_xmousewin = window; 01154 in_a_window = true; 01155 fl_dnd_source_window = data[0]; 01156 fl_event_time = data[2]; 01157 Window to_window = fl_xevent->xclient.window; 01158 Fl::e_text = unknown; 01159 Fl::e_length = unknown_len; 01160 if (Fl::handle(FL_DND_RELEASE, window)) { 01161 fl_selection_requestor = Fl::belowmouse(); 01162 XConvertSelection(fl_display, fl_XdndSelection, 01163 fl_dnd_type, XA_SECONDARY, 01164 to_window, fl_event_time); 01165 } else { 01166 // Send the finished message if I refuse the drop. 01167 // It is not clear whether I can just send finished always, 01168 // or if I have to wait for the SelectionNotify event as the 01169 // code is currently doing. 01170 fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, to_window); 01171 fl_dnd_source_window = 0; 01172 } 01173 return 1; 01174 01175 } 01176 break;} 01177 01178 case UnmapNotify: 01179 event = FL_HIDE; 01180 break; 01181 01182 case Expose: 01183 Fl_X::i(window)->wait_for_expose = 0; 01184 # if 0 01185 // try to keep windows on top even if WM_TRANSIENT_FOR does not work: 01186 // opaque move/resize window managers do not like this, so I disabled it. 01187 if (Fl::first_window()->non_modal() && window != Fl::first_window()) 01188 Fl::first_window()->show(); 01189 # endif 01190 01191 case GraphicsExpose: 01192 window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x, xevent.xexpose.y, 01193 xevent.xexpose.width, xevent.xexpose.height); 01194 return 1; 01195 01196 case FocusIn: 01197 if (fl_xim_ic) XSetICFocus(fl_xim_ic); 01198 event = FL_FOCUS; 01199 break; 01200 01201 case FocusOut: 01202 if (fl_xim_ic) XUnsetICFocus(fl_xim_ic); 01203 event = FL_UNFOCUS; 01204 break; 01205 01206 case KeyPress: 01207 case KeyRelease: { 01208 KEYPRESS: 01209 int keycode = xevent.xkey.keycode; 01210 fl_key_vector[keycode/8] |= (1 << (keycode%8)); 01211 static char *buffer = NULL; 01212 static int buffer_len = 0; 01213 int len; 01214 KeySym keysym; 01215 if (buffer_len == 0) { 01216 buffer_len = 4096; 01217 buffer = (char*) malloc(buffer_len); 01218 } 01219 if (xevent.type == KeyPress) { 01220 event = FL_KEYDOWN; 01221 int len = 0; 01222 01223 if (fl_xim_ic) { 01224 Status status; 01225 len = XUtf8LookupString(fl_xim_ic, (XKeyPressedEvent *)&xevent.xkey, 01226 buffer, buffer_len, &keysym, &status); 01227 01228 while (status == XBufferOverflow && buffer_len < 50000) { 01229 buffer_len = buffer_len * 5 + 1; 01230 buffer = (char*)realloc(buffer, buffer_len); 01231 len = XUtf8LookupString(fl_xim_ic, (XKeyPressedEvent *)&xevent.xkey, 01232 buffer, buffer_len, &keysym, &status); 01233 } 01234 keysym = XKeycodeToKeysym(fl_display, keycode, 0); 01235 } else { 01236 //static XComposeStatus compose; 01237 len = XLookupString((XKeyEvent*)&(xevent.xkey), 01238 buffer, buffer_len, &keysym, 0/*&compose*/); 01239 if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets 01240 // force it to type a character (not sure if this ever is needed): 01241 // if (!len) {buffer[0] = char(keysym); len = 1;} 01242 len = fl_utf8encode(XKeysymToUcs(keysym), buffer); 01243 if (len < 1) len = 1; 01244 // ignore all effects of shift on the keysyms, which makes it a lot 01245 // easier to program shortcuts and is Windoze-compatable: 01246 keysym = XKeycodeToKeysym(fl_display, keycode, 0); 01247 } 01248 } 01249 // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not 01250 // set until set_event_xy() is called later... 01251 if ((xevent.xkey.state & ControlMask) && keysym == '-') buffer[0] = 0x1f; // ^_ 01252 buffer[len] = 0; 01253 Fl::e_text = buffer; 01254 Fl::e_length = len; 01255 } else { 01256 // Stupid X sends fake key-up events when a repeating key is held 01257 // down, probably due to some back compatibility problem. Fortunately 01258 // we can detect this because the repeating KeyPress event is in 01259 // the queue, get it and execute it instead: 01260 01261 // Bool XkbSetDetectableAutorepeat ( display, detectable, supported_rtrn ) 01262 // Display * display ; 01263 // Bool detectable ; 01264 // Bool * supported_rtrn ; 01265 // ...would be the easy way to corrct this isuue. Unfortunatly, this call is also 01266 // broken on many Unix distros including Ubuntu and Solaris (as of Dec 2009) 01267 01268 // Bogus KeyUp events are generated by repeated KeyDown events. One 01269 // neccessary condition is an identical key event pending right after 01270 // the bogus KeyUp. 01271 // The new code introduced Dec 2009 differs in that it only check the very 01272 // next event in the queue, not the entire queue of events. 01273 // This function wrongly detects a repeat key if a software keyboard 01274 // sends a burst of events containing two consecutive equal keys. However, 01275 // in every non-gaming situation, this is no problem because both KeyPress 01276 // events will cause the expected behavior. 01277 XEvent peekevent; 01278 if (XPending(fl_display)) { 01279 XPeekEvent(fl_display, &peekevent); 01280 if ( (peekevent.type == KeyPress) // must be a KeyPress event 01281 && (peekevent.xkey.keycode == xevent.xkey.keycode) // must be the same key 01282 && (peekevent.xkey.time == xevent.xkey.time) // must be sent at the exact same time 01283 ) { 01284 XNextEvent(fl_display, &xevent); 01285 goto KEYPRESS; 01286 } 01287 } 01288 01289 event = FL_KEYUP; 01290 fl_key_vector[keycode/8] &= ~(1 << (keycode%8)); 01291 // keyup events just get the unshifted keysym: 01292 keysym = XKeycodeToKeysym(fl_display, keycode, 0); 01293 } 01294 # ifdef __sgi 01295 // You can plug a microsoft keyboard into an sgi but the extra shift 01296 // keys are not translated. Make them translate like XFree86 does: 01297 if (!keysym) switch(keycode) { 01298 case 147: keysym = FL_Meta_L; break; 01299 case 148: keysym = FL_Meta_R; break; 01300 case 149: keysym = FL_Menu; break; 01301 } 01302 # endif 01303 # if BACKSPACE_HACK 01304 // Attempt to fix keyboards that send "delete" for the key in the 01305 // upper-right corner of the main keyboard. But it appears that 01306 // very few of these remain? 01307 static int got_backspace = 0; 01308 if (!got_backspace) { 01309 if (keysym == FL_Delete) keysym = FL_BackSpace; 01310 else if (keysym == FL_BackSpace) got_backspace = 1; 01311 } 01312 # endif 01313 // We have to get rid of the XK_KP_function keys, because they are 01314 // not produced on Windoze and thus case statements tend not to check 01315 // for them. There are 15 of these in the range 0xff91 ... 0xff9f 01316 if (keysym >= 0xff91 && keysym <= 0xff9f) { 01317 // Map keypad keysym to character or keysym depending on 01318 // numlock state... 01319 unsigned long keysym1 = XKeycodeToKeysym(fl_display, keycode, 1); 01320 if (keysym1 <= 0x7f || (keysym1 > 0xff9f && keysym1 <= FL_KP_Last)) 01321 Fl::e_original_keysym = (int)(keysym1 | FL_KP); 01322 if ((xevent.xkey.state & Mod2Mask) && 01323 (keysym1 <= 0x7f || (keysym1 > 0xff9f && keysym1 <= FL_KP_Last))) { 01324 // Store ASCII numeric keypad value... 01325 keysym = keysym1 | FL_KP; 01326 buffer[0] = char(keysym1) & 0x7F; 01327 len = 1; 01328 } else { 01329 // Map keypad to special key... 01330 static const unsigned short table[15] = { 01331 FL_F+1, FL_F+2, FL_F+3, FL_F+4, 01332 FL_Home, FL_Left, FL_Up, FL_Right, 01333 FL_Down, FL_Page_Up, FL_Page_Down, FL_End, 01334 0xff0b/*XK_Clear*/, FL_Insert, FL_Delete}; 01335 keysym = table[keysym-0xff91]; 01336 } 01337 } else { 01338 // Store this so we can later know if the KP was used 01339 Fl::e_original_keysym = (int)keysym; 01340 } 01341 Fl::e_keysym = int(keysym); 01342 01343 // replace XK_ISO_Left_Tab (Shift-TAB) with FL_Tab (modifier flags are set correctly by X11) 01344 if (Fl::e_keysym == 0xfe20) Fl::e_keysym = FL_Tab; 01345 01346 set_event_xy(); 01347 Fl::e_is_click = 0; 01348 break;} 01349 01350 case ButtonPress: 01351 Fl::e_keysym = FL_Button + xevent.xbutton.button; 01352 set_event_xy(); 01353 if (xevent.xbutton.button == Button4) { 01354 Fl::e_dy = -1; // Up 01355 event = FL_MOUSEWHEEL; 01356 } else if (xevent.xbutton.button == Button5) { 01357 Fl::e_dy = +1; // Down 01358 event = FL_MOUSEWHEEL; 01359 } else { 01360 Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); 01361 event = FL_PUSH; 01362 checkdouble(); 01363 } 01364 01365 fl_xmousewin = window; 01366 in_a_window = true; 01367 break; 01368 01369 case MotionNotify: 01370 set_event_xy(); 01371 # if CONSOLIDATE_MOTION 01372 send_motion = fl_xmousewin = window; 01373 in_a_window = true; 01374 return 0; 01375 # else 01376 event = FL_MOVE; 01377 fl_xmousewin = window; 01378 in_a_window = true; 01379 break; 01380 # endif 01381 01382 case ButtonRelease: 01383 Fl::e_keysym = FL_Button + xevent.xbutton.button; 01384 set_event_xy(); 01385 Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1)); 01386 if (xevent.xbutton.button == Button4 || 01387 xevent.xbutton.button == Button5) return 0; 01388 event = FL_RELEASE; 01389 01390 fl_xmousewin = window; 01391 in_a_window = true; 01392 break; 01393 01394 case EnterNotify: 01395 if (xevent.xcrossing.detail == NotifyInferior) break; 01396 // XInstallColormap(fl_display, Fl_X::i(window)->colormap); 01397 set_event_xy(); 01398 Fl::e_state = xevent.xcrossing.state << 16; 01399 event = FL_ENTER; 01400 01401 fl_xmousewin = window; 01402 in_a_window = true; 01403 { XIMStyles *xim_styles = NULL; 01404 if(!fl_xim_im || XGetIMValues(fl_xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL)) { 01405 fl_init_xim(); 01406 } 01407 if (xim_styles) XFree(xim_styles); 01408 } 01409 break; 01410 01411 case LeaveNotify: 01412 if (xevent.xcrossing.detail == NotifyInferior) break; 01413 set_event_xy(); 01414 Fl::e_state = xevent.xcrossing.state << 16; 01415 fl_xmousewin = 0; 01416 in_a_window = false; // make do_queued_events produce FL_LEAVE event 01417 return 0; 01418 01419 // We cannot rely on the x,y position in the configure notify event. 01420 // I now think this is an unavoidable problem with X: it is impossible 01421 // for a window manager to prevent the "real" notify event from being 01422 // sent when it resizes the contents, even though it can send an 01423 // artificial event with the correct position afterwards (and some 01424 // window managers do not send this fake event anyway) 01425 // So anyway, do a round trip to find the correct x,y: 01426 case MapNotify: 01427 event = FL_SHOW; 01428 01429 case ConfigureNotify: { 01430 if (window->parent()) break; // ignore child windows 01431 01432 // figure out where OS really put window 01433 XWindowAttributes actual; 01434 XGetWindowAttributes(fl_display, fl_xid(window), &actual); 01435 Window cr; int X, Y, W = actual.width, H = actual.height; 01436 XTranslateCoordinates(fl_display, fl_xid(window), actual.root, 01437 0, 0, &X, &Y, &cr); 01438 01439 // tell Fl_Window about it and set flag to prevent echoing: 01440 resize_bug_fix = window; 01441 window->resize(X, Y, W, H); 01442 break; // allow add_handler to do something too 01443 } 01444 01445 case ReparentNotify: { 01446 int xpos, ypos; 01447 Window junk; 01448 01449 // on some systems, the ReparentNotify event is not handled as we would expect. 01450 XErrorHandler oldHandler = XSetErrorHandler(catchXExceptions()); 01451 01452 //ReparentNotify gives the new position of the window relative to 01453 //the new parent. FLTK cares about the position on the root window. 01454 XTranslateCoordinates(fl_display, xevent.xreparent.parent, 01455 XRootWindow(fl_display, fl_screen), 01456 xevent.xreparent.x, xevent.xreparent.y, 01457 &xpos, &ypos, &junk); 01458 XSetErrorHandler(oldHandler); 01459 01460 // tell Fl_Window about it and set flag to prevent echoing: 01461 if ( !wasXExceptionRaised() ) { 01462 resize_bug_fix = window; 01463 window->position(xpos, ypos); 01464 } 01465 break; 01466 } 01467 } 01468 01469 return Fl::handle(event, window); 01470 } 01471 01473 01474 void Fl_Window::resize(int X,int Y,int W,int H) { 01475 int is_a_move = (X != x() || Y != y()); 01476 int is_a_resize = (W != w() || H != h()); 01477 int is_a_enlarge = (W > w() || H > h()); 01478 int resize_from_program = (this != resize_bug_fix); 01479 if (!resize_from_program) resize_bug_fix = 0; 01480 if (is_a_move && resize_from_program) set_flag(FORCE_POSITION); 01481 else if (!is_a_resize && !is_a_move) return; 01482 if (is_a_resize) { 01483 Fl_Group::resize(X,Y,W,H); 01484 if (shown()) {redraw(); if(is_a_enlarge) i->wait_for_expose = 1;} 01485 } else { 01486 x(X); y(Y); 01487 } 01488 01489 if (resize_from_program && is_a_resize && !resizable()) { 01490 size_range(w(), h(), w(), h()); 01491 } 01492 01493 if (resize_from_program && shown()) { 01494 if (is_a_resize) { 01495 if (!resizable()) size_range(w(),h(),w(),h()); 01496 if (is_a_move) { 01497 XMoveResizeWindow(fl_display, i->xid, X, Y, W>0 ? W : 1, H>0 ? H : 1); 01498 } else { 01499 XResizeWindow(fl_display, i->xid, W>0 ? W : 1, H>0 ? H : 1); 01500 } 01501 } else 01502 XMoveWindow(fl_display, i->xid, X, Y); 01503 } 01504 } 01505 01507 01508 // A subclass of Fl_Window may call this to associate an X window it 01509 // creates with the Fl_Window: 01510 01511 void fl_fix_focus(); // in Fl.cxx 01512 01513 Fl_X* Fl_X::set_xid(Fl_Window* win, Window winxid) { 01514 Fl_X* xp = new Fl_X; 01515 xp->xid = winxid; 01516 xp->other_xid = 0; 01517 xp->setwindow(win); 01518 xp->next = Fl_X::first; 01519 xp->region = 0; 01520 xp->wait_for_expose = 1; 01521 xp->backbuffer_bad = 1; 01522 Fl_X::first = xp; 01523 if (win->modal()) {Fl::modal_ = win; fl_fix_focus();} 01524 return xp; 01525 } 01526 01527 // More commonly a subclass calls this, because it hides the really 01528 // ugly parts of X and sets all the stuff for a window that is set 01529 // normally. The global variables like fl_show_iconic are so that 01530 // subclasses of *that* class may change the behavior... 01531 01532 char fl_show_iconic; // hack for iconize() 01533 int fl_background_pixel = -1; // hack to speed up bg box drawing 01534 int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR 01535 01536 static const int childEventMask = ExposureMask; 01537 01538 static const int XEventMask = 01539 ExposureMask|StructureNotifyMask 01540 |KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask 01541 |ButtonPressMask|ButtonReleaseMask 01542 |EnterWindowMask|LeaveWindowMask 01543 |PointerMotionMask; 01544 01545 void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap) 01546 { 01547 Fl_Group::current(0); // get rid of very common user bug: forgot end() 01548 01549 int X = win->x(); 01550 int Y = win->y(); 01551 int W = win->w(); 01552 if (W <= 0) W = 1; // X don't like zero... 01553 int H = win->h(); 01554 if (H <= 0) H = 1; // X don't like zero... 01555 if (!win->parent() && !Fl::grab()) { 01556 // center windows in case window manager does not do anything: 01557 #ifdef FL_CENTER_WINDOWS 01558 if (!(win->flags() & Fl_Widget::FORCE_POSITION)) { 01559 win->x(X = scr_x+(scr_w-W)/2); 01560 win->y(Y = scr_y+(scr_h-H)/2); 01561 } 01562 #endif // FL_CENTER_WINDOWS 01563 01564 // force the window to be on-screen. Usually the X window manager 01565 // does this, but a few don't, so we do it here for consistency: 01566 int scr_x, scr_y, scr_w, scr_h; 01567 Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); 01568 01569 if (win->border()) { 01570 // ensure border is on screen: 01571 // (assume extremely minimal dimensions for this border) 01572 const int top = 20; 01573 const int left = 1; 01574 const int right = 1; 01575 const int bottom = 1; 01576 if (X+W+right > scr_x+scr_w) X = scr_x+scr_w-right-W; 01577 if (X-left < scr_x) X = scr_x+left; 01578 if (Y+H+bottom > scr_y+scr_h) Y = scr_y+scr_h-bottom-H; 01579 if (Y-top < scr_y) Y = scr_y+top; 01580 } 01581 // now insure contents are on-screen (more important than border): 01582 if (X+W > scr_x+scr_w) X = scr_x+scr_w-W; 01583 if (X < scr_x) X = scr_x; 01584 if (Y+H > scr_y+scr_h) Y = scr_y+scr_h-H; 01585 if (Y < scr_y) Y = scr_y; 01586 } 01587 01588 // if the window is a subwindow and our parent is not mapped yet, we 01589 // mark this window visible, so that mapping the parent at a later 01590 // point in time will call this function again to finally map the subwindow. 01591 if (win->parent() && !Fl_X::i(win->window())) { 01592 win->set_visible(); 01593 return; 01594 } 01595 01596 ulong root = win->parent() ? 01597 fl_xid(win->window()) : RootWindow(fl_display, fl_screen); 01598 01599 XSetWindowAttributes attr; 01600 int mask = CWBorderPixel|CWColormap|CWEventMask|CWBitGravity; 01601 attr.event_mask = win->parent() ? childEventMask : XEventMask; 01602 attr.colormap = colormap; 01603 attr.border_pixel = 0; 01604 attr.bit_gravity = 0; // StaticGravity; 01605 if (win->override()) { 01606 attr.override_redirect = 1; 01607 attr.save_under = 1; 01608 mask |= CWOverrideRedirect | CWSaveUnder; 01609 } else attr.override_redirect = 0; 01610 if (Fl::grab()) { 01611 attr.save_under = 1; mask |= CWSaveUnder; 01612 if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;} 01613 } 01614 if (fl_background_pixel >= 0) { 01615 attr.background_pixel = fl_background_pixel; 01616 fl_background_pixel = -1; 01617 mask |= CWBackPixel; 01618 } 01619 01620 Fl_X* xp = 01621 set_xid(win, XCreateWindow(fl_display, 01622 root, 01623 X, Y, W, H, 01624 0, // borderwidth 01625 visual->depth, 01626 InputOutput, 01627 visual->visual, 01628 mask, &attr)); 01629 int showit = 1; 01630 01631 if (!win->parent() && !attr.override_redirect) { 01632 // Communicate all kinds 'o junk to the X Window Manager: 01633 01634 win->label(win->label(), win->iconlabel()); 01635 01636 XChangeProperty(fl_display, xp->xid, WM_PROTOCOLS, 01637 XA_ATOM, 32, 0, (uchar*)&WM_DELETE_WINDOW, 1); 01638 01639 // send size limits and border: 01640 xp->sendxjunk(); 01641 01642 // set the class property, which controls the icon used: 01643 if (win->xclass()) { 01644 char buffer[1024]; 01645 char *p; const char *q; 01646 // truncate on any punctuation, because they break XResource lookup: 01647 for (p = buffer, q = win->xclass(); isalnum(*q)||(*q&128);) *p++ = *q++; 01648 *p++ = 0; 01649 // create the capitalized version: 01650 q = buffer; 01651 *p = toupper(*q++); if (*p++ == 'X') *p++ = toupper(*q++); 01652 while ((*p++ = *q++)); 01653 XChangeProperty(fl_display, xp->xid, XA_WM_CLASS, XA_STRING, 8, 0, 01654 (unsigned char *)buffer, p-buffer-1); 01655 } 01656 01657 if (win->non_modal() && xp->next && !fl_disable_transient_for) { 01658 // find some other window to be "transient for": 01659 Fl_Window* wp = xp->next->w; 01660 while (wp->parent()) wp = wp->window(); 01661 XSetTransientForHint(fl_display, xp->xid, fl_xid(wp)); 01662 if (!wp->visible()) showit = 0; // guess that wm will not show it 01663 } 01664 01665 // Make sure that borderless windows do not show in the task bar 01666 if (!win->border()) { 01667 Atom net_wm_state = XInternAtom (fl_display, "_NET_WM_STATE", 0); 01668 Atom net_wm_state_skip_taskbar = XInternAtom (fl_display, "_NET_WM_STATE_SKIP_TASKBAR", 0); 01669 XChangeProperty (fl_display, xp->xid, net_wm_state, XA_ATOM, 32, 01670 PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1); 01671 } 01672 01673 // Make it receptive to DnD: 01674 long version = 4; 01675 XChangeProperty(fl_display, xp->xid, fl_XdndAware, 01676 XA_ATOM, sizeof(int)*8, 0, (unsigned char*)&version, 1); 01677 01678 XWMHints *hints = XAllocWMHints(); 01679 hints->input = True; 01680 hints->flags = InputHint; 01681 if (fl_show_iconic) { 01682 hints->flags |= StateHint; 01683 hints->initial_state = IconicState; 01684 fl_show_iconic = 0; 01685 showit = 0; 01686 } 01687 if (win->icon()) { 01688 hints->icon_pixmap = (Pixmap)win->icon(); 01689 hints->flags |= IconPixmapHint; 01690 } 01691 XSetWMHints(fl_display, xp->xid, hints); 01692 XFree(hints); 01693 } 01694 01695 // set the window type for menu and tooltip windows to avoid animations (compiz) 01696 if (win->menu_window() || win->tooltip_window()) { 01697 Atom net_wm_type = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE", False); 01698 Atom net_wm_type_kind = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_MENU", False); 01699 XChangeProperty(fl_display, xp->xid, net_wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_type_kind, 1); 01700 } 01701 01702 XMapWindow(fl_display, xp->xid); 01703 if (showit) { 01704 win->set_visible(); 01705 int old_event = Fl::e_number; 01706 win->handle(Fl::e_number = FL_SHOW); // get child windows to appear 01707 Fl::e_number = old_event; 01708 win->redraw(); 01709 } 01710 } 01711 01713 // Send X window stuff that can be changed over time: 01714 01715 void Fl_X::sendxjunk() { 01716 if (w->parent() || w->override()) return; // it's not a window manager window! 01717 01718 if (!w->size_range_set) { // default size_range based on resizable(): 01719 if (w->resizable()) { 01720 Fl_Widget *o = w->resizable(); 01721 int minw = o->w(); if (minw > 100) minw = 100; 01722 int minh = o->h(); if (minh > 100) minh = 100; 01723 w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); 01724 } else { 01725 w->size_range(w->w(), w->h(), w->w(), w->h()); 01726 } 01727 return; // because this recursively called here 01728 } 01729 01730 XSizeHints *hints = XAllocSizeHints(); 01731 // memset(&hints, 0, sizeof(hints)); jreiser suggestion to fix purify? 01732 hints->min_width = w->minw; 01733 hints->min_height = w->minh; 01734 hints->max_width = w->maxw; 01735 hints->max_height = w->maxh; 01736 hints->width_inc = w->dw; 01737 hints->height_inc = w->dh; 01738 hints->win_gravity = StaticGravity; 01739 01740 // see the file /usr/include/X11/Xm/MwmUtil.h: 01741 // fill all fields to avoid bugs in kwm and perhaps other window managers: 01742 // 0, MWM_FUNC_ALL, MWM_DECOR_ALL 01743 long prop[5] = {0, 1, 1, 0, 0}; 01744 01745 if (hints->min_width != hints->max_width || 01746 hints->min_height != hints->max_height) { // resizable 01747 hints->flags = PMinSize|PWinGravity; 01748 if (hints->max_width >= hints->min_width || 01749 hints->max_height >= hints->min_height) { 01750 hints->flags = PMinSize|PMaxSize|PWinGravity; 01751 // unfortunately we can't set just one maximum size. Guess a 01752 // value for the other one. Some window managers will make the 01753 // window fit on screen when maximized, others will put it off screen: 01754 if (hints->max_width < hints->min_width) hints->max_width = Fl::w(); 01755 if (hints->max_height < hints->min_height) hints->max_height = Fl::h(); 01756 } 01757 if (hints->width_inc && hints->height_inc) hints->flags |= PResizeInc; 01758 if (w->aspect) { 01759 // stupid X! It could insist that the corner go on the 01760 // straight line between min and max... 01761 hints->min_aspect.x = hints->max_aspect.x = hints->min_width; 01762 hints->min_aspect.y = hints->max_aspect.y = hints->min_height; 01763 hints->flags |= PAspect; 01764 } 01765 } else { // not resizable: 01766 hints->flags = PMinSize|PMaxSize|PWinGravity; 01767 prop[0] = 1; // MWM_HINTS_FUNCTIONS 01768 prop[1] = 1|2|16; // MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE 01769 } 01770 01771 if (w->flags() & Fl_Widget::FORCE_POSITION) { 01772 hints->flags |= USPosition; 01773 hints->x = w->x(); 01774 hints->y = w->y(); 01775 } 01776 01777 if (!w->border()) { 01778 prop[0] |= 2; // MWM_HINTS_DECORATIONS 01779 prop[2] = 0; // no decorations 01780 } 01781 01782 XSetWMNormalHints(fl_display, xid, hints); 01783 XChangeProperty(fl_display, xid, 01784 fl_MOTIF_WM_HINTS, fl_MOTIF_WM_HINTS, 01785 32, 0, (unsigned char *)prop, 5); 01786 XFree(hints); 01787 } 01788 01789 void Fl_Window::size_range_() { 01790 size_range_set = 1; 01791 if (shown()) i->sendxjunk(); 01792 } 01793 01795 01796 // returns pointer to the filename, or null if name ends with '/' 01797 const char *fl_filename_name(const char *name) { 01798 const char *p,*q; 01799 if (!name) return (0); 01800 for (p=q=name; *p;) if (*p++ == '/') q = p; 01801 return q; 01802 } 01803 01804 void Fl_Window::label(const char *name,const char *iname) { 01805 Fl_Widget::label(name); 01806 iconlabel_ = iname; 01807 if (shown() && !parent()) { 01808 if (!name) name = ""; 01809 int namelen = strlen(name); 01810 if (!iname) iname = fl_filename_name(name); 01811 int inamelen = strlen(iname); 01812 XChangeProperty(fl_display, i->xid, fl_NET_WM_NAME, fl_XaUtf8String, 8, 0, (uchar*)name, namelen); // utf8 01813 XChangeProperty(fl_display, i->xid, XA_WM_NAME, XA_STRING, 8, 0, (uchar*)name, namelen); // non-utf8 01814 XChangeProperty(fl_display, i->xid, fl_NET_WM_ICON_NAME, fl_XaUtf8String, 8, 0, (uchar*)iname, inamelen); // utf8 01815 XChangeProperty(fl_display, i->xid, XA_WM_ICON_NAME, XA_STRING, 8, 0, (uchar*)iname, inamelen); // non-utf8 01816 } 01817 } 01818 01820 // Implement the virtual functions for the base Fl_Window class: 01821 01822 // If the box is a filled rectangle, we can make the redisplay *look* 01823 // faster by using X's background pixel erasing. We can make it 01824 // actually *be* faster by drawing the frame only, this is done by 01825 // setting fl_boxcheat, which is seen by code in fl_drawbox.cxx: 01826 // 01827 // On XFree86 (and prehaps all X's) this has a problem if the window 01828 // is resized while a save-behind window is atop it. The previous 01829 // contents are restored to the area, but this assumes the area 01830 // is cleared to background color. So this is disabled in this version. 01831 // Fl_Window *fl_boxcheat; 01832 static inline int can_boxcheat(uchar b) {return (b==1 || ((b&2) && b<=15));} 01833 01834 void Fl_Window::show() { 01835 image(Fl::scheme_bg_); 01836 if (Fl::scheme_bg_) { 01837 labeltype(FL_NORMAL_LABEL); 01838 align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); 01839 } else { 01840 labeltype(FL_NO_LABEL); 01841 } 01842 Fl_Tooltip::exit(this); 01843 if (!shown()) { 01844 fl_open_display(); 01845 // Don't set background pixel for double-buffered windows... 01846 if (type() == FL_WINDOW && can_boxcheat(box())) { 01847 fl_background_pixel = int(fl_xpixel(color())); 01848 } 01849 Fl_X::make_xid(this); 01850 } else { 01851 XMapRaised(fl_display, i->xid); 01852 } 01853 #ifdef USE_PRINT_BUTTON 01854 void preparePrintFront(void); 01855 preparePrintFront(); 01856 #endif 01857 } 01858 01859 Window fl_window; 01860 Fl_Window *Fl_Window::current_; 01861 GC fl_gc; 01862 01863 // make X drawing go into this window (called by subclass flush() impl.) 01864 void Fl_Window::make_current() { 01865 static GC gc; // the GC used by all X windows 01866 if (!gc) gc = XCreateGC(fl_display, i->xid, 0, 0); 01867 fl_window = i->xid; 01868 fl_gc = gc; 01869 current_ = this; 01870 fl_clip_region(0); 01871 01872 #ifdef FLTK_USE_CAIRO 01873 // update the cairo_t context 01874 if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this); 01875 #endif 01876 01877 } 01878 01879 #ifdef USE_PRINT_BUTTON 01880 // to test the Fl_Printer class creating a "Print front window" button in a separate window 01881 // contains also preparePrintFront call above 01882 #include <FL/Fl_Printer.H> 01883 #include <FL/Fl_Button.H> 01884 void printFront(Fl_Widget *o, void *data) 01885 { 01886 Fl_Printer printer; 01887 o->window()->hide(); 01888 Fl_Window *win = Fl::first_window(); 01889 if(!win) return; 01890 int w, h; 01891 if( printer.start_job(1) ) { o->window()->show(); return; } 01892 if( printer.start_page() ) { o->window()->show(); return; } 01893 printer.printable_rect(&w,&h); 01894 // scale the printer device so that the window fits on the page 01895 float scale = 1; 01896 if (win->w() > w || win->h() > h) { 01897 scale = (float)w/win->w(); 01898 if ((float)h/win->h() < scale) scale = (float)h/win->h(); 01899 printer.scale(scale, scale); 01900 } 01901 01902 // #define ROTATE 20.0 01903 #ifdef ROTATE 01904 printer.scale(scale * 0.8, scale * 0.8); 01905 printer.printable_rect(&w, &h); 01906 printer.origin(w/2, h/2 ); 01907 printer.rotate(ROTATE); 01908 printer.print_widget( win, - win->w()/2, - win->h()/2 ); 01909 //printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 ); 01910 #else 01911 printer.print_widget( win ); 01912 //printer.print_window_part( win, 0,0,win->w(), win->h() ); 01913 #endif 01914 01915 printer.end_page(); 01916 printer.end_job(); 01917 o->window()->show(); 01918 } 01919 01920 void preparePrintFront(void) 01921 { 01922 static int first=1; 01923 if(!first) return; 01924 first=0; 01925 static Fl_Window w(0,0,150,30); 01926 static Fl_Button b(0,0,w.w(),w.h(), "Print front window"); 01927 b.callback(printFront); 01928 w.end(); 01929 w.show(); 01930 } 01931 #endif // USE_PRINT_BUTTON 01932 01933 #endif 01934 01935 // 01936 // End of "$Id: Fl_x.cxx 8198 2011-01-06 10:24:58Z manolo $". 01937 //