1///////////////////////////////////////////////////////////////////////////// 2// Name: src/mgl/window.cpp 3// Purpose: wxWindow 4// Author: Vaclav Slavik 5// (based on GTK & MSW implementations) 6// RCS-ID: $Id: window.cpp 48765 2007-09-18 14:15:27Z JS $ 7// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) 8// Licence: wxWindows licence 9///////////////////////////////////////////////////////////////////////////// 10 11// =========================================================================== 12// declarations 13// =========================================================================== 14 15// --------------------------------------------------------------------------- 16// headers 17// --------------------------------------------------------------------------- 18 19// For compilers that support precompilation, includes "wx.h". 20#include "wx/wxprec.h" 21 22#ifdef __BORLANDC__ 23 #pragma hdrstop 24#endif 25 26#include "wx/window.h" 27 28#ifndef WX_PRECOMP 29 #include "wx/msgdlg.h" 30 #include "wx/accel.h" 31 #include "wx/dc.h" 32 #include "wx/dcclient.h" 33 #include "wx/utils.h" 34 #include "wx/app.h" 35 #include "wx/panel.h" 36 #include "wx/intl.h" 37 #include "wx/log.h" 38 #include "wx/dcscreen.h" 39 #include "wx/menu.h" 40#endif 41 42#if wxUSE_DRAG_AND_DROP 43 #include "wx/dnd.h" 44#endif 45 46#include "wx/sysopt.h" 47#include "wx/mgl/private.h" 48#include "wx/caret.h" 49 50#include <mgraph.hpp> 51 52#if wxUSE_TOOLTIPS 53 #include "wx/tooltip.h" 54#endif 55 56// --------------------------------------------------------------------------- 57// global variables 58// --------------------------------------------------------------------------- 59 60// MGL window manager and associated DC. 61winmng_t *g_winMng = NULL; 62MGLDevCtx *g_displayDC = NULL; 63 64// the window that has keyboard focus: 65static wxWindowMGL *gs_focusedWindow = NULL; 66// the window that is about to be focused after currently focused 67// one looses focus: 68static wxWindow *gs_toBeFocusedWindow = NULL; 69// the window that is currently under mouse cursor: 70static wxWindowMGL *gs_windowUnderMouse = NULL; 71// the window that has mouse capture 72static wxWindowMGL *gs_mouseCapture = NULL; 73// the frame that is currently active (i.e. its child has focus). It is 74// used to generate wxActivateEvents 75static wxWindowMGL *gs_activeFrame = NULL; 76// track the mouse button state for wxGetMouseState() 77unsigned long g_buttonState = 0; 78 79// --------------------------------------------------------------------------- 80// constants 81// --------------------------------------------------------------------------- 82 83// Custom identifiers used to distinguish between various event handlers 84// and capture handlers passed to MGL_wm 85enum 86{ 87 wxMGL_CAPTURE_MOUSE = 1, 88 wxMGL_CAPTURE_KEYB = 2 89}; 90 91 92// --------------------------------------------------------------------------- 93// private functions 94// --------------------------------------------------------------------------- 95 96// Returns toplevel grandparent of given window: 97static wxWindowMGL* wxGetTopLevelParent(wxWindowMGL *win) 98{ 99 wxWindowMGL *p = win; 100 while (p && !p->IsTopLevel()) 101 p = p->GetParent(); 102 return p; 103} 104 105// An easy way to capture screenshots: 106static void wxCaptureScreenshot(bool activeWindowOnly) 107{ 108#ifdef __DOS__ 109 #define SCREENSHOT_FILENAME _T("sshot%03i.png") 110#else 111 #define SCREENSHOT_FILENAME _T("screenshot-%03i.png") 112#endif 113 static int screenshot_num = 0; 114 wxString screenshot; 115 116 do 117 { 118 screenshot.Printf(SCREENSHOT_FILENAME, screenshot_num++); 119 } while ( wxFileExists(screenshot) && screenshot_num < 1000 ); 120 121 wxRect r(0, 0, g_displayDC->sizex(), g_displayDC->sizey()); 122 123 if ( activeWindowOnly && gs_activeFrame ) 124 { 125 r.Intersect(gs_activeFrame->GetRect()); 126 } 127 128 g_displayDC->savePNGFromDC(screenshot.mb_str(), 129 r.x, r. y, r.x+r.width, r.y+r.height); 130 131 wxMessageBox(wxString::Format(_T("Screenshot captured: %s"), 132 screenshot.c_str())); 133} 134 135// --------------------------------------------------------------------------- 136// MGL_WM hooks: 137// --------------------------------------------------------------------------- 138 139static void MGLAPI wxWindowPainter(window_t *wnd, MGLDC *dc) 140{ 141 wxWindowMGL *w = (wxWindow*) wnd->userData; 142 143 if ( w && !(w->GetWindowStyle() & wxTRANSPARENT_WINDOW) ) 144 { 145 MGLDevCtx ctx(dc); 146 w->HandlePaint(&ctx); 147 } 148} 149 150static ibool MGLAPI wxWindowMouseHandler(window_t *wnd, event_t *e) 151{ 152 wxWindowMGL *win = (wxWindowMGL*)MGL_wmGetWindowUserData(wnd); 153 wxPoint orig(win->GetClientAreaOrigin()); 154 wxPoint where; 155 156 g_buttonState = e->modifiers; 157 158 MGL_wmCoordGlobalToLocal(win->GetHandle(), 159 e->where_x, e->where_y, &where.x, &where.y); 160 161 for (wxWindowMGL *w = win; w; w = w->GetParent()) 162 { 163 if ( !w->IsEnabled() ) 164 return FALSE; 165 if ( w->IsTopLevel() ) 166 break; 167 } 168 169 wxEventType type = wxEVT_NULL; 170 wxMouseEvent event; 171 event.SetEventObject(win); 172 event.SetTimestamp(e->when); 173 event.m_x = where.x - orig.x; 174 event.m_y = where.y - orig.y; 175 event.m_shiftDown = ( e->modifiers & EVT_SHIFTKEY ) != 0; 176 event.m_controlDown = ( e->modifiers & EVT_CTRLSTATE ) != 0; 177 event.m_altDown = ( e->modifiers & EVT_LEFTALT ) != 0; 178 event.m_metaDown = ( e->modifiers & EVT_RIGHTALT ) != 0; 179 event.m_leftDown = ( e->modifiers & EVT_LEFTBUT ) != 0; 180 event.m_middleDown = ( e->modifiers & EVT_MIDDLEBUT ) != 0; 181 event.m_rightDown = ( e->modifiers & EVT_RIGHTBUT ) != 0; 182 183 switch (e->what) 184 { 185 case EVT_MOUSEDOWN: 186 // Change focus if the user clicks outside focused window: 187 if ( win->AcceptsFocus() && wxWindow::FindFocus() != win ) 188 win->SetFocus(); 189 190 if ( e->message & EVT_DBLCLICK ) 191 { 192 if ( e->message & EVT_LEFTBMASK ) 193 type = wxEVT_LEFT_DCLICK; 194 else if ( e->message & EVT_MIDDLEBMASK ) 195 type = wxEVT_MIDDLE_DCLICK; 196 else if ( e->message & EVT_RIGHTBMASK ) 197 type = wxEVT_RIGHT_DCLICK; 198 } 199 else 200 { 201 if ( e->message & EVT_LEFTBMASK ) 202 type = wxEVT_LEFT_DOWN; 203 else if ( e->message & EVT_MIDDLEBMASK ) 204 type = wxEVT_MIDDLE_DOWN; 205 else if ( e->message & EVT_RIGHTBMASK ) 206 type = wxEVT_RIGHT_DOWN; 207 } 208 209 break; 210 211 case EVT_MOUSEUP: 212 if ( e->message & EVT_LEFTBMASK ) 213 type = wxEVT_LEFT_UP; 214 else if ( e->message & EVT_MIDDLEBMASK ) 215 type = wxEVT_MIDDLE_UP; 216 else if ( e->message & EVT_RIGHTBMASK ) 217 type = wxEVT_RIGHT_UP; 218 break; 219 220 case EVT_MOUSEMOVE: 221 if ( !gs_mouseCapture ) 222 { 223 if ( win != gs_windowUnderMouse ) 224 { 225 if ( gs_windowUnderMouse ) 226 { 227 wxMouseEvent event2(event); 228 MGL_wmCoordGlobalToLocal(gs_windowUnderMouse->GetHandle(), 229 e->where_x, e->where_y, 230 &event2.m_x, &event2.m_y); 231 232 wxPoint orig(gs_windowUnderMouse->GetClientAreaOrigin()); 233 event2.m_x -= orig.x; 234 event2.m_y -= orig.y; 235 236 event2.SetEventObject(gs_windowUnderMouse); 237 event2.SetEventType(wxEVT_LEAVE_WINDOW); 238 gs_windowUnderMouse->GetEventHandler()->ProcessEvent(event2); 239 } 240 241 wxMouseEvent event3(event); 242 event3.SetEventType(wxEVT_ENTER_WINDOW); 243 win->GetEventHandler()->ProcessEvent(event3); 244 245 gs_windowUnderMouse = win; 246 } 247 } 248 else // gs_mouseCapture 249 { 250 bool inside = (where.x >= 0 && 251 where.y >= 0 && 252 where.x < win->GetSize().x && 253 where.y < win->GetSize().y); 254 if ( (inside && gs_windowUnderMouse != win) || 255 (!inside && gs_windowUnderMouse == win) ) 256 { 257 wxMouseEvent evt(inside ? 258 wxEVT_ENTER_WINDOW : wxEVT_LEAVE_WINDOW); 259 evt.SetEventObject(win); 260 win->GetEventHandler()->ProcessEvent(evt); 261 gs_windowUnderMouse = inside ? win : NULL; 262 } 263 } 264 265 type = wxEVT_MOTION; 266 break; 267 268 default: 269 break; 270 } 271 272 if ( type == wxEVT_NULL ) 273 { 274 return FALSE; 275 } 276 else 277 { 278 event.SetEventType(type); 279 return win->GetEventHandler()->ProcessEvent(event); 280 } 281} 282 283static long wxScanToKeyCode(event_t *event, bool translate) 284{ 285 // VS: make it __WXDEBUG__-only, since we have lots of wxLogTrace calls 286 // here and the arguments would be stored in non-debug executable even 287 // though wxLogTrace would be no-op... 288 #ifdef __WXDEBUG__ 289 #define KEY(mgl_key,wx_key) \ 290 case mgl_key: \ 291 wxLogTrace(_T("keyevents"), \ 292 _T("key " #mgl_key ", mapped to " #wx_key)); \ 293 key = wx_key; \ 294 break; 295 #else 296 #define KEY(mgl_key,wx_key) \ 297 case mgl_key: key = wx_key; break; 298 #endif 299 300 long key = 0; 301 302 if ( translate ) 303 { 304 bool numlock = (event->modifiers & EVT_NUMLOCK) != 0; 305 306 switch ( EVT_scanCode(event->message) ) 307 { 308 KEY (KB_padMinus, WXK_NUMPAD_SUBTRACT) 309 KEY (KB_padPlus, WXK_NUMPAD_ADD) 310 KEY (KB_padTimes, WXK_NUMPAD_MULTIPLY) 311 KEY (KB_padDivide, WXK_NUMPAD_DIVIDE) 312 KEY (KB_padCenter, numlock ? WXK_NUMPAD5 : WXK_NUMPAD_SEPARATOR) // ? 313 KEY (KB_padLeft, numlock ? WXK_NUMPAD4 : WXK_NUMPAD_LEFT) 314 KEY (KB_padRight, numlock ? WXK_NUMPAD6 : WXK_NUMPAD_RIGHT) 315 KEY (KB_padUp, numlock ? WXK_NUMPAD8 : WXK_NUMPAD_UP) 316 KEY (KB_padDown, numlock ? WXK_NUMPAD2 : WXK_NUMPAD_DOWN) 317 KEY (KB_padInsert, numlock ? WXK_NUMPAD0 : WXK_NUMPAD_INSERT) 318 KEY (KB_padDelete, numlock ? WXK_DECIMAL : WXK_NUMPAD_DELETE) 319 KEY (KB_padHome, numlock ? WXK_NUMPAD7 : WXK_NUMPAD_HOME) 320 KEY (KB_padEnd, numlock ? WXK_NUMPAD1 : WXK_NUMPAD_END) 321 KEY (KB_padPageUp, numlock ? WXK_NUMPAD9 : WXK_NUMPAD_PAGEUP) 322 KEY (KB_padPageDown, numlock ? WXK_NUMPAD3 : WXK_NUMPAD_PAGEDOWN) 323 KEY (KB_1, '1') 324 KEY (KB_2, '2') 325 KEY (KB_3, '3') 326 KEY (KB_4, '4') 327 KEY (KB_5, '5') 328 KEY (KB_6, '6') 329 KEY (KB_7, '7') 330 KEY (KB_8, '8') 331 KEY (KB_9, '9') 332 KEY (KB_0, '0') 333 KEY (KB_minus, WXK_SUBTRACT) 334 KEY (KB_equals, WXK_ADD) 335 KEY (KB_backSlash, '\\') 336 KEY (KB_Q, 'Q') 337 KEY (KB_W, 'W') 338 KEY (KB_E, 'E') 339 KEY (KB_R, 'R') 340 KEY (KB_T, 'T') 341 KEY (KB_Y, 'Y') 342 KEY (KB_U, 'U') 343 KEY (KB_I, 'I') 344 KEY (KB_O, 'O') 345 KEY (KB_P, 'P') 346 KEY (KB_leftSquareBrace,'[') 347 KEY (KB_rightSquareBrace,']') 348 KEY (KB_A, 'A') 349 KEY (KB_S, 'S') 350 KEY (KB_D, 'D') 351 KEY (KB_F, 'F') 352 KEY (KB_G, 'G') 353 KEY (KB_H, 'H') 354 KEY (KB_J, 'J') 355 KEY (KB_K, 'K') 356 KEY (KB_L, 'L') 357 KEY (KB_semicolon, ';') 358 KEY (KB_apostrophe, '\'') 359 KEY (KB_Z, 'Z') 360 KEY (KB_X, 'X') 361 KEY (KB_C, 'C') 362 KEY (KB_V, 'V') 363 KEY (KB_B, 'B') 364 KEY (KB_N, 'N') 365 KEY (KB_M, 'M') 366 KEY (KB_comma, ',') 367 KEY (KB_period, '.') 368 KEY (KB_divide, WXK_DIVIDE) 369 KEY (KB_space, WXK_SPACE) 370 KEY (KB_tilde, '~') 371 372 default: break; 373 } 374 } 375 376 if ( key == 0 ) 377 { 378 switch ( EVT_scanCode(event->message) ) 379 { 380 KEY (KB_padEnter, WXK_NUMPAD_ENTER) 381 KEY (KB_F1, WXK_F1) 382 KEY (KB_F2, WXK_F2) 383 KEY (KB_F3, WXK_F3) 384 KEY (KB_F4, WXK_F4) 385 KEY (KB_F5, WXK_F5) 386 KEY (KB_F6, WXK_F6) 387 KEY (KB_F7, WXK_F7) 388 KEY (KB_F8, WXK_F8) 389 KEY (KB_F9, WXK_F9) 390 KEY (KB_F10, WXK_F10) 391 KEY (KB_F11, WXK_F11) 392 KEY (KB_F12, WXK_F12) 393 KEY (KB_left, WXK_LEFT) 394 KEY (KB_right, WXK_RIGHT) 395 KEY (KB_up, WXK_UP) 396 KEY (KB_down, WXK_DOWN) 397 KEY (KB_insert, WXK_INSERT) 398 KEY (KB_delete, WXK_DELETE) 399 KEY (KB_home, WXK_HOME) 400 KEY (KB_end, WXK_END) 401 KEY (KB_pageUp, WXK_PAGEUP) 402 KEY (KB_pageDown, WXK_PAGEDOWN) 403 KEY (KB_capsLock, WXK_CAPITAL) 404 KEY (KB_numLock, WXK_NUMLOCK) 405 KEY (KB_scrollLock, WXK_SCROLL) 406 KEY (KB_leftShift, WXK_SHIFT) 407 KEY (KB_rightShift, WXK_SHIFT) 408 KEY (KB_leftCtrl, WXK_CONTROL) 409 KEY (KB_rightCtrl, WXK_CONTROL) 410 KEY (KB_leftAlt, WXK_ALT) 411 KEY (KB_rightAlt, WXK_ALT) 412 KEY (KB_leftWindows, WXK_START) 413 KEY (KB_rightWindows, WXK_START) 414 KEY (KB_menu, WXK_MENU) 415 KEY (KB_sysReq, WXK_SNAPSHOT) 416 KEY (KB_esc, WXK_ESCAPE) 417 KEY (KB_backspace, WXK_BACK) 418 KEY (KB_tab, WXK_TAB) 419 KEY (KB_enter, WXK_RETURN) 420 421 default: 422 key = EVT_asciiCode(event->message); 423 break; 424 } 425 } 426 427 #undef KEY 428 429 return key; 430} 431 432static bool wxHandleSpecialKeys(wxKeyEvent& event) 433{ 434 // Add an easy way to capture screenshots: 435 if ( event.m_keyCode == WXK_SNAPSHOT 436 #ifdef __WXDEBUG__ // FIXME_MGL - remove when KB_sysReq works in MGL! 437 || (event.m_keyCode == WXK_F1 && 438 event.m_shiftDown && event.m_controlDown) 439 #endif 440 ) 441 { 442 wxCaptureScreenshot(event.m_altDown/*only active wnd?*/); 443 return true; 444 } 445 446 return false; 447} 448 449static ibool MGLAPI wxWindowKeybHandler(window_t *wnd, event_t *e) 450{ 451 wxWindowMGL *win = (wxWindowMGL*)MGL_wmGetWindowUserData(wnd); 452 453 if ( !win->IsEnabled() ) return FALSE; 454 455 wxPoint where; 456 MGL_wmCoordGlobalToLocal(win->GetHandle(), 457 e->where_x, e->where_y, &where.x, &where.y); 458 459 wxKeyEvent event; 460 event.SetEventObject(win); 461 event.SetTimestamp(e->when); 462 event.m_keyCode = wxScanToKeyCode(e, true); 463 event.m_scanCode = 0; // not used by wx at all 464 event.m_x = where.x; 465 event.m_y = where.y; 466 event.m_shiftDown = ( e->modifiers & EVT_SHIFTKEY ) != 0; 467 event.m_controlDown = ( e->modifiers & EVT_CTRLSTATE ) != 0; 468 event.m_altDown = ( e->modifiers & EVT_LEFTALT ) != 0; 469 event.m_metaDown = ( e->modifiers & EVT_RIGHTALT ) != 0; 470 471 if ( e->what == EVT_KEYUP ) 472 { 473 event.SetEventType(wxEVT_KEY_UP); 474 return win->GetEventHandler()->ProcessEvent(event); 475 } 476 else 477 { 478 bool ret; 479 wxKeyEvent event2; 480 481 event.SetEventType(wxEVT_KEY_DOWN); 482 event2 = event; 483 484 ret = win->GetEventHandler()->ProcessEvent(event); 485 486 // wxMSW doesn't send char events with Alt pressed 487 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x 488 // will only be sent if it is not in an accelerator table: 489 event2.m_keyCode = wxScanToKeyCode(e, false); 490 if ( !ret && event2.m_keyCode != 0 ) 491 { 492 event2.SetEventType(wxEVT_CHAR); 493 ret = win->GetEventHandler()->ProcessEvent(event2); 494 } 495 496 // Synthetize navigation key event, but do it only if the TAB key 497 // wasn't handled yet: 498 if ( !ret && event.m_keyCode == WXK_TAB && 499 win->GetParent() && win->GetParent()->HasFlag(wxTAB_TRAVERSAL) ) 500 { 501 wxNavigationKeyEvent navEvent; 502 navEvent.SetEventObject(win->GetParent()); 503 // Shift-TAB goes in reverse direction: 504 navEvent.SetDirection(!event.m_shiftDown); 505 // Ctrl-TAB changes the (parent) window, i.e. switch notebook page: 506 navEvent.SetWindowChange(event.m_controlDown); 507 navEvent.SetCurrentFocus(wxStaticCast(win, wxWindow)); 508 ret = win->GetParent()->GetEventHandler()->ProcessEvent(navEvent); 509 } 510 511 // Finally, process special meaning keys that are usually 512 // a responsibility of OS or window manager: 513 if ( !ret ) 514 ret = wxHandleSpecialKeys(event); 515 516 return ret; 517 } 518} 519 520// --------------------------------------------------------------------------- 521// event tables 522// --------------------------------------------------------------------------- 523 524// in wxUniv this class is abstract because it doesn't have DoPopupMenu() 525IMPLEMENT_ABSTRACT_CLASS(wxWindowMGL, wxWindowBase) 526 527BEGIN_EVENT_TABLE(wxWindowMGL, wxWindowBase) 528END_EVENT_TABLE() 529 530// =========================================================================== 531// implementation 532// =========================================================================== 533 534// ---------------------------------------------------------------------------- 535// constructors and such 536// ---------------------------------------------------------------------------- 537 538extern wxVideoMode wxGetDefaultDisplayMode(); 539 540void wxWindowMGL::Init() 541{ 542 // First of all, make sure window manager is up and running. If it is 543 // not the case, initialize it in default display mode 544 if ( !g_winMng ) 545 { 546 if ( !wxTheApp->SetDisplayMode(wxGetDefaultDisplayMode()) ) 547 wxLogFatalError(_("Cannot initialize display.")); 548 } 549 550 // mgl specific: 551 m_wnd = NULL; 552 m_isShown = true; 553 m_frozen = false; 554 m_paintMGLDC = NULL; 555 m_eraseBackground = -1; 556} 557 558// Destructor 559wxWindowMGL::~wxWindowMGL() 560{ 561 SendDestroyEvent(); 562 563 m_isBeingDeleted = true; 564 565 if ( gs_mouseCapture == this ) 566 ReleaseMouse(); 567 568 if (gs_activeFrame == this) 569 { 570 gs_activeFrame = NULL; 571 // activate next frame in Z-order: 572 if ( m_wnd->prev ) 573 { 574 wxWindowMGL *win = (wxWindowMGL*)m_wnd->prev->userData; 575 win->SetFocus(); 576 } 577 else if ( m_wnd->next ) 578 { 579 wxWindowMGL *win = (wxWindowMGL*)m_wnd->next->userData; 580 win->SetFocus(); 581 } 582 } 583 584 if ( gs_focusedWindow == this ) 585 KillFocus(); 586 587 if ( gs_windowUnderMouse == this ) 588 gs_windowUnderMouse = NULL; 589 590 DestroyChildren(); 591 592 if ( m_wnd ) 593 MGL_wmDestroyWindow(m_wnd); 594} 595 596// real construction (Init() must have been called before!) 597bool wxWindowMGL::Create(wxWindow *parent, 598 wxWindowID id, 599 const wxPoint& pos, 600 const wxSize& size, 601 long style, 602 const wxString& name) 603{ 604 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) 605 return false; 606 607 if ( parent ) 608 parent->AddChild(this); 609 610 int x, y, w, h; 611 x = pos.x, y = pos.y; 612 if ( x == -1 ) 613 x = 0; // FIXME_MGL, something better, see GTK+ 614 if ( y == -1 ) 615 y = 0; // FIXME_MGL, something better, see GTK+ 616 AdjustForParentClientOrigin(x, y, 0); 617 w = WidthDefault(size.x); 618 h = HeightDefault(size.y); 619 620 long mgl_style = 0; 621 window_t *wnd_parent = parent ? parent->GetHandle() : NULL; 622 623 if ( style & wxFULL_REPAINT_ON_RESIZE ) 624 { 625 mgl_style |= MGL_WM_FULL_REPAINT_ON_RESIZE; 626 } 627 if ( style & wxSTAY_ON_TOP ) 628 { 629 mgl_style |= MGL_WM_ALWAYS_ON_TOP; 630 } 631 if ( style & wxPOPUP_WINDOW ) 632 { 633 mgl_style |= MGL_WM_ALWAYS_ON_TOP; 634 // it is created hidden as other top level windows 635 m_isShown = false; 636 wnd_parent = NULL; 637 } 638 639 window_t *wnd = MGL_wmCreateWindow(g_winMng, wnd_parent, x, y, w, h); 640 641 MGL_wmSetWindowFlags(wnd, mgl_style); 642 MGL_wmShowWindow(wnd, m_isShown); 643 644 SetMGLwindow_t(wnd); 645 646 return true; 647} 648 649void wxWindowMGL::SetMGLwindow_t(struct window_t *wnd) 650{ 651 if ( m_wnd ) 652 MGL_wmDestroyWindow(m_wnd); 653 654 m_wnd = wnd; 655 if ( !m_wnd ) return; 656 657 m_isShown = (bool)m_wnd->visible; 658 659 MGL_wmSetWindowUserData(m_wnd, (void*) this); 660 MGL_wmSetWindowPainter(m_wnd, wxWindowPainter); 661 MGL_wmPushWindowEventHandler(m_wnd, wxWindowMouseHandler, EVT_MOUSEEVT, 0); 662 MGL_wmPushWindowEventHandler(m_wnd, wxWindowKeybHandler, EVT_KEYEVT, 0); 663 664 if ( m_cursor.Ok() ) 665 MGL_wmSetWindowCursor(m_wnd, *m_cursor.GetMGLCursor()); 666 else 667 MGL_wmSetWindowCursor(m_wnd, *wxSTANDARD_CURSOR->GetMGLCursor()); 668} 669 670// --------------------------------------------------------------------------- 671// basic operations 672// --------------------------------------------------------------------------- 673 674void wxWindowMGL::SetFocus() 675{ 676 if ( gs_focusedWindow == this ) return; 677 678 wxWindowMGL *oldFocusedWindow = gs_focusedWindow; 679 680 if ( gs_focusedWindow ) 681 { 682 gs_toBeFocusedWindow = (wxWindow*)this; 683 gs_focusedWindow->KillFocus(); 684 gs_toBeFocusedWindow = NULL; 685 } 686 687 gs_focusedWindow = this; 688 689 MGL_wmCaptureEvents(GetHandle(), EVT_KEYEVT, wxMGL_CAPTURE_KEYB); 690 691 wxWindowMGL *active = wxGetTopLevelParent(this); 692 if ( !(m_windowStyle & wxPOPUP_WINDOW) && active != gs_activeFrame ) 693 { 694 if ( gs_activeFrame ) 695 { 696 wxActivateEvent event(wxEVT_ACTIVATE, false, gs_activeFrame->GetId()); 697 event.SetEventObject(gs_activeFrame); 698 gs_activeFrame->GetEventHandler()->ProcessEvent(event); 699 } 700 701 gs_activeFrame = active; 702 wxActivateEvent event(wxEVT_ACTIVATE, true, gs_activeFrame->GetId()); 703 event.SetEventObject(gs_activeFrame); 704 gs_activeFrame->GetEventHandler()->ProcessEvent(event); 705 } 706 707 // notify the parent keeping track of focus for the kbd navigation 708 // purposes that we got it 709 wxChildFocusEvent eventFocus((wxWindow*)this); 710 GetEventHandler()->ProcessEvent(eventFocus); 711 712 wxFocusEvent event(wxEVT_SET_FOCUS, GetId()); 713 event.SetEventObject(this); 714 event.SetWindow((wxWindow*)oldFocusedWindow); 715 GetEventHandler()->ProcessEvent(event); 716 717#if wxUSE_CARET 718 // caret needs to be informed about focus change 719 wxCaret *caret = GetCaret(); 720 if ( caret ) 721 caret->OnSetFocus(); 722#endif // wxUSE_CARET 723} 724 725void wxWindowMGL::KillFocus() 726{ 727 if ( gs_focusedWindow != this ) return; 728 gs_focusedWindow = NULL; 729 730 if ( m_isBeingDeleted ) return; 731 732 MGL_wmUncaptureEvents(GetHandle(), wxMGL_CAPTURE_KEYB); 733 734#if wxUSE_CARET 735 // caret needs to be informed about focus change 736 wxCaret *caret = GetCaret(); 737 if ( caret ) 738 caret->OnKillFocus(); 739#endif // wxUSE_CARET 740 741 wxFocusEvent event(wxEVT_KILL_FOCUS, GetId()); 742 event.SetEventObject(this); 743 event.SetWindow(gs_toBeFocusedWindow); 744 GetEventHandler()->ProcessEvent(event); 745} 746 747// ---------------------------------------------------------------------------- 748// this wxWindowBase function is implemented here (in platform-specific file) 749// because it is static and so couldn't be made virtual 750// ---------------------------------------------------------------------------- 751wxWindow *wxWindowBase::DoFindFocus() 752{ 753 return (wxWindow*)gs_focusedWindow; 754} 755 756bool wxWindowMGL::Show(bool show) 757{ 758 if ( !wxWindowBase::Show(show) ) 759 return false; 760 761 MGL_wmShowWindow(m_wnd, show); 762 763 if (!show && gs_activeFrame == this) 764 { 765 // activate next frame in Z-order: 766 if ( m_wnd->prev ) 767 { 768 wxWindowMGL *win = (wxWindowMGL*)m_wnd->prev->userData; 769 win->SetFocus(); 770 } 771 else if ( m_wnd->next ) 772 { 773 wxWindowMGL *win = (wxWindowMGL*)m_wnd->next->userData; 774 win->SetFocus(); 775 } 776 else 777 { 778 gs_activeFrame = NULL; 779 } 780 } 781 782 return true; 783} 784 785// Raise the window to the top of the Z order 786void wxWindowMGL::Raise() 787{ 788 MGL_wmRaiseWindow(m_wnd); 789} 790 791// Lower the window to the bottom of the Z order 792void wxWindowMGL::Lower() 793{ 794 MGL_wmLowerWindow(m_wnd); 795} 796 797void wxWindowMGL::DoCaptureMouse() 798{ 799 if ( gs_mouseCapture ) 800 MGL_wmUncaptureEvents(gs_mouseCapture->m_wnd, wxMGL_CAPTURE_MOUSE); 801 802 gs_mouseCapture = this; 803 MGL_wmCaptureEvents(m_wnd, EVT_MOUSEEVT, wxMGL_CAPTURE_MOUSE); 804} 805 806void wxWindowMGL::DoReleaseMouse() 807{ 808 wxASSERT_MSG( gs_mouseCapture == this, wxT("attempt to release mouse, but this window hasn't captured it") ); 809 810 MGL_wmUncaptureEvents(m_wnd, wxMGL_CAPTURE_MOUSE); 811 gs_mouseCapture = NULL; 812} 813 814/* static */ wxWindow *wxWindowBase::GetCapture() 815{ 816 return (wxWindow*)gs_mouseCapture; 817} 818 819bool wxWindowMGL::SetCursor(const wxCursor& cursor) 820{ 821 if ( !wxWindowBase::SetCursor(cursor) ) 822 { 823 // no change 824 return false; 825 } 826 827 if ( m_cursor.Ok() ) 828 MGL_wmSetWindowCursor(m_wnd, *m_cursor.GetMGLCursor()); 829 else 830 MGL_wmSetWindowCursor(m_wnd, *wxSTANDARD_CURSOR->GetMGLCursor()); 831 832 return true; 833} 834 835void wxWindowMGL::WarpPointer(int x, int y) 836{ 837 int w, h; 838 wxDisplaySize(&w, &h); 839 840 ClientToScreen(&x, &y); 841 if ( x < 0 ) 842 x = 0; 843 if ( y < 0 ) 844 y = 0; 845 if ( x >= w ) 846 x = w-1; 847 if ( y >= h ) 848 y = h-1; 849 850 EVT_setMousePos(x, y); 851} 852 853// Set this window to be the child of 'parent'. 854bool wxWindowMGL::Reparent(wxWindowBase *parent) 855{ 856 if ( !wxWindowBase::Reparent(parent) ) 857 return false; 858 859 MGL_wmReparentWindow(m_wnd, parent->GetHandle()); 860 861 return true; 862} 863 864 865// --------------------------------------------------------------------------- 866// drag and drop 867// --------------------------------------------------------------------------- 868 869#if wxUSE_DRAG_AND_DROP 870 871void wxWindowMGL::SetDropTarget(wxDropTarget *pDropTarget) 872{ 873 if ( m_dropTarget != 0 ) { 874 m_dropTarget->Revoke(m_hWnd); 875 delete m_dropTarget; 876 } 877 878 m_dropTarget = pDropTarget; 879 if ( m_dropTarget != 0 ) 880 m_dropTarget->Register(m_hWnd); 881} 882// FIXME_MGL 883#endif // wxUSE_DRAG_AND_DROP 884 885// old style file-manager drag&drop support: we retain the old-style 886// DragAcceptFiles in parallel with SetDropTarget. 887void wxWindowMGL::DragAcceptFiles(bool WXUNUSED(accept)) 888{ 889#if 0 // FIXME_MGL 890 HWND hWnd = GetHwnd(); 891 if ( hWnd ) 892 ::DragAcceptFiles(hWnd, (BOOL)accept); 893#endif 894} 895 896// --------------------------------------------------------------------------- 897// moving and resizing 898// --------------------------------------------------------------------------- 899 900// Get total size 901void wxWindowMGL::DoGetSize(int *x, int *y) const 902{ 903 wxASSERT_MSG( m_wnd, wxT("invalid window") ); 904 905 if (x) *x = m_wnd->width; 906 if (y) *y = m_wnd->height; 907} 908 909void wxWindowMGL::DoGetPosition(int *x, int *y) const 910{ 911 wxASSERT_MSG( m_wnd, wxT("invalid window") ); 912 913 int pX = 0, pY = 0; 914 AdjustForParentClientOrigin(pX, pY, 0); 915 916 if (x) *x = m_wnd->x - pX; 917 if (y) *y = m_wnd->y - pY; 918} 919 920void wxWindowMGL::DoScreenToClient(int *x, int *y) const 921{ 922 int ax, ay; 923 MGL_wmCoordGlobalToLocal(m_wnd, 0, 0, &ax, &ay); 924 if (x) 925 (*x) += ax; 926 if (y) 927 (*y) += ay; 928} 929 930void wxWindowMGL::DoClientToScreen(int *x, int *y) const 931{ 932 int ax, ay; 933 MGL_wmCoordLocalToGlobal(m_wnd, 0, 0, &ax, &ay); 934 if (x) 935 (*x) += ax; 936 if (y) 937 (*y) += ay; 938} 939 940// Get size *available for subwindows* i.e. excluding menu bar etc. 941void wxWindowMGL::DoGetClientSize(int *x, int *y) const 942{ 943 DoGetSize(x, y); 944} 945 946void wxWindowMGL::DoMoveWindow(int x, int y, int width, int height) 947{ 948 wxRect rcClient(GetClientRect()); 949 950 MGL_wmSetWindowPosition(m_wnd, x, y, width, height); 951 952 // When the origin or a window stays fixed but the height or width 953 // changes, invalidate the old and new non-client areas 954 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) && 955 m_wnd->x == x && m_wnd->y == y && 956 rcClient.Intersect(GetClientRect()) != wxRect(0, 0, width, height) ) 957 { 958 wxRegion rgn(0, 0, width, height); 959 rgn.Subtract(rcClient); 960 961 // This should work I think, but doesn't seem to: 962 //MGL_wmInvalidateWindowRegion(m_wnd, rgn.GetMGLRegion().rgnPointer()); 963 964 // Use MGL_wmInvalidateWindowRect instead: 965 for (wxRegionIterator it(rgn); it; it++) 966 { 967 rect_t rc; 968 rc.left = it.GetX(); 969 rc.top = it.GetY(); 970 rc.right = rc.left + it.GetW(); 971 rc.bottom = rc.top + it.GetH(); 972 MGL_wmInvalidateWindowRect(m_wnd, &rc); 973 } 974 } 975} 976 977// set the size of the window: if the dimensions are positive, just use them, 978// but if any of them is equal to -1, it means that we must find the value for 979// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in 980// which case -1 is a valid value for x and y) 981// 982// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate 983// the width/height to best suit our contents, otherwise we reuse the current 984// width/height 985void wxWindowMGL::DoSetSize(int x, int y, int width, int height, int sizeFlags) 986{ 987 // get the current size and position... 988 int currentX, currentY; 989 GetPosition(¤tX, ¤tY); 990 int currentW,currentH; 991 GetSize(¤tW, ¤tH); 992 993 // ... and don't do anything (avoiding flicker) if it's already ok 994 if ( x == currentX && y == currentY && 995 width == currentW && height == currentH ) 996 { 997 return; 998 } 999 1000 if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) 1001 x = currentX; 1002 if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) 1003 y = currentY; 1004 1005 AdjustForParentClientOrigin(x, y, sizeFlags); 1006 1007 wxSize size(-1, -1); 1008 if ( width == -1 ) 1009 { 1010 if ( sizeFlags & wxSIZE_AUTO_WIDTH ) 1011 { 1012 size = DoGetBestSize(); 1013 width = size.x; 1014 } 1015 else 1016 { 1017 // just take the current one 1018 width = currentW; 1019 } 1020 } 1021 1022 if ( height == -1 ) 1023 { 1024 if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) 1025 { 1026 if ( size.x == -1 ) 1027 { 1028 size = DoGetBestSize(); 1029 } 1030 //else: already called DoGetBestSize() above 1031 1032 height = size.y; 1033 } 1034 else 1035 { 1036 // just take the current one 1037 height = currentH; 1038 } 1039 } 1040 1041 int maxWidth = GetMaxWidth(), 1042 minWidth = GetMinWidth(), 1043 maxHeight = GetMaxHeight(), 1044 minHeight = GetMinHeight(); 1045 1046 if ( minWidth != -1 && width < minWidth ) width = minWidth; 1047 if ( maxWidth != -1 && width > maxWidth ) width = maxWidth; 1048 if ( minHeight != -1 && height < minHeight ) height = minHeight; 1049 if ( maxHeight != -1 && height > maxHeight ) height = maxHeight; 1050 1051 if ( m_wnd->x != x || m_wnd->y != y || 1052 (int)m_wnd->width != width || (int)m_wnd->height != height ) 1053 { 1054 DoMoveWindow(x, y, width, height); 1055 1056 wxSize newSize(width, height); 1057 wxSizeEvent event(newSize, GetId()); 1058 event.SetEventObject(this); 1059 GetEventHandler()->ProcessEvent(event); 1060 } 1061} 1062 1063void wxWindowMGL::DoSetClientSize(int width, int height) 1064{ 1065 SetSize(width, height); 1066} 1067 1068// --------------------------------------------------------------------------- 1069// text metrics 1070// --------------------------------------------------------------------------- 1071 1072int wxWindowMGL::GetCharHeight() const 1073{ 1074 wxScreenDC dc; 1075 dc.SetFont(m_font); 1076 return dc.GetCharHeight(); 1077} 1078 1079int wxWindowMGL::GetCharWidth() const 1080{ 1081 wxScreenDC dc; 1082 dc.SetFont(m_font); 1083 return dc.GetCharWidth(); 1084} 1085 1086void wxWindowMGL::GetTextExtent(const wxString& string, 1087 int *x, int *y, 1088 int *descent, int *externalLeading, 1089 const wxFont *theFont) const 1090{ 1091 wxScreenDC dc; 1092 if (!theFont) 1093 theFont = &m_font; 1094 dc.GetTextExtent(string, x, y, descent, externalLeading, (wxFont*)theFont); 1095} 1096 1097 1098// --------------------------------------------------------------------------- 1099// painting 1100// --------------------------------------------------------------------------- 1101 1102void wxWindowMGL::Clear() 1103{ 1104 wxClientDC dc((wxWindow *)this); 1105 wxBrush brush(GetBackgroundColour(), wxSOLID); 1106 dc.SetBackground(brush); 1107 dc.Clear(); 1108} 1109 1110void wxWindowMGL::Refresh(bool eraseBack, const wxRect *rect) 1111{ 1112 if ( m_eraseBackground == -1 ) 1113 m_eraseBackground = eraseBack; 1114 else 1115 m_eraseBackground |= eraseBack; 1116 1117 if ( rect ) 1118 { 1119 rect_t r; 1120 r.left = rect->GetLeft(), r.right = rect->GetRight(); 1121 r.top = rect->GetTop(), r.bottom = rect->GetBottom(); 1122 MGL_wmInvalidateWindowRect(GetHandle(), &r); 1123 } 1124 else 1125 MGL_wmInvalidateWindow(GetHandle()); 1126} 1127 1128void wxWindowMGL::Update() 1129{ 1130 if ( !m_frozen ) 1131 MGL_wmUpdateDC(g_winMng); 1132} 1133 1134void wxWindowMGL::Freeze() 1135{ 1136 m_frozen = true; 1137 m_refreshAfterThaw = false; 1138} 1139 1140void wxWindowMGL::Thaw() 1141{ 1142 m_frozen = false; 1143 if ( m_refreshAfterThaw ) 1144 Refresh(); 1145} 1146 1147void wxWindowMGL::HandlePaint(MGLDevCtx *dc) 1148{ 1149 if ( m_frozen ) 1150 { 1151 // Don't paint anything if the window is frozen. 1152 m_refreshAfterThaw = true; 1153 return; 1154 } 1155 1156#ifdef __WXDEBUG__ 1157 // FIXME_MGL -- debugging stuff, to be removed! 1158 static int debugPaintEvents = -1; 1159 if ( debugPaintEvents == -1 ) 1160 debugPaintEvents = wxGetEnv(wxT("WXMGL_DEBUG_PAINT_EVENTS"), NULL); 1161 if ( debugPaintEvents ) 1162 { 1163 dc->setColorRGB(255,0,255); 1164 dc->fillRect(-1000,-1000,2000,2000); 1165 wxMilliSleep(50); 1166 } 1167#endif 1168 1169 MGLRegion clip; 1170 dc->getClipRegion(clip); 1171 m_updateRegion = wxRegion(clip); 1172 m_paintMGLDC = dc; 1173 1174#if wxUSE_CARET 1175 // must hide caret temporarily, otherwise we'd get rendering artifacts 1176 wxCaret *caret = GetCaret(); 1177 if ( caret ) 1178 caret->Hide(); 1179#endif // wxUSE_CARET 1180 1181 if ( m_eraseBackground != 0 ) 1182 { 1183 wxWindowDC dc((wxWindow*)this); 1184 wxEraseEvent eventEr(m_windowId, &dc); 1185 eventEr.SetEventObject(this); 1186 GetEventHandler()->ProcessEvent(eventEr); 1187 } 1188 m_eraseBackground = -1; 1189 1190 wxNcPaintEvent eventNc(GetId()); 1191 eventNc.SetEventObject(this); 1192 GetEventHandler()->ProcessEvent(eventNc); 1193 1194 wxPaintEvent eventPt(GetId()); 1195 eventPt.SetEventObject(this); 1196 GetEventHandler()->ProcessEvent(eventPt); 1197 1198#if wxUSE_CARET 1199 if ( caret ) 1200 caret->Show(); 1201#endif // wxUSE_CARET 1202 1203 m_paintMGLDC = NULL; 1204 m_updateRegion.Clear(); 1205} 1206 1207 1208// Find the wxWindow at the current mouse position, returning the mouse 1209// position. 1210wxWindow* wxFindWindowAtPointer(wxPoint& pt) 1211{ 1212 return wxFindWindowAtPoint(pt = wxGetMousePosition()); 1213} 1214 1215wxWindow* wxFindWindowAtPoint(const wxPoint& pt) 1216{ 1217 window_t *wnd = MGL_wmGetWindowAtPosition(g_winMng, pt.x, pt.y); 1218 return (wxWindow*)wnd->userData; 1219} 1220 1221 1222// --------------------------------------------------------------------------- 1223// idle events processing 1224// --------------------------------------------------------------------------- 1225 1226void wxWindowMGL::OnInternalIdle() 1227{ 1228 if (wxUpdateUIEvent::CanUpdate(this) && IsShown()) 1229 UpdateWindowUI(wxUPDATE_UI_FROMIDLE); 1230} 1231