1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
4 // we have to do this because the jpeg libraries use the symbol 'INT32'
5 #define INT32 WIN32_INT32
7 // this has to precede the others so we don't get collisions on min/max
8 #include <org/xwt/util/JSObject.h>
9 #include <org/xwt/Box.h>
24 #include <java/lang/Integer.h>
25 #include <java/util/Hashtable.h>
26 #include <org/xwt/Box.h>
27 #include <org/xwt/Surface.h>
28 #include <org/xwt/DoubleBuffer.h>
29 #include <org/xwt/Picture.h>
30 #include <org/xwt/ByteStream.h>
31 #include <org/xwt/Platform.h>
32 #include <org/xwt/Platform$ParsedFont.h>
33 #include <org/xwt/plat/Win32.h>
34 #include <org/xwt/plat/Win32$Win32Font.h>
35 #include <org/xwt/plat/Win32$Win32Surface.h>
36 #include <org/xwt/plat/Win32$Win32DoubleBuffer.h>
37 #include <org/xwt/plat/Win32$Win32Picture.h>
38 #include <org/xwt/util/Log.h>
39 #include <org/xwt/util/Semaphore.h>
42 #include <java/lang/System.h>
43 #include <java/io/PrintStream.h>
45 #define WM_USER_SETCURSOR WM_USER
46 #define WM_USER_DISPOSE (WM_USER + 1)
47 #define WM_USER_CREATEWINDOW (WM_USER + 2)
48 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
50 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
51 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
53 // Callbacks ////////////////////////////////////////////////////////////////////
55 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
56 org::xwt::plat::Win32$Win32Surface* surface =
57 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
59 if (surface != NULL) {
60 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
63 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
64 return DefWindowProc(hwnd, iMsg, wParam, lParam);
68 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
69 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
73 lf.lfCharSet = ANSI_CHARSET;
74 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
75 lf.lfPitchAndFamily = 0;
76 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
79 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
80 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
81 tm->tmItalic == 0 ? 0 : 1,
82 tm->tmWeight <= 400 ? 0 : 1);
88 // Initialization ////////////////////////////////////////////////////////////////////
90 static int window_class_counter = 0;
92 jstring org::xwt::plat::Win32::getTempPath() {
94 DWORD ret = GetTempPath(1024, buf);
95 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
96 return JvNewStringLatin1(buf);
99 // XOR mask for the hand cursor
100 static unsigned char hand_cursor_xor[32 * 4] = {
101 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x0C, 0x00, 0x00,
103 0x00, 0x0C, 0x00, 0x00,
104 0x00, 0x0C, 0x00, 0x00,
105 0x00, 0x0C, 0x00, 0x00,
106 0x00, 0x0C, 0x00, 0x00,
107 0x00, 0x0D, 0x80, 0x00,
108 0x00, 0x0D, 0xB0, 0x00,
109 0x00, 0x0D, 0xB4, 0x00,
110 0x00, 0x0D, 0xB6, 0x00,
111 0x00, 0xCF, 0xF6, 0x00,
112 0x00, 0xEF, 0xFE, 0x00,
113 0x00, 0x6F, 0xFE, 0x00,
114 0x00, 0x2F, 0xFE, 0x00,
115 0x00, 0x3F, 0xFE, 0x00,
116 0x00, 0x1F, 0xFE, 0x00,
117 0x00, 0x1F, 0xFC, 0x00,
118 0x00, 0x0F, 0xFC, 0x00,
119 0x00, 0x0F, 0xFC, 0x00,
120 0x00, 0x07, 0xF8, 0x00,
121 0x00, 0x07, 0xF8, 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,
130 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00
135 // AND mask for the hand cursor
136 static unsigned char hand_cursor_and[32 * 4] = {
137 0xFF, 0xF3, 0xFF, 0xFF,
138 0xFF, 0xE1, 0xFF, 0xFF,
139 0xFF, 0xE1, 0xFF, 0xFF,
140 0xFF, 0xE1, 0xFF, 0xFF,
141 0xFF, 0xE1, 0xFF, 0xFF,
142 0xFF, 0xE0, 0x7F, 0xFF,
143 0xFF, 0xE0, 0x0F, 0xFF,
144 0xFF, 0xE0, 0x03, 0xFF,
145 0xFF, 0xE0, 0x01, 0xFF,
146 0xFF, 0x20, 0x00, 0xFF,
147 0xFE, 0x00, 0x00, 0xFF,
148 0xFE, 0x00, 0x00, 0xFF,
149 0xFF, 0x00, 0x00, 0xFF,
150 0xFF, 0x80, 0x00, 0xFF,
151 0xFF, 0x80, 0x00, 0xFF,
152 0xFF, 0xC0, 0x00, 0xFF,
153 0xFF, 0xC0, 0x01, 0xFF,
154 0xFF, 0xE0, 0x01, 0xFF,
155 0xFF, 0xE0, 0x01, 0xFF,
156 0xFF, 0xF0, 0x03, 0xFF,
157 0xFF, 0xF0, 0x03, 0xFF,
158 0xFF, 0xF0, 0x03, 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,
166 0xFF, 0xFF, 0xFF, 0xFF,
167 0xFF, 0xFF, 0xFF, 0xFF,
168 0xFF, 0xFF, 0xFF, 0xFF
172 void org::xwt::plat::Win32::natInit() {
174 // grab desktop dc/handle
175 desktop_handle = (jint)GetDesktopWindow();
176 desktop_dc = (jint)GetDC((HWND)desktop_handle);
179 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
180 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
181 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
182 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
183 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
184 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
185 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
186 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
187 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
188 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
192 lf.lfCharSet = ANSI_CHARSET;
193 lf.lfFaceName[0] = 0;
194 lf.lfPitchAndFamily = 0;
195 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
197 messagePumpThread = (jint)GetCurrentThreadId();
198 messagePumpStarted->release();
201 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
203 if (msg.message == WM_USER_CREATEWINDOW) {
204 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
206 // we must create a unique window class name for each
207 // window so that minimization icons can be set independantly
209 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
212 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
213 wc.lpfnWndProc = WndProc;
215 wc.cbSize = sizeof(WNDCLASSEX);
217 wc.hInstance = GetModuleHandle(NULL);
221 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
222 wc.lpszMenuName = NULL;
223 wc.lpszClassName = buf;
224 RegisterClassEx(&wc);
226 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
227 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
228 SetFocus((HWND)surface->hwnd);
229 surface->hwndCreated->release();
232 TranslateMessage(&msg);
233 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
234 DispatchMessage(&msg);
238 java::lang::System::exit(-1);
242 // Platform Methods ///////////////////////////////////////////////////////////////////
244 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
245 int len = JvGetStringUTFLength(key);
247 JvGetStringUTFRegion(key, 0, len, buf);
250 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
251 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
255 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
259 memset(buf, 0, 1024);
260 memset(&ofn, 0, sizeof(OPENFILENAME));
262 if (suggestedFileName != NULL)
263 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
265 ofn.lStructSize = sizeof(OPENFILENAME);
266 ofn.nMaxCustFilter = 0;
270 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
271 ofn.Flags |= OFN_HIDEREADONLY;
273 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
274 return ret == 0 ? NULL : JvNewStringLatin1(buf);
277 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
283 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
284 if (result != ERROR_SUCCESS) return;
289 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
291 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
295 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
296 if (buf[0] != 1) return;
301 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
303 elements(container)[0] = JvNewStringLatin1(buf);
307 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
309 elements(container)[1] = JvNewStringLatin1(buf);
312 jstring org::xwt::plat::Win32::_getClipBoard() {
313 OpenClipboard((HWND)desktop_handle);
314 HGLOBAL hmem = GetClipboardData(CF_TEXT);
315 if (hmem == NULL) return NULL;
316 char* buf = (char*)GlobalLock(hmem);
317 if (buf == NULL) return NULL;
318 jstring ret = JvNewStringLatin1(buf);
324 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
325 OpenClipboard((HWND)desktop_handle);
326 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
327 if (hmem == NULL) return;
328 char* buf = (char*)GlobalLock(hmem);
329 if (buf == NULL) return;
330 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
331 buf[JvGetStringUTFLength(s)] = '\0';
333 SetClipboardData(CF_TEXT, hmem);
337 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
338 char buf[JvGetStringUTFLength(message) + 1];
339 buf[JvGetStringUTFLength(message)] = '\0';
340 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
341 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
342 java::lang::System::exit(-1);
345 jint org::xwt::plat::Win32::_getScreenWidth() {
347 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
348 return rect.right - rect.left;
351 jint org::xwt::plat::Win32::_getScreenHeight() {
353 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
354 return rect.bottom - rect.top;
357 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
358 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
360 memset(&logfont, 0, sizeof(LOGFONT));
361 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
362 if (pf->italic) logfont.lfItalic = 1;
363 if (pf->bold) logfont.lfWeight = FW_BOLD;
364 logfont.lfCharSet = ANSI_CHARSET;
366 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
367 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
369 ret->hfont = (jint)CreateFontIndirect(&logfont);
370 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
373 GetTextMetrics((HDC)desktop_dc, &tm);
375 p.x = 0; p.y = tm.tmAscent;
376 LPtoDP((HDC)desktop_dc, &p, 1);
377 ret->maxAscent = p.y;
379 p.x = 0; p.y = tm.tmDescent;
380 LPtoDP((HDC)desktop_dc, &p, 1);
381 ret->maxDescent = p.y;
386 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
388 HFONT hfont = (HFONT)(getFont(font)->hfont);
389 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
391 int len = min(1024, JvGetStringUTFLength(text));
394 JvGetStringUTFRegion(text, 0, len, buf);
397 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
401 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
403 int len = min(2048, JvGetStringUTFLength(url));
405 JvGetStringUTFRegion(url, 0, len, buf);
409 memset(&ei, 0, sizeof(ei));
410 ei.cbSize = sizeof(ei);
413 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
414 ei.nShow = SW_SHOWDEFAULT;
415 return (ShellExecuteEx(&ei) == 0);
420 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
422 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
423 // Since all drawing operations are single-threaded, it's safe to use a global here.
424 static HBITMAP scratch = NULL;
425 static HDC scratch_dc = NULL;
426 static jint* scratch_bits = NULL;
427 static jint scratch_w = 0;
428 static jint scratch_h = 0;
430 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
431 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
432 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
434 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
436 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
437 jint dx1, jint dy1, jint dx2, jint dy2,
438 jint sx1, jint sy1, jint sx2, jint sy2) {
439 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
441 if (source->hasalpha) {
443 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
444 if (scratch_dc != NULL) DeleteDC(scratch_dc);
445 if (scratch != NULL) DeleteObject(scratch);
446 scratch_w = max(dx2 - dx1, scratch_w);
447 scratch_h = max(dy2 - dy1, scratch_h);
449 BITMAPINFO bitmapinfo;
450 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
451 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
452 bitmapinfo.bmiHeader.biWidth = scratch_w;
453 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
454 bitmapinfo.bmiHeader.biPlanes = 1;
455 bitmapinfo.bmiHeader.biBitCount = 32;
456 bitmapinfo.bmiHeader.biCompression = BI_RGB;
458 // create section DIB
459 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
460 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
461 SelectObject(scratch_dc, scratch);
464 // copy from screen to scratch
465 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
467 // apply alpha-blending to scratch
468 jint* dat = elements(source->data);
470 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
471 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
472 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
473 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
474 jint dst = scratch_bits[y * scratch_w + x];
475 jint src = dat[sy * source->getWidth() + sx];
476 jint alpha = (src & 0xFF000000) >> 24;
477 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
478 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
479 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
480 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
483 // copy back from scratch to screen
484 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
487 if (source->hasmask) {
488 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
489 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
491 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
498 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
500 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
501 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
503 // Platform API passes us the y-pos of the bottom of the text; we need the top
506 int len = min(1024, JvGetStringUTFLength(text));
509 JvGetStringUTFRegion(text, 0, len, buf);
511 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
512 TextOut((HDC)hdc, x, y, buf, len);
515 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
519 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
520 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
522 RECT rect = { x, y, x + w, y + h };
523 FillRect((HDC)hdc, &rect, brush);
527 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
528 // we create the DC lazily to get around some strange race condition in WinXP
529 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
530 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
533 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
534 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
535 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
536 SetBkMode((HDC)hdc, TRANSPARENT);
537 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
540 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
541 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
542 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
543 SelectClipRgn((HDC)hdc, hrgn);
547 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
548 DeleteObject((void*)hdc);
549 DeleteObject((void*)hbitmap);
554 // Win32Picture /////////////////////////////////////////////////////////////////////////
556 void org::xwt::plat::Win32$Win32Picture::natInit() {
558 BITMAPINFO bitmapinfo;
559 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
560 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
561 bitmapinfo.bmiHeader.biWidth = w;
562 bitmapinfo.bmiHeader.biHeight = -1 * h;
563 bitmapinfo.bmiHeader.biPlanes = 1;
564 bitmapinfo.bmiHeader.biBitCount = 32;
565 bitmapinfo.bmiHeader.biCompression = BI_RGB;
567 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
568 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
569 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
570 uint32_t* dat = (uint32_t*)elements(data);
571 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
572 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
574 jint _copy[min(1024, data->length)];
575 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
577 memcpy(copy, elements(data), data->length * 4);
578 for(int i=0; i<data->length; i++)
579 if ((copy[i] & 0xFF000000) == 0x00000000) {
581 copy[i] = 0x00FFFFFF;
582 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
583 copy[i] = 0x00000000;
587 if (data->length > 1024) free(copy);
592 if (data->length > 1024) free(copy);
596 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
597 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
598 maskdc = (jint)CreateCompatibleDC(NULL);
599 SelectObject((HDC)maskdc, (HBITMAP)hmask);
600 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
601 if (data->length > 1024) free(copy);
606 // Win32Surface /////////////////////////////////////////////////////////////////////////////
608 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
610 // Ask the message-handling thread to create a window for us
611 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
612 hwndCreated->block();
614 // turn on incremental GC now that we have a user-visible interface
615 // [[this is causing segfaults; enable it later...]]
616 // GC_enable_incremental();
618 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
621 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
622 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
623 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
624 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
625 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
626 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
627 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
628 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
630 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
635 ClientToScreen((HWND)hwnd, &point);
636 GetWindowRect((HWND)hwnd, &rect);
637 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
640 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
641 RECT client_rect, window_rect;
642 GetClientRect((HWND)hwnd, &client_rect);
643 GetWindowRect((HWND)hwnd, &window_rect);
644 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
645 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
646 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
649 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
650 int len = min(1024, JvGetStringUTFLength(title));
653 JvGetStringUTFRegion(title, 0, len, buf);
654 SetWindowText((HWND)hwnd, buf);
657 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
659 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
660 int icon_width = GetSystemMetrics(SM_CXSMICON);
661 int icon_height = GetSystemMetrics(SM_CYSMICON);
663 // we create the DC lazily to get around some strange race condition in WinXP
664 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
667 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
668 HDC memdc = CreateCompatibleDC((HDC)hdc);
669 SelectObject(memdc, bit);
670 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
673 jint* dat = elements(p->data);
674 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
675 SelectObject(memdc, bit_mask);
676 for(int x=0; x<icon_width; x++)
677 for(int y=0; y<icon_height; y++) {
678 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
679 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
680 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
683 // instantiate the icon and assign it to the window class
686 ici.hbmMask = bit_mask;
688 HICON hicon = CreateIconIndirect(&ici);
689 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
690 if (oldicon != NULL) DestroyIcon(oldicon);
694 static jstring keyToString(WPARAM wParam);
695 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
697 UINT iMsg = (UINT)_iMsg;
698 WPARAM wParam = (WPARAM)_wParam;
699 LPARAM lParam = (LPARAM)_lParam;
701 int oldmousex, oldmousey;
706 RECT client_rect, window_rect;
710 int addwidth, addheight;
713 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
714 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
715 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
716 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
718 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
720 KeyPressed(keyToString(wParam));
723 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
725 KeyReleased(keyToString(wParam));
728 case WM_SETFOCUS: Focused(true); return 0;
729 case WM_KILLFOCUS: Focused(false); return 0;
730 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
731 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
732 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
733 case WM_LBUTTONDOWN: Press(1); return 0;
734 case WM_RBUTTONDOWN: Press(2); return 0;
735 case WM_MBUTTONDOWN: Press(3); return 0;
736 case WM_CLOSE: Close(); return 0;
737 case WM_ERASEBKGND: return 0;
742 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
743 if (captured && !inside) {
745 SetCursor((HCURSOR)previous_cursor);
750 GetClientRect((HWND)hwnd, &rect);
751 PosChange(rect.left, rect.top);
755 if (wParam == SIZE_MINIMIZED) {
756 if (maximized) Maximized(false);
758 } else if (wParam == SIZE_MAXIMIZED) {
759 if (minimized) Minimized(false);
762 if (minimized) Minimized(false);
763 if (maximized) Maximized(false);
765 // deliberately fall through to WM_SIZING
768 GetClientRect((HWND)hwnd, &rect);
769 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
773 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
775 GetClientRect((HWND)hwnd, &rect);
776 point.x = mouse_x = lParam & 0xFFFF;
777 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
778 ClientToScreen((HWND)hwnd, &point);
779 hwnd2 = WindowFromPoint(point);
781 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
783 Move(mouse_x, mouse_y);
785 if (newinside && !inside) {
787 SetCapture((HWND)hwnd);
789 previous_cursor = (jint)GetCursor();
790 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
792 } else if (!newinside && inside) {
794 if (!button1 && !button2 && !button3) {
797 SetCursor((HCURSOR)previous_cursor);
803 case WM_USER_SETCURSOR:
804 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
805 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
806 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
807 // cursor should be re-set to "current_cursor".
808 SetCursor((HCURSOR)current_cursor);
811 case WM_USER_DISPOSE:
812 // used to signal that we should destroy ourselves
813 DestroyWindow((HWND)hwnd);
816 case WM_GETMINMAXINFO:
817 GetClientRect((HWND)hwnd, &client_rect);
818 GetWindowRect((HWND)hwnd, &window_rect);
819 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
820 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
821 mmi = (MINMAXINFO*)lParam;
822 mmi->ptMinTrackSize.x = ((uint32_t)root->dmin(0)) + addwidth;
823 mmi->ptMinTrackSize.y = ((uint32_t)root->dmin(1)) + addheight;
824 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->dmax(0)) + addwidth);
825 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->dmax(1)) + addheight);
830 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
831 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
832 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
838 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
842 // Key Translator Helper /////////////////////////////////////////////////////////////////////
844 static char keyarr [256] = { 0 };
845 static jstring keyToString(WPARAM wParam) {
847 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
848 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
849 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
850 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
852 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
854 case '\t': return JvNewStringLatin1("tab");
855 case 0x1b: return JvNewStringLatin1("escape");
856 case '\n': return JvNewStringLatin1("enter");
857 case '\r': return JvNewStringLatin1("enter");
858 case 0x08: return JvNewStringLatin1("back_space");
859 default: return JvNewStringLatin1(arr, 1);
862 } else switch (wParam) {
863 case VK_CLEAR: return JvNewStringLatin1("clear");
864 case VK_SHIFT: return JvNewStringLatin1("shift");
865 case VK_CONTROL: return JvNewStringLatin1("control");
866 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
867 case VK_MENU: return JvNewStringLatin1("alt");
868 case VK_PAUSE: return JvNewStringLatin1("pause");
869 case VK_PRIOR: return JvNewStringLatin1("page_up");
870 case VK_NEXT: return JvNewStringLatin1("page_down");
871 case VK_END: return JvNewStringLatin1("end");
872 case VK_HOME: return JvNewStringLatin1("home");
873 case VK_LEFT: return JvNewStringLatin1("left");
874 case VK_UP: return JvNewStringLatin1("up");
875 case VK_RIGHT: return JvNewStringLatin1("right");
876 case VK_DOWN: return JvNewStringLatin1("down");
877 case VK_INSERT: return JvNewStringLatin1("insert");
878 case VK_DELETE: return JvNewStringLatin1("delete");
879 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
880 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
881 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
882 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
883 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
884 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
885 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
886 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
887 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
888 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
889 case VK_F1: return JvNewStringLatin1("f1");
890 case VK_F2: return JvNewStringLatin1("f2");
891 case VK_F3: return JvNewStringLatin1("f3");
892 case VK_F4: return JvNewStringLatin1("f4");
893 case VK_F5: return JvNewStringLatin1("f5");
894 case VK_F6: return JvNewStringLatin1("f6");
895 case VK_F7: return JvNewStringLatin1("f7");
896 case VK_F8: return JvNewStringLatin1("f8");
897 case VK_F9: return JvNewStringLatin1("f9");
898 case VK_F10: return JvNewStringLatin1("f10");
899 case VK_F11: return JvNewStringLatin1("f11");
900 case VK_F12: return JvNewStringLatin1("f12");
901 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
902 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
903 case VK_LSHIFT: return JvNewStringLatin1("shift");
904 case VK_RSHIFT: return JvNewStringLatin1("shift");
905 case VK_LCONTROL: return JvNewStringLatin1("control");
906 case VK_RCONTROL: return JvNewStringLatin1("control");