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::_fileDialog(jstring suggestedFileName, jboolean write) {
243 memset(buf, 0, 1024);
244 memset(&ofn, 0, sizeof(OPENFILENAME));
246 if (suggestedFileName != NULL)
247 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
249 ofn.lStructSize = sizeof(OPENFILENAME);
250 ofn.nMaxCustFilter = 0;
254 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
255 ofn.Flags |= OFN_HIDEREADONLY;
257 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
258 return ret == 0 ? NULL : JvNewStringLatin1(buf);
261 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
267 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
268 if (result != ERROR_SUCCESS) return;
273 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
275 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
279 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
280 if (buf[0] != 1) return;
285 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
287 elements(container)[0] = JvNewStringLatin1(buf);
291 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
293 elements(container)[1] = JvNewStringLatin1(buf);
296 jstring org::xwt::plat::Win32::_getClipBoard() {
297 OpenClipboard((HWND)desktop_handle);
298 HGLOBAL hmem = GetClipboardData(CF_TEXT);
299 if (hmem == NULL) return NULL;
300 char* buf = (char*)GlobalLock(hmem);
301 if (buf == NULL) return NULL;
302 jstring ret = JvNewStringLatin1(buf);
308 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
309 OpenClipboard((HWND)desktop_handle);
310 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
311 if (hmem == NULL) return;
312 char* buf = (char*)GlobalLock(hmem);
313 if (buf == NULL) return;
314 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
315 buf[JvGetStringUTFLength(s)] = '\0';
317 SetClipboardData(CF_TEXT, hmem);
321 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
322 char buf[JvGetStringUTFLength(message) + 1];
323 buf[JvGetStringUTFLength(message)] = '\0';
324 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
325 MessageBox (NULL, buf, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
326 java::lang::System::exit(-1);
329 jint org::xwt::plat::Win32::_getScreenWidth() {
331 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
332 return rect.right - rect.left;
335 jint org::xwt::plat::Win32::_getScreenHeight() {
337 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
338 return rect.bottom - rect.top;
341 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
342 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
344 memset(&logfont, 0, sizeof(LOGFONT));
345 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
346 if (pf->italic) logfont.lfItalic = 1;
347 if (pf->bold) logfont.lfWeight = FW_BOLD;
348 logfont.lfCharSet = ANSI_CHARSET;
350 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
351 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
353 ret->hfont = (jint)CreateFontIndirect(&logfont);
354 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
357 GetTextMetrics((HDC)desktop_dc, &tm);
359 p.x = 0; p.y = tm.tmAscent;
360 LPtoDP((HDC)desktop_dc, &p, 1);
361 ret->maxAscent = p.y;
363 p.x = 0; p.y = tm.tmDescent;
364 LPtoDP((HDC)desktop_dc, &p, 1);
365 ret->maxDescent = p.y;
370 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
372 HFONT hfont = (HFONT)(getFont(font)->hfont);
373 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
375 int len = min(1024, JvGetStringUTFLength(text));
378 JvGetStringUTFRegion(text, 0, len, buf);
381 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
385 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
387 int len = min(2048, JvGetStringUTFLength(url));
389 JvGetStringUTFRegion(url, 0, len, buf);
393 memset(&ei, 0, sizeof(ei));
394 ei.cbSize = sizeof(ei);
397 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
398 ei.nShow = SW_SHOWDEFAULT;
399 return (ShellExecuteEx(&ei) == 0);
404 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
406 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
407 // Since all drawing operations are single-threaded, it's safe to use a global here.
408 static HBITMAP scratch = NULL;
409 static HDC scratch_dc = NULL;
410 static jint* scratch_bits = NULL;
411 static jint scratch_w = 0;
412 static jint scratch_h = 0;
414 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
415 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
416 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
418 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
420 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
421 jint dx1, jint dy1, jint dx2, jint dy2,
422 jint sx1, jint sy1, jint sx2, jint sy2) {
424 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
426 if (source->hasalpha) {
428 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
429 if (scratch_dc != NULL) DeleteDC(scratch_dc);
430 if (scratch != NULL) DeleteObject(scratch);
431 scratch_w = max(dx2 - dx1, scratch_w);
432 scratch_h = max(dy2 - dy1, scratch_h);
434 BITMAPINFO bitmapinfo;
435 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
436 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
437 bitmapinfo.bmiHeader.biWidth = scratch_w;
438 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
439 bitmapinfo.bmiHeader.biPlanes = 1;
440 bitmapinfo.bmiHeader.biBitCount = 32;
441 bitmapinfo.bmiHeader.biCompression = BI_RGB;
443 // create section DIB
444 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
445 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
446 SelectObject(scratch_dc, scratch);
449 // copy from screen to scratch
450 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
452 // apply alpha-blending to scratch
453 jint* dat = elements(source->data);
455 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
456 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
457 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
458 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
459 jint dst = scratch_bits[y * scratch_w + x];
460 jint src = dat[sy * source->getWidth() + sx];
461 jint alpha = (src & 0xFF000000) >> 24;
462 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
463 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
464 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
465 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
468 // copy back from scratch to screen
469 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
472 if (source->hasmask) {
473 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
474 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
476 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
483 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
485 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
486 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
488 // Platform API passes us the y-pos of the bottom of the text; we need the top
491 int len = min(1024, JvGetStringUTFLength(text));
494 JvGetStringUTFRegion(text, 0, len, buf);
496 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
497 TextOut((HDC)hdc, x, y, buf, len);
500 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
504 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
505 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
507 RECT rect = { x, y, x + w, y + h };
508 FillRect((HDC)hdc, &rect, brush);
512 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
513 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
516 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
517 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
518 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
519 SetBkMode((HDC)hdc, TRANSPARENT);
520 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
523 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
524 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
525 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
526 SelectClipRgn((HDC)hdc, hrgn);
530 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
531 DeleteObject((void*)hdc);
532 DeleteObject((void*)hbitmap);
537 // Win32Picture /////////////////////////////////////////////////////////////////////////
539 void org::xwt::plat::Win32$Win32Picture::natInit() {
541 BITMAPINFO bitmapinfo;
542 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
543 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
544 bitmapinfo.bmiHeader.biWidth = w;
545 bitmapinfo.bmiHeader.biHeight = -1 * h;
546 bitmapinfo.bmiHeader.biPlanes = 1;
547 bitmapinfo.bmiHeader.biBitCount = 32;
548 bitmapinfo.bmiHeader.biCompression = BI_RGB;
550 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
551 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
552 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
553 uint32_t* dat = (uint32_t*)elements(data);
554 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
555 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
557 jint _copy[min(1024, data->length)];
558 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
560 memcpy(copy, elements(data), data->length * 4);
561 for(int i=0; i<data->length; i++)
562 if ((copy[i] & 0xFF000000) == 0x00000000) {
564 copy[i] = 0x00FFFFFF;
565 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
566 copy[i] = 0x00000000;
570 if (data->length > 1024) free(copy);
575 if (data->length > 1024) free(copy);
579 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
580 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
581 maskdc = (jint)CreateCompatibleDC(NULL);
582 SelectObject((HDC)maskdc, (HBITMAP)hmask);
583 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
584 if (data->length > 1024) free(copy);
589 // Win32Surface /////////////////////////////////////////////////////////////////////////////
591 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
593 // Ask the message-handling thread to create a window for us
594 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
595 hwndCreated->block();
597 // turn on incremental GC now that we have a user-visible interface
598 // [[this is causing segfaults; enable it later...]]
599 // GC_enable_incremental();
601 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
602 hdc = (jint)GetDC((HWND)hwnd);
605 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
606 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
607 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
608 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
609 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
610 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
611 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
612 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
614 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
619 ClientToScreen((HWND)hwnd, &point);
620 GetWindowRect((HWND)hwnd, &rect);
621 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
624 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
625 RECT client_rect, window_rect;
626 GetClientRect((HWND)hwnd, &client_rect);
627 GetWindowRect((HWND)hwnd, &window_rect);
628 int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
629 int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
630 SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
633 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
634 int len = min(1024, JvGetStringUTFLength(title));
637 JvGetStringUTFRegion(title, 0, len, buf);
638 SetWindowText((HWND)hwnd, buf);
641 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
643 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
644 int icon_width = GetSystemMetrics(SM_CXSMICON);
645 int icon_height = GetSystemMetrics(SM_CYSMICON);
648 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
649 HDC memdc = CreateCompatibleDC((HDC)hdc);
650 SelectObject(memdc, bit);
651 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
654 jint* dat = elements(p->data);
655 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
656 SelectObject(memdc, bit_mask);
657 for(int x=0; x<icon_width; x++)
658 for(int y=0; y<icon_height; y++) {
659 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
660 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
661 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
664 // instantiate the icon and assign it to the window class
667 ici.hbmMask = bit_mask;
669 HICON hicon = CreateIconIndirect(&ici);
670 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
671 if (oldicon != NULL) DestroyIcon(oldicon);
675 static jstring keyToString(WPARAM wParam);
676 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
678 UINT iMsg = (UINT)_iMsg;
679 WPARAM wParam = (WPARAM)_wParam;
680 LPARAM lParam = (LPARAM)_lParam;
682 int oldmousex, oldmousey;
692 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
693 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
694 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
695 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
697 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
699 KeyPressed(keyToString(wParam));
702 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
704 KeyReleased(keyToString(wParam));
707 case WM_SETFOCUS: Focused(true); return 0;
708 case WM_KILLFOCUS: Focused(false); return 0;
709 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
710 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
711 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
712 case WM_LBUTTONDOWN: Press(1); return 0;
713 case WM_RBUTTONDOWN: Press(2); return 0;
714 case WM_MBUTTONDOWN: Press(3); return 0;
715 case WM_CLOSE: Close(); return 0;
716 case WM_ERASEBKGND: return 0;
721 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
722 if (captured && !inside) {
724 SetCursor((HCURSOR)previous_cursor);
729 GetClientRect((HWND)hwnd, &rect);
730 PosChange(rect.left, rect.top);
734 if (wParam == SIZE_MINIMIZED) {
735 if (maximized) Maximized(false);
737 } else if (wParam == SIZE_MAXIMIZED) {
738 if (minimized) Minimized(false);
741 if (minimized) Minimized(false);
742 if (maximized) Maximized(false);
744 // deliberately fall through to WM_SIZING
747 GetClientRect((HWND)hwnd, &rect);
748 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
752 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
754 GetClientRect((HWND)hwnd, &rect);
755 point.x = mouse_x = lParam & 0xFFFF;
756 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
757 ClientToScreen((HWND)hwnd, &point);
758 hwnd2 = WindowFromPoint(point);
760 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
762 Move(mouse_x, mouse_y);
764 if (newinside && !inside) {
766 SetCapture((HWND)hwnd);
768 previous_cursor = (jint)GetCursor();
769 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
771 } else if (!newinside && inside) {
773 if (!button1 && !button2 && !button3) {
776 SetCursor((HCURSOR)previous_cursor);
782 case WM_USER_SETCURSOR:
783 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
784 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
785 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
786 // cursor should be re-set to "current_cursor".
787 SetCursor((HCURSOR)current_cursor);
790 case WM_USER_DISPOSE:
791 // used to signal that we should destroy ourselves
792 DestroyWindow((HWND)hwnd);
795 case WM_GETMINMAXINFO:
796 mmi = (MINMAXINFO*)lParam;
797 mmi->ptMinTrackSize.x = root->dmin(0);
798 mmi->ptMinTrackSize.y = root->dmin(1);
799 mmi->ptMaxTrackSize.x = root->dmax(0);
800 mmi->ptMaxTrackSize.y = root->dmax(1);
805 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
806 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
807 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
813 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
817 // Key Translator Helper /////////////////////////////////////////////////////////////////////
819 static char keyarr [256] = { 0 };
820 static jstring keyToString(WPARAM wParam) {
822 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
823 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
824 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
825 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
827 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
829 case '\t': return JvNewStringLatin1("tab");
830 case 0x1b: return JvNewStringLatin1("escape");
831 case '\n': return JvNewStringLatin1("enter");
832 case '\r': return JvNewStringLatin1("enter");
833 case 0x08: return JvNewStringLatin1("back_space");
834 default: return JvNewStringLatin1(arr, 1);
837 } else switch (wParam) {
838 case VK_CLEAR: return JvNewStringLatin1("clear");
839 case VK_SHIFT: return JvNewStringLatin1("shift");
840 case VK_CONTROL: return JvNewStringLatin1("control");
841 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
842 case VK_MENU: return JvNewStringLatin1("alt");
843 case VK_PAUSE: return JvNewStringLatin1("pause");
844 case VK_PRIOR: return JvNewStringLatin1("page_up");
845 case VK_NEXT: return JvNewStringLatin1("page_down");
846 case VK_END: return JvNewStringLatin1("end");
847 case VK_HOME: return JvNewStringLatin1("home");
848 case VK_LEFT: return JvNewStringLatin1("left");
849 case VK_UP: return JvNewStringLatin1("up");
850 case VK_RIGHT: return JvNewStringLatin1("right");
851 case VK_DOWN: return JvNewStringLatin1("down");
852 case VK_INSERT: return JvNewStringLatin1("insert");
853 case VK_DELETE: return JvNewStringLatin1("delete");
854 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
855 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
856 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
857 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
858 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
859 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
860 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
861 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
862 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
863 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
864 case VK_F1: return JvNewStringLatin1("f1");
865 case VK_F2: return JvNewStringLatin1("f2");
866 case VK_F3: return JvNewStringLatin1("f3");
867 case VK_F4: return JvNewStringLatin1("f4");
868 case VK_F5: return JvNewStringLatin1("f5");
869 case VK_F6: return JvNewStringLatin1("f6");
870 case VK_F7: return JvNewStringLatin1("f7");
871 case VK_F8: return JvNewStringLatin1("f8");
872 case VK_F9: return JvNewStringLatin1("f9");
873 case VK_F10: return JvNewStringLatin1("f10");
874 case VK_F11: return JvNewStringLatin1("f11");
875 case VK_F12: return JvNewStringLatin1("f12");
876 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
877 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
878 case VK_LSHIFT: return JvNewStringLatin1("shift");
879 case VK_RSHIFT: return JvNewStringLatin1("shift");
880 case VK_LCONTROL: return JvNewStringLatin1("control");
881 case VK_RCONTROL: return JvNewStringLatin1("control");