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 static wxWindowMGL
*g_focusedWindow
;
71 // ---------------------------------------------------------------------------
73 // ---------------------------------------------------------------------------
75 // Custom identifiers used to distinguish between various event handlers
76 // and capture handlers passed to MGL_wm
79 wxMGL_CAPTURE_MOUSE
= 1,
80 wxMGL_CAPTURE_KEYB
= 2
84 // ---------------------------------------------------------------------------
86 // ---------------------------------------------------------------------------
88 static void wxWindowPainter(window_t
*wnd
, MGLDC
*dc
);
90 // wxCreateMGL_WM creates MGL display DC and associates it with winmng_t
91 // structure. Dimensions and depth of the DC are fetched from wxSystemOptions
93 // This function is *not* called from wxApp's initialization but rather at
94 // the time when WM is needed, i.e. when first wxWindow is created. This
95 // has two important effects:
96 // a) it is possible to write windowless wxMGL apps
97 // b) the app has plenty of time in wxApp::OnInit to feed wxSystemOptions
98 // with desired settings
100 bool wxCreateMGL_WM()
103 int width
= 640, height
= 480, depth
= 16;
104 int refresh
= MGL_DEFAULT_REFRESH
;
106 #if wxUSE_SYSTEM_OPTIONS
107 if ( wxSystemOptions::HasOption(wxT("mgl.screen-width") )
108 width
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-width"));
109 if ( wxSystemOptions::HasOption(wxT("mgl.screen-height") )
110 height
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-height"));
111 if ( wxSystemOptions::HasOption(wxT("mgl.screen-depth") )
112 depth
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-depth"));
113 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
114 refresh
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
117 mode
= MGL_findMode(width
, height
, depth
);
120 wxLogWarning(_("Mode %ix%i-%i not available, falling back to default mode."), width
, height
, depth
);
121 mode
= 0; // always available
123 g_displayDC
= new MGLDisplayDC(mode
, 1, refresh
);
124 if ( !g_displayDC
->isValid() )
131 g_winMng
= MGL_wmCreate(g_displayDC
->getDC());
138 void wxDestroyMGL_WM()
142 MGL_wmDestroy(g_winMng
);
150 // ---------------------------------------------------------------------------
152 // ---------------------------------------------------------------------------
154 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
156 IMPLEMENT_ABSTRACT_CLASS(wxWindowMGL
, wxWindowBase
)
158 BEGIN_EVENT_TABLE(wxWindowMGL
, wxWindowBase
)
159 EVT_ERASE_BACKGROUND(wxWindowMGL::OnEraseBackground
)
160 EVT_SET_FOCUS(wxWindowMGL::OnSetFocus
)
163 // ===========================================================================
165 // ===========================================================================
167 // ----------------------------------------------------------------------------
168 // constructors and such
169 // ----------------------------------------------------------------------------
171 void wxWindowMGL::Init()
177 if ( !g_winMng
&& !wxCreateMGL_WM() )
178 wxFatalError(_T("Can't initalize MGL, aborting!"));
182 m_isBeingDeleted
= FALSE
;
189 wxWindowMGL::~wxWindowMGL()
191 m_isBeingDeleted
= TRUE
;
193 if ( g_focusedWindow
== this )
194 g_focusedWindow
= NULL
;
195 #if 0 // -- fixme - do we need this?
196 // VS: make sure there's no wxFrame with last focus set to us:
197 for (wxWindow
*win
= GetParent(); win
; win
= win
->GetParent())
199 wxFrame
*frame
= wxDynamicCast(win
, wxFrame
);
202 if ( frame
->GetLastFocus() == this )
203 frame
->SetLastFocus((wxWindow
*)NULL
);
209 // VS: destroy children first and _then_ detach *this from its parent.
210 // If we'd do it the other way around, children wouldn't be able
211 // find their parent frame (see above).
215 m_parent
->RemoveChild(this);
218 MGL_wmDestroyWindow(m_wnd
);
221 // real construction (Init() must have been called before!)
222 bool wxWindowMGL::Create(wxWindow
*parent
,
227 const wxString
& name
)
229 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
231 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
234 parent
->AddChild(this);
236 if ( style
& wxPOPUP_WINDOW
)
238 // it is created hidden as other top level windows
242 m_wnd
= MGL_wmCreateWindow(g_winMng
,
243 parent
? parent
->GetHandle() : NULL
,
244 pos
.x
, pos
.y
, size
.x
, size
.y
);
245 MGL_wmSetWindowUserData(m_wnd
, (void*) this);
246 MGL_wmSetWindowPainter(m_wnd
, wxWindowPainter
);
250 // ---------------------------------------------------------------------------
252 // ---------------------------------------------------------------------------
254 void wxWindowMGL::SetFocus()
257 g_focusedWindow
->KillFocus();
259 g_focusedWindow
= this;
261 MGL_wmCaptureEvents(GetHandle(), EVT_KEYEVT
| EVT_JOYEVT
, wxMGL_CAPTURE_KEYB
);
263 wxPanel
*panel
= wxDynamicCast(GetParent(), wxPanel
);
265 panel
->SetLastFocus((wxWindow
*)this);
268 // caret needs to be informed about focus change
269 wxCaret
*caret
= GetCaret();
272 #endif // wxUSE_CARET
276 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, GetId());
277 event
.SetEventObject(this);
278 GetEventHandler()->ProcessEvent(event
);
281 wxFocusEvent
event(wxEVT_SET_FOCUS
, GetId());
282 event
.SetEventObject(this);
283 GetEventHandler()->ProcessEvent(event
);
286 void wxWindowMGL::KillFocus()
288 if ( g_focusedWindow
!= this ) return;
289 g_focusedWindow
= NULL
;
291 MGL_wmUncaptureEvents(GetHandle(), wxMGL_CAPTURE_KEYB
);
294 // caret needs to be informed about focus change
295 wxCaret
*caret
= GetCaret();
297 caret
->OnKillFocus();
298 #endif // wxUSE_CARET
302 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, GetId());
303 event
.SetEventObject(this);
304 GetEventHandler()->ProcessEvent(event
);
307 wxFocusEvent
event(wxEVT_KILL_FOCUS
, GetId());
308 event
.SetEventObject(this);
309 GetEventHandler()->ProcessEvent(event
);
312 // ----------------------------------------------------------------------------
313 // this wxWindowBase function is implemented here (in platform-specific file)
314 // because it is static and so couldn't be made virtual
315 // ----------------------------------------------------------------------------
316 wxWindow
*wxWindowBase::FindFocus()
318 return (wxWindow
*)g_focusedWindow
;
321 bool wxWindowMGL::Show(bool show
)
323 if ( !wxWindowBase::Show(show
) )
326 MGL_wmShowWindow(m_wnd
, show
);
330 // Raise the window to the top of the Z order
331 void wxWindowMGL::Raise()
333 MGL_wmRaiseWindow(m_wnd
);
336 // Lower the window to the bottom of the Z order
337 void wxWindowMGL::Lower()
339 MGL_wmLowerWindow(m_wnd
);
342 void wxWindowMGL::CaptureMouse()
344 MGL_wmCaptureEvents(m_wnd
, EVT_MOUSEEVT
, wxMGL_CAPTURE_MOUSE
);
347 void wxWindowMGL::ReleaseMouse()
349 MGL_wmUncaptureEvents(m_wnd
, wxMGL_CAPTURE_MOUSE
);
352 /* static */ wxWindow
*wxWindowBase::GetCapture()
354 for (captureentry_t
*c
= g_winMng
->capturedEvents
; c
; c
= c
->next
)
356 if ( c
->id
== wxMGL_CAPTURE_MOUSE
)
357 return (wxWindow
*)c
->wnd
->userData
;
362 bool wxWindowMGL::SetCursor(const wxCursor
& cursor
)
364 if ( !wxWindowBase::SetCursor(cursor
) )
371 MGL_wmSetWindowCursor(m_wnd
, *m_cursor
.GetMGLCursor());
376 void wxWindowMGL::WarpPointer(int x
, int y
)
378 ClientToScreen(&x
, &y
);
379 EVT_setMousePos(x
, y
);
382 #if WXWIN_COMPATIBILITY
383 // If nothing defined for this, try the parent.
384 // E.g. we may be a button loaded from a resource, with no callback function
386 void wxWindowMGL::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
388 if ( GetEventHandler()->ProcessEvent(event
) )
391 m_parent
->GetEventHandler()->OnCommand(win
, event
);
393 #endif // WXWIN_COMPATIBILITY_2
395 #if WXWIN_COMPATIBILITY
396 wxObject
* wxWindowMGL::GetChild(int number
) const
398 // Return a pointer to the Nth object in the Panel
399 wxNode
*node
= GetChildren().First();
405 wxObject
*obj
= (wxObject
*)node
->Data();
411 #endif // WXWIN_COMPATIBILITY
413 // Set this window to be the child of 'parent'.
414 bool wxWindowMGL::Reparent(wxWindowBase
*parent
)
416 if ( !wxWindowBase::Reparent(parent
) )
419 MGL_wmReparentWindow(m_wnd
, parent
->GetHandle());
425 // ---------------------------------------------------------------------------
427 // ---------------------------------------------------------------------------
429 #if wxUSE_DRAG_AND_DROP
431 void wxWindowMGL::SetDropTarget(wxDropTarget
*pDropTarget
)
433 if ( m_dropTarget
!= 0 ) {
434 m_dropTarget
->Revoke(m_hWnd
);
438 m_dropTarget
= pDropTarget
;
439 if ( m_dropTarget
!= 0 )
440 m_dropTarget
->Register(m_hWnd
);
443 #endif // wxUSE_DRAG_AND_DROP
445 // old style file-manager drag&drop support: we retain the old-style
446 // DragAcceptFiles in parallel with SetDropTarget.
447 void wxWindowMGL::DragAcceptFiles(bool accept
)
450 HWND hWnd
= GetHwnd();
452 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
456 // ---------------------------------------------------------------------------
457 // moving and resizing
458 // ---------------------------------------------------------------------------
461 void wxWindowMGL::DoGetSize(int *x
, int *y
) const
463 if (x
) *x
= m_wnd
->width
;
464 if (y
) *y
= m_wnd
->height
;
467 void wxWindowMGL::DoGetPosition(int *x
, int *y
) const
469 if (x
) *x
= m_wnd
->x
;
470 if (y
) *y
= m_wnd
->y
;
473 void wxWindowMGL::DoScreenToClient(int *x
, int *y
) const
476 wxPoint co
= GetClientAreaOrigin();
478 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
, m_wnd
->y
, &ax
, &ay
);
487 void wxWindowMGL::DoClientToScreen(int *x
, int *y
) const
490 wxPoint co
= GetClientAreaOrigin();
492 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
+co
.x
, m_wnd
->y
+co
.y
, &ax
, &ay
);
499 // Get size *available for subwindows* i.e. excluding menu bar etc.
500 void wxWindowMGL::DoGetClientSize(int *x
, int *y
) const
505 void wxWindowMGL::DoMoveWindow(int x
, int y
, int width
, int height
)
507 MGL_wmSetWindowPosition(GetHandle(), x
, y
, width
, height
);
510 // set the size of the window: if the dimensions are positive, just use them,
511 // but if any of them is equal to -1, it means that we must find the value for
512 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
513 // which case -1 is a valid value for x and y)
515 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
516 // the width/height to best suit our contents, otherwise we reuse the current
518 void wxWindowMGL::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
520 // get the current size and position...
521 int currentX
, currentY
;
522 GetPosition(¤tX
, ¤tY
);
523 int currentW
,currentH
;
524 GetSize(¤tW
, ¤tH
);
526 // ... and don't do anything (avoiding flicker) if it's already ok
527 if ( x
== currentX
&& y
== currentY
&&
528 width
== currentW
&& height
== currentH
)
533 if ( x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
535 if ( y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
538 #if 0 // FIXME_MGL -- what's this good for?
539 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
545 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
547 size
= DoGetBestSize();
552 // just take the current one
559 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
563 size
= DoGetBestSize();
565 //else: already called DoGetBestSize() above
571 // just take the current one
576 DoMoveWindow(x
, y
, width
, height
);
578 wxSizeEvent
event(wxSize(width
, height
), GetId());
579 event
.SetEventObject(this);
580 GetEventHandler()->ProcessEvent(event
);
583 void wxWindowMGL::DoSetClientSize(int width
, int height
)
585 SetSize(width
, height
);
588 // ---------------------------------------------------------------------------
590 // ---------------------------------------------------------------------------
592 int wxWindowMGL::GetCharHeight() const
596 return dc
.GetCharHeight();
599 int wxWindowMGL::GetCharWidth() const
603 return dc
.GetCharWidth();
606 void wxWindowMGL::GetTextExtent(const wxString
& string
,
608 int *descent
, int *externalLeading
,
609 const wxFont
*theFont
) const
614 dc
.GetTextExtent(string
, x
, y
, descent
, externalLeading
, (wxFont
*)theFont
);
617 #if wxUSE_CARET && WXWIN_COMPATIBILITY
618 // ---------------------------------------------------------------------------
619 // Caret manipulation
620 // ---------------------------------------------------------------------------
622 void wxWindowMGL::CreateCaret(int w
, int h
)
624 SetCaret(new wxCaret(this, w
, h
));
627 void wxWindowMGL::CreateCaret(const wxBitmap
*WXUNUSED(bitmap
))
629 wxFAIL_MSG("not implemented");
632 void wxWindowMGL::ShowCaret(bool show
)
634 wxCHECK_RET( m_caret
, "no caret to show" );
639 void wxWindowMGL::DestroyCaret()
644 void wxWindowMGL::SetCaretPos(int x
, int y
)
646 wxCHECK_RET( m_caret
, "no caret to move" );
651 void wxWindowMGL::GetCaretPos(int *x
, int *y
) const
653 wxCHECK_RET( m_caret
, "no caret to get position of" );
655 m_caret
->GetPosition(x
, y
);
657 #endif // wxUSE_CARET
660 // ---------------------------------------------------------------------------
662 // ---------------------------------------------------------------------------
664 void wxWindowMGL::OnSetFocus(wxFocusEvent
& event
)
666 // panel wants to track the window which was the last to have focus in it,
667 // so we want to set ourselves as the window which last had focus
669 // notice that it's also important to do it upwards the tree becaus
670 // otherwise when the top level panel gets focus, it won't set it back to
671 // us, but to some other sibling
672 wxWindow
*win
= (wxWindow
*)this;
675 wxWindow
*parent
= win
->GetParent();
676 wxPanel
*panel
= wxDynamicCast(parent
, wxPanel
);
679 panel
->SetLastFocus(win
);
689 // ---------------------------------------------------------------------------
691 // ---------------------------------------------------------------------------
693 void wxWindowMGL::Clear()
695 wxClientDC
dc((wxWindow
*)this);
696 wxBrush
brush(GetBackgroundColour(), wxSOLID
);
697 dc
.SetBackground(brush
);
701 void wxWindowMGL::Refresh(bool WXUNUSED(eraseBack
), const wxRect
*rect
)
706 r
.left
= rect
->GetLeft(), r
.right
= rect
->GetRight();
707 r
.top
= rect
->GetTop(), r
.bottom
= rect
->GetBottom();
708 MGL_wmInvalidateWindowRect(GetHandle(), &r
);
711 MGL_wmInvalidateWindow(GetHandle());
714 void wxWindowMGL::Update()
718 MGL_wmUpdateDC(g_winMng
);
721 void wxWindowMGL::Freeze()
724 m_refreshAfterThaw
= FALSE
;
727 void wxWindowMGL::Thaw()
730 if ( m_refreshAfterThaw
)
734 static void wxWindowPainter(window_t
*wnd
, MGLDC
*dc
)
736 wxWindow
*w
= (wxWindow
*) wnd
->userData
;
740 w
->HandlePaint(&ctx
);
744 void wxWindowMGL::HandlePaint(MGLDevCtx
*dc
)
748 // Don't paint anything if the window is frozen.
752 region_t
*clip
= NULL
;
753 MGL_getClipRegionDC(*dc
, clip
);
754 m_updateRegion
= wxRegion(MGLRegion(clip
));
757 wxEraseEvent
eventEr(m_windowId
, NULL
);
758 eventEr
.SetEventObject(this);
759 GetEventHandler()->ProcessEvent(eventEr
);
761 wxNcPaintEvent
eventNc(GetId());
762 eventNc
.SetEventObject(this);
763 GetEventHandler()->ProcessEvent(eventNc
);
765 wxPaintEvent
eventPt(GetId());
766 eventPt
.SetEventObject(this);
767 GetEventHandler()->ProcessEvent(eventPt
);
770 void wxWindowMGL::OnEraseBackground(wxEraseEvent
& event
)
776 // Find the wxWindow at the current mouse position, returning the mouse
778 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
780 return wxFindWindowAtPoint(pt
= wxGetMousePosition());
783 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
785 window_t
*wnd
= MGL_wmGetWindowAtPosition(g_winMng
, pt
.x
, pt
.y
);
786 return (wxWindow
*)wnd
->userData
;