diff options
Diffstat (limited to 'src/Fl_x.cxx')
| -rw-r--r-- | src/Fl_x.cxx | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx new file mode 100644 index 000000000..2d5a5ab46 --- /dev/null +++ b/src/Fl_x.cxx @@ -0,0 +1,807 @@ +// Fl_x.C + +// fltk (Fast Light Tool Kit) version 0.99 +// Copyright (C) 1998 Bill Spitzak + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. + +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. + +// Written by Bill Spitzak spitzak@d2.com + +#ifdef WIN32 +#include "Fl_win32.C" +#else + +#include <config.h> +#include <FL/Fl.H> +#include <FL/x.H> +#include <FL/Fl_Window.H> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + +//////////////////////////////////////////////////////////////// +// interface to poll/select call: + +#if HAVE_POLL +#include <poll.h> +#else +struct pollfd {int fd; short events; short revents;}; +#define POLLIN 1 +#define POLLOUT 4 +#define POLLERR 8 +#ifdef __sgi // fix bugs in Irix's select header: +//inline static void bzero(void *b, int l) {memset(b,0,l);} +extern "C" int select( int, fd_set *, fd_set *, fd_set *, struct timeval * ); +#endif +#ifdef hpux // fix from wm2: +#define select(a,b,c,d,e) select((a),(int *)(b),(int *)(c),(int *)(d),(e)) +#endif +#ifdef __EMX__ +#include <sys/select.h> +#endif +#endif + +#define MAXFD 8 +#if !HAVE_POLL +static fd_set fdsets[3]; +static int maxfd; +#endif +static int nfds; +static struct pollfd fds[MAXFD]; +static struct { + void (*cb)(int, void*); + void* arg; +} fd[MAXFD]; + +void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { + int i; + if (nfds < MAXFD) {i = nfds; nfds++;} else {i = MAXFD-1;} + fds[i].fd = n; + fds[i].events = events; +#if !HAVE_POLL + if (events & POLLIN) FD_SET(n, &fdsets[0]); + if (events & POLLOUT) FD_SET(n, &fdsets[1]); + if (events & POLLERR) FD_SET(n, &fdsets[2]); + if (n > maxfd) maxfd = n; +#endif + fd[i].cb = cb; + fd[i].arg = v; +} + +void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { + Fl::add_fd(fd,POLLIN,cb,v); +} + +void Fl::remove_fd(int n) { + int i,j; + for (i=j=0; i<nfds; i++) { + if (fds[i].fd == n); + else {if (j<i) {fd[j]=fd[i]; fds[j]=fds[i];} j++;} + } + nfds = j; +#if !HAVE_POLL + FD_CLR(n, &fdsets[0]); + FD_CLR(n, &fdsets[1]); + FD_CLR(n, &fdsets[2]); + if (n == maxfd) maxfd--; +#endif +} + +int fl_ready() { + if (XQLength(fl_display)) return 1; +#if HAVE_POLL + return ::poll(fds, nfds, 0); +#else + timeval t; + t.tv_sec = 0; + t.tv_usec = 0; + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; + return ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); +#endif +} + +static void do_queued_events() { + while (XEventsQueued(fl_display,QueuedAfterReading)) { + XEvent xevent; + XNextEvent(fl_display, &xevent); + fl_handle(xevent); + } +} + +double fl_wait(int timeout_flag, double time) { + + // OpenGL and other broken libraries call XEventsQueued + // unnecessarily and thus cause the file descriptor to not be ready, + // so we must check for already-read events: + if (XQLength(fl_display)) {do_queued_events(); return time;} + +#if !HAVE_POLL + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; +#endif + int n; + + if (!timeout_flag) { +#if HAVE_POLL + n = ::poll(fds, nfds, -1); +#else + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); +#endif + } else { +#if HAVE_POLL + int n = ::poll(fds, nfds, time > 0.0 ? int(time*1000) : 0); +#else + timeval t; + if (time <= 0.0) { + t.tv_sec = 0; + t.tv_usec = 0; + } else { + t.tv_sec = int(time); + t.tv_usec = int(1000000 * (time-t.tv_sec)); + } + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); +#endif + } + if (n > 0) { + for (int i=0; i<nfds; i++) { +#if HAVE_POLL + if (fds[i].revents) fd[i].cb(fds[i].fd, fd[i].arg); +#else + int f = fds[i].fd; + short revents = 0; + if (FD_ISSET(f,&fdt[0])) revents |= POLLIN; + if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT; + if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; + if (fds[i].events & revents) fd[i].cb(f, fd[i].arg); +#endif + } + } + return time; +} + +//////////////////////////////////////////////////////////////// + +Display *fl_display; +int fl_screen; +XVisualInfo *fl_visual; +Colormap fl_colormap; + +static Atom wm_delete_window; +static Atom wm_protocols; +static Atom _motif_wm_hints; + +static void fd_callback(int,void *) {do_queued_events();} + +static int io_error_handler(Display*) {Fl::fatal("X I/O error"); return 0;} + +static int xerror_handler(Display* d, XErrorEvent* e) { + char buf1[128], buf2[128]; + sprintf(buf1, "XRequest.%d", e->request_code); + XGetErrorDatabaseText(d,"",buf1,buf1,buf2,128); + XGetErrorText(d, e->error_code, buf1, 128); + Fl::warning("%s: %s 0x%lx", buf2, buf1, e->resourceid); + return 0; +} + +void fl_open_display() { + if (fl_display) return; + + XSetIOErrorHandler(io_error_handler); + XSetErrorHandler(xerror_handler); + + Display *d = XOpenDisplay(0); + if (!d) Fl::fatal("Can't open display: %s",XDisplayName(0)); + + fl_display = d; + + wm_delete_window = XInternAtom(d,"WM_DELETE_WINDOW",0); + wm_protocols = XInternAtom(d,"WM_PROTOCOLS",0); + _motif_wm_hints = XInternAtom(d,"_MOTIF_WM_HINTS",0); + Fl::add_fd(ConnectionNumber(d), POLLIN, fd_callback); + + fl_screen = DefaultScreen(fl_display); +// construct an XVisualInfo that matches the default Visual: + XVisualInfo templt; int num; + templt.visualid = XVisualIDFromVisual(DefaultVisual(fl_display,fl_screen)); + fl_visual = XGetVisualInfo(fl_display, VisualIDMask, &templt, &num); + fl_colormap = DefaultColormap(fl_display,fl_screen); +} + +void fl_close_display() { + Fl::remove_fd(ConnectionNumber(fl_display)); + XCloseDisplay(fl_display); +} + +int Fl::h() { + fl_open_display(); + return DisplayHeight(fl_display,fl_screen); +} + +int Fl::w() { + fl_open_display(); + return DisplayWidth(fl_display,fl_screen); +} + +void Fl::get_mouse(int &x, int &y) { + fl_open_display(); + Window root = RootWindow(fl_display, fl_screen); + Window c; int mx,my,cx,cy; unsigned int mask; + XQueryPointer(fl_display,root,&root,&c,&mx,&my,&cx,&cy,&mask); + x = mx; + y = my; +} + +//////////////////////////////////////////////////////////////// + +extern Fl_Window *fl_xfocus; // in Fl.C +extern Fl_Window *fl_xmousewin; // in Fl.C +void fl_fix_focus(); // in Fl.C + +//////////////////////////////////////////////////////////////// + +const XEvent* fl_xevent; // the current x event +ulong fl_event_time; // the last timestamp from an x event + +char fl_key_vector[32]; // used by Fl::get_key() + +// Record event mouse position and state from an XEvent: + +static int px, py; +static ulong ptime; + +static void set_event_xy() { + Fl::e_x_root = fl_xevent->xbutton.x_root; + Fl::e_x = fl_xevent->xbutton.x; + Fl::e_y_root = fl_xevent->xbutton.y_root; + Fl::e_y = fl_xevent->xbutton.y; + Fl::e_state = fl_xevent->xbutton.state << 16; + fl_event_time = fl_xevent->xbutton.time; +#ifdef __sgi + // get the meta key off PC keyboards: + if (fl_key_vector[18]&0x18) Fl::e_state |= FL_META; +#endif + // turn off is_click if enough time or mouse movement has passed: + if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 + || fl_event_time >= ptime+1000) + Fl::e_is_click = 0; +} + +// if this is same event as last && is_click, increment click count: +static inline void checkdouble() { + if (Fl::e_is_click == Fl::e_keysym) + Fl::e_clicks++; + else { + Fl::e_clicks = 0; + Fl::e_is_click = Fl::e_keysym; + } + px = Fl::e_x_root; + py = Fl::e_y_root; + ptime = fl_event_time; +} + +static Fl_Window* resize_bug_fix; + +//////////////////////////////////////////////////////////////// + +int fl_handle(const XEvent& xevent) +{ + fl_xevent = &xevent; + + switch (xevent.type) { // events where we don't care about window + + case KeymapNotify: + memcpy(fl_key_vector, xevent.xkeymap.key_vector, 32); + return 0; + + case MappingNotify: + XRefreshKeyboardMapping((XMappingEvent*)&xevent.xmapping); + return 0; + } + + int event = 0; + Fl_Window* window = fl_find(xevent.xany.window); + + if (window) switch (xevent.type) { + + case ClientMessage: + if ((Atom)(xevent.xclient.data.l[0]) == wm_delete_window) event = FL_CLOSE; + break; + + case MapNotify: + event = FL_SHOW; + break; + + case UnmapNotify: + event = FL_HIDE; + break; + + case Expose: + case GraphicsExpose: +#if 1 // try to keep windows on top even if WM_TRANSIENT_FOR does not work: + if (Fl::first_window()->non_modal() && window != Fl::first_window()) + Fl::first_window()->show(); +#endif + window->damage(2, xevent.xexpose.x, xevent.xexpose.y, + xevent.xexpose.width, xevent.xexpose.height); + return 1; + + case ButtonPress: + Fl::e_keysym = FL_Button + xevent.xbutton.button; + set_event_xy(); checkdouble(); + // fix buggy window managers that position window wrong: + Fl_X::x(window,Fl::e_x_root-Fl::e_x); + Fl_X::y(window,Fl::e_y_root-Fl::e_y); + Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); + event = FL_PUSH; + break; + + case MotionNotify: + set_event_xy(); + event = FL_MOVE; + break; + + case ButtonRelease: + Fl::e_keysym = FL_Button + xevent.xbutton.button; + set_event_xy(); + Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1)); + event = FL_RELEASE; + break; + + case FocusIn: + event = FL_FOCUS; + break; + + case FocusOut: + event = FL_UNFOCUS; + break; + + case KeyPress: { + static int got_backspace; + static char buffer[21]; + KeySym keysym; + int i = xevent.xkey.keycode; fl_key_vector[i/8] |= (1 << (i%8)); + int len = XLookupString((XKeyEvent*)&(xevent.xkey),buffer,20,&keysym,0); + if (!len && keysym < 0x400) { + // turn all latin-2,3,4 characters into 8-bit codes: + buffer[0] = char(keysym); + len = 1; + } + // ignore all effects of shift on the keysyms (makes it a lot + // easier to program shortcuts!) + keysym = XKeycodeToKeysym(fl_display, i, 0); +#ifdef __sgi + // get some missing PC keyboard keys: + if (!keysym) switch(i) { + case 147: keysym = FL_Meta_L; break; + case 148: keysym = FL_Meta_R; break; + case 149: keysym = FL_Menu; break; + } +#endif + if (!got_backspace) { + // Backspace kludge: until user hits the backspace key, assumme + // it is missing and use the Delete key for that purpose: + if (keysym == FL_Delete) keysym = FL_BackSpace; + else if (keysym == FL_BackSpace) got_backspace = 1; + } + if (keysym >= 0xff95 && keysym < 0xffa0) { + // Make NumLock irrelevant (always on): + // This lookup table turns the XK_KP_* functions back into the + // ascii characters. This won't work on non-PC layout keyboards, + // but are there any of those left?? + buffer[0] = "7486293150."[keysym-0xff95]; + len = 1; + keysym = FL_KP+buffer[0]; + } + buffer[len] = 0; + Fl::e_keysym = int(keysym); + Fl::e_text = buffer; + Fl::e_length = len; + set_event_xy(); Fl::e_is_click = 0; + if (Fl::event_state(FL_CTRL) && keysym == '-') buffer[0] = 0x1f; // ^_ + event = FL_KEYBOARD; + break;} + + case KeyRelease: { + int i = xevent.xkey.keycode; fl_key_vector[i/8] &= ~(1 << (i%8)); + set_event_xy();} + break; + + case EnterNotify: + if (xevent.xcrossing.detail == NotifyInferior) break; + // XInstallColormap(fl_display, Fl_X::i(window)->colormap); + set_event_xy(); + Fl::e_state = xevent.xcrossing.state << 16; + event = FL_ENTER; + break; + + case LeaveNotify: + if (xevent.xcrossing.detail == NotifyInferior) break; + set_event_xy(); + Fl::e_state = xevent.xcrossing.state << 16; + event = FL_LEAVE; + break; + + case ConfigureNotify: { + int x = xevent.xconfigure.x; + int y = xevent.xconfigure.y; + // avoid bug (?) in 4DWM, it reports position of 0,0 on resize: + if (!x && !y) { + Window r, c; int X, Y; unsigned int m; + XQueryPointer(fl_display, fl_xid(window), &r, &c, &x, &y, &X, &Y, &m); + x = x-X; y = y-Y; + } + resize_bug_fix = window; + window->resize(x, y, + xevent.xconfigure.width, xevent.xconfigure.height); + return 1;} + } + + return Fl::handle(event, window); +} + +//////////////////////////////////////////////////////////////// + +void Fl_Window::resize(int X,int Y,int W,int H) { + if (resize_bug_fix == this) + resize_bug_fix = 0; + else if (shown()) { + // tell X window manager to change window size: + if (!(flags()&FL_FORCE_POSITION) && X == x() && Y == y()) + XResizeWindow(fl_display, i->xid, W>0 ? W : 1, H>0 ? H : 1); + else if (W != w() || H != h()) + XMoveResizeWindow(fl_display, i->xid, X, Y, W>0 ? W : 1, H>0 ? H : 1); + else + XMoveWindow(fl_display, i->xid, X, Y); + } + if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION); + if (W != w() || H != h()) Fl_Group::resize(X,Y,W,H); else {x(X); y(Y);} + // Notice that this does *not* set any redraw bits. I assumme + // I will receive damage for the whole window from X. I think + // that "ForgetGravity" forces the expose event for the entire + // window, but this may not be true on some implementations. +} + +//////////////////////////////////////////////////////////////// + +// A subclass of Fl_Window may call this to associate an X window it +// creates with the Fl_Window: + +Fl_X* Fl_X::set_xid(Fl_Window* w, Window xid) { + Fl_X* x = new Fl_X; + x->xid = xid; + x->other_xid = 0; + x->setwindow(w); + x->next = Fl_X::first; + x->region = 0; + Fl_X::first = x; + w->set_visible(); + w->handle(FL_SHOW); // get child windows to appear + fl_fix_focus(); // if this is modal we must fix focus now + return x; +} + +// More commonly a subclass calls this, because it hides the really +// ugly parts of X and sets all the stuff for a window that is set +// normally. The global variables like fl_show_iconic are so that +// subclasses of *that* class may change the behavior... + +char fl_show_iconic; // hack for iconize() +int fl_background_pixel = -1; // hack to speed up bg box drawing +int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR + +static const int childEventMask = ExposureMask; + +static const int XEventMask = +ExposureMask|StructureNotifyMask +|KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask +|ButtonPressMask|ButtonReleaseMask +|EnterWindowMask|LeaveWindowMask +|PointerMotionMask; + +void Fl_X::make_xid(Fl_Window* w, XVisualInfo *visual, Colormap colormap) +{ + Fl_Group::current(0); // get rid of very common user bug: forgot end() + + ulong root = w->parent() ? + fl_xid(w->window()) : RootWindow(fl_display, fl_screen); + + XSetWindowAttributes attr; + int mask = CWBorderPixel|CWColormap|CWEventMask|CWBitGravity; + attr.event_mask = w->parent() ? childEventMask : XEventMask; + attr.colormap = colormap; + attr.border_pixel = 0; + attr.bit_gravity = 0; // StaticGravity; + attr.override_redirect = 0; + if (Fl::grab()) { + attr.save_under = 1; mask |= CWSaveUnder; + if (!w->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;} + } + if (fl_background_pixel >= 0) { + attr.background_pixel = fl_background_pixel; + fl_background_pixel = -1; + mask |= CWBackPixel; + } + Fl_X* x = + set_xid(w, XCreateWindow(fl_display, + root, + w->x(), w->y(), + w->w()>0 ? w->w() : 1, + w->h()>0 ? w->h() : 1, + 0, // borderwidth + visual->depth, + InputOutput, + visual->visual, + mask, &attr)); + //XInstallColormap(fl_display, colormap); + + if (!w->parent() && !attr.override_redirect) { + // Communicate all kinds 'o junk to the X Window Manager: + + w->label(w->label(), w->iconlabel()); + + XChangeProperty(fl_display, x->xid, wm_protocols, + XA_ATOM, 32, 0, (uchar*)&wm_delete_window, 1); + + // send size limits and border: + x->sendxjunk(); + + // set the class property, which controls the icon used: + if (w->xclass()) { + char buffer[1024]; + char *p; const char *q; + // truncate on any punctuation, because they break XResource lookup: + for (p = buffer, q = w->xclass(); isalnum(*q)||(*q&128);) *p++ = *q++; + *p++ = 0; + // create the capitalized version: + q = buffer; + *p = toupper(*q++); if (*p++ == 'X') *p++ = toupper(*q++); + while ((*p++ = *q++)); + XChangeProperty(fl_display, x->xid, XA_WM_CLASS, XA_STRING, 8, 0, + (unsigned char *)buffer, p-buffer-1); + } + + if (w->non_modal() && x->next && !fl_disable_transient_for) { + // find some other window to be "transient for": + Fl_Window* w = x->next->w; + while (w->parent()) w = w->window(); + XSetTransientForHint(fl_display, x->xid, fl_xid(w)); + } + + if (fl_show_iconic) { + XWMHints hints; + hints.flags = StateHint; + hints.initial_state = 3; + XSetWMHints(fl_display, x->xid, &hints); + fl_show_iconic = 0; + } + } + + XMapWindow(fl_display, x->xid); +} + +//////////////////////////////////////////////////////////////// +// Send X window stuff that can be changed over time: + +void Fl_X::sendxjunk() { + if (w->parent()) return; // it's not a window manager window! + + if (!w->size_range_set) { // default size_range based on resizable(): + if (w->resizable()) { + Fl_Widget *o = w->resizable(); + int minw = o->w(); if (minw > 100) minw = 100; + int minh = o->h(); if (minh > 100) minh = 100; + w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); + } else { + w->size_range(w->w(), w->h(), w->w(), w->h()); + } + return; // because this recursively called here + } + + XSizeHints hints; + hints.min_width = w->minw; + hints.min_height = w->minh; + hints.max_width = w->maxw; + hints.max_height = w->maxh; + hints.width_inc = w->dw; + hints.height_inc = w->dh; + + // see the file /usr/include/X11/Xm/MwmUtil.h: + // fill all fields to avoid bugs in kwm and perhaps other window managers: + // 0, MWM_FUNC_ALL, MWM_DECOR_ALL + long prop[5] = {0, 1, 1, 0, 0}; + + if (hints.min_width != hints.max_width || + hints.min_height != hints.max_height) { // resizable + hints.flags = PMinSize; + if (hints.max_width >= hints.min_width || + hints.max_height >= hints.min_height) { + hints.flags = PMinSize|PMaxSize; + // unfortunately we can't set just one maximum size. Guess a + // value for the other one. Some window managers will make the + // window fit on screen when maximized, others will put it off screen: + if (hints.max_width < hints.min_width) hints.max_width = Fl::w(); + if (hints.max_height < hints.min_height) hints.max_height = Fl::h(); + } + if (hints.width_inc && hints.height_inc) hints.flags |= PResizeInc; + if (w->aspect) { + // stupid X! It could insist that the corner go on the + // straight line between min and max... + hints.min_aspect.x = hints.max_aspect.x = hints.min_width; + hints.min_aspect.y = hints.max_aspect.y = hints.min_height; + hints.flags |= PAspect; + } + } else { // not resizable: + hints.flags = PMinSize|PMaxSize; + prop[0] = 1; // MWM_HINTS_FUNCTIONS + prop[1] = 1|2|16; // MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE + } + if (w->non_modal()) { + prop[0] = 1; // MWM_HINTS_FUNCTIONS + prop[1] |= 8; // turn off MWM_FUNC_MINIMIZE in 4Dwm + } + + if (w->flags() & Fl_Window::FL_FORCE_POSITION) { + hints.flags |= USPosition; + hints.x = w->x(); + hints.y = w->y(); + } + + if (!w->border()) { + prop[0] |= 2; // MWM_HINTS_DECORATIONS + prop[2] = 0; // no decorations + } + + XSetWMNormalHints(fl_display, xid, &hints); + XChangeProperty(fl_display, xid, + _motif_wm_hints, _motif_wm_hints, + 32, 0, (unsigned char *)prop, 5); +} + +void Fl_Window::size_range_() { + size_range_set = 1; + if (shown()) i->sendxjunk(); +} + +//////////////////////////////////////////////////////////////// + +// returns pointer to the filename, or null if name ends with '/' +const char *filename_name(const char *name) { + const char *p,*q; + for (p=q=name; *p;) if (*p++ == '/') q = p; + return q; +} + +void Fl_Window::label(const char *name,const char *iname) { + Fl_Widget::label(name); + iconlabel_ = iname; + if (shown() && !parent()) { + if (!name) name = ""; + XChangeProperty(fl_display, i->xid, XA_WM_NAME, + XA_STRING, 8, 0, (uchar*)name, strlen(name)); + if (!iname) iname = filename_name(name); + XChangeProperty(fl_display, i->xid, XA_WM_ICON_NAME, + XA_STRING, 8, 0, (uchar*)iname, strlen(iname)); + } +} + +//////////////////////////////////////////////////////////////// +// Implement the virtual functions for the base Fl_Window class: + +// If the box is a filled rectangle, we can make the redisplay *look* +// faster by using X's background pixel erasing. We can make it +// actually *be* faster by drawing the frame only, this is done by +// setting fl_boxcheat, which is seen by code in fl_drawbox.C: +// +// On XFree86 (and prehaps all X's) this has a problem if the window +// is resized while a save-behind window is atop it. The previous +// contents are restored to the area, but this assummes the area +// is cleared to background color. So this is disabled in this version. +// Fl_Window *fl_boxcheat; +static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} + +void Fl_Window::show() { + if (!shown()) { + fl_open_display(); + if (can_boxcheat(box())) fl_background_pixel = int(fl_xpixel(color())); + Fl_X::make_xid(this); + } else { + XMapRaised(fl_display, i->xid); + } +} + +Window fl_window; +Fl_Window *Fl_Window::current_; +GC fl_gc; + +// make X drawing go into this window (called by subclass flush() impl.) +void Fl_Window::make_current() { + static GC gc; // the GC used by all X windows + if (!gc) gc = XCreateGC(fl_display, i->xid, 0, 0); + fl_window = i->xid; + fl_gc = gc; + current_ = this; + fl_clip_region(0); +} + +#include <FL/fl_draw.H> + +// Current meaning of damage() bits on a window: +// 1 = a child needs redrawing +// 2 = expose events +// 128 = redraw everything + +void Fl_Widget::damage(uchar flags) { + if (type() < FL_WINDOW) { + damage(flags, x(), y(), w(), h()); + } else { + Fl_X* i = Fl_X::i((Fl_Window*)this); + if (i) { + if (i->region) {XDestroyRegion(i->region); i->region = 0;} + damage_ |= flags; + Fl::damage(1); + } + } +} + +void Fl_Widget::redraw() {damage(~0);} + +Region XRectangleRegion(int x, int y, int w, int h); // in fl_rect.C + +void Fl_Widget::damage(uchar flags, int X, int Y, int W, int H) { + if (type() < FL_WINDOW) { + damage_ |= flags; + if (parent()) parent()->damage(1,X,Y,W,H); + } else { + // see if damage covers entire window: + if (X<=0 && Y<=0 && W>=w() && H>=h()) {damage(flags); return;} + Fl_X* i = Fl_X::i((Fl_Window*)this); + if (i) { + if (damage()) { + // if we already have damage we must merge with existing region: + if (i->region) { + XRectangle R; + R.x = X; R.y = Y; R.width = W; R.height = H; + XUnionRectWithRegion(&R, i->region, i->region); + } + damage_ |= flags; + } else { + // create a new region: + if (i->region) XDestroyRegion(i->region); + i->region = XRectangleRegion(X,Y,W,H); + damage_ = flags; + } + Fl::damage(1); + } + } +} + +void Fl_Window::flush() { + make_current(); +//if (damage() == 2 && can_boxcheat(box())) fl_boxcheat = this; + fl_clip_region(i->region); i->region = 0; + draw(); +} + +#endif +// End of Fl_x.C |
