From e7d805a88ca71a0e6499fe72830e58fe594ef05b Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Tue, 6 Oct 1998 18:46:47 +0000 Subject: Commited Gustavo Hime's NT patches/fixes. git-svn-id: file:///fltk/svn/fltk/trunk@7 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- src/Fl_win32.cxx | 1463 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 767 insertions(+), 696 deletions(-) (limited to 'src/Fl_win32.cxx') 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 // -- cgit v1.2.3