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 max(a,b) ((a)>(b)?(a):(b))
358 #define min(a,b) ((a)<(b)?(a):(b))
360 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
362 jint cx1, jint cy1, jint cx2, jint cy2,
363 jint rgb, jboolean alphaOnly) {
364 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
368 cx2 = min(dx + source->getWidth(), cx2);
369 cy2 = min(dy + source->getHeight(), cy2);
370 if (cx1 >= cx2 || cy1 >= cy2) return;
372 if (source->hasalpha) {
374 if (scratch == NULL || scratch_w < cx2 - cx1 || scratch_h < cy2 - cy1) {
375 if (scratch_dc != NULL) DeleteDC(scratch_dc);
376 if (scratch != NULL) DeleteObject(scratch);
377 scratch_w = max(cx2 - cx1, scratch_w);
378 scratch_h = max(cy2 - cy1, scratch_h);
380 BITMAPINFO bitmapinfo;
381 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
382 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
383 bitmapinfo.bmiHeader.biWidth = scratch_w;
384 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
385 bitmapinfo.bmiHeader.biPlanes = 1;
386 bitmapinfo.bmiHeader.biBitCount = 32;
387 bitmapinfo.bmiHeader.biCompression = BI_RGB;
389 // create section DIB
390 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
391 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
392 SelectObject(scratch_dc, scratch);
395 // copy from screen to scratch
396 BitBlt((HDC)scratch_dc, 0, 0, cx2 - cx1, cy2 - cy1, (HDC)hdc, cx1, cy1, SRCCOPY);
398 // apply alpha-blending to scratch
399 jint* dat = elements(source->data);
401 for(int x = cx1; x < cx2; x++)
402 for(int y = cy1; y < cy2; y++) {
403 jint dst = scratch_bits[(y - dy) * scratch_w + (x - dx)];
405 // FEATURE: see if we can leverage GDI to do something more clever here with alphaOnly
406 jint src = alphaOnly ? rgb : dat[(y - dy) * source->getWidth() + x - dx];
407 jint alpha = (dat[(y - dy) * source->getWidth() + x - dx] & 0xFF000000) >> 24;
408 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
409 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
410 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
411 scratch_bits[(y - dy) * scratch_w + (x - dx)] = (r << 16) | (g << 8) | b;
414 // copy back from scratch to screen
415 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
419 // FIXME: support alphaOnly case here
420 if (source->hasmask) {
421 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->maskdc, cx1 - dx, cy1 - dy, SRCAND);
422 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCPAINT);
424 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCCOPY);
431 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
435 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
436 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
438 RECT rect = { x, y, x + w, y + h };
439 FillRect((HDC)hdc, &rect, brush);
443 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
444 // we create the DC lazily to get around some strange race condition in WinXP
445 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
446 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
449 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
450 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
451 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
452 SetBkMode((HDC)hdc, TRANSPARENT);
453 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
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 BitBlt((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, 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");