1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
4 // we have to do this because the jpeg libraries use the symbol 'INT32'
5 #define INT32 WIN32_INT32
7 // this has to precede the others so we don't get collisions on min/max
8 #include <org/xwt/js/JS.h>
9 #include <org/xwt/Box.h>
24 #include <java/lang/Integer.h>
25 #include <java/util/Hashtable.h>
26 #include <org/xwt/Box.h>
27 #include <org/xwt/Surface.h>
28 #include <org/xwt/PixelBuffer.h>
29 #include <org/xwt/Picture.h>
30 #include <org/xwt/Platform.h>
31 #include <org/xwt/plat/Win32.h>
32 #include <org/xwt/plat/Win32$Win32Surface.h>
33 #include <org/xwt/plat/Win32$Win32PixelBuffer.h>
34 #include <org/xwt/plat/Win32$Win32Picture.h>
35 #include <org/xwt/util/Log.h>
36 #include <org/xwt/util/Semaphore.h>
39 #include <java/lang/System.h>
40 #include <java/io/PrintStream.h>
42 #define WM_USER_SETCURSOR WM_USER
43 #define WM_USER_DISPOSE (WM_USER + 1)
44 #define WM_USER_CREATEWINDOW (WM_USER + 2)
45 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
47 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
48 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
50 // Callbacks ////////////////////////////////////////////////////////////////////
52 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
53 org::xwt::plat::Win32$Win32Surface* surface =
54 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
56 if (surface != NULL) {
57 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
60 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
61 return DefWindowProc(hwnd, iMsg, wParam, lParam);
66 // Initialization ////////////////////////////////////////////////////////////////////
68 static int window_class_counter = 0;
70 jstring org::xwt::plat::Win32::getTempPath() {
72 DWORD ret = GetTempPath(1024, buf);
73 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
74 return JvNewStringLatin1(buf);
77 // XOR mask for the hand cursor
78 static unsigned char hand_cursor_xor[32 * 4] = {
79 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x0C, 0x00, 0x00,
81 0x00, 0x0C, 0x00, 0x00,
82 0x00, 0x0C, 0x00, 0x00,
83 0x00, 0x0C, 0x00, 0x00,
84 0x00, 0x0C, 0x00, 0x00,
85 0x00, 0x0D, 0x80, 0x00,
86 0x00, 0x0D, 0xB0, 0x00,
87 0x00, 0x0D, 0xB4, 0x00,
88 0x00, 0x0D, 0xB6, 0x00,
89 0x00, 0xCF, 0xF6, 0x00,
90 0x00, 0xEF, 0xFE, 0x00,
91 0x00, 0x6F, 0xFE, 0x00,
92 0x00, 0x2F, 0xFE, 0x00,
93 0x00, 0x3F, 0xFE, 0x00,
94 0x00, 0x1F, 0xFE, 0x00,
95 0x00, 0x1F, 0xFC, 0x00,
96 0x00, 0x0F, 0xFC, 0x00,
97 0x00, 0x0F, 0xFC, 0x00,
98 0x00, 0x07, 0xF8, 0x00,
99 0x00, 0x07, 0xF8, 0x00,
100 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00
113 // AND mask for the hand cursor
114 static unsigned char hand_cursor_and[32 * 4] = {
115 0xFF, 0xF3, 0xFF, 0xFF,
116 0xFF, 0xE1, 0xFF, 0xFF,
117 0xFF, 0xE1, 0xFF, 0xFF,
118 0xFF, 0xE1, 0xFF, 0xFF,
119 0xFF, 0xE1, 0xFF, 0xFF,
120 0xFF, 0xE0, 0x7F, 0xFF,
121 0xFF, 0xE0, 0x0F, 0xFF,
122 0xFF, 0xE0, 0x03, 0xFF,
123 0xFF, 0xE0, 0x01, 0xFF,
124 0xFF, 0x20, 0x00, 0xFF,
125 0xFE, 0x00, 0x00, 0xFF,
126 0xFE, 0x00, 0x00, 0xFF,
127 0xFF, 0x00, 0x00, 0xFF,
128 0xFF, 0x80, 0x00, 0xFF,
129 0xFF, 0x80, 0x00, 0xFF,
130 0xFF, 0xC0, 0x00, 0xFF,
131 0xFF, 0xC0, 0x01, 0xFF,
132 0xFF, 0xE0, 0x01, 0xFF,
133 0xFF, 0xE0, 0x01, 0xFF,
134 0xFF, 0xF0, 0x03, 0xFF,
135 0xFF, 0xF0, 0x03, 0xFF,
136 0xFF, 0xF0, 0x03, 0xFF,
137 0xFF, 0xFF, 0xFF, 0xFF,
138 0xFF, 0xFF, 0xFF, 0xFF,
139 0xFF, 0xFF, 0xFF, 0xFF,
140 0xFF, 0xFF, 0xFF, 0xFF,
141 0xFF, 0xFF, 0xFF, 0xFF,
142 0xFF, 0xFF, 0xFF, 0xFF,
143 0xFF, 0xFF, 0xFF, 0xFF,
144 0xFF, 0xFF, 0xFF, 0xFF,
145 0xFF, 0xFF, 0xFF, 0xFF,
146 0xFF, 0xFF, 0xFF, 0xFF
150 void org::xwt::plat::Win32::natInit() {
152 // grab desktop dc/handle
153 desktop_handle = (jint)GetDesktopWindow();
154 desktop_dc = (jint)GetDC((HWND)desktop_handle);
157 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
158 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
159 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
160 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
161 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
162 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
163 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
164 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
165 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
166 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
168 messagePumpThread = (jint)GetCurrentThreadId();
169 messagePumpStarted->release();
172 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
174 if (msg.message == WM_USER_CREATEWINDOW) {
175 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
177 // we must create a unique window class name for each
178 // window so that minimization icons can be set independantly
180 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
183 wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
184 wc.lpfnWndProc = WndProc;
186 wc.cbSize = sizeof(WNDCLASSEX);
188 wc.hInstance = GetModuleHandle(NULL);
189 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
190 wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL),
193 GetSystemMetrics(SM_CXSMICON),
194 GetSystemMetrics(SM_CYSMICON),
196 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
197 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
198 wc.lpszMenuName = "menu";
199 wc.lpszClassName = buf;
200 RegisterClassEx(&wc);
202 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""),
203 msg.wParam ? WS_NORMAL : WS_POPUP,
205 (HWND__*)NULL, (HMENU__*)NULL,
206 GetModuleHandle(NULL), (LPVOID)NULL);
209 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""),
210 (msg.wParam ? WS_NORMAL : WS_POPUP) | WS_SIZEBOX,
212 (HWND__*)NULL, (HMENU__*)NULL,
213 GetModuleHandle(NULL), (LPVOID)NULL);
216 SetFocus((HWND)surface->hwnd);
217 surface->hwndCreated->release();
220 TranslateMessage(&msg);
221 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
222 DispatchMessage(&msg);
226 java::lang::System::exit(-1);
230 // Platform Methods ///////////////////////////////////////////////////////////////////
232 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
233 int len = JvGetStringUTFLength(key);
235 JvGetStringUTFRegion(key, 0, len, buf);
238 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
239 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
243 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
247 memset(buf, 0, 1024);
248 memset(&ofn, 0, sizeof(OPENFILENAME));
250 if (suggestedFileName != NULL)
251 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
253 ofn.lStructSize = sizeof(OPENFILENAME);
254 ofn.nMaxCustFilter = 0;
258 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
259 ofn.Flags |= OFN_HIDEREADONLY;
261 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
262 return ret == 0 ? NULL : JvNewStringLatin1(buf);
265 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
271 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
272 if (result != ERROR_SUCCESS) return;
277 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
279 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
283 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
284 if (buf[0] != 1) return;
289 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
291 elements(container)[0] = JvNewStringLatin1(buf);
295 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
297 elements(container)[1] = JvNewStringLatin1(buf);
300 jstring org::xwt::plat::Win32::_getClipBoard() {
301 OpenClipboard((HWND)desktop_handle);
302 HGLOBAL hmem = GetClipboardData(CF_TEXT);
303 if (hmem == NULL) return NULL;
304 char* buf = (char*)GlobalLock(hmem);
305 if (buf == NULL) return NULL;
306 jstring ret = JvNewStringLatin1(buf);
312 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
313 OpenClipboard((HWND)desktop_handle);
314 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
315 if (hmem == NULL) return;
316 char* buf = (char*)GlobalLock(hmem);
317 if (buf == NULL) return;
318 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
319 buf[JvGetStringUTFLength(s)] = '\0';
321 SetClipboardData(CF_TEXT, hmem);
325 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
326 char buf[JvGetStringUTFLength(message) + 1];
327 buf[JvGetStringUTFLength(message)] = '\0';
328 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
329 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
330 java::lang::System::exit(-1);
333 jint org::xwt::plat::Win32::_getScreenWidth() {
335 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
336 return rect.right - rect.left;
339 jint org::xwt::plat::Win32::_getScreenHeight() {
341 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
342 return rect.bottom - rect.top;
345 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
347 int len = min(2048, JvGetStringUTFLength(url));
349 JvGetStringUTFRegion(url, 0, len, buf);
353 memset(&ei, 0, sizeof(ei));
354 ei.cbSize = sizeof(ei);
357 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
358 ei.nShow = SW_SHOWDEFAULT;
359 return (ShellExecuteEx(&ei) == 0);
364 // Win32PixelBuffer /////////////////////////////////////////////////////////////////////////
366 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
367 // Since all drawing operations are single-threaded, it's safe to use a global here.
368 static HBITMAP scratch = NULL;
369 static HDC scratch_dc = NULL;
370 static jint* scratch_bits = NULL;
371 static jint scratch_w = 0;
372 static jint scratch_h = 0;
374 #define max(a,b) ((a)>(b)?(a):(b))
375 #define min(a,b) ((a)<(b)?(a):(b))
377 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
379 jint cx1, jint cy1, jint cx2, jint cy2,
380 jint rgb, jboolean alphaOnly) {
381 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
385 cx2 = min(dx + source->getWidth(), cx2);
386 cy2 = min(dy + source->getHeight(), cy2);
387 if (cx1 >= cx2 || cy1 >= cy2) return;
389 if (source->hasalpha) {
391 if (scratch == NULL || scratch_w < cx2 - cx1 || scratch_h < cy2 - cy1) {
392 if (scratch_dc != NULL) DeleteDC(scratch_dc);
393 if (scratch != NULL) DeleteObject(scratch);
394 scratch_w = max(cx2 - cx1, scratch_w);
395 scratch_h = max(cy2 - cy1, scratch_h);
397 BITMAPINFO bitmapinfo;
398 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
399 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
400 bitmapinfo.bmiHeader.biWidth = scratch_w;
401 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
402 bitmapinfo.bmiHeader.biPlanes = 1;
403 bitmapinfo.bmiHeader.biBitCount = 32;
404 bitmapinfo.bmiHeader.biCompression = BI_RGB;
406 // create section DIB
407 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
408 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
409 SelectObject(scratch_dc, scratch);
412 // copy from screen to scratch
413 BitBlt((HDC)scratch_dc, 0, 0, cx2 - cx1, cy2 - cy1, (HDC)hdc, cx1, cy1, SRCCOPY);
415 // apply alpha-blending to scratch
416 jint* dat = elements(source->data);
418 for(int x = cx1; x < cx2; x++)
419 for(int y = cy1; y < cy2; y++) {
420 jint dst = scratch_bits[(y - dy) * scratch_w + (x - dx)];
422 // FEATURE: see if we can leverage GDI to do something more clever here with alphaOnly
423 jint src = alphaOnly ? rgb : dat[(y - dy) * source->getWidth() + x - dx];
424 jint alpha = (dat[(y - dy) * source->getWidth() + x - dx] & 0xFF000000) >> 24;
425 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
426 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
427 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
428 scratch_bits[(y - dy) * scratch_w + (x - dx)] = (r << 16) | (g << 8) | b;
431 // copy back from scratch to screen
432 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
436 // FIXME: support alphaOnly case here
437 if (source->hasmask) {
438 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->maskdc, cx1 - dx, cy1 - dy, SRCAND);
439 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCPAINT);
441 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCCOPY);
448 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
452 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
453 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
455 RECT rect = { x, y, x + w, y + h };
456 FillRect((HDC)hdc, &rect, brush);
460 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
461 // we create the DC lazily to get around some strange race condition in WinXP
462 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
463 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
466 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
467 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
468 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
469 SetBkMode((HDC)hdc, TRANSPARENT);
470 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
473 void org::xwt::plat::Win32$Win32PixelBuffer::finalize() {
474 DeleteObject((void*)hdc);
475 DeleteObject((void*)hbitmap);
480 // Win32Picture /////////////////////////////////////////////////////////////////////////
482 void org::xwt::plat::Win32$Win32Picture::natInit() {
484 BITMAPINFO bitmapinfo;
485 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
486 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
487 bitmapinfo.bmiHeader.biWidth = width;
488 bitmapinfo.bmiHeader.biHeight = -1 * height;
489 bitmapinfo.bmiHeader.biPlanes = 1;
490 bitmapinfo.bmiHeader.biBitCount = 32;
491 bitmapinfo.bmiHeader.biCompression = BI_RGB;
493 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, width, height);
494 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
495 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
496 uint32_t* dat = (uint32_t*)elements(data);
497 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
498 StretchDIBits((HDC)hdc, 0, 0, width, height, 0, 0, width, height, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
500 jint _copy[min(1024, data->length)];
501 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
503 memcpy(copy, elements(data), data->length * 4);
504 for(int i=0; i<data->length; i++)
505 if ((copy[i] & 0xFF000000) == 0x00000000) {
507 copy[i] = 0x00FFFFFF;
508 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
509 copy[i] = 0x00000000;
513 if (data->length > 1024) free(copy);
518 if (data->length > 1024) free(copy);
522 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
523 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, width, height);
524 maskdc = (jint)CreateCompatibleDC(NULL);
525 SelectObject((HDC)maskdc, (HBITMAP)hmask);
526 StretchDIBits((HDC)maskdc, 0, 0, width, height, 0, 0, width, height, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
527 if (data->length > 1024) free(copy);
532 // Win32Surface /////////////////////////////////////////////////////////////////////////////
534 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
536 // Ask the message-handling thread to create a window for us
537 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
538 hwndCreated->block();
540 // turn on incremental GC now that we have a user-visible interface
541 // [[this is causing segfaults; enable it later...]]
542 // GC_enable_incremental();
544 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
547 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
548 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
549 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
550 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
551 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
552 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
553 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
554 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
556 void org::xwt::plat::Win32$Win32Surface::setLocation() {
561 ClientToScreen((HWND)hwnd, &point);
562 GetWindowRect((HWND)hwnd, &rect);
563 SetWindowPos((HWND)hwnd, NULL, root->x - (point.x - rect.left), root->y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
566 void org::xwt::plat::Win32$Win32Surface::_setSize(jint w, jint h) {
567 RECT client_rect, window_rect;
568 GetClientRect((HWND)hwnd, &client_rect);
569 GetWindowRect((HWND)hwnd, &window_rect);
570 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
571 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
572 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
575 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
576 int len = min(1024, JvGetStringUTFLength(title));
579 JvGetStringUTFRegion(title, 0, len, buf);
580 SetWindowText((HWND)hwnd, buf);
583 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
585 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
586 int icon_width = GetSystemMetrics(SM_CXSMICON);
587 int icon_height = GetSystemMetrics(SM_CYSMICON);
589 // we create the DC lazily to get around some strange race condition in WinXP
590 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
593 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
594 HDC memdc = CreateCompatibleDC((HDC)hdc);
595 SelectObject(memdc, bit);
596 BitBlt((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, SRCCOPY);
599 jint* dat = elements(p->data);
600 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
601 SelectObject(memdc, bit_mask);
602 for(int x=0; x<icon_width; x++)
603 for(int y=0; y<icon_height; y++) {
604 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
605 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
606 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
609 // instantiate the icon and assign it to the window class
612 ici.hbmMask = bit_mask;
614 HICON hicon = CreateIconIndirect(&ici);
615 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
616 if (oldicon != NULL) DestroyIcon(oldicon);
620 static jstring keyToString(WPARAM wParam);
621 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
623 UINT iMsg = (UINT)_iMsg;
624 WPARAM wParam = (WPARAM)_wParam;
625 LPARAM lParam = (LPARAM)_lParam;
627 int oldmousex, oldmousey;
633 RECT client_rect, window_rect;
637 int addwidth, addheight;
640 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
641 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
642 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
644 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
646 KeyPressed(keyToString(wParam));
649 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
651 KeyReleased(keyToString(wParam));
654 case WM_SETFOCUS: Focused(true); return 0;
655 case WM_KILLFOCUS: Focused(false); return 0;
656 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
657 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
658 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
659 case WM_LBUTTONDOWN: Press(1); return 0;
660 case WM_RBUTTONDOWN: Press(2); return 0;
661 case WM_MBUTTONDOWN: Press(3); return 0;
662 case WM_CLOSE: Close(); return 0;
663 case WM_ERASEBKGND: return 0;
668 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
669 if (captured && !inside) {
671 SetCursor((HCURSOR)previous_cursor);
676 GetClientRect((HWND)hwnd, &rect);
677 PosChange(rect.left, rect.top);
681 if (wParam == SIZE_MINIMIZED) {
682 if (maximized) Maximized(false);
684 } else if (wParam == SIZE_MAXIMIZED) {
685 if (minimized) Minimized(false);
688 if (minimized) Minimized(false);
689 if (maximized) Maximized(false);
691 // deliberately fall through to WM_SIZING
694 GetClientRect((HWND)hwnd, &rect);
695 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
699 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
701 GetClientRect((HWND)hwnd, &rect);
702 point.x = mouse_x = lParam & 0xFFFF;
703 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
704 ClientToScreen((HWND)hwnd, &point);
705 hwnd2 = WindowFromPoint(point);
707 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
709 Move(mouse_x, mouse_y);
711 if (newinside && !inside) {
713 SetCapture((HWND)hwnd);
715 previous_cursor = (jint)GetCursor();
716 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
718 } else if (!newinside && inside) {
720 if (!button1 && !button2 && !button3) {
723 SetCursor((HCURSOR)previous_cursor);
729 case WM_USER_SETCURSOR:
730 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
731 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
732 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
733 // cursor should be re-set to "current_cursor".
734 SetCursor((HCURSOR)current_cursor);
737 case WM_USER_DISPOSE:
738 // used to signal that we should destroy ourselves
739 DestroyWindow((HWND)hwnd);
742 case WM_GETMINMAXINFO:
743 GetClientRect((HWND)hwnd, &client_rect);
744 GetWindowRect((HWND)hwnd, &window_rect);
745 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
746 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
747 mmi = (MINMAXINFO*)lParam;
748 mmi->ptMinTrackSize.x = ((uint32_t)root->minwidth) + addwidth;
749 mmi->ptMinTrackSize.y = ((uint32_t)root->minheight) + addheight;
750 resizable = !((root->minwidth == root->maxwidth) && (root->minheight == root->maxheight));
751 mmi->ptMaxTrackSize.x = resizable ? org::xwt::plat::Win32::getScreenWidth() : mmi->ptMinTrackSize.x;
752 mmi->ptMaxTrackSize.y = resizable ? org::xwt::plat::Win32::getScreenHeight() : mmi->ptMinTrackSize.y;
757 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
758 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
759 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
765 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
769 // Key Translator Helper /////////////////////////////////////////////////////////////////////
771 static char keyarr [256] = { 0 };
772 static jstring keyToString(WPARAM wParam) {
774 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
775 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
776 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
777 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
779 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
781 case '\t': return JvNewStringLatin1("tab");
782 case 0x1b: return JvNewStringLatin1("escape");
783 case '\n': return JvNewStringLatin1("enter");
784 case '\r': return JvNewStringLatin1("enter");
785 case 0x08: return JvNewStringLatin1("back_space");
786 default: return JvNewStringLatin1(arr, 1);
789 } else switch (wParam) {
790 case VK_CLEAR: return JvNewStringLatin1("clear");
791 case VK_SHIFT: return JvNewStringLatin1("shift");
792 case VK_CONTROL: return JvNewStringLatin1("control");
793 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
794 case VK_MENU: return JvNewStringLatin1("alt");
795 case VK_PAUSE: return JvNewStringLatin1("pause");
796 case VK_PRIOR: return JvNewStringLatin1("page_up");
797 case VK_NEXT: return JvNewStringLatin1("page_down");
798 case VK_END: return JvNewStringLatin1("end");
799 case VK_HOME: return JvNewStringLatin1("home");
800 case VK_LEFT: return JvNewStringLatin1("left");
801 case VK_UP: return JvNewStringLatin1("up");
802 case VK_RIGHT: return JvNewStringLatin1("right");
803 case VK_DOWN: return JvNewStringLatin1("down");
804 case VK_INSERT: return JvNewStringLatin1("insert");
805 case VK_DELETE: return JvNewStringLatin1("delete");
806 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
807 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
808 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
809 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
810 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
811 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
812 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
813 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
814 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
815 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
816 case VK_F1: return JvNewStringLatin1("f1");
817 case VK_F2: return JvNewStringLatin1("f2");
818 case VK_F3: return JvNewStringLatin1("f3");
819 case VK_F4: return JvNewStringLatin1("f4");
820 case VK_F5: return JvNewStringLatin1("f5");
821 case VK_F6: return JvNewStringLatin1("f6");
822 case VK_F7: return JvNewStringLatin1("f7");
823 case VK_F8: return JvNewStringLatin1("f8");
824 case VK_F9: return JvNewStringLatin1("f9");
825 case VK_F10: return JvNewStringLatin1("f10");
826 case VK_F11: return JvNewStringLatin1("f11");
827 case VK_F12: return JvNewStringLatin1("f12");
828 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
829 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
830 case VK_LSHIFT: return JvNewStringLatin1("shift");
831 case VK_RSHIFT: return JvNewStringLatin1("shift");
832 case VK_LCONTROL: return JvNewStringLatin1("control");
833 case VK_RCONTROL: return JvNewStringLatin1("control");