diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl.cxx | 1131 | ||||
| -rw-r--r-- | src/Fl_Double_Window.cxx | 320 | ||||
| -rw-r--r-- | src/Fl_Gl_Window.cxx | 580 | ||||
| -rw-r--r-- | src/Fl_visual.cxx | 157 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 1463 | ||||
| -rw-r--r-- | src/fl_font_win32.cxx | 318 | ||||
| -rw-r--r-- | src/fl_rect.cxx | 731 | ||||
| -rw-r--r-- | src/gl_start.cxx | 196 | ||||
| -rw-r--r-- | src/numericsort.c | 109 | ||||
| -rw-r--r-- | src/scandir_win32.c | 161 |
10 files changed, 2613 insertions, 2553 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx index 06a0c62b1..17973ded6 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,566 +1,565 @@ -// Fl.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 - -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include <FL/x.H> -#include <ctype.h> - -int Fl::damage_; -Fl_Widget *Fl::belowmouse_; -Fl_Widget *Fl::pushed_; -Fl_Widget *Fl::focus_; -Fl_Widget *Fl::selection_owner_; -int Fl::e_x, Fl::e_y, Fl::e_x_root, Fl::e_y_root; -int Fl::e_state; -int Fl::e_clicks; -int Fl::e_is_click; -int Fl::e_keysym; -char *Fl::e_text; -int Fl::e_length; - -int Fl::event_inside(int x,int y,int w,int h) /*const*/ { - int mx = event_x(); - int my = event_y(); - return (mx >= x && mx < x+w && my >= y && my < y+h); -} - -int Fl::event_inside(const Fl_Widget *o) /*const*/ { - return event_inside(o->x(),o->y(),o->w(),o->h()); -} - -// Timeouts are insert-sorted into order. This works good if there -// are only a small number: - -#define MAXTIMEOUT 8 - -static struct { - double time; - void (*cb)(void*); - void* arg; -} timeout[MAXTIMEOUT+1]; -static int numtimeouts; - -void Fl::add_timeout(double t, void (*cb)(void *), void *v) { - int i; - if (numtimeouts<MAXTIMEOUT) numtimeouts++; - for (i=0; i<numtimeouts-1; i++) { - if (timeout[i].time > t) { - for (int j=numtimeouts-1; j>i; j--) timeout[j] = timeout[j-1]; - break; - } - } - timeout[i].time = t; - timeout[i].cb = cb; - timeout[i].arg = v; -} - -void Fl::remove_timeout(void (*cb)(void *), void *v) { - int i,j; - for (i=j=0; i<numtimeouts; i++) { - if (timeout[i].cb == cb && timeout[i].arg==v) ; - else {if (j<i) timeout[j]=timeout[i]; j++;} - } - numtimeouts = j; -} - -static void call_timeouts() { - if (timeout[0].time > 0) return; - struct { - void (*cb)(void *); - void *arg; - } temp[MAXTIMEOUT]; - int i,j,k; - // copy all expired timeouts to temp array: - for (i=j=0; j<numtimeouts && timeout[j].time <= 0; i++,j++) { - temp[i].cb = timeout[j].cb; - temp[i].arg= timeout[j].arg; - } - // remove them from source array: - for (k=0; j<numtimeouts;) timeout[k++] = timeout[j++]; - numtimeouts = k; - // and then call them: - for (k=0; k<i; k++) temp[k].cb(temp[k].arg); -} - -void Fl::flush() { - if (damage()) { - damage_ = 0; - for (Fl_X* x = Fl_X::first; x; x = x->next) { - if (x->w->damage() && x->w->visible()) { - x->flush(); - x->w->clear_damage(); - } - } - } -#ifndef WIN32 - if (fl_display) XFlush(fl_display); -#endif -} - -extern double fl_wait(int timeout_flag, double timeout); -extern int fl_ready(); - -static int initclock; // if false we didn't call fl_elapsed() last time - -#ifndef WIN32 -#include <sys/time.h> -#endif - -// fl_elapsed must return the amount of time since the last time it was -// called. To reduce the number of system calls the to get the -// current time, the "initclock" symbol is turned on by an indefinate -// wait. This should then reset the measured-from time and return zero -static double fl_elapsed() { - -#ifdef WIN32 - - unsigned long newclock = fl_msg.time; // NOT YET IMPLEMENTED! - const int TICKS_PER_SECOND = 1000; // divisor of the value to get seconds - static unsigned long prevclock; - if (!initclock) {prevclock = newclock; initclock = 1; return 0.0;} - double t = double(newclock-prevclock)/TICKS_PER_SECOND; - prevclock = newclock; - -#else - - static struct timeval prevclock; - struct timeval newclock; - gettimeofday(&newclock, 0); - if (!initclock) { - prevclock.tv_sec = newclock.tv_sec; - prevclock.tv_usec = newclock.tv_usec; - initclock = 1; - return 0.0; - } - double t = newclock.tv_sec - prevclock.tv_sec + - (newclock.tv_usec - prevclock.tv_usec)/1000000.0; - prevclock.tv_sec = newclock.tv_sec; - prevclock.tv_usec = newclock.tv_usec; - -#endif - - // expire any timeouts: - if (t > 0.0) for (int i=0; i<numtimeouts; i++) timeout[i].time -= t; - return t; -} - -void (*Fl::idle)(); -static char in_idle; -static void callidle() { - if (!Fl::idle || in_idle) return; - in_idle = 1; - Fl::idle(); - in_idle = 0; -} - -int Fl::wait() { - callidle(); - if (numtimeouts) {fl_elapsed(); call_timeouts();} - flush(); - if (!Fl_X::first) return 0; // no windows - if (idle && !in_idle) - fl_wait(1,0.0); - else if (numtimeouts) - fl_wait(1, timeout[0].time); - else { - initclock = 0; - fl_wait(0,0); - } - return 1; -} - -double Fl::wait(double time) { - callidle(); - if (numtimeouts) {time -= fl_elapsed(); call_timeouts();} - flush(); - double wait_time = idle && !in_idle ? 0.0 : time; - if (numtimeouts && timeout[0].time < wait_time) wait_time = timeout[0].time; - fl_wait(1, wait_time); - return time - fl_elapsed(); -} - -int Fl::check() { - callidle(); - if (numtimeouts) {fl_elapsed(); call_timeouts();} - flush(); - if (!Fl_X::first) return 0; // no windows - fl_wait(1, 0.0); - return 1; -} - -int Fl::ready() { - // if (idle && !in_idle) return 1; // should it do this? - if (numtimeouts) {fl_elapsed(); if (timeout[0].time <= 0) return 1;} - return fl_ready(); -} - -int Fl::run() { - while (wait()); - return 0; -} - -//////////////////////////////////////////////////////////////// -// Window list management: - -Fl_X* Fl_X::first; - -Fl_Window* fl_find(Window xid) { - Fl_X *window; - for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next) - if (window->xid == xid) { - if (window != Fl_X::first && !Fl::modal()) { - // make this window be first to speed up searches - // this is not done if modal is true to avoid messing up modal stack - *pp = window->next; - window->next = Fl_X::first; - Fl_X::first = window; - } - return window->w; - } - return 0; -} - -void Fl::redraw() { - for (Fl_X* x = Fl_X::first; x; x = x->next) x->w->redraw(); -} - -Fl_Window* Fl::first_window() {Fl_X* x = Fl_X::first; return x ? x->w : 0;} - -Fl_Window* Fl::next_window(const Fl_Window* w) { - Fl_X* x = Fl_X::i(w)->next; return x ? x->w : 0;} - -//////////////////////////////////////////////////////////////// -// Event handlers: - -struct handler_link { - int (*handle)(int); - const handler_link *next; -}; - -static const handler_link *handlers = 0; - -void Fl::add_handler(int (*h)(int)) { - handler_link *l = new handler_link; - l->handle = h; - l->next = handlers; - handlers = l; -} - -static int send_handlers(int event) { - for (const handler_link *h = handlers; h; h = h->next) - if (h->handle(event)) return 1; - return 0; -} - -//////////////////////////////////////////////////////////////// - -Fl_Widget* fl_oldfocus; // kludge for Fl_Group... - -void Fl::focus(Fl_Widget *o) { - Fl_Widget *p = focus_; - if (o != p) { - focus_ = o; - fl_oldfocus = 0; - for (; p && !p->contains(o); p = p->parent()) { - p->handle(FL_UNFOCUS); - fl_oldfocus = p; - } - } -} - -void Fl::belowmouse(Fl_Widget *o) { - Fl_Widget *p = belowmouse_; - if (o != p) { - event_is_click(0); - belowmouse_ = o; - for (; p && !p->contains(o); p = p->parent()) p->handle(FL_LEAVE); - } -} - -// Because mouse events are posted to the outermost window we need to -// adjust them for child windows if they are pushed(). This should also -// be done for the focus() but that is nyi. -static int mouse_dx; -static int mouse_dy; - -void Fl::pushed(Fl_Widget *o) { - pushed_ = o; - mouse_dx = 0; - mouse_dy = 0; - if (o) for (Fl_Widget* w = o; w->parent(); w = w->parent()) { - if (w->type()>=FL_WINDOW) {mouse_dx -= w->x(); mouse_dy -= w->y();} - } -} - -Fl_Window *fl_xfocus; // which window X thinks has focus -Fl_Window *fl_xmousewin; // which window X thinks has FL_ENTER -Fl_Window *Fl::grab_; // most recent Fl::grab() -Fl_Window *Fl::modal_; - -// Update modal(), focus() and other state according to system state. -// This is called whenever a window is added or hidden, and whenever -// X says the focus or mouse window have changed, and when grab_ is -// changed. -void fl_fix_focus() { - - // set Fl::modal() based on grab or any modal windows displayed: - if (Fl::grab_) - Fl::modal_ = Fl::grab_; - else { - Fl_Window* w = Fl::first_window(); - while (w && w->parent()) w = Fl::next_window(w); - Fl::modal_ = w && w->modal() ? w : 0; - } - - // set focus based on Fl::modal() and fl_xfocus - Fl_Window *w = fl_xfocus; - while (w && w->parent()) w = w->window(); - if (w) { - if (Fl::modal()) w = Fl::modal(); - if (!w->contains(Fl::focus())) - if (!w->take_focus()) Fl::focus(w); - } else - Fl::focus(0); - - if (Fl::pushed()) { - - // move pushed() to modal window (necessary for menus): - if (Fl::modal() && !Fl::modal()->contains(Fl::pushed())) - Fl::pushed_ = Fl::modal(); - - } else { // set belowmouse only when pushed() is false - - // set belowmouse based on Fl::modal() and fl_xmousewin: - w = fl_xmousewin; - if (w) { - if (Fl::modal()) w = Fl::modal(); - if (!w->contains(Fl::belowmouse())) { - Fl::belowmouse(w); w->handle(FL_ENTER);} - } else - Fl::belowmouse(0); - } -} - -//////////////////////////////////////////////////////////////// - -int Fl::handle(int event, Fl_Window* window) -{ - Fl_Widget* w = window; - - switch (event) { - - case FL_CLOSE: - if (modal() && window != modal()) return 0; - w->do_callback(); - return 1; - - case FL_SHOW: - ((Fl_Widget*)w)->show(); - return 1; - - case FL_HIDE: - ((Fl_Widget*)w)->hide(); - return 1; - - case FL_PUSH: - if (Fl::grab()) w = Fl::grab(); - else if (Fl::modal() && w != Fl::modal()) return 0; - Fl::pushed_ = w; mouse_dx = mouse_dy = 0; - if (w->handle(event)) return 1; - // raise windows that are clicked on: - window->show(); - return 1; - - case FL_MOVE: - case FL_DRAG: - if (window != fl_xmousewin) { - // this should not happen if enter/leave events were reported - // correctly by the system, but just in case... - fl_xmousewin = window; fl_fix_focus(); - } - if (Fl::pushed()) { - Fl::e_x += mouse_dx; - Fl::e_y += mouse_dy; - event = FL_DRAG; - w = Fl::pushed(); - } else if (Fl::grab()) - w = Fl::grab(); - else if (Fl::modal() && w != Fl::modal()) - w = 0; - break; - - case FL_RELEASE: { - if (Fl::pushed_) w = Fl::pushed_; Fl::pushed_ = 0; - int r = w->handle(event); - fl_fix_focus(); - if (fl_xmousewin) fl_xmousewin->handle(FL_MOVE); - return r;} - - case FL_UNFOCUS: - window = 0; - case FL_FOCUS: - fl_xfocus = window; - Fl::e_keysym = 0; // make sure it is not confused with navigation key - fl_fix_focus(); - return 1; - - case FL_KEYBOARD: - if (window != fl_xfocus) { - // this should not happen if enter/leave events were reported - // correctly by the system, but just in case... - fl_xfocus = window; fl_fix_focus(); - } - // Try it as keystroke, sending it to focus and all parents: - for (w = Fl::focus(); w; w = w->parent()) - if (w->handle(FL_KEYBOARD)) return 1; - - // Try it as shortcut, sending to mouse widget and all parents: - w = Fl::belowmouse(); if (!w) {w = Fl::modal(); if (!w) w = window;} - for (; w; w = w->parent()) if (w->handle(FL_SHORTCUT)) return 1; - - // try using add_handle() functions: - if (send_handlers(FL_SHORTCUT)) return 1; - - // Try swapping the case of the text in the shortcut: - if (isalpha(Fl::event_text()[0])) { - *(char*)(Fl::event_text()) ^= ('A'^'a'); - w = Fl::belowmouse(); if (!w) {w = Fl::modal(); if (!w) w = window;} - for (; w; w = w->parent()) if (w->handle(FL_SHORTCUT)) return 1; - if (send_handlers(FL_SHORTCUT)) return 1; - } - - // make Escape key close windows: - if (Fl::event_key()==FL_Escape) { - window->do_callback(); - return 1; - } - - return 0; - - case FL_ENTER: - fl_xmousewin = window; fl_fix_focus(); - return 1; - - case FL_LEAVE: - if (window == fl_xmousewin) {fl_xmousewin = 0; fl_fix_focus();} - return 1; - - default: - break; - } - if (w && w->handle(event)) return 1; - return send_handlers(event); -} - -//////////////////////////////////////////////////////////////// -// hide() destroys the X window, it does not do unmap! - -void fl_throw_focus(Fl_Widget*); // in Fl_x.C - -void Fl_Window::hide() { - if (!shown()) return; - - // remove from the list of windows: - Fl_X* x = i; - Fl_X** pp = &Fl_X::first; - for (; *pp != x; pp = &(*pp)->next) if (!*pp) return; - *pp = x->next; - i = 0; - - // recursively remove any subwindows: - for (Fl_X *w = Fl_X::first; w;) { - Fl_Window* W = w->w; - if (W->window() == this) { - W->hide(); - W->set_visible(); - w = Fl_X::first; - } else w = w->next; - } - - // Make sure no events are sent to this window: - if (this == fl_xmousewin) fl_xmousewin = 0; - if (this == fl_xfocus) fl_xfocus = 0; - fl_throw_focus(this); - handle(FL_HIDE); - -#ifdef WIN32 - if (x->private_dc) ReleaseDC(x->xid,x->private_dc); - if (x->xid == fl_window) fl_GetDC(0); // releases dc belonging to window -#else - if (x->region) XDestroyRegion(x->region); -#endif - XDestroyWindow(fl_display, x->xid); - - delete x; -} - -Fl_Window::~Fl_Window() { - hide(); -} - -// Child windows must respond to FL_SHOW and FL_HIDE by actually -// doing unmap operations. Outer windows assumme FL_SHOW & FL_HIDE -// are messages from X: - -int Fl_Window::handle(int event) { - if (parent()) switch (event) { - case FL_SHOW: - if (!shown()) show(); - else XMapWindow(fl_display, fl_xid(this)); - break; - case FL_HIDE: - if (shown()) XUnmapWindow(fl_display, fl_xid(this)); - break; - } - return Fl_Group::handle(event); -} - -//////////////////////////////////////////////////////////////// -// ~Fl_Widget() calls this: this function must get rid of any -// global pointers to the widget. This is also called by hide() -// and deactivate(). - -// call this to free a selection (or change the owner): -void Fl::selection_owner(Fl_Widget *owner) { - if (selection_owner_ && owner != selection_owner_) - selection_owner_->handle(FL_SELECTIONCLEAR); - selection_owner_ = owner; -} - -#ifndef WIN32 -Fl_Widget *fl_selection_requestor; // from Fl_cutpaste.C -#endif - -void fl_throw_focus(Fl_Widget *o) { - if (o->contains(Fl::pushed())) Fl::pushed(0); - if (o->contains(Fl::selection_owner())) Fl::selection_owner(0); -#ifndef WIN32 - if (o->contains(fl_selection_requestor)) fl_selection_requestor = 0; -#endif - int fix = 0; - if (o->contains(Fl::belowmouse())) {Fl::belowmouse(0); fix = 1;} - if (o->contains(Fl::focus())) {Fl::focus(0); fix = 1;} - if (fix) fl_fix_focus(); -} - -// End of Fl.C // +// Fl.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
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/x.H>
+#include <ctype.h>
+
+int Fl::damage_;
+Fl_Widget *Fl::belowmouse_;
+Fl_Widget *Fl::pushed_;
+Fl_Widget *Fl::focus_;
+Fl_Widget *Fl::selection_owner_;
+int Fl::e_x, Fl::e_y, Fl::e_x_root, Fl::e_y_root;
+int Fl::e_state;
+int Fl::e_clicks;
+int Fl::e_is_click;
+int Fl::e_keysym;
+char *Fl::e_text;
+int Fl::e_length;
+
+int Fl::event_inside(int x,int y,int w,int h) /*const*/ {
+ int mx = event_x();
+ int my = event_y();
+ return (mx >= x && mx < x+w && my >= y && my < y+h);
+}
+
+int Fl::event_inside(const Fl_Widget *o) /*const*/ {
+ return event_inside(o->x(),o->y(),o->w(),o->h());
+}
+
+// Timeouts are insert-sorted into order. This works good if there
+// are only a small number:
+
+#define MAXTIMEOUT 8
+
+static struct {
+ double time;
+ void (*cb)(void*);
+ void* arg;
+} timeout[MAXTIMEOUT+1];
+static int numtimeouts;
+
+void Fl::add_timeout(double t, void (*cb)(void *), void *v) {
+ int i;
+ if (numtimeouts<MAXTIMEOUT) numtimeouts++;
+ for (i=0; i<numtimeouts-1; i++) {
+ if (timeout[i].time > t) {
+ for (int j=numtimeouts-1; j>i; j--) timeout[j] = timeout[j-1];
+ break;
+ }
+ }
+ timeout[i].time = t;
+ timeout[i].cb = cb;
+ timeout[i].arg = v;
+}
+
+void Fl::remove_timeout(void (*cb)(void *), void *v) {
+ int i,j;
+ for (i=j=0; i<numtimeouts; i++) {
+ if (timeout[i].cb == cb && timeout[i].arg==v) ;
+ else {if (j<i) timeout[j]=timeout[i]; j++;}
+ }
+ numtimeouts = j;
+}
+
+static void call_timeouts() {
+ if (timeout[0].time > 0) return;
+ struct {
+ void (*cb)(void *);
+ void *arg;
+ } temp[MAXTIMEOUT];
+ int i,j,k;
+ // copy all expired timeouts to temp array:
+ for (i=j=0; j<numtimeouts && timeout[j].time <= 0; i++,j++) {
+ temp[i].cb = timeout[j].cb;
+ temp[i].arg= timeout[j].arg;
+ }
+ // remove them from source array:
+ for (k=0; j<numtimeouts;) timeout[k++] = timeout[j++];
+ numtimeouts = k;
+ // and then call them:
+ for (k=0; k<i; k++) temp[k].cb(temp[k].arg);
+}
+
+void Fl::flush() {
+ if (damage()) {
+ damage_ = 0;
+ for (Fl_X* x = Fl_X::first; x; x = x->next) {
+ if (x->w->damage() && x->w->visible()) {
+ x->flush();
+ x->w->clear_damage();
+ }
+ }
+ }
+#ifndef WIN32
+ if (fl_display) XFlush(fl_display);
+#endif
+}
+
+extern double fl_wait(int timeout_flag, double timeout);
+extern int fl_ready();
+
+static int initclock; // if false we didn't call fl_elapsed() last time
+
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+
+// fl_elapsed must return the amount of time since the last time it was
+// called. To reduce the number of system calls the to get the
+// current time, the "initclock" symbol is turned on by an indefinate
+// wait. This should then reset the measured-from time and return zero
+static double fl_elapsed() {
+
+#ifdef WIN32
+
+ unsigned long newclock = fl_msg.time; // NOT YET IMPLEMENTED!
+ const int TICKS_PER_SECOND = 1000; // divisor of the value to get seconds
+ static unsigned long prevclock;
+ if (!initclock) {prevclock = newclock; initclock = 1; return 0.0;}
+ double t = double(newclock-prevclock)/TICKS_PER_SECOND;
+ prevclock = newclock;
+
+#else
+
+ static struct timeval prevclock;
+ struct timeval newclock;
+ gettimeofday(&newclock, 0);
+ if (!initclock) {
+ prevclock.tv_sec = newclock.tv_sec;
+ prevclock.tv_usec = newclock.tv_usec;
+ initclock = 1;
+ return 0.0;
+ }
+ double t = newclock.tv_sec - prevclock.tv_sec +
+ (newclock.tv_usec - prevclock.tv_usec)/1000000.0;
+ prevclock.tv_sec = newclock.tv_sec;
+ prevclock.tv_usec = newclock.tv_usec;
+
+#endif
+
+ // expire any timeouts:
+ if (t > 0.0) for (int i=0; i<numtimeouts; i++) timeout[i].time -= t;
+ return t;
+}
+
+void (*Fl::idle)();
+static char in_idle;
+static void callidle() {
+ if (!Fl::idle || in_idle) return;
+ in_idle = 1;
+ Fl::idle();
+ in_idle = 0;
+}
+
+int Fl::wait() {
+ callidle();
+ if (numtimeouts) {fl_elapsed(); call_timeouts();}
+ flush();
+ if (!Fl_X::first) return 0; // no windows
+ if (idle && !in_idle)
+ fl_wait(1,0.0);
+ else if (numtimeouts)
+ fl_wait(1, timeout[0].time);
+ else {
+ initclock = 0;
+ fl_wait(0,0);
+ }
+ return 1;
+}
+
+double Fl::wait(double time) {
+ callidle();
+ if (numtimeouts) {time -= fl_elapsed(); call_timeouts();}
+ flush();
+ double wait_time = idle && !in_idle ? 0.0 : time;
+ if (numtimeouts && timeout[0].time < wait_time) wait_time = timeout[0].time;
+ fl_wait(1, wait_time);
+ return time - fl_elapsed();
+}
+
+int Fl::check() {
+ callidle();
+ if (numtimeouts) {fl_elapsed(); call_timeouts();}
+ flush();
+ if (!Fl_X::first) return 0; // no windows
+ fl_wait(1, 0.0);
+ return 1;
+}
+
+int Fl::ready() {
+ // if (idle && !in_idle) return 1; // should it do this?
+ if (numtimeouts) {fl_elapsed(); if (timeout[0].time <= 0) return 1;}
+ return fl_ready();
+}
+
+int Fl::run() {
+ while (wait());
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////
+// Window list management:
+
+Fl_X* Fl_X::first;
+
+Fl_Window* fl_find(Window xid) {
+ Fl_X *window;
+ for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next)
+ if (window->xid == xid) {
+ if (window != Fl_X::first && !Fl::modal()) {
+ // make this window be first to speed up searches
+ // this is not done if modal is true to avoid messing up modal stack
+ *pp = window->next;
+ window->next = Fl_X::first;
+ Fl_X::first = window;
+ }
+ return window->w;
+ }
+ return 0;
+}
+
+void Fl::redraw() {
+ for (Fl_X* x = Fl_X::first; x; x = x->next) x->w->redraw();
+}
+
+Fl_Window* Fl::first_window() {Fl_X* x = Fl_X::first; return x ? x->w : 0;}
+
+Fl_Window* Fl::next_window(const Fl_Window* w) {
+ Fl_X* x = Fl_X::i(w)->next; return x ? x->w : 0;}
+
+////////////////////////////////////////////////////////////////
+// Event handlers:
+
+struct handler_link {
+ int (*handle)(int);
+ const handler_link *next;
+};
+
+static const handler_link *handlers = 0;
+
+void Fl::add_handler(int (*h)(int)) {
+ handler_link *l = new handler_link;
+ l->handle = h;
+ l->next = handlers;
+ handlers = l;
+}
+
+static int send_handlers(int event) {
+ for (const handler_link *h = handlers; h; h = h->next)
+ if (h->handle(event)) return 1;
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////
+
+Fl_Widget* fl_oldfocus; // kludge for Fl_Group...
+
+void Fl::focus(Fl_Widget *o) {
+ Fl_Widget *p = focus_;
+ if (o != p) {
+ focus_ = o;
+ fl_oldfocus = 0;
+ for (; p && !p->contains(o); p = p->parent()) {
+ p->handle(FL_UNFOCUS);
+ fl_oldfocus = p;
+ }
+ }
+}
+
+void Fl::belowmouse(Fl_Widget *o) {
+ Fl_Widget *p = belowmouse_;
+ if (o != p) {
+ event_is_click(0);
+ belowmouse_ = o;
+ for (; p && !p->contains(o); p = p->parent()) p->handle(FL_LEAVE);
+ }
+}
+
+// Because mouse events are posted to the outermost window we need to
+// adjust them for child windows if they are pushed(). This should also
+// be done for the focus() but that is nyi.
+static int mouse_dx;
+static int mouse_dy;
+
+void Fl::pushed(Fl_Widget *o) {
+ pushed_ = o;
+ mouse_dx = 0;
+ mouse_dy = 0;
+ if (o) for (Fl_Widget* w = o; w->parent(); w = w->parent()) {
+ if (w->type()>=FL_WINDOW) {mouse_dx -= w->x(); mouse_dy -= w->y();}
+ }
+}
+
+Fl_Window *fl_xfocus; // which window X thinks has focus
+Fl_Window *fl_xmousewin; // which window X thinks has FL_ENTER
+Fl_Window *Fl::grab_; // most recent Fl::grab()
+Fl_Window *Fl::modal_;
+
+// Update modal(), focus() and other state according to system state.
+// This is called whenever a window is added or hidden, and whenever
+// X says the focus or mouse window have changed, and when grab_ is
+// changed.
+void fl_fix_focus() {
+
+ // set Fl::modal() based on grab or any modal windows displayed:
+ if (Fl::grab_)
+ Fl::modal_ = Fl::grab_;
+ else {
+ Fl_Window* w = Fl::first_window();
+ while (w && w->parent()) w = Fl::next_window(w);
+ Fl::modal_ = w && w->modal() ? w : 0;
+ }
+
+ // set focus based on Fl::modal() and fl_xfocus
+ Fl_Window *w = fl_xfocus;
+ while (w && w->parent()) w = w->window();
+ if (w) {
+ if (Fl::modal()) w = Fl::modal();
+ if (!w->contains(Fl::focus()))
+ if (!w->take_focus()) Fl::focus(w);
+ } else
+ Fl::focus(0);
+
+ if (Fl::pushed()) {
+
+ // move pushed() to modal window (necessary for menus):
+ if (Fl::modal() && !Fl::modal()->contains(Fl::pushed()))
+ Fl::pushed_ = Fl::modal();
+
+ } else { // set belowmouse only when pushed() is false
+
+ // set belowmouse based on Fl::modal() and fl_xmousewin:
+ w = fl_xmousewin;
+ if (w) {
+ if (Fl::modal()) w = Fl::modal();
+ if (!w->contains(Fl::belowmouse())) {
+ Fl::belowmouse(w); w->handle(FL_ENTER);}
+ } else
+ Fl::belowmouse(0);
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+int Fl::handle(int event, Fl_Window* window)
+{
+ Fl_Widget* w = window;
+
+ switch (event) {
+
+ case FL_CLOSE:
+ if (modal() && window != modal()) return 0;
+ w->do_callback();
+ return 1;
+
+ case FL_SHOW:
+ ((Fl_Widget*)w)->show();
+ return 1;
+
+ case FL_HIDE:
+ ((Fl_Widget*)w)->hide();
+ return 1;
+
+ case FL_PUSH:
+ if (Fl::grab()) w = Fl::grab();
+ else if (Fl::modal() && w != Fl::modal()) return 0;
+ Fl::pushed_ = w; mouse_dx = mouse_dy = 0;
+ if (w->handle(event)) return 1;
+ // raise windows that are clicked on:
+ window->show();
+ return 1;
+
+ case FL_MOVE:
+ case FL_DRAG:
+ if (window != fl_xmousewin) {
+ // this should not happen if enter/leave events were reported
+ // correctly by the system, but just in case...
+ fl_xmousewin = window; fl_fix_focus();
+ }
+ if (Fl::pushed()) {
+ Fl::e_x += mouse_dx;
+ Fl::e_y += mouse_dy;
+ event = FL_DRAG;
+ w = Fl::pushed();
+ } else if (Fl::grab())
+ w = Fl::grab();
+ else if (Fl::modal() && w != Fl::modal())
+ w = 0;
+ break;
+
+ case FL_RELEASE: {
+ if (Fl::pushed_) w = Fl::pushed_; Fl::pushed_ = 0;
+ int r = w->handle(event);
+ fl_fix_focus();
+ if (fl_xmousewin) fl_xmousewin->handle(FL_MOVE);
+ return r;}
+
+ case FL_UNFOCUS:
+ window = 0;
+ case FL_FOCUS:
+ fl_xfocus = window;
+ Fl::e_keysym = 0; // make sure it is not confused with navigation key
+ fl_fix_focus();
+ return 1;
+
+ case FL_KEYBOARD:
+ if (window != fl_xfocus) {
+ // this should not happen if enter/leave events were reported
+ // correctly by the system, but just in case...
+ fl_xfocus = window; fl_fix_focus();
+ }
+ // Try it as keystroke, sending it to focus and all parents:
+ for (w = Fl::focus(); w; w = w->parent())
+ if (w->handle(FL_KEYBOARD)) return 1;
+
+ // Try it as shortcut, sending to mouse widget and all parents:
+ w = Fl::belowmouse(); if (!w) {w = Fl::modal(); if (!w) w = window;}
+ for (; w; w = w->parent()) if (w->handle(FL_SHORTCUT)) return 1;
+
+ // try using add_handle() functions:
+ if (send_handlers(FL_SHORTCUT)) return 1;
+
+ // Try swapping the case of the text in the shortcut:
+ if (isalpha(Fl::event_text()[0])) {
+ *(char*)(Fl::event_text()) ^= ('A'^'a');
+ w = Fl::belowmouse(); if (!w) {w = Fl::modal(); if (!w) w = window;}
+ for (; w; w = w->parent()) if (w->handle(FL_SHORTCUT)) return 1;
+ if (send_handlers(FL_SHORTCUT)) return 1;
+ }
+
+ // make Escape key close windows:
+ if (Fl::event_key()==FL_Escape) {
+ window->do_callback();
+ return 1;
+ }
+
+ return 0;
+
+ case FL_ENTER:
+ fl_xmousewin = window; fl_fix_focus();
+ return 1;
+
+ case FL_LEAVE:
+ if (window == fl_xmousewin) {fl_xmousewin = 0; fl_fix_focus();}
+ return 1;
+
+ default:
+ break;
+ }
+ if (w && w->handle(event)) return 1;
+ return send_handlers(event);
+}
+
+////////////////////////////////////////////////////////////////
+// hide() destroys the X window, it does not do unmap!
+
+void fl_throw_focus(Fl_Widget*); // in Fl_x.C
+
+void Fl_Window::hide() {
+ if (!shown()) return;
+
+ // remove from the list of windows:
+ Fl_X* x = i;
+ Fl_X** pp = &Fl_X::first;
+ for (; *pp != x; pp = &(*pp)->next) if (!*pp) return;
+ *pp = x->next;
+ i = 0;
+
+ // recursively remove any subwindows:
+ for (Fl_X *w = Fl_X::first; w;) {
+ Fl_Window* W = w->w;
+ if (W->window() == this) {
+ W->hide();
+ W->set_visible();
+ w = Fl_X::first;
+ } else w = w->next;
+ }
+
+ // Make sure no events are sent to this window:
+ if (this == fl_xmousewin) fl_xmousewin = 0;
+ if (this == fl_xfocus) fl_xfocus = 0;
+ fl_throw_focus(this);
+ handle(FL_HIDE);
+
+#ifdef WIN32
+ if (x->private_dc) ReleaseDC(x->xid,x->private_dc);
+ if (x->xid == fl_window) fl_GetDC(0); // releases dc belonging to window
+#endif
+ if (x->region) XDestroyRegion(x->region);
+ XDestroyWindow(fl_display, x->xid);
+
+ delete x;
+}
+
+Fl_Window::~Fl_Window() {
+ hide();
+}
+
+// Child windows must respond to FL_SHOW and FL_HIDE by actually
+// doing unmap operations. Outer windows assumme FL_SHOW & FL_HIDE
+// are messages from X:
+
+int Fl_Window::handle(int event) {
+ if (parent()) switch (event) {
+ case FL_SHOW:
+ if (!shown()) show();
+ else XMapWindow(fl_display, fl_xid(this));
+ break;
+ case FL_HIDE:
+ if (shown()) XUnmapWindow(fl_display, fl_xid(this));
+ break;
+ }
+ return Fl_Group::handle(event);
+}
+
+////////////////////////////////////////////////////////////////
+// ~Fl_Widget() calls this: this function must get rid of any
+// global pointers to the widget. This is also called by hide()
+// and deactivate().
+
+// call this to free a selection (or change the owner):
+void Fl::selection_owner(Fl_Widget *owner) {
+ if (selection_owner_ && owner != selection_owner_)
+ selection_owner_->handle(FL_SELECTIONCLEAR);
+ selection_owner_ = owner;
+}
+
+#ifndef WIN32
+Fl_Widget *fl_selection_requestor; // from Fl_cutpaste.C
+#endif
+
+void fl_throw_focus(Fl_Widget *o) {
+ if (o->contains(Fl::pushed())) Fl::pushed(0);
+ if (o->contains(Fl::selection_owner())) Fl::selection_owner(0);
+#ifndef WIN32
+ if (o->contains(fl_selection_requestor)) fl_selection_requestor = 0;
+#endif
+ int fix = 0;
+ if (o->contains(Fl::belowmouse())) {Fl::belowmouse(0); fix = 1;}
+ if (o->contains(Fl::focus())) {Fl::focus(0); fix = 1;}
+ if (fix) fl_fix_focus();
+}
+
+// End of Fl.C //
diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx index aa285a5d2..864ba1019 100644 --- a/src/Fl_Double_Window.cxx +++ b/src/Fl_Double_Window.cxx @@ -1,157 +1,163 @@ -// Fl_Double_Window.C - -// A double-buffered window. This is achieved by using the Xdbe extension, -// or a pixmap if that is not available. - -// On systems that support double buffering "naturally" the base -// Fl_Window class will probably do double-buffer and this subclass -// does nothing. - -#include <config.h> -#include <FL/Fl.H> -#include <FL/Fl_Double_Window.H> -#include <FL/x.H> -#include <FL/fl_draw.H> - -#if USE_XDBE - -#include <X11/extensions/Xdbe.h> - -static int use_xdbe; - -static int can_xdbe() { - static int tried; - if (!tried) { - tried = 1; - int event_base, error_base; - if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; - Drawable root = RootWindow(fl_display,fl_screen); - int numscreens = 1; - XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens); - if (!a) return 0; - for (int j = 0; j < a->count; j++) - if (a->visinfo[j].visual == fl_visual->visualid - /*&& a->visinfo[j].perflevel > 0*/) {use_xdbe = 1; break;} - XdbeFreeVisualInfo(a); - } - return use_xdbe; -} -#endif - -void Fl_Double_Window::show() { -#ifndef WIN32 - if (!shown()) { // don't set the background pixel - fl_open_display(); - Fl_X::make_xid(this); - return; - } -#endif - Fl_Window::show(); -} - -#ifdef WIN32 - -// Code to switch output to an off-screen window: -// this is lame, I allow two to exist... - -static HDC blt_gc[2]; - -void fl_switch_offscreen(HBITMAP bitmap) { - if (!blt_gc[0]) for (int i = 0; i < 2; i++) { - blt_gc[i] = CreateCompatibleDC(fl_gc); - SetTextAlign(blt_gc[i], TA_BASELINE|TA_LEFT); - SetBkMode(blt_gc[i], TRANSPARENT); -#if USE_COLORMAP - if (fl_palette) SelectPalette(blt_gc[i], fl_palette, FALSE); -#endif - } - int which = 0; if (fl_gc == blt_gc[0]) which = 1; - SelectObject(blt_gc[which], bitmap); - fl_gc = blt_gc[which]; -} - -void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { - int which = 0; if (fl_gc == blt_gc[0]) which = 1; - SelectObject(blt_gc[which], bitmap); - BitBlt(fl_gc, x, y, w, h, blt_gc[which], srcx, srcy, SRCCOPY); -} - -#endif - -// protected method used by Fl_Overlay_Window to fake overlay: -void Fl_Double_Window::_flush(int eraseoverlay) { - make_current(); // make sure fl_gc is non-zero - Fl_X *i = Fl_X::i(this); - if (!i->other_xid) { -#if USE_XDBE - if (can_xdbe()) i->other_xid = - XdbeAllocateBackBufferName(fl_display, fl_xid(this), XdbeCopied); - else -#endif - i->other_xid = fl_create_offscreen(w(), h()); - clear_damage(~0); - } - XRectangle rect = {0,0,w(),h()}; - if (damage()) { - if (i->region && !eraseoverlay) XClipBox(i->region, &rect); - if ( // don't draw if back buffer is ok -#if USE_XDBE - use_xdbe || -#endif - damage() != 2) { -#ifdef WIN32 - fl_begin_offscreen(i->other_xid); - fl_clip_region(i->region); i->region = 0; - draw(); - fl_end_offscreen(); -#else - fl_window = i->other_xid; - fl_clip_region(i->region); i->region = 0; - draw(); - fl_window = i->xid; -#endif - } - } - fl_clip_region(0); -#if USE_XDBE - if (use_xdbe) { - XdbeSwapInfo s; - s.swap_window = fl_xid(this); - s.swap_action = XdbeCopied; - XdbeSwapBuffers(fl_display,&s,1); - } else -#endif - fl_copy_offscreen(rect.x, rect.y, rect.width, rect.height, - i->other_xid, rect.x, rect.y); -} - -void Fl_Double_Window::flush() {_flush(0);} - -void Fl_Double_Window::resize(int X,int Y,int W,int H) { - int ow = w(); - int oh = h(); - Fl_Window::resize(X,Y,W,H); -#if USE_XDBE - if (use_xdbe) return; -#endif - Fl_X* i = Fl_X::i(this); - if (i && i->other_xid && (ow != w() || oh != h())) { - fl_delete_offscreen(i->other_xid); - i->other_xid = 0; - } -} - -void Fl_Double_Window::hide() { - Fl_X* i = Fl_X::i(this); - if (i && i->other_xid) { -#if USE_XDBE - if (!use_xdbe) -#endif - fl_delete_offscreen(i->other_xid); - } - Fl_Window::hide(); -} - -Fl_Double_Window::~Fl_Double_Window() { - hide(); -} +// Fl_Double_Window.C
+
+// A double-buffered window. This is achieved by using the Xdbe extension,
+// or a pixmap if that is not available.
+
+// On systems that support double buffering "naturally" the base
+// Fl_Window class will probably do double-buffer and this subclass
+// does nothing.
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/x.H>
+#include <FL/fl_draw.H>
+
+#if USE_XDBE
+
+#include <X11/extensions/Xdbe.h>
+
+static int use_xdbe;
+
+static int can_xdbe() {
+ static int tried;
+ if (!tried) {
+ tried = 1;
+ int event_base, error_base;
+ if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0;
+ Drawable root = RootWindow(fl_display,fl_screen);
+ int numscreens = 1;
+ XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens);
+ if (!a) return 0;
+ for (int j = 0; j < a->count; j++)
+ if (a->visinfo[j].visual == fl_visual->visualid
+ /*&& a->visinfo[j].perflevel > 0*/) {use_xdbe = 1; break;}
+ XdbeFreeVisualInfo(a);
+ }
+ return use_xdbe;
+}
+#endif
+
+void Fl_Double_Window::show() {
+#ifndef WIN32
+ if (!shown()) { // don't set the background pixel
+ fl_open_display();
+ Fl_X::make_xid(this);
+ return;
+ }
+#endif
+ Fl_Window::show();
+}
+
+#ifdef WIN32
+
+// I've removed the second one (never understool why
+// it was there to begin with).
+
+static HDC blt_gc;
+
+void fl_switch_offscreen(HBITMAP bitmap) {
+ if (!blt_gc) {
+ blt_gc = CreateCompatibleDC(fl_gc);
+ SetTextAlign(blt_gc, TA_BASELINE|TA_LEFT);
+ SetBkMode(blt_gc, TRANSPARENT);
+#if USE_COLORMAP
+ if (fl_palette) SelectPalette(blt_gc, fl_palette, FALSE);
+#endif
+ }
+ SelectObject(blt_gc, bitmap);
+ fl_gc = blt_gc;
+}
+
+void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) {
+ SelectObject(blt_gc, bitmap);
+ BitBlt(window_dc, x, y, w, h, blt_gc, srcx, srcy, SRCCOPY);
+}
+
+#endif
+
+// protected method used by Fl_Overlay_Window to fake overlay:
+void Fl_Double_Window::_flush(int eraseoverlay) {
+ make_current(); // make sure fl_gc is non-zero
+ Fl_X *i = Fl_X::i(this);
+ if (!i->other_xid) {
+#if USE_XDBE
+ if (can_xdbe()) i->other_xid =
+ XdbeAllocateBackBufferName(fl_display, fl_xid(this), XdbeCopied);
+ else
+#endif
+ i->other_xid = fl_create_offscreen(w(), h());
+ clear_damage(~0);
+ }
+ XRectangle rect = {0,0,w(),h()};
+ if (damage()) {
+ if ( // don't draw if back buffer is ok
+#if USE_XDBE
+ use_xdbe ||
+#endif
+ damage() != 2) {
+/*
+#ifdef WIN32
+ fl_begin_offscreen(i->other_xid);
+ fl_clip_region(i->region); i->region = 0;
+ draw();
+ fl_end_offscreen();
+#else
+*/
+#ifdef WIN32
+ fl_begin_offscreen(i->other_xid);
+#endif
+ fl_window = i->other_xid;
+ fl_clip_region(i->region); i->region = 0;
+ draw();
+ fl_window = i->xid;
+#ifdef WIN32
+ fl_end_offscreen();
+#endif
+//#endif
+ }
+ }
+ fl_clip_region(0);
+#if USE_XDBE
+ if (i->region && !eraseoverlay) XClipBox(i->region, &rect);
+ if (use_xdbe) {
+ XdbeSwapInfo s;
+ s.swap_window = fl_xid(this);
+ s.swap_action = XdbeCopied;
+ XdbeSwapBuffers(fl_display,&s,1);
+ } else
+#endif
+ fl_copy_offscreen(rect.x, rect.y, rect.width, rect.height,
+ i->other_xid, rect.x, rect.y);
+}
+
+void Fl_Double_Window::flush() {_flush(0);}
+
+void Fl_Double_Window::resize(int X,int Y,int W,int H) {
+ int ow = w();
+ int oh = h();
+ Fl_Window::resize(X,Y,W,H);
+#if USE_XDBE
+ if (use_xdbe) return;
+#endif
+ Fl_X* i = Fl_X::i(this);
+ if (i && i->other_xid && (ow != w() || oh != h())) {
+ fl_delete_offscreen(i->other_xid);
+ i->other_xid = 0;
+ }
+}
+
+void Fl_Double_Window::hide() {
+ Fl_X* i = Fl_X::i(this);
+ if (i && i->other_xid) {
+#if USE_XDBE
+ if (!use_xdbe)
+#endif
+ fl_delete_offscreen(i->other_xid);
+ }
+ Fl_Window::hide();
+}
+
+Fl_Double_Window::~Fl_Double_Window() {
+ hide();
+}
diff --git a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx index acd08e6f3..0879e734e 100644 --- a/src/Fl_Gl_Window.cxx +++ b/src/Fl_Gl_Window.cxx @@ -1,287 +1,293 @@ -// Fl_Gl_Window.C - -#include <config.h> -#if HAVE_GL - -#include <FL/Fl.H> -#include <FL/x.H> -#include <FL/Fl_Gl_Window.H> -#include "Fl_Gl_Choice.H" - -//////////////////////////////////////////////////////////////// - -// The symbol SWAP_TYPE defines what is in the back buffer after doing -// a glXSwapBuffers(). - -// The OpenGl documentation says that the contents of the backbuffer -// are "undefined" after glXSwapBuffers(). However, if we know what -// is in the backbuffers then we can save a good deal of time. For -// this reason you can define some symbols to describe what is left in -// the back buffer. - -// The default of SWAP_SWAP works on an SGI, and will also work (but -// is sub-optimal) on machines that should be SWAP_COPY or SWAP_NODAMAGE. -// The win32 emulation of OpenGL can use COPY, but some (all?) OpenGL -// cards use SWAP. - -// contents of back buffer after glXSwapBuffers(): -#define UNDEFINED 0 // unknown -#define SWAP 1 // former front buffer -#define COPY 2 // unchanged -#define NODAMAGE 3 // unchanged even by X expose() events - -#ifdef MESA -#define SWAP_TYPE NODAMAGE -#else -#define SWAP_TYPE SWAP -#endif - -//////////////////////////////////////////////////////////////// - -int Fl_Gl_Window::can_do(int a, const int *b) { -#ifdef WIN32 - Fl_Gl_Choice *g = Fl_Gl_Choice::find(a,b); - HWND w = GetDesktopWindow(); - HDC dc = GetDC(w); - int r = ChoosePixelFormat(dc, &g->pfd); - ReleaseDC(w,dc); - return r != 0; -#else - return Fl_Gl_Choice::find(a,b) != 0; -#endif -} - -void Fl_Gl_Window::show() { -#ifndef WIN32 - if (!shown()) { - if (!g) { - g = Fl_Gl_Choice::find(mode_,alist); - if (!g) {Fl::error("Insufficient GL support"); return;} - } - Fl_X::make_xid(this, g->vis, g->colormap); - if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show(); - } -#endif - Fl_Window::show(); -} - -void Fl_Gl_Window::invalidate() { - valid(0); -#ifndef WIN32 - if (overlay) ((Fl_Gl_Window*)overlay)->valid(0); -#endif -} - -extern GLXContext fl_first_context; // in Fl_Gl_Choice.C - -int Fl_Gl_Window::mode(int m, const int *a) { - if (m == mode_ && a == alist) return 0; - mode_ = m; alist = a; -#ifdef WIN32 - // destroy context and g: - if (shown()) {hide(); show();} -#else - // under X, if the visual changes we must make a new X window (!): - if (shown()) { - Fl_Gl_Choice *g1 = g; - g = Fl_Gl_Choice::find(mode_,alist); - if (!g || g->vis->visualid != g1->vis->visualid || g->d != g1->d) { - hide(); show(); - } - } -#endif - return 1; -} - -#ifdef WIN32 -extern char fl_direct_paint; // true when responding to WM_PAINT -#endif - -void Fl_Gl_Window::make_current() { -#ifdef WIN32 - HDC hdc = fl_private_dc(this, mode_,&g); - if (!context) { - context = wglCreateContext(hdc); - if (fl_first_context) wglShareLists(fl_first_context, (GLXContext)context); - else fl_first_context = (GLXContext)context; - valid(0); - } - wglMakeCurrent(hdc, (GLXContext)context); -#else - if (!context) { - context = glXCreateContext(fl_display, g->vis, fl_first_context, 1); - if (!fl_first_context) fl_first_context = (GLXContext)context; - valid(0); - } - glXMakeCurrent(fl_display, fl_xid(this), (GLXContext)context); -#endif - glDrawBuffer(GL_BACK); -} - -void Fl_Gl_Window::ortho() { - glLoadIdentity(); - glViewport(0, 0, w(), h()); - glOrtho(0, w(), 0, h(), -1, 1); -} - -void Fl_Gl_Window::swap_buffers() { -#ifdef WIN32 - SwapBuffers(Fl_X::i(this)->private_dc); -#else - glXSwapBuffers(fl_display, fl_xid(this)); -#endif -} - -#if HAVE_GL_OVERLAY -#if WIN32 -uchar fl_overlay; // changes how fl_color() works -#endif -#endif - -void Fl_Gl_Window::flush() { - make_current(); - -#if HAVE_GL_OVERLAY -#ifdef WIN32 - uchar save_valid = valid_; - if (overlay && overlay!= this && damage() == 8) goto DRAW_OVERLAY_ONLY; -#endif -#endif - - if (g->d) { - -#if SWAP_TYPE == NODAMAGE - - // don't draw if only overlay damage or expose events: - if ((damage()&~0xA0) || !valid()) draw(); - swap_buffers(); - -#elif SWAP_TYPE == COPY - - // don't draw if only the overlay is damaged: - if (damage() != 8 || !valid()) draw(); - swap_buffers(); - -#else // SWAP_TYPE == SWAP || SWAP_TYPE == UNDEFINED - - if (overlay == this) { // Use CopyPixels to act like SWAP_TYPE == COPY - - // don't draw if only the overlay is damaged: - if (damage1_ || damage() != 8 || !valid()) draw(); - // we use a seperate context for the copy because rasterpos must be 0 - // and depth test needs to be off: - static GLXContext ortho_context; - int init = !ortho_context; -#ifdef WIN32 - if (init) ortho_context = wglCreateContext(Fl_X::i(this)->private_dc); - wglMakeCurrent(Fl_X::i(this)->private_dc, ortho_context); -#else - if (init) - ortho_context = glXCreateContext(fl_display,g->vis,fl_first_context,1); - glXMakeCurrent(fl_display, fl_xid(this), ortho_context); -#endif - if (init) { - glDisable(GL_DEPTH_TEST); - glReadBuffer(GL_BACK); - glDrawBuffer(GL_FRONT); - } - glCopyPixels(0,0,w(),h(),GL_COLOR); - make_current(); // set current context back to draw overlay - damage1_ = 0; - - } else { - -#if SWAP_TYPE == SWAP - uchar old_damage = damage(); - clear_damage(damage1_|old_damage); draw(); - swap_buffers(); - damage1_ = old_damage; -#else // SWAP_TYPE == UNDEFINED - clear_damage(~0); draw(); - swap_buffers(); - damage1_ = ~0; -#endif - - } -#endif - - if (overlay==this) { // fake overlay in front buffer - glDrawBuffer(GL_FRONT); - draw_overlay(); - glDrawBuffer(GL_BACK); - glFlush(); - } - - } else { // single-buffered context is simpler: - - // this faking of the overlay is incorrect but worked good for - // one in-house program: - if (overlay != this || damage()!=8 || !Fl::pushed()) draw(); - if (overlay == this) draw_overlay(); - glFlush(); - - } - -#if HAVE_GL_OVERLAY -#ifdef WIN32 - if (overlay && overlay != this) { - DRAW_OVERLAY_ONLY: - valid_ = save_valid; - wglMakeCurrent(Fl_X::i(this)->private_dc, (GLXContext)overlay); - glDisable(GL_SCISSOR_TEST); - fl_overlay = 1; - glClear(GL_COLOR_BUFFER_BIT); - draw_overlay(); - wglSwapLayerBuffers(Fl_X::i(this)->private_dc,WGL_SWAP_OVERLAY1); - fl_overlay = 0; - } -#endif -#endif - - valid(1); -} - -void Fl_Gl_Window::resize(int X,int Y,int W,int H) { - if (W != w() || H != h()) valid(0); - Fl_Window::resize(X,Y,W,H); -} - -void Fl_Gl_Window::hide() { - if (context) { -#ifdef WIN32 - wglMakeCurrent(0, 0); - if (context && context != fl_first_context) - wglDeleteContext((GLXContext)context); - g = 0; -#else - glXMakeCurrent(fl_display, 0, 0); - if (context != fl_first_context) - glXDestroyContext(fl_display, (GLXContext)context); -#ifdef GLX_MESA_release_buffers - glXReleaseBuffersMESA(fl_display, fl_xid(this)); -#endif -#endif - context = 0; - } - Fl_Window::hide(); -} - -Fl_Gl_Window::~Fl_Gl_Window() { - hide(); -// delete overlay; this is done by ~Fl_Group -} - -void Fl_Gl_Window::init() { - end(); // we probably don't want any children - box(FL_NO_BOX); - mode_ = FL_RGB | FL_DEPTH | FL_DOUBLE; - alist = 0; - context = 0; - g = 0; - overlay = 0; - damage1_ = 0; -} - -void Fl_Gl_Window::draw_overlay() {} - -#endif +// Fl_Gl_Window.C
+
+#include <config.h>
+#if HAVE_GL
+
+#include <FL/Fl.H>
+#include <FL/x.H>
+#include <FL/Fl_Gl_Window.H>
+#include "Fl_Gl_Choice.H"
+
+////////////////////////////////////////////////////////////////
+
+// The symbol SWAP_TYPE defines what is in the back buffer after doing
+// a glXSwapBuffers().
+
+// The OpenGl documentation says that the contents of the backbuffer
+// are "undefined" after glXSwapBuffers(). However, if we know what
+// is in the backbuffers then we can save a good deal of time. For
+// this reason you can define some symbols to describe what is left in
+// the back buffer.
+
+// The default of SWAP_SWAP works on an SGI, and will also work (but
+// is sub-optimal) on machines that should be SWAP_COPY or SWAP_NODAMAGE.
+// The win32 emulation of OpenGL can use COPY, but some (all?) OpenGL
+// cards use SWAP.
+
+// contents of back buffer after glXSwapBuffers():
+#define UNDEFINED 0 // unknown
+#define SWAP 1 // former front buffer
+#define COPY 2 // unchanged
+#define NODAMAGE 3 // unchanged even by X expose() events
+
+#ifdef MESA
+#define SWAP_TYPE NODAMAGE
+#else
+#define SWAP_TYPE SWAP
+#endif
+
+////////////////////////////////////////////////////////////////
+
+HDC fl_GetDC(HWND);
+
+int Fl_Gl_Window::can_do(int a, const int *b) {
+#ifdef WIN32
+ Fl_Gl_Choice *g = Fl_Gl_Choice::find(a,b);
+/*
+ Is this necessary? Don't all windows have the same
+ support for pixel formats?
+ HWND w = GetDesktopWindow();
+ HDC dc = GetDC(w);
+*/
+ if (!fl_gc) fl_GetDC(0);
+ int r = ChoosePixelFormat(fl_gc, &g->pfd);
+ return r != 0;
+#else
+ return Fl_Gl_Choice::find(a,b) != 0;
+#endif
+}
+
+void Fl_Gl_Window::show() {
+#ifndef WIN32
+ if (!shown()) {
+ if (!g) {
+ g = Fl_Gl_Choice::find(mode_,alist);
+ if (!g) {Fl::error("Insufficient GL support"); return;}
+ }
+ Fl_X::make_xid(this, g->vis, g->colormap);
+ if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show();
+ }
+#endif
+ Fl_Window::show();
+}
+
+void Fl_Gl_Window::invalidate() {
+ valid(0);
+#ifndef WIN32
+ if (overlay) ((Fl_Gl_Window*)overlay)->valid(0);
+#endif
+}
+
+extern GLXContext fl_first_context; // in Fl_Gl_Choice.C
+
+int Fl_Gl_Window::mode(int m, const int *a) {
+ if (m == mode_ && a == alist) return 0;
+ mode_ = m; alist = a;
+#ifdef WIN32
+ // destroy context and g:
+ if (shown()) {hide(); show();}
+#else
+ // under X, if the visual changes we must make a new X window (!):
+ if (shown()) {
+ Fl_Gl_Choice *g1 = g;
+ g = Fl_Gl_Choice::find(mode_,alist);
+ if (!g || g->vis->visualid != g1->vis->visualid || g->d != g1->d) {
+ hide(); show();
+ }
+ }
+#endif
+ return 1;
+}
+
+#ifdef WIN32
+extern char fl_direct_paint; // true when responding to WM_PAINT
+#endif
+
+void Fl_Gl_Window::make_current() {
+#ifdef WIN32
+ HDC hdc = fl_private_dc(this, mode_,&g);
+ if (!context) {
+ context = wglCreateContext(hdc);
+ if (fl_first_context) wglShareLists(fl_first_context, (GLXContext)context);
+ else fl_first_context = (GLXContext)context;
+ valid(0);
+ }
+ wglMakeCurrent(hdc, (GLXContext)context);
+#else
+ if (!context) {
+ context = glXCreateContext(fl_display, g->vis, fl_first_context, 1);
+ if (!fl_first_context) fl_first_context = (GLXContext)context;
+ valid(0);
+ }
+ glXMakeCurrent(fl_display, fl_xid(this), (GLXContext)context);
+#endif
+ glDrawBuffer(GL_BACK);
+}
+
+void Fl_Gl_Window::ortho() {
+ glLoadIdentity();
+ glViewport(0, 0, w(), h());
+ glOrtho(0, w(), 0, h(), -1, 1);
+}
+
+void Fl_Gl_Window::swap_buffers() {
+#ifdef WIN32
+ SwapBuffers(Fl_X::i(this)->private_dc);
+#else
+ glXSwapBuffers(fl_display, fl_xid(this));
+#endif
+}
+
+#if HAVE_GL_OVERLAY
+#if WIN32
+uchar fl_overlay; // changes how fl_color() works
+#endif
+#endif
+
+void Fl_Gl_Window::flush() {
+ make_current();
+
+#if HAVE_GL_OVERLAY
+#ifdef WIN32
+ uchar save_valid = valid_;
+ if (overlay && overlay!= this && damage() == 8) goto DRAW_OVERLAY_ONLY;
+#endif
+#endif
+
+ if (g->d) {
+
+#if SWAP_TYPE == NODAMAGE
+
+ // don't draw if only overlay damage or expose events:
+ if ((damage()&~0xA0) || !valid()) draw();
+ swap_buffers();
+
+#elif SWAP_TYPE == COPY
+
+ // don't draw if only the overlay is damaged:
+ if (damage() != 8 || !valid()) draw();
+ swap_buffers();
+
+#else // SWAP_TYPE == SWAP || SWAP_TYPE == UNDEFINED
+
+ if (overlay == this) { // Use CopyPixels to act like SWAP_TYPE == COPY
+
+ // don't draw if only the overlay is damaged:
+ if (damage1_ || damage() != 8 || !valid()) draw();
+ // we use a seperate context for the copy because rasterpos must be 0
+ // and depth test needs to be off:
+ static GLXContext ortho_context;
+ int init = !ortho_context;
+#ifdef WIN32
+ if (init) ortho_context = wglCreateContext(Fl_X::i(this)->private_dc);
+ wglMakeCurrent(Fl_X::i(this)->private_dc, ortho_context);
+#else
+ if (init)
+ ortho_context = glXCreateContext(fl_display,g->vis,fl_first_context,1);
+ glXMakeCurrent(fl_display, fl_xid(this), ortho_context);
+#endif
+ if (init) {
+ glDisable(GL_DEPTH_TEST);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_FRONT);
+ }
+ glCopyPixels(0,0,w(),h(),GL_COLOR);
+ make_current(); // set current context back to draw overlay
+ damage1_ = 0;
+
+ } else {
+
+#if SWAP_TYPE == SWAP
+ uchar old_damage = damage();
+ clear_damage(damage1_|old_damage); draw();
+ swap_buffers();
+ damage1_ = old_damage;
+#else // SWAP_TYPE == UNDEFINED
+ clear_damage(~0); draw();
+ swap_buffers();
+ damage1_ = ~0;
+#endif
+
+ }
+#endif
+
+ if (overlay==this) { // fake overlay in front buffer
+ glDrawBuffer(GL_FRONT);
+ draw_overlay();
+ glDrawBuffer(GL_BACK);
+ glFlush();
+ }
+
+ } else { // single-buffered context is simpler:
+
+ // this faking of the overlay is incorrect but worked good for
+ // one in-house program:
+ if (overlay != this || damage()!=8 || !Fl::pushed()) draw();
+ if (overlay == this) draw_overlay();
+ glFlush();
+
+ }
+
+#if HAVE_GL_OVERLAY
+#ifdef WIN32
+ if (overlay && overlay != this) {
+ DRAW_OVERLAY_ONLY:
+ valid_ = save_valid;
+ wglMakeCurrent(Fl_X::i(this)->private_dc, (GLXContext)overlay);
+ glDisable(GL_SCISSOR_TEST);
+ fl_overlay = 1;
+ glClear(GL_COLOR_BUFFER_BIT);
+ draw_overlay();
+ wglSwapLayerBuffers(Fl_X::i(this)->private_dc,WGL_SWAP_OVERLAY1);
+ fl_overlay = 0;
+ }
+#endif
+#endif
+
+ valid(1);
+}
+
+void Fl_Gl_Window::resize(int X,int Y,int W,int H) {
+ if (W != w() || H != h()) valid(0);
+ Fl_Window::resize(X,Y,W,H);
+}
+
+void Fl_Gl_Window::hide() {
+ if (context) {
+#ifdef WIN32
+ wglMakeCurrent(0, 0);
+ if (context && context != fl_first_context)
+ wglDeleteContext((GLXContext)context);
+ g = 0;
+#else
+ glXMakeCurrent(fl_display, 0, 0);
+ if (context != fl_first_context)
+ glXDestroyContext(fl_display, (GLXContext)context);
+#ifdef GLX_MESA_release_buffers
+ glXReleaseBuffersMESA(fl_display, fl_xid(this));
+#endif
+#endif
+ context = 0;
+ }
+ Fl_Window::hide();
+}
+
+Fl_Gl_Window::~Fl_Gl_Window() {
+ hide();
+// delete overlay; this is done by ~Fl_Group
+}
+
+void Fl_Gl_Window::init() {
+ end(); // we probably don't want any children
+ box(FL_NO_BOX);
+ mode_ = FL_RGB | FL_DEPTH | FL_DOUBLE;
+ alist = 0;
+ context = 0;
+ g = 0;
+ overlay = 0;
+ damage1_ = 0;
+}
+
+void Fl_Gl_Window::draw_overlay() {}
+
+#endif
diff --git a/src/Fl_visual.cxx b/src/Fl_visual.cxx index d45c3ed49..05d90edd1 100644 --- a/src/Fl_visual.cxx +++ b/src/Fl_visual.cxx @@ -1,78 +1,79 @@ -// Fl_visual.C -// -// Set the default visual according to passed switches: - -#include <config.h> -#include <FL/Fl.H> -#include <FL/x.H> - -#ifdef WIN32 -int Fl::visual(int flags) { - if (flags & FL_DOUBLE) return 0; - if (!(flags & FL_INDEX) && - GetDeviceCaps(fl_GetDC(0),BITSPIXEL) <= 8) return 0; - if ((flags & FL_RGB8) && GetDeviceCaps(fl_GetDC(0),BITSPIXEL)<24) return 0; - return 1; -} -#else - -#if USE_XDBE -#include <X11/extensions/Xdbe.h> -#endif - -static int test_visual(XVisualInfo& v, int flags) { - if (v.screen != fl_screen) return 0; - if (!(flags & FL_INDEX)) { - if (!v.red_mask) return 0; // detects static, true, and direct color - if (v.depth <= 8) return 0; // fltk will work better in colormap mode - } - if (flags & FL_RGB8) { - if (v.depth < 24) return 0; - } - // for now, fltk does not like colormaps of more than 8 bits: - if (!v.red_mask && v.depth > 8) return 0; -#if USE_XDBE - if (flags & FL_DOUBLE) { - static XdbeScreenVisualInfo *xdbejunk; - if (!xdbejunk) { - int event_base, error_base; - if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; - Drawable root = RootWindow(fl_display,fl_screen); - int numscreens = 1; - xdbejunk = XdbeGetVisualInfo(fl_display,&root,&numscreens); - if (!xdbejunk) return 0; - } - for (int j = 0; ; j++) { - if (j >= xdbejunk->count) return 0; - if (xdbejunk->visinfo[j].visual == v.visualid) break; - } - } -#endif - return 1; -} - -int Fl::visual(int flags) { -#if USE_XDBE == 0 - if (flags & FL_DOUBLE) return 0; -#endif - fl_open_display(); - // always use default if possible: - if (test_visual(*fl_visual, flags)) return 1; - // get all the visuals: - XVisualInfo vTemplate; - int num; - XVisualInfo *visualList = XGetVisualInfo(fl_display, 0, &vTemplate, &num); - // find all matches, use the one with greatest depth: - XVisualInfo *found = 0; - for (int i=0; i<num; i++) if (test_visual(visualList[i], flags)) { - if (!found || found->depth < visualList[i].depth) - found = &visualList[i]; - } - if (!found) {XFree((void*)visualList); return 0;} - fl_visual = found; - fl_colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), - fl_visual->visual, AllocNone); - return 1; -} - -#endif +// Fl_visual.C
+//
+// Set the default visual according to passed switches:
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/x.H>
+
+#ifdef WIN32
+int Fl::visual(int flags) {
+ fl_GetDC(0);
+ if (flags & FL_DOUBLE) return 0;
+ if (!(flags & FL_INDEX) &&
+ GetDeviceCaps(fl_gc,BITSPIXEL) <= 8) return 0;
+ if ((flags & FL_RGB8) && GetDeviceCaps(fl_gc,BITSPIXEL)<24) return 0;
+ return 1;
+}
+#else
+
+#if USE_XDBE
+#include <X11/extensions/Xdbe.h>
+#endif
+
+static int test_visual(XVisualInfo& v, int flags) {
+ if (v.screen != fl_screen) return 0;
+ if (!(flags & FL_INDEX)) {
+ if (!v.red_mask) return 0; // detects static, true, and direct color
+ if (v.depth <= 8) return 0; // fltk will work better in colormap mode
+ }
+ if (flags & FL_RGB8) {
+ if (v.depth < 24) return 0;
+ }
+ // for now, fltk does not like colormaps of more than 8 bits:
+ if (!v.red_mask && v.depth > 8) return 0;
+#if USE_XDBE
+ if (flags & FL_DOUBLE) {
+ static XdbeScreenVisualInfo *xdbejunk;
+ if (!xdbejunk) {
+ int event_base, error_base;
+ if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0;
+ Drawable root = RootWindow(fl_display,fl_screen);
+ int numscreens = 1;
+ xdbejunk = XdbeGetVisualInfo(fl_display,&root,&numscreens);
+ if (!xdbejunk) return 0;
+ }
+ for (int j = 0; ; j++) {
+ if (j >= xdbejunk->count) return 0;
+ if (xdbejunk->visinfo[j].visual == v.visualid) break;
+ }
+ }
+#endif
+ return 1;
+}
+
+int Fl::visual(int flags) {
+#if USE_XDBE == 0
+ if (flags & FL_DOUBLE) return 0;
+#endif
+ fl_open_display();
+ // always use default if possible:
+ if (test_visual(*fl_visual, flags)) return 1;
+ // get all the visuals:
+ XVisualInfo vTemplate;
+ int num;
+ XVisualInfo *visualList = XGetVisualInfo(fl_display, 0, &vTemplate, &num);
+ // find all matches, use the one with greatest depth:
+ XVisualInfo *found = 0;
+ for (int i=0; i<num; i++) if (test_visual(visualList[i], flags)) {
+ if (!found || found->depth < visualList[i].depth)
+ found = &visualList[i];
+ }
+ if (!found) {XFree((void*)visualList); return 0;}
+ fl_visual = found;
+ fl_colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen),
+ fl_visual->visual, AllocNone);
+ return 1;
+}
+
+#endif
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index d00a22531..0a7ecd3b1 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,696 +1,767 @@ -// Fl_win32.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 - -// This file contains win32-specific code for fltk which is always linked -// in. Search other files for "WIN32" or filenames ending in _win32.C -// for other system-specific code. - -#include <config.h> -#include <FL/Fl.H> -#include <FL/win32.H> -#include <FL/Fl_Window.H> -#include <string.h> - -//////////////////////////////////////////////////////////////// -// interface to poll/select call: - -// fd's are not yet implemented. -// On NT these are probably only used for network stuff, so this may -// talk to a package that Wonko has proposed writing to make the network -// interface system independent. - -#define POLLIN 1 -#define POLLOUT 4 -#define POLLERR 8 - -void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *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) {} - -MSG fl_msg; - -int fl_ready() { - return PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE); -} - -double fl_wait(int timeout_flag, double time) { - int have_message; - // get the first message by waiting the correct amount of time: - if (!timeout_flag) { - GetMessage(&fl_msg, NULL, 0, 0); - have_message = 1; - } else { - if (time >= 0.001) { - int timerid = SetTimer(NULL, 0, int(time*1000), NULL); - GetMessage(&fl_msg, NULL, 0, 0); - KillTimer(NULL, timerid); - have_message = 1; - } else { - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - } - } - // execute it, them execute any other messages that become ready during it: - while (have_message) { - DispatchMessage(&fl_msg); - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - } - return time; -} - -//////////////////////////////////////////////////////////////// - -int Fl::h() {return GetSystemMetrics(SM_CYSCREEN);} - -int Fl::w() {return GetSystemMetrics(SM_CXSCREEN);} - -void Fl::get_mouse(int &x, int &y) { - POINT p; - GetCursorPos(&p); - x = p.x; - y = p.y; -} - -//////////////////////////////////////////////////////////////// - -extern Fl_Window *fl_xfocus; // in Fl.C -extern Fl_Window *fl_xmousewin; // in Fl.C -void fl_fix_focus(); // in Fl.C - -//////////////////////////////////////////////////////////////// - -extern HWND fl_capture; - -static int mouse_event(Fl_Window *window, int what, int button, - WPARAM wParam, LPARAM lParam) -{ - static int px, py, pmx, pmy; - POINT pt; - Fl::e_x = pt.x = (signed short)LOWORD(lParam); - Fl::e_y = pt.y = (signed short)HIWORD(lParam); - ClientToScreen(fl_xid(window), &pt); - Fl::e_x_root = pt.x; - Fl::e_y_root = pt.y; - while (window->parent()) { - Fl::e_x += window->x(); - Fl::e_y += window->y(); - window = window->window(); - } - - ulong state = Fl::e_state & 0xff0000; // keep shift key states -#if 0 - // mouse event reports some shift flags, perhaps save them? - if (wParam & MK_SHIFT) state |= FL_SHIFT; - if (wParam & MK_CONTROL) state |= FL_CTRL; -#endif - if (wParam & MK_LBUTTON) state |= FL_BUTTON1; - if (wParam & MK_MBUTTON) state |= FL_BUTTON2; - if (wParam & MK_RBUTTON) state |= FL_BUTTON3; - Fl::e_state = state; - - switch (what) { - case 1: // double-click - if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} - case 0: // single-click - Fl::e_clicks = 0; - J1: - if (!fl_capture) SetCapture(fl_xid(window)); - Fl::e_keysym = FL_Button + button; - Fl::e_is_click = 1; - px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; - return Fl::handle(FL_PUSH,window); - - case 2: // release: - if (!fl_capture) ReleaseCapture(); - Fl::e_keysym = FL_Button + button; - return Fl::handle(FL_RELEASE,window); - - case 3: // move: - default: // avoid compiler warning - // MSWindows produces extra events even if mouse does not move, ignore em: - if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; - pmx = Fl::e_x_root; pmy = Fl::e_y_root; - if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; - return Fl::handle(FL_MOVE,window); - - } -} - -// convert a Micro$oft VK_x to an Fltk (X) Keysym: -// See also the inverse converter in Fl_get_key_win32.C -// This table is in numeric order by VK: -static const struct {unsigned short vk, fltk;} vktab[] = { - {VK_BACK, FL_BackSpace}, - {VK_TAB, FL_Tab}, - {VK_CLEAR, FL_KP+'5'}, - {VK_RETURN, FL_Enter}, - {VK_SHIFT, FL_Shift_L}, - {VK_CONTROL, FL_Control_L}, - {VK_MENU, FL_Alt_L}, - {VK_PAUSE, FL_Pause}, - {VK_CAPITAL, FL_Caps_Lock}, - {VK_ESCAPE, FL_Escape}, - {VK_SPACE, ' '}, - {VK_PRIOR, FL_Page_Up}, - {VK_NEXT, FL_Page_Down}, - {VK_END, FL_End}, - {VK_HOME, FL_Home}, - {VK_LEFT, FL_Left}, - {VK_UP, FL_Up}, - {VK_RIGHT, FL_Right}, - {VK_DOWN, FL_Down}, - {VK_SNAPSHOT, FL_Print}, // does not work on NT - {VK_INSERT, FL_Insert}, - {VK_DELETE, FL_Delete}, - {VK_LWIN, FL_Meta_L}, - {VK_RWIN, FL_Meta_R}, - {VK_APPS, FL_Menu}, - {VK_MULTIPLY, FL_KP+'*'}, - {VK_ADD, FL_KP+'+'}, - {VK_SUBTRACT, FL_KP+'-'}, - {VK_DECIMAL, FL_KP+'.'}, - {VK_DIVIDE, FL_KP+'/'}, - {VK_NUMLOCK, FL_Num_Lock}, - {VK_SCROLL, FL_Scroll_Lock}, - {0xba, ';'}, - {0xbb, '='}, - {0xbc, ','}, - {0xbd, '-'}, - {0xbe, '.'}, - {0xbf, '/'}, - {0xc0, '`'}, - {0xdb, '['}, - {0xdc, '\\'}, - {0xdd, ']'}, - {0xde, '\''} -}; -static int ms2fltk(int vk, int extended) { - static unsigned short vklut[256]; - if (!vklut[1]) { // init the table - int i; - for (i = 0; i < 256; i++) vklut[i] = tolower(i); - for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); - for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); - for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) - vklut[vktab[i].vk] = vktab[i].fltk; - } - if (extended) switch (vk) { - case VK_CONTROL : return FL_Control_R; - case VK_MENU: return FL_Alt_R; - case VK_RETURN: return FL_KP_Enter; - } - return vklut[vk]; -} - -char fl_direct_paint; -static HDC direct_paint_dc; - -#if USE_COLORMAP -extern HPALETTE fl_select_palette(); // in fl_color_win32.C -#endif - -static Fl_Window* resize_bug_fix; - -static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static char buffer[2]; - - fl_msg.message = uMsg; - - Fl_Window *window = fl_find(hWnd); - - STUPID_MICROSOFT: - if (window) switch (uMsg) { - - case WM_QUIT: // this should not happen? - Fl::fatal("WM_QUIT message"); - - case WM_CLOSE: // user clicked close box - Fl::handle(FL_CLOSE, window); - return 0; - - case WM_PAINT: { - // MSWindows has already set the clip region! Fltk does not like this, - // since it wants to draw it's own damage at the same time, and - // this damage may be outside the clip region. I kludge around - // this, grep for fl_direct_paint to find the kludges... - if (!window->damage()) fl_direct_paint = 1; - PAINTSTRUCT ps; - direct_paint_dc = BeginPaint(hWnd, &ps); - window->expose(2, ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right-ps.rcPaint.left, - ps.rcPaint.bottom-ps.rcPaint.top); - if (!fl_direct_paint) {EndPaint(hWnd,&ps);ReleaseDC(hWnd,direct_paint_dc);} - Fl_X::i(window)->flush(); - window->clear_damage(); - Fl_X::i(window)->region = 0; - if (fl_direct_paint) {EndPaint(hWnd, &ps); fl_direct_paint = 0;} - } break; - - case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; - case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; - case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; - case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; - case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; - case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; - case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; - case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; - case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; - case WM_MOUSEMOVE: mouse_event(window, 3, 0, wParam, lParam); return 0; - - // kludges so the pop-up menus work. Title bar still blinks, sigh... - case WM_CAPTURECHANGED: - if (fl_capture && lParam != (LPARAM)fl_capture) { - SetCapture(fl_capture); - return 0; - } - break; - case WM_ACTIVATE: - if (fl_capture && wParam && hWnd!=fl_capture) { - SetActiveWindow(fl_capture); - return 0; - } - break; - - case WM_SETFOCUS: - Fl::handle(FL_FOCUS, window); - break; - - case WM_KILLFOCUS: - Fl::handle(FL_UNFOCUS, window); - Fl::flush(); // it never returns to main loop when deactivated... - break; - - case WM_SHOWWINDOW: - if (!window->parent()) - Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); - break; - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - // save the keysym until we figure out the characters: - Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24)); - case WM_KEYUP: - case WM_SYSKEYUP: - TranslateMessage(&fl_msg); // always returns 1!!! - // TranslateMessage is supposed to return true only if it turns - // into another message, but it seems to always return 1 on my - // NT machine. So I will instead peek to see if there is a - // character message in the queue, I hope this can only happen - // if the translation worked: - if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, 1)) { - uMsg = fl_msg.message; - wParam = fl_msg.wParam; - lParam = fl_msg.lParam; - goto STUPID_MICROSOFT; - } - // otherwise use it as a 0-character key... - case WM_DEADCHAR: - case WM_SYSDEADCHAR: - buffer[0] = 0; - Fl::e_text = buffer; - Fl::e_length = 0; - goto GETSTATE; - case WM_CHAR: - case WM_SYSCHAR: - buffer[0] = char(wParam); - Fl::e_text = buffer; - Fl::e_length = 1; - GETSTATE: - {ulong state = Fl::e_state & 0xff000000; // keep the mouse button state - // if GetKeyState is expensive we might want to comment some of these out: - if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; - if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; - if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL; - // Alt gets reported for the Alt-GR switch on foreign keyboards. - // so we need to check the event as well to get it right: - if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU) - && uMsg != WM_CHAR) state |= FL_ALT; - if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; - if (GetKeyState(VK_LWIN)&~1 || GetKeyState(VK_RWIN)&~1) state |= FL_META; - if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; - Fl::e_state = state;} - if (lParam & (1<<31)) goto DEFAULT; // ignore up events after fixing shift - // for (int i = lParam&0xff; i--;) - while (window->parent()) window = window->window(); - if (Fl::handle(FL_KEYBOARD,window)) return 0; - break; - - case WM_GETMINMAXINFO: - Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); - break; - - case WM_SIZE: - if (!window->parent()) { - if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { - Fl::handle(FL_HIDE, window); - } else { - Fl::handle(FL_SHOW, window); - resize_bug_fix = window; - window->size(LOWORD(lParam), HIWORD(lParam)); - } - } - break; - - case WM_MOVE: - resize_bug_fix = window; - window->position(LOWORD(lParam), HIWORD(lParam)); - break; - - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - while (window->parent()) window = window->window(); - SetCursor(Fl_X::i(window)->cursor); - return 0; - } - break; - -#if USE_COLORMAP - case WM_QUERYNEWPALETTE : - fl_GetDC(hWnd); - if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE); - break; - - case WM_PALETTECHANGED: - fl_GetDC(hWnd); - if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc); - break; - - case WM_CREATE : - fl_GetDC(hWnd); - fl_select_palette(); - break; -#endif - - default: - DEFAULT: - if (Fl::handle(0,0)) return 0; - break; - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -//////////////////////////////////////////////////////////////// - -void Fl_Window::resize(int X,int Y,int W,int H) { - int resize_from_program = 1; - if (this == resize_bug_fix) { - resize_from_program = 0; - resize_bug_fix = 0; - } - if (X==x() && Y==y() && W==w() && H==h()) return; - 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);} - if (resize_from_program && shown()) { - if (border() && !parent()) { - X -= GetSystemMetrics(SM_CXFRAME); - Y -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - W += 2*GetSystemMetrics(SM_CXFRAME); - H += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - } - MoveWindow(i->xid, X, Y, W, H, TRUE); - //if (!parent()) redraw(); - } -} - -//////////////////////////////////////////////////////////////// - -char fl_show_iconic; // hack for Fl_Window::iconic() -// int fl_background_pixel = -1; // color to use for background -HCURSOR fl_default_cursor; -int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR - -Fl_X* Fl_X::make(Fl_Window* w) { - Fl_Group::current(0); // get rid of very common user bug: forgot end() - w->clear_damage(); // wait for expose events - - static char* class_name; - if (!class_name) { // create a single WNDCLASS used for everything: - class_name = "FLTK"; - WNDCLASSEX wc; - wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; - wc.lpfnWndProc = (WNDPROC)WndProc; - wc.cbClsExtra = wc.cbWndExtra = 0; - wc.hInstance = fl_display; - wc.hIcon = wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); - //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); - //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = class_name; - wc.cbSize = sizeof(WNDCLASSEX); - RegisterClassEx(&wc); - } - - HWND parent; - DWORD style; - DWORD styleEx; - int xp = w->x(); - int yp = w->y(); - int wp = w->w(); - int hp = w->h(); - - if (w->parent()) { - style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - parent = fl_xid(w->window()); - } else { - if (!w->size_range_set) { - 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()); - } - } - if (w->border()) { - style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU - | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - if (w->maxw != w->minw || w->maxh != w->minh) - style |= WS_THICKFRAME | WS_MAXIMIZEBOX; - if (!w->modal()) style |= WS_MINIMIZEBOX; - xp -= GetSystemMetrics(SM_CXFRAME); - yp -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - wp += 2*GetSystemMetrics(SM_CXFRAME); - hp += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - } else { - style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED; - styleEx = WS_EX_LEFT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - } - if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) { - xp = yp = CW_USEDEFAULT; - } - parent = 0; - if (w->non_modal() && !fl_disable_transient_for) { - // find some other window to be "transient for": - for (Fl_X* y = Fl_X::first; y; y = y->next) { - Fl_Window* w = y->w; - while (w->parent()) w = w->window(); - if (!w->non_modal()) { - parent = fl_xid(w); - break; - } - } - } - } - - Fl_X* x = new Fl_X; - x->other_xid = 0; - x->setwindow(w); - x->region = 0; - x->private_dc = 0; - x->cursor = fl_default_cursor; - x->xid = CreateWindowEx( - styleEx, - class_name, w->label(), style, - xp, yp, wp, hp, - parent, - NULL, // menu - fl_display, - NULL // creation parameters - ); - x->next = Fl_X::first; - Fl_X::first = x; - - // use w->xclass() to set the icon... - - w->set_visible(); - w->handle(FL_SHOW); // get child windows to appear - ShowWindow(x->xid, fl_show_iconic ? SW_MINIMIZE : SW_SHOW); - fl_show_iconic = 0; - fl_fix_focus(); - return x; -} - -//////////////////////////////////////////////////////////////// - -HINSTANCE fl_display; - -int Fl_WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow, - int (*mainp)(int, char**)) { - fl_display = hInstance; - - int argc; - char **argv; - // test version for now: - argc = 1; char* testargv[] = {"test", 0}; argv = testargv; - - return mainp(argc, argv); -} - -//////////////////////////////////////////////////////////////// - -void Fl_Window::size_range_() { - size_range_set = 1; -} - -void Fl_X::set_minmax(LPMINMAXINFO minmax) -{ - int wd, hd; - if (w->border()) { - wd = 2*GetSystemMetrics(SM_CXFRAME); - hd = 2*GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION); - } else { - wd = hd = 0; - } - minmax->ptMinTrackSize.x = w->minw + wd; - minmax->ptMinTrackSize.y = w->minh + hd; - if (w->maxw) { - minmax->ptMaxTrackSize.x = w->maxw + wd; - minmax->ptMaxSize.x = w->maxw + wd; - } - if (w->maxh) { - minmax->ptMaxTrackSize.y = w->maxh + hd; - minmax->ptMaxSize.y = w->maxh + hd; - } -} - -//////////////////////////////////////////////////////////////// - -// returns pointer to the filename, or null if name ends with '/' -const char *filename_name(const char *name) { - const char *p,*q; - q = name; - if (q[0] && q[1]==':') q += 2; // skip leading drive letter - for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1; - return q; -} - -void Fl_Window::label(const char *name,const char *iname) { - Fl_Widget::label(name); - iconlabel_ = iname; - if (shown() && !parent()) { - if (!name) name = ""; - SetWindowText(i->xid, name); - // if (!iname) iname = filename_name(name); - // should do something with iname here... - } -} - -//////////////////////////////////////////////////////////////// -// 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: -// For WIN32 it looks like all windows share a background color, so -// I use FL_GRAY for this and only do this cheat for windows that are -// that color. -// Actually it is totally disabled. -// Fl_Widget *fl_boxcheat; -//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} - -void Fl_Window::show() { - if (!shown()) { - // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color()); - Fl_X::make(this); - } else { - ShowWindow(i->xid, SW_RESTORE); - SetActiveWindow(i->xid); - } -} - -Fl_Window *Fl_Window::current_; -HDC fl_gc; // the current context -HWND fl_window; // the current window - -// Make sure we always ReleaseDC every DC we allocate... -HDC fl_GetDC(HWND w) { - if (fl_gc) { - if (w == fl_window) return fl_gc; - ReleaseDC(fl_window, fl_gc); - } - fl_gc = fl_direct_paint ? direct_paint_dc : GetDC(w); - fl_window = w; - // calling GetDC seems to always reset these: (?) - SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT); - SetBkMode(fl_gc, TRANSPARENT); - return fl_gc; -} - -// make X drawing go into this window (called by subclass flush() impl.) -void Fl_Window::make_current() { - fl_GetDC(fl_xid(this)); - current_ = this; -} - -// WM_PAINT events and cropped damage call this: -void Fl_Window::expose(uchar flags,int X,int Y,int W,int H) { - if (i) { - if (!i->region.r) { - i->region.x = X; - i->region.y = Y; - i->region.r = X+W; - i->region.b = Y+H; - } else { - if (X < i->region.x) i->region.x = X; - if (Y < i->region.y) i->region.y = Y; - if (X+W > i->region.r) i->region.r = X+W; - if (Y+H > i->region.b) i->region.b = Y+H; - } - } - damage(flags); -} - -#include <FL/fl_draw.H> - -void Fl_Window::flush() { - make_current(); - if (damage() & ~6) { - draw(); - } else { - fl_clip_region(i->region); - draw(); - fl_pop_clip(); - } -} - -// End of Fl_win32.C // +// Fl_win32.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
+
+// This file contains win32-specific code for fltk which is always linked
+// in. Search other files for "WIN32" or filenames ending in _win32.C
+// for other system-specific code.
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/win32.H>
+#include <FL/Fl_Window.H>
+#include <string.h>
+
+////////////////////////////////////////////////////////////////
+// interface to poll/select call:
+
+// fd's are not yet implemented.
+// On NT these are probably only used for network stuff, so this may
+// talk to a package that Wonko has proposed writing to make the network
+// interface system independent.
+
+#define POLLIN 1
+#define POLLOUT 4
+#define POLLERR 8
+
+void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *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) {}
+
+MSG fl_msg;
+
+int fl_ready() {
+ return PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE);
+}
+
+double fl_wait(int timeout_flag, double time) {
+ int have_message;
+ // get the first message by waiting the correct amount of time:
+ if (!timeout_flag) {
+ GetMessage(&fl_msg, NULL, 0, 0);
+ have_message = 1;
+ } else {
+ if (time >= 0.001) {
+ int timerid = SetTimer(NULL, 0, int(time*1000), NULL);
+ GetMessage(&fl_msg, NULL, 0, 0);
+ KillTimer(NULL, timerid);
+ have_message = 1;
+ } else {
+ have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
+ }
+ }
+ // execute it, them execute any other messages that become ready during it:
+ while (have_message) {
+ DispatchMessage(&fl_msg);
+ have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
+ }
+ return time;
+}
+
+////////////////////////////////////////////////////////////////
+
+int Fl::h() {return GetSystemMetrics(SM_CYSCREEN);}
+
+int Fl::w() {return GetSystemMetrics(SM_CXSCREEN);}
+
+void Fl::get_mouse(int &x, int &y) {
+ POINT p;
+ GetCursorPos(&p);
+ x = p.x;
+ y = p.y;
+}
+
+////////////////////////////////////////////////////////////////
+
+extern Fl_Window *fl_xfocus; // in Fl.C
+extern Fl_Window *fl_xmousewin; // in Fl.C
+void fl_fix_focus(); // in Fl.C
+
+////////////////////////////////////////////////////////////////
+
+extern HWND fl_capture;
+
+static int mouse_event(Fl_Window *window, int what, int button,
+ WPARAM wParam, LPARAM lParam)
+{
+ static int px, py, pmx, pmy;
+ POINT pt;
+ Fl::e_x = pt.x = (signed short)LOWORD(lParam);
+ Fl::e_y = pt.y = (signed short)HIWORD(lParam);
+ ClientToScreen(fl_xid(window), &pt);
+ Fl::e_x_root = pt.x;
+ Fl::e_y_root = pt.y;
+ while (window->parent()) {
+ Fl::e_x += window->x();
+ Fl::e_y += window->y();
+ window = window->window();
+ }
+
+ ulong state = Fl::e_state & 0xff0000; // keep shift key states
+#if 0
+ // mouse event reports some shift flags, perhaps save them?
+ if (wParam & MK_SHIFT) state |= FL_SHIFT;
+ if (wParam & MK_CONTROL) state |= FL_CTRL;
+#endif
+ if (wParam & MK_LBUTTON) state |= FL_BUTTON1;
+ if (wParam & MK_MBUTTON) state |= FL_BUTTON2;
+ if (wParam & MK_RBUTTON) state |= FL_BUTTON3;
+ Fl::e_state = state;
+
+ switch (what) {
+ case 1: // double-click
+ if (Fl::e_is_click) {Fl::e_clicks++; goto J1;}
+ case 0: // single-click
+ Fl::e_clicks = 0;
+ J1:
+ if (!fl_capture) SetCapture(fl_xid(window));
+ Fl::e_keysym = FL_Button + button;
+ Fl::e_is_click = 1;
+ px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root;
+ return Fl::handle(FL_PUSH,window);
+
+ case 2: // release:
+ if (!fl_capture) ReleaseCapture();
+ Fl::e_keysym = FL_Button + button;
+ return Fl::handle(FL_RELEASE,window);
+
+ case 3: // move:
+ default: // avoid compiler warning
+ // MSWindows produces extra events even if mouse does not move, ignore em:
+ if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1;
+ pmx = Fl::e_x_root; pmy = Fl::e_y_root;
+ if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0;
+ return Fl::handle(FL_MOVE,window);
+
+ }
+}
+
+// convert a MSWindows VK_x to an Fltk (X) Keysym:
+// See also the inverse converter in Fl_get_key_win32.C
+// This table is in numeric order by VK:
+static const struct {unsigned short vk, fltk;} vktab[] = {
+ {VK_BACK, FL_BackSpace},
+ {VK_TAB, FL_Tab},
+ {VK_CLEAR, FL_KP+'5'},
+ {VK_RETURN, FL_Enter},
+ {VK_SHIFT, FL_Shift_L},
+ {VK_CONTROL, FL_Control_L},
+ {VK_MENU, FL_Alt_L},
+ {VK_PAUSE, FL_Pause},
+ {VK_CAPITAL, FL_Caps_Lock},
+ {VK_ESCAPE, FL_Escape},
+ {VK_SPACE, ' '},
+ {VK_PRIOR, FL_Page_Up},
+ {VK_NEXT, FL_Page_Down},
+ {VK_END, FL_End},
+ {VK_HOME, FL_Home},
+ {VK_LEFT, FL_Left},
+ {VK_UP, FL_Up},
+ {VK_RIGHT, FL_Right},
+ {VK_DOWN, FL_Down},
+ {VK_SNAPSHOT, FL_Print}, // does not work on NT
+ {VK_INSERT, FL_Insert},
+ {VK_DELETE, FL_Delete},
+ {VK_LWIN, FL_Meta_L},
+ {VK_RWIN, FL_Meta_R},
+ {VK_APPS, FL_Menu},
+ {VK_MULTIPLY, FL_KP+'*'},
+ {VK_ADD, FL_KP+'+'},
+ {VK_SUBTRACT, FL_KP+'-'},
+ {VK_DECIMAL, FL_KP+'.'},
+ {VK_DIVIDE, FL_KP+'/'},
+ {VK_NUMLOCK, FL_Num_Lock},
+ {VK_SCROLL, FL_Scroll_Lock},
+ {0xba, ';'},
+ {0xbb, '='},
+ {0xbc, ','},
+ {0xbd, '-'},
+ {0xbe, '.'},
+ {0xbf, '/'},
+ {0xc0, '`'},
+ {0xdb, '['},
+ {0xdc, '\\'},
+ {0xdd, ']'},
+ {0xde, '\''}
+};
+static int ms2fltk(int vk, int extended) {
+ static unsigned short vklut[256];
+ if (!vklut[1]) { // init the table
+ unsigned int i;
+ for (i = 0; i < 256; i++) vklut[i] = tolower(i);
+ for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1));
+ for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0);
+ for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++)
+ vklut[vktab[i].vk] = vktab[i].fltk;
+ }
+ if (extended) switch (vk) {
+ case VK_CONTROL : return FL_Control_R;
+ case VK_MENU: return FL_Alt_R;
+ case VK_RETURN: return FL_KP_Enter;
+ }
+ return vklut[vk];
+}
+
+#if USE_COLORMAP
+extern HPALETTE fl_select_palette(); // in fl_color_win32.C
+#endif
+
+static Fl_Window* resize_bug_fix;
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static char buffer[2];
+
+ fl_msg.message = uMsg;
+
+ Fl_Window *window = fl_find(hWnd);
+
+ STUPID_MICROSOFT:
+ if (window) switch (uMsg) {
+
+ case WM_QUIT: // this should not happen?
+ Fl::fatal("WM_QUIT message");
+
+ case WM_CLOSE: // user clicked close box
+ Fl::handle(FL_CLOSE, window);
+ return 0;
+
+ case WM_PAINT: {
+ // MSWindows has already set the clip region! Fltk does not like this,
+ // since it wants to draw it's own damage at the same time, and
+ // this damage may be outside the clip region. I kludge around
+ // this, grep for fl_direct_paint to find the kludges...
+ // if (!(window->damage())) fl_direct_paint = 1;
+ PAINTSTRUCT ps;
+
+ // I think MSWindows refuses to allocate two DCs for the same hWnd,
+ // so it may kludge the way the DCs are being handled. Works for now,
+ // the "final" solution can wait... Whatever the behaviour of the win32
+ // API, there is bound to be some small memory leak here.
+ // If anyone knows EXACTLY how DCs are allocated, please fix.
+ fl_window = hWnd;
+ fl_gc = BeginPaint(hWnd, &ps);
+ // A bug popped up because of the two following lines, which according to
+ // the original code's comments GetDC always resets. I just don't get
+ // why the problem hadn't manifested itself here earlier (well, probably
+ // because MSWindows was not allocating a new DC, but using the old one)
+ // Anyway, these followed the original GetDC calls, but for some reason
+ // were not here with the BeginPaint
+ SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
+ SetBkMode(fl_gc, TRANSPARENT);
+
+ window->expose(2, ps.rcPaint.left, ps.rcPaint.top,
+ ps.rcPaint.right-ps.rcPaint.left,
+ ps.rcPaint.bottom-ps.rcPaint.top);
+
+ Fl_X::i(window)->flush();
+ window->clear_damage();
+ //Since damage has been reset, we can dispose of the clip region
+ Region &r=Fl_X::i(window)->region;
+ if (r) {
+ DeleteObject(r);
+ r = 0;
+ }
+ EndPaint(hWnd, &ps);
+
+ fl_gc = 0;
+ fl_window = (HWND)-1;
+ } break;
+
+ case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0;
+ case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0;
+ case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0;
+ case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0;
+ case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0;
+ case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0;
+ case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0;
+ case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0;
+ case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0;
+ case WM_MOUSEMOVE: mouse_event(window, 3, 0, wParam, lParam); return 0;
+
+ // kludges so the pop-up menus work. Title bar still blinks, sigh...
+ case WM_CAPTURECHANGED:
+ if (fl_capture && lParam != (LPARAM)fl_capture) {
+ SetCapture(fl_capture);
+ return 0;
+ }
+ break;
+ case WM_ACTIVATE:
+ if (fl_capture && wParam && hWnd!=fl_capture) {
+ SetActiveWindow(fl_capture);
+ return 0;
+ }
+ break;
+
+ case WM_SETFOCUS:
+ Fl::handle(FL_FOCUS, window);
+ break;
+
+ case WM_KILLFOCUS:
+ Fl::handle(FL_UNFOCUS, window);
+ Fl::flush(); // it never returns to main loop when deactivated...
+ break;
+
+ case WM_SHOWWINDOW:
+ if (!window->parent())
+ Fl::handle(wParam ? FL_SHOW : FL_HIDE, window);
+ break;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ // save the keysym until we figure out the characters:
+ Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24));
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ TranslateMessage(&fl_msg); // always returns 1!!!
+ // TranslateMessage is supposed to return true only if it turns
+ // into another message, but it seems to always return 1 on my
+ // NT machine. So I will instead peek to see if there is a
+ // character message in the queue, I hope this can only happen
+ // if the translation worked:
+ if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, 1)) {
+ uMsg = fl_msg.message;
+ wParam = fl_msg.wParam;
+ lParam = fl_msg.lParam;
+ goto STUPID_MICROSOFT;
+ }
+ // otherwise use it as a 0-character key...
+ case WM_DEADCHAR:
+ case WM_SYSDEADCHAR:
+ buffer[0] = 0;
+ Fl::e_text = buffer;
+ Fl::e_length = 0;
+ goto GETSTATE;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ buffer[0] = char(wParam);
+ Fl::e_text = buffer;
+ Fl::e_length = 1;
+ GETSTATE:
+ {ulong state = Fl::e_state & 0xff000000; // keep the mouse button state
+ // if GetKeyState is expensive we might want to comment some of these out:
+ if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
+ if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
+ if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
+ // Alt gets reported for the Alt-GR switch on foreign keyboards.
+ // so we need to check the event as well to get it right:
+ if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU)
+ && uMsg != WM_CHAR) state |= FL_ALT;
+ if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
+ if (GetKeyState(VK_LWIN)&~1 || GetKeyState(VK_RWIN)&~1) state |= FL_META;
+ if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
+ Fl::e_state = state;}
+ if (lParam & (1<<31)) goto DEFAULT; // ignore up events after fixing shift
+ // for (int i = lParam&0xff; i--;)
+ while (window->parent()) window = window->window();
+ if (Fl::handle(FL_KEYBOARD,window)) return 0;
+ break;
+
+ case WM_GETMINMAXINFO:
+ Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
+ break;
+
+ case WM_SIZE:
+ if (!window->parent()) {
+ if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) {
+ Fl::handle(FL_HIDE, window);
+ } else {
+ Fl::handle(FL_SHOW, window);
+ resize_bug_fix = window;
+ window->size(LOWORD(lParam), HIWORD(lParam));
+ }
+ }
+ break;
+
+ case WM_MOVE:
+ resize_bug_fix = window;
+ window->position(LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) == HTCLIENT) {
+ while (window->parent()) window = window->window();
+ SetCursor(Fl_X::i(window)->cursor);
+ return 0;
+ }
+ break;
+
+#if USE_COLORMAP
+ case WM_QUERYNEWPALETTE :
+ fl_GetDC(hWnd);
+ if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE);
+ break;
+
+ case WM_PALETTECHANGED:
+ fl_GetDC(hWnd);
+ if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc);
+ break;
+
+ case WM_CREATE :
+ fl_GetDC(hWnd);
+ fl_select_palette();
+ break;
+#endif
+
+ default:
+ DEFAULT:
+ if (Fl::handle(0,0)) return 0;
+ break;
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+////////////////////////////////////////////////////////////////
+
+void Fl_Window::resize(int X,int Y,int W,int H) {
+ int resize_from_program = 1;
+ if (this == resize_bug_fix) {
+ resize_from_program = 0;
+ resize_bug_fix = 0;
+ }
+ if (X==x() && Y==y() && W==w() && H==h()) return;
+ 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);}
+ if (resize_from_program && shown()) {
+ if (border() && !parent()) {
+ X -= GetSystemMetrics(SM_CXFRAME);
+ Y -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ W += 2*GetSystemMetrics(SM_CXFRAME);
+ H += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ }
+ MoveWindow(i->xid, X, Y, W, H, TRUE);
+ //if (!parent()) redraw();
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+char fl_show_iconic; // hack for Fl_Window::iconic()
+// int fl_background_pixel = -1; // color to use for background
+HCURSOR fl_default_cursor;
+int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
+
+Fl_X* Fl_X::make(Fl_Window* w) {
+ Fl_Group::current(0); // get rid of very common user bug: forgot end()
+ w->clear_damage(); // wait for expose events
+
+ static char* class_name;
+ if (!class_name) { // create a single WNDCLASS used for everything:
+ class_name = "FLTK";
+ WNDCLASSEX wc;
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
+ wc.lpfnWndProc = (WNDPROC)WndProc;
+ wc.cbClsExtra = wc.cbWndExtra = 0;
+ wc.hInstance = fl_display;
+ wc.hIcon = wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
+ //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
+ //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = class_name;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ RegisterClassEx(&wc);
+ }
+
+ HWND parent;
+ DWORD style;
+ DWORD styleEx;
+ int xp = w->x();
+ int yp = w->y();
+ int wp = w->w();
+ int hp = w->h();
+
+ if (w->parent()) {
+ style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
+ parent = fl_xid(w->window());
+ } else {
+ if (!w->size_range_set) {
+ 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());
+ }
+ }
+ if (w->border()) {
+ style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
+ | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
+ if (w->maxw != w->minw || w->maxh != w->minh)
+ style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
+ if (!w->modal()) style |= WS_MINIMIZEBOX;
+ xp -= GetSystemMetrics(SM_CXFRAME);
+ yp -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ wp += 2*GetSystemMetrics(SM_CXFRAME);
+ hp += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ } else {
+ style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED;
+ styleEx = WS_EX_LEFT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
+ }
+ if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) {
+ xp = yp = CW_USEDEFAULT;
+ }
+ parent = 0;
+ if (w->non_modal() && !fl_disable_transient_for) {
+ // find some other window to be "transient for":
+ for (Fl_X* y = Fl_X::first; y; y = y->next) {
+ Fl_Window* w = y->w;
+ while (w->parent()) w = w->window();
+ if (!w->non_modal()) {
+ parent = fl_xid(w);
+ break;
+ }
+ }
+ }
+ }
+
+ Fl_X* x = new Fl_X;
+ x->other_xid = 0;
+ x->setwindow(w);
+ x->region = 0;
+ x->private_dc = 0;
+ x->cursor = fl_default_cursor;
+ x->xid = CreateWindowEx(
+ styleEx,
+ class_name, w->label(), style,
+ xp, yp, wp, hp,
+ parent,
+ NULL, // menu
+ fl_display,
+ NULL // creation parameters
+ );
+ x->next = Fl_X::first;
+ Fl_X::first = x;
+
+ // use w->xclass() to set the icon...
+
+ w->set_visible();
+ w->handle(FL_SHOW); // get child windows to appear
+ ShowWindow(x->xid, fl_show_iconic ? SW_MINIMIZE : SW_SHOW);
+ fl_show_iconic = 0;
+ fl_fix_focus();
+ return x;
+}
+
+////////////////////////////////////////////////////////////////
+
+HINSTANCE fl_display;
+
+int Fl_WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow,
+ int (*mainp)(int, char**)) {
+ fl_display = hInstance;
+
+ int argc;
+ char **argv;
+ // test version for now:
+ argc = 1; char* testargv[] = {"test", 0}; argv = testargv;
+
+ return mainp(argc, argv);
+}
+
+////////////////////////////////////////////////////////////////
+
+void Fl_Window::size_range_() {
+ size_range_set = 1;
+}
+
+void Fl_X::set_minmax(LPMINMAXINFO minmax)
+{
+ int wd, hd;
+ if (w->border()) {
+ wd = 2*GetSystemMetrics(SM_CXFRAME);
+ hd = 2*GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
+ } else {
+ wd = hd = 0;
+ }
+ minmax->ptMinTrackSize.x = w->minw + wd;
+ minmax->ptMinTrackSize.y = w->minh + hd;
+ if (w->maxw) {
+ minmax->ptMaxTrackSize.x = w->maxw + wd;
+ minmax->ptMaxSize.x = w->maxw + wd;
+ }
+ if (w->maxh) {
+ minmax->ptMaxTrackSize.y = w->maxh + hd;
+ minmax->ptMaxSize.y = w->maxh + hd;
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+// returns pointer to the filename, or null if name ends with '/'
+const char *filename_name(const char *name) {
+ const char *p,*q;
+ q = name;
+ if (q[0] && q[1]==':') q += 2; // skip leading drive letter
+ for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1;
+ return q;
+}
+
+void Fl_Window::label(const char *name,const char *iname) {
+ Fl_Widget::label(name);
+ iconlabel_ = iname;
+ if (shown() && !parent()) {
+ if (!name) name = "";
+ SetWindowText(i->xid, name);
+ // if (!iname) iname = filename_name(name);
+ // should do something with iname here...
+ }
+}
+
+////////////////////////////////////////////////////////////////
+// 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:
+// For WIN32 it looks like all windows share a background color, so
+// I use FL_GRAY for this and only do this cheat for windows that are
+// that color.
+// Actually it is totally disabled.
+// Fl_Widget *fl_boxcheat;
+//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);}
+
+void Fl_Window::show() {
+ if (!shown()) {
+ // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color());
+ Fl_X::make(this);
+ } else {
+ ShowWindow(i->xid, SW_RESTORE);
+ SetActiveWindow(i->xid);
+ }
+}
+
+Fl_Window *Fl_Window::current_;
+HDC window_dc;
+// the current context
+HDC fl_gc = 0;
+// the current window handle, initially set to -1 so we can correctly
+// allocate fl_GetDC(0)
+HWND fl_window = (HWND)-1;
+
+// Here we ensure only one GetDC is ever in place. There is a little
+// workaround for the case of direct_paint.
+HDC fl_GetDC(HWND w) {
+ /*
+ if (fl_direct_paint) {
+ if (w == direct_paint_window) return direct_paint_dc;
+ }
+*/
+ if (fl_gc) {
+ if (w == fl_window) return fl_gc;
+ ReleaseDC(fl_window, fl_gc);
+ }
+ fl_gc = GetDC(w);
+ fl_window = w;
+ // calling GetDC seems to always reset these: (?)
+ SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
+ SetBkMode(fl_gc, TRANSPARENT);
+ return fl_gc;
+}
+
+// make X drawing go into this window (called by subclass flush() impl.)
+void Fl_Window::make_current() {
+ fl_GetDC(fl_xid(this));
+ current_ = this;
+}
+
+// WM_PAINT events and cropped damage call this:
+void Fl_Window::expose(uchar flags,int X,int Y,int W,int H) {
+ if (i) {
+ Region temp= XRectangleRegion(X,Y,W,H);
+ if (i->region) {
+ CombineRgn(temp,temp,i->region,RGN_AND);
+ DeleteObject((HGDIOBJ)i->region);
+ }
+ i->region=temp;
+ }
+ damage(flags);
+}
+
+#include <FL/fl_draw.H>
+
+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) {DeleteObject((HGDIOBJ)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) {
+ Region r = XRectangleRegion(X,Y,W,H);
+ CombineRgn(i->region,i->region,r,RGN_OR);
+ DeleteObject(r);
+ }
+ damage_ |= flags;
+ } else {
+ // create a new region:
+ if (i->region) DeleteObject(i->region);
+ i->region = XRectangleRegion(X,Y,W,H);
+ damage_ = flags;
+ }
+ Fl::damage(1);
+ }
+ }
+}
+
+void Fl_Window::flush() {
+ make_current();
+ if (damage() & ~6) {
+ draw();
+ } else {
+ fl_clip_region(i->region);
+ draw();
+ fl_pop_clip();
+ }
+}
+
+// End of Fl_win32.C //
diff --git a/src/fl_font_win32.cxx b/src/fl_font_win32.cxx index 0f4e20e77..99283a433 100644 --- a/src/fl_font_win32.cxx +++ b/src/fl_font_win32.cxx @@ -1,159 +1,159 @@ -// fl_font_win32.C - -#include <config.h> -#include <FL/Fl.H> -#include <FL/fl_draw.H> -#include <FL/win32.H> -#include "Fl_Font.H" - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> - -Fl_XFont::Fl_XFont(const char *name, int size, int num) { - int weight = FW_NORMAL; - int italic = 0; - switch (*name++) { - case 'I': italic = 1; break; - case 'P': italic = 1; - case 'B': weight = FW_BOLD; break; - case ' ': break; - default: name--; - } - fid = CreateFont( - -size, // negative makes it use "char size" - 0, // logical average character width - 0, // angle of escapement - 0, // base-line orientation angle - weight, - italic, - FALSE, // underline attribute flag - FALSE, // strikeout attribute flag - DEFAULT_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS,// clipping precision - DEFAULT_QUALITY, // output quality - DEFAULT_PITCH, // pitch and family - name // pointer to typeface name string - ); - if (!fl_gc) fl_gc = fl_GetDC(0); - SelectObject(fl_gc, fid); - GetTextMetrics(fl_gc, &metr); -// BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar); -// ...would be the right call, but is not implemented into Window95! (WinNT?) - GetCharWidth(fl_gc, 0, 255, width); -#if HAVE_GL - listbase = 0; -#endif - number = num; - minsize = maxsize = size; -} - -Fl_XFont *fl_current_xfont; - -Fl_XFont::~Fl_XFont() { -#if HAVE_GL -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -// if (listbase) { -// int base = font->min_char_or_byte2; -// int size = font->max_char_or_byte2-base+1; -// int base = 0; int size = 256; -// glDeleteLists(listbase+base,size); -// } -#endif - if (this == fl_current_xfont) fl_current_xfont = 0; - DeleteObject(fid); -} - -//////////////////////////////////////////////////////////////// - -// WARNING: if you add to this table, you must redefine FL_FREE_FONT -// in Enumerations.H & recompile!! -static Fl_Fontdesc built_in_table[] = { -{" Arial"}, -{"BArial"}, -{"IArial"}, -{"PArial"}, -{" Courier New"}, -{"BCourier New"}, -{"ICourier New"}, -{"PCourier New"}, -{" Times New Roman"}, -{"BTimes New Roman"}, -{"ITimes New Roman"}, -{"PTimes New Roman"}, -{" Symbol"}, -{" Terminal"}, -{"BTerminal"}, -{" Wingdings"}, -}; - -Fl_Fontdesc *fl_fonts = built_in_table; - -static Fl_XFont *find(int fnum, int size) { - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_XFont *f; - for (f = s->first; f; f = f->next) - if (f->minsize <= size && f->maxsize >= size) return f; - f = new Fl_XFont(s->name, size, fnum); - f->next = s->first; - s->first = f; - return f; -} - -//////////////////////////////////////////////////////////////// -// Public interface: - -int fl_font_; -int fl_size_; -static HDC font_gc; - -void fl_font(int fnum, int size) { - if (fnum == fl_font_ && size == fl_size_) return; - fl_font_ = fnum; fl_size_ = size; - fl_current_xfont = find(fnum, size); -} - -void fl_font(int fnum, int size, Fl_Font default_font, int default_size) { - if (fnum<4) fnum |= default_font; - fl_font(fnum, size + default_size); -} - -int fl_height() { - return (fl_current_xfont->metr.tmAscent + fl_current_xfont->metr.tmDescent); -} - -int fl_descent() { - return fl_current_xfont->metr.tmDescent; -} - -double fl_width(const char *c) { - double w = 0.0; - while (*c) w += fl_current_xfont->width[uchar(*c++)]; - return w; -} - -double fl_width(const char *c, int n) { - double w = 0.0; - while (n--) w += fl_current_xfont->width[uchar(*c++)]; - return w; -} - -double fl_width(uchar c) { - return fl_current_xfont->width[c]; -} - -void fl_draw(const char *str, int n, int x, int y) { - SetTextColor(fl_gc, fl_RGB()); - SelectObject(fl_gc, fl_current_xfont->fid); - TextOut(fl_gc, x, y, str, n); -} - -void fl_draw(const char *str, int x, int y) { - fl_draw(str, strlen(str), x, y); -} - -// end of fl_font_win32.C +// fl_font_win32.C
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/win32.H>
+#include "Fl_Font.H"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+Fl_XFont::Fl_XFont(const char *name, int size, int num) {
+ int weight = FW_NORMAL;
+ int italic = 0;
+ switch (*name++) {
+ case 'I': italic = 1; break;
+ case 'P': italic = 1;
+ case 'B': weight = FW_BOLD; break;
+ case ' ': break;
+ default: name--;
+ }
+ fid = CreateFont(
+ -size, // negative makes it use "char size"
+ 0, // logical average character width
+ 0, // angle of escapement
+ 0, // base-line orientation angle
+ weight,
+ italic,
+ FALSE, // underline attribute flag
+ FALSE, // strikeout attribute flag
+ DEFAULT_CHARSET, // character set identifier
+ OUT_DEFAULT_PRECIS, // output precision
+ CLIP_DEFAULT_PRECIS,// clipping precision
+ DEFAULT_QUALITY, // output quality
+ DEFAULT_PITCH, // pitch and family
+ name // pointer to typeface name string
+ );
+ if (!fl_gc) fl_GetDC(0);
+ SelectObject(fl_gc, fid);
+ GetTextMetrics(fl_gc, &metr);
+// BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar);
+// ...would be the right call, but is not implemented into Window95! (WinNT?)
+ GetCharWidth(fl_gc, 0, 255, width);
+#if HAVE_GL
+ listbase = 0;
+#endif
+ number = num;
+ minsize = maxsize = size;
+}
+
+Fl_XFont *fl_current_xfont;
+
+Fl_XFont::~Fl_XFont() {
+#if HAVE_GL
+// Delete list created by gl_draw(). This is not done by this code
+// as it will link in GL unnecessarily. There should be some kind
+// of "free" routine pointer, or a subclass?
+// if (listbase) {
+// int base = font->min_char_or_byte2;
+// int size = font->max_char_or_byte2-base+1;
+// int base = 0; int size = 256;
+// glDeleteLists(listbase+base,size);
+// }
+#endif
+ if (this == fl_current_xfont) fl_current_xfont = 0;
+ DeleteObject(fid);
+}
+
+////////////////////////////////////////////////////////////////
+
+// WARNING: if you add to this table, you must redefine FL_FREE_FONT
+// in Enumerations.H & recompile!!
+static Fl_Fontdesc built_in_table[] = {
+{" Arial"},
+{"BArial"},
+{"IArial"},
+{"PArial"},
+{" Courier New"},
+{"BCourier New"},
+{"ICourier New"},
+{"PCourier New"},
+{" Times New Roman"},
+{"BTimes New Roman"},
+{"ITimes New Roman"},
+{"PTimes New Roman"},
+{" Symbol"},
+{" Terminal"},
+{"BTerminal"},
+{" Wingdings"},
+};
+
+Fl_Fontdesc *fl_fonts = built_in_table;
+
+static Fl_XFont *find(int fnum, int size) {
+ Fl_Fontdesc *s = fl_fonts+fnum;
+ if (!s->name) s = fl_fonts; // use 0 if fnum undefined
+ Fl_XFont *f;
+ for (f = s->first; f; f = f->next)
+ if (f->minsize <= size && f->maxsize >= size) return f;
+ f = new Fl_XFont(s->name, size, fnum);
+ f->next = s->first;
+ s->first = f;
+ return f;
+}
+
+////////////////////////////////////////////////////////////////
+// Public interface:
+
+int fl_font_;
+int fl_size_;
+//static HDC font_gc;
+
+void fl_font(int fnum, int size) {
+ if (fnum == fl_font_ && size == fl_size_) return;
+ fl_font_ = fnum; fl_size_ = size;
+ fl_current_xfont = find(fnum, size);
+}
+
+void fl_font(int fnum, int size, Fl_Font default_font, int default_size) {
+ if (fnum<4) fnum |= default_font;
+ fl_font(fnum, size + default_size);
+}
+
+int fl_height() {
+ return (fl_current_xfont->metr.tmAscent + fl_current_xfont->metr.tmDescent);
+}
+
+int fl_descent() {
+ return fl_current_xfont->metr.tmDescent;
+}
+
+double fl_width(const char *c) {
+ double w = 0.0;
+ while (*c) w += fl_current_xfont->width[uchar(*c++)];
+ return w;
+}
+
+double fl_width(const char *c, int n) {
+ double w = 0.0;
+ while (n--) w += fl_current_xfont->width[uchar(*c++)];
+ return w;
+}
+
+double fl_width(uchar c) {
+ return fl_current_xfont->width[c];
+}
+
+void fl_draw(const char *str, int n, int x, int y) {
+ SetTextColor(fl_gc, fl_RGB());
+ SelectObject(fl_gc, fl_current_xfont->fid);
+ TextOut(fl_gc, x, y, str, n);
+}
+
+void fl_draw(const char *str, int x, int y) {
+ fl_draw(str, strlen(str), x, y);
+}
+
+// end of fl_font_win32.C
diff --git a/src/fl_rect.cxx b/src/fl_rect.cxx index 2e294bd96..1ea826c6f 100644 --- a/src/fl_rect.cxx +++ b/src/fl_rect.cxx @@ -1,380 +1,351 @@ -// fl_rect.C - -// These routines from fl_draw.H are used by the standard boxtypes -// and thus are always linked into an fltk program. - -// Also all fl_clip routines, since they are always linked in so -// that minimal update works. - -#include <FL/Fl_Widget.H> -#include <FL/fl_draw.H> -#include <FL/x.H> - -void fl_rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x+w-1, y); - LineTo(fl_gc, x+w-1, y+h-1); - LineTo(fl_gc, x, y+h-1); - LineTo(fl_gc, x, y); -#else - XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); -#endif -} - -void fl_rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; -#ifdef WIN32 - RECT rect; - rect.left = x; rect.top = y; - rect.right = x + w; rect.bottom = y + h; - FillRect(fl_gc, &rect, fl_brush()); -#else - if (w && h) XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); -#endif -} - -void fl_xyline(int x, int y, int x1) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y); -#else - XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y); -#endif -} - -void fl_xyline(int x, int y, int x1, int y2) { -#ifdef WIN32 - if (y2 < y) y2--; - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y); - LineTo(fl_gc, x1, y2); -#else - XPoint p[3]; - p[0].x = x; p[0].y = p[1].y = y; - p[1].x = p[2].x = x1; p[2].y = y2; - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -#endif -} - -void fl_xyline(int x, int y, int x1, int y2, int x3) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y); - LineTo(fl_gc, x1, y2); - LineTo(fl_gc, x3, y2); -#else - XPoint p[4]; - p[0].x = x; p[0].y = p[1].y = y; - p[1].x = p[2].x = x1; p[2].y = p[3].y = y2; - p[3].x = x3; - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -#endif -} - -void fl_yxline(int x, int y, int y1) { -#ifdef WIN32 - if (y1 < y) y1--; - MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1); -#else - XDrawLine(fl_display, fl_window, fl_gc, x, y, x, y1); -#endif -} - -void fl_yxline(int x, int y, int y1, int x2) { -#ifdef WIN32 - if (x2 > x) x2++; - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x, y1); - LineTo(fl_gc, x2, y1); -#else - XPoint p[3]; - p[0].x = p[1].x = x; p[0].y = y; - p[1].y = p[2].y = y1; p[2].x = x2; - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -#endif -} - -void fl_yxline(int x, int y, int y1, int x2, int y3) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x, y1); - LineTo(fl_gc, x2, y1); - LineTo(fl_gc, x2, y3); -#else - XPoint p[4]; - p[0].x = p[1].x = x; p[0].y = y; - p[1].y = p[2].y = y1; p[2].x = p[3].x = x2; - p[3].y = y3; - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -#endif -} - -void fl_line(int x, int y, int x1, int y1) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y1); -#else - XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1); -#endif -} - -void fl_line(int x, int y, int x1, int y1, int x2, int y2) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y1); - LineTo(fl_gc, x2, y2); -#else - XPoint p[3]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -#endif -} - -void fl_loop(int x, int y, int x1, int y1, int x2, int y2) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y1); - LineTo(fl_gc, x2, y2); - LineTo(fl_gc, x, y); -#else - XPoint p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x; p[3].y = y; - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -#endif -} - -void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { -#ifdef WIN32 - MoveToEx(fl_gc, x, y, 0L); - LineTo(fl_gc, x1, y1); - LineTo(fl_gc, x2, y2); - LineTo(fl_gc, x3, y3); - LineTo(fl_gc, x, y); -#else - XPoint p[5]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; - p[4].x = x; p[4].y = y; - XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); -#endif -} - -void fl_polygon(int x, int y, int x1, int y1, int x2, int y2) { - XPoint p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; -#ifdef WIN32 - SelectObject(fl_gc, fl_brush()); - Polygon(fl_gc, p, 3); -#else - p[3].x = x; p[3].y = y; - XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0); - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -#endif -} - -void fl_polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - XPoint p[5]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; -#ifdef WIN32 - SelectObject(fl_gc, fl_brush()); - Polygon(fl_gc, p, 4); -#else - p[4].x = x; p[4].y = y; - XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0); - XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); -#endif -} - -void fl_point(int x, int y) { -#ifdef WIN32 - SetPixel(fl_gc, x, y, fl_RGB()); -#else - XDrawPoint(fl_display, fl_window, fl_gc, x, y); -#endif -} - -//////////////////////////////////////////////////////////////// - -#ifdef WIN32 - -static struct rect {int notnull, x, y, r, b;} rstack[10]; -static int rstackptr; -int fl_clip_state_number; // used by gl_begin.C to update GL clip -extern char fl_direct_paint; // in Fl_win32.C - -void fl_clip(int x, int y, int w, int h) { - fl_clip_state_number++; - int r = x+w; - int b = y+h; - rect& current = rstack[rstackptr]; - if (current.notnull) { - if (current.x > x) x = current.x; - if (current.y > y) y = current.y; - if (current.r < r) r = current.r; - if (current.b < b) b = current.b; - } - rect& newrect = rstack[++rstackptr]; - newrect.notnull = 1; - newrect.x = x; - newrect.y = y; - newrect.r = r; - newrect.b = b; - if (rstackptr == 1 && fl_direct_paint) return; - HRGN R = CreateRectRgn(x,y,r,b); - SelectClipRgn(fl_gc, R); - DeleteObject(R); -} - -void fl_push_no_clip() { - fl_clip_state_number++; - if (rstack[rstackptr].notnull) SelectClipRgn(fl_gc, 0); - rstack[++rstackptr].notnull = 0; -} - -void fl_pop_clip() { - fl_clip_state_number++; - rect& r = rstack[--rstackptr]; - if (r.notnull) { - HRGN R = CreateRectRgn(r.x, r.y, r.r, r.b); - SelectClipRgn(fl_gc, R); - DeleteObject(R); - } else { - SelectClipRgn(fl_gc, 0); - } -} - -// does this rectangle intersect current clip? -int fl_not_clipped(int x, int y, int w, int h) { - rect& r = rstack[rstackptr]; - if (!r.notnull) return 2; - return (x < r.r && x+w > r.x && y < r.b && y+h > r.y); -} - -// return rectangle surrounding intersection of this rectangle and clip: -int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - rect& r = rstack[rstackptr]; - if (!r.notnull) return 0; - int R = x+w; - int B = y+h; - int ret = 0; - if (r.x > x) {X = r.x; ret = 1;} - if (r.y > y) {Y = r.y; ret = 1;} - if (r.r < R) {R = r.r; ret = 1;} - if (r.b < B) {B = r.b; ret = 1;} - if (B <= Y || R <= X) {W = H = 0; return 2;} - W = R-X; - H = B-Y; - return ret; -} - -#else - -// Missing X call: (is this the fastest way to init a 1-rectangle region?) -Region XRectangleRegion(int x, int y, int w, int h) { - XRectangle R; - R.x = x; R.y = y; R.width = w; R.height = h; - Region r = XCreateRegion(); - XUnionRectWithRegion(&R, r, r); - return r; -} - -static Region rstack[10]; -static int rstackptr; -int fl_clip_state_number; // used by gl_begin.C to update GL clip - -// undo any clobbering of clip done by your program: -void fl_restore_clip() { - fl_clip_state_number++; - Region r = rstack[rstackptr]; - if (r) XSetRegion(fl_display, fl_gc, r); - else XSetClipMask(fl_display, fl_gc, 0); -} - -// Replace the top of the clip stack: -void fl_clip_region(Region r) { - Region oldr = rstack[rstackptr]; - if (oldr) XDestroyRegion(oldr); - rstack[rstackptr] = r; - fl_restore_clip(); -} - -// Intersect & push a new clip rectangle: -void fl_clip(int x, int y, int w, int h) { - Region r; - if (w > 0 && h > 0) { - r = XRectangleRegion(x,y,w,h); - Region current = rstack[rstackptr]; - if (current) { - Region temp = XCreateRegion(); - XIntersectRegion(current, r, temp); - XDestroyRegion(r); - r = temp; - } - } else { // make empty clip region: - r = XCreateRegion(); - } - rstack[++rstackptr] = r; - fl_restore_clip(); -} - -// make there be no clip (used by fl_begin_offscreen() only!) -void fl_push_no_clip() { - rstack[++rstackptr] = 0; - fl_restore_clip(); -} - -// pop back to previous clip: -void fl_pop_clip() { - Region oldr = rstack[rstackptr--]; - if (oldr) XDestroyRegion(oldr); - fl_restore_clip(); -} - -// does this rectangle intersect current clip? -int fl_not_clipped(int x, int y, int w, int h) { - Region r = rstack[rstackptr]; - return r ? XRectInRegion(r, x, y, w, h) : 1; -} - -// return rectangle surrounding intersection of this rectangle and clip: -int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - Region r = rstack[rstackptr]; - if (!r) return 0; - switch (XRectInRegion(r, x, y, w, h)) { - case 0: // completely outside - W = H = 0; - return 2; - case 1: // completely inside: - return 0; - default: // partial: - break; - } - Region rr = XRectangleRegion(x,y,w,h); - Region temp = XCreateRegion(); - XIntersectRegion(r, rr, temp); - XRectangle rect; - XClipBox(temp, &rect); - X = rect.x; Y = rect.y; W = rect.width; H = rect.height; - XDestroyRegion(temp); - XDestroyRegion(rr); - return 1; -} - -#endif - -// end of fl_rect.C +// fl_rect.C
+
+// These routines from fl_draw.H are used by the standard boxtypes
+// and thus are always linked into an fltk program.
+
+// Also all fl_clip routines, since they are always linked in so
+// that minimal update works.
+
+#include <FL/Fl_Widget.H>
+#include <FL/fl_draw.H>
+#include <FL/x.H>
+
+void fl_rect(int x, int y, int w, int h) {
+ if (w<=0 || h<=0) return;
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x+w-1, y);
+ LineTo(fl_gc, x+w-1, y+h-1);
+ LineTo(fl_gc, x, y+h-1);
+ LineTo(fl_gc, x, y);
+#else
+ XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
+#endif
+}
+
+void fl_rectf(int x, int y, int w, int h) {
+ if (w<=0 || h<=0) return;
+#ifdef WIN32
+ RECT rect;
+ rect.left = x; rect.top = y;
+ rect.right = x + w; rect.bottom = y + h;
+ FillRect(fl_gc, &rect, fl_brush());
+#else
+ if (w && h) XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
+#endif
+}
+
+void fl_xyline(int x, int y, int x1) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y);
+#else
+ XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y);
+#endif
+}
+
+void fl_xyline(int x, int y, int x1, int y2) {
+#ifdef WIN32
+ if (y2 < y) y2--;
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y);
+ LineTo(fl_gc, x1, y2);
+#else
+ XPoint p[3];
+ p[0].x = x; p[0].y = p[1].y = y;
+ p[1].x = p[2].x = x1; p[2].y = y2;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+#endif
+}
+
+void fl_xyline(int x, int y, int x1, int y2, int x3) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y);
+ LineTo(fl_gc, x1, y2);
+ LineTo(fl_gc, x3, y2);
+#else
+ XPoint p[4];
+ p[0].x = x; p[0].y = p[1].y = y;
+ p[1].x = p[2].x = x1; p[2].y = p[3].y = y2;
+ p[3].x = x3;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+#endif
+}
+
+void fl_yxline(int x, int y, int y1) {
+#ifdef WIN32
+ if (y1 < y) y1--;
+ MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1);
+#else
+ XDrawLine(fl_display, fl_window, fl_gc, x, y, x, y1);
+#endif
+}
+
+void fl_yxline(int x, int y, int y1, int x2) {
+#ifdef WIN32
+ if (x2 > x) x2++;
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x, y1);
+ LineTo(fl_gc, x2, y1);
+#else
+ XPoint p[3];
+ p[0].x = p[1].x = x; p[0].y = y;
+ p[1].y = p[2].y = y1; p[2].x = x2;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+#endif
+}
+
+void fl_yxline(int x, int y, int y1, int x2, int y3) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x, y1);
+ LineTo(fl_gc, x2, y1);
+ LineTo(fl_gc, x2, y3);
+#else
+ XPoint p[4];
+ p[0].x = p[1].x = x; p[0].y = y;
+ p[1].y = p[2].y = y1; p[2].x = p[3].x = x2;
+ p[3].y = y3;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+#endif
+}
+
+void fl_line(int x, int y, int x1, int y1) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y1);
+#else
+ XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1);
+#endif
+}
+
+void fl_line(int x, int y, int x1, int y1, int x2, int y2) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y1);
+ LineTo(fl_gc, x2, y2);
+#else
+ XPoint p[3];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+#endif
+}
+
+void fl_loop(int x, int y, int x1, int y1, int x2, int y2) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y1);
+ LineTo(fl_gc, x2, y2);
+ LineTo(fl_gc, x, y);
+#else
+ XPoint p[4];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x; p[3].y = y;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+#endif
+}
+
+void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
+#ifdef WIN32
+ MoveToEx(fl_gc, x, y, 0L);
+ LineTo(fl_gc, x1, y1);
+ LineTo(fl_gc, x2, y2);
+ LineTo(fl_gc, x3, y3);
+ LineTo(fl_gc, x, y);
+#else
+ XPoint p[5];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x3; p[3].y = y3;
+ p[4].x = x; p[4].y = y;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
+#endif
+}
+
+void fl_polygon(int x, int y, int x1, int y1, int x2, int y2) {
+ XPoint p[4];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+#ifdef WIN32
+ SelectObject(fl_gc, fl_brush());
+ Polygon(fl_gc, p, 3);
+#else
+ p[3].x = x; p[3].y = y;
+ XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+#endif
+}
+
+void fl_polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
+ XPoint p[5];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x3; p[3].y = y3;
+#ifdef WIN32
+ SelectObject(fl_gc, fl_brush());
+ Polygon(fl_gc, p, 4);
+#else
+ p[4].x = x; p[4].y = y;
+ XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
+#endif
+}
+
+void fl_point(int x, int y) {
+#ifdef WIN32
+ SetPixel(fl_gc, x, y, fl_RGB());
+#else
+ XDrawPoint(fl_display, fl_window, fl_gc, x, y);
+#endif
+}
+
+////////////////////////////////////////////////////////////////
+
+static Region rstack[10];
+static int rstackptr;
+int fl_clip_state_number=0; // used by gl_begin.C to update GL clip
+
+#ifndef WIN32
+// Missing X call: (is this the fastest way to init a 1-rectangle region?)
+// MSWindows equivalent exists, implemented inline in win32.H
+Region XRectangleRegion(int x, int y, int w, int h) {
+ XRectangle R;
+ R.x = x; R.y = y; R.width = w; R.height = h;
+ Region r = XCreateRegion();
+ XUnionRectWithRegion(&R, r, r);
+ return r;
+}
+#endif
+
+// undo any clobbering of clip done by your program:
+void fl_restore_clip() {
+ fl_clip_state_number++;
+ Region r = rstack[rstackptr];
+#ifdef WIN32
+ SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared
+#else
+ if (r) XSetRegion(fl_display, fl_gc, r);
+ else XSetClipMask(fl_display, fl_gc, 0);
+#endif
+}
+
+// Replace the top of the clip stack:
+void fl_clip_region(Region r) {
+ Region oldr = rstack[rstackptr];
+ if (oldr) XDestroyRegion(oldr);
+ rstack[rstackptr] = r;
+ fl_restore_clip();
+}
+
+// Intersect & push a new clip rectangle:
+void fl_clip(int x, int y, int w, int h) {
+ Region r;
+ if (w > 0 && h > 0) {
+ r = XRectangleRegion(x,y,w,h);
+ Region current = rstack[rstackptr];
+ if (current) {
+#ifndef WIN32
+ Region temp = XCreateRegion();
+ XIntersectRegion(current, r, temp);
+ XDestroyRegion(r);
+ r = temp;
+#else
+ CombineRgn(r,r,current,RGN_AND);
+#endif
+ }
+ } else { // make empty clip region:
+#ifndef WIN32
+ r = XCreateRegion();
+#else
+ r = 0; //whatever, for win32 this is the same as having 0 for HRGN
+#endif
+ }
+ rstack[++rstackptr] = r;
+ fl_restore_clip();
+}
+
+// make there be no clip (used by fl_begin_offscreen() only!)
+void fl_push_no_clip() {
+ rstack[++rstackptr] = 0;
+ fl_restore_clip();
+}
+
+// pop back to previous clip:
+void fl_pop_clip() {
+ Region oldr = rstack[rstackptr--];
+ if (oldr) XDestroyRegion(oldr);
+ fl_restore_clip();
+}
+
+// does this rectangle intersect current clip?
+int fl_not_clipped(int x, int y, int w, int h) {
+ Region r = rstack[rstackptr];
+#ifndef WIN32
+ return r ? XRectInRegion(r, x, y, w, h) : 1;
+#else
+ if (!r) return 1;
+ RECT rect;
+ rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
+ return RectInRegion(r,&rect);
+#endif
+}
+
+// return rectangle surrounding intersection of this rectangle and clip:
+int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){
+ X = x; Y = y; W = w; H = h;
+ Region r = rstack[rstackptr];
+ if (!r) return 0;
+#ifndef WIN32
+ switch (XRectInRegion(r, x, y, w, h)) {
+ case 0: // completely outside
+ W = H = 0;
+ return 2;
+ case 1: // completely inside:
+ return 0;
+ default: // partial:
+ break;
+ }
+#else
+// The win32 API makes no distinction between partial and complete
+// intersection, so we have to check for partial intersection ourselves.
+ RECT rect;
+ rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
+ if (!RectInRegion(r,&rect)) {
+ W = H = 0;
+ return 2;
+ } else {
+ if (PtInRegion(r, rect.left, rect.top) &&
+ PtInRegion(r, rect.left, rect.top) &&
+ PtInRegion(r, rect.right, rect.bottom) &&
+ PtInRegion(r, rect.right, rect.bottom))
+ return 0;
+ }
+#endif
+
+#ifndef WIN32
+ Region rr = XRectangleRegion(x,y,w,h);
+ Region temp = XCreateRegion();
+ XIntersectRegion(r, rr, temp);
+ XRectangle rect;
+ XClipBox(temp, &rect);
+ X = rect.x; Y = rect.y; W = rect.width; H = rect.height;
+ XDestroyRegion(temp);
+ XDestroyRegion(rr);
+#else
+ Region rr = XRectangleRegion(x,y,w,h);
+ CombineRgn(rr, rr, r,RGN_AND);
+ GetRgnBox(rr, &rect);
+ X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y;
+ DeleteObject(rr);
+#endif
+ return 1;
+}
+
+// end of fl_rect.C
diff --git a/src/gl_start.cxx b/src/gl_start.cxx index 255a78127..7fa20dbbb 100644 --- a/src/gl_start.cxx +++ b/src/gl_start.cxx @@ -1,98 +1,98 @@ -// Code to switch current fltk drawing context in/out of GL "mode": - -// You MUST use gl_visual() to select the default visual before doing -// show() of any windows. Mesa will crash if you try to use a visual -// not returned by glxChooseVisual. - -// This does not work with Fl_Double_Window's! It will try to draw -// into the front buffer. Depending on the system this will either -// crash or do nothing (when pixmaps are being used as back buffer -// and GL is being done by hardware), work correctly (when GL is done -// with software, such as Mesa), or draw into the front buffer and -// be erased when the buffers are swapped (when double buffer hardware -// is being used) - -#include <config.h> -#if HAVE_GL - -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include <FL/x.H> -#include <FL/fl_draw.H> - -#include "Fl_Gl_Choice.H" - -extern GLXContext fl_first_context; // in Fl_Gl_Choice.C -extern int fl_clip_state_number; // in fl_rect.C - -static GLXContext context; -static int clip_state_number; -static int pw, ph; - -#ifdef WIN32 -static int default_mode; -#endif - -Region XRectangleRegion(int x, int y, int w, int h); // in fl_rect.C - -void gl_start() { -#ifdef WIN32 - HDC hdc = fl_private_dc(Fl_Window::current(), default_mode,0); - if (!context) { - context = wglCreateContext(hdc); - if (!fl_first_context) fl_first_context = context; - else wglShareLists(fl_first_context, context); - } - wglMakeCurrent(hdc, context); -#else - if (!context) { - context = glXCreateContext(fl_display, fl_visual, fl_first_context, 1); - if (!context) Fl::fatal("OpenGL does not support this visual"); - if (!fl_first_context) fl_first_context = context; - } - glXMakeCurrent(fl_display, fl_window, context); - glXWaitX(); -#endif - if (pw != Fl_Window::current()->w() || ph != Fl_Window::current()->h()) { - pw = Fl_Window::current()->w(); - ph = Fl_Window::current()->h(); - glLoadIdentity(); - glViewport(0, 0, pw, ph); - glOrtho(0, pw, 0, ph, -1, 1); - glDrawBuffer(GL_FRONT); - } - if (clip_state_number != fl_clip_state_number) { - clip_state_number = fl_clip_state_number; - int x, y, w, h; - if (fl_clip_box(0, 0, Fl_Window::current()->w(), Fl_Window::current()->h(), - x, y, w, h)) { - fl_clip_region(XRectangleRegion(x,y,w,h)); - glScissor(x, Fl_Window::current()->h()-(y+h), w, h); - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } - } -} - -void gl_finish() { -#ifdef WIN32 - glFlush(); -#else - glXWaitGL(); -#endif -} - -int Fl::gl_visual(int mode, int *alist) { -#ifdef WIN32 - default_mode = mode; -#else - Fl_Gl_Choice *c = Fl_Gl_Choice::find(mode,alist); - if (!c) return 0; - fl_visual = c->vis; - fl_colormap = c->colormap; -#endif - return 1; -} - -#endif +// Code to switch current fltk drawing context in/out of GL "mode":
+
+// You MUST use gl_visual() to select the default visual before doing
+// show() of any windows. Mesa will crash if you try to use a visual
+// not returned by glxChooseVisual.
+
+// This does not work with Fl_Double_Window's! It will try to draw
+// into the front buffer. Depending on the system this will either
+// crash or do nothing (when pixmaps are being used as back buffer
+// and GL is being done by hardware), work correctly (when GL is done
+// with software, such as Mesa), or draw into the front buffer and
+// be erased when the buffers are swapped (when double buffer hardware
+// is being used)
+
+#include <config.h>
+#if HAVE_GL
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/x.H>
+#include <FL/fl_draw.H>
+
+#include "Fl_Gl_Choice.H"
+
+extern GLXContext fl_first_context; // in Fl_Gl_Choice.C
+extern int fl_clip_state_number; // in fl_rect.C
+
+static GLXContext context;
+static int clip_state_number=-1;
+static int pw, ph;
+
+#ifdef WIN32
+static int default_mode;
+#endif
+
+Region XRectangleRegion(int x, int y, int w, int h); // in fl_rect.C
+
+void gl_start() {
+#ifdef WIN32
+ HDC hdc = fl_private_dc(Fl_Window::current(), default_mode,0);
+ if (!context) {
+ context = wglCreateContext(hdc);
+ if (!fl_first_context) fl_first_context = context;
+ else wglShareLists(fl_first_context, context);
+ }
+ wglMakeCurrent(hdc, context);
+#else
+ if (!context) {
+ context = glXCreateContext(fl_display, fl_visual, fl_first_context, 1);
+ if (!context) Fl::fatal("OpenGL does not support this visual");
+ if (!fl_first_context) fl_first_context = context;
+ }
+ glXMakeCurrent(fl_display, fl_window, context);
+ glXWaitX();
+#endif
+ if (pw != Fl_Window::current()->w() || ph != Fl_Window::current()->h()) {
+ pw = Fl_Window::current()->w();
+ ph = Fl_Window::current()->h();
+ glLoadIdentity();
+ glViewport(0, 0, pw, ph);
+ glOrtho(0, pw, 0, ph, -1, 1);
+ glDrawBuffer(GL_FRONT);
+ }
+ if (clip_state_number != fl_clip_state_number) {
+ clip_state_number = fl_clip_state_number;
+ int x, y, w, h;
+ if (fl_clip_box(0, 0, Fl_Window::current()->w(), Fl_Window::current()->h(),
+ x, y, w, h)) {
+ fl_clip_region(XRectangleRegion(x,y,w,h));
+ glScissor(x, Fl_Window::current()->h()-(y+h), w, h);
+ glEnable(GL_SCISSOR_TEST);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ }
+}
+
+void gl_finish() {
+#ifdef WIN32
+ glFlush();
+#else
+ glXWaitGL();
+#endif
+}
+
+int Fl::gl_visual(int mode, int *alist) {
+#ifdef WIN32
+ default_mode = mode;
+#else
+ Fl_Gl_Choice *c = Fl_Gl_Choice::find(mode,alist);
+ if (!c) return 0;
+ fl_visual = c->vis;
+ fl_colormap = c->colormap;
+#endif
+ return 1;
+}
+
+#endif
diff --git a/src/numericsort.c b/src/numericsort.c index 17149be6f..b0729c326 100644 --- a/src/numericsort.c +++ b/src/numericsort.c @@ -1,53 +1,56 @@ -/* My own scandir sorting function, useful for the film industry where - we have many files with numbers in their names: */ - -#include <config.h> -#include <ctype.h> -#include <stdlib.h> -#include <sys/types.h> - -#ifdef WIN32 -#include <FL/filename.H> -#else -#if HAVE_DIRENT_H -# include <dirent.h> -#else -# define dirent direct -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif -#endif - -int numericsort(const struct dirent **A, const struct dirent **B) { - const char* a = (*A)->d_name; - const char* b = (*B)->d_name; - int ret = 0; - for (;;) { - if (isdigit(*a) && isdigit(*b)) { - int zdiff,diff,magdiff; - zdiff = 0; - while (*a == '0') {a++; zdiff++;} - while (*b == '0') {b++; zdiff--;} - while (isdigit(*a) && *a == *b) {a++; b++;} - diff = (isdigit(*a) && isdigit(*b)) ? *a - *b : 0; - magdiff = 0; - while (isdigit(*a)) {magdiff++; a++;} - while (isdigit(*b)) {magdiff--; b++;} - if (ret); - else if (magdiff) ret = magdiff; - else if (diff) ret = diff; - else if (zdiff) ret = zdiff; - } else if (*a == *b) { - if (!*a) return ret; - a++; b++; - } else - return (*a-*b); - } -} +/* My own scandir sorting function, useful for the film industry where
+ we have many files with numbers in their names: */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef WIN32
+#include <FL/filename.H>
+#else
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int numericsort(const struct dirent **A, const struct dirent **B) {
+ const char* a = (*A)->d_name;
+ const char* b = (*B)->d_name;
+ int ret = 0;
+ for (;;) {
+ if (isdigit(*a) && isdigit(*b)) {
+ int zdiff,diff,magdiff;
+ zdiff = 0;
+ while (*a == '0') {a++; zdiff++;}
+ while (*b == '0') {b++; zdiff--;}
+ while (isdigit(*a) && *a == *b) {a++; b++;}
+ diff = (isdigit(*a) && isdigit(*b)) ? *a - *b : 0;
+ magdiff = 0;
+ while (isdigit(*a)) {magdiff++; a++;}
+ while (isdigit(*b)) {magdiff--; b++;}
+ if (ret);
+ else if (magdiff) ret = magdiff;
+ else if (diff) ret = diff;
+ else if (zdiff) ret = zdiff;
+ } else if (*a == *b) {
+ if (!*a) return ret;
+ a++; b++;
+ } else
+ return (*a-*b);
+ }
+}
diff --git a/src/scandir_win32.c b/src/scandir_win32.c index ea3d18723..525b289d4 100644 --- a/src/scandir_win32.c +++ b/src/scandir_win32.c @@ -1,79 +1,82 @@ -// scandir_win32.C - -// Emulation of posix scandir() call - -#include <config.h> -#include <FL/filename.H> -#include <string.h> -#include <windows.h> - -int scandir(const char *dirname, struct dirent ***namelist, - int (*select)(const struct dirent *), - int (*compar)(const struct dirent **, const struct dirent **)) { - - int len = strlen(dirname); - char *findIn = new char[len+5]; strcpy(findIn, dirname); - for (char *d = findIn; *d; d++) if (*d=='/') *d='\\'; - if ((len==0)) { strcpy(findIn, ".\\*"); } - if ((len==1)&& (d[-1]=='.')) { strcpy(findIn, ".\\*"); } - if ((len>0) && (d[-1]=='\\')) { *d++ = '*'; *d = 0; } - if ((len>1) && (d[-1]=='.') && (d[-2]=='\\')) { d[-1] = '*'; } - - WIN32_FIND_DATA find; - HANDLE h; - int nDir = 0, NDir = 0; - struct dirent **dir = 0, *selectDir; - /* - selectDir = (struct dirent*)new char[sizeof(dirent)+1]; - strcpy(selectDir->d_name, "."); - dir[0] = selectDir; - selectDir = (struct dirent*)new char[sizeof(dirent)+2]; - strcpy(selectDir->d_name, ".."); - dir[1] = selectDir; - */ - unsigned long ret; - - if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE) { - ret = GetLastError(); - if (ret != ERROR_NO_MORE_FILES) { - // TODO: return some error code - } - *namelist = dir; - return nDir; - } - do { - selectDir=(struct dirent*)new char[sizeof(dirent)+strlen(find.cFileName)]; - strcpy(selectDir->d_name, find.cFileName); - if (!select || (*select)(selectDir)) { - if (nDir==NDir) { - struct dirent **tempDir = new struct dirent*[NDir+33]; - if (NDir) memcpy(tempDir, dir, sizeof(struct dirent*)*NDir); - if (dir) delete dir; - dir = tempDir; - NDir += 32; - } - dir[nDir] = selectDir; - nDir++; - dir[nDir] = 0; - } else { - delete selectDir; - } - } while (FindNextFile(h, &find)); - ret = GetLastError(); - if (ret != ERROR_NO_MORE_FILES) { - // TODO: return some error code - } - FindClose(h); - - delete findIn; - - if (compar) qsort (dir, nDir, sizeof(*dir), - (int(*)(const void*, const void*))compar); - - *namelist = dir; - return nDir; -} - -int alphasort (const struct dirent **a, const struct dirent **b) { - return strcmp ((*a)->d_name, (*b)->d_name); -} +// scandir_win32.C
+
+// Emulation of posix scandir() call
+
+#include <config.h>
+#include <FL/filename.H>
+#include <string.h>
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int scandir(const char *dirname, struct dirent ***namelist,
+ int (*select)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **)) {
+
+ int len = strlen(dirname);
+ char *findIn = new char[len+5]; strcpy(findIn, dirname);
+ for (char *d = findIn; *d; d++) if (*d=='/') *d='\\';
+ if ((len==0)) { strcpy(findIn, ".\\*"); }
+ if ((len==1)&& (d[-1]=='.')) { strcpy(findIn, ".\\*"); }
+ if ((len>0) && (d[-1]=='\\')) { *d++ = '*'; *d = 0; }
+ if ((len>1) && (d[-1]=='.') && (d[-2]=='\\')) { d[-1] = '*'; }
+
+ WIN32_FIND_DATA find;
+ HANDLE h;
+ int nDir = 0, NDir = 0;
+ struct dirent **dir = 0, *selectDir;
+ /*
+ selectDir = (struct dirent*)new char[sizeof(dirent)+1];
+ strcpy(selectDir->d_name, ".");
+ dir[0] = selectDir;
+ selectDir = (struct dirent*)new char[sizeof(dirent)+2];
+ strcpy(selectDir->d_name, "..");
+ dir[1] = selectDir;
+ */
+ unsigned long ret;
+
+ if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ if (ret != ERROR_NO_MORE_FILES) {
+ // TODO: return some error code
+ }
+ *namelist = dir;
+ return nDir;
+ }
+ do {
+ selectDir=(struct dirent*)new char[sizeof(dirent)+strlen(find.cFileName)];
+ strcpy(selectDir->d_name, find.cFileName);
+ if (!select || (*select)(selectDir)) {
+ if (nDir==NDir) {
+ struct dirent **tempDir = new struct dirent*[NDir+33];
+ if (NDir) memcpy(tempDir, dir, sizeof(struct dirent*)*NDir);
+ if (dir) delete dir;
+ dir = tempDir;
+ NDir += 32;
+ }
+ dir[nDir] = selectDir;
+ nDir++;
+ dir[nDir] = 0;
+ } else {
+ delete selectDir;
+ }
+ } while (FindNextFile(h, &find));
+ ret = GetLastError();
+ if (ret != ERROR_NO_MORE_FILES) {
+ // TODO: return some error code
+ }
+ FindClose(h);
+
+ delete findIn;
+
+ if (compar) qsort (dir, nDir, sizeof(*dir),
+ (int(*)(const void*, const void*))compar);
+
+ *namelist = dir;
+ return nDir;
+}
+
+int alphasort (const struct dirent **a, const struct dirent **b) {
+ return strcmp ((*a)->d_name, (*b)->d_name);
+}
|
