1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mgl/window.cpp
4 // Author: Vaclav Slavik
5 // (based on GTK & MSW implementations)
7 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows license
9 /////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
13 // ===========================================================================
15 // ---------------------------------------------------------------------------
17 // ---------------------------------------------------------------------------
20 #pragma implementation "window.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
31 #include "wx/window.h"
35 #include "wx/dcclient.h"
42 #if wxUSE_DRAG_AND_DROP
47 #include "wx/sysopt.h"
48 #include "wx/mgl/private.h"
50 #include "wx/dcscreen.h"
55 #include "wx/tooltip.h"
58 // ---------------------------------------------------------------------------
60 // ---------------------------------------------------------------------------
62 // MGL window manager and associated DC.
63 winmng_t
*g_winMng
= NULL
;
64 MGLDevCtx
*g_displayDC
= NULL
;
66 extern wxList WXDLLEXPORT wxPendingDelete
;
69 // the window that has keyboard+joystick focus:
70 static wxWindowMGL
*g_focusedWindow
= NULL
;
71 // the window that is currently under mouse cursor:
72 static wxWindowMGL
*g_windowUnderMouse
= NULL
;
74 // ---------------------------------------------------------------------------
76 // ---------------------------------------------------------------------------
78 // Custom identifiers used to distinguish between various event handlers
79 // and capture handlers passed to MGL_wm
82 wxMGL_CAPTURE_MOUSE
= 1,
83 wxMGL_CAPTURE_KEYB
= 2
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 // wxCreateMGL_WM creates MGL display DC and associates it with winmng_t
92 // structure. Dimensions and depth of the DC are fetched from wxSystemOptions
94 // This function is *not* called from wxApp's initialization but rather at
95 // the time when WM is needed, i.e. when first wxWindow is created. This
96 // has two important effects:
97 // a) it is possible to write windowless wxMGL apps
98 // b) the app has plenty of time in wxApp::OnInit to feed wxSystemOptions
99 // with desired settings
101 // FIXME_MGL -- move to app.cpp??
102 bool wxCreateMGL_WM()
105 int width
= 640, height
= 480, depth
= 16;
106 int refresh
= MGL_DEFAULT_REFRESH
;
108 #if wxUSE_SYSTEM_OPTIONS
109 if ( wxSystemOptions::HasOption(wxT("mgl.screen-width") )
110 width
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-width"));
111 if ( wxSystemOptions::HasOption(wxT("mgl.screen-height") )
112 height
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-height"));
113 if ( wxSystemOptions::HasOption(wxT("mgl.screen-depth") )
114 depth
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-depth"));
115 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
116 refresh
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
119 mode
= MGL_findMode(width
, height
, depth
);
122 wxLogWarning(_("Mode %ix%i-%i not available, falling back to default mode."), width
, height
, depth
);
123 mode
= 0; // always available
125 g_displayDC
= new MGLDisplayDC(mode
, 1, refresh
);
126 if ( !g_displayDC
->isValid() )
133 g_winMng
= MGL_wmCreate(g_displayDC
->getDC());
140 void wxDestroyMGL_WM()
144 MGL_wmDestroy(g_winMng
);
154 // ---------------------------------------------------------------------------
156 // ---------------------------------------------------------------------------
158 static void wxWindowPainter(window_t
*wnd
, MGLDC
*dc
)
160 wxWindowMGL
*w
= (wxWindow
*) wnd
->userData
;
164 w
->HandlePaint(&ctx
);
168 // ---------------------------------------------------------------------------
170 // ---------------------------------------------------------------------------
172 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
174 IMPLEMENT_ABSTRACT_CLASS(wxWindowMGL
, wxWindowBase
)
176 BEGIN_EVENT_TABLE(wxWindowMGL
, wxWindowBase
)
179 // ===========================================================================
181 // ===========================================================================
183 // ----------------------------------------------------------------------------
184 // constructors and such
185 // ----------------------------------------------------------------------------
187 void wxWindowMGL::Init()
193 if ( !g_winMng
&& !wxCreateMGL_WM() )
194 wxFatalError(_T("Can't initalize MGL, aborting!"));
198 m_isBeingDeleted
= FALSE
;
205 wxWindowMGL::~wxWindowMGL()
207 m_isBeingDeleted
= TRUE
;
209 if ( g_focusedWindow
== this )
212 #if 0 // -- fixme - do we need this?
213 // VS: make sure there's no wxFrame with last focus set to us:
214 for (wxWindow
*win
= GetParent(); win
; win
= win
->GetParent())
216 wxFrame
*frame
= wxDynamicCast(win
, wxFrame
);
219 if ( frame
->GetLastFocus() == this )
220 frame
->SetLastFocus((wxWindow
*)NULL
);
226 // VS: destroy children first and _then_ detach *this from its parent.
227 // If we'd do it the other way around, children wouldn't be able
228 // find their parent frame (see above).
232 m_parent
->RemoveChild(this);
235 MGL_wmDestroyWindow(m_wnd
);
238 // real construction (Init() must have been called before!)
239 bool wxWindowMGL::Create(wxWindow
*parent
,
244 const wxString
& name
)
246 // FIXME_MGL -- temporary!
247 //wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
249 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
252 if ( parent
) // FIXME_MGL temporary
253 parent
->AddChild(this);
255 m_isShown
=FALSE
;// FIXME_MGL -- temporary, simulates wxTLW/wxFrame
257 if ( style
& wxPOPUP_WINDOW
)
259 // it is created hidden as other top level windows
263 m_wnd
= MGL_wmCreateWindow(g_winMng
,
264 parent
? parent
->GetHandle() : NULL
,
265 pos
.x
, pos
.y
, size
.x
, size
.y
);
266 MGL_wmShowWindow(m_wnd
, m_isShown
);
267 MGL_wmSetWindowUserData(m_wnd
, (void*) this);
268 MGL_wmSetWindowPainter(m_wnd
, wxWindowPainter
);
272 // ---------------------------------------------------------------------------
274 // ---------------------------------------------------------------------------
276 void wxWindowMGL::SetFocus()
279 g_focusedWindow
->KillFocus();
281 g_focusedWindow
= this;
283 MGL_wmCaptureEvents(GetHandle(), EVT_KEYEVT
| EVT_JOYEVT
, wxMGL_CAPTURE_KEYB
);
286 // caret needs to be informed about focus change
287 wxCaret
*caret
= GetCaret();
290 #endif // wxUSE_CARET
294 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, GetId());
295 event
.SetEventObject(this);
296 GetEventHandler()->ProcessEvent(event
);
299 wxFocusEvent
event(wxEVT_SET_FOCUS
, GetId());
300 event
.SetEventObject(this);
301 GetEventHandler()->ProcessEvent(event
);
304 void wxWindowMGL::KillFocus()
306 if ( g_focusedWindow
!= this ) return;
307 g_focusedWindow
= NULL
;
309 if ( m_isBeingDeleted
) return;
311 MGL_wmUncaptureEvents(GetHandle(), wxMGL_CAPTURE_KEYB
);
314 // caret needs to be informed about focus change
315 wxCaret
*caret
= GetCaret();
317 caret
->OnKillFocus();
318 #endif // wxUSE_CARET
322 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, GetId());
323 event
.SetEventObject(this);
324 GetEventHandler()->ProcessEvent(event
);
327 wxFocusEvent
event(wxEVT_KILL_FOCUS
, GetId());
328 event
.SetEventObject(this);
329 GetEventHandler()->ProcessEvent(event
);
332 // ----------------------------------------------------------------------------
333 // this wxWindowBase function is implemented here (in platform-specific file)
334 // because it is static and so couldn't be made virtual
335 // ----------------------------------------------------------------------------
336 wxWindow
*wxWindowBase::FindFocus()
338 return (wxWindow
*)g_focusedWindow
;
341 bool wxWindowMGL::Show(bool show
)
343 if ( !wxWindowBase::Show(show
) )
346 MGL_wmShowWindow(m_wnd
, show
);
350 // Raise the window to the top of the Z order
351 void wxWindowMGL::Raise()
353 MGL_wmRaiseWindow(m_wnd
);
356 // Lower the window to the bottom of the Z order
357 void wxWindowMGL::Lower()
359 MGL_wmLowerWindow(m_wnd
);
362 void wxWindowMGL::CaptureMouse()
364 MGL_wmCaptureEvents(m_wnd
, EVT_MOUSEEVT
, wxMGL_CAPTURE_MOUSE
);
367 void wxWindowMGL::ReleaseMouse()
369 MGL_wmUncaptureEvents(m_wnd
, wxMGL_CAPTURE_MOUSE
);
372 /* static */ wxWindow
*wxWindowBase::GetCapture()
374 for (captureentry_t
*c
= g_winMng
->capturedEvents
; c
; c
= c
->next
)
376 if ( c
->id
== wxMGL_CAPTURE_MOUSE
)
377 return (wxWindow
*)c
->wnd
->userData
;
382 bool wxWindowMGL::SetCursor(const wxCursor
& cursor
)
384 if ( !wxWindowBase::SetCursor(cursor
) )
391 MGL_wmSetWindowCursor(m_wnd
, *m_cursor
.GetMGLCursor());
396 void wxWindowMGL::WarpPointer(int x
, int y
)
398 ClientToScreen(&x
, &y
);
399 EVT_setMousePos(x
, y
);
402 #if WXWIN_COMPATIBILITY
403 // If nothing defined for this, try the parent.
404 // E.g. we may be a button loaded from a resource, with no callback function
406 void wxWindowMGL::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
408 if ( GetEventHandler()->ProcessEvent(event
) )
411 m_parent
->GetEventHandler()->OnCommand(win
, event
);
413 #endif // WXWIN_COMPATIBILITY_2
415 #if WXWIN_COMPATIBILITY
416 wxObject
* wxWindowMGL::GetChild(int number
) const
418 // Return a pointer to the Nth object in the Panel
419 wxNode
*node
= GetChildren().First();
425 wxObject
*obj
= (wxObject
*)node
->Data();
431 #endif // WXWIN_COMPATIBILITY
433 // Set this window to be the child of 'parent'.
434 bool wxWindowMGL::Reparent(wxWindowBase
*parent
)
436 if ( !wxWindowBase::Reparent(parent
) )
439 MGL_wmReparentWindow(m_wnd
, parent
->GetHandle());
445 // ---------------------------------------------------------------------------
447 // ---------------------------------------------------------------------------
449 #if wxUSE_DRAG_AND_DROP
451 void wxWindowMGL::SetDropTarget(wxDropTarget
*pDropTarget
)
453 if ( m_dropTarget
!= 0 ) {
454 m_dropTarget
->Revoke(m_hWnd
);
458 m_dropTarget
= pDropTarget
;
459 if ( m_dropTarget
!= 0 )
460 m_dropTarget
->Register(m_hWnd
);
463 #endif // wxUSE_DRAG_AND_DROP
465 // old style file-manager drag&drop support: we retain the old-style
466 // DragAcceptFiles in parallel with SetDropTarget.
467 void wxWindowMGL::DragAcceptFiles(bool accept
)
470 HWND hWnd
= GetHwnd();
472 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
476 // ---------------------------------------------------------------------------
477 // moving and resizing
478 // ---------------------------------------------------------------------------
481 void wxWindowMGL::DoGetSize(int *x
, int *y
) const
483 if (x
) *x
= m_wnd
->width
;
484 if (y
) *y
= m_wnd
->height
;
487 void wxWindowMGL::DoGetPosition(int *x
, int *y
) const
489 if (x
) *x
= m_wnd
->x
;
490 if (y
) *y
= m_wnd
->y
;
493 void wxWindowMGL::DoScreenToClient(int *x
, int *y
) const
496 wxPoint co
= GetClientAreaOrigin();
498 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
, m_wnd
->y
, &ax
, &ay
);
507 void wxWindowMGL::DoClientToScreen(int *x
, int *y
) const
510 wxPoint co
= GetClientAreaOrigin();
512 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
+co
.x
, m_wnd
->y
+co
.y
, &ax
, &ay
);
519 // Get size *available for subwindows* i.e. excluding menu bar etc.
520 void wxWindowMGL::DoGetClientSize(int *x
, int *y
) const
525 void wxWindowMGL::DoMoveWindow(int x
, int y
, int width
, int height
)
527 MGL_wmSetWindowPosition(GetHandle(), x
, y
, width
, height
);
530 // set the size of the window: if the dimensions are positive, just use them,
531 // but if any of them is equal to -1, it means that we must find the value for
532 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
533 // which case -1 is a valid value for x and y)
535 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
536 // the width/height to best suit our contents, otherwise we reuse the current
538 void wxWindowMGL::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
540 // get the current size and position...
541 int currentX
, currentY
;
542 GetPosition(¤tX
, ¤tY
);
543 int currentW
,currentH
;
544 GetSize(¤tW
, ¤tH
);
546 // ... and don't do anything (avoiding flicker) if it's already ok
547 if ( x
== currentX
&& y
== currentY
&&
548 width
== currentW
&& height
== currentH
)
553 if ( x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
555 if ( y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
558 #if 0 // FIXME_MGL -- what's this good for?
559 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
565 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
567 size
= DoGetBestSize();
572 // just take the current one
579 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
583 size
= DoGetBestSize();
585 //else: already called DoGetBestSize() above
591 // just take the current one
596 DoMoveWindow(x
, y
, width
, height
);
598 wxSizeEvent
event(wxSize(width
, height
), GetId());
599 event
.SetEventObject(this);
600 GetEventHandler()->ProcessEvent(event
);
603 void wxWindowMGL::DoSetClientSize(int width
, int height
)
605 SetSize(width
, height
);
608 // ---------------------------------------------------------------------------
610 // ---------------------------------------------------------------------------
612 int wxWindowMGL::GetCharHeight() const
616 return dc
.GetCharHeight();
619 int wxWindowMGL::GetCharWidth() const
623 return dc
.GetCharWidth();
626 void wxWindowMGL::GetTextExtent(const wxString
& string
,
628 int *descent
, int *externalLeading
,
629 const wxFont
*theFont
) const
634 dc
.GetTextExtent(string
, x
, y
, descent
, externalLeading
, (wxFont
*)theFont
);
637 #if wxUSE_CARET && WXWIN_COMPATIBILITY
638 // ---------------------------------------------------------------------------
639 // Caret manipulation
640 // ---------------------------------------------------------------------------
642 void wxWindowMGL::CreateCaret(int w
, int h
)
644 SetCaret(new wxCaret(this, w
, h
));
647 void wxWindowMGL::CreateCaret(const wxBitmap
*WXUNUSED(bitmap
))
649 wxFAIL_MSG("not implemented");
652 void wxWindowMGL::ShowCaret(bool show
)
654 wxCHECK_RET( m_caret
, "no caret to show" );
659 void wxWindowMGL::DestroyCaret()
664 void wxWindowMGL::SetCaretPos(int x
, int y
)
666 wxCHECK_RET( m_caret
, "no caret to move" );
671 void wxWindowMGL::GetCaretPos(int *x
, int *y
) const
673 wxCHECK_RET( m_caret
, "no caret to get position of" );
675 m_caret
->GetPosition(x
, y
);
677 #endif // wxUSE_CARET
680 // ---------------------------------------------------------------------------
682 // ---------------------------------------------------------------------------
684 void wxWindowMGL::Clear()
686 wxClientDC
dc((wxWindow
*)this);
687 wxBrush
brush(GetBackgroundColour(), wxSOLID
);
688 dc
.SetBackground(brush
);
692 void wxWindowMGL::Refresh(bool WXUNUSED(eraseBack
), const wxRect
*rect
)
697 r
.left
= rect
->GetLeft(), r
.right
= rect
->GetRight();
698 r
.top
= rect
->GetTop(), r
.bottom
= rect
->GetBottom();
699 MGL_wmInvalidateWindowRect(GetHandle(), &r
);
702 MGL_wmInvalidateWindow(GetHandle());
705 void wxWindowMGL::Update()
708 MGL_wmUpdateDC(g_winMng
);
711 void wxWindowMGL::Freeze()
714 m_refreshAfterThaw
= FALSE
;
717 void wxWindowMGL::Thaw()
720 if ( m_refreshAfterThaw
)
724 void wxWindowMGL::HandlePaint(MGLDevCtx
*dc
)
728 // Don't paint anything if the window is frozen.
729 m_refreshAfterThaw
= TRUE
;
734 dc
->getClipRegion(clip
);
735 m_updateRegion
= wxRegion(clip
);
739 wxWindowDC
dc((wxWindow
*)this);
740 wxEraseEvent
eventEr(m_windowId
, &dc
);
741 eventEr
.SetEventObject(this);
742 GetEventHandler()->ProcessEvent(eventEr
);
745 wxNcPaintEvent
eventNc(GetId());
746 eventNc
.SetEventObject(this);
747 GetEventHandler()->ProcessEvent(eventNc
);
749 wxPaintEvent
eventPt(GetId());
750 eventPt
.SetEventObject(this);
751 GetEventHandler()->ProcessEvent(eventPt
);
754 m_updateRegion
.Clear();
758 // Find the wxWindow at the current mouse position, returning the mouse
760 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
762 return wxFindWindowAtPoint(pt
= wxGetMousePosition());
765 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
767 window_t
*wnd
= MGL_wmGetWindowAtPosition(g_winMng
, pt
.x
, pt
.y
);
768 return (wxWindow
*)wnd
->userData
;