|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_win32.cxx 8205 2011-01-07 01:12:04Z matt $" 00003 // 00004 // WIN32-specific code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 // This file contains win32-specific code for fltk which is always linked 00029 // in. Search other files for "WIN32" or filenames ending in _win32.cxx 00030 // for other system-specific code. 00031 00032 // This file must be #include'd in Fl.cxx and not compiled separately. 00033 00034 #ifndef FL_DOXYGEN 00035 #include <FL/Fl.H> 00036 #include <FL/fl_utf8.h> 00037 #include <FL/Fl_Window.H> 00038 #include <FL/fl_draw.H> 00039 #include <FL/Enumerations.H> 00040 #include <FL/Fl_Tooltip.H> 00041 #include "flstring.h" 00042 #include "Fl_Font.H" 00043 #include <stdio.h> 00044 #include <stdlib.h> 00045 #include <sys/types.h> 00046 #include <time.h> 00047 #ifdef __CYGWIN__ 00048 # include <sys/time.h> 00049 # include <unistd.h> 00050 #endif 00051 00052 #if !defined(NO_TRACK_MOUSE) 00053 #include <commctrl.h> // TrackMouseEvent 00054 #endif 00055 00056 #if defined(__GNUC__) 00057 # include <wchar.h> 00058 #endif 00059 00060 #include <ole2.h> 00061 #include <shellapi.h> 00062 00063 #include "aimm.h" 00064 00065 // 00066 // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... 00067 // USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons: 00068 /* 00069 This feature was supposed to provide an efficient alternative to the current 00070 polling method, but as it has been discussed (Thanks Albrecht!) : 00071 - the async mode would imply to change the socket to non blocking mode. 00072 This can have unexpected side effects for 3rd party apps, especially 00073 if it is set on-the-fly when socket service is really needed, as it is 00074 done today and on purpose, but still the 3rd party developer wouldn't easily 00075 control the sequencing of socket operations. 00076 - Finer granularity of events furthered by the async select is a plus only 00077 for socket 3rd party impl., it is simply not needed for the 'light' fltk 00078 use we make of wsock, so here it would also be a bad point, because of all 00079 the logic add-ons necessary for using this functionality, without a clear 00080 benefit. 00081 00082 So async mode select would not add benefits to fltk, worse, it can slowdown 00083 fltk because of this finer granularity and instrumentation code to be added 00084 for async mode proper operation, not mentioning the side effects... 00085 */ 00086 00087 static Fl_GDI_Graphics_Driver fl_gdi_driver; 00088 static Fl_Display_Device fl_gdi_display(&fl_gdi_driver); 00089 FL_EXPORT Fl_Display_Device *fl_display_device = (Fl_Display_Device*)&fl_gdi_display; // does not change 00090 FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver = (Fl_Graphics_Driver*)&fl_gdi_driver; // the current target driver of graphics operations 00091 FL_EXPORT Fl_Surface_Device *fl_surface = (Fl_Surface_Device*)fl_display_device; // the current target surface of graphics operations 00092 00093 // dynamic wsock dll handling api: 00094 #if defined(__CYGWIN__) && !defined(SOCKET) 00095 # define SOCKET int 00096 #endif 00097 00098 // note: winsock2.h has been #include'd in Fl.cxx 00099 #define WSCK_DLL_NAME "WS2_32.DLL" 00100 00101 typedef int (WINAPI* fl_wsk_select_f)(int, fd_set*, fd_set*, fd_set*, const struct timeval*); 00102 typedef int (WINAPI* fl_wsk_fd_is_set_f)(SOCKET, fd_set *); 00103 00104 static HMODULE s_wsock_mod = 0; 00105 static fl_wsk_select_f s_wsock_select = 0; 00106 static fl_wsk_fd_is_set_f fl_wsk_fd_is_set = 0; 00107 00108 static HMODULE get_wsock_mod() { 00109 if (!s_wsock_mod) { 00110 s_wsock_mod = LoadLibrary(WSCK_DLL_NAME); 00111 if (s_wsock_mod==NULL) 00112 Fl::fatal("FLTK Lib Error: %s file not found! Please check your winsock dll accessibility.\n",WSCK_DLL_NAME); 00113 s_wsock_select = (fl_wsk_select_f) GetProcAddress(s_wsock_mod, "select"); 00114 fl_wsk_fd_is_set = (fl_wsk_fd_is_set_f) GetProcAddress(s_wsock_mod, "__WSAFDIsSet"); 00115 } 00116 return s_wsock_mod; 00117 } 00118 00119 /* 00120 * Dynamic linking of imm32.dll 00121 * This library is only needed for a hand full (four ATM) functions relating to 00122 * international text rendering and locales. Dynamically loading reduces initial 00123 * size and link dependencies. 00124 */ 00125 static HMODULE s_imm_module = 0; 00126 typedef HIMC (WINAPI* flTypeImmGetContext)(HWND); 00127 static flTypeImmGetContext flImmGetContext = 0; 00128 typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); 00129 static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0; 00130 typedef BOOL (WINAPI* flTypeImmReleaseContext)(HWND, HIMC); 00131 static flTypeImmReleaseContext flImmReleaseContext = 0; 00132 typedef BOOL (WINAPI* flTypeImmIsIME)(HKL); 00133 static flTypeImmIsIME flImmIsIME = 0; 00134 00135 static HMODULE get_imm_module() { 00136 if (!s_imm_module) { 00137 s_imm_module = LoadLibrary("IMM32.DLL"); 00138 if (!s_imm_module) 00139 Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" 00140 "Please check your input method manager library accessibility."); 00141 flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); 00142 flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); 00143 flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); 00144 flImmIsIME = (flTypeImmIsIME)GetProcAddress(s_imm_module, "ImmIsIME"); 00145 } 00146 return s_imm_module; 00147 } 00148 00149 // USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have 00150 // TrackMouseEvent()... 00151 // 00152 // Now (Dec. 2008) we can assume that current Cygwin/MinGW versions 00153 // support the TrackMouseEvent() function, but WinCE obviously doesn't 00154 // support it (STR 2095). Therefore, USE_TRACK_MOUSE is enabled by 00155 // default, but you can disable it by defining NO_TRACK_MOUSE. 00156 // 00157 // TrackMouseEvent is only used to support window leave notifications 00158 // under Windows. It can be used to get FL_LEAVE events, when the 00159 // mouse leaves the _main_ application window (FLTK detects subwindow 00160 // leave events by using normal move events). 00161 // 00162 // Implementation note: If the mouse cursor leaves one subwindow and 00163 // enters another window, then Windows sends a WM_MOUSEMOVE message to 00164 // the new window before it sends a WM_MOUSELEAVE message to the old 00165 // (just left) window. We save the current mouse window in a static variable, 00166 // and if we get a WM_MOUSELEAVE event for the current mouse window, this 00167 // means that the top level window has been left (otherwise we would have 00168 // got another WM_MOUSEMOVE message before). 00169 00170 // #define NO_TRACK_MOUSE 00171 00172 #if !defined(NO_TRACK_MOUSE) 00173 # define USE_TRACK_MOUSE 00174 #endif // NO_TRACK_MOUSE 00175 00176 static Fl_Window *track_mouse_win=0; // current TrackMouseEvent() window 00177 00178 // USE_CAPTURE_MOUSE_WIN - this must be defined for TrackMouseEvent to work 00179 // correctly with subwindows - otherwise a single mouse click and release 00180 // (without a move) would generate phantom leave events. 00181 // This defines, if the current mouse window (maybe a subwindow) or the 00182 // main window should get mouse events after pushing (and holding) a mouse 00183 // button, i.e. when dragging the mouse. This is done by calling SetCapture 00184 // (see below). 00185 00186 #ifdef USE_TRACK_MOUSE 00187 #define USE_CAPTURE_MOUSE_WIN 00188 #endif // USE_TRACK_MOUSE 00189 00190 // 00191 // WM_SYNCPAINT is an "undocumented" message, which is finally defined in 00192 // VC++ 6.0. 00193 // 00194 00195 #ifndef WM_SYNCPAINT 00196 # define WM_SYNCPAINT 0x0088 00197 #endif 00198 00199 #ifndef WM_MOUSELEAVE 00200 # define WM_MOUSELEAVE 0x02a3 00201 #endif 00202 00203 #ifndef WM_MOUSEWHEEL 00204 # define WM_MOUSEWHEEL 0x020a 00205 #endif 00206 00207 #ifndef WHEEL_DELTA 00208 # define WHEEL_DELTA 120 // according to MSDN. 00209 #endif 00210 00211 00212 // 00213 // WM_FLSELECT is the user-defined message that we get when one of 00214 // the sockets has pending data, etc. 00215 // 00216 00217 #define WM_FLSELECT (WM_APP+1) // WM_APP is used for hide-window 00218 00219 00221 // interface to poll/select call: 00222 00223 // fd's are only implemented for sockets. Microsoft Windows does not 00224 // have a unified IO system, so it doesn't support select() on files, 00225 // devices, or pipes... 00226 // 00227 // Microsoft provides the Berkeley select() call and an asynchronous 00228 // select function that sends a WIN32 message when the select condition 00229 // exists. However, we don't try to use the asynchronous WSAAsyncSelect() 00230 // any more for good reasons (see above). 00231 // 00232 // A.S. Dec 2009: We got reports that current winsock2.h files define 00233 // POLLIN, POLLOUT, and POLLERR with conflicting values WRT what we 00234 // used before (STR #2301). Therefore we must not use these values 00235 // for our internal purposes, but use FL_READ, FL_WRITE, and 00236 // FL_EXCEPT, as defined for use in Fl::add_fd(). 00237 // 00238 static int maxfd = 0; 00239 static fd_set fdsets[3]; 00240 00241 extern IDropTarget *flIDropTarget; 00242 00243 static int nfds = 0; 00244 static int fd_array_size = 0; 00245 static struct FD { 00246 int fd; 00247 short events; 00248 void (*cb)(int, void*); 00249 void* arg; 00250 } *fd = 0; 00251 00252 extern unsigned int fl_codepage; 00253 00254 void fl_reset_spot() 00255 { 00256 } 00257 00258 void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win) 00259 { 00260 if (!win) return; 00261 Fl_Window* tw = win; 00262 while (tw->parent()) tw = tw->window(); // find top level window 00263 00264 get_imm_module(); 00265 HIMC himc = flImmGetContext(fl_xid(tw)); 00266 00267 if (himc) { 00268 COMPOSITIONFORM cfs; 00269 cfs.dwStyle = CFS_POINT; 00270 cfs.ptCurrentPos.x = X; 00271 cfs.ptCurrentPos.y = Y - tw->labelsize(); 00272 MapWindowPoints(fl_xid(win), fl_xid(tw), &cfs.ptCurrentPos, 1); 00273 flImmSetCompositionWindow(himc, &cfs); 00274 flImmReleaseContext(fl_xid(tw), himc); 00275 } 00276 } 00277 00278 void fl_set_status(int x, int y, int w, int h) 00279 { 00280 } 00281 00282 void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { 00283 remove_fd(n,events); 00284 int i = nfds++; 00285 if (i >= fd_array_size) { 00286 fd_array_size = 2*fd_array_size+1; 00287 fd = (FD*)realloc(fd, fd_array_size*sizeof(FD)); 00288 } 00289 fd[i].fd = n; 00290 fd[i].events = (short)events; 00291 fd[i].cb = cb; 00292 fd[i].arg = v; 00293 00294 if (events & FL_READ) FD_SET((unsigned)n, &fdsets[0]); 00295 if (events & FL_WRITE) FD_SET((unsigned)n, &fdsets[1]); 00296 if (events & FL_EXCEPT) FD_SET((unsigned)n, &fdsets[2]); 00297 if (n > maxfd) maxfd = n; 00298 } 00299 00300 void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { 00301 Fl::add_fd(fd, FL_READ, cb, v); 00302 } 00303 00304 void Fl::remove_fd(int n, int events) { 00305 int i,j; 00306 for (i=j=0; i<nfds; i++) { 00307 if (fd[i].fd == n) { 00308 short e = fd[i].events & ~events; 00309 if (!e) continue; // if no events left, delete this fd 00310 fd[i].events = e; 00311 } 00312 // move it down in the array if necessary: 00313 if (j<i) { 00314 fd[j]=fd[i]; 00315 } 00316 j++; 00317 } 00318 nfds = j; 00319 00320 if (events & FL_READ) FD_CLR(unsigned(n), &fdsets[0]); 00321 if (events & FL_WRITE) FD_CLR(unsigned(n), &fdsets[1]); 00322 if (events & FL_EXCEPT) FD_CLR(unsigned(n), &fdsets[2]); 00323 } 00324 00325 void Fl::remove_fd(int n) { 00326 remove_fd(n, -1); 00327 } 00328 00329 // these pointers are set by the Fl::lock() function: 00330 static void nothing() {} 00331 void (*fl_lock_function)() = nothing; 00332 void (*fl_unlock_function)() = nothing; 00333 00334 static void* thread_message_; 00335 void* Fl::thread_message() { 00336 void* r = thread_message_; 00337 thread_message_ = 0; 00338 return r; 00339 } 00340 00341 IActiveIMMApp *fl_aimm = NULL; 00342 MSG fl_msg; 00343 00344 // This is never called with time_to_wait < 0.0. 00345 // It *should* return negative on error, 0 if nothing happens before 00346 // timeout, and >0 if any callbacks were done. This version only 00347 // returns zero if nothing happens during a 0.0 timeout, otherwise 00348 // it returns 1. 00349 int fl_wait(double time_to_wait) { 00350 int have_message = 0; 00351 00352 run_checks(); 00353 00354 // idle processing 00355 static char in_idle; 00356 if (Fl::idle && !in_idle) { 00357 in_idle = 1; 00358 Fl::idle(); 00359 in_idle = 0; 00360 } 00361 00362 if (nfds) { 00363 // For WIN32 we need to poll for socket input FIRST, since 00364 // the event queue is not something we can select() on... 00365 timeval t; 00366 t.tv_sec = 0; 00367 t.tv_usec = 0; 00368 00369 fd_set fdt[3]; 00370 memcpy(fdt, fdsets, sizeof fdt); // one shot faster fdt init 00371 if (get_wsock_mod()&& s_wsock_select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) { 00372 // We got something - do the callback! 00373 for (int i = 0; i < nfds; i ++) { 00374 SOCKET f = fd[i].fd; 00375 short revents = 0; 00376 if (fl_wsk_fd_is_set(f, &fdt[0])) revents |= FL_READ; 00377 if (fl_wsk_fd_is_set(f, &fdt[1])) revents |= FL_WRITE; 00378 if (fl_wsk_fd_is_set(f, &fdt[2])) revents |= FL_EXCEPT; 00379 if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); 00380 } 00381 time_to_wait = 0.0; // just peek for any messages 00382 } else { 00383 // we need to check them periodically, so set a short timeout: 00384 if (time_to_wait > .001) time_to_wait = .001; 00385 } 00386 } 00387 00388 if (Fl::idle || Fl::damage()) 00389 time_to_wait = 0.0; 00390 00391 // if there are no more windows and this timer is set 00392 // to FOREVER, continue through or look up indefinitely 00393 if (!Fl::first_window() && time_to_wait==1e20) 00394 time_to_wait = 0.0; 00395 00396 fl_unlock_function(); 00397 00398 time_to_wait = (time_to_wait > 10000 ? 10000 : time_to_wait); 00399 int t_msec = (int) (time_to_wait * 1000.0 + 0.5); 00400 MsgWaitForMultipleObjects(0, NULL, FALSE, t_msec, QS_ALLINPUT); 00401 00402 fl_lock_function(); 00403 00404 // Execute the message we got, and all other pending messages: 00405 // have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); 00406 have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); 00407 if (have_message > 0) { 00408 while (have_message != 0 && have_message != -1) { 00409 if (fl_msg.message == fl_wake_msg) { 00410 // Used for awaking wait() from another thread 00411 thread_message_ = (void*)fl_msg.wParam; 00412 Fl_Awake_Handler func; 00413 void *data; 00414 while (Fl::get_awake_handler_(func, data)==0) { 00415 func(data); 00416 } 00417 } 00418 00419 TranslateMessage(&fl_msg); 00420 DispatchMessageW(&fl_msg); 00421 have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); 00422 } 00423 } 00424 Fl::flush(); 00425 00426 // This should return 0 if only timer events were handled: 00427 return 1; 00428 } 00429 00430 // fl_ready() is just like fl_wait(0.0) except no callbacks are done: 00431 int fl_ready() { 00432 if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; 00433 if (!nfds) return 0; 00434 timeval t; 00435 t.tv_sec = 0; 00436 t.tv_usec = 0; 00437 fd_set fdt[3]; 00438 memcpy(fdt, fdsets, sizeof fdt); 00439 return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0; 00440 } 00441 00443 00444 int Fl::x() 00445 { 00446 RECT r; 00447 00448 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); 00449 return r.left; 00450 } 00451 00452 int Fl::y() 00453 { 00454 RECT r; 00455 00456 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); 00457 return r.top; 00458 } 00459 00460 int Fl::h() 00461 { 00462 RECT r; 00463 00464 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); 00465 return r.bottom - r.top; 00466 } 00467 00468 int Fl::w() 00469 { 00470 RECT r; 00471 00472 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); 00473 return r.right - r.left; 00474 } 00475 00476 void Fl::get_mouse(int &x, int &y) { 00477 POINT p; 00478 GetCursorPos(&p); 00479 x = p.x; 00480 y = p.y; 00481 } 00482 00484 // code used for selections: 00485 00486 char *fl_selection_buffer[2]; 00487 int fl_selection_length[2]; 00488 int fl_selection_buffer_length[2]; 00489 char fl_i_own_selection[2]; 00490 00491 UINT fl_get_lcid_codepage(LCID id) 00492 { 00493 char buf[8]; 00494 buf[GetLocaleInfo(id, LOCALE_IDEFAULTANSICODEPAGE, buf, 8)] = 0; 00495 return atol(buf); 00496 } 00497 00498 // Convert \n -> \r\n 00499 class Lf2CrlfConvert { 00500 char *out; 00501 int outlen; 00502 public: 00503 Lf2CrlfConvert(const char *in, int inlen) { 00504 outlen = 0; 00505 const char *i; 00506 char *o; 00507 int lencount; 00508 // Predict size of \r\n conversion buffer 00509 for ( i=in, lencount = inlen; lencount--; ) { 00510 if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated 00511 { i+=2; outlen+=2; } 00512 else if ( *i == '\n' ) // \n by itself? leave room to insert \r 00513 { i++; outlen+=2; } 00514 else 00515 { ++i; ++outlen; } 00516 } 00517 // Alloc conversion buffer + NULL 00518 out = new char[outlen+1]; 00519 // Handle \n -> \r\n conversion 00520 for ( i=in, o=out, lencount = inlen; lencount--; ) { 00521 if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated 00522 { *o++ = *i++; *o++ = *i++; } 00523 else if ( *i == '\n' ) // \n by itself? insert \r 00524 { *o++ = '\r'; *o++ = *i++; } 00525 else 00526 { *o++ = *i++; } 00527 } 00528 *o++ = 0; 00529 } 00530 ~Lf2CrlfConvert() { 00531 delete[] out; 00532 } 00533 int GetLength() const { return(outlen); } 00534 const char* GetValue() const { return(out); } 00535 }; 00536 00537 // call this when you create a selection: 00538 void Fl::copy(const char *stuff, int len, int clipboard) { 00539 if (!stuff || len<0) return; 00540 00541 // Convert \n -> \r\n (for old apps like Notepad, DOS) 00542 Lf2CrlfConvert buf(stuff, len); 00543 len = buf.GetLength(); 00544 stuff = buf.GetValue(); 00545 00546 if (len+1 > fl_selection_buffer_length[clipboard]) { 00547 delete[] fl_selection_buffer[clipboard]; 00548 fl_selection_buffer[clipboard] = new char[len+100]; 00549 fl_selection_buffer_length[clipboard] = len+100; 00550 } 00551 memcpy(fl_selection_buffer[clipboard], stuff, len); 00552 fl_selection_buffer[clipboard][len] = 0; // needed for direct paste 00553 fl_selection_length[clipboard] = len; 00554 if (clipboard) { 00555 // set up for "delayed rendering": 00556 if (OpenClipboard(NULL)) { 00557 // if the system clipboard works, use it 00558 int utf16_len = fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], 0, 0); 00559 EmptyClipboard(); 00560 HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc. 00561 LPVOID memLock = GlobalLock(hMem); 00562 fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], (unsigned short*) memLock, utf16_len + 1); 00563 GlobalUnlock(hMem); 00564 SetClipboardData(CF_UNICODETEXT, hMem); 00565 CloseClipboard(); 00566 GlobalFree(hMem); 00567 fl_i_own_selection[clipboard] = 0; 00568 } else { 00569 // only if it fails, instruct paste() to use the internal buffers 00570 fl_i_own_selection[clipboard] = 1; 00571 } 00572 } 00573 } 00574 00575 // Call this when a "paste" operation happens: 00576 void Fl::paste(Fl_Widget &receiver, int clipboard) { 00577 if (!clipboard || fl_i_own_selection[clipboard]) { 00578 // We already have it, do it quickly without window server. 00579 // Notice that the text is clobbered if set_selection is 00580 // called in response to FL_PASTE! 00581 00582 // Convert \r\n -> \n 00583 char *i = fl_selection_buffer[clipboard]; 00584 if (i==0L) { 00585 Fl::e_text = 0; 00586 return; 00587 } 00588 Fl::e_text = new char[fl_selection_length[clipboard]+1]; 00589 char *o = Fl::e_text; 00590 while (*i) { 00591 if ( *i == '\r' && *(i+1) == '\n') i++; 00592 else *o++ = *i++; 00593 } 00594 *o = 0; 00595 Fl::e_length = o - Fl::e_text; 00596 receiver.handle(FL_PASTE); 00597 delete [] Fl::e_text; 00598 Fl::e_text = 0; 00599 } else { 00600 if (!OpenClipboard(NULL)) return; 00601 HANDLE h = GetClipboardData(CF_UNICODETEXT); 00602 if (h) { 00603 wchar_t *memLock = (wchar_t*) GlobalLock(h); 00604 int utf16_len = wcslen(memLock); 00605 Fl::e_text = (char*) malloc (utf16_len * 4 + 1); 00606 int utf8_len = fl_utf8fromwc(Fl::e_text, utf16_len * 4, memLock, utf16_len); 00607 *(Fl::e_text + utf8_len) = 0; 00608 LPSTR a,b; 00609 a = b = Fl::e_text; 00610 while (*a) { // strip the CRLF pairs ($%$#@^) 00611 if (*a == '\r' && a[1] == '\n') a++; 00612 else *b++ = *a++; 00613 } 00614 *b = 0; 00615 Fl::e_length = b - Fl::e_text; 00616 receiver.handle(FL_PASTE); 00617 GlobalUnlock(h); 00618 free(Fl::e_text); 00619 Fl::e_text = 0; 00620 } 00621 CloseClipboard(); 00622 } 00623 } 00624 00626 char fl_is_ime = 0; 00627 void fl_get_codepage() 00628 { 00629 HKL hkl = GetKeyboardLayout(0); 00630 TCHAR ld[8]; 00631 00632 GetLocaleInfo (LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6); 00633 DWORD ccp = atol(ld); 00634 fl_is_ime = 0; 00635 00636 fl_codepage = ccp; 00637 if (fl_aimm) { 00638 fl_aimm->GetCodePageA(GetKeyboardLayout(0), &fl_codepage); 00639 } else if (get_imm_module() && flImmIsIME(hkl)) { 00640 fl_is_ime = 1; 00641 } 00642 } 00643 00644 HWND fl_capture; 00645 00646 static int mouse_event(Fl_Window *window, int what, int button, 00647 WPARAM wParam, LPARAM lParam) 00648 { 00649 static int px, py, pmx, pmy; 00650 POINT pt; 00651 Fl::e_x = pt.x = (signed short)LOWORD(lParam); 00652 Fl::e_y = pt.y = (signed short)HIWORD(lParam); 00653 ClientToScreen(fl_xid(window), &pt); 00654 Fl::e_x_root = pt.x; 00655 Fl::e_y_root = pt.y; 00656 #ifdef USE_CAPTURE_MOUSE_WIN 00657 Fl_Window *mouse_window = window; // save "mouse window" 00658 #endif 00659 while (window->parent()) { 00660 Fl::e_x += window->x(); 00661 Fl::e_y += window->y(); 00662 window = window->window(); 00663 } 00664 00665 ulong state = Fl::e_state & 0xff0000; // keep shift key states 00666 #if 0 00667 // mouse event reports some shift flags, perhaps save them? 00668 if (wParam & MK_SHIFT) state |= FL_SHIFT; 00669 if (wParam & MK_CONTROL) state |= FL_CTRL; 00670 #endif 00671 if (wParam & MK_LBUTTON) state |= FL_BUTTON1; 00672 if (wParam & MK_MBUTTON) state |= FL_BUTTON2; 00673 if (wParam & MK_RBUTTON) state |= FL_BUTTON3; 00674 Fl::e_state = state; 00675 00676 switch (what) { 00677 case 1: // double-click 00678 if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} 00679 case 0: // single-click 00680 Fl::e_clicks = 0; 00681 J1: 00682 #ifdef USE_CAPTURE_MOUSE_WIN 00683 if (!fl_capture) SetCapture(fl_xid(mouse_window)); // use mouse window 00684 #else 00685 if (!fl_capture) SetCapture(fl_xid(window)); // use main window 00686 #endif 00687 Fl::e_keysym = FL_Button + button; 00688 Fl::e_is_click = 1; 00689 px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; 00690 return Fl::handle(FL_PUSH,window); 00691 00692 case 2: // release: 00693 if (!fl_capture) ReleaseCapture(); 00694 Fl::e_keysym = FL_Button + button; 00695 return Fl::handle(FL_RELEASE,window); 00696 00697 case 3: // move: 00698 default: // avoid compiler warning 00699 // MSWindows produces extra events even if mouse does not move, ignore em: 00700 if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; 00701 pmx = Fl::e_x_root; pmy = Fl::e_y_root; 00702 if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; 00703 return Fl::handle(FL_MOVE,window); 00704 00705 } 00706 } 00707 00708 // convert a MSWindows VK_x to an Fltk (X) Keysym: 00709 // See also the inverse converter in Fl_get_key_win32.cxx 00710 // This table is in numeric order by VK: 00711 static const struct {unsigned short vk, fltk, extended;} vktab[] = { 00712 {VK_BACK, FL_BackSpace}, 00713 {VK_TAB, FL_Tab}, 00714 {VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/}, 00715 {VK_RETURN, FL_Enter, FL_KP_Enter}, 00716 {VK_SHIFT, FL_Shift_L, FL_Shift_R}, 00717 {VK_CONTROL, FL_Control_L, FL_Control_R}, 00718 {VK_MENU, FL_Alt_L, FL_Alt_R}, 00719 {VK_PAUSE, FL_Pause}, 00720 {VK_CAPITAL, FL_Caps_Lock}, 00721 {VK_ESCAPE, FL_Escape}, 00722 {VK_SPACE, ' '}, 00723 {VK_PRIOR, FL_KP+'9', FL_Page_Up}, 00724 {VK_NEXT, FL_KP+'3', FL_Page_Down}, 00725 {VK_END, FL_KP+'1', FL_End}, 00726 {VK_HOME, FL_KP+'7', FL_Home}, 00727 {VK_LEFT, FL_KP+'4', FL_Left}, 00728 {VK_UP, FL_KP+'8', FL_Up}, 00729 {VK_RIGHT, FL_KP+'6', FL_Right}, 00730 {VK_DOWN, FL_KP+'2', FL_Down}, 00731 {VK_SNAPSHOT, FL_Print}, // does not work on NT 00732 {VK_INSERT, FL_KP+'0', FL_Insert}, 00733 {VK_DELETE, FL_KP+'.', FL_Delete}, 00734 {VK_LWIN, FL_Meta_L}, 00735 {VK_RWIN, FL_Meta_R}, 00736 {VK_APPS, FL_Menu}, 00737 {VK_MULTIPLY, FL_KP+'*'}, 00738 {VK_ADD, FL_KP+'+'}, 00739 {VK_SUBTRACT, FL_KP+'-'}, 00740 {VK_DECIMAL, FL_KP+'.'}, 00741 {VK_DIVIDE, FL_KP+'/'}, 00742 {VK_NUMLOCK, FL_Num_Lock}, 00743 {VK_SCROLL, FL_Scroll_Lock}, 00744 {0xba, ';'}, 00745 {0xbb, '='}, 00746 {0xbc, ','}, 00747 {0xbd, '-'}, 00748 {0xbe, '.'}, 00749 {0xbf, '/'}, 00750 {0xc0, '`'}, 00751 {0xdb, '['}, 00752 {0xdc, '\\'}, 00753 {0xdd, ']'}, 00754 {0xde, '\''} 00755 }; 00756 static int ms2fltk(int vk, int extended) { 00757 static unsigned short vklut[256]; 00758 static unsigned short extendedlut[256]; 00759 if (!vklut[1]) { // init the table 00760 unsigned int i; 00761 for (i = 0; i < 256; i++) vklut[i] = tolower(i); 00762 for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); 00763 for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); 00764 for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) { 00765 vklut[vktab[i].vk] = vktab[i].fltk; 00766 extendedlut[vktab[i].vk] = vktab[i].extended; 00767 } 00768 for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i]; 00769 } 00770 return extended ? extendedlut[vk] : vklut[vk]; 00771 } 00772 00773 #if USE_COLORMAP 00774 extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx 00775 #endif 00776 00777 00781 00782 struct Win32Timer 00783 { 00784 UINT_PTR handle; 00785 Fl_Timeout_Handler callback; 00786 void *data; 00787 }; 00788 static Win32Timer* win32_timers; 00789 static int win32_timer_alloc; 00790 static int win32_timer_used; 00791 static HWND s_TimerWnd; 00792 00793 static void realloc_timers() 00794 { 00795 if (win32_timer_alloc == 0) { 00796 win32_timer_alloc = 8; 00797 } 00798 win32_timer_alloc *= 2; 00799 Win32Timer* new_timers = new Win32Timer[win32_timer_alloc]; 00800 memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used); 00801 memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used); 00802 Win32Timer* delete_me = win32_timers; 00803 win32_timers = new_timers; 00804 delete [] delete_me; 00805 } 00806 00807 static void delete_timer(Win32Timer& t) 00808 { 00809 KillTimer(s_TimerWnd, t.handle); 00810 memset(&t, 0, sizeof(Win32Timer)); 00811 } 00812 00815 00816 static Fl_Window* resize_bug_fix; 00817 00818 extern void fl_save_pen(void); 00819 extern void fl_restore_pen(void); 00820 00821 static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00822 { 00823 // Copy the message to fl_msg so add_handler code can see it, it is 00824 // already there if this is called by DispatchMessage, but not if 00825 // Windows calls this directly. 00826 fl_msg.hwnd = hWnd; 00827 fl_msg.message = uMsg; 00828 fl_msg.wParam = wParam; 00829 fl_msg.lParam = lParam; 00830 //fl_msg.time = ??? 00831 //fl_msg.pt = ??? 00832 //fl_msg.lPrivate = ??? 00833 00834 Fl_Window *window = fl_find(hWnd); 00835 00836 if (window) switch (uMsg) { 00837 00838 case WM_QUIT: // this should not happen? 00839 Fl::fatal("WM_QUIT message"); 00840 00841 case WM_CLOSE: // user clicked close box 00842 Fl::handle(FL_CLOSE, window); 00843 PostQuitMessage(0); 00844 return 0; 00845 00846 case WM_SYNCPAINT : 00847 case WM_NCPAINT : 00848 case WM_ERASEBKGND : 00849 // Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc 00850 // so that Windows can generate the proper paint messages... 00851 // Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too... 00852 break; 00853 00854 case WM_PAINT: { 00855 Fl_Region R; 00856 Fl_X *i = Fl_X::i(window); 00857 i->wait_for_expose = 0; 00858 char redraw_whole_window = false; 00859 if (!i->region && window->damage()) { 00860 // Redraw the whole window... 00861 i->region = CreateRectRgn(0, 0, window->w(), window->h()); 00862 redraw_whole_window = true; 00863 } 00864 00865 // We need to merge WIN32's damage into FLTK's damage. 00866 R = CreateRectRgn(0,0,0,0); 00867 int r = GetUpdateRgn(hWnd,R,0); 00868 if (r==NULLREGION && !redraw_whole_window) { 00869 break; 00870 } 00871 00872 if (i->region) { 00873 // Also tell WIN32 that we are drawing someplace else as well... 00874 CombineRgn(i->region, i->region, R, RGN_OR); 00875 XDestroyRegion(R); 00876 } else { 00877 i->region = R; 00878 } 00879 if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0); 00880 else ValidateRgn(hWnd,i->region); 00881 00882 window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE)); 00883 // These next two statements should not be here, so that all update 00884 // is deferred until Fl::flush() is called during idle. However WIN32 00885 // apparently is very unhappy if we don't obey it and draw right now. 00886 // Very annoying! 00887 fl_GetDC(hWnd); // Make sure we have a DC for this window... 00888 fl_save_pen(); 00889 i->flush(); 00890 fl_restore_pen(); 00891 window->clear_damage(); 00892 } return 0; 00893 00894 case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; 00895 case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; 00896 case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; 00897 case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; 00898 case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; 00899 case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; 00900 case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; 00901 case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; 00902 case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; 00903 00904 case WM_MOUSEMOVE: 00905 #ifdef USE_TRACK_MOUSE 00906 if (track_mouse_win != window) { 00907 TRACKMOUSEEVENT tme; 00908 tme.cbSize = sizeof(TRACKMOUSEEVENT); 00909 tme.dwFlags = TME_LEAVE; 00910 tme.hwndTrack = hWnd; 00911 _TrackMouseEvent(&tme); 00912 track_mouse_win = window; 00913 } 00914 #endif // USE_TRACK_MOUSE 00915 mouse_event(window, 3, 0, wParam, lParam); 00916 return 0; 00917 00918 case WM_MOUSELEAVE: 00919 if (track_mouse_win == window) { // we left the top level window ! 00920 Fl_Window *tw = window; 00921 while (tw->parent()) tw = tw->window(); // find top level window 00922 Fl::belowmouse(0); 00923 Fl::handle(FL_LEAVE, tw); 00924 } 00925 track_mouse_win = 0; // force TrackMouseEvent() restart 00926 break; 00927 00928 case WM_SETFOCUS: 00929 Fl::handle(FL_FOCUS, window); 00930 break; 00931 00932 case WM_KILLFOCUS: 00933 Fl::handle(FL_UNFOCUS, window); 00934 Fl::flush(); // it never returns to main loop when deactivated... 00935 break; 00936 00937 case WM_SHOWWINDOW: 00938 if (!window->parent()) { 00939 Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); 00940 } 00941 break; 00942 00943 case WM_ACTIVATEAPP: 00944 // From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP 00945 // messages to restore the correct state of the shift/ctrl/alt/lock 00946 // keys... Added control, shift, alt, and meta keys, and changed 00947 // to use GetAsyncKeyState and do it when wParam is 1 00948 // (that means we have focus...) 00949 if (wParam) 00950 { 00951 ulong state = 0; 00952 if (GetAsyncKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; 00953 if (GetAsyncKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; 00954 if (GetAsyncKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; 00955 if (GetAsyncKeyState(VK_CONTROL)&~1) state |= FL_CTRL; 00956 if (GetAsyncKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; 00957 if (GetAsyncKeyState(VK_MENU)) state |= FL_ALT; 00958 if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META; 00959 Fl::e_state = state; 00960 return 0; 00961 } 00962 break; 00963 00964 case WM_INPUTLANGCHANGE: 00965 fl_get_codepage(); 00966 break; 00967 case WM_IME_COMPOSITION: 00968 // if (!fl_is_nt4() && lParam & GCS_RESULTCLAUSE) { 00969 // HIMC himc = ImmGetContext(hWnd); 00970 // wlen = ImmGetCompositionStringW(himc, GCS_RESULTSTR, 00971 // wbuf, sizeof(wbuf)) / sizeof(short); 00972 // if (wlen < 0) wlen = 0; 00973 // wbuf[wlen] = 0; 00974 // ImmReleaseContext(hWnd, himc); 00975 // } 00976 break; 00977 case WM_KEYDOWN: 00978 case WM_SYSKEYDOWN: 00979 case WM_KEYUP: 00980 case WM_SYSKEYUP: 00981 // save the keysym until we figure out the characters: 00982 Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam,lParam&(1<<24)); 00983 // See if TranslateMessage turned it into a WM_*CHAR message: 00984 if (PeekMessageW(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) 00985 { 00986 uMsg = fl_msg.message; 00987 wParam = fl_msg.wParam; 00988 lParam = fl_msg.lParam; 00989 } 00990 case WM_DEADCHAR: 00991 case WM_SYSDEADCHAR: 00992 case WM_CHAR: 00993 case WM_SYSCHAR: { 00994 ulong state = Fl::e_state & 0xff000000; // keep the mouse button state 00995 // if GetKeyState is expensive we might want to comment some of these out: 00996 if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; 00997 if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; 00998 if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL; 00999 // Alt gets reported for the Alt-GR switch on foreign keyboards. 01000 // so we need to check the event as well to get it right: 01001 if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU) 01002 && uMsg != WM_CHAR) state |= FL_ALT; 01003 if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; 01004 if ((GetKeyState(VK_LWIN)|GetKeyState(VK_RWIN))&~1) { 01005 // WIN32 bug? GetKeyState returns garbage if the user hit the 01006 // meta key to pop up start menu. Sigh. 01007 if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) 01008 state |= FL_META; 01009 } 01010 if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; 01011 Fl::e_state = state; 01012 static char buffer[1024]; 01013 if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { 01014 01015 xchar u = (xchar) wParam; 01016 // Fl::e_length = fl_unicode2utf(&u, 1, buffer); 01017 Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); 01018 buffer[Fl::e_length] = 0; 01019 01020 01021 } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { 01022 if (state & FL_NUM_LOCK) { 01023 // Convert to regular keypress... 01024 buffer[0] = Fl::e_keysym-FL_KP; 01025 Fl::e_length = 1; 01026 } else { 01027 // Convert to special keypress... 01028 buffer[0] = 0; 01029 Fl::e_length = 0; 01030 switch (Fl::e_keysym) { 01031 case FL_KP + '0' : 01032 Fl::e_keysym = FL_Insert; 01033 break; 01034 case FL_KP + '1' : 01035 Fl::e_keysym = FL_End; 01036 break; 01037 case FL_KP + '2' : 01038 Fl::e_keysym = FL_Down; 01039 break; 01040 case FL_KP + '3' : 01041 Fl::e_keysym = FL_Page_Down; 01042 break; 01043 case FL_KP + '4' : 01044 Fl::e_keysym = FL_Left; 01045 break; 01046 case FL_KP + '6' : 01047 Fl::e_keysym = FL_Right; 01048 break; 01049 case FL_KP + '7' : 01050 Fl::e_keysym = FL_Home; 01051 break; 01052 case FL_KP + '8' : 01053 Fl::e_keysym = FL_Up; 01054 break; 01055 case FL_KP + '9' : 01056 Fl::e_keysym = FL_Page_Up; 01057 break; 01058 case FL_KP + '.' : 01059 Fl::e_keysym = FL_Delete; 01060 break; 01061 case FL_KP + '/' : 01062 case FL_KP + '*' : 01063 case FL_KP + '-' : 01064 case FL_KP + '+' : 01065 buffer[0] = Fl::e_keysym-FL_KP; 01066 Fl::e_length = 1; 01067 break; 01068 } 01069 } 01070 } else if ((lParam & (1<<31))==0){ 01071 //buffer[0] = 0; 01072 //Fl::e_length = 0; 01073 xchar u = (xchar) wParam; 01074 // Fl::e_length = fl_unicode2utf(&u, 1, buffer); 01075 Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); 01076 buffer[Fl::e_length] = 0; 01077 } 01078 Fl::e_text = buffer; 01079 if (lParam & (1<<31)) { // key up events. 01080 if (Fl::handle(FL_KEYUP, window)) return 0; 01081 break; 01082 } 01083 // for (int i = lParam&0xff; i--;) 01084 while (window->parent()) window = window->window(); 01085 if (Fl::handle(FL_KEYBOARD,window)) { 01086 if (uMsg==WM_DEADCHAR || uMsg==WM_SYSDEADCHAR) 01087 Fl::compose_state = 1; 01088 return 0; 01089 } 01090 break;} 01091 01092 case WM_MOUSEWHEEL: { 01093 static int delta = 0; // running total of all motion 01094 delta += (SHORT)(HIWORD(wParam)); 01095 Fl::e_dy = -delta / WHEEL_DELTA; 01096 delta += Fl::e_dy * WHEEL_DELTA; 01097 if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window); 01098 return 0; 01099 } 01100 01101 case WM_GETMINMAXINFO: 01102 Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); 01103 break; 01104 01105 case WM_SIZE: 01106 if (!window->parent()) { 01107 if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { 01108 Fl::handle(FL_HIDE, window); 01109 } else { 01110 Fl::handle(FL_SHOW, window); 01111 resize_bug_fix = window; 01112 window->size(LOWORD(lParam), HIWORD(lParam)); 01113 } 01114 } 01115 break; 01116 01117 case WM_MOVE: { 01118 resize_bug_fix = window; 01119 int nx = LOWORD(lParam); 01120 int ny = HIWORD(lParam); 01121 if (nx & 0x8000) nx -= 65536; 01122 if (ny & 0x8000) ny -= 65536; 01123 window->position(nx, ny); } 01124 break; 01125 01126 case WM_SETCURSOR: 01127 if (LOWORD(lParam) == HTCLIENT) { 01128 while (window->parent()) window = window->window(); 01129 SetCursor(Fl_X::i(window)->cursor); 01130 return 0; 01131 } 01132 break; 01133 01134 #if USE_COLORMAP 01135 case WM_QUERYNEWPALETTE : 01136 fl_GetDC(hWnd); 01137 if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE); 01138 break; 01139 01140 case WM_PALETTECHANGED: 01141 fl_GetDC(hWnd); 01142 if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc); 01143 break; 01144 01145 case WM_CREATE : 01146 fl_GetDC(hWnd); 01147 fl_select_palette(); 01148 break; 01149 #endif 01150 01151 case WM_DESTROYCLIPBOARD: 01152 fl_i_own_selection[1] = 0; 01153 return 1; 01154 01155 case WM_RENDERALLFORMATS: 01156 fl_i_own_selection[1] = 0; 01157 // Windoze seems unhappy unless I do these two steps. Documentation 01158 // seems to vary on whether opening the clipboard is necessary or 01159 // is in fact wrong: 01160 CloseClipboard(); 01161 OpenClipboard(NULL); 01162 // fall through... 01163 case WM_RENDERFORMAT: { 01164 HANDLE h; 01165 01166 // int l = fl_utf_nb_char((unsigned char*)fl_selection_buffer[1], fl_selection_length[1]); 01167 int l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], NULL, 0); // Pass NULL buffer to query length required 01168 h = GlobalAlloc(GHND, (l+1) * sizeof(unsigned short)); 01169 if (h) { 01170 unsigned short *g = (unsigned short*) GlobalLock(h); 01171 // fl_utf2unicode((unsigned char *)fl_selection_buffer[1], fl_selection_length[1], (xchar*)g); 01172 l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], g, (l+1)); 01173 g[l] = 0; 01174 GlobalUnlock(h); 01175 SetClipboardData(CF_UNICODETEXT, h); 01176 } 01177 01178 // Windoze also seems unhappy if I don't do this. Documentation very 01179 // unclear on what is correct: 01180 if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard(); 01181 return 1;} 01182 01183 default: 01184 if (Fl::handle(0,0)) return 0; 01185 break; 01186 } 01187 01188 01189 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 01190 } 01191 01193 // This function gets the dimensions of the top/left borders and 01194 // the title bar, if there is one, based on the FL_BORDER, FL_MODAL 01195 // and FL_NONMODAL flags, and on the window's size range. 01196 // It returns the following values: 01197 // 01198 // value | border | title bar 01199 // 0 | none | no 01200 // 1 | fix | yes 01201 // 2 | size | yes 01202 01203 int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) { 01204 int W, H, xoff, yoff, dx, dy; 01205 int ret = bx = by = bt = 0; 01206 01207 int fallback = 1; 01208 if (!w->parent()) { 01209 HWND hwnd = fl_xid(w); 01210 if (hwnd) { 01211 // The block below calculates the window borders by requesting the 01212 // required decorated window rectangle for a desired client rectangle. 01213 // If any part of the function above fails, we will drop to a 01214 // fallback to get the best guess which is always available. 01215 HWND hwnd = fl_xid(w); 01216 // request the style flags of this window, as WIN32 sees them 01217 LONG style = GetWindowLong(hwnd, GWL_STYLE); 01218 LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); 01219 RECT r; 01220 r.left = w->x(); 01221 r.top = w->y(); 01222 r.right = w->x()+w->w(); 01223 r.bottom = w->y()+w->h(); 01224 // get the decoration rectangle for the desired client rectangle 01225 BOOL ok = AdjustWindowRectEx(&r, style, FALSE, exstyle); 01226 if (ok) { 01227 X = r.left; 01228 Y = r.top; 01229 W = r.right - r.left; 01230 H = r.bottom - r.top; 01231 bx = w->x() - r.left; 01232 by = r.bottom - w->y() - w->h(); // height of the bootm frame 01233 bt = w->y() - r.top - by; // height of top caption bar 01234 xoff = bx; 01235 yoff = by + bt; 01236 dx = W - w->w(); 01237 dy = H - w->h(); 01238 if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) 01239 ret = 2; 01240 else 01241 ret = 1; 01242 fallback = 0; 01243 } 01244 } 01245 } 01246 // This is the original (pre 1.1.7) routine to calculate window border sizes. 01247 if (fallback) { 01248 if (w->border() && !w->parent()) { 01249 if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { 01250 ret = 2; 01251 bx = GetSystemMetrics(SM_CXSIZEFRAME); 01252 by = GetSystemMetrics(SM_CYSIZEFRAME); 01253 } else { 01254 ret = 1; 01255 bx = GetSystemMetrics(SM_CXFIXEDFRAME); 01256 by = GetSystemMetrics(SM_CYFIXEDFRAME); 01257 } 01258 bt = GetSystemMetrics(SM_CYCAPTION); 01259 } 01260 //The coordinates of the whole window, including non-client area 01261 xoff = bx; 01262 yoff = by + bt; 01263 dx = 2*bx; 01264 dy = 2*by + bt; 01265 X = w->x()-xoff; 01266 Y = w->y()-yoff; 01267 W = w->w()+dx; 01268 H = w->h()+dy; 01269 } 01270 01271 //Proceed to positioning the window fully inside the screen, if possible 01272 //Make border's lower right corner visible 01273 int scr_x, scr_y, scr_w, scr_h; 01274 Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); 01275 if (scr_x+scr_w < X+W) X = scr_x+scr_w - W; 01276 if (scr_y+scr_h < Y+H) Y = scr_y+scr_h - H; 01277 //Make border's upper left corner visible 01278 if (X<scr_x) X = scr_x; 01279 if (Y<scr_y) Y = scr_y; 01280 //Make client area's lower right corner visible 01281 if (scr_x+scr_w < X+dx+ w->w()) X = scr_x+scr_w - w->w() - dx; 01282 if (scr_y+scr_h < Y+dy+ w->h()) Y = scr_y+scr_h - w->h() - dy; 01283 //Make client area's upper left corner visible 01284 if (X+xoff < scr_x) X = scr_x-xoff; 01285 if (Y+yoff < scr_y) Y = scr_y-yoff; 01286 //Return the client area's top left corner in (X,Y) 01287 X+=xoff; 01288 Y+=yoff; 01289 01290 return ret; 01291 } 01292 01294 01295 void Fl_Window::resize(int X,int Y,int W,int H) { 01296 UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER 01297 | SWP_NOACTIVATE | SWP_NOOWNERZORDER; 01298 int is_a_resize = (W != w() || H != h()); 01299 int resize_from_program = (this != resize_bug_fix); 01300 if (!resize_from_program) resize_bug_fix = 0; 01301 if (X != x() || Y != y()) { 01302 force_position(1); 01303 } else { 01304 if (!is_a_resize) return; 01305 flags |= SWP_NOMOVE; 01306 } 01307 if (is_a_resize) { 01308 Fl_Group::resize(X,Y,W,H); 01309 if (visible_r()) { 01310 redraw(); 01311 // only wait for exposure if this window has a size - a window 01312 // with no width or height will never get an exposure event 01313 if (i && W>0 && H>0) 01314 i->wait_for_expose = 1; 01315 } 01316 } else { 01317 x(X); y(Y); 01318 flags |= SWP_NOSIZE; 01319 } 01320 if (!border()) flags |= SWP_NOACTIVATE; 01321 if (resize_from_program && shown()) { 01322 if (!resizable()) size_range(w(),h(),w(),h()); 01323 int dummy_x, dummy_y, bt, bx, by; 01324 //Ignore window managing when resizing, so that windows (and more 01325 //specifically menus) can be moved offscreen. 01326 if (Fl_X::fake_X_wm(this, dummy_x, dummy_y, bt, bx, by)) { 01327 X -= bx; 01328 Y -= by+bt; 01329 W += 2*bx; 01330 H += 2*by+bt; 01331 } 01332 // avoid zero size windows. A zero sized window on Win32 01333 // will cause continouly new redraw events. 01334 if (W<=0) W = 1; 01335 if (H<=0) H = 1; 01336 SetWindowPos(i->xid, 0, X, Y, W, H, flags); 01337 } 01338 } 01339 01341 01342 /* 01343 * This silly little class remembers the name of all window classes 01344 * we register to avoid double registration. It has the added bonus 01345 * of freeing everything on application close as well. 01346 */ 01347 class NameList { 01348 public: 01349 NameList() { name = (char**)malloc(sizeof(char**)); NName = 1; nName = 0; } 01350 ~NameList() { 01351 int i; 01352 for (i=0; i<nName; i++) free(name[i]); 01353 if (name) free(name); 01354 } 01355 void add_name(const char *n) { 01356 if (NName==nName) { 01357 NName += 5; 01358 name = (char**)realloc(name, NName * sizeof(char*)); 01359 } 01360 name[nName++] = strdup(n); 01361 } 01362 char has_name(const char *n) { 01363 int i; 01364 for (i=0; i<nName; i++) { 01365 if (strcmp(name[i], n)==0) return 1; 01366 } 01367 return 0; 01368 } 01369 private: 01370 char **name; 01371 int nName, NName; 01372 }; 01373 01374 void fl_fix_focus(); // in Fl.cxx 01375 01376 char fl_show_iconic; // hack for Fl_Window::iconic() 01377 // int fl_background_pixel = -1; // color to use for background 01378 HCURSOR fl_default_cursor; 01379 UINT fl_wake_msg = 0; 01380 int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR 01381 01382 Fl_X* Fl_X::make(Fl_Window* w) { 01383 Fl_Group::current(0); // get rid of very common user bug: forgot end() 01384 01385 // if the window is a subwindow and our parent is not mapped yet, we 01386 // mark this window visible, so that mapping the parent at a later 01387 // point in time will call this function again to finally map the subwindow. 01388 if (w->parent() && !Fl_X::i(w->window())) { 01389 w->set_visible(); 01390 return 0L; 01391 } 01392 01393 static NameList class_name_list; 01394 static const char *first_class_name = 0L; 01395 const char *class_name = w->xclass(); 01396 if (!class_name) class_name = first_class_name; // reuse first class name used 01397 if (!class_name) class_name = "FLTK"; // default to create a "FLTK" WNDCLASS 01398 if (!first_class_name) { 01399 first_class_name = class_name; 01400 } 01401 01402 wchar_t class_namew[100]; // (limited) buffer for Windows class name 01403 01404 // convert UTF-8 class_name to wchar_t for RegisterClassExW and CreateWindowExW 01405 01406 fl_utf8toUtf16(class_name,strlen(class_name), // in 01407 (unsigned short*)class_namew, // out 01408 sizeof(class_namew)/sizeof(wchar_t)); // max. size 01409 01410 if (!class_name_list.has_name(class_name)) { 01411 WNDCLASSEXW wcw; 01412 memset(&wcw, 0, sizeof(wcw)); 01413 wcw.cbSize = sizeof(WNDCLASSEXW); 01414 01415 // Documentation states a device context consumes about 800 bytes 01416 // of memory... so who cares? If 800 bytes per window is what it 01417 // takes to speed things up, I'm game. 01418 //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; 01419 wcw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; 01420 wcw.lpfnWndProc = (WNDPROC)WndProc; 01421 wcw.cbClsExtra = wcw.cbWndExtra = 0; 01422 wcw.hInstance = fl_display; 01423 if (!w->icon()) 01424 w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); 01425 wcw.hIcon = wcw.hIconSm = (HICON)w->icon(); 01426 wcw.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); 01427 //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); 01428 //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); 01429 wcw.hbrBackground = NULL; 01430 wcw.lpszMenuName = NULL; 01431 wcw.lpszClassName = class_namew; 01432 RegisterClassExW(&wcw); 01433 class_name_list.add_name(class_name); 01434 } 01435 01436 const wchar_t* message_namew = L"FLTK::ThreadWakeup"; 01437 if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessageW(message_namew); 01438 01439 HWND parent; 01440 DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; 01441 DWORD styleEx = WS_EX_LEFT; 01442 01443 int xp = w->x(); 01444 int yp = w->y(); 01445 int wp = w->w(); 01446 int hp = w->h(); 01447 01448 int showit = 1; 01449 01450 if (w->parent()) { 01451 style |= WS_CHILD; 01452 styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; 01453 parent = fl_xid(w->window()); 01454 } else { 01455 if (!w->size_range_set) { 01456 if (w->resizable()) { 01457 Fl_Widget *o = w->resizable(); 01458 int minw = o->w(); if (minw > 100) minw = 100; 01459 int minh = o->h(); if (minh > 100) minh = 100; 01460 w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); 01461 } else { 01462 w->size_range(w->w(), w->h(), w->w(), w->h()); 01463 } 01464 } 01465 styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; 01466 int xwm = xp , ywm = yp , bt, bx, by; 01467 switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) { 01468 // No border (used for menus) 01469 case 0: style |= WS_POPUP; 01470 styleEx |= WS_EX_TOOLWINDOW; 01471 break; 01472 01473 // Thin border and title bar 01474 case 1: style |= WS_DLGFRAME | WS_CAPTION; break; 01475 01476 // Thick, resizable border and title bar, with maximize button 01477 case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break; 01478 } 01479 if (by+bt) { 01480 if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX; 01481 wp += 2*bx; 01482 hp += 2*by+bt; 01483 } 01484 if (!w->force_position()) { 01485 xp = yp = CW_USEDEFAULT; 01486 } else { 01487 if (!Fl::grab()) { 01488 xp = xwm; yp = ywm; 01489 w->x(xp);w->y(yp); 01490 } 01491 xp -= bx; 01492 yp -= by+bt; 01493 } 01494 01495 parent = 0; 01496 if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) { 01497 // find some other window to be "transient for": 01498 Fl_Window* w = Fl_X::first->w; 01499 while (w->parent()) w = w->window(); 01500 parent = fl_xid(w); 01501 if (!w->visible()) showit = 0; 01502 } else if (Fl::grab()) parent = fl_xid(Fl::grab()); 01503 } 01504 01505 Fl_X* x = new Fl_X; 01506 x->other_xid = 0; 01507 x->setwindow(w); 01508 x->region = 0; 01509 x->private_dc = 0; 01510 x->cursor = fl_default_cursor; 01511 if (!fl_codepage) fl_get_codepage(); 01512 01513 WCHAR *lab = NULL; 01514 if (w->label()) { 01515 int l = strlen(w->label()); 01516 // lab = (WCHAR*) malloc((l + 1) * sizeof(short)); 01517 // l = fl_utf2unicode((unsigned char*)w->label(), l, (xchar*)lab); 01518 // lab[l] = 0; 01519 unsigned wlen = fl_utf8toUtf16(w->label(), l, NULL, 0); // Pass NULL to query length 01520 wlen++; 01521 lab = (WCHAR *) malloc(sizeof(WCHAR)*wlen); 01522 wlen = fl_utf8toUtf16(w->label(), l, (unsigned short*)lab, wlen); 01523 lab[wlen] = 0; 01524 } 01525 x->xid = CreateWindowExW( 01526 styleEx, 01527 class_namew, lab, style, 01528 xp, yp, wp, hp, 01529 parent, 01530 NULL, // menu 01531 fl_display, 01532 NULL // creation parameters 01533 ); 01534 if (lab) free(lab); 01535 01536 x->next = Fl_X::first; 01537 Fl_X::first = x; 01538 01539 x->wait_for_expose = 1; 01540 if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;} 01541 if (showit) { 01542 w->set_visible(); 01543 int old_event = Fl::e_number; 01544 w->handle(Fl::e_number = FL_SHOW); // get child windows to appear 01545 Fl::e_number = old_event; 01546 w->redraw(); // force draw to happen 01547 } 01548 // If we've captured the mouse, we dont want to activate any 01549 // other windows from the code, or we loose the capture. 01550 ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : 01551 (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); 01552 01553 // Register all windows for potential drag'n'drop operations 01554 fl_OleInitialize(); 01555 RegisterDragDrop(x->xid, flIDropTarget); 01556 01557 if (!fl_aimm) { 01558 CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, 01559 IID_IActiveIMMApp, (void**) &fl_aimm); 01560 if (fl_aimm) { 01561 fl_aimm->Activate(TRUE); 01562 } 01563 } 01564 01565 if (w->modal()) {Fl::modal_ = w; fl_fix_focus();} 01566 return x; 01567 } 01568 01569 01570 01571 01575 01576 01577 static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg, 01578 WPARAM wParam, LPARAM lParam) 01579 { 01580 switch (msg) { 01581 case WM_TIMER: 01582 { 01583 unsigned int id = wParam - 1; 01584 if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) { 01585 Fl_Timeout_Handler cb = win32_timers[id].callback; 01586 void* data = win32_timers[id].data; 01587 delete_timer(win32_timers[id]); 01588 if (cb) { 01589 (*cb)(data); 01590 } 01591 } 01592 } 01593 return 0; 01594 01595 default: 01596 break; 01597 } 01598 01599 return DefWindowProc(hwnd, msg, wParam, lParam); 01600 } 01601 01602 void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data) 01603 { 01604 repeat_timeout(time, cb, data); 01605 } 01606 01607 void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) 01608 { 01609 int timer_id = -1; 01610 for (int i = 0; i < win32_timer_used; ++i) { 01611 if ( !win32_timers[i].handle ) { 01612 timer_id = i; 01613 break; 01614 } 01615 } 01616 if (timer_id == -1) { 01617 if (win32_timer_used == win32_timer_alloc) { 01618 realloc_timers(); 01619 } 01620 timer_id = win32_timer_used++; 01621 } 01622 unsigned int elapsed = (unsigned int)(time * 1000); 01623 01624 if ( !s_TimerWnd ) { 01625 const char* timer_class = "FLTimer"; 01626 WNDCLASSEX wc; 01627 memset(&wc, 0, sizeof(wc)); 01628 wc.cbSize = sizeof (wc); 01629 wc.style = CS_CLASSDC; 01630 wc.lpfnWndProc = (WNDPROC)s_TimerProc; 01631 wc.hInstance = fl_display; 01632 wc.lpszClassName = timer_class; 01633 /*ATOM atom =*/ RegisterClassEx(&wc); 01634 // create a zero size window to handle timer events 01635 s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, 01636 timer_class, "", 01637 WS_POPUP, 01638 0, 0, 0, 0, 01639 NULL, NULL, fl_display, NULL); 01640 // just in case this OS won't let us create a 0x0 size window: 01641 if (!s_TimerWnd) 01642 s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, 01643 timer_class, "", 01644 WS_POPUP, 01645 0, 0, 1, 1, 01646 NULL, NULL, fl_display, NULL); 01647 ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE); 01648 } 01649 01650 win32_timers[timer_id].callback = cb; 01651 win32_timers[timer_id].data = data; 01652 01653 win32_timers[timer_id].handle = 01654 SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL); 01655 } 01656 01657 int Fl::has_timeout(Fl_Timeout_Handler cb, void* data) 01658 { 01659 for (int i = 0; i < win32_timer_used; ++i) { 01660 Win32Timer& t = win32_timers[i]; 01661 if (t.handle && t.callback == cb && t.data == data) { 01662 return 1; 01663 } 01664 } 01665 return 0; 01666 } 01667 01668 void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data) 01669 { 01670 int i; 01671 for (i = 0; i < win32_timer_used; ++i) { 01672 Win32Timer& t = win32_timers[i]; 01673 if (t.handle && t.callback == cb && 01674 (t.data == data || data == NULL)) { 01675 delete_timer(t); 01676 } 01677 } 01678 } 01679 01682 01683 01684 01686 01687 HINSTANCE fl_display = GetModuleHandle(NULL); 01688 01689 void Fl_Window::size_range_() { 01690 size_range_set = 1; 01691 } 01692 01693 void Fl_X::set_minmax(LPMINMAXINFO minmax) 01694 { 01695 int td, wd, hd, dummy_x, dummy_y; 01696 01697 fake_X_wm(w, dummy_x, dummy_y, td, wd, hd); 01698 wd *= 2; 01699 hd *= 2; 01700 hd += td; 01701 01702 minmax->ptMinTrackSize.x = w->minw + wd; 01703 minmax->ptMinTrackSize.y = w->minh + hd; 01704 if (w->maxw) { 01705 minmax->ptMaxTrackSize.x = w->maxw + wd; 01706 minmax->ptMaxSize.x = w->maxw + wd; 01707 } 01708 if (w->maxh) { 01709 minmax->ptMaxTrackSize.y = w->maxh + hd; 01710 minmax->ptMaxSize.y = w->maxh + hd; 01711 } 01712 } 01713 01715 01716 #include <FL/filename.H> // need so FL_EXPORT fl_filename_name works 01717 01718 // returns pointer to the filename, or null if name ends with '/' 01719 const char *fl_filename_name(const char *name) { 01720 const char *p,*q; 01721 if (!name) return (0); 01722 q = name; 01723 if (q[0] && q[1]==':') q += 2; // skip leading drive letter 01724 for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1; 01725 return q; 01726 } 01727 01728 void Fl_Window::label(const char *name,const char *iname) { 01729 Fl_Widget::label(name); 01730 iconlabel_ = iname; 01731 if (shown() && !parent()) { 01732 if (!name) name = ""; 01733 int l = strlen(name); 01734 // WCHAR *lab = (WCHAR*) malloc((l + 1) * sizeof(short)); 01735 // l = fl_utf2unicode((unsigned char*)name, l, (xchar*)lab); 01736 unsigned wlen = fl_utf8toUtf16(name, l, NULL, 0); // Pass NULL to query length 01737 wlen++; 01738 unsigned short * lab = (unsigned short*)malloc(sizeof(unsigned short)*wlen); 01739 wlen = fl_utf8toUtf16(name, l, lab, wlen); 01740 lab[wlen] = 0; 01741 SetWindowTextW(i->xid, (WCHAR *)lab); 01742 free(lab); 01743 } 01744 } 01745 01747 // Implement the virtual functions for the base Fl_Window class: 01748 01749 // If the box is a filled rectangle, we can make the redisplay *look* 01750 // faster by using X's background pixel erasing. We can make it 01751 // actually *be* faster by drawing the frame only, this is done by 01752 // setting fl_boxcheat, which is seen by code in fl_drawbox.cxx: 01753 // For WIN32 it looks like all windows share a background color, so 01754 // I use FL_GRAY for this and only do this cheat for windows that are 01755 // that color. 01756 // Actually it is totally disabled. 01757 // Fl_Widget *fl_boxcheat; 01758 //static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} 01759 01760 void Fl_Window::show() { 01761 image(Fl::scheme_bg_); 01762 if (Fl::scheme_bg_) { 01763 labeltype(FL_NORMAL_LABEL); 01764 align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); 01765 } else { 01766 labeltype(FL_NO_LABEL); 01767 } 01768 Fl_Tooltip::exit(this); 01769 if (!shown()) { 01770 // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color()); 01771 Fl_X::make(this); 01772 } else { 01773 // Once again, we would lose the capture if we activated the window. 01774 if (IsIconic(i->xid)) OpenIcon(i->xid); 01775 if (!fl_capture) BringWindowToTop(i->xid); 01776 //ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE); 01777 } 01778 #ifdef USE_PRINT_BUTTON 01779 void preparePrintFront(void); 01780 preparePrintFront(); 01781 #endif 01782 } 01783 01784 Fl_Window *Fl_Window::current_; 01785 // the current context 01786 HDC fl_gc = 0; 01787 // the current window handle, initially set to -1 so we can correctly 01788 // allocate fl_GetDC(0) 01789 HWND fl_window = NULL; 01790 01791 // Here we ensure only one GetDC is ever in place. 01792 HDC fl_GetDC(HWND w) { 01793 if (fl_gc) { 01794 if (w == fl_window && fl_window != NULL) return fl_gc; 01795 if (fl_window) fl_release_dc(fl_window, fl_gc); // ReleaseDC 01796 } 01797 fl_gc = GetDC(w); 01798 fl_save_dc(w, fl_gc); 01799 fl_window = w; 01800 // calling GetDC seems to always reset these: (?) 01801 SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT); 01802 SetBkMode(fl_gc, TRANSPARENT); 01803 01804 return fl_gc; 01805 } 01806 01807 // make X drawing go into this window (called by subclass flush() impl.) 01808 void Fl_Window::make_current() { 01809 fl_GetDC(fl_xid(this)); 01810 01811 #if USE_COLORMAP 01812 // Windows maintains a hardware and software color palette; the 01813 // SelectPalette() call updates the current soft->hard mapping 01814 // for all drawing calls, so we must select it here before any 01815 // code does any drawing... 01816 01817 fl_select_palette(); 01818 #endif // USE_COLORMAP 01819 01820 current_ = this; 01821 fl_clip_region(0); 01822 01823 01824 } 01825 01826 /* Make sure that all allocated fonts are released. This works only if 01827 Fl::run() is allowed to exit by closing all windows. Calling 'exit(int)' 01828 will not automatically free any fonts. */ 01829 void fl_free_fonts(void) 01830 { 01831 // remove the Fl_Font_Descriptor chains 01832 int i; 01833 Fl_Fontdesc * s; 01834 Fl_Font_Descriptor * f; 01835 Fl_Font_Descriptor * ff; 01836 for (i=0; i<FL_FREE_FONT; i++) { 01837 s = fl_fonts + i; 01838 for (f=s->first; f; f=ff) { 01839 ff = f->next; 01840 delete f; 01841 s->first = ff; 01842 } 01843 } 01844 } 01845 01846 01848 // 01849 // The following routines help fix a problem with the leaking of Windows 01850 // Device Context (DC) objects. The 'proper' protocol is for a program to 01851 // acquire a DC, save its state, do the modifications needed for drawing, 01852 // perform the drawing, restore the initial state, and release the DC. In 01853 // FLTK, the save and restore steps have previously been omitted and DCs are 01854 // not properly released, leading to a great number of DC leaks. As some 01855 // Windows "OSs" will hang when any process exceeds roughly 10,000 GDI objects, 01856 // it is important to control GDI leaks, which are much more important than memory 01857 // leaks. The following struct, global variable, and routines help implement 01858 // the above protocol for those cases where the GetDC and RestoreDC are not in 01859 // the same routine. For each GetDC, fl_save_dc is used to create an entry in 01860 // a linked list that saves the window handle, the DC handle, and the initial 01861 // state. When the DC is to be released, 'fl_release_dc' is called. It restores 01862 // the initial state and releases the DC. When the program exits, 'fl_cleanup_dc_list' 01863 // frees any remaining nodes in the list. 01864 01865 struct Win_DC_List { // linked list 01866 HWND window; // window handle 01867 HDC dc; // device context handle 01868 int saved_dc; // initial state of DC 01869 Win_DC_List * next; // pointer to next item 01870 }; 01871 01872 static Win_DC_List * win_DC_list = 0; 01873 01874 void fl_save_dc( HWND w, HDC dc) { 01875 Win_DC_List * t; 01876 t = new Win_DC_List; 01877 t->window = w; 01878 t->dc = dc; 01879 t->saved_dc = SaveDC(dc); 01880 if (win_DC_list) 01881 t->next = win_DC_list; 01882 else 01883 t->next = NULL; 01884 win_DC_list = t; 01885 } 01886 01887 void fl_release_dc(HWND w, HDC dc) { 01888 Win_DC_List * t= win_DC_list; 01889 Win_DC_List * prev = 0; 01890 if (!t) 01891 return; 01892 do { 01893 if (t->dc == dc) { 01894 RestoreDC(dc, t->saved_dc); 01895 ReleaseDC(w, dc); 01896 if (!prev) { 01897 win_DC_list = t->next; // delete first item 01898 } else { 01899 prev->next = t->next; // one in the middle 01900 } 01901 delete (t); 01902 return; 01903 } 01904 prev = t; 01905 t = t->next; 01906 } while (t); 01907 } 01908 01909 void fl_cleanup_dc_list(void) { // clean up the list 01910 Win_DC_List * t = win_DC_list; 01911 if (!t)return; 01912 do { 01913 RestoreDC(t->dc, t->saved_dc); 01914 ReleaseDC(t->window, t->dc); 01915 win_DC_list = t->next; 01916 delete (t); 01917 t = win_DC_list; 01918 } while(t); 01919 } 01920 01921 Fl_Region XRectangleRegion(int x, int y, int w, int h) { 01922 if (Fl_Surface_Device::surface()->class_name() == Fl_Display_Device::class_id) return CreateRectRgn(x,y,x+w,y+h); 01923 // because rotation may apply, the rectangle becomes a polygon in device coords 01924 POINT pt[4] = { {x, y}, {x + w, y}, {x + w, y + h}, {x, y + h} }; 01925 LPtoDP(fl_gc, pt, 4); 01926 return CreatePolygonRgn(pt, 4, ALTERNATE); 01927 } 01928 01929 #ifdef USE_PRINT_BUTTON 01930 // to test the Fl_Printer class creating a "Print front window" button in a separate window 01931 // contains also preparePrintFront call above 01932 #include <FL/Fl_Printer.H> 01933 #include <FL/Fl_Button.H> 01934 void printFront(Fl_Widget *o, void *data) 01935 { 01936 Fl_Printer printer; 01937 o->window()->hide(); 01938 Fl_Window *win = Fl::first_window(); 01939 if(!win) return; 01940 int w, h; 01941 if( printer.start_job(1) ) { o->window()->show(); return; } 01942 if( printer.start_page() ) { o->window()->show(); return; } 01943 printer.printable_rect(&w,&h); 01944 // scale the printer device so that the window fits on the page 01945 float scale = 1; 01946 if (win->w() > w || win->h() > h) { 01947 scale = (float)w/win->w(); 01948 if ((float)h/win->h() < scale) scale = (float)h/win->h(); 01949 printer.scale(scale, scale); 01950 } 01951 // #define ROTATE 20.0 01952 #ifdef ROTATE 01953 printer.scale(scale * 0.8, scale * 0.8); 01954 printer.printable_rect(&w, &h); 01955 printer.origin(w/2, h/2 ); 01956 printer.rotate(ROTATE); 01957 printer.print_widget( win, - win->w()/2, - win->h()/2 ); 01958 //printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 ); 01959 #else 01960 printer.print_widget( win ); 01961 //printer.print_window_part( win, 0,0, win->w(), win->h() ); 01962 #endif 01963 printer.end_page(); 01964 printer.end_job(); 01965 o->window()->show(); 01966 } 01967 01968 void preparePrintFront(void) 01969 { 01970 static BOOL first=TRUE; 01971 if(!first) return; 01972 first=FALSE; 01973 static Fl_Window w(0,0,120,30); 01974 static Fl_Button b(0,0,w.w(),w.h(), "Print front window"); 01975 b.callback(printFront); 01976 w.end(); 01977 w.show(); 01978 } 01979 #endif // USE_PRINT_BUTTON 01980 01981 #endif // FL_DOXYGEN 01982 01983 // 01984 // End of "$Id: Fl_win32.cxx 8205 2011-01-07 01:12:04Z matt $". 01985 //