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/Box.h>
23 #include <java/lang/Integer.h>
24 #include <java/util/Hashtable.h>
25 #include <org/xwt/Box.h>
26 #include <org/xwt/Surface.h>
27 #include <org/xwt/PixelBuffer.h>
28 #include <org/xwt/Picture.h>
29 #include <org/xwt/Platform.h>
30 #include <org/xwt/plat/Win32.h>
31 #include <org/xwt/plat/Win32$Win32Surface.h>
32 #include <org/xwt/plat/Win32$Win32PixelBuffer.h>
33 #include <org/xwt/plat/Win32$Win32Picture.h>
34 #include <org/xwt/util/Log.h>
35 #include <org/xwt/util/Semaphore.h>
38 #include <java/lang/System.h>
39 #include <java/io/PrintStream.h>
41 #define WM_USER_SETCURSOR WM_USER
42 #define WM_USER_DISPOSE (WM_USER + 1)
43 #define WM_USER_CREATEWINDOW (WM_USER + 2)
44 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
46 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
47 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
49 // Callbacks ////////////////////////////////////////////////////////////////////
51 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
52 org::xwt::plat::Win32$Win32Surface* surface =
53 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
55 if (surface != NULL) {
56 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
59 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
60 return DefWindowProc(hwnd, iMsg, wParam, lParam);
65 // Initialization ////////////////////////////////////////////////////////////////////
67 static int window_class_counter = 0;
69 jstring org::xwt::plat::Win32::getTempPath() {
71 DWORD ret = GetTempPath(1024, buf);
72 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
73 return JvNewStringLatin1(buf);
76 // XOR mask for the hand cursor
77 static unsigned char hand_cursor_xor[32 * 4] = {
78 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x0C, 0x00, 0x00,
80 0x00, 0x0C, 0x00, 0x00,
81 0x00, 0x0C, 0x00, 0x00,
82 0x00, 0x0C, 0x00, 0x00,
83 0x00, 0x0C, 0x00, 0x00,
84 0x00, 0x0D, 0x80, 0x00,
85 0x00, 0x0D, 0xB0, 0x00,
86 0x00, 0x0D, 0xB4, 0x00,
87 0x00, 0x0D, 0xB6, 0x00,
88 0x00, 0xCF, 0xF6, 0x00,
89 0x00, 0xEF, 0xFE, 0x00,
90 0x00, 0x6F, 0xFE, 0x00,
91 0x00, 0x2F, 0xFE, 0x00,
92 0x00, 0x3F, 0xFE, 0x00,
93 0x00, 0x1F, 0xFE, 0x00,
94 0x00, 0x1F, 0xFC, 0x00,
95 0x00, 0x0F, 0xFC, 0x00,
96 0x00, 0x0F, 0xFC, 0x00,
97 0x00, 0x07, 0xF8, 0x00,
98 0x00, 0x07, 0xF8, 0x00,
99 0x00, 0x00, 0x00, 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
112 // AND mask for the hand cursor
113 static unsigned char hand_cursor_and[32 * 4] = {
114 0xFF, 0xF3, 0xFF, 0xFF,
115 0xFF, 0xE1, 0xFF, 0xFF,
116 0xFF, 0xE1, 0xFF, 0xFF,
117 0xFF, 0xE1, 0xFF, 0xFF,
118 0xFF, 0xE1, 0xFF, 0xFF,
119 0xFF, 0xE0, 0x7F, 0xFF,
120 0xFF, 0xE0, 0x0F, 0xFF,
121 0xFF, 0xE0, 0x03, 0xFF,
122 0xFF, 0xE0, 0x01, 0xFF,
123 0xFF, 0x20, 0x00, 0xFF,
124 0xFE, 0x00, 0x00, 0xFF,
125 0xFE, 0x00, 0x00, 0xFF,
126 0xFF, 0x00, 0x00, 0xFF,
127 0xFF, 0x80, 0x00, 0xFF,
128 0xFF, 0x80, 0x00, 0xFF,
129 0xFF, 0xC0, 0x00, 0xFF,
130 0xFF, 0xC0, 0x01, 0xFF,
131 0xFF, 0xE0, 0x01, 0xFF,
132 0xFF, 0xE0, 0x01, 0xFF,
133 0xFF, 0xF0, 0x03, 0xFF,
134 0xFF, 0xF0, 0x03, 0xFF,
135 0xFF, 0xF0, 0x03, 0xFF,
136 0xFF, 0xFF, 0xFF, 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
149 void org::xwt::plat::Win32::natInit() {
151 // grab desktop dc/handle
152 desktop_handle = (jint)GetDesktopWindow();
153 desktop_dc = (jint)GetDC((HWND)desktop_handle);
156 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
157 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
158 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
159 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
160 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
161 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
162 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
163 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
164 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
165 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
167 messagePumpThread = (jint)GetCurrentThreadId();
168 messagePumpStarted->release();
171 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
173 if (msg.message == WM_USER_CREATEWINDOW) {
174 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
176 // we must create a unique window class name for each
177 // window so that minimization icons can be set independantly
179 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
182 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
183 wc.lpfnWndProc = WndProc;
185 wc.cbSize = sizeof(WNDCLASSEX);
187 wc.hInstance = GetModuleHandle(NULL);
191 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
192 wc.lpszMenuName = NULL;
193 wc.lpszClassName = buf;
194 RegisterClassEx(&wc);
196 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
197 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
198 SetFocus((HWND)surface->hwnd);
199 surface->hwndCreated->release();
202 TranslateMessage(&msg);
203 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
204 DispatchMessage(&msg);
208 java::lang::System::exit(-1);
212 // Platform Methods ///////////////////////////////////////////////////////////////////
214 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
215 int len = JvGetStringUTFLength(key);
217 JvGetStringUTFRegion(key, 0, len, buf);
220 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
221 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
225 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
229 memset(buf, 0, 1024);
230 memset(&ofn, 0, sizeof(OPENFILENAME));
232 if (suggestedFileName != NULL)
233 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
235 ofn.lStructSize = sizeof(OPENFILENAME);
236 ofn.nMaxCustFilter = 0;
240 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
241 ofn.Flags |= OFN_HIDEREADONLY;
243 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
244 return ret == 0 ? NULL : JvNewStringLatin1(buf);
247 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
253 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
254 if (result != ERROR_SUCCESS) return;
259 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
261 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
265 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
266 if (buf[0] != 1) return;
271 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
273 elements(container)[0] = JvNewStringLatin1(buf);
277 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
279 elements(container)[1] = JvNewStringLatin1(buf);
282 jstring org::xwt::plat::Win32::_getClipBoard() {
283 OpenClipboard((HWND)desktop_handle);
284 HGLOBAL hmem = GetClipboardData(CF_TEXT);
285 if (hmem == NULL) return NULL;
286 char* buf = (char*)GlobalLock(hmem);
287 if (buf == NULL) return NULL;
288 jstring ret = JvNewStringLatin1(buf);
294 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
295 OpenClipboard((HWND)desktop_handle);
296 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
297 if (hmem == NULL) return;
298 char* buf = (char*)GlobalLock(hmem);
299 if (buf == NULL) return;
300 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
301 buf[JvGetStringUTFLength(s)] = '\0';
303 SetClipboardData(CF_TEXT, hmem);
307 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
308 char buf[JvGetStringUTFLength(message) + 1];
309 buf[JvGetStringUTFLength(message)] = '\0';
310 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
311 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
312 java::lang::System::exit(-1);
315 jint org::xwt::plat::Win32::_getScreenWidth() {
317 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
318 return rect.right - rect.left;
321 jint org::xwt::plat::Win32::_getScreenHeight() {
323 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
324 return rect.bottom - rect.top;
327 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
329 int len = min(2048, JvGetStringUTFLength(url));
331 JvGetStringUTFRegion(url, 0, len, buf);
335 memset(&ei, 0, sizeof(ei));
336 ei.cbSize = sizeof(ei);
339 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
340 ei.nShow = SW_SHOWDEFAULT;
341 return (ShellExecuteEx(&ei) == 0);
346 // Win32PixelBuffer /////////////////////////////////////////////////////////////////////////
348 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
349 // Since all drawing operations are single-threaded, it's safe to use a global here.
350 static HBITMAP scratch = NULL;
351 static HDC scratch_dc = NULL;
352 static jint* scratch_bits = NULL;
353 static jint scratch_w = 0;
354 static jint scratch_h = 0;
356 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
357 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
358 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
360 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
362 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
363 jint dx1, jint dy1, jint dx2, jint dy2,
364 jint sx1, jint sy1, jint sx2, jint sy2) {
365 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
367 if (source->hasalpha) {
369 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
370 if (scratch_dc != NULL) DeleteDC(scratch_dc);
371 if (scratch != NULL) DeleteObject(scratch);
372 scratch_w = max(dx2 - dx1, scratch_w);
373 scratch_h = max(dy2 - dy1, scratch_h);
375 BITMAPINFO bitmapinfo;
376 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
377 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
378 bitmapinfo.bmiHeader.biWidth = scratch_w;
379 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
380 bitmapinfo.bmiHeader.biPlanes = 1;
381 bitmapinfo.bmiHeader.biBitCount = 32;
382 bitmapinfo.bmiHeader.biCompression = BI_RGB;
384 // create section DIB
385 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
386 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
387 SelectObject(scratch_dc, scratch);
390 // copy from screen to scratch
391 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
393 // apply alpha-blending to scratch
394 jint* dat = elements(source->data);
396 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
397 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
398 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
399 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
400 jint dst = scratch_bits[y * scratch_w + x];
401 jint src = dat[sy * source->getWidth() + sx];
402 jint alpha = (src & 0xFF000000) >> 24;
403 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
404 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
405 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
406 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
409 // copy back from scratch to screen
410 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
413 if (source->hasmask) {
414 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
415 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
417 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
424 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
428 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
429 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
431 RECT rect = { x, y, x + w, y + h };
432 FillRect((HDC)hdc, &rect, brush);
436 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
437 // we create the DC lazily to get around some strange race condition in WinXP
438 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
439 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
442 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
443 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
444 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
445 SetBkMode((HDC)hdc, TRANSPARENT);
446 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
449 void org::xwt::plat::Win32$Win32PixelBuffer::setClip(jint x, jint y, jint x2, jint y2) {
450 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
451 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
452 SelectClipRgn((HDC)hdc, hrgn);
456 void org::xwt::plat::Win32$Win32PixelBuffer::finalize() {
457 DeleteObject((void*)hdc);
458 DeleteObject((void*)hbitmap);
463 // Win32Picture /////////////////////////////////////////////////////////////////////////
465 void org::xwt::plat::Win32$Win32Picture::natInit() {
467 BITMAPINFO bitmapinfo;
468 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
469 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
470 bitmapinfo.bmiHeader.biWidth = w;
471 bitmapinfo.bmiHeader.biHeight = -1 * h;
472 bitmapinfo.bmiHeader.biPlanes = 1;
473 bitmapinfo.bmiHeader.biBitCount = 32;
474 bitmapinfo.bmiHeader.biCompression = BI_RGB;
476 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
477 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
478 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
479 uint32_t* dat = (uint32_t*)elements(data);
480 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
481 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
483 jint _copy[min(1024, data->length)];
484 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
486 memcpy(copy, elements(data), data->length * 4);
487 for(int i=0; i<data->length; i++)
488 if ((copy[i] & 0xFF000000) == 0x00000000) {
490 copy[i] = 0x00FFFFFF;
491 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
492 copy[i] = 0x00000000;
496 if (data->length > 1024) free(copy);
501 if (data->length > 1024) free(copy);
505 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
506 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
507 maskdc = (jint)CreateCompatibleDC(NULL);
508 SelectObject((HDC)maskdc, (HBITMAP)hmask);
509 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
510 if (data->length > 1024) free(copy);
515 // Win32Surface /////////////////////////////////////////////////////////////////////////////
517 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
519 // Ask the message-handling thread to create a window for us
520 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
521 hwndCreated->block();
523 // turn on incremental GC now that we have a user-visible interface
524 // [[this is causing segfaults; enable it later...]]
525 // GC_enable_incremental();
527 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
530 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
531 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
532 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
533 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
534 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
535 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
536 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
537 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
539 void org::xwt::plat::Win32$Win32Surface::setLocation() {
544 ClientToScreen((HWND)hwnd, &point);
545 GetWindowRect((HWND)hwnd, &rect);
546 SetWindowPos((HWND)hwnd, NULL, root->x - (point.x - rect.left), root->y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
549 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
550 RECT client_rect, window_rect;
551 GetClientRect((HWND)hwnd, &client_rect);
552 GetWindowRect((HWND)hwnd, &window_rect);
553 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
554 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
555 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
558 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
559 int len = min(1024, JvGetStringUTFLength(title));
562 JvGetStringUTFRegion(title, 0, len, buf);
563 SetWindowText((HWND)hwnd, buf);
566 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
568 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
569 int icon_width = GetSystemMetrics(SM_CXSMICON);
570 int icon_height = GetSystemMetrics(SM_CYSMICON);
572 // we create the DC lazily to get around some strange race condition in WinXP
573 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
576 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
577 HDC memdc = CreateCompatibleDC((HDC)hdc);
578 SelectObject(memdc, bit);
579 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
582 jint* dat = elements(p->data);
583 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
584 SelectObject(memdc, bit_mask);
585 for(int x=0; x<icon_width; x++)
586 for(int y=0; y<icon_height; y++) {
587 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
588 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
589 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
592 // instantiate the icon and assign it to the window class
595 ici.hbmMask = bit_mask;
597 HICON hicon = CreateIconIndirect(&ici);
598 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
599 if (oldicon != NULL) DestroyIcon(oldicon);
603 static jstring keyToString(WPARAM wParam);
604 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
606 UINT iMsg = (UINT)_iMsg;
607 WPARAM wParam = (WPARAM)_wParam;
608 LPARAM lParam = (LPARAM)_lParam;
610 int oldmousex, oldmousey;
615 RECT client_rect, window_rect;
619 int addwidth, addheight;
622 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
623 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
624 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
626 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
628 KeyPressed(keyToString(wParam));
631 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
633 KeyReleased(keyToString(wParam));
636 case WM_SETFOCUS: Focused(true); return 0;
637 case WM_KILLFOCUS: Focused(false); return 0;
638 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
639 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
640 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
641 case WM_LBUTTONDOWN: Press(1); return 0;
642 case WM_RBUTTONDOWN: Press(2); return 0;
643 case WM_MBUTTONDOWN: Press(3); return 0;
644 case WM_CLOSE: Close(); return 0;
645 case WM_ERASEBKGND: return 0;
650 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
651 if (captured && !inside) {
653 SetCursor((HCURSOR)previous_cursor);
658 GetClientRect((HWND)hwnd, &rect);
659 PosChange(rect.left, rect.top);
663 if (wParam == SIZE_MINIMIZED) {
664 if (maximized) Maximized(false);
666 } else if (wParam == SIZE_MAXIMIZED) {
667 if (minimized) Minimized(false);
670 if (minimized) Minimized(false);
671 if (maximized) Maximized(false);
673 // deliberately fall through to WM_SIZING
676 GetClientRect((HWND)hwnd, &rect);
677 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
681 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
683 GetClientRect((HWND)hwnd, &rect);
684 point.x = mouse_x = lParam & 0xFFFF;
685 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
686 ClientToScreen((HWND)hwnd, &point);
687 hwnd2 = WindowFromPoint(point);
689 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
691 Move(mouse_x, mouse_y);
693 if (newinside && !inside) {
695 SetCapture((HWND)hwnd);
697 previous_cursor = (jint)GetCursor();
698 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
700 } else if (!newinside && inside) {
702 if (!button1 && !button2 && !button3) {
705 SetCursor((HCURSOR)previous_cursor);
711 case WM_USER_SETCURSOR:
712 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
713 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
714 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
715 // cursor should be re-set to "current_cursor".
716 SetCursor((HCURSOR)current_cursor);
719 case WM_USER_DISPOSE:
720 // used to signal that we should destroy ourselves
721 DestroyWindow((HWND)hwnd);
724 case WM_GETMINMAXINFO:
725 GetClientRect((HWND)hwnd, &client_rect);
726 GetWindowRect((HWND)hwnd, &window_rect);
727 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
728 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
729 mmi = (MINMAXINFO*)lParam;
730 mmi->ptMinTrackSize.x = ((uint32_t)root->minwidth) + addwidth;
731 mmi->ptMinTrackSize.y = ((uint32_t)root->minheight) + addheight;
732 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->maxwidth) + addwidth);
733 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->maxheight) + addheight);
738 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
739 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
740 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
746 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
750 // Key Translator Helper /////////////////////////////////////////////////////////////////////
752 static char keyarr [256] = { 0 };
753 static jstring keyToString(WPARAM wParam) {
755 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
756 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
757 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
758 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
760 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
762 case '\t': return JvNewStringLatin1("tab");
763 case 0x1b: return JvNewStringLatin1("escape");
764 case '\n': return JvNewStringLatin1("enter");
765 case '\r': return JvNewStringLatin1("enter");
766 case 0x08: return JvNewStringLatin1("back_space");
767 default: return JvNewStringLatin1(arr, 1);
770 } else switch (wParam) {
771 case VK_CLEAR: return JvNewStringLatin1("clear");
772 case VK_SHIFT: return JvNewStringLatin1("shift");
773 case VK_CONTROL: return JvNewStringLatin1("control");
774 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
775 case VK_MENU: return JvNewStringLatin1("alt");
776 case VK_PAUSE: return JvNewStringLatin1("pause");
777 case VK_PRIOR: return JvNewStringLatin1("page_up");
778 case VK_NEXT: return JvNewStringLatin1("page_down");
779 case VK_END: return JvNewStringLatin1("end");
780 case VK_HOME: return JvNewStringLatin1("home");
781 case VK_LEFT: return JvNewStringLatin1("left");
782 case VK_UP: return JvNewStringLatin1("up");
783 case VK_RIGHT: return JvNewStringLatin1("right");
784 case VK_DOWN: return JvNewStringLatin1("down");
785 case VK_INSERT: return JvNewStringLatin1("insert");
786 case VK_DELETE: return JvNewStringLatin1("delete");
787 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
788 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
789 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
790 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
791 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
792 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
793 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
794 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
795 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
796 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
797 case VK_F1: return JvNewStringLatin1("f1");
798 case VK_F2: return JvNewStringLatin1("f2");
799 case VK_F3: return JvNewStringLatin1("f3");
800 case VK_F4: return JvNewStringLatin1("f4");
801 case VK_F5: return JvNewStringLatin1("f5");
802 case VK_F6: return JvNewStringLatin1("f6");
803 case VK_F7: return JvNewStringLatin1("f7");
804 case VK_F8: return JvNewStringLatin1("f8");
805 case VK_F9: return JvNewStringLatin1("f9");
806 case VK_F10: return JvNewStringLatin1("f10");
807 case VK_F11: return JvNewStringLatin1("f11");
808 case VK_F12: return JvNewStringLatin1("f12");
809 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
810 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
811 case VK_LSHIFT: return JvNewStringLatin1("shift");
812 case VK_RSHIFT: return JvNewStringLatin1("shift");
813 case VK_LCONTROL: return JvNewStringLatin1("control");
814 case VK_RCONTROL: return JvNewStringLatin1("control");