diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:46:47 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:46:47 +0000 |
| commit | e7d805a88ca71a0e6499fe72830e58fe594ef05b (patch) | |
| tree | 8c0cd05b0f4098bba4b90b229c23ef8d96a80d8a /src/Fl_win32.cxx | |
| parent | f9039b2ae21988783feae9b362818e7923e82d14 (diff) | |
Commited Gustavo Hime's NT patches/fixes.
git-svn-id: file:///fltk/svn/fltk/trunk@7 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_win32.cxx')
| -rw-r--r-- | src/Fl_win32.cxx | 1463 |
1 files changed, 767 insertions, 696 deletions
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index d00a22531..0a7ecd3b1 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,696 +1,767 @@ -// Fl_win32.C - -// fltk (Fast Light Tool Kit) version 0.99 -// Copyright (C) 1998 Bill Spitzak - -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. - -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. - -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. - -// Written by Bill Spitzak spitzak@d2.com - -// This file contains win32-specific code for fltk which is always linked -// in. Search other files for "WIN32" or filenames ending in _win32.C -// for other system-specific code. - -#include <config.h> -#include <FL/Fl.H> -#include <FL/win32.H> -#include <FL/Fl_Window.H> -#include <string.h> - -//////////////////////////////////////////////////////////////// -// interface to poll/select call: - -// fd's are not yet implemented. -// On NT these are probably only used for network stuff, so this may -// talk to a package that Wonko has proposed writing to make the network -// interface system independent. - -#define POLLIN 1 -#define POLLOUT 4 -#define POLLERR 8 - -void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {} - -void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { - Fl::add_fd(fd,POLLIN,cb,v); -} - -void Fl::remove_fd(int n) {} - -MSG fl_msg; - -int fl_ready() { - return PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE); -} - -double fl_wait(int timeout_flag, double time) { - int have_message; - // get the first message by waiting the correct amount of time: - if (!timeout_flag) { - GetMessage(&fl_msg, NULL, 0, 0); - have_message = 1; - } else { - if (time >= 0.001) { - int timerid = SetTimer(NULL, 0, int(time*1000), NULL); - GetMessage(&fl_msg, NULL, 0, 0); - KillTimer(NULL, timerid); - have_message = 1; - } else { - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - } - } - // execute it, them execute any other messages that become ready during it: - while (have_message) { - DispatchMessage(&fl_msg); - have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); - } - return time; -} - -//////////////////////////////////////////////////////////////// - -int Fl::h() {return GetSystemMetrics(SM_CYSCREEN);} - -int Fl::w() {return GetSystemMetrics(SM_CXSCREEN);} - -void Fl::get_mouse(int &x, int &y) { - POINT p; - GetCursorPos(&p); - x = p.x; - y = p.y; -} - -//////////////////////////////////////////////////////////////// - -extern Fl_Window *fl_xfocus; // in Fl.C -extern Fl_Window *fl_xmousewin; // in Fl.C -void fl_fix_focus(); // in Fl.C - -//////////////////////////////////////////////////////////////// - -extern HWND fl_capture; - -static int mouse_event(Fl_Window *window, int what, int button, - WPARAM wParam, LPARAM lParam) -{ - static int px, py, pmx, pmy; - POINT pt; - Fl::e_x = pt.x = (signed short)LOWORD(lParam); - Fl::e_y = pt.y = (signed short)HIWORD(lParam); - ClientToScreen(fl_xid(window), &pt); - Fl::e_x_root = pt.x; - Fl::e_y_root = pt.y; - while (window->parent()) { - Fl::e_x += window->x(); - Fl::e_y += window->y(); - window = window->window(); - } - - ulong state = Fl::e_state & 0xff0000; // keep shift key states -#if 0 - // mouse event reports some shift flags, perhaps save them? - if (wParam & MK_SHIFT) state |= FL_SHIFT; - if (wParam & MK_CONTROL) state |= FL_CTRL; -#endif - if (wParam & MK_LBUTTON) state |= FL_BUTTON1; - if (wParam & MK_MBUTTON) state |= FL_BUTTON2; - if (wParam & MK_RBUTTON) state |= FL_BUTTON3; - Fl::e_state = state; - - switch (what) { - case 1: // double-click - if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} - case 0: // single-click - Fl::e_clicks = 0; - J1: - if (!fl_capture) SetCapture(fl_xid(window)); - Fl::e_keysym = FL_Button + button; - Fl::e_is_click = 1; - px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; - return Fl::handle(FL_PUSH,window); - - case 2: // release: - if (!fl_capture) ReleaseCapture(); - Fl::e_keysym = FL_Button + button; - return Fl::handle(FL_RELEASE,window); - - case 3: // move: - default: // avoid compiler warning - // MSWindows produces extra events even if mouse does not move, ignore em: - if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; - pmx = Fl::e_x_root; pmy = Fl::e_y_root; - if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; - return Fl::handle(FL_MOVE,window); - - } -} - -// convert a Micro$oft VK_x to an Fltk (X) Keysym: -// See also the inverse converter in Fl_get_key_win32.C -// This table is in numeric order by VK: -static const struct {unsigned short vk, fltk;} vktab[] = { - {VK_BACK, FL_BackSpace}, - {VK_TAB, FL_Tab}, - {VK_CLEAR, FL_KP+'5'}, - {VK_RETURN, FL_Enter}, - {VK_SHIFT, FL_Shift_L}, - {VK_CONTROL, FL_Control_L}, - {VK_MENU, FL_Alt_L}, - {VK_PAUSE, FL_Pause}, - {VK_CAPITAL, FL_Caps_Lock}, - {VK_ESCAPE, FL_Escape}, - {VK_SPACE, ' '}, - {VK_PRIOR, FL_Page_Up}, - {VK_NEXT, FL_Page_Down}, - {VK_END, FL_End}, - {VK_HOME, FL_Home}, - {VK_LEFT, FL_Left}, - {VK_UP, FL_Up}, - {VK_RIGHT, FL_Right}, - {VK_DOWN, FL_Down}, - {VK_SNAPSHOT, FL_Print}, // does not work on NT - {VK_INSERT, FL_Insert}, - {VK_DELETE, FL_Delete}, - {VK_LWIN, FL_Meta_L}, - {VK_RWIN, FL_Meta_R}, - {VK_APPS, FL_Menu}, - {VK_MULTIPLY, FL_KP+'*'}, - {VK_ADD, FL_KP+'+'}, - {VK_SUBTRACT, FL_KP+'-'}, - {VK_DECIMAL, FL_KP+'.'}, - {VK_DIVIDE, FL_KP+'/'}, - {VK_NUMLOCK, FL_Num_Lock}, - {VK_SCROLL, FL_Scroll_Lock}, - {0xba, ';'}, - {0xbb, '='}, - {0xbc, ','}, - {0xbd, '-'}, - {0xbe, '.'}, - {0xbf, '/'}, - {0xc0, '`'}, - {0xdb, '['}, - {0xdc, '\\'}, - {0xdd, ']'}, - {0xde, '\''} -}; -static int ms2fltk(int vk, int extended) { - static unsigned short vklut[256]; - if (!vklut[1]) { // init the table - int i; - for (i = 0; i < 256; i++) vklut[i] = tolower(i); - for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); - for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); - for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) - vklut[vktab[i].vk] = vktab[i].fltk; - } - if (extended) switch (vk) { - case VK_CONTROL : return FL_Control_R; - case VK_MENU: return FL_Alt_R; - case VK_RETURN: return FL_KP_Enter; - } - return vklut[vk]; -} - -char fl_direct_paint; -static HDC direct_paint_dc; - -#if USE_COLORMAP -extern HPALETTE fl_select_palette(); // in fl_color_win32.C -#endif - -static Fl_Window* resize_bug_fix; - -static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static char buffer[2]; - - fl_msg.message = uMsg; - - Fl_Window *window = fl_find(hWnd); - - STUPID_MICROSOFT: - if (window) switch (uMsg) { - - case WM_QUIT: // this should not happen? - Fl::fatal("WM_QUIT message"); - - case WM_CLOSE: // user clicked close box - Fl::handle(FL_CLOSE, window); - return 0; - - case WM_PAINT: { - // MSWindows has already set the clip region! Fltk does not like this, - // since it wants to draw it's own damage at the same time, and - // this damage may be outside the clip region. I kludge around - // this, grep for fl_direct_paint to find the kludges... - if (!window->damage()) fl_direct_paint = 1; - PAINTSTRUCT ps; - direct_paint_dc = BeginPaint(hWnd, &ps); - window->expose(2, ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right-ps.rcPaint.left, - ps.rcPaint.bottom-ps.rcPaint.top); - if (!fl_direct_paint) {EndPaint(hWnd,&ps);ReleaseDC(hWnd,direct_paint_dc);} - Fl_X::i(window)->flush(); - window->clear_damage(); - Fl_X::i(window)->region = 0; - if (fl_direct_paint) {EndPaint(hWnd, &ps); fl_direct_paint = 0;} - } break; - - case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; - case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; - case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; - case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; - case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; - case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; - case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; - case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; - case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; - case WM_MOUSEMOVE: mouse_event(window, 3, 0, wParam, lParam); return 0; - - // kludges so the pop-up menus work. Title bar still blinks, sigh... - case WM_CAPTURECHANGED: - if (fl_capture && lParam != (LPARAM)fl_capture) { - SetCapture(fl_capture); - return 0; - } - break; - case WM_ACTIVATE: - if (fl_capture && wParam && hWnd!=fl_capture) { - SetActiveWindow(fl_capture); - return 0; - } - break; - - case WM_SETFOCUS: - Fl::handle(FL_FOCUS, window); - break; - - case WM_KILLFOCUS: - Fl::handle(FL_UNFOCUS, window); - Fl::flush(); // it never returns to main loop when deactivated... - break; - - case WM_SHOWWINDOW: - if (!window->parent()) - Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); - break; - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - // save the keysym until we figure out the characters: - Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24)); - case WM_KEYUP: - case WM_SYSKEYUP: - TranslateMessage(&fl_msg); // always returns 1!!! - // TranslateMessage is supposed to return true only if it turns - // into another message, but it seems to always return 1 on my - // NT machine. So I will instead peek to see if there is a - // character message in the queue, I hope this can only happen - // if the translation worked: - if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, 1)) { - uMsg = fl_msg.message; - wParam = fl_msg.wParam; - lParam = fl_msg.lParam; - goto STUPID_MICROSOFT; - } - // otherwise use it as a 0-character key... - case WM_DEADCHAR: - case WM_SYSDEADCHAR: - buffer[0] = 0; - Fl::e_text = buffer; - Fl::e_length = 0; - goto GETSTATE; - case WM_CHAR: - case WM_SYSCHAR: - buffer[0] = char(wParam); - Fl::e_text = buffer; - Fl::e_length = 1; - GETSTATE: - {ulong state = Fl::e_state & 0xff000000; // keep the mouse button state - // if GetKeyState is expensive we might want to comment some of these out: - if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; - if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; - if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL; - // Alt gets reported for the Alt-GR switch on foreign keyboards. - // so we need to check the event as well to get it right: - if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU) - && uMsg != WM_CHAR) state |= FL_ALT; - if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; - if (GetKeyState(VK_LWIN)&~1 || GetKeyState(VK_RWIN)&~1) state |= FL_META; - if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; - Fl::e_state = state;} - if (lParam & (1<<31)) goto DEFAULT; // ignore up events after fixing shift - // for (int i = lParam&0xff; i--;) - while (window->parent()) window = window->window(); - if (Fl::handle(FL_KEYBOARD,window)) return 0; - break; - - case WM_GETMINMAXINFO: - Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); - break; - - case WM_SIZE: - if (!window->parent()) { - if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { - Fl::handle(FL_HIDE, window); - } else { - Fl::handle(FL_SHOW, window); - resize_bug_fix = window; - window->size(LOWORD(lParam), HIWORD(lParam)); - } - } - break; - - case WM_MOVE: - resize_bug_fix = window; - window->position(LOWORD(lParam), HIWORD(lParam)); - break; - - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - while (window->parent()) window = window->window(); - SetCursor(Fl_X::i(window)->cursor); - return 0; - } - break; - -#if USE_COLORMAP - case WM_QUERYNEWPALETTE : - fl_GetDC(hWnd); - if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE); - break; - - case WM_PALETTECHANGED: - fl_GetDC(hWnd); - if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc); - break; - - case WM_CREATE : - fl_GetDC(hWnd); - fl_select_palette(); - break; -#endif - - default: - DEFAULT: - if (Fl::handle(0,0)) return 0; - break; - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -//////////////////////////////////////////////////////////////// - -void Fl_Window::resize(int X,int Y,int W,int H) { - int resize_from_program = 1; - if (this == resize_bug_fix) { - resize_from_program = 0; - resize_bug_fix = 0; - } - if (X==x() && Y==y() && W==w() && H==h()) return; - if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION); - if (W != w() || H != h()) Fl_Group::resize(X,Y,W,H); else {x(X); y(Y);} - if (resize_from_program && shown()) { - if (border() && !parent()) { - X -= GetSystemMetrics(SM_CXFRAME); - Y -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - W += 2*GetSystemMetrics(SM_CXFRAME); - H += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - } - MoveWindow(i->xid, X, Y, W, H, TRUE); - //if (!parent()) redraw(); - } -} - -//////////////////////////////////////////////////////////////// - -char fl_show_iconic; // hack for Fl_Window::iconic() -// int fl_background_pixel = -1; // color to use for background -HCURSOR fl_default_cursor; -int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR - -Fl_X* Fl_X::make(Fl_Window* w) { - Fl_Group::current(0); // get rid of very common user bug: forgot end() - w->clear_damage(); // wait for expose events - - static char* class_name; - if (!class_name) { // create a single WNDCLASS used for everything: - class_name = "FLTK"; - WNDCLASSEX wc; - wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; - wc.lpfnWndProc = (WNDPROC)WndProc; - wc.cbClsExtra = wc.cbWndExtra = 0; - wc.hInstance = fl_display; - wc.hIcon = wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); - //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); - //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = class_name; - wc.cbSize = sizeof(WNDCLASSEX); - RegisterClassEx(&wc); - } - - HWND parent; - DWORD style; - DWORD styleEx; - int xp = w->x(); - int yp = w->y(); - int wp = w->w(); - int hp = w->h(); - - if (w->parent()) { - style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - parent = fl_xid(w->window()); - } else { - if (!w->size_range_set) { - if (w->resizable()) { - Fl_Widget *o = w->resizable(); - int minw = o->w(); if (minw > 100) minw = 100; - int minh = o->h(); if (minh > 100) minh = 100; - w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); - } else { - w->size_range(w->w(), w->h(), w->w(), w->h()); - } - } - if (w->border()) { - style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU - | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; - if (w->maxw != w->minw || w->maxh != w->minh) - style |= WS_THICKFRAME | WS_MAXIMIZEBOX; - if (!w->modal()) style |= WS_MINIMIZEBOX; - xp -= GetSystemMetrics(SM_CXFRAME); - yp -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - wp += 2*GetSystemMetrics(SM_CXFRAME); - hp += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION); - } else { - style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED; - styleEx = WS_EX_LEFT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - } - if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) { - xp = yp = CW_USEDEFAULT; - } - parent = 0; - if (w->non_modal() && !fl_disable_transient_for) { - // find some other window to be "transient for": - for (Fl_X* y = Fl_X::first; y; y = y->next) { - Fl_Window* w = y->w; - while (w->parent()) w = w->window(); - if (!w->non_modal()) { - parent = fl_xid(w); - break; - } - } - } - } - - Fl_X* x = new Fl_X; - x->other_xid = 0; - x->setwindow(w); - x->region = 0; - x->private_dc = 0; - x->cursor = fl_default_cursor; - x->xid = CreateWindowEx( - styleEx, - class_name, w->label(), style, - xp, yp, wp, hp, - parent, - NULL, // menu - fl_display, - NULL // creation parameters - ); - x->next = Fl_X::first; - Fl_X::first = x; - - // use w->xclass() to set the icon... - - w->set_visible(); - w->handle(FL_SHOW); // get child windows to appear - ShowWindow(x->xid, fl_show_iconic ? SW_MINIMIZE : SW_SHOW); - fl_show_iconic = 0; - fl_fix_focus(); - return x; -} - -//////////////////////////////////////////////////////////////// - -HINSTANCE fl_display; - -int Fl_WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow, - int (*mainp)(int, char**)) { - fl_display = hInstance; - - int argc; - char **argv; - // test version for now: - argc = 1; char* testargv[] = {"test", 0}; argv = testargv; - - return mainp(argc, argv); -} - -//////////////////////////////////////////////////////////////// - -void Fl_Window::size_range_() { - size_range_set = 1; -} - -void Fl_X::set_minmax(LPMINMAXINFO minmax) -{ - int wd, hd; - if (w->border()) { - wd = 2*GetSystemMetrics(SM_CXFRAME); - hd = 2*GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION); - } else { - wd = hd = 0; - } - minmax->ptMinTrackSize.x = w->minw + wd; - minmax->ptMinTrackSize.y = w->minh + hd; - if (w->maxw) { - minmax->ptMaxTrackSize.x = w->maxw + wd; - minmax->ptMaxSize.x = w->maxw + wd; - } - if (w->maxh) { - minmax->ptMaxTrackSize.y = w->maxh + hd; - minmax->ptMaxSize.y = w->maxh + hd; - } -} - -//////////////////////////////////////////////////////////////// - -// returns pointer to the filename, or null if name ends with '/' -const char *filename_name(const char *name) { - const char *p,*q; - q = name; - if (q[0] && q[1]==':') q += 2; // skip leading drive letter - for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1; - return q; -} - -void Fl_Window::label(const char *name,const char *iname) { - Fl_Widget::label(name); - iconlabel_ = iname; - if (shown() && !parent()) { - if (!name) name = ""; - SetWindowText(i->xid, name); - // if (!iname) iname = filename_name(name); - // should do something with iname here... - } -} - -//////////////////////////////////////////////////////////////// -// Implement the virtual functions for the base Fl_Window class: - -// If the box is a filled rectangle, we can make the redisplay *look* -// faster by using X's background pixel erasing. We can make it -// actually *be* faster by drawing the frame only, this is done by -// setting fl_boxcheat, which is seen by code in fl_drawbox.C: -// For WIN32 it looks like all windows share a background color, so -// I use FL_GRAY for this and only do this cheat for windows that are -// that color. -// Actually it is totally disabled. -// Fl_Widget *fl_boxcheat; -//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} - -void Fl_Window::show() { - if (!shown()) { - // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color()); - Fl_X::make(this); - } else { - ShowWindow(i->xid, SW_RESTORE); - SetActiveWindow(i->xid); - } -} - -Fl_Window *Fl_Window::current_; -HDC fl_gc; // the current context -HWND fl_window; // the current window - -// Make sure we always ReleaseDC every DC we allocate... -HDC fl_GetDC(HWND w) { - if (fl_gc) { - if (w == fl_window) return fl_gc; - ReleaseDC(fl_window, fl_gc); - } - fl_gc = fl_direct_paint ? direct_paint_dc : GetDC(w); - fl_window = w; - // calling GetDC seems to always reset these: (?) - SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT); - SetBkMode(fl_gc, TRANSPARENT); - return fl_gc; -} - -// make X drawing go into this window (called by subclass flush() impl.) -void Fl_Window::make_current() { - fl_GetDC(fl_xid(this)); - current_ = this; -} - -// WM_PAINT events and cropped damage call this: -void Fl_Window::expose(uchar flags,int X,int Y,int W,int H) { - if (i) { - if (!i->region.r) { - i->region.x = X; - i->region.y = Y; - i->region.r = X+W; - i->region.b = Y+H; - } else { - if (X < i->region.x) i->region.x = X; - if (Y < i->region.y) i->region.y = Y; - if (X+W > i->region.r) i->region.r = X+W; - if (Y+H > i->region.b) i->region.b = Y+H; - } - } - damage(flags); -} - -#include <FL/fl_draw.H> - -void Fl_Window::flush() { - make_current(); - if (damage() & ~6) { - draw(); - } else { - fl_clip_region(i->region); - draw(); - fl_pop_clip(); - } -} - -// End of Fl_win32.C // +// Fl_win32.C
+
+// fltk (Fast Light Tool Kit) version 0.99
+// Copyright (C) 1998 Bill Spitzak
+
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+
+// Written by Bill Spitzak spitzak@d2.com
+
+// This file contains win32-specific code for fltk which is always linked
+// in. Search other files for "WIN32" or filenames ending in _win32.C
+// for other system-specific code.
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/win32.H>
+#include <FL/Fl_Window.H>
+#include <string.h>
+
+////////////////////////////////////////////////////////////////
+// interface to poll/select call:
+
+// fd's are not yet implemented.
+// On NT these are probably only used for network stuff, so this may
+// talk to a package that Wonko has proposed writing to make the network
+// interface system independent.
+
+#define POLLIN 1
+#define POLLOUT 4
+#define POLLERR 8
+
+void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {}
+
+void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) {
+ Fl::add_fd(fd,POLLIN,cb,v);
+}
+
+void Fl::remove_fd(int n) {}
+
+MSG fl_msg;
+
+int fl_ready() {
+ return PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE);
+}
+
+double fl_wait(int timeout_flag, double time) {
+ int have_message;
+ // get the first message by waiting the correct amount of time:
+ if (!timeout_flag) {
+ GetMessage(&fl_msg, NULL, 0, 0);
+ have_message = 1;
+ } else {
+ if (time >= 0.001) {
+ int timerid = SetTimer(NULL, 0, int(time*1000), NULL);
+ GetMessage(&fl_msg, NULL, 0, 0);
+ KillTimer(NULL, timerid);
+ have_message = 1;
+ } else {
+ have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
+ }
+ }
+ // execute it, them execute any other messages that become ready during it:
+ while (have_message) {
+ DispatchMessage(&fl_msg);
+ have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
+ }
+ return time;
+}
+
+////////////////////////////////////////////////////////////////
+
+int Fl::h() {return GetSystemMetrics(SM_CYSCREEN);}
+
+int Fl::w() {return GetSystemMetrics(SM_CXSCREEN);}
+
+void Fl::get_mouse(int &x, int &y) {
+ POINT p;
+ GetCursorPos(&p);
+ x = p.x;
+ y = p.y;
+}
+
+////////////////////////////////////////////////////////////////
+
+extern Fl_Window *fl_xfocus; // in Fl.C
+extern Fl_Window *fl_xmousewin; // in Fl.C
+void fl_fix_focus(); // in Fl.C
+
+////////////////////////////////////////////////////////////////
+
+extern HWND fl_capture;
+
+static int mouse_event(Fl_Window *window, int what, int button,
+ WPARAM wParam, LPARAM lParam)
+{
+ static int px, py, pmx, pmy;
+ POINT pt;
+ Fl::e_x = pt.x = (signed short)LOWORD(lParam);
+ Fl::e_y = pt.y = (signed short)HIWORD(lParam);
+ ClientToScreen(fl_xid(window), &pt);
+ Fl::e_x_root = pt.x;
+ Fl::e_y_root = pt.y;
+ while (window->parent()) {
+ Fl::e_x += window->x();
+ Fl::e_y += window->y();
+ window = window->window();
+ }
+
+ ulong state = Fl::e_state & 0xff0000; // keep shift key states
+#if 0
+ // mouse event reports some shift flags, perhaps save them?
+ if (wParam & MK_SHIFT) state |= FL_SHIFT;
+ if (wParam & MK_CONTROL) state |= FL_CTRL;
+#endif
+ if (wParam & MK_LBUTTON) state |= FL_BUTTON1;
+ if (wParam & MK_MBUTTON) state |= FL_BUTTON2;
+ if (wParam & MK_RBUTTON) state |= FL_BUTTON3;
+ Fl::e_state = state;
+
+ switch (what) {
+ case 1: // double-click
+ if (Fl::e_is_click) {Fl::e_clicks++; goto J1;}
+ case 0: // single-click
+ Fl::e_clicks = 0;
+ J1:
+ if (!fl_capture) SetCapture(fl_xid(window));
+ Fl::e_keysym = FL_Button + button;
+ Fl::e_is_click = 1;
+ px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root;
+ return Fl::handle(FL_PUSH,window);
+
+ case 2: // release:
+ if (!fl_capture) ReleaseCapture();
+ Fl::e_keysym = FL_Button + button;
+ return Fl::handle(FL_RELEASE,window);
+
+ case 3: // move:
+ default: // avoid compiler warning
+ // MSWindows produces extra events even if mouse does not move, ignore em:
+ if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1;
+ pmx = Fl::e_x_root; pmy = Fl::e_y_root;
+ if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0;
+ return Fl::handle(FL_MOVE,window);
+
+ }
+}
+
+// convert a MSWindows VK_x to an Fltk (X) Keysym:
+// See also the inverse converter in Fl_get_key_win32.C
+// This table is in numeric order by VK:
+static const struct {unsigned short vk, fltk;} vktab[] = {
+ {VK_BACK, FL_BackSpace},
+ {VK_TAB, FL_Tab},
+ {VK_CLEAR, FL_KP+'5'},
+ {VK_RETURN, FL_Enter},
+ {VK_SHIFT, FL_Shift_L},
+ {VK_CONTROL, FL_Control_L},
+ {VK_MENU, FL_Alt_L},
+ {VK_PAUSE, FL_Pause},
+ {VK_CAPITAL, FL_Caps_Lock},
+ {VK_ESCAPE, FL_Escape},
+ {VK_SPACE, ' '},
+ {VK_PRIOR, FL_Page_Up},
+ {VK_NEXT, FL_Page_Down},
+ {VK_END, FL_End},
+ {VK_HOME, FL_Home},
+ {VK_LEFT, FL_Left},
+ {VK_UP, FL_Up},
+ {VK_RIGHT, FL_Right},
+ {VK_DOWN, FL_Down},
+ {VK_SNAPSHOT, FL_Print}, // does not work on NT
+ {VK_INSERT, FL_Insert},
+ {VK_DELETE, FL_Delete},
+ {VK_LWIN, FL_Meta_L},
+ {VK_RWIN, FL_Meta_R},
+ {VK_APPS, FL_Menu},
+ {VK_MULTIPLY, FL_KP+'*'},
+ {VK_ADD, FL_KP+'+'},
+ {VK_SUBTRACT, FL_KP+'-'},
+ {VK_DECIMAL, FL_KP+'.'},
+ {VK_DIVIDE, FL_KP+'/'},
+ {VK_NUMLOCK, FL_Num_Lock},
+ {VK_SCROLL, FL_Scroll_Lock},
+ {0xba, ';'},
+ {0xbb, '='},
+ {0xbc, ','},
+ {0xbd, '-'},
+ {0xbe, '.'},
+ {0xbf, '/'},
+ {0xc0, '`'},
+ {0xdb, '['},
+ {0xdc, '\\'},
+ {0xdd, ']'},
+ {0xde, '\''}
+};
+static int ms2fltk(int vk, int extended) {
+ static unsigned short vklut[256];
+ if (!vklut[1]) { // init the table
+ unsigned int i;
+ for (i = 0; i < 256; i++) vklut[i] = tolower(i);
+ for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1));
+ for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0);
+ for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++)
+ vklut[vktab[i].vk] = vktab[i].fltk;
+ }
+ if (extended) switch (vk) {
+ case VK_CONTROL : return FL_Control_R;
+ case VK_MENU: return FL_Alt_R;
+ case VK_RETURN: return FL_KP_Enter;
+ }
+ return vklut[vk];
+}
+
+#if USE_COLORMAP
+extern HPALETTE fl_select_palette(); // in fl_color_win32.C
+#endif
+
+static Fl_Window* resize_bug_fix;
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static char buffer[2];
+
+ fl_msg.message = uMsg;
+
+ Fl_Window *window = fl_find(hWnd);
+
+ STUPID_MICROSOFT:
+ if (window) switch (uMsg) {
+
+ case WM_QUIT: // this should not happen?
+ Fl::fatal("WM_QUIT message");
+
+ case WM_CLOSE: // user clicked close box
+ Fl::handle(FL_CLOSE, window);
+ return 0;
+
+ case WM_PAINT: {
+ // MSWindows has already set the clip region! Fltk does not like this,
+ // since it wants to draw it's own damage at the same time, and
+ // this damage may be outside the clip region. I kludge around
+ // this, grep for fl_direct_paint to find the kludges...
+ // if (!(window->damage())) fl_direct_paint = 1;
+ PAINTSTRUCT ps;
+
+ // I think MSWindows refuses to allocate two DCs for the same hWnd,
+ // so it may kludge the way the DCs are being handled. Works for now,
+ // the "final" solution can wait... Whatever the behaviour of the win32
+ // API, there is bound to be some small memory leak here.
+ // If anyone knows EXACTLY how DCs are allocated, please fix.
+ fl_window = hWnd;
+ fl_gc = BeginPaint(hWnd, &ps);
+ // A bug popped up because of the two following lines, which according to
+ // the original code's comments GetDC always resets. I just don't get
+ // why the problem hadn't manifested itself here earlier (well, probably
+ // because MSWindows was not allocating a new DC, but using the old one)
+ // Anyway, these followed the original GetDC calls, but for some reason
+ // were not here with the BeginPaint
+ SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
+ SetBkMode(fl_gc, TRANSPARENT);
+
+ window->expose(2, ps.rcPaint.left, ps.rcPaint.top,
+ ps.rcPaint.right-ps.rcPaint.left,
+ ps.rcPaint.bottom-ps.rcPaint.top);
+
+ Fl_X::i(window)->flush();
+ window->clear_damage();
+ //Since damage has been reset, we can dispose of the clip region
+ Region &r=Fl_X::i(window)->region;
+ if (r) {
+ DeleteObject(r);
+ r = 0;
+ }
+ EndPaint(hWnd, &ps);
+
+ fl_gc = 0;
+ fl_window = (HWND)-1;
+ } break;
+
+ case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0;
+ case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0;
+ case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0;
+ case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0;
+ case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0;
+ case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0;
+ case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0;
+ case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0;
+ case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0;
+ case WM_MOUSEMOVE: mouse_event(window, 3, 0, wParam, lParam); return 0;
+
+ // kludges so the pop-up menus work. Title bar still blinks, sigh...
+ case WM_CAPTURECHANGED:
+ if (fl_capture && lParam != (LPARAM)fl_capture) {
+ SetCapture(fl_capture);
+ return 0;
+ }
+ break;
+ case WM_ACTIVATE:
+ if (fl_capture && wParam && hWnd!=fl_capture) {
+ SetActiveWindow(fl_capture);
+ return 0;
+ }
+ break;
+
+ case WM_SETFOCUS:
+ Fl::handle(FL_FOCUS, window);
+ break;
+
+ case WM_KILLFOCUS:
+ Fl::handle(FL_UNFOCUS, window);
+ Fl::flush(); // it never returns to main loop when deactivated...
+ break;
+
+ case WM_SHOWWINDOW:
+ if (!window->parent())
+ Fl::handle(wParam ? FL_SHOW : FL_HIDE, window);
+ break;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ // save the keysym until we figure out the characters:
+ Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24));
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ TranslateMessage(&fl_msg); // always returns 1!!!
+ // TranslateMessage is supposed to return true only if it turns
+ // into another message, but it seems to always return 1 on my
+ // NT machine. So I will instead peek to see if there is a
+ // character message in the queue, I hope this can only happen
+ // if the translation worked:
+ if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, 1)) {
+ uMsg = fl_msg.message;
+ wParam = fl_msg.wParam;
+ lParam = fl_msg.lParam;
+ goto STUPID_MICROSOFT;
+ }
+ // otherwise use it as a 0-character key...
+ case WM_DEADCHAR:
+ case WM_SYSDEADCHAR:
+ buffer[0] = 0;
+ Fl::e_text = buffer;
+ Fl::e_length = 0;
+ goto GETSTATE;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ buffer[0] = char(wParam);
+ Fl::e_text = buffer;
+ Fl::e_length = 1;
+ GETSTATE:
+ {ulong state = Fl::e_state & 0xff000000; // keep the mouse button state
+ // if GetKeyState is expensive we might want to comment some of these out:
+ if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
+ if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
+ if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
+ // Alt gets reported for the Alt-GR switch on foreign keyboards.
+ // so we need to check the event as well to get it right:
+ if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU)
+ && uMsg != WM_CHAR) state |= FL_ALT;
+ if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
+ if (GetKeyState(VK_LWIN)&~1 || GetKeyState(VK_RWIN)&~1) state |= FL_META;
+ if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
+ Fl::e_state = state;}
+ if (lParam & (1<<31)) goto DEFAULT; // ignore up events after fixing shift
+ // for (int i = lParam&0xff; i--;)
+ while (window->parent()) window = window->window();
+ if (Fl::handle(FL_KEYBOARD,window)) return 0;
+ break;
+
+ case WM_GETMINMAXINFO:
+ Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
+ break;
+
+ case WM_SIZE:
+ if (!window->parent()) {
+ if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) {
+ Fl::handle(FL_HIDE, window);
+ } else {
+ Fl::handle(FL_SHOW, window);
+ resize_bug_fix = window;
+ window->size(LOWORD(lParam), HIWORD(lParam));
+ }
+ }
+ break;
+
+ case WM_MOVE:
+ resize_bug_fix = window;
+ window->position(LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) == HTCLIENT) {
+ while (window->parent()) window = window->window();
+ SetCursor(Fl_X::i(window)->cursor);
+ return 0;
+ }
+ break;
+
+#if USE_COLORMAP
+ case WM_QUERYNEWPALETTE :
+ fl_GetDC(hWnd);
+ if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE);
+ break;
+
+ case WM_PALETTECHANGED:
+ fl_GetDC(hWnd);
+ if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc);
+ break;
+
+ case WM_CREATE :
+ fl_GetDC(hWnd);
+ fl_select_palette();
+ break;
+#endif
+
+ default:
+ DEFAULT:
+ if (Fl::handle(0,0)) return 0;
+ break;
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+////////////////////////////////////////////////////////////////
+
+void Fl_Window::resize(int X,int Y,int W,int H) {
+ int resize_from_program = 1;
+ if (this == resize_bug_fix) {
+ resize_from_program = 0;
+ resize_bug_fix = 0;
+ }
+ if (X==x() && Y==y() && W==w() && H==h()) return;
+ if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION);
+ if (W != w() || H != h()) Fl_Group::resize(X,Y,W,H); else {x(X); y(Y);}
+ if (resize_from_program && shown()) {
+ if (border() && !parent()) {
+ X -= GetSystemMetrics(SM_CXFRAME);
+ Y -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ W += 2*GetSystemMetrics(SM_CXFRAME);
+ H += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ }
+ MoveWindow(i->xid, X, Y, W, H, TRUE);
+ //if (!parent()) redraw();
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+char fl_show_iconic; // hack for Fl_Window::iconic()
+// int fl_background_pixel = -1; // color to use for background
+HCURSOR fl_default_cursor;
+int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
+
+Fl_X* Fl_X::make(Fl_Window* w) {
+ Fl_Group::current(0); // get rid of very common user bug: forgot end()
+ w->clear_damage(); // wait for expose events
+
+ static char* class_name;
+ if (!class_name) { // create a single WNDCLASS used for everything:
+ class_name = "FLTK";
+ WNDCLASSEX wc;
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
+ wc.lpfnWndProc = (WNDPROC)WndProc;
+ wc.cbClsExtra = wc.cbWndExtra = 0;
+ wc.hInstance = fl_display;
+ wc.hIcon = wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
+ //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
+ //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = class_name;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ RegisterClassEx(&wc);
+ }
+
+ HWND parent;
+ DWORD style;
+ DWORD styleEx;
+ int xp = w->x();
+ int yp = w->y();
+ int wp = w->w();
+ int hp = w->h();
+
+ if (w->parent()) {
+ style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
+ parent = fl_xid(w->window());
+ } else {
+ if (!w->size_range_set) {
+ if (w->resizable()) {
+ Fl_Widget *o = w->resizable();
+ int minw = o->w(); if (minw > 100) minw = 100;
+ int minh = o->h(); if (minh > 100) minh = 100;
+ w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0);
+ } else {
+ w->size_range(w->w(), w->h(), w->w(), w->h());
+ }
+ }
+ if (w->border()) {
+ style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
+ | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ styleEx = WS_EX_LEFT | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
+ if (w->maxw != w->minw || w->maxh != w->minh)
+ style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
+ if (!w->modal()) style |= WS_MINIMIZEBOX;
+ xp -= GetSystemMetrics(SM_CXFRAME);
+ yp -= GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ wp += 2*GetSystemMetrics(SM_CXFRAME);
+ hp += 2*GetSystemMetrics(SM_CYFRAME)+GetSystemMetrics(SM_CYCAPTION);
+ } else {
+ style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED;
+ styleEx = WS_EX_LEFT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
+ }
+ if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) {
+ xp = yp = CW_USEDEFAULT;
+ }
+ parent = 0;
+ if (w->non_modal() && !fl_disable_transient_for) {
+ // find some other window to be "transient for":
+ for (Fl_X* y = Fl_X::first; y; y = y->next) {
+ Fl_Window* w = y->w;
+ while (w->parent()) w = w->window();
+ if (!w->non_modal()) {
+ parent = fl_xid(w);
+ break;
+ }
+ }
+ }
+ }
+
+ Fl_X* x = new Fl_X;
+ x->other_xid = 0;
+ x->setwindow(w);
+ x->region = 0;
+ x->private_dc = 0;
+ x->cursor = fl_default_cursor;
+ x->xid = CreateWindowEx(
+ styleEx,
+ class_name, w->label(), style,
+ xp, yp, wp, hp,
+ parent,
+ NULL, // menu
+ fl_display,
+ NULL // creation parameters
+ );
+ x->next = Fl_X::first;
+ Fl_X::first = x;
+
+ // use w->xclass() to set the icon...
+
+ w->set_visible();
+ w->handle(FL_SHOW); // get child windows to appear
+ ShowWindow(x->xid, fl_show_iconic ? SW_MINIMIZE : SW_SHOW);
+ fl_show_iconic = 0;
+ fl_fix_focus();
+ return x;
+}
+
+////////////////////////////////////////////////////////////////
+
+HINSTANCE fl_display;
+
+int Fl_WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow,
+ int (*mainp)(int, char**)) {
+ fl_display = hInstance;
+
+ int argc;
+ char **argv;
+ // test version for now:
+ argc = 1; char* testargv[] = {"test", 0}; argv = testargv;
+
+ return mainp(argc, argv);
+}
+
+////////////////////////////////////////////////////////////////
+
+void Fl_Window::size_range_() {
+ size_range_set = 1;
+}
+
+void Fl_X::set_minmax(LPMINMAXINFO minmax)
+{
+ int wd, hd;
+ if (w->border()) {
+ wd = 2*GetSystemMetrics(SM_CXFRAME);
+ hd = 2*GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
+ } else {
+ wd = hd = 0;
+ }
+ minmax->ptMinTrackSize.x = w->minw + wd;
+ minmax->ptMinTrackSize.y = w->minh + hd;
+ if (w->maxw) {
+ minmax->ptMaxTrackSize.x = w->maxw + wd;
+ minmax->ptMaxSize.x = w->maxw + wd;
+ }
+ if (w->maxh) {
+ minmax->ptMaxTrackSize.y = w->maxh + hd;
+ minmax->ptMaxSize.y = w->maxh + hd;
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+// returns pointer to the filename, or null if name ends with '/'
+const char *filename_name(const char *name) {
+ const char *p,*q;
+ q = name;
+ if (q[0] && q[1]==':') q += 2; // skip leading drive letter
+ for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1;
+ return q;
+}
+
+void Fl_Window::label(const char *name,const char *iname) {
+ Fl_Widget::label(name);
+ iconlabel_ = iname;
+ if (shown() && !parent()) {
+ if (!name) name = "";
+ SetWindowText(i->xid, name);
+ // if (!iname) iname = filename_name(name);
+ // should do something with iname here...
+ }
+}
+
+////////////////////////////////////////////////////////////////
+// Implement the virtual functions for the base Fl_Window class:
+
+// If the box is a filled rectangle, we can make the redisplay *look*
+// faster by using X's background pixel erasing. We can make it
+// actually *be* faster by drawing the frame only, this is done by
+// setting fl_boxcheat, which is seen by code in fl_drawbox.C:
+// For WIN32 it looks like all windows share a background color, so
+// I use FL_GRAY for this and only do this cheat for windows that are
+// that color.
+// Actually it is totally disabled.
+// Fl_Widget *fl_boxcheat;
+//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);}
+
+void Fl_Window::show() {
+ if (!shown()) {
+ // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color());
+ Fl_X::make(this);
+ } else {
+ ShowWindow(i->xid, SW_RESTORE);
+ SetActiveWindow(i->xid);
+ }
+}
+
+Fl_Window *Fl_Window::current_;
+HDC window_dc;
+// the current context
+HDC fl_gc = 0;
+// the current window handle, initially set to -1 so we can correctly
+// allocate fl_GetDC(0)
+HWND fl_window = (HWND)-1;
+
+// Here we ensure only one GetDC is ever in place. There is a little
+// workaround for the case of direct_paint.
+HDC fl_GetDC(HWND w) {
+ /*
+ if (fl_direct_paint) {
+ if (w == direct_paint_window) return direct_paint_dc;
+ }
+*/
+ if (fl_gc) {
+ if (w == fl_window) return fl_gc;
+ ReleaseDC(fl_window, fl_gc);
+ }
+ fl_gc = GetDC(w);
+ fl_window = w;
+ // calling GetDC seems to always reset these: (?)
+ SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
+ SetBkMode(fl_gc, TRANSPARENT);
+ return fl_gc;
+}
+
+// make X drawing go into this window (called by subclass flush() impl.)
+void Fl_Window::make_current() {
+ fl_GetDC(fl_xid(this));
+ current_ = this;
+}
+
+// WM_PAINT events and cropped damage call this:
+void Fl_Window::expose(uchar flags,int X,int Y,int W,int H) {
+ if (i) {
+ Region temp= XRectangleRegion(X,Y,W,H);
+ if (i->region) {
+ CombineRgn(temp,temp,i->region,RGN_AND);
+ DeleteObject((HGDIOBJ)i->region);
+ }
+ i->region=temp;
+ }
+ damage(flags);
+}
+
+#include <FL/fl_draw.H>
+
+void Fl_Widget::damage(uchar flags) {
+ if (type() < FL_WINDOW) {
+ damage(flags, x(), y(), w(), h());
+ } else {
+ Fl_X* i = Fl_X::i((Fl_Window*)this);
+ if (i) {
+ if (i->region) {DeleteObject((HGDIOBJ)i->region); i->region = 0;}
+ damage_ |= flags;
+ Fl::damage(1);
+ }
+ }
+}
+
+void Fl_Widget::redraw() {damage(~0);}
+
+Region XRectangleRegion(int x, int y, int w, int h); // in fl_rect.C
+
+void Fl_Widget::damage(uchar flags, int X, int Y, int W, int H) {
+ if (type() < FL_WINDOW) {
+ damage_ |= flags;
+ if (parent()) parent()->damage(1,X,Y,W,H);
+ } else {
+ // see if damage covers entire window:
+ if (X<=0 && Y<=0 && W>=w() && H>=h()) {damage(flags); return;}
+ Fl_X* i = Fl_X::i((Fl_Window*)this);
+ if (i) {
+ if (damage()) {
+ // if we already have damage we must merge with existing region:
+ if (i->region) {
+ Region r = XRectangleRegion(X,Y,W,H);
+ CombineRgn(i->region,i->region,r,RGN_OR);
+ DeleteObject(r);
+ }
+ damage_ |= flags;
+ } else {
+ // create a new region:
+ if (i->region) DeleteObject(i->region);
+ i->region = XRectangleRegion(X,Y,W,H);
+ damage_ = flags;
+ }
+ Fl::damage(1);
+ }
+ }
+}
+
+void Fl_Window::flush() {
+ make_current();
+ if (damage() & ~6) {
+ draw();
+ } else {
+ fl_clip_region(i->region);
+ draw();
+ fl_pop_clip();
+ }
+}
+
+// End of Fl_win32.C //
|
