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/Box.h>
23 #include <java/lang/Integer.h>
24 #include <java/util/Hashtable.h>
25 #include <org/xwt/Box.h>
26 #include <org/xwt/Surface.h>
27 #include <org/xwt/PixelBuffer.h>
28 #include <org/xwt/Picture.h>
29 #include <org/xwt/ByteStream.h>
30 #include <org/xwt/Platform.h>
31 #include <org/xwt/Platform$ParsedFont.h>
32 #include <org/xwt/plat/Win32.h>
33 #include <org/xwt/plat/Win32$Win32Font.h>
34 #include <org/xwt/plat/Win32$Win32Surface.h>
35 #include <org/xwt/plat/Win32$Win32PixelBuffer.h>
36 #include <org/xwt/plat/Win32$Win32Picture.h>
37 #include <org/xwt/util/Log.h>
38 #include <org/xwt/util/Semaphore.h>
41 #include <java/lang/System.h>
42 #include <java/io/PrintStream.h>
44 #define WM_USER_SETCURSOR WM_USER
45 #define WM_USER_DISPOSE (WM_USER + 1)
46 #define WM_USER_CREATEWINDOW (WM_USER + 2)
47 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
49 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
50 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
52 // Callbacks ////////////////////////////////////////////////////////////////////
54 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
55 org::xwt::plat::Win32$Win32Surface* surface =
56 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
58 if (surface != NULL) {
59 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
62 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
63 return DefWindowProc(hwnd, iMsg, wParam, lParam);
67 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
68 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
72 lf.lfCharSet = ANSI_CHARSET;
73 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
74 lf.lfPitchAndFamily = 0;
75 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
78 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
79 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
80 tm->tmItalic == 0 ? 0 : 1,
81 tm->tmWeight <= 400 ? 0 : 1);
87 // Initialization ////////////////////////////////////////////////////////////////////
89 static int window_class_counter = 0;
91 jstring org::xwt::plat::Win32::getTempPath() {
93 DWORD ret = GetTempPath(1024, buf);
94 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
95 return JvNewStringLatin1(buf);
98 // XOR mask for the hand cursor
99 static unsigned char hand_cursor_xor[32 * 4] = {
100 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x0C, 0x00, 0x00,
102 0x00, 0x0C, 0x00, 0x00,
103 0x00, 0x0C, 0x00, 0x00,
104 0x00, 0x0C, 0x00, 0x00,
105 0x00, 0x0C, 0x00, 0x00,
106 0x00, 0x0D, 0x80, 0x00,
107 0x00, 0x0D, 0xB0, 0x00,
108 0x00, 0x0D, 0xB4, 0x00,
109 0x00, 0x0D, 0xB6, 0x00,
110 0x00, 0xCF, 0xF6, 0x00,
111 0x00, 0xEF, 0xFE, 0x00,
112 0x00, 0x6F, 0xFE, 0x00,
113 0x00, 0x2F, 0xFE, 0x00,
114 0x00, 0x3F, 0xFE, 0x00,
115 0x00, 0x1F, 0xFE, 0x00,
116 0x00, 0x1F, 0xFC, 0x00,
117 0x00, 0x0F, 0xFC, 0x00,
118 0x00, 0x0F, 0xFC, 0x00,
119 0x00, 0x07, 0xF8, 0x00,
120 0x00, 0x07, 0xF8, 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,
130 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00
134 // AND mask for the hand cursor
135 static unsigned char hand_cursor_and[32 * 4] = {
136 0xFF, 0xF3, 0xFF, 0xFF,
137 0xFF, 0xE1, 0xFF, 0xFF,
138 0xFF, 0xE1, 0xFF, 0xFF,
139 0xFF, 0xE1, 0xFF, 0xFF,
140 0xFF, 0xE1, 0xFF, 0xFF,
141 0xFF, 0xE0, 0x7F, 0xFF,
142 0xFF, 0xE0, 0x0F, 0xFF,
143 0xFF, 0xE0, 0x03, 0xFF,
144 0xFF, 0xE0, 0x01, 0xFF,
145 0xFF, 0x20, 0x00, 0xFF,
146 0xFE, 0x00, 0x00, 0xFF,
147 0xFE, 0x00, 0x00, 0xFF,
148 0xFF, 0x00, 0x00, 0xFF,
149 0xFF, 0x80, 0x00, 0xFF,
150 0xFF, 0x80, 0x00, 0xFF,
151 0xFF, 0xC0, 0x00, 0xFF,
152 0xFF, 0xC0, 0x01, 0xFF,
153 0xFF, 0xE0, 0x01, 0xFF,
154 0xFF, 0xE0, 0x01, 0xFF,
155 0xFF, 0xF0, 0x03, 0xFF,
156 0xFF, 0xF0, 0x03, 0xFF,
157 0xFF, 0xF0, 0x03, 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,
166 0xFF, 0xFF, 0xFF, 0xFF,
167 0xFF, 0xFF, 0xFF, 0xFF
171 void org::xwt::plat::Win32::natInit() {
173 // grab desktop dc/handle
174 desktop_handle = (jint)GetDesktopWindow();
175 desktop_dc = (jint)GetDC((HWND)desktop_handle);
178 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
179 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
180 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
181 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
182 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
183 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
184 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
185 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
186 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
187 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
191 lf.lfCharSet = ANSI_CHARSET;
192 lf.lfFaceName[0] = 0;
193 lf.lfPitchAndFamily = 0;
194 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
196 messagePumpThread = (jint)GetCurrentThreadId();
197 messagePumpStarted->release();
200 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
202 if (msg.message == WM_USER_CREATEWINDOW) {
203 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
205 // we must create a unique window class name for each
206 // window so that minimization icons can be set independantly
208 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
211 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
212 wc.lpfnWndProc = WndProc;
214 wc.cbSize = sizeof(WNDCLASSEX);
216 wc.hInstance = GetModuleHandle(NULL);
220 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
221 wc.lpszMenuName = NULL;
222 wc.lpszClassName = buf;
223 RegisterClassEx(&wc);
225 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
226 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
227 SetFocus((HWND)surface->hwnd);
228 surface->hwndCreated->release();
231 TranslateMessage(&msg);
232 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
233 DispatchMessage(&msg);
237 java::lang::System::exit(-1);
241 // Platform Methods ///////////////////////////////////////////////////////////////////
243 jstring org::xwt::plat::Win32::_getEnv(jstring key) {
244 int len = JvGetStringUTFLength(key);
246 JvGetStringUTFRegion(key, 0, len, buf);
249 DWORD ret = GetEnvironmentVariable(buf, buf2, 1024);
250 if (ret > 0 && ret < 1024) return JvNewStringLatin1(buf2);
254 jstring org::xwt::plat::Win32::_fileDialog(jstring suggestedFileName, jboolean write) {
258 memset(buf, 0, 1024);
259 memset(&ofn, 0, sizeof(OPENFILENAME));
261 if (suggestedFileName != NULL)
262 JvGetStringUTFRegion(suggestedFileName, 0, min(1023, JvGetStringUTFLength(suggestedFileName)), buf);
264 ofn.lStructSize = sizeof(OPENFILENAME);
265 ofn.nMaxCustFilter = 0;
269 if (write) ofn.Flags |= OFN_OVERWRITEPROMPT;
270 ofn.Flags |= OFN_HIDEREADONLY;
272 int ret = write ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
273 return ret == 0 ? NULL : JvNewStringLatin1(buf);
276 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
282 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
283 if (result != ERROR_SUCCESS) return;
288 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
290 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
294 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
295 if (buf[0] != 1) return;
300 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
302 elements(container)[0] = JvNewStringLatin1(buf);
306 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
308 elements(container)[1] = JvNewStringLatin1(buf);
311 jstring org::xwt::plat::Win32::_getClipBoard() {
312 OpenClipboard((HWND)desktop_handle);
313 HGLOBAL hmem = GetClipboardData(CF_TEXT);
314 if (hmem == NULL) return NULL;
315 char* buf = (char*)GlobalLock(hmem);
316 if (buf == NULL) return NULL;
317 jstring ret = JvNewStringLatin1(buf);
323 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
324 OpenClipboard((HWND)desktop_handle);
325 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
326 if (hmem == NULL) return;
327 char* buf = (char*)GlobalLock(hmem);
328 if (buf == NULL) return;
329 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
330 buf[JvGetStringUTFLength(s)] = '\0';
332 SetClipboardData(CF_TEXT, hmem);
336 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
337 char buf[JvGetStringUTFLength(message) + 1];
338 buf[JvGetStringUTFLength(message)] = '\0';
339 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
340 MessageBox (NULL, buf, "XWT Cannot Continue", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
341 java::lang::System::exit(-1);
344 jint org::xwt::plat::Win32::_getScreenWidth() {
346 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
347 return rect.right - rect.left;
350 jint org::xwt::plat::Win32::_getScreenHeight() {
352 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
353 return rect.bottom - rect.top;
356 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
357 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
359 memset(&logfont, 0, sizeof(LOGFONT));
360 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
361 if (pf->italic) logfont.lfItalic = 1;
362 if (pf->bold) logfont.lfWeight = FW_BOLD;
363 logfont.lfCharSet = ANSI_CHARSET;
365 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
366 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
368 ret->hfont = (jint)CreateFontIndirect(&logfont);
369 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
372 GetTextMetrics((HDC)desktop_dc, &tm);
374 p.x = 0; p.y = tm.tmAscent;
375 LPtoDP((HDC)desktop_dc, &p, 1);
376 ret->maxAscent = p.y;
378 p.x = 0; p.y = tm.tmDescent;
379 LPtoDP((HDC)desktop_dc, &p, 1);
380 ret->maxDescent = p.y;
385 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
387 HFONT hfont = (HFONT)(getFont(font)->hfont);
388 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
390 int len = min(1024, JvGetStringUTFLength(text));
393 JvGetStringUTFRegion(text, 0, len, buf);
396 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
400 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
402 int len = min(2048, JvGetStringUTFLength(url));
404 JvGetStringUTFRegion(url, 0, len, buf);
408 memset(&ei, 0, sizeof(ei));
409 ei.cbSize = sizeof(ei);
412 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
413 ei.nShow = SW_SHOWDEFAULT;
414 return (ShellExecuteEx(&ei) == 0);
419 // Win32PixelBuffer /////////////////////////////////////////////////////////////////////////
421 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
422 // Since all drawing operations are single-threaded, it's safe to use a global here.
423 static HBITMAP scratch = NULL;
424 static HDC scratch_dc = NULL;
425 static jint* scratch_bits = NULL;
426 static jint scratch_w = 0;
427 static jint scratch_h = 0;
429 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
430 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
431 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
433 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
435 void org::xwt::plat::Win32$Win32PixelBuffer::drawPicture(org::xwt::Picture* source0,
436 jint dx1, jint dy1, jint dx2, jint dy2,
437 jint sx1, jint sy1, jint sx2, jint sy2) {
438 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
440 if (source->hasalpha) {
442 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
443 if (scratch_dc != NULL) DeleteDC(scratch_dc);
444 if (scratch != NULL) DeleteObject(scratch);
445 scratch_w = max(dx2 - dx1, scratch_w);
446 scratch_h = max(dy2 - dy1, scratch_h);
448 BITMAPINFO bitmapinfo;
449 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
450 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
451 bitmapinfo.bmiHeader.biWidth = scratch_w;
452 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
453 bitmapinfo.bmiHeader.biPlanes = 1;
454 bitmapinfo.bmiHeader.biBitCount = 32;
455 bitmapinfo.bmiHeader.biCompression = BI_RGB;
457 // create section DIB
458 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
459 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
460 SelectObject(scratch_dc, scratch);
463 // copy from screen to scratch
464 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
466 // apply alpha-blending to scratch
467 jint* dat = elements(source->data);
469 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
470 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
471 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
472 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
473 jint dst = scratch_bits[y * scratch_w + x];
474 jint src = dat[sy * source->getWidth() + sx];
475 jint alpha = (src & 0xFF000000) >> 24;
476 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
477 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
478 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
479 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
482 // copy back from scratch to screen
483 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
486 if (source->hasmask) {
487 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
488 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
490 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
497 void org::xwt::plat::Win32$Win32PixelBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
499 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
500 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
502 // Platform API passes us the y-pos of the bottom of the text; we need the top
505 int len = min(1024, JvGetStringUTFLength(text));
508 JvGetStringUTFRegion(text, 0, len, buf);
510 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
511 TextOut((HDC)hdc, x, y, buf, len);
514 void org::xwt::plat::Win32$Win32PixelBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
518 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
519 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
521 RECT rect = { x, y, x + w, y + h };
522 FillRect((HDC)hdc, &rect, brush);
526 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::PixelBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
527 // we create the DC lazily to get around some strange race condition in WinXP
528 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
529 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32PixelBuffer*)s)->hdc), sx, sy, SRCCOPY);
532 void org::xwt::plat::Win32$Win32PixelBuffer::natInit() {
533 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
534 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
535 SetBkMode((HDC)hdc, TRANSPARENT);
536 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
539 void org::xwt::plat::Win32$Win32PixelBuffer::setClip(jint x, jint y, jint x2, jint y2) {
540 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
541 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
542 SelectClipRgn((HDC)hdc, hrgn);
546 void org::xwt::plat::Win32$Win32PixelBuffer::finalize() {
547 DeleteObject((void*)hdc);
548 DeleteObject((void*)hbitmap);
553 // Win32Picture /////////////////////////////////////////////////////////////////////////
555 void org::xwt::plat::Win32$Win32Picture::natInit() {
557 BITMAPINFO bitmapinfo;
558 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
559 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
560 bitmapinfo.bmiHeader.biWidth = w;
561 bitmapinfo.bmiHeader.biHeight = -1 * h;
562 bitmapinfo.bmiHeader.biPlanes = 1;
563 bitmapinfo.bmiHeader.biBitCount = 32;
564 bitmapinfo.bmiHeader.biCompression = BI_RGB;
566 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
567 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
568 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
569 uint32_t* dat = (uint32_t*)elements(data);
570 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
571 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
573 jint _copy[min(1024, data->length)];
574 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
576 memcpy(copy, elements(data), data->length * 4);
577 for(int i=0; i<data->length; i++)
578 if ((copy[i] & 0xFF000000) == 0x00000000) {
580 copy[i] = 0x00FFFFFF;
581 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
582 copy[i] = 0x00000000;
586 if (data->length > 1024) free(copy);
591 if (data->length > 1024) free(copy);
595 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
596 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
597 maskdc = (jint)CreateCompatibleDC(NULL);
598 SelectObject((HDC)maskdc, (HBITMAP)hmask);
599 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
600 if (data->length > 1024) free(copy);
605 // Win32Surface /////////////////////////////////////////////////////////////////////////////
607 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
609 // Ask the message-handling thread to create a window for us
610 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
611 hwndCreated->block();
613 // turn on incremental GC now that we have a user-visible interface
614 // [[this is causing segfaults; enable it later...]]
615 // GC_enable_incremental();
617 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
620 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
621 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
622 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
623 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
624 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
625 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
626 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
627 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
629 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
634 ClientToScreen((HWND)hwnd, &point);
635 GetWindowRect((HWND)hwnd, &rect);
636 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
639 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
640 RECT client_rect, window_rect;
641 GetClientRect((HWND)hwnd, &client_rect);
642 GetWindowRect((HWND)hwnd, &window_rect);
643 int width = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left) + w;
644 int height = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top) + h;
645 SetWindowPos((HWND)hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
648 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
649 int len = min(1024, JvGetStringUTFLength(title));
652 JvGetStringUTFRegion(title, 0, len, buf);
653 SetWindowText((HWND)hwnd, buf);
656 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
658 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
659 int icon_width = GetSystemMetrics(SM_CXSMICON);
660 int icon_height = GetSystemMetrics(SM_CYSMICON);
662 // we create the DC lazily to get around some strange race condition in WinXP
663 if (hdc == 0) hdc = (jint)GetDC((HWND)hwnd);
666 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
667 HDC memdc = CreateCompatibleDC((HDC)hdc);
668 SelectObject(memdc, bit);
669 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
672 jint* dat = elements(p->data);
673 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
674 SelectObject(memdc, bit_mask);
675 for(int x=0; x<icon_width; x++)
676 for(int y=0; y<icon_height; y++) {
677 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
678 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
679 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
682 // instantiate the icon and assign it to the window class
685 ici.hbmMask = bit_mask;
687 HICON hicon = CreateIconIndirect(&ici);
688 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
689 if (oldicon != NULL) DestroyIcon(oldicon);
693 static jstring keyToString(WPARAM wParam);
694 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
696 UINT iMsg = (UINT)_iMsg;
697 WPARAM wParam = (WPARAM)_wParam;
698 LPARAM lParam = (LPARAM)_lParam;
700 int oldmousex, oldmousey;
705 RECT client_rect, window_rect;
709 int addwidth, addheight;
712 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
713 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
714 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
715 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
717 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
719 KeyPressed(keyToString(wParam));
722 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
724 KeyReleased(keyToString(wParam));
727 case WM_SETFOCUS: Focused(true); return 0;
728 case WM_KILLFOCUS: Focused(false); return 0;
729 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
730 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
731 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
732 case WM_LBUTTONDOWN: Press(1); return 0;
733 case WM_RBUTTONDOWN: Press(2); return 0;
734 case WM_MBUTTONDOWN: Press(3); return 0;
735 case WM_CLOSE: Close(); return 0;
736 case WM_ERASEBKGND: return 0;
741 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
742 if (captured && !inside) {
744 SetCursor((HCURSOR)previous_cursor);
749 GetClientRect((HWND)hwnd, &rect);
750 PosChange(rect.left, rect.top);
754 if (wParam == SIZE_MINIMIZED) {
755 if (maximized) Maximized(false);
757 } else if (wParam == SIZE_MAXIMIZED) {
758 if (minimized) Minimized(false);
761 if (minimized) Minimized(false);
762 if (maximized) Maximized(false);
764 // deliberately fall through to WM_SIZING
767 GetClientRect((HWND)hwnd, &rect);
768 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
772 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
774 GetClientRect((HWND)hwnd, &rect);
775 point.x = mouse_x = lParam & 0xFFFF;
776 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
777 ClientToScreen((HWND)hwnd, &point);
778 hwnd2 = WindowFromPoint(point);
780 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
782 Move(mouse_x, mouse_y);
784 if (newinside && !inside) {
786 SetCapture((HWND)hwnd);
788 previous_cursor = (jint)GetCursor();
789 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
791 } else if (!newinside && inside) {
793 if (!button1 && !button2 && !button3) {
796 SetCursor((HCURSOR)previous_cursor);
802 case WM_USER_SETCURSOR:
803 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
804 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
805 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
806 // cursor should be re-set to "current_cursor".
807 SetCursor((HCURSOR)current_cursor);
810 case WM_USER_DISPOSE:
811 // used to signal that we should destroy ourselves
812 DestroyWindow((HWND)hwnd);
815 case WM_GETMINMAXINFO:
816 GetClientRect((HWND)hwnd, &client_rect);
817 GetWindowRect((HWND)hwnd, &window_rect);
818 addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
819 addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
820 mmi = (MINMAXINFO*)lParam;
821 mmi->ptMinTrackSize.x = ((uint32_t)root->minwidth) + addwidth;
822 mmi->ptMinTrackSize.y = ((uint32_t)root->minheight) + addheight;
823 mmi->ptMaxTrackSize.x = min(org::xwt::plat::Win32::getScreenWidth(), ((uint32_t)root->maxwidth) + addwidth);
824 mmi->ptMaxTrackSize.y = min(org::xwt::plat::Win32::getScreenHeight(), ((uint32_t)root->maxheight) + addheight);
829 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
830 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
831 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
837 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
841 // Key Translator Helper /////////////////////////////////////////////////////////////////////
843 static char keyarr [256] = { 0 };
844 static jstring keyToString(WPARAM wParam) {
846 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
847 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
848 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
849 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
851 if (ToAsciiEx(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0, GetKeyboardLayout(0)) == 1) {
853 case '\t': return JvNewStringLatin1("tab");
854 case 0x1b: return JvNewStringLatin1("escape");
855 case '\n': return JvNewStringLatin1("enter");
856 case '\r': return JvNewStringLatin1("enter");
857 case 0x08: return JvNewStringLatin1("back_space");
858 default: return JvNewStringLatin1(arr, 1);
861 } else switch (wParam) {
862 case VK_CLEAR: return JvNewStringLatin1("clear");
863 case VK_SHIFT: return JvNewStringLatin1("shift");
864 case VK_CONTROL: return JvNewStringLatin1("control");
865 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
866 case VK_MENU: return JvNewStringLatin1("alt");
867 case VK_PAUSE: return JvNewStringLatin1("pause");
868 case VK_PRIOR: return JvNewStringLatin1("page_up");
869 case VK_NEXT: return JvNewStringLatin1("page_down");
870 case VK_END: return JvNewStringLatin1("end");
871 case VK_HOME: return JvNewStringLatin1("home");
872 case VK_LEFT: return JvNewStringLatin1("left");
873 case VK_UP: return JvNewStringLatin1("up");
874 case VK_RIGHT: return JvNewStringLatin1("right");
875 case VK_DOWN: return JvNewStringLatin1("down");
876 case VK_INSERT: return JvNewStringLatin1("insert");
877 case VK_DELETE: return JvNewStringLatin1("delete");
878 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
879 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
880 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
881 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
882 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
883 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
884 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
885 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
886 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
887 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
888 case VK_F1: return JvNewStringLatin1("f1");
889 case VK_F2: return JvNewStringLatin1("f2");
890 case VK_F3: return JvNewStringLatin1("f3");
891 case VK_F4: return JvNewStringLatin1("f4");
892 case VK_F5: return JvNewStringLatin1("f5");
893 case VK_F6: return JvNewStringLatin1("f6");
894 case VK_F7: return JvNewStringLatin1("f7");
895 case VK_F8: return JvNewStringLatin1("f8");
896 case VK_F9: return JvNewStringLatin1("f9");
897 case VK_F10: return JvNewStringLatin1("f10");
898 case VK_F11: return JvNewStringLatin1("f11");
899 case VK_F12: return JvNewStringLatin1("f12");
900 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
901 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
902 case VK_LSHIFT: return JvNewStringLatin1("shift");
903 case VK_RSHIFT: return JvNewStringLatin1("shift");
904 case VK_LCONTROL: return JvNewStringLatin1("control");
905 case VK_RCONTROL: return JvNewStringLatin1("control");