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_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
184 wc.lpfnWndProc = WndProc;
186 wc.cbSize = sizeof(WNDCLASSEX);
188 wc.hInstance = GetModuleHandle(NULL);
192 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
193 wc.lpszMenuName = NULL;
194 wc.lpszClassName = buf;
195 RegisterClassEx(&wc);
197 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
198 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
199 SetFocus((HWND)surface->hwnd);
200 surface->hwndCreated->release();
203 TranslateMessage(&msg);
204 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
205 DispatchMessage(&msg);
209 java::lang::System::exit(-1);
213 // Platform Methods ///////////////////////////////////////////////////////////////////
215 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
216 int len = JvGetStringUTFLength(key);
218 JvGetStringUTFRegion(key, 0, len, buf);
221 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
222 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
226 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
230 memset(buf, 0, 1024);
231 memset(&ofn, 0, sizeof(OPENFILENAME));
233 if (suggestedFileName != NULL)
234 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
236 ofn.lStructSize = sizeof(OPENFILENAME);
237 ofn.nMaxCustFilter = 0;
241 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
242 ofn.Flags |= OFN_HIDEREADONLY;
244 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
245 return ret == 0 ? NULL : JvNewStringLatin1(buf);
248 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
254 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
255 if (result != ERROR_SUCCESS) return;
260 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
262 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
266 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
267 if (buf[0] != 1) return;
272 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
274 elements(container)[0] = JvNewStringLatin1(buf);
278 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
280 elements(container)[1] = JvNewStringLatin1(buf);
283 jstring org::xwt::plat::Win32::_getClipBoard() {
284 OpenClipboard((HWND)desktop_handle);
285 HGLOBAL hmem = GetClipboardData(CF_TEXT);
286 if (hmem == NULL) return NULL;
287 char* buf = (char*)GlobalLock(hmem);
288 if (buf == NULL) return NULL;
289 jstring ret = JvNewStringLatin1(buf);
295 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
296 OpenClipboard((HWND)desktop_handle);
297 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
298 if (hmem == NULL) return;
299 char* buf = (char*)GlobalLock(hmem);
300 if (buf == NULL) return;
301 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
302 buf[JvGetStringUTFLength(s)] = '\0';
304 SetClipboardData(CF_TEXT, hmem);
308 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
309 char buf[JvGetStringUTFLength(message) + 1];
310 buf[JvGetStringUTFLength(message)] = '\0';
311 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
312 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
313 java::lang::System::exit(-1);
316 jint org::xwt::plat::Win32::_getScreenWidth() {
318 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
319 return rect.right - rect.left;
322 jint org::xwt::plat::Win32::_getScreenHeight() {
324 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
325 return rect.bottom - rect.top;
328 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
330 int len = min(2048, JvGetStringUTFLength(url));
332 JvGetStringUTFRegion(url, 0, len, buf);
336 memset(&ei, 0, sizeof(ei));
337 ei.cbSize = sizeof(ei);
340 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
341 ei.nShow = SW_SHOWDEFAULT;
342 return (ShellExecuteEx(&ei) == 0);
347 // Win32PixelBuffer /////////////////////////////////////////////////////////////////////////
349 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
350 // Since all drawing operations are single-threaded, it's safe to use a global here.
351 static HBITMAP scratch = NULL;
352 static HDC scratch_dc = NULL;
353 static jint* scratch_bits = NULL;
354 static jint scratch_w = 0;
355 static jint scratch_h = 0;
357 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
358 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
359 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
361 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
363 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
364 jint dx1, jint dy1, jint dx2, jint dy2,
365 jint sx1, jint sy1, jint sx2, jint sy2,
366 jint rgb, jboolean alphaOnly) {
367 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
369 if (source->hasalpha) {
371 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
372 if (scratch_dc != NULL) DeleteDC(scratch_dc);
373 if (scratch != NULL) DeleteObject(scratch);
374 scratch_w = max(dx2 - dx1, scratch_w);
375 scratch_h = max(dy2 - dy1, scratch_h);
377 BITMAPINFO bitmapinfo;
378 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
379 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
380 bitmapinfo.bmiHeader.biWidth = scratch_w;
381 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
382 bitmapinfo.bmiHeader.biPlanes = 1;
383 bitmapinfo.bmiHeader.biBitCount = 32;
384 bitmapinfo.bmiHeader.biCompression = BI_RGB;
386 // create section DIB
387 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
388 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
389 SelectObject(scratch_dc, scratch);
392 // copy from screen to scratch
393 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
395 // apply alpha-blending to scratch
396 jint* dat = elements(source->data);
398 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
399 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
400 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
401 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
402 jint dst = scratch_bits[y * scratch_w + x];
404 // FEATURE: see if we can leverage GDI to do something more clever here with alphaOnly
405 jint src = alphaOnly ? rgb : dat[sy * source->getWidth() + sx];
406 jint alpha = (dat[sy * source->getWidth() + sx] & 0xFF000000) >> 24;
407 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
408 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
409 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
410 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
413 // copy back from scratch to screen
414 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
418 // FIXME: support alphaOnly case here
419 if (source->hasmask) {
420 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
421 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
423 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
430 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
434 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
435 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
437 RECT rect = { x, y, x + w, y + h };
438 FillRect((HDC)hdc, &rect, brush);
442 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
443 // we create the DC lazily to get around some strange race condition in WinXP
444 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
445 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
448 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
449 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
450 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
451 SetBkMode((HDC)hdc, TRANSPARENT);
452 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
455 void org::xwt::plat::Win32$Win32PixelBuffer::setClip(jint x, jint y, jint x2, jint y2) {
456 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
457 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
458 SelectClipRgn((HDC)hdc, hrgn);
462 void org::xwt::plat::Win32$Win32PixelBuffer::finalize() {
463 DeleteObject((void*)hdc);
464 DeleteObject((void*)hbitmap);
469 // Win32Picture /////////////////////////////////////////////////////////////////////////
471 void org::xwt::plat::Win32$Win32Picture::natInit() {
473 BITMAPINFO bitmapinfo;
474 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
475 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
476 bitmapinfo.bmiHeader.biWidth = w;
477 bitmapinfo.bmiHeader.biHeight = -1 * h;
478 bitmapinfo.bmiHeader.biPlanes = 1;
479 bitmapinfo.bmiHeader.biBitCount = 32;
480 bitmapinfo.bmiHeader.biCompression = BI_RGB;
482 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
483 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
484 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
485 uint32_t* dat = (uint32_t*)elements(data);
486 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
487 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
489 jint _copy[min(1024, data->length)];
490 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
492 memcpy(copy, elements(data), data->length * 4);
493 for(int i=0; i<data->length; i++)
494 if ((copy[i] & 0xFF000000) == 0x00000000) {
496 copy[i] = 0x00FFFFFF;
497 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
498 copy[i] = 0x00000000;
502 if (data->length > 1024) free(copy);
507 if (data->length > 1024) free(copy);
511 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
512 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
513 maskdc = (jint)CreateCompatibleDC(NULL);
514 SelectObject((HDC)maskdc, (HBITMAP)hmask);
515 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
516 if (data->length > 1024) free(copy);
521 // Win32Surface /////////////////////////////////////////////////////////////////////////////
523 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
525 // Ask the message-handling thread to create a window for us
526 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
527 hwndCreated->block();
529 // turn on incremental GC now that we have a user-visible interface
530 // [[this is causing segfaults; enable it later...]]
531 // GC_enable_incremental();
533 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
536 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
537 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
538 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
539 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
540 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
541 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
542 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
543 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
545 void org::xwt::plat::Win32$Win32Surface::setLocation() {
550 ClientToScreen((HWND)hwnd, &point);
551 GetWindowRect((HWND)hwnd, &rect);
552 SetWindowPos((HWND)hwnd, NULL, root->x - (point.x - rect.left), root->y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
555 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
556 RECT client_rect, window_rect;
557 GetClientRect((HWND)hwnd, &client_rect);
558 GetWindowRect((HWND)hwnd, &window_rect);
559 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
560 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
561 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
564 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
565 int len = min(1024, JvGetStringUTFLength(title));
568 JvGetStringUTFRegion(title, 0, len, buf);
569 SetWindowText((HWND)hwnd, buf);
572 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
574 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
575 int icon_width = GetSystemMetrics(SM_CXSMICON);
576 int icon_height = GetSystemMetrics(SM_CYSMICON);
578 // we create the DC lazily to get around some strange race condition in WinXP
579 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
582 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
583 HDC memdc = CreateCompatibleDC((HDC)hdc);
584 SelectObject(memdc, bit);
585 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
588 jint* dat = elements(p->data);
589 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
590 SelectObject(memdc, bit_mask);
591 for(int x=0; x<icon_width; x++)
592 for(int y=0; y<icon_height; y++) {
593 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
594 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
595 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
598 // instantiate the icon and assign it to the window class
601 ici.hbmMask = bit_mask;
603 HICON hicon = CreateIconIndirect(&ici);
604 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
605 if (oldicon != NULL) DestroyIcon(oldicon);
609 static jstring keyToString(WPARAM wParam);
610 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
612 UINT iMsg = (UINT)_iMsg;
613 WPARAM wParam = (WPARAM)_wParam;
614 LPARAM lParam = (LPARAM)_lParam;
616 int oldmousex, oldmousey;
621 RECT client_rect, window_rect;
625 int addwidth, addheight;
628 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
629 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
630 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
632 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
634 KeyPressed(keyToString(wParam));
637 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
639 KeyReleased(keyToString(wParam));
642 case WM_SETFOCUS: Focused(true); return 0;
643 case WM_KILLFOCUS: Focused(false); return 0;
644 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
645 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
646 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
647 case WM_LBUTTONDOWN: Press(1); return 0;
648 case WM_RBUTTONDOWN: Press(2); return 0;
649 case WM_MBUTTONDOWN: Press(3); return 0;
650 case WM_CLOSE: Close(); return 0;
651 case WM_ERASEBKGND: return 0;
656 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
657 if (captured && !inside) {
659 SetCursor((HCURSOR)previous_cursor);
664 GetClientRect((HWND)hwnd, &rect);
665 PosChange(rect.left, rect.top);
669 if (wParam == SIZE_MINIMIZED) {
670 if (maximized) Maximized(false);
672 } else if (wParam == SIZE_MAXIMIZED) {
673 if (minimized) Minimized(false);
676 if (minimized) Minimized(false);
677 if (maximized) Maximized(false);
679 // deliberately fall through to WM_SIZING
682 GetClientRect((HWND)hwnd, &rect);
683 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
687 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
689 GetClientRect((HWND)hwnd, &rect);
690 point.x = mouse_x = lParam & 0xFFFF;
691 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
692 ClientToScreen((HWND)hwnd, &point);
693 hwnd2 = WindowFromPoint(point);
695 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
697 Move(mouse_x, mouse_y);
699 if (newinside && !inside) {
701 SetCapture((HWND)hwnd);
703 previous_cursor = (jint)GetCursor();
704 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
706 } else if (!newinside && inside) {
708 if (!button1 && !button2 && !button3) {
711 SetCursor((HCURSOR)previous_cursor);
717 case WM_USER_SETCURSOR:
718 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
719 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
720 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
721 // cursor should be re-set to "current_cursor".
722 SetCursor((HCURSOR)current_cursor);
725 case WM_USER_DISPOSE:
726 // used to signal that we should destroy ourselves
727 DestroyWindow((HWND)hwnd);
730 case WM_GETMINMAXINFO:
731 GetClientRect((HWND)hwnd, &client_rect);
732 GetWindowRect((HWND)hwnd, &window_rect);
733 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
734 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
735 mmi = (MINMAXINFO*)lParam;
736 mmi->ptMinTrackSize.x = ((uint32_t)root->minwidth) + addwidth;
737 mmi->ptMinTrackSize.y = ((uint32_t)root->minheight) + addheight;
738 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->maxwidth) + addwidth);
739 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->maxheight) + addheight);
744 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
745 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
746 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
752 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
756 // Key Translator Helper /////////////////////////////////////////////////////////////////////
758 static char keyarr [256] = { 0 };
759 static jstring keyToString(WPARAM wParam) {
761 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
762 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
763 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
764 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
766 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
768 case '\t': return JvNewStringLatin1("tab");
769 case 0x1b: return JvNewStringLatin1("escape");
770 case '\n': return JvNewStringLatin1("enter");
771 case '\r': return JvNewStringLatin1("enter");
772 case 0x08: return JvNewStringLatin1("back_space");
773 default: return JvNewStringLatin1(arr, 1);
776 } else switch (wParam) {
777 case VK_CLEAR: return JvNewStringLatin1("clear");
778 case VK_SHIFT: return JvNewStringLatin1("shift");
779 case VK_CONTROL: return JvNewStringLatin1("control");
780 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
781 case VK_MENU: return JvNewStringLatin1("alt");
782 case VK_PAUSE: return JvNewStringLatin1("pause");
783 case VK_PRIOR: return JvNewStringLatin1("page_up");
784 case VK_NEXT: return JvNewStringLatin1("page_down");
785 case VK_END: return JvNewStringLatin1("end");
786 case VK_HOME: return JvNewStringLatin1("home");
787 case VK_LEFT: return JvNewStringLatin1("left");
788 case VK_UP: return JvNewStringLatin1("up");
789 case VK_RIGHT: return JvNewStringLatin1("right");
790 case VK_DOWN: return JvNewStringLatin1("down");
791 case VK_INSERT: return JvNewStringLatin1("insert");
792 case VK_DELETE: return JvNewStringLatin1("delete");
793 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
794 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
795 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
796 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
797 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
798 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
799 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
800 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
801 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
802 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
803 case VK_F1: return JvNewStringLatin1("f1");
804 case VK_F2: return JvNewStringLatin1("f2");
805 case VK_F3: return JvNewStringLatin1("f3");
806 case VK_F4: return JvNewStringLatin1("f4");
807 case VK_F5: return JvNewStringLatin1("f5");
808 case VK_F6: return JvNewStringLatin1("f6");
809 case VK_F7: return JvNewStringLatin1("f7");
810 case VK_F8: return JvNewStringLatin1("f8");
811 case VK_F9: return JvNewStringLatin1("f9");
812 case VK_F10: return JvNewStringLatin1("f10");
813 case VK_F11: return JvNewStringLatin1("f11");
814 case VK_F12: return JvNewStringLatin1("f12");
815 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
816 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
817 case VK_LSHIFT: return JvNewStringLatin1("shift");
818 case VK_RSHIFT: return JvNewStringLatin1("shift");
819 case VK_LCONTROL: return JvNewStringLatin1("control");
820 case VK_RCONTROL: return JvNewStringLatin1("control");