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 bool wxCreateMGL_WM()
104 int width
= 640, height
= 480, depth
= 16;
105 int refresh
= MGL_DEFAULT_REFRESH
;
107 #if wxUSE_SYSTEM_OPTIONS
108 if ( wxSystemOptions::HasOption(wxT("mgl.screen-width") )
109 width
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-width"));
110 if ( wxSystemOptions::HasOption(wxT("mgl.screen-height") )
111 height
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-height"));
112 if ( wxSystemOptions::HasOption(wxT("mgl.screen-depth") )
113 depth
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-depth"));
114 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
115 refresh
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
118 mode
= MGL_findMode(width
, height
, depth
);
121 wxLogWarning(_("Mode %ix%i-%i not available, falling back to default mode."), width
, height
, depth
);
122 mode
= 0; // always available
124 g_displayDC
= new MGLDisplayDC(mode
, 1, refresh
);
125 if ( !g_displayDC
->isValid() )
132 g_winMng
= MGL_wmCreate(g_displayDC
->getDC());
139 void wxDestroyMGL_WM()
143 MGL_wmDestroy(g_winMng
);
153 // ---------------------------------------------------------------------------
155 // ---------------------------------------------------------------------------
157 static void wxWindowPainter(window_t
*wnd
, MGLDC
*dc
)
159 wxWindowMGL
*w
= (wxWindow
*) wnd
->userData
;
163 w
->HandlePaint(&ctx
);
167 // ---------------------------------------------------------------------------
169 // ---------------------------------------------------------------------------
171 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
173 IMPLEMENT_ABSTRACT_CLASS(wxWindowMGL
, wxWindowBase
)
175 BEGIN_EVENT_TABLE(wxWindowMGL
, wxWindowBase
)
178 // ===========================================================================
180 // ===========================================================================
182 // ----------------------------------------------------------------------------
183 // constructors and such
184 // ----------------------------------------------------------------------------
186 void wxWindowMGL::Init()
192 if ( !g_winMng
&& !wxCreateMGL_WM() )
193 wxFatalError(_T("Can't initalize MGL, aborting!"));
197 m_isBeingDeleted
= FALSE
;
204 wxWindowMGL::~wxWindowMGL()
206 m_isBeingDeleted
= TRUE
;
208 if ( g_focusedWindow
== this )
211 #if 0 // -- fixme - do we need this?
212 // VS: make sure there's no wxFrame with last focus set to us:
213 for (wxWindow
*win
= GetParent(); win
; win
= win
->GetParent())
215 wxFrame
*frame
= wxDynamicCast(win
, wxFrame
);
218 if ( frame
->GetLastFocus() == this )
219 frame
->SetLastFocus((wxWindow
*)NULL
);
225 // VS: destroy children first and _then_ detach *this from its parent.
226 // If we'd do it the other way around, children wouldn't be able
227 // find their parent frame (see above).
231 m_parent
->RemoveChild(this);
234 MGL_wmDestroyWindow(m_wnd
);
237 // real construction (Init() must have been called before!)
238 bool wxWindowMGL::Create(wxWindow
*parent
,
243 const wxString
& name
)
245 // FIXME_MGL -- temporary!
246 //wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
248 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
251 if ( parent
) // FIXME_MGL temporary
252 parent
->AddChild(this);
254 m_isShown
=FALSE
;// FIXME_MGL -- temporary, simulates wxTLW/wxFrame
256 if ( style
& wxPOPUP_WINDOW
)
258 // it is created hidden as other top level windows
262 m_wnd
= MGL_wmCreateWindow(g_winMng
,
263 parent
? parent
->GetHandle() : NULL
,
264 pos
.x
, pos
.y
, size
.x
, size
.y
);
265 MGL_wmSetWindowUserData(m_wnd
, (void*) this);
266 MGL_wmSetWindowPainter(m_wnd
, wxWindowPainter
);
270 // ---------------------------------------------------------------------------
272 // ---------------------------------------------------------------------------
274 void wxWindowMGL::SetFocus()
277 g_focusedWindow
->KillFocus();
279 g_focusedWindow
= this;
281 MGL_wmCaptureEvents(GetHandle(), EVT_KEYEVT
| EVT_JOYEVT
, wxMGL_CAPTURE_KEYB
);
284 // caret needs to be informed about focus change
285 wxCaret
*caret
= GetCaret();
288 #endif // wxUSE_CARET
292 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, GetId());
293 event
.SetEventObject(this);
294 GetEventHandler()->ProcessEvent(event
);
297 wxFocusEvent
event(wxEVT_SET_FOCUS
, GetId());
298 event
.SetEventObject(this);
299 GetEventHandler()->ProcessEvent(event
);
302 void wxWindowMGL::KillFocus()
304 if ( g_focusedWindow
!= this ) return;
305 g_focusedWindow
= NULL
;
307 if ( m_isBeingDeleted
) return;
309 MGL_wmUncaptureEvents(GetHandle(), wxMGL_CAPTURE_KEYB
);
312 // caret needs to be informed about focus change
313 wxCaret
*caret
= GetCaret();
315 caret
->OnKillFocus();
316 #endif // wxUSE_CARET
320 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, GetId());
321 event
.SetEventObject(this);
322 GetEventHandler()->ProcessEvent(event
);
325 wxFocusEvent
event(wxEVT_KILL_FOCUS
, GetId());
326 event
.SetEventObject(this);
327 GetEventHandler()->ProcessEvent(event
);
330 // ----------------------------------------------------------------------------
331 // this wxWindowBase function is implemented here (in platform-specific file)
332 // because it is static and so couldn't be made virtual
333 // ----------------------------------------------------------------------------
334 wxWindow
*wxWindowBase::FindFocus()
336 return (wxWindow
*)g_focusedWindow
;
339 bool wxWindowMGL::Show(bool show
)
341 if ( !wxWindowBase::Show(show
) )
344 MGL_wmShowWindow(m_wnd
, show
);
348 // Raise the window to the top of the Z order
349 void wxWindowMGL::Raise()
351 MGL_wmRaiseWindow(m_wnd
);
354 // Lower the window to the bottom of the Z order
355 void wxWindowMGL::Lower()
357 MGL_wmLowerWindow(m_wnd
);
360 void wxWindowMGL::CaptureMouse()
362 MGL_wmCaptureEvents(m_wnd
, EVT_MOUSEEVT
, wxMGL_CAPTURE_MOUSE
);
365 void wxWindowMGL::ReleaseMouse()
367 MGL_wmUncaptureEvents(m_wnd
, wxMGL_CAPTURE_MOUSE
);
370 /* static */ wxWindow
*wxWindowBase::GetCapture()
372 for (captureentry_t
*c
= g_winMng
->capturedEvents
; c
; c
= c
->next
)
374 if ( c
->id
== wxMGL_CAPTURE_MOUSE
)
375 return (wxWindow
*)c
->wnd
->userData
;
380 bool wxWindowMGL::SetCursor(const wxCursor
& cursor
)
382 if ( !wxWindowBase::SetCursor(cursor
) )
389 MGL_wmSetWindowCursor(m_wnd
, *m_cursor
.GetMGLCursor());
394 void wxWindowMGL::WarpPointer(int x
, int y
)
396 ClientToScreen(&x
, &y
);
397 EVT_setMousePos(x
, y
);
400 #if WXWIN_COMPATIBILITY
401 // If nothing defined for this, try the parent.
402 // E.g. we may be a button loaded from a resource, with no callback function
404 void wxWindowMGL::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
406 if ( GetEventHandler()->ProcessEvent(event
) )
409 m_parent
->GetEventHandler()->OnCommand(win
, event
);
411 #endif // WXWIN_COMPATIBILITY_2
413 #if WXWIN_COMPATIBILITY
414 wxObject
* wxWindowMGL::GetChild(int number
) const
416 // Return a pointer to the Nth object in the Panel
417 wxNode
*node
= GetChildren().First();
423 wxObject
*obj
= (wxObject
*)node
->Data();
429 #endif // WXWIN_COMPATIBILITY
431 // Set this window to be the child of 'parent'.
432 bool wxWindowMGL::Reparent(wxWindowBase
*parent
)
434 if ( !wxWindowBase::Reparent(parent
) )
437 MGL_wmReparentWindow(m_wnd
, parent
->GetHandle());
443 // ---------------------------------------------------------------------------
445 // ---------------------------------------------------------------------------
447 #if wxUSE_DRAG_AND_DROP
449 void wxWindowMGL::SetDropTarget(wxDropTarget
*pDropTarget
)
451 if ( m_dropTarget
!= 0 ) {
452 m_dropTarget
->Revoke(m_hWnd
);
456 m_dropTarget
= pDropTarget
;
457 if ( m_dropTarget
!= 0 )
458 m_dropTarget
->Register(m_hWnd
);
461 #endif // wxUSE_DRAG_AND_DROP
463 // old style file-manager drag&drop support: we retain the old-style
464 // DragAcceptFiles in parallel with SetDropTarget.
465 void wxWindowMGL::DragAcceptFiles(bool accept
)
468 HWND hWnd
= GetHwnd();
470 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
474 // ---------------------------------------------------------------------------
475 // moving and resizing
476 // ---------------------------------------------------------------------------
479 void wxWindowMGL::DoGetSize(int *x
, int *y
) const
481 if (x
) *x
= m_wnd
->width
;
482 if (y
) *y
= m_wnd
->height
;
485 void wxWindowMGL::DoGetPosition(int *x
, int *y
) const
487 if (x
) *x
= m_wnd
->x
;
488 if (y
) *y
= m_wnd
->y
;
491 void wxWindowMGL::DoScreenToClient(int *x
, int *y
) const
494 wxPoint co
= GetClientAreaOrigin();
496 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
, m_wnd
->y
, &ax
, &ay
);
505 void wxWindowMGL::DoClientToScreen(int *x
, int *y
) const
508 wxPoint co
= GetClientAreaOrigin();
510 MGL_wmCoordGlobalToLocal(m_wnd
, m_wnd
->x
+co
.x
, m_wnd
->y
+co
.y
, &ax
, &ay
);
517 // Get size *available for subwindows* i.e. excluding menu bar etc.
518 void wxWindowMGL::DoGetClientSize(int *x
, int *y
) const
523 void wxWindowMGL::DoMoveWindow(int x
, int y
, int width
, int height
)
525 MGL_wmSetWindowPosition(GetHandle(), x
, y
, width
, height
);
528 // set the size of the window: if the dimensions are positive, just use them,
529 // but if any of them is equal to -1, it means that we must find the value for
530 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
531 // which case -1 is a valid value for x and y)
533 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
534 // the width/height to best suit our contents, otherwise we reuse the current
536 void wxWindowMGL::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
538 // get the current size and position...
539 int currentX
, currentY
;
540 GetPosition(¤tX
, ¤tY
);
541 int currentW
,currentH
;
542 GetSize(¤tW
, ¤tH
);
544 // ... and don't do anything (avoiding flicker) if it's already ok
545 if ( x
== currentX
&& y
== currentY
&&
546 width
== currentW
&& height
== currentH
)
551 if ( x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
553 if ( y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
556 #if 0 // FIXME_MGL -- what's this good for?
557 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
563 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
565 size
= DoGetBestSize();
570 // just take the current one
577 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
581 size
= DoGetBestSize();
583 //else: already called DoGetBestSize() above
589 // just take the current one
594 DoMoveWindow(x
, y
, width
, height
);
596 wxSizeEvent
event(wxSize(width
, height
), GetId());
597 event
.SetEventObject(this);
598 GetEventHandler()->ProcessEvent(event
);
601 void wxWindowMGL::DoSetClientSize(int width
, int height
)
603 SetSize(width
, height
);
606 // ---------------------------------------------------------------------------
608 // ---------------------------------------------------------------------------
610 int wxWindowMGL::GetCharHeight() const
614 return dc
.GetCharHeight();
617 int wxWindowMGL::GetCharWidth() const
621 return dc
.GetCharWidth();
624 void wxWindowMGL::GetTextExtent(const wxString
& string
,
626 int *descent
, int *externalLeading
,
627 const wxFont
*theFont
) const
632 dc
.GetTextExtent(string
, x
, y
, descent
, externalLeading
, (wxFont
*)theFont
);
635 #if wxUSE_CARET && WXWIN_COMPATIBILITY
636 // ---------------------------------------------------------------------------
637 // Caret manipulation
638 // ---------------------------------------------------------------------------
640 void wxWindowMGL::CreateCaret(int w
, int h
)
642 SetCaret(new wxCaret(this, w
, h
));
645 void wxWindowMGL::CreateCaret(const wxBitmap
*WXUNUSED(bitmap
))
647 wxFAIL_MSG("not implemented");
650 void wxWindowMGL::ShowCaret(bool show
)
652 wxCHECK_RET( m_caret
, "no caret to show" );
657 void wxWindowMGL::DestroyCaret()
662 void wxWindowMGL::SetCaretPos(int x
, int y
)
664 wxCHECK_RET( m_caret
, "no caret to move" );
669 void wxWindowMGL::GetCaretPos(int *x
, int *y
) const
671 wxCHECK_RET( m_caret
, "no caret to get position of" );
673 m_caret
->GetPosition(x
, y
);
675 #endif // wxUSE_CARET
678 // ---------------------------------------------------------------------------
680 // ---------------------------------------------------------------------------
682 void wxWindowMGL::Clear()
684 wxClientDC
dc((wxWindow
*)this);
685 wxBrush
brush(GetBackgroundColour(), wxSOLID
);
686 dc
.SetBackground(brush
);
690 void wxWindowMGL::Refresh(bool WXUNUSED(eraseBack
), const wxRect
*rect
)
695 r
.left
= rect
->GetLeft(), r
.right
= rect
->GetRight();
696 r
.top
= rect
->GetTop(), r
.bottom
= rect
->GetBottom();
697 MGL_wmInvalidateWindowRect(GetHandle(), &r
);
700 MGL_wmInvalidateWindow(GetHandle());
703 void wxWindowMGL::Update()
707 MGL_wmUpdateDC(g_winMng
);
710 void wxWindowMGL::Freeze()
713 m_refreshAfterThaw
= FALSE
;
716 void wxWindowMGL::Thaw()
719 if ( m_refreshAfterThaw
)
723 void wxWindowMGL::HandlePaint(MGLDevCtx
*dc
)
727 // Don't paint anything if the window is frozen.
732 MGL_getClipRegionDC(*dc
, &clip
);
733 m_updateRegion
= wxRegion(MGLRegion(&clip
));
737 wxWindowDC
dc((wxWindow
*)this);
738 wxEraseEvent
eventEr(m_windowId
, &dc
);
739 eventEr
.SetEventObject(this);
740 GetEventHandler()->ProcessEvent(eventEr
);
743 wxNcPaintEvent
eventNc(GetId());
744 eventNc
.SetEventObject(this);
745 GetEventHandler()->ProcessEvent(eventNc
);
747 wxPaintEvent
eventPt(GetId());
748 eventPt
.SetEventObject(this);
749 GetEventHandler()->ProcessEvent(eventPt
);
755 // Find the wxWindow at the current mouse position, returning the mouse
757 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
759 return wxFindWindowAtPoint(pt
= wxGetMousePosition());
762 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
764 window_t
*wnd
= MGL_wmGetWindowAtPosition(g_winMng
, pt
.x
, pt
.y
);
765 return (wxWindow
*)wnd
->userData
;