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