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>
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);
65 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
66 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
70 lf.lfCharSet = ANSI_CHARSET;
71 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
72 lf.lfPitchAndFamily = 0;
73 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
76 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
77 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
78 tm->tmItalic == 0 ? 0 : 1,
79 tm->tmWeight <= 400 ? 0 : 1);
85 // Initialization ////////////////////////////////////////////////////////////////////
87 static int window_class_counter = 0;
89 jstring org::xwt::plat::Win32::getTempPath() {
91 DWORD ret = GetTempPath(1024, buf);
92 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
93 return JvNewStringLatin1(buf);
96 // XOR mask for the hand cursor
97 static unsigned char hand_cursor_xor[32 * 4] = {
98 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x0C, 0x00, 0x00,
100 0x00, 0x0C, 0x00, 0x00,
101 0x00, 0x0C, 0x00, 0x00,
102 0x00, 0x0C, 0x00, 0x00,
103 0x00, 0x0C, 0x00, 0x00,
104 0x00, 0x0D, 0x80, 0x00,
105 0x00, 0x0D, 0xB0, 0x00,
106 0x00, 0x0D, 0xB4, 0x00,
107 0x00, 0x0D, 0xB6, 0x00,
108 0x00, 0xCF, 0xF6, 0x00,
109 0x00, 0xEF, 0xFE, 0x00,
110 0x00, 0x6F, 0xFE, 0x00,
111 0x00, 0x2F, 0xFE, 0x00,
112 0x00, 0x3F, 0xFE, 0x00,
113 0x00, 0x1F, 0xFE, 0x00,
114 0x00, 0x1F, 0xFC, 0x00,
115 0x00, 0x0F, 0xFC, 0x00,
116 0x00, 0x0F, 0xFC, 0x00,
117 0x00, 0x07, 0xF8, 0x00,
118 0x00, 0x07, 0xF8, 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,
128 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00
132 // AND mask for the hand cursor
133 static unsigned char hand_cursor_and[32 * 4] = {
134 0xFF, 0xF3, 0xFF, 0xFF,
135 0xFF, 0xE1, 0xFF, 0xFF,
136 0xFF, 0xE1, 0xFF, 0xFF,
137 0xFF, 0xE1, 0xFF, 0xFF,
138 0xFF, 0xE1, 0xFF, 0xFF,
139 0xFF, 0xE0, 0x7F, 0xFF,
140 0xFF, 0xE0, 0x0F, 0xFF,
141 0xFF, 0xE0, 0x03, 0xFF,
142 0xFF, 0xE0, 0x01, 0xFF,
143 0xFF, 0x20, 0x00, 0xFF,
144 0xFE, 0x00, 0x00, 0xFF,
145 0xFE, 0x00, 0x00, 0xFF,
146 0xFF, 0x00, 0x00, 0xFF,
147 0xFF, 0x80, 0x00, 0xFF,
148 0xFF, 0x80, 0x00, 0xFF,
149 0xFF, 0xC0, 0x00, 0xFF,
150 0xFF, 0xC0, 0x01, 0xFF,
151 0xFF, 0xE0, 0x01, 0xFF,
152 0xFF, 0xE0, 0x01, 0xFF,
153 0xFF, 0xF0, 0x03, 0xFF,
154 0xFF, 0xF0, 0x03, 0xFF,
155 0xFF, 0xF0, 0x03, 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,
164 0xFF, 0xFF, 0xFF, 0xFF,
165 0xFF, 0xFF, 0xFF, 0xFF
169 void org::xwt::plat::Win32::natInit() {
171 // grab desktop dc/handle
172 desktop_handle = (jint)GetDesktopWindow();
173 desktop_dc = (jint)GetDC((HWND)desktop_handle);
176 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
177 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
178 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
179 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
180 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
181 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
182 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
183 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
184 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
185 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
189 lf.lfCharSet = ANSI_CHARSET;
190 lf.lfFaceName[0] = 0;
191 lf.lfPitchAndFamily = 0;
192 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
194 messagePumpThread = (jint)GetCurrentThreadId();
195 messagePumpStarted->release();
198 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
200 if (msg.message == WM_USER_CREATEWINDOW) {
201 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
203 // we must create a unique window class name for each
204 // window so that minimization icons can be set independantly
206 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
209 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
210 wc.lpfnWndProc = WndProc;
212 wc.cbSize = sizeof(WNDCLASSEX);
214 wc.hInstance = GetModuleHandle(NULL);
218 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
219 wc.lpszMenuName = NULL;
220 wc.lpszClassName = buf;
221 RegisterClassEx(&wc);
223 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
224 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
225 SetFocus((HWND)surface->hwnd);
226 surface->hwndCreated->release();
229 TranslateMessage(&msg);
230 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
231 DispatchMessage(&msg);
235 java::lang::System::exit(-1);
239 // Platform Methods ///////////////////////////////////////////////////////////////////
241 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
242 int len = JvGetStringUTFLength(key);
244 JvGetStringUTFRegion(key, 0, len, buf);
247 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
248 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
252 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
256 memset(buf, 0, 1024);
257 memset(&ofn, 0, sizeof(OPENFILENAME));
259 if (suggestedFileName != NULL)
260 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
262 ofn.lStructSize = sizeof(OPENFILENAME);
263 ofn.nMaxCustFilter = 0;
267 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
268 ofn.Flags |= OFN_HIDEREADONLY;
270 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
271 return ret == 0 ? NULL : JvNewStringLatin1(buf);
274 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
280 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
281 if (result != ERROR_SUCCESS) return;
286 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
288 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
292 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
293 if (buf[0] != 1) return;
298 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
300 elements(container)[0] = JvNewStringLatin1(buf);
304 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
306 elements(container)[1] = JvNewStringLatin1(buf);
309 jstring org::xwt::plat::Win32::_getClipBoard() {
310 OpenClipboard((HWND)desktop_handle);
311 HGLOBAL hmem = GetClipboardData(CF_TEXT);
312 if (hmem == NULL) return NULL;
313 char* buf = (char*)GlobalLock(hmem);
314 if (buf == NULL) return NULL;
315 jstring ret = JvNewStringLatin1(buf);
321 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
322 OpenClipboard((HWND)desktop_handle);
323 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
324 if (hmem == NULL) return;
325 char* buf = (char*)GlobalLock(hmem);
326 if (buf == NULL) return;
327 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
328 buf[JvGetStringUTFLength(s)] = '\0';
330 SetClipboardData(CF_TEXT, hmem);
334 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
335 char buf[JvGetStringUTFLength(message) + 1];
336 buf[JvGetStringUTFLength(message)] = '\0';
337 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
338 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
339 java::lang::System::exit(-1);
342 jint org::xwt::plat::Win32::_getScreenWidth() {
344 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
345 return rect.right - rect.left;
348 jint org::xwt::plat::Win32::_getScreenHeight() {
350 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
351 return rect.bottom - rect.top;
354 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
355 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
357 memset(&logfont, 0, sizeof(LOGFONT));
358 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
359 if (pf->italic) logfont.lfItalic = 1;
360 if (pf->bold) logfont.lfWeight = FW_BOLD;
361 logfont.lfCharSet = ANSI_CHARSET;
363 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
364 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
366 ret->hfont = (jint)CreateFontIndirect(&logfont);
367 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
370 GetTextMetrics((HDC)desktop_dc, &tm);
372 p.x = 0; p.y = tm.tmAscent;
373 LPtoDP((HDC)desktop_dc, &p, 1);
374 ret->maxAscent = p.y;
376 p.x = 0; p.y = tm.tmDescent;
377 LPtoDP((HDC)desktop_dc, &p, 1);
378 ret->maxDescent = p.y;
383 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
385 HFONT hfont = (HFONT)(getFont(font)->hfont);
386 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
388 int len = min(1024, JvGetStringUTFLength(text));
391 JvGetStringUTFRegion(text, 0, len, buf);
394 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
398 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
400 int len = min(2048, JvGetStringUTFLength(url));
402 JvGetStringUTFRegion(url, 0, len, buf);
406 memset(&ei, 0, sizeof(ei));
407 ei.cbSize = sizeof(ei);
410 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
411 ei.nShow = SW_SHOWDEFAULT;
412 return (ShellExecuteEx(&ei) == 0);
417 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
419 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
420 // Since all drawing operations are single-threaded, it's safe to use a global here.
421 static HBITMAP scratch = NULL;
422 static HDC scratch_dc = NULL;
423 static jint* scratch_bits = NULL;
424 static jint scratch_w = 0;
425 static jint scratch_h = 0;
427 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
428 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
429 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
431 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
433 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
434 jint dx1, jint dy1, jint dx2, jint dy2,
435 jint sx1, jint sy1, jint sx2, jint sy2) {
436 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
438 if (source->hasalpha) {
440 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
441 if (scratch_dc != NULL) DeleteDC(scratch_dc);
442 if (scratch != NULL) DeleteObject(scratch);
443 scratch_w = max(dx2 - dx1, scratch_w);
444 scratch_h = max(dy2 - dy1, scratch_h);
446 BITMAPINFO bitmapinfo;
447 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
448 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
449 bitmapinfo.bmiHeader.biWidth = scratch_w;
450 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
451 bitmapinfo.bmiHeader.biPlanes = 1;
452 bitmapinfo.bmiHeader.biBitCount = 32;
453 bitmapinfo.bmiHeader.biCompression = BI_RGB;
455 // create section DIB
456 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
457 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
458 SelectObject(scratch_dc, scratch);
461 // copy from screen to scratch
462 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
464 // apply alpha-blending to scratch
465 jint* dat = elements(source->data);
467 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
468 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
469 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
470 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
471 jint dst = scratch_bits[y * scratch_w + x];
472 jint src = dat[sy * source->getWidth() + sx];
473 jint alpha = (src & 0xFF000000) >> 24;
474 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
475 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
476 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
477 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
480 // copy back from scratch to screen
481 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
484 if (source->hasmask) {
485 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
486 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
488 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
495 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
497 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
498 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
500 // Platform API passes us the y-pos of the bottom of the text; we need the top
503 int len = min(1024, JvGetStringUTFLength(text));
506 JvGetStringUTFRegion(text, 0, len, buf);
508 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
509 TextOut((HDC)hdc, x, y, buf, len);
512 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
516 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
517 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
519 RECT rect = { x, y, x + w, y + h };
520 FillRect((HDC)hdc, &rect, brush);
524 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
525 // we create the DC lazily to get around some strange race condition in WinXP
526 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
527 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
530 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
531 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
532 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
533 SetBkMode((HDC)hdc, TRANSPARENT);
534 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
537 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
538 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
539 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
540 SelectClipRgn((HDC)hdc, hrgn);
544 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
545 DeleteObject((void*)hdc);
546 DeleteObject((void*)hbitmap);
551 // Win32Picture /////////////////////////////////////////////////////////////////////////
553 void org::xwt::plat::Win32$Win32Picture::natInit() {
555 BITMAPINFO bitmapinfo;
556 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
557 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
558 bitmapinfo.bmiHeader.biWidth = w;
559 bitmapinfo.bmiHeader.biHeight = -1 * h;
560 bitmapinfo.bmiHeader.biPlanes = 1;
561 bitmapinfo.bmiHeader.biBitCount = 32;
562 bitmapinfo.bmiHeader.biCompression = BI_RGB;
564 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
565 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
566 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
567 uint32_t* dat = (uint32_t*)elements(data);
568 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
569 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
571 jint _copy[min(1024, data->length)];
572 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
574 memcpy(copy, elements(data), data->length * 4);
575 for(int i=0; i<data->length; i++)
576 if ((copy[i] & 0xFF000000) == 0x00000000) {
578 copy[i] = 0x00FFFFFF;
579 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
580 copy[i] = 0x00000000;
584 if (data->length > 1024) free(copy);
589 if (data->length > 1024) free(copy);
593 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
594 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
595 maskdc = (jint)CreateCompatibleDC(NULL);
596 SelectObject((HDC)maskdc, (HBITMAP)hmask);
597 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
598 if (data->length > 1024) free(copy);
603 // Win32Surface /////////////////////////////////////////////////////////////////////////////
605 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
607 // Ask the message-handling thread to create a window for us
608 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
609 hwndCreated->block();
611 // turn on incremental GC now that we have a user-visible interface
612 // [[this is causing segfaults; enable it later...]]
613 // GC_enable_incremental();
615 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
618 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
619 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
620 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
621 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
622 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
623 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
624 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
625 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
627 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
632 ClientToScreen((HWND)hwnd, &point);
633 GetWindowRect((HWND)hwnd, &rect);
634 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
637 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
638 RECT client_rect, window_rect;
639 GetClientRect((HWND)hwnd, &client_rect);
640 GetWindowRect((HWND)hwnd, &window_rect);
641 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
642 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
643 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
646 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
647 int len = min(1024, JvGetStringUTFLength(title));
650 JvGetStringUTFRegion(title, 0, len, buf);
651 SetWindowText((HWND)hwnd, buf);
654 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
656 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
657 int icon_width = GetSystemMetrics(SM_CXSMICON);
658 int icon_height = GetSystemMetrics(SM_CYSMICON);
660 // we create the DC lazily to get around some strange race condition in WinXP
661 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
664 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
665 HDC memdc = CreateCompatibleDC((HDC)hdc);
666 SelectObject(memdc, bit);
667 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
670 jint* dat = elements(p->data);
671 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
672 SelectObject(memdc, bit_mask);
673 for(int x=0; x<icon_width; x++)
674 for(int y=0; y<icon_height; y++) {
675 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
676 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
677 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
680 // instantiate the icon and assign it to the window class
683 ici.hbmMask = bit_mask;
685 HICON hicon = CreateIconIndirect(&ici);
686 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
687 if (oldicon != NULL) DestroyIcon(oldicon);
691 static jstring keyToString(WPARAM wParam);
692 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
694 UINT iMsg = (UINT)_iMsg;
695 WPARAM wParam = (WPARAM)_wParam;
696 LPARAM lParam = (LPARAM)_lParam;
698 int oldmousex, oldmousey;
703 RECT client_rect, window_rect;
707 int addwidth, addheight;
710 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
711 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
712 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
713 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
715 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
717 KeyPressed(keyToString(wParam));
720 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
722 KeyReleased(keyToString(wParam));
725 case WM_SETFOCUS: Focused(true); return 0;
726 case WM_KILLFOCUS: Focused(false); return 0;
727 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
728 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
729 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
730 case WM_LBUTTONDOWN: Press(1); return 0;
731 case WM_RBUTTONDOWN: Press(2); return 0;
732 case WM_MBUTTONDOWN: Press(3); return 0;
733 case WM_CLOSE: Close(); return 0;
734 case WM_ERASEBKGND: return 0;
739 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
740 if (captured && !inside) {
742 SetCursor((HCURSOR)previous_cursor);
747 GetClientRect((HWND)hwnd, &rect);
748 PosChange(rect.left, rect.top);
752 if (wParam == SIZE_MINIMIZED) {
753 if (maximized) Maximized(false);
755 } else if (wParam == SIZE_MAXIMIZED) {
756 if (minimized) Minimized(false);
759 if (minimized) Minimized(false);
760 if (maximized) Maximized(false);
762 // deliberately fall through to WM_SIZING
765 GetClientRect((HWND)hwnd, &rect);
766 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
770 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
772 GetClientRect((HWND)hwnd, &rect);
773 point.x = mouse_x = lParam & 0xFFFF;
774 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
775 ClientToScreen((HWND)hwnd, &point);
776 hwnd2 = WindowFromPoint(point);
778 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
780 Move(mouse_x, mouse_y);
782 if (newinside && !inside) {
784 SetCapture((HWND)hwnd);
786 previous_cursor = (jint)GetCursor();
787 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
789 } else if (!newinside && inside) {
791 if (!button1 && !button2 && !button3) {
794 SetCursor((HCURSOR)previous_cursor);
800 case WM_USER_SETCURSOR:
801 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
802 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
803 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
804 // cursor should be re-set to "current_cursor".
805 SetCursor((HCURSOR)current_cursor);
808 case WM_USER_DISPOSE:
809 // used to signal that we should destroy ourselves
810 DestroyWindow((HWND)hwnd);
813 case WM_GETMINMAXINFO:
814 GetClientRect((HWND)hwnd, &client_rect);
815 GetWindowRect((HWND)hwnd, &window_rect);
816 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
817 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
818 mmi = (MINMAXINFO*)lParam;
819 mmi->ptMinTrackSize.x = ((uint32_t)root->dmin(0)) + addwidth;
820 mmi->ptMinTrackSize.y = ((uint32_t)root->dmin(1)) + addheight;
821 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->dmax(0)) + addwidth);
822 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->dmax(1)) + addheight);
827 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
828 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
829 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
835 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
839 // Key Translator Helper /////////////////////////////////////////////////////////////////////
841 static char keyarr [256] = { 0 };
842 static jstring keyToString(WPARAM wParam) {
844 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
845 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
846 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
847 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
849 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
851 case '\t': return JvNewStringLatin1("tab");
852 case 0x1b: return JvNewStringLatin1("escape");
853 case '\n': return JvNewStringLatin1("enter");
854 case '\r': return JvNewStringLatin1("enter");
855 case 0x08: return JvNewStringLatin1("back_space");
856 default: return JvNewStringLatin1(arr, 1);
859 } else switch (wParam) {
860 case VK_CLEAR: return JvNewStringLatin1("clear");
861 case VK_SHIFT: return JvNewStringLatin1("shift");
862 case VK_CONTROL: return JvNewStringLatin1("control");
863 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
864 case VK_MENU: return JvNewStringLatin1("alt");
865 case VK_PAUSE: return JvNewStringLatin1("pause");
866 case VK_PRIOR: return JvNewStringLatin1("page_up");
867 case VK_NEXT: return JvNewStringLatin1("page_down");
868 case VK_END: return JvNewStringLatin1("end");
869 case VK_HOME: return JvNewStringLatin1("home");
870 case VK_LEFT: return JvNewStringLatin1("left");
871 case VK_UP: return JvNewStringLatin1("up");
872 case VK_RIGHT: return JvNewStringLatin1("right");
873 case VK_DOWN: return JvNewStringLatin1("down");
874 case VK_INSERT: return JvNewStringLatin1("insert");
875 case VK_DELETE: return JvNewStringLatin1("delete");
876 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
877 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
878 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
879 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
880 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
881 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
882 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
883 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
884 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
885 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
886 case VK_F1: return JvNewStringLatin1("f1");
887 case VK_F2: return JvNewStringLatin1("f2");
888 case VK_F3: return JvNewStringLatin1("f3");
889 case VK_F4: return JvNewStringLatin1("f4");
890 case VK_F5: return JvNewStringLatin1("f5");
891 case VK_F6: return JvNewStringLatin1("f6");
892 case VK_F7: return JvNewStringLatin1("f7");
893 case VK_F8: return JvNewStringLatin1("f8");
894 case VK_F9: return JvNewStringLatin1("f9");
895 case VK_F10: return JvNewStringLatin1("f10");
896 case VK_F11: return JvNewStringLatin1("f11");
897 case VK_F12: return JvNewStringLatin1("f12");
898 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
899 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
900 case VK_LSHIFT: return JvNewStringLatin1("shift");
901 case VK_RSHIFT: return JvNewStringLatin1("shift");
902 case VK_LCONTROL: return JvNewStringLatin1("control");
903 case VK_RCONTROL: return JvNewStringLatin1("control");