1 module dlangui.platforms.windows.winapp; 2 3 version (Windows) { 4 5 import core.runtime; 6 import win32.windows; 7 import std.string; 8 import std.utf; 9 import std.stdio; 10 import std.algorithm; 11 import std.file; 12 import dlangui.platforms.common.platform; 13 import dlangui.platforms.windows.win32fonts; 14 import dlangui.platforms.windows.win32drawbuf; 15 import dlangui.widgets.styles; 16 import dlangui.widgets.widget; 17 import dlangui.graphics.drawbuf; 18 import dlangui.graphics.images; 19 import dlangui.graphics.fonts; 20 import dlangui.core.logger; 21 22 version (USE_OPENGL) { 23 import dlangui.graphics.glsupport; 24 } 25 26 pragma(lib, "gdi32.lib"); 27 pragma(lib, "user32.lib"); 28 pragma(lib, "libpng15.lib"); 29 30 /// this function should be defined in user application! 31 extern (C) int UIAppMain(string[] args); 32 33 immutable WIN_CLASS_NAME = "DLANGUI_APP"; 34 35 __gshared HINSTANCE _hInstance; 36 __gshared int _cmdShow; 37 38 version (USE_OPENGL) { 39 bool setupPixelFormat(HDC hDC) 40 { 41 PIXELFORMATDESCRIPTOR pfd = { 42 PIXELFORMATDESCRIPTOR.sizeof, /* size */ 43 1, /* version */ 44 PFD_SUPPORT_OPENGL | 45 PFD_DRAW_TO_WINDOW | 46 PFD_DOUBLEBUFFER, /* support double-buffering */ 47 PFD_TYPE_RGBA, /* color type */ 48 16, /* prefered color depth */ 49 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ 50 0, /* no alpha buffer */ 51 0, /* alpha bits (ignored) */ 52 0, /* no accumulation buffer */ 53 0, 0, 0, 0, /* accum bits (ignored) */ 54 16, /* depth buffer */ 55 0, /* no stencil buffer */ 56 0, /* no auxiliary buffers */ 57 0, /* main layer PFD_MAIN_PLANE */ 58 0, /* reserved */ 59 0, 0, 0, /* no layer, visible, damage masks */ 60 }; 61 int pixelFormat; 62 63 pixelFormat = ChoosePixelFormat(hDC, &pfd); 64 if (pixelFormat == 0) { 65 Log.e("ChoosePixelFormat failed."); 66 return false; 67 } 68 69 if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) { 70 Log.e("SetPixelFormat failed."); 71 return false; 72 } 73 return true; 74 } 75 76 HPALETTE setupPalette(HDC hDC) 77 { 78 import core.stdc.stdlib; 79 HPALETTE hPalette = NULL; 80 int pixelFormat = GetPixelFormat(hDC); 81 PIXELFORMATDESCRIPTOR pfd; 82 LOGPALETTE* pPal; 83 int paletteSize; 84 85 DescribePixelFormat(hDC, pixelFormat, PIXELFORMATDESCRIPTOR.sizeof, &pfd); 86 87 if (pfd.dwFlags & PFD_NEED_PALETTE) { 88 paletteSize = 1 << pfd.cColorBits; 89 } else { 90 return null; 91 } 92 93 pPal = cast(LOGPALETTE*) 94 malloc(LOGPALETTE.sizeof + paletteSize * PALETTEENTRY.sizeof); 95 pPal.palVersion = 0x300; 96 pPal.palNumEntries = cast(ushort)paletteSize; 97 98 /* build a simple RGB color palette */ 99 { 100 int redMask = (1 << pfd.cRedBits) - 1; 101 int greenMask = (1 << pfd.cGreenBits) - 1; 102 int blueMask = (1 << pfd.cBlueBits) - 1; 103 int i; 104 105 for (i=0; i<paletteSize; ++i) { 106 pPal.palPalEntry[i].peRed = cast(ubyte)( 107 (((i >> pfd.cRedShift) & redMask) * 255) / redMask); 108 pPal.palPalEntry[i].peGreen = cast(ubyte)( 109 (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask); 110 pPal.palPalEntry[i].peBlue = cast(ubyte)( 111 (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask); 112 pPal.palPalEntry[i].peFlags = 0; 113 } 114 } 115 116 hPalette = CreatePalette(pPal); 117 free(pPal); 118 119 if (hPalette) { 120 SelectPalette(hDC, hPalette, FALSE); 121 RealizePalette(hDC); 122 } 123 124 return hPalette; 125 } 126 127 private __gshared bool DERELICT_GL3_RELOADED = false; 128 } 129 130 class Win32Window : Window { 131 Win32Platform _platform; 132 HWND _hwnd; 133 version (USE_OPENGL) { 134 HGLRC _hGLRC; // opengl context 135 HPALETTE _hPalette; 136 } 137 string _caption; 138 Win32ColorDrawBuf _drawbuf; 139 bool useOpengl; 140 this(Win32Platform platform, string windowCaption, Window parent) { 141 _platform = platform; 142 _caption = windowCaption; 143 _hwnd = CreateWindow(toUTF16z(WIN_CLASS_NAME), // window class name 144 toUTF16z(windowCaption), // window caption 145 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window style 146 CW_USEDEFAULT, // initial x position 147 CW_USEDEFAULT, // initial y position 148 CW_USEDEFAULT, // initial x size 149 CW_USEDEFAULT, // initial y size 150 null, // parent window handle 151 null, // window menu handle 152 _hInstance, // program instance handle 153 cast(void*)this); // creation parameters 154 155 version (USE_OPENGL) { 156 import derelict.opengl3.wgl; 157 158 /* initialize OpenGL rendering */ 159 HDC hDC = GetDC(_hwnd); 160 161 if (!DERELICT_GL3_RELOADED || openglEnabled) { 162 if (setupPixelFormat(hDC)) { 163 _hPalette = setupPalette(hDC); 164 _hGLRC = wglCreateContext(hDC); 165 if (_hGLRC) { 166 wglMakeCurrent(hDC, _hGLRC); 167 168 if (!DERELICT_GL3_RELOADED) { 169 // run this code only once 170 DERELICT_GL3_RELOADED = true; 171 try { 172 import derelict.opengl3.gl3; 173 DerelictGL3.reload(); 174 // successful 175 if (initShaders()) { 176 setOpenglEnabled(); 177 useOpengl = true; 178 } else { 179 Log.e("Failed to compile shaders"); 180 } 181 } catch (Exception e) { 182 Log.e("Derelict exception", e); 183 } 184 } else { 185 if (initShaders()) { 186 setOpenglEnabled(); 187 useOpengl = true; 188 } else { 189 Log.e("Failed to compile shaders"); 190 } 191 } 192 } 193 } else { 194 Log.e("Pixelformat failed"); 195 // disable GL 196 DERELICT_GL3_RELOADED = true; 197 } 198 } 199 } 200 } 201 202 version (USE_OPENGL) { 203 private void paintUsingOpenGL() { 204 // hack to stop infinite WM_PAINT loop 205 PAINTSTRUCT ps; 206 HDC hdc2 = BeginPaint(_hwnd, &ps); 207 EndPaint(_hwnd, &ps); 208 209 210 import derelict.opengl3.gl3; 211 import derelict.opengl3.wgl; 212 import dlangui.graphics.gldrawbuf; 213 //Log.d("onPaint() start drawing opengl viewport: ", _dx, "x", _dy); 214 //PAINTSTRUCT ps; 215 //HDC hdc = BeginPaint(_hwnd, &ps); 216 //scope(exit) EndPaint(_hwnd, &ps); 217 HDC hdc = GetDC(_hwnd); 218 wglMakeCurrent(hdc, _hGLRC); 219 glDisable(GL_DEPTH_TEST); 220 glViewport(0, 0, _dx, _dy); 221 float a = 1.0f; 222 float r = ((_backgroundColor >> 16) & 255) / 255.0f; 223 float g = ((_backgroundColor >> 8) & 255) / 255.0f; 224 float b = ((_backgroundColor >> 0) & 255) / 255.0f; 225 glClearColor(r, g, b, a); 226 glClear(GL_COLOR_BUFFER_BIT); 227 228 GLDrawBuf buf = new GLDrawBuf(_dx, _dy, false); 229 buf.beforeDrawing(); 230 static if (false) { 231 // for testing for render 232 buf.fillRect(Rect(100, 100, 200, 200), 0x704020); 233 buf.fillRect(Rect(40, 70, 100, 120), 0x000000); 234 buf.fillRect(Rect(80, 80, 150, 150), 0x80008000); // green 235 drawableCache.get("exit").drawTo(buf, Rect(300, 100, 364, 164)); 236 drawableCache.get("btn_default_pressed").drawTo(buf, Rect(300, 200, 564, 264)); 237 drawableCache.get("btn_default_normal").drawTo(buf, Rect(300, 0, 400, 50)); 238 drawableCache.get("btn_default_selected").drawTo(buf, Rect(0, 0, 100, 50)); 239 FontRef fnt = currentTheme.font; 240 fnt.drawText(buf, 40, 40, "Some Text 1234567890 !@#$^*", 0x80FF0000); 241 } else { 242 onDraw(buf); 243 } 244 buf.afterDrawing(); 245 SwapBuffers(hdc); 246 wglMakeCurrent(hdc, null); 247 } 248 } 249 250 ~this() { 251 Log.d("Window destructor"); 252 version (USE_OPENGL) { 253 import derelict.opengl3.wgl; 254 if (_hGLRC) { 255 uninitShaders(); 256 wglMakeCurrent (null, null) ; 257 wglDeleteContext(_hGLRC); 258 _hGLRC = null; 259 } 260 } 261 if (_hwnd) 262 DestroyWindow(_hwnd); 263 _hwnd = null; 264 } 265 Win32ColorDrawBuf getDrawBuf() { 266 //RECT rect; 267 //GetClientRect(_hwnd, &rect); 268 //int dx = rect.right - rect.left; 269 //int dy = rect.bottom - rect.top; 270 if (_drawbuf is null) 271 _drawbuf = new Win32ColorDrawBuf(_dx, _dy); 272 else 273 _drawbuf.resize(_dx, _dy); 274 return _drawbuf; 275 } 276 override void show() { 277 ShowWindow(_hwnd, _cmdShow); 278 UpdateWindow(_hwnd); 279 } 280 override @property string windowCaption() { 281 return _caption; 282 } 283 override @property void windowCaption(string caption) { 284 _caption = caption; 285 SetWindowTextW(_hwnd, toUTF16z(_caption)); 286 } 287 void onCreate() { 288 Log.d("Window onCreate"); 289 _platform.onWindowCreated(_hwnd, this); 290 } 291 void onDestroy() { 292 Log.d("Window onDestroy"); 293 _platform.onWindowDestroyed(_hwnd, this); 294 } 295 296 private void paintUsingGDI() { 297 PAINTSTRUCT ps; 298 HDC hdc = BeginPaint(_hwnd, &ps); 299 scope(exit) EndPaint(_hwnd, &ps); 300 301 Win32ColorDrawBuf buf = getDrawBuf(); 302 buf.fill(_backgroundColor); 303 onDraw(buf); 304 buf.drawTo(hdc, 0, 0); 305 } 306 307 void onPaint() { 308 Log.d("onPaint()"); 309 long paintStart = currentTimeMillis; 310 version (USE_OPENGL) { 311 if (useOpengl && _hGLRC) { 312 paintUsingOpenGL(); 313 } else { 314 paintUsingGDI(); 315 } 316 } else { 317 paintUsingGDI(); 318 } 319 long paintEnd = currentTimeMillis; 320 Log.d("WM_PAINT handling took ", paintEnd - paintStart, " ms"); 321 } 322 323 protected ButtonDetails _lbutton; 324 protected ButtonDetails _mbutton; 325 protected ButtonDetails _rbutton; 326 327 private bool _mouseTracking; 328 private bool onMouse(uint message, uint flags, short x, short y) { 329 //Log.d("Win32 Mouse Message ", message, " flags=", flags, " x=", x, " y=", y); 330 MouseButton button = MouseButton.None; 331 MouseAction action = MouseAction.ButtonDown; 332 ButtonDetails * pbuttonDetails = null; 333 short wheelDelta = 0; 334 switch (message) { 335 case WM_MOUSEMOVE: 336 action = MouseAction.Move; 337 break; 338 case WM_LBUTTONDOWN: 339 action = MouseAction.ButtonDown; 340 button = MouseButton.Left; 341 pbuttonDetails = &_lbutton; 342 break; 343 case WM_RBUTTONDOWN: 344 action = MouseAction.ButtonDown; 345 button = MouseButton.Right; 346 pbuttonDetails = &_rbutton; 347 break; 348 case WM_MBUTTONDOWN: 349 action = MouseAction.ButtonDown; 350 button = MouseButton.Middle; 351 pbuttonDetails = &_mbutton; 352 break; 353 case WM_LBUTTONUP: 354 action = MouseAction.ButtonUp; 355 button = MouseButton.Left; 356 pbuttonDetails = &_lbutton; 357 break; 358 case WM_RBUTTONUP: 359 action = MouseAction.ButtonUp; 360 button = MouseButton.Right; 361 pbuttonDetails = &_rbutton; 362 break; 363 case WM_MBUTTONUP: 364 action = MouseAction.ButtonUp; 365 button = MouseButton.Middle; 366 pbuttonDetails = &_mbutton; 367 break; 368 case WM_MOUSELEAVE: 369 Log.d("WM_MOUSELEAVE"); 370 action = MouseAction.Leave; 371 break; 372 case WM_MOUSEWHEEL: 373 { 374 action = MouseAction.Wheel; 375 wheelDelta = (cast(short)(flags >> 16)) / 120; 376 POINT pt; 377 pt.x = x; 378 pt.y = y; 379 ScreenToClient(_hwnd, &pt); 380 x = cast(short)pt.x; 381 y = cast(short)pt.y; 382 } 383 break; 384 default: 385 // unsupported event 386 return false; 387 } 388 if (action == MouseAction.ButtonDown) { 389 pbuttonDetails.down(x, y, cast(ushort)flags); 390 } else if (action == MouseAction.ButtonUp) { 391 pbuttonDetails.up(x, y, cast(ushort)flags); 392 } 393 if (((message == WM_MOUSELEAVE) || (x < 0 || y < 0 || x > _dx || y > _dy)) && _mouseTracking) { 394 action = MouseAction.Leave; 395 Log.d("WM_MOUSELEAVE - releasing capture"); 396 _mouseTracking = false; 397 ReleaseCapture(); 398 } 399 if (message != WM_MOUSELEAVE && !_mouseTracking) { 400 if (x >=0 && y >= 0 && x < _dx && y < _dy) { 401 Log.d("Setting capture"); 402 _mouseTracking = true; 403 SetCapture(_hwnd); 404 } 405 } 406 MouseEvent event = new MouseEvent(action, button, cast(ushort)flags, x, y, wheelDelta); 407 event.lbutton = _lbutton; 408 event.rbutton = _rbutton; 409 event.mbutton = _mbutton; 410 bool res = dispatchMouseEvent(event); 411 if (res) { 412 Log.d("Calling update() after mouse event"); 413 update(); 414 } 415 return res; 416 } 417 418 419 protected uint _keyFlags; 420 421 protected void updateKeyFlags(KeyAction action, KeyFlag flag) { 422 if (action == KeyAction.KeyDown) 423 _keyFlags |= flag; 424 else 425 _keyFlags &= ~flag; 426 } 427 428 bool onKey(KeyAction action, uint keyCode, int repeatCount, dchar character = 0) { 429 KeyEvent event; 430 if (action == KeyAction.KeyDown || action == KeyAction.KeyUp) { 431 switch(keyCode) { 432 case KeyCode.SHIFT: 433 updateKeyFlags(action, KeyFlag.Shift); 434 break; 435 case KeyCode.CONTROL: 436 updateKeyFlags(action, KeyFlag.Control); 437 break; 438 case KeyCode.ALT: 439 updateKeyFlags(action, KeyFlag.Alt); 440 break; 441 default: 442 break; 443 } 444 event = new KeyEvent(action, keyCode, _keyFlags); 445 } else if (action == KeyAction.Text && character != 0) { 446 dchar[] text; 447 text ~= character; 448 event = new KeyEvent(action, 0, _keyFlags, cast(dstring)text); 449 } 450 bool res = false; 451 if (event !is null) { 452 res = dispatchKeyEvent(event); 453 } 454 if (res) { 455 Log.d("Calling update() after key event"); 456 update(); 457 } 458 return res; 459 } 460 461 /// request window redraw 462 override void invalidate() { 463 InvalidateRect(_hwnd, null, FALSE); 464 UpdateWindow(_hwnd); 465 } 466 467 /// after drawing, call to schedule redraw if animation is active 468 override void scheduleAnimation() { 469 invalidate(); 470 } 471 472 } 473 474 class Win32Platform : Platform { 475 this() { 476 } 477 bool registerWndClass() { 478 //MSG msg; 479 WNDCLASS wndclass; 480 481 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 482 wndclass.lpfnWndProc = &WndProc; 483 wndclass.cbClsExtra = 0; 484 wndclass.cbWndExtra = 0; 485 wndclass.hInstance = _hInstance; 486 wndclass.hIcon = LoadIcon(null, IDI_APPLICATION); 487 wndclass.hCursor = LoadCursor(null, IDC_ARROW); 488 wndclass.hbrBackground = cast(HBRUSH)GetStockObject(WHITE_BRUSH); 489 wndclass.lpszMenuName = null; 490 wndclass.lpszClassName = toUTF16z(WIN_CLASS_NAME); 491 492 if(!RegisterClass(&wndclass)) 493 { 494 return false; 495 } 496 return true; 497 } 498 override int enterMessageLoop() { 499 MSG msg; 500 while (GetMessage(&msg, null, 0, 0)) 501 { 502 TranslateMessage(&msg); 503 DispatchMessage(&msg); 504 } 505 return msg.wParam; 506 } 507 private Win32Window[ulong] _windowMap; 508 /// add window to window map 509 void onWindowCreated(HWND hwnd, Win32Window window) { 510 _windowMap[cast(ulong)hwnd] = window; 511 } 512 /// remove window from window map, returns true if there are some more windows left in map 513 bool onWindowDestroyed(HWND hwnd, Win32Window window) { 514 Win32Window wnd = getWindow(hwnd); 515 if (wnd) { 516 _windowMap.remove(cast(ulong)hwnd); 517 destroy(window); 518 } 519 return _windowMap.length > 0; 520 } 521 /// returns number of currently active windows 522 @property int windowCount() { 523 return cast(int)_windowMap.length; 524 } 525 /// returns window instance by HWND 526 Win32Window getWindow(HWND hwnd) { 527 if ((cast(ulong)hwnd) in _windowMap) 528 return _windowMap[cast(ulong)hwnd]; 529 return null; 530 } 531 override Window createWindow(string windowCaption, Window parent) { 532 return new Win32Window(this, windowCaption, parent); 533 } 534 } 535 536 extern(Windows) 537 int DLANGUIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 538 LPSTR lpCmdLine, int nCmdShow) { 539 int result; 540 541 try 542 { 543 Runtime.initialize(); 544 result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); 545 //Runtime.terminate(); 546 } 547 catch (Throwable e) // catch any uncaught exceptions 548 { 549 MessageBox(null, toUTF16z(e.toString()), "Error", 550 MB_OK | MB_ICONEXCLAMATION); 551 result = 0; // failed 552 } 553 554 return result; 555 } 556 557 string[] splitCmdLine(string line) { 558 string[] res; 559 int start = 0; 560 bool insideQuotes = false; 561 for (int i = 0; i <= line.length; i++) { 562 char ch = i < line.length ? line[i] : 0; 563 if (ch == '\"') { 564 if (insideQuotes) { 565 if (i > start) 566 res ~= line[start .. i]; 567 start = i + 1; 568 insideQuotes = false; 569 } else { 570 insideQuotes = true; 571 start = i + 1; 572 } 573 } else if (!insideQuotes && (ch == ' ' || ch == '\t' || ch == 0)) { 574 if (i > start) { 575 res ~= line[start .. i]; 576 } 577 start = i + 1; 578 } 579 } 580 return res; 581 } 582 583 private __gshared Win32Platform platform; 584 585 int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) 586 { 587 setFileLogger(std.stdio.File("ui.log", "w")); 588 setLogLevel(LogLevel.Trace); 589 Log.d("myWinMain()"); 590 string basePath = exePath(); 591 Log.i("Current executable: ", exePath()); 592 string cmdline = fromStringz(lpCmdLine); 593 Log.i("Command line: ", cmdline); 594 string[] args = splitCmdLine(cmdline); 595 Log.i("Command line params: ", args); 596 597 _cmdShow = iCmdShow; 598 _hInstance = hInstance; 599 600 platform = new Win32Platform(); 601 if (!platform.registerWndClass()) { 602 MessageBoxA(null, "This program requires Windows NT!", "DLANGUI App".toStringz, MB_ICONERROR); 603 return 0; 604 } 605 Platform.setInstance(platform); 606 607 608 if (true) { 609 /// testing freetype font manager 610 import dlangui.graphics.ftfonts; 611 import win32.shlobj; 612 FreeTypeFontManager ftfontMan = new FreeTypeFontManager(); 613 string fontsPath = "c:\\Windows\\Fonts\\"; 614 static if (false) { // SHGetFolderPathW not found in shell32.lib 615 WCHAR szPath[MAX_PATH]; 616 const CSIDL_FLAG_NO_ALIAS = 0x1000; 617 const CSIDL_FLAG_DONT_UNEXPAND = 0x2000; 618 if(SUCCEEDED(SHGetFolderPathW(NULL, 619 CSIDL_FONTS|CSIDL_FLAG_NO_ALIAS|CSIDL_FLAG_DONT_UNEXPAND, 620 NULL, 621 0, 622 szPath.ptr))) 623 { 624 fontsPath = toUTF8(fromWStringz(szPath)); 625 } 626 } 627 ftfontMan.registerFont(fontsPath ~ "arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal); 628 ftfontMan.registerFont(fontsPath ~ "arialbd.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold); 629 ftfontMan.registerFont(fontsPath ~ "arialbi.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold); 630 ftfontMan.registerFont(fontsPath ~ "ariali.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal); 631 ftfontMan.registerFont(fontsPath ~ "cour.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal); 632 ftfontMan.registerFont(fontsPath ~ "courbd.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold); 633 ftfontMan.registerFont(fontsPath ~ "courbi.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold); 634 ftfontMan.registerFont(fontsPath ~ "couri.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal); 635 ftfontMan.registerFont(fontsPath ~ "times.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Normal); 636 ftfontMan.registerFont(fontsPath ~ "timesbd.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Bold); 637 ftfontMan.registerFont(fontsPath ~ "timesbi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Bold); 638 ftfontMan.registerFont(fontsPath ~ "timesi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Normal); 639 FontManager.instance = ftfontMan; 640 } 641 642 // use Win32 font manager 643 if (FontManager.instance is null) { 644 //Win32FontManager fontMan = new Win32FontManager(); 645 FontManager.instance = new Win32FontManager(); 646 } 647 648 currentTheme = createDefaultTheme(); 649 650 version (USE_OPENGL) { 651 import derelict.opengl3.gl3; 652 DerelictGL3.load(); 653 654 // just to check OpenGL context 655 Log.i("Trying to setup OpenGL context"); 656 Win32Window tmpWindow = new Win32Window(platform, "", null); 657 destroy(tmpWindow); 658 if (openglEnabled) 659 Log.i("OpenGL support is enabled"); 660 else 661 Log.w("OpenGL support is disabled"); 662 // process messages 663 platform.enterMessageLoop(); 664 } 665 666 // Load versions 1.2+ and all supported ARB and EXT extensions. 667 668 Log.i("Entering UIAppMain: ", args); 669 int result = UIAppMain(args); 670 Log.i("UIAppMain returned ", result); 671 return result; 672 } 673 674 675 extern(Windows) 676 LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 677 { 678 HDC hdc; 679 RECT rect; 680 681 void * p = cast(void*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 682 Win32Window windowParam = p is null ? null : cast(Win32Window)(p); 683 Win32Window window = platform.getWindow(hwnd); 684 if (windowParam !is null && window !is null) 685 assert(window is windowParam); 686 if (window is null && windowParam !is null) { 687 Log.e("Cannot find window in map by HWND"); 688 } 689 690 switch (message) 691 { 692 case WM_CREATE: 693 { 694 CREATESTRUCT * pcreateStruct = cast(CREATESTRUCT*)lParam; 695 window = cast(Win32Window)pcreateStruct.lpCreateParams; 696 void * ptr = cast(void*) window; 697 SetWindowLongPtr(hwnd, GWLP_USERDATA, cast(LONG_PTR)ptr); 698 window._hwnd = hwnd; 699 window.onCreate(); 700 } 701 return 0; 702 case WM_DESTROY: 703 if (window !is null) 704 window.onDestroy(); 705 if (platform.windowCount == 0) 706 PostQuitMessage(0); 707 return 0; 708 case WM_WINDOWPOSCHANGED: 709 { 710 if (window !is null) { 711 WINDOWPOS * pos = cast(WINDOWPOS*)lParam; 712 GetClientRect(hwnd, &rect); 713 int dx = rect.right - rect.left; 714 int dy = rect.bottom - rect.top; 715 //window.onResize(pos.cx, pos.cy); 716 window.onResize(dx, dy); 717 InvalidateRect(hwnd, null, FALSE); 718 } 719 } 720 return 0; 721 case WM_ERASEBKGND: 722 // processed 723 return 1; 724 case WM_PAINT: 725 { 726 if (window !is null) 727 window.onPaint(); 728 } 729 return 0; // processed 730 case WM_MOUSELEAVE: 731 case WM_MOUSEMOVE: 732 case WM_LBUTTONDOWN: 733 case WM_MBUTTONDOWN: 734 case WM_RBUTTONDOWN: 735 case WM_LBUTTONUP: 736 case WM_MBUTTONUP: 737 case WM_RBUTTONUP: 738 case WM_MOUSEWHEEL: 739 if (window !is null) { 740 if (window.onMouse(message, cast(uint)wParam, cast(short)(lParam & 0xFFFF), cast(short)((lParam >> 16) & 0xFFFF))) 741 return 0; // processed 742 } 743 // not processed - default handling 744 return DefWindowProc(hwnd, message, wParam, lParam); 745 case WM_KEYDOWN: 746 case WM_KEYUP: 747 if (window !is null) { 748 int repeatCount = lParam & 0xFFFF; 749 if (window.onKey(message == WM_KEYDOWN ? KeyAction.KeyDown : KeyAction.KeyUp, wParam, repeatCount)) 750 return 0; // processed 751 return 0; 752 } 753 break; 754 case WM_UNICHAR: 755 if (window !is null) { 756 int repeatCount = lParam & 0xFFFF; 757 if (window.onKey(KeyAction.Text, wParam, repeatCount, wParam == UNICODE_NOCHAR ? 0 : wParam)) 758 return 1; // processed 759 return 1; 760 } 761 break; 762 case WM_GETMINMAXINFO: 763 case WM_NCCREATE: 764 case WM_NCCALCSIZE: 765 default: 766 //Log.d("Unhandled message ", message); 767 break; 768 } 769 770 return DefWindowProc(hwnd, message, wParam, lParam); 771 } 772 773 //=========================================== 774 // end of version(Windows) 775 //=========================================== 776 } 777 778