1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
3 // this has to precede the others so we don't get collisions on min/max
4 #include <org/xwt/Box.h>
19 #include <java/lang/Integer.h>
20 #include <java/util/Hashtable.h>
21 #include <org/xwt/Box.h>
22 #include <org/xwt/Surface.h>
23 #include <org/xwt/DoubleBuffer.h>
24 #include <org/xwt/Picture.h>
25 #include <org/xwt/ByteStream.h>
26 #include <org/xwt/Platform.h>
27 #include <org/xwt/Platform$ParsedFont.h>
28 #include <org/xwt/plat/Win32.h>
29 #include <org/xwt/plat/Win32$Win32Font.h>
30 #include <org/xwt/plat/Win32$Win32Surface.h>
31 #include <org/xwt/plat/Win32$Win32DoubleBuffer.h>
32 #include <org/xwt/plat/Win32$Win32Picture.h>
33 #include <org/xwt/util/Log.h>
34 #include <org/xwt/util/Semaphore.h>
37 #include <java/lang/System.h>
38 #include <java/io/PrintStream.h>
40 #define WM_USER_SETCURSOR WM_USER
41 #define WM_USER_DISPOSE (WM_USER + 1)
42 #define WM_USER_CREATEWINDOW (WM_USER + 2)
43 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
45 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
46 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
48 // Callbacks ////////////////////////////////////////////////////////////////////
50 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
51 org::xwt::plat::Win32$Win32Surface* surface =
52 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
54 if (surface != NULL) {
55 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
58 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
59 return DefWindowProc(hwnd, iMsg, wParam, lParam);
63 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
64 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
68 lf.lfCharSet = ANSI_CHARSET;
69 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
70 lf.lfPitchAndFamily = 0;
71 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
74 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
75 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
76 tm->tmItalic == 0 ? 0 : 1,
77 tm->tmWeight <= 400 ? 0 : 1);
83 // Initialization ////////////////////////////////////////////////////////////////////
85 static int window_class_counter = 0;
87 jstring org::xwt::plat::Win32::getTempPath() {
89 DWORD ret = GetTempPath(1024, buf);
90 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
91 return JvNewStringLatin1(buf);
94 // XOR mask for the hand cursor
95 static unsigned char hand_cursor_xor[32 * 4] = {
96 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x0C, 0x00, 0x00,
98 0x00, 0x0C, 0x00, 0x00,
99 0x00, 0x0C, 0x00, 0x00,
100 0x00, 0x0C, 0x00, 0x00,
101 0x00, 0x0C, 0x00, 0x00,
102 0x00, 0x0D, 0x80, 0x00,
103 0x00, 0x0D, 0xB0, 0x00,
104 0x00, 0x0D, 0xB4, 0x00,
105 0x00, 0x0D, 0xB6, 0x00,
106 0x00, 0xCF, 0xF6, 0x00,
107 0x00, 0xEF, 0xFE, 0x00,
108 0x00, 0x6F, 0xFE, 0x00,
109 0x00, 0x2F, 0xFE, 0x00,
110 0x00, 0x3F, 0xFE, 0x00,
111 0x00, 0x1F, 0xFE, 0x00,
112 0x00, 0x1F, 0xFC, 0x00,
113 0x00, 0x0F, 0xFC, 0x00,
114 0x00, 0x0F, 0xFC, 0x00,
115 0x00, 0x07, 0xF8, 0x00,
116 0x00, 0x07, 0xF8, 0x00,
117 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00
130 // AND mask for the hand cursor
131 static unsigned char hand_cursor_and[32 * 4] = {
132 0xFF, 0xF3, 0xFF, 0xFF,
133 0xFF, 0xE1, 0xFF, 0xFF,
134 0xFF, 0xE1, 0xFF, 0xFF,
135 0xFF, 0xE1, 0xFF, 0xFF,
136 0xFF, 0xE1, 0xFF, 0xFF,
137 0xFF, 0xE0, 0x7F, 0xFF,
138 0xFF, 0xE0, 0x0F, 0xFF,
139 0xFF, 0xE0, 0x03, 0xFF,
140 0xFF, 0xE0, 0x01, 0xFF,
141 0xFF, 0x20, 0x00, 0xFF,
142 0xFE, 0x00, 0x00, 0xFF,
143 0xFE, 0x00, 0x00, 0xFF,
144 0xFF, 0x00, 0x00, 0xFF,
145 0xFF, 0x80, 0x00, 0xFF,
146 0xFF, 0x80, 0x00, 0xFF,
147 0xFF, 0xC0, 0x00, 0xFF,
148 0xFF, 0xC0, 0x01, 0xFF,
149 0xFF, 0xE0, 0x01, 0xFF,
150 0xFF, 0xE0, 0x01, 0xFF,
151 0xFF, 0xF0, 0x03, 0xFF,
152 0xFF, 0xF0, 0x03, 0xFF,
153 0xFF, 0xF0, 0x03, 0xFF,
154 0xFF, 0xFF, 0xFF, 0xFF,
155 0xFF, 0xFF, 0xFF, 0xFF,
156 0xFF, 0xFF, 0xFF, 0xFF,
157 0xFF, 0xFF, 0xFF, 0xFF,
158 0xFF, 0xFF, 0xFF, 0xFF,
159 0xFF, 0xFF, 0xFF, 0xFF,
160 0xFF, 0xFF, 0xFF, 0xFF,
161 0xFF, 0xFF, 0xFF, 0xFF,
162 0xFF, 0xFF, 0xFF, 0xFF,
163 0xFF, 0xFF, 0xFF, 0xFF
167 void org::xwt::plat::Win32::natInit() {
169 // grab desktop dc/handle
170 desktop_handle = (jint)GetDesktopWindow();
171 desktop_dc = (jint)GetDC((HWND)desktop_handle);
174 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
175 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
176 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
177 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
178 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
179 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
180 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
181 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
182 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
183 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
187 lf.lfCharSet = ANSI_CHARSET;
188 lf.lfFaceName[0] = 0;
189 lf.lfPitchAndFamily = 0;
190 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
192 messagePumpThread = (jint)GetCurrentThreadId();
193 messagePumpStarted->release();
196 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
198 if (msg.message == WM_USER_CREATEWINDOW) {
199 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
201 // we must create a unique window class name for each
202 // window so that minimization icons can be set independantly
204 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
207 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
208 wc.lpfnWndProc = WndProc;
210 wc.cbSize = sizeof(WNDCLASSEX);
212 wc.hInstance = GetModuleHandle(NULL);
216 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
217 wc.lpszMenuName = NULL;
218 wc.lpszClassName = buf;
219 RegisterClassEx(&wc);
221 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
222 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
223 SetFocus((HWND)surface->hwnd);
224 surface->hwndCreated->release();
227 TranslateMessage(&msg);
228 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
229 DispatchMessage(&msg);
233 java::lang::System::exit(-1);
237 // Platform Methods ///////////////////////////////////////////////////////////////////
239 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
240 int len = JvGetStringUTFLength(key);
242 JvGetStringUTFRegion(key, 0, len, buf);
245 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
246 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
250 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
254 memset(buf, 0, 1024);
255 memset(&ofn, 0, sizeof(OPENFILENAME));
257 if (suggestedFileName != NULL)
258 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
260 ofn.lStructSize = sizeof(OPENFILENAME);
261 ofn.nMaxCustFilter = 0;
265 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
266 ofn.Flags |= OFN_HIDEREADONLY;
268 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
269 return ret == 0 ? NULL : JvNewStringLatin1(buf);
272 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
278 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
279 if (result != ERROR_SUCCESS) return;
284 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
286 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
290 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
291 if (buf[0] != 1) return;
296 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
298 elements(container)[0] = JvNewStringLatin1(buf);
302 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
304 elements(container)[1] = JvNewStringLatin1(buf);
307 jstring org::xwt::plat::Win32::_getClipBoard() {
308 OpenClipboard((HWND)desktop_handle);
309 HGLOBAL hmem = GetClipboardData(CF_TEXT);
310 if (hmem == NULL) return NULL;
311 char* buf = (char*)GlobalLock(hmem);
312 if (buf == NULL) return NULL;
313 jstring ret = JvNewStringLatin1(buf);
319 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
320 OpenClipboard((HWND)desktop_handle);
321 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
322 if (hmem == NULL) return;
323 char* buf = (char*)GlobalLock(hmem);
324 if (buf == NULL) return;
325 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
326 buf[JvGetStringUTFLength(s)] = '\0';
328 SetClipboardData(CF_TEXT, hmem);
332 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
333 char buf[JvGetStringUTFLength(message) + 1];
334 buf[JvGetStringUTFLength(message)] = '\0';
335 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
336 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
337 java::lang::System::exit(-1);
340 jint org::xwt::plat::Win32::_getScreenWidth() {
342 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
343 return rect.right - rect.left;
346 jint org::xwt::plat::Win32::_getScreenHeight() {
348 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
349 return rect.bottom - rect.top;
352 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
353 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
355 memset(&logfont, 0, sizeof(LOGFONT));
356 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
357 if (pf->italic) logfont.lfItalic = 1;
358 if (pf->bold) logfont.lfWeight = FW_BOLD;
359 logfont.lfCharSet = ANSI_CHARSET;
361 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
362 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
364 ret->hfont = (jint)CreateFontIndirect(&logfont);
365 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
368 GetTextMetrics((HDC)desktop_dc, &tm);
370 p.x = 0; p.y = tm.tmAscent;
371 LPtoDP((HDC)desktop_dc, &p, 1);
372 ret->maxAscent = p.y;
374 p.x = 0; p.y = tm.tmDescent;
375 LPtoDP((HDC)desktop_dc, &p, 1);
376 ret->maxDescent = p.y;
381 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
383 HFONT hfont = (HFONT)(getFont(font)->hfont);
384 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
386 int len = min(1024, JvGetStringUTFLength(text));
389 JvGetStringUTFRegion(text, 0, len, buf);
392 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
396 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
398 int len = min(2048, JvGetStringUTFLength(url));
400 JvGetStringUTFRegion(url, 0, len, buf);
404 memset(&ei, 0, sizeof(ei));
405 ei.cbSize = sizeof(ei);
408 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
409 ei.nShow = SW_SHOWDEFAULT;
410 return (ShellExecuteEx(&ei) == 0);
415 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
417 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
418 // Since all drawing operations are single-threaded, it's safe to use a global here.
419 static HBITMAP scratch = NULL;
420 static HDC scratch_dc = NULL;
421 static jint* scratch_bits = NULL;
422 static jint scratch_w = 0;
423 static jint scratch_h = 0;
425 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
426 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
427 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
429 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
431 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
432 jint dx1, jint dy1, jint dx2, jint dy2,
433 jint sx1, jint sy1, jint sx2, jint sy2) {
434 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
436 if (source->hasalpha) {
438 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
439 if (scratch_dc != NULL) DeleteDC(scratch_dc);
440 if (scratch != NULL) DeleteObject(scratch);
441 scratch_w = max(dx2 - dx1, scratch_w);
442 scratch_h = max(dy2 - dy1, scratch_h);
444 BITMAPINFO bitmapinfo;
445 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
446 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
447 bitmapinfo.bmiHeader.biWidth = scratch_w;
448 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
449 bitmapinfo.bmiHeader.biPlanes = 1;
450 bitmapinfo.bmiHeader.biBitCount = 32;
451 bitmapinfo.bmiHeader.biCompression = BI_RGB;
453 // create section DIB
454 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
455 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
456 SelectObject(scratch_dc, scratch);
459 // copy from screen to scratch
460 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
462 // apply alpha-blending to scratch
463 jint* dat = elements(source->data);
465 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
466 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
467 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
468 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
469 jint dst = scratch_bits[y * scratch_w + x];
470 jint src = dat[sy * source->getWidth() + sx];
471 jint alpha = (src & 0xFF000000) >> 24;
472 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
473 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
474 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
475 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
478 // copy back from scratch to screen
479 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
482 if (source->hasmask) {
483 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
484 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
486 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
493 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
495 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
496 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
498 // Platform API passes us the y-pos of the bottom of the text; we need the top
501 int len = min(1024, JvGetStringUTFLength(text));
504 JvGetStringUTFRegion(text, 0, len, buf);
506 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
507 TextOut((HDC)hdc, x, y, buf, len);
510 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
514 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
515 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
517 RECT rect = { x, y, x + w, y + h };
518 FillRect((HDC)hdc, &rect, brush);
522 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
523 // we create the DC lazily to get around some strange race condition in WinXP
524 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
525 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
528 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
529 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
530 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
531 SetBkMode((HDC)hdc, TRANSPARENT);
532 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
535 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
536 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
537 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
538 SelectClipRgn((HDC)hdc, hrgn);
542 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
543 DeleteObject((void*)hdc);
544 DeleteObject((void*)hbitmap);
549 // Win32Picture /////////////////////////////////////////////////////////////////////////
551 void org::xwt::plat::Win32$Win32Picture::natInit() {
553 BITMAPINFO bitmapinfo;
554 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
555 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
556 bitmapinfo.bmiHeader.biWidth = w;
557 bitmapinfo.bmiHeader.biHeight = -1 * h;
558 bitmapinfo.bmiHeader.biPlanes = 1;
559 bitmapinfo.bmiHeader.biBitCount = 32;
560 bitmapinfo.bmiHeader.biCompression = BI_RGB;
562 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
563 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
564 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
565 uint32_t* dat = (uint32_t*)elements(data);
566 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
567 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
569 jint _copy[min(1024, data->length)];
570 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
572 memcpy(copy, elements(data), data->length * 4);
573 for(int i=0; i<data->length; i++)
574 if ((copy[i] & 0xFF000000) == 0x00000000) {
576 copy[i] = 0x00FFFFFF;
577 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
578 copy[i] = 0x00000000;
582 if (data->length > 1024) free(copy);
587 if (data->length > 1024) free(copy);
591 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
592 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
593 maskdc = (jint)CreateCompatibleDC(NULL);
594 SelectObject((HDC)maskdc, (HBITMAP)hmask);
595 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
596 if (data->length > 1024) free(copy);
601 // Win32Surface /////////////////////////////////////////////////////////////////////////////
603 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
605 // Ask the message-handling thread to create a window for us
606 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
607 hwndCreated->block();
609 // turn on incremental GC now that we have a user-visible interface
610 // [[this is causing segfaults; enable it later...]]
611 // GC_enable_incremental();
613 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
616 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
617 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
618 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
619 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
620 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
621 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
622 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
623 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
625 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
630 ClientToScreen((HWND)hwnd, &point);
631 GetWindowRect((HWND)hwnd, &rect);
632 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
635 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
636 RECT client_rect, window_rect;
637 GetClientRect((HWND)hwnd, &client_rect);
638 GetWindowRect((HWND)hwnd, &window_rect);
639 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
640 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
641 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
644 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
645 int len = min(1024, JvGetStringUTFLength(title));
648 JvGetStringUTFRegion(title, 0, len, buf);
649 SetWindowText((HWND)hwnd, buf);
652 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
654 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
655 int icon_width = GetSystemMetrics(SM_CXSMICON);
656 int icon_height = GetSystemMetrics(SM_CYSMICON);
658 // we create the DC lazily to get around some strange race condition in WinXP
659 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
662 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
663 HDC memdc = CreateCompatibleDC((HDC)hdc);
664 SelectObject(memdc, bit);
665 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
668 jint* dat = elements(p->data);
669 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
670 SelectObject(memdc, bit_mask);
671 for(int x=0; x<icon_width; x++)
672 for(int y=0; y<icon_height; y++) {
673 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
674 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
675 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
678 // instantiate the icon and assign it to the window class
681 ici.hbmMask = bit_mask;
683 HICON hicon = CreateIconIndirect(&ici);
684 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
685 if (oldicon != NULL) DestroyIcon(oldicon);
689 static jstring keyToString(WPARAM wParam);
690 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
692 UINT iMsg = (UINT)_iMsg;
693 WPARAM wParam = (WPARAM)_wParam;
694 LPARAM lParam = (LPARAM)_lParam;
696 int oldmousex, oldmousey;
701 RECT client_rect, window_rect;
705 int addwidth, addheight;
708 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
709 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
710 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
711 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
713 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
715 KeyPressed(keyToString(wParam));
718 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
720 KeyReleased(keyToString(wParam));
723 case WM_SETFOCUS: Focused(true); return 0;
724 case WM_KILLFOCUS: Focused(false); return 0;
725 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
726 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
727 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
728 case WM_LBUTTONDOWN: Press(1); return 0;
729 case WM_RBUTTONDOWN: Press(2); return 0;
730 case WM_MBUTTONDOWN: Press(3); return 0;
731 case WM_CLOSE: Close(); return 0;
732 case WM_ERASEBKGND: return 0;
737 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
738 if (captured && !inside) {
740 SetCursor((HCURSOR)previous_cursor);
745 GetClientRect((HWND)hwnd, &rect);
746 PosChange(rect.left, rect.top);
750 if (wParam == SIZE_MINIMIZED) {
751 if (maximized) Maximized(false);
753 } else if (wParam == SIZE_MAXIMIZED) {
754 if (minimized) Minimized(false);
757 if (minimized) Minimized(false);
758 if (maximized) Maximized(false);
760 // deliberately fall through to WM_SIZING
763 GetClientRect((HWND)hwnd, &rect);
764 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
768 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
770 GetClientRect((HWND)hwnd, &rect);
771 point.x = mouse_x = lParam & 0xFFFF;
772 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
773 ClientToScreen((HWND)hwnd, &point);
774 hwnd2 = WindowFromPoint(point);
776 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
778 Move(mouse_x, mouse_y);
780 if (newinside && !inside) {
782 SetCapture((HWND)hwnd);
784 previous_cursor = (jint)GetCursor();
785 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
787 } else if (!newinside && inside) {
789 if (!button1 && !button2 && !button3) {
792 SetCursor((HCURSOR)previous_cursor);
798 case WM_USER_SETCURSOR:
799 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
800 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
801 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
802 // cursor should be re-set to "current_cursor".
803 SetCursor((HCURSOR)current_cursor);
806 case WM_USER_DISPOSE:
807 // used to signal that we should destroy ourselves
808 DestroyWindow((HWND)hwnd);
811 case WM_GETMINMAXINFO:
812 GetClientRect((HWND)hwnd, &client_rect);
813 GetWindowRect((HWND)hwnd, &window_rect);
814 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
815 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
816 mmi = (MINMAXINFO*)lParam;
817 mmi->ptMinTrackSize.x = ((uint32_t)root->dmin(0)) + addwidth;
818 mmi->ptMinTrackSize.y = ((uint32_t)root->dmin(1)) + addheight;
819 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->dmax(0)) + addwidth);
820 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->dmax(1)) + addheight);
825 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
826 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
827 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
833 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
837 // Key Translator Helper /////////////////////////////////////////////////////////////////////
839 static char keyarr [256] = { 0 };
840 static jstring keyToString(WPARAM wParam) {
842 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
843 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
844 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
845 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
847 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
849 case '\t': return JvNewStringLatin1("tab");
850 case 0x1b: return JvNewStringLatin1("escape");
851 case '\n': return JvNewStringLatin1("enter");
852 case '\r': return JvNewStringLatin1("enter");
853 case 0x08: return JvNewStringLatin1("back_space");
854 default: return JvNewStringLatin1(arr, 1);
857 } else switch (wParam) {
858 case VK_CLEAR: return JvNewStringLatin1("clear");
859 case VK_SHIFT: return JvNewStringLatin1("shift");
860 case VK_CONTROL: return JvNewStringLatin1("control");
861 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
862 case VK_MENU: return JvNewStringLatin1("alt");
863 case VK_PAUSE: return JvNewStringLatin1("pause");
864 case VK_PRIOR: return JvNewStringLatin1("page_up");
865 case VK_NEXT: return JvNewStringLatin1("page_down");
866 case VK_END: return JvNewStringLatin1("end");
867 case VK_HOME: return JvNewStringLatin1("home");
868 case VK_LEFT: return JvNewStringLatin1("left");
869 case VK_UP: return JvNewStringLatin1("up");
870 case VK_RIGHT: return JvNewStringLatin1("right");
871 case VK_DOWN: return JvNewStringLatin1("down");
872 case VK_INSERT: return JvNewStringLatin1("insert");
873 case VK_DELETE: return JvNewStringLatin1("delete");
874 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
875 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
876 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
877 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
878 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
879 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
880 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
881 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
882 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
883 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
884 case VK_F1: return JvNewStringLatin1("f1");
885 case VK_F2: return JvNewStringLatin1("f2");
886 case VK_F3: return JvNewStringLatin1("f3");
887 case VK_F4: return JvNewStringLatin1("f4");
888 case VK_F5: return JvNewStringLatin1("f5");
889 case VK_F6: return JvNewStringLatin1("f6");
890 case VK_F7: return JvNewStringLatin1("f7");
891 case VK_F8: return JvNewStringLatin1("f8");
892 case VK_F9: return JvNewStringLatin1("f9");
893 case VK_F10: return JvNewStringLatin1("f10");
894 case VK_F11: return JvNewStringLatin1("f11");
895 case VK_F12: return JvNewStringLatin1("f12");
896 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
897 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
898 case VK_LSHIFT: return JvNewStringLatin1("shift");
899 case VK_RSHIFT: return JvNewStringLatin1("shift");
900 case VK_LCONTROL: return JvNewStringLatin1("control");
901 case VK_RCONTROL: return JvNewStringLatin1("control");