diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl.cxx | 1135 | ||||
| -rw-r--r-- | src/Fl_Double_Window.cxx | 326 | ||||
| -rw-r--r-- | src/Fl_Gl_Window.cxx | 586 | ||||
| -rw-r--r-- | src/Fl_visual.cxx | 158 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 1534 | ||||
| -rw-r--r-- | src/Fl_x.cxx | 2 | ||||
| -rw-r--r-- | src/fl_font_win32.cxx | 318 | ||||
| -rw-r--r-- | src/fl_rect.cxx | 702 | ||||
| -rw-r--r-- | src/gl_start.cxx | 196 | ||||
| -rw-r--r-- | src/numericsort.c | 112 | ||||
| -rw-r--r-- | src/scandir_win32.c | 164 |
11 files changed, 2619 insertions, 2614 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx index 17973ded6..d16c27973 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,565 +1,570 @@ -// 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 //
+// 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_) { + Fl::e_x += mouse_dx; + Fl::e_y += mouse_dy; + w = Fl::pushed_; + Fl::pushed_ = 0; // must be zero before callback is done! + } + 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 864ba1019..036c7ab10 100644 --- a/src/Fl_Double_Window.cxx +++ b/src/Fl_Double_Window.cxx @@ -1,163 +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
-
-// 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();
-}
+// 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 0879e734e..8778d0b4f 100644 --- a/src/Fl_Gl_Window.cxx +++ b/src/Fl_Gl_Window.cxx @@ -1,293 +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
-
-////////////////////////////////////////////////////////////////
-
-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
+// 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 05d90edd1..76df209b4 100644 --- a/src/Fl_visual.cxx +++ b/src/Fl_visual.cxx @@ -1,79 +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) {
- 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
+// 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 0a7ecd3b1..d27c2c2cc 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,767 +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 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 //
+// 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_x.cxx b/src/Fl_x.cxx index 2d5a5ab46..ef0bb386d 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -389,7 +389,7 @@ int fl_handle(const XEvent& xevent) } // ignore all effects of shift on the keysyms (makes it a lot // easier to program shortcuts!) - keysym = XKeycodeToKeysym(fl_display, i, 0); + if (keysym < 0x400) keysym = XKeycodeToKeysym(fl_display, i, 0); #ifdef __sgi // get some missing PC keyboard keys: if (!keysym) switch(i) { diff --git a/src/fl_font_win32.cxx b/src/fl_font_win32.cxx index 99283a433..f82f710fe 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_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 1ea826c6f..f047bb824 100644 --- a/src/fl_rect.cxx +++ b/src/fl_rect.cxx @@ -1,351 +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
-}
-
-////////////////////////////////////////////////////////////////
-
-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
+// 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 7fa20dbbb..152c2310c 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=-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
+// 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 b0729c326..0df0815d6 100644 --- a/src/numericsort.c +++ b/src/numericsort.c @@ -1,56 +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
-
-#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);
- }
-}
+/* 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 525b289d4..cbb4b536b 100644 --- a/src/scandir_win32.c +++ b/src/scandir_win32.c @@ -1,82 +1,82 @@ -// 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);
-}
+// 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); +} |
