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);
208 SetFocus((HWND)surface->hwnd);
209 surface->hwndCreated->release();
212 TranslateMessage(&msg);
213 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
214 DispatchMessage(&msg);
218 java::lang::System::exit(-1);
222 // Platform Methods ///////////////////////////////////////////////////////////////////
224 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
225 int len = JvGetStringUTFLength(key);
227 JvGetStringUTFRegion(key, 0, len, buf);
230 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
231 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
235 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
239 memset(buf, 0, 1024);
240 memset(&ofn, 0, sizeof(OPENFILENAME));
242 if (suggestedFileName != NULL)
243 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
245 ofn.lStructSize = sizeof(OPENFILENAME);
246 ofn.nMaxCustFilter = 0;
250 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
251 ofn.Flags |= OFN_HIDEREADONLY;
253 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
254 return ret == 0 ? NULL : JvNewStringLatin1(buf);
257 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
263 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
264 if (result != ERROR_SUCCESS) return;
269 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
271 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
275 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
276 if (buf[0] != 1) return;
281 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
283 elements(container)[0] = JvNewStringLatin1(buf);
287 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
289 elements(container)[1] = JvNewStringLatin1(buf);
292 jstring org::xwt::plat::Win32::_getClipBoard() {
293 OpenClipboard((HWND)desktop_handle);
294 HGLOBAL hmem = GetClipboardData(CF_TEXT);
295 if (hmem == NULL) return NULL;
296 char* buf = (char*)GlobalLock(hmem);
297 if (buf == NULL) return NULL;
298 jstring ret = JvNewStringLatin1(buf);
304 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
305 OpenClipboard((HWND)desktop_handle);
306 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
307 if (hmem == NULL) return;
308 char* buf = (char*)GlobalLock(hmem);
309 if (buf == NULL) return;
310 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
311 buf[JvGetStringUTFLength(s)] = '\0';
313 SetClipboardData(CF_TEXT, hmem);
317 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
318 char buf[JvGetStringUTFLength(message) + 1];
319 buf[JvGetStringUTFLength(message)] = '\0';
320 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
321 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
322 java::lang::System::exit(-1);
325 jint org::xwt::plat::Win32::_getScreenWidth() {
327 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
328 return rect.right - rect.left;
331 jint org::xwt::plat::Win32::_getScreenHeight() {
333 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
334 return rect.bottom - rect.top;
337 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
339 int len = min(2048, JvGetStringUTFLength(url));
341 JvGetStringUTFRegion(url, 0, len, buf);
345 memset(&ei, 0, sizeof(ei));
346 ei.cbSize = sizeof(ei);
349 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
350 ei.nShow = SW_SHOWDEFAULT;
351 return (ShellExecuteEx(&ei) == 0);
356 // Win32PixelBuffer /////////////////////////////////////////////////////////////////////////
358 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
359 // Since all drawing operations are single-threaded, it's safe to use a global here.
360 static HBITMAP scratch = NULL;
361 static HDC scratch_dc = NULL;
362 static jint* scratch_bits = NULL;
363 static jint scratch_w = 0;
364 static jint scratch_h = 0;
366 #define max(a,b) ((a)>(b)?(a):(b))
367 #define min(a,b) ((a)<(b)?(a):(b))
369 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
371 jint cx1, jint cy1, jint cx2, jint cy2,
372 jint rgb, jboolean alphaOnly) {
373 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
377 cx2 = min(dx + source->getWidth(), cx2);
378 cy2 = min(dy + source->getHeight(), cy2);
379 if (cx1 >= cx2 || cy1 >= cy2) return;
381 if (source->hasalpha) {
383 if (scratch == NULL || scratch_w < cx2 - cx1 || scratch_h < cy2 - cy1) {
384 if (scratch_dc != NULL) DeleteDC(scratch_dc);
385 if (scratch != NULL) DeleteObject(scratch);
386 scratch_w = max(cx2 - cx1, scratch_w);
387 scratch_h = max(cy2 - cy1, scratch_h);
389 BITMAPINFO bitmapinfo;
390 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
391 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
392 bitmapinfo.bmiHeader.biWidth = scratch_w;
393 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
394 bitmapinfo.bmiHeader.biPlanes = 1;
395 bitmapinfo.bmiHeader.biBitCount = 32;
396 bitmapinfo.bmiHeader.biCompression = BI_RGB;
398 // create section DIB
399 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
400 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
401 SelectObject(scratch_dc, scratch);
404 // copy from screen to scratch
405 BitBlt((HDC)scratch_dc, 0, 0, cx2 - cx1, cy2 - cy1, (HDC)hdc, cx1, cy1, SRCCOPY);
407 // apply alpha-blending to scratch
408 jint* dat = elements(source->data);
410 for(int x = cx1; x < cx2; x++)
411 for(int y = cy1; y < cy2; y++) {
412 jint dst = scratch_bits[(y - dy) * scratch_w + (x - dx)];
414 // FEATURE: see if we can leverage GDI to do something more clever here with alphaOnly
415 jint src = alphaOnly ? rgb : dat[(y - dy) * source->getWidth() + x - dx];
416 jint alpha = (dat[(y - dy) * source->getWidth() + x - dx] & 0xFF000000) >> 24;
417 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
418 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
419 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
420 scratch_bits[(y - dy) * scratch_w + (x - dx)] = (r << 16) | (g << 8) | b;
423 // copy back from scratch to screen
424 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
428 // FIXME: support alphaOnly case here
429 if (source->hasmask) {
430 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->maskdc, cx1 - dx, cy1 - dy, SRCAND);
431 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCPAINT);
433 BitBlt((HDC)hdc, cx1, cy1, cx2 - cx1, cy2 - cy1, (HDC)source->hdc, cx1 - dx, cy1 - dy, SRCCOPY);
440 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
444 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
445 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
447 RECT rect = { x, y, x + w, y + h };
448 FillRect((HDC)hdc, &rect, brush);
452 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
453 // we create the DC lazily to get around some strange race condition in WinXP
454 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
455 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
458 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
459 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
460 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
461 SetBkMode((HDC)hdc, TRANSPARENT);
462 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
465 void org::xwt::plat::Win32$Win32PixelBuffer::finalize() {
466 DeleteObject((void*)hdc);
467 DeleteObject((void*)hbitmap);
472 // Win32Picture /////////////////////////////////////////////////////////////////////////
474 void org::xwt::plat::Win32$Win32Picture::natInit() {
476 BITMAPINFO bitmapinfo;
477 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
478 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
479 bitmapinfo.bmiHeader.biWidth = width;
480 bitmapinfo.bmiHeader.biHeight = -1 * height;
481 bitmapinfo.bmiHeader.biPlanes = 1;
482 bitmapinfo.bmiHeader.biBitCount = 32;
483 bitmapinfo.bmiHeader.biCompression = BI_RGB;
485 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, width, height);
486 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
487 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
488 uint32_t* dat = (uint32_t*)elements(data);
489 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
490 StretchDIBits((HDC)hdc, 0, 0, width, height, 0, 0, width, height, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
492 jint _copy[min(1024, data->length)];
493 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
495 memcpy(copy, elements(data), data->length * 4);
496 for(int i=0; i<data->length; i++)
497 if ((copy[i] & 0xFF000000) == 0x00000000) {
499 copy[i] = 0x00FFFFFF;
500 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
501 copy[i] = 0x00000000;
505 if (data->length > 1024) free(copy);
510 if (data->length > 1024) free(copy);
514 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
515 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, width, height);
516 maskdc = (jint)CreateCompatibleDC(NULL);
517 SelectObject((HDC)maskdc, (HBITMAP)hmask);
518 StretchDIBits((HDC)maskdc, 0, 0, width, height, 0, 0, width, height, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
519 if (data->length > 1024) free(copy);
524 // Win32Surface /////////////////////////////////////////////////////////////////////////////
526 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
528 // Ask the message-handling thread to create a window for us
529 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
530 hwndCreated->block();
532 // turn on incremental GC now that we have a user-visible interface
533 // [[this is causing segfaults; enable it later...]]
534 // GC_enable_incremental();
536 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
539 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
540 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
541 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
542 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
543 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
544 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
545 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
546 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
548 void org::xwt::plat::Win32$Win32Surface::setLocation() {
553 ClientToScreen((HWND)hwnd, &point);
554 GetWindowRect((HWND)hwnd, &rect);
555 SetWindowPos((HWND)hwnd, NULL, root->x - (point.x - rect.left), root->y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
558 void org::xwt::plat::Win32$Win32Surface::_setSize(jint w, jint h) {
559 RECT client_rect, window_rect;
560 GetClientRect((HWND)hwnd, &client_rect);
561 GetWindowRect((HWND)hwnd, &window_rect);
562 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
563 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
564 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
567 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
568 int len = min(1024, JvGetStringUTFLength(title));
571 JvGetStringUTFRegion(title, 0, len, buf);
572 SetWindowText((HWND)hwnd, buf);
575 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
577 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
578 int icon_width = GetSystemMetrics(SM_CXSMICON);
579 int icon_height = GetSystemMetrics(SM_CYSMICON);
581 // we create the DC lazily to get around some strange race condition in WinXP
582 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
585 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
586 HDC memdc = CreateCompatibleDC((HDC)hdc);
587 SelectObject(memdc, bit);
588 BitBlt((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, SRCCOPY);
591 jint* dat = elements(p->data);
592 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
593 SelectObject(memdc, bit_mask);
594 for(int x=0; x<icon_width; x++)
595 for(int y=0; y<icon_height; y++) {
596 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
597 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
598 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
601 // instantiate the icon and assign it to the window class
604 ici.hbmMask = bit_mask;
606 HICON hicon = CreateIconIndirect(&ici);
607 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
608 if (oldicon != NULL) DestroyIcon(oldicon);
612 static jstring keyToString(WPARAM wParam);
613 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
615 UINT iMsg = (UINT)_iMsg;
616 WPARAM wParam = (WPARAM)_wParam;
617 LPARAM lParam = (LPARAM)_lParam;
619 int oldmousex, oldmousey;
625 RECT client_rect, window_rect;
629 int addwidth, addheight;
632 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
633 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
634 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
636 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
638 KeyPressed(keyToString(wParam));
641 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
643 KeyReleased(keyToString(wParam));
646 case WM_SETFOCUS: Focused(true); return 0;
647 case WM_KILLFOCUS: Focused(false); return 0;
648 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
649 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
650 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
651 case WM_LBUTTONDOWN: Press(1); return 0;
652 case WM_RBUTTONDOWN: Press(2); return 0;
653 case WM_MBUTTONDOWN: Press(3); return 0;
654 case WM_CLOSE: Close(); return 0;
655 case WM_ERASEBKGND: return 0;
660 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
661 if (captured && !inside) {
663 SetCursor((HCURSOR)previous_cursor);
668 GetClientRect((HWND)hwnd, &rect);
669 PosChange(rect.left, rect.top);
673 if (wParam == SIZE_MINIMIZED) {
674 if (maximized) Maximized(false);
676 } else if (wParam == SIZE_MAXIMIZED) {
677 if (minimized) Minimized(false);
680 if (minimized) Minimized(false);
681 if (maximized) Maximized(false);
683 // deliberately fall through to WM_SIZING
686 GetClientRect((HWND)hwnd, &rect);
687 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
691 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
693 GetClientRect((HWND)hwnd, &rect);
694 point.x = mouse_x = lParam & 0xFFFF;
695 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
696 ClientToScreen((HWND)hwnd, &point);
697 hwnd2 = WindowFromPoint(point);
699 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
701 Move(mouse_x, mouse_y);
703 if (newinside && !inside) {
705 SetCapture((HWND)hwnd);
707 previous_cursor = (jint)GetCursor();
708 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
710 } else if (!newinside && inside) {
712 if (!button1 && !button2 && !button3) {
715 SetCursor((HCURSOR)previous_cursor);
721 case WM_USER_SETCURSOR:
722 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
723 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
724 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
725 // cursor should be re-set to "current_cursor".
726 SetCursor((HCURSOR)current_cursor);
729 case WM_USER_DISPOSE:
730 // used to signal that we should destroy ourselves
731 DestroyWindow((HWND)hwnd);
734 case WM_GETMINMAXINFO:
735 GetClientRect((HWND)hwnd, &client_rect);
736 GetWindowRect((HWND)hwnd, &window_rect);
737 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
738 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
739 mmi = (MINMAXINFO*)lParam;
740 mmi->ptMinTrackSize.x = ((uint32_t)root->minwidth) + addwidth;
741 mmi->ptMinTrackSize.y = ((uint32_t)root->minheight) + addheight;
742 resizable = !((root->minwidth == root->maxwidth) && (root->minheight == root->maxheight));
743 mmi->ptMaxTrackSize.x = resizable ? org::xwt::plat::Win32::getScreenWidth() : mmi->ptMinTrackSize.x;
744 mmi->ptMaxTrackSize.y = resizable ? org::xwt::plat::Win32::getScreenHeight() : mmi->ptMinTrackSize.y;
749 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
750 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
751 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
757 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
761 // Key Translator Helper /////////////////////////////////////////////////////////////////////
763 static char keyarr [256] = { 0 };
764 static jstring keyToString(WPARAM wParam) {
766 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
767 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
768 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
769 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
771 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
773 case '\t': return JvNewStringLatin1("tab");
774 case 0x1b: return JvNewStringLatin1("escape");
775 case '\n': return JvNewStringLatin1("enter");
776 case '\r': return JvNewStringLatin1("enter");
777 case 0x08: return JvNewStringLatin1("back_space");
778 default: return JvNewStringLatin1(arr, 1);
781 } else switch (wParam) {
782 case VK_CLEAR: return JvNewStringLatin1("clear");
783 case VK_SHIFT: return JvNewStringLatin1("shift");
784 case VK_CONTROL: return JvNewStringLatin1("control");
785 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
786 case VK_MENU: return JvNewStringLatin1("alt");
787 case VK_PAUSE: return JvNewStringLatin1("pause");
788 case VK_PRIOR: return JvNewStringLatin1("page_up");
789 case VK_NEXT: return JvNewStringLatin1("page_down");
790 case VK_END: return JvNewStringLatin1("end");
791 case VK_HOME: return JvNewStringLatin1("home");
792 case VK_LEFT: return JvNewStringLatin1("left");
793 case VK_UP: return JvNewStringLatin1("up");
794 case VK_RIGHT: return JvNewStringLatin1("right");
795 case VK_DOWN: return JvNewStringLatin1("down");
796 case VK_INSERT: return JvNewStringLatin1("insert");
797 case VK_DELETE: return JvNewStringLatin1("delete");
798 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
799 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
800 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
801 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
802 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
803 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
804 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
805 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
806 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
807 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
808 case VK_F1: return JvNewStringLatin1("f1");
809 case VK_F2: return JvNewStringLatin1("f2");
810 case VK_F3: return JvNewStringLatin1("f3");
811 case VK_F4: return JvNewStringLatin1("f4");
812 case VK_F5: return JvNewStringLatin1("f5");
813 case VK_F6: return JvNewStringLatin1("f6");
814 case VK_F7: return JvNewStringLatin1("f7");
815 case VK_F8: return JvNewStringLatin1("f8");
816 case VK_F9: return JvNewStringLatin1("f9");
817 case VK_F10: return JvNewStringLatin1("f10");
818 case VK_F11: return JvNewStringLatin1("f11");
819 case VK_F12: return JvNewStringLatin1("f12");
820 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
821 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
822 case VK_LSHIFT: return JvNewStringLatin1("shift");
823 case VK_RSHIFT: return JvNewStringLatin1("shift");
824 case VK_LCONTROL: return JvNewStringLatin1("control");
825 case VK_RCONTROL: return JvNewStringLatin1("control");