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) {
435 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
437 if (source->hasalpha) {
439 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
440 if (scratch_dc != NULL) DeleteDC(scratch_dc);
441 if (scratch != NULL) DeleteObject(scratch);
442 scratch_w = max(dx2 - dx1, scratch_w);
443 scratch_h = max(dy2 - dy1, scratch_h);
445 BITMAPINFO bitmapinfo;
446 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
447 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
448 bitmapinfo.bmiHeader.biWidth = scratch_w;
449 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
450 bitmapinfo.bmiHeader.biPlanes = 1;
451 bitmapinfo.bmiHeader.biBitCount = 32;
452 bitmapinfo.bmiHeader.biCompression = BI_RGB;
454 // create section DIB
455 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
456 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
457 SelectObject(scratch_dc, scratch);
460 // copy from screen to scratch
461 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
463 // apply alpha-blending to scratch
464 jint* dat = elements(source->data);
466 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
467 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
468 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
469 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
470 jint dst = scratch_bits[y * scratch_w + x];
471 jint src = dat[sy * source->getWidth() + sx];
472 jint alpha = (src & 0xFF000000) >> 24;
473 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
474 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
475 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
476 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
479 // copy back from scratch to screen
480 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
483 if (source->hasmask) {
484 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
485 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
487 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
494 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
496 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
497 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
499 // Platform API passes us the y-pos of the bottom of the text; we need the top
502 int len = min(1024, JvGetStringUTFLength(text));
505 JvGetStringUTFRegion(text, 0, len, buf);
507 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
508 TextOut((HDC)hdc, x, y, buf, len);
511 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
515 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
516 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
518 RECT rect = { x, y, x + w, y + h };
519 FillRect((HDC)hdc, &rect, brush);
523 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
524 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
527 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
528 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
529 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
530 SetBkMode((HDC)hdc, TRANSPARENT);
531 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
534 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
535 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
536 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
537 SelectClipRgn((HDC)hdc, hrgn);
541 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
542 DeleteObject((void*)hdc);
543 DeleteObject((void*)hbitmap);
548 // Win32Picture /////////////////////////////////////////////////////////////////////////
550 void org::xwt::plat::Win32$Win32Picture::natInit() {
552 BITMAPINFO bitmapinfo;
553 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
554 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
555 bitmapinfo.bmiHeader.biWidth = w;
556 bitmapinfo.bmiHeader.biHeight = -1 * h;
557 bitmapinfo.bmiHeader.biPlanes = 1;
558 bitmapinfo.bmiHeader.biBitCount = 32;
559 bitmapinfo.bmiHeader.biCompression = BI_RGB;
561 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
562 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
563 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
564 uint32_t* dat = (uint32_t*)elements(data);
565 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
566 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
568 jint _copy[min(1024, data->length)];
569 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
571 memcpy(copy, elements(data), data->length * 4);
572 for(int i=0; i<data->length; i++)
573 if ((copy[i] & 0xFF000000) == 0x00000000) {
575 copy[i] = 0x00FFFFFF;
576 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
577 copy[i] = 0x00000000;
581 if (data->length > 1024) free(copy);
586 if (data->length > 1024) free(copy);
590 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
591 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
592 maskdc = (jint)CreateCompatibleDC(NULL);
593 SelectObject((HDC)maskdc, (HBITMAP)hmask);
594 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
595 if (data->length > 1024) free(copy);
600 // Win32Surface /////////////////////////////////////////////////////////////////////////////
602 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
604 // Ask the message-handling thread to create a window for us
605 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
606 hwndCreated->block();
608 // turn on incremental GC now that we have a user-visible interface
609 // [[this is causing segfaults; enable it later...]]
610 // GC_enable_incremental();
612 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
613 hdc = (jint)GetDC((HWND)hwnd);
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);
659 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
660 HDC memdc = CreateCompatibleDC((HDC)hdc);
661 SelectObject(memdc, bit);
662 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
665 jint* dat = elements(p->data);
666 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
667 SelectObject(memdc, bit_mask);
668 for(int x=0; x<icon_width; x++)
669 for(int y=0; y<icon_height; y++) {
670 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
671 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
672 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
675 // instantiate the icon and assign it to the window class
678 ici.hbmMask = bit_mask;
680 HICON hicon = CreateIconIndirect(&ici);
681 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
682 if (oldicon != NULL) DestroyIcon(oldicon);
686 static jstring keyToString(WPARAM wParam);
687 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
689 UINT iMsg = (UINT)_iMsg;
690 WPARAM wParam = (WPARAM)_wParam;
691 LPARAM lParam = (LPARAM)_lParam;
693 int oldmousex, oldmousey;
698 RECT client_rect, window_rect;
702 int addwidth, addheight;
705 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
706 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
707 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
708 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
710 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
712 KeyPressed(keyToString(wParam));
715 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
717 KeyReleased(keyToString(wParam));
720 case WM_SETFOCUS: Focused(true); return 0;
721 case WM_KILLFOCUS: Focused(false); return 0;
722 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
723 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
724 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
725 case WM_LBUTTONDOWN: Press(1); return 0;
726 case WM_RBUTTONDOWN: Press(2); return 0;
727 case WM_MBUTTONDOWN: Press(3); return 0;
728 case WM_CLOSE: Close(); return 0;
729 case WM_ERASEBKGND: return 0;
734 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
735 if (captured && !inside) {
737 SetCursor((HCURSOR)previous_cursor);
742 GetClientRect((HWND)hwnd, &rect);
743 PosChange(rect.left, rect.top);
747 if (wParam == SIZE_MINIMIZED) {
748 if (maximized) Maximized(false);
750 } else if (wParam == SIZE_MAXIMIZED) {
751 if (minimized) Minimized(false);
754 if (minimized) Minimized(false);
755 if (maximized) Maximized(false);
757 // deliberately fall through to WM_SIZING
760 GetClientRect((HWND)hwnd, &rect);
761 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
765 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
767 GetClientRect((HWND)hwnd, &rect);
768 point.x = mouse_x = lParam & 0xFFFF;
769 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
770 ClientToScreen((HWND)hwnd, &point);
771 hwnd2 = WindowFromPoint(point);
773 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
775 Move(mouse_x, mouse_y);
777 if (newinside && !inside) {
779 SetCapture((HWND)hwnd);
781 previous_cursor = (jint)GetCursor();
782 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
784 } else if (!newinside && inside) {
786 if (!button1 && !button2 && !button3) {
789 SetCursor((HCURSOR)previous_cursor);
795 case WM_USER_SETCURSOR:
796 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
797 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
798 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
799 // cursor should be re-set to "current_cursor".
800 SetCursor((HCURSOR)current_cursor);
803 case WM_USER_DISPOSE:
804 // used to signal that we should destroy ourselves
805 DestroyWindow((HWND)hwnd);
808 case WM_GETMINMAXINFO:
809 GetClientRect((HWND)hwnd, &client_rect);
810 GetWindowRect((HWND)hwnd, &window_rect);
811 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
812 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
813 mmi = (MINMAXINFO*)lParam;
814 mmi->ptMinTrackSize.x = ((uint32_t)root->dmin(0)) + addwidth;
815 mmi->ptMinTrackSize.y = ((uint32_t)root->dmin(1)) + addheight;
816 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->dmax(0)) + addwidth);
817 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->dmax(1)) + addheight);
822 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
823 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
824 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
830 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
834 // Key Translator Helper /////////////////////////////////////////////////////////////////////
836 static char keyarr [256] = { 0 };
837 static jstring keyToString(WPARAM wParam) {
839 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
840 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
841 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
842 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
844 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
846 case '\t': return JvNewStringLatin1("tab");
847 case 0x1b: return JvNewStringLatin1("escape");
848 case '\n': return JvNewStringLatin1("enter");
849 case '\r': return JvNewStringLatin1("enter");
850 case 0x08: return JvNewStringLatin1("back_space");
851 default: return JvNewStringLatin1(arr, 1);
854 } else switch (wParam) {
855 case VK_CLEAR: return JvNewStringLatin1("clear");
856 case VK_SHIFT: return JvNewStringLatin1("shift");
857 case VK_CONTROL: return JvNewStringLatin1("control");
858 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
859 case VK_MENU: return JvNewStringLatin1("alt");
860 case VK_PAUSE: return JvNewStringLatin1("pause");
861 case VK_PRIOR: return JvNewStringLatin1("page_up");
862 case VK_NEXT: return JvNewStringLatin1("page_down");
863 case VK_END: return JvNewStringLatin1("end");
864 case VK_HOME: return JvNewStringLatin1("home");
865 case VK_LEFT: return JvNewStringLatin1("left");
866 case VK_UP: return JvNewStringLatin1("up");
867 case VK_RIGHT: return JvNewStringLatin1("right");
868 case VK_DOWN: return JvNewStringLatin1("down");
869 case VK_INSERT: return JvNewStringLatin1("insert");
870 case VK_DELETE: return JvNewStringLatin1("delete");
871 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
872 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
873 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
874 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
875 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
876 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
877 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
878 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
879 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
880 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
881 case VK_F1: return JvNewStringLatin1("f1");
882 case VK_F2: return JvNewStringLatin1("f2");
883 case VK_F3: return JvNewStringLatin1("f3");
884 case VK_F4: return JvNewStringLatin1("f4");
885 case VK_F5: return JvNewStringLatin1("f5");
886 case VK_F6: return JvNewStringLatin1("f6");
887 case VK_F7: return JvNewStringLatin1("f7");
888 case VK_F8: return JvNewStringLatin1("f8");
889 case VK_F9: return JvNewStringLatin1("f9");
890 case VK_F10: return JvNewStringLatin1("f10");
891 case VK_F11: return JvNewStringLatin1("f11");
892 case VK_F12: return JvNewStringLatin1("f12");
893 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
894 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
895 case VK_LSHIFT: return JvNewStringLatin1("shift");
896 case VK_RSHIFT: return JvNewStringLatin1("shift");
897 case VK_LCONTROL: return JvNewStringLatin1("control");
898 case VK_RCONTROL: return JvNewStringLatin1("control");