]> git.saurik.com Git - wxWidgets.git/blame - src/univ/topluniv.cpp
another segfault fix
[wxWidgets.git] / src / univ / topluniv.cpp
CommitLineData
0f1bf77d
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: topluniv.cpp
3// Author: Vaclav Slavik
4// Id: $Id$
5// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
6// Licence: wxWindows licence
7/////////////////////////////////////////////////////////////////////////////
8
9// ============================================================================
10// declarations
11// ============================================================================
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17#ifdef __GNUG__
18 #pragma implementation "univtoplevel.h"
19#endif
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25#pragma hdrstop
26#endif
27
28#include "wx/defs.h"
f8e3449c
VS
29
30#ifndef WX_PRECOMP
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33#endif
34
0f1bf77d 35#include "wx/toplevel.h"
24a23c35 36#include "wx/univ/renderer.h"
24a23c35
VS
37#include "wx/bitmap.h"
38#include "wx/image.h"
813edf09 39#include "wx/cshelp.h"
0f1bf77d
VS
40
41
42// ----------------------------------------------------------------------------
43// event tables
44// ----------------------------------------------------------------------------
45
24a23c35 46BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
ea1b0d6c 47 WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
24a23c35
VS
48 EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
49END_EVENT_TABLE()
50
ea1b0d6c
VS
51WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
52
0f1bf77d
VS
53// ============================================================================
54// implementation
55// ============================================================================
56
24a23c35 57int wxTopLevelWindow::ms_drawDecorations = -1;
253293c1 58int wxTopLevelWindow::ms_canIconize = -1;
24a23c35 59
0f1bf77d
VS
60void wxTopLevelWindow::Init()
61{
24a23c35 62 m_isActive = FALSE;
ea1b0d6c 63 m_windowStyle = 0;
813edf09 64 m_pressedButton = 0;
0f1bf77d
VS
65}
66
67bool wxTopLevelWindow::Create(wxWindow *parent,
68 wxWindowID id,
69 const wxString& title,
70 const wxPoint& pos,
7ee7c43f 71 const wxSize& size,
0f1bf77d
VS
72 long style,
73 const wxString &name)
74{
2e9f62da
VZ
75 // init them to avoid compiler warnings
76 long styleOrig = 0,
77 exstyleOrig = 0;
24a23c35
VS
78
79 if ( ms_drawDecorations == -1 )
253293c1
VS
80 {
81 ms_drawDecorations =
82 !wxSystemSettings::GetCapability(wxSYS_CAN_DRAW_FRAME_DECORATIONS)
83 || wxGetEnv(wxT("WXDECOR"), NULL);
4c785218
VS
84 // FIXME -- wxUniv should provide a way to force non-native decorations!
85 // $WXDECOR is just a hack in absence of better wxUniv solution
253293c1
VS
86 }
87
88 if ( ms_canIconize == -1 )
89 {
90 ms_canIconize = wxSystemSettings::GetCapability(wxSYS_CAN_ICONIZE_FRAME);
91 }
24a23c35
VS
92
93 if ( ms_drawDecorations )
94 {
ea1b0d6c
VS
95 CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
96
24a23c35
VS
97 styleOrig = style;
98 exstyleOrig = GetExtraStyle();
7ee7c43f
VZ
99 style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
100 wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
813edf09
VS
101 wxTHICK_FRAME);
102 style = wxSIMPLE_BORDER;
7ee7c43f 103 SetExtraStyle(exstyleOrig &
813edf09 104 ~(wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP));
24a23c35
VS
105 }
106
7ee7c43f
VZ
107 if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
108 size, style, name) )
109 return FALSE;
110
24a23c35
VS
111 if ( ms_drawDecorations )
112 {
113 m_windowStyle = styleOrig;
114 m_exStyle = exstyleOrig;
115 }
7ee7c43f 116
0f1bf77d
VS
117 return TRUE;
118}
119
120bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
121{
122 if ( show == IsFullScreen() ) return FALSE;
7ee7c43f 123
ea1b0d6c
VS
124 if ( ms_drawDecorations )
125 {
126 if ( show )
127 {
128 m_fsSavedStyle = m_windowStyle;
129 if ( style & wxFULLSCREEN_NOBORDER )
130 m_windowStyle |= wxSIMPLE_BORDER;
131 if ( style & wxFULLSCREEN_NOCAPTION )
132 m_windowStyle &= ~wxCAPTION;
133 }
134 else
135 {
136 m_windowStyle = m_fsSavedStyle;
137 }
138 }
2e9f62da 139
ea1b0d6c 140 return wxTopLevelWindowNative::ShowFullScreen(show, style);
0f1bf77d
VS
141}
142
24a23c35
VS
143long wxTopLevelWindow::GetDecorationsStyle() const
144{
145 long style = 0;
146
147 if ( m_windowStyle & wxCAPTION )
148 {
ea1b0d6c 149 style |= wxTOPLEVEL_TITLEBAR | wxTOPLEVEL_BUTTON_CLOSE;
253293c1 150 if ( (m_windowStyle & wxMINIMIZE_BOX) && ms_canIconize )
813edf09 151 style |= wxTOPLEVEL_BUTTON_ICONIZE;
24a23c35 152 if ( m_windowStyle & wxMAXIMIZE_BOX )
15678bec
VS
153 {
154 if ( IsMaximized() )
155 style |= wxTOPLEVEL_BUTTON_RESTORE;
156 else
157 style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
158 }
813edf09 159#if wxUSE_HELP
24a23c35 160 if ( m_exStyle & (wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP))
ea1b0d6c 161 style |= wxTOPLEVEL_BUTTON_HELP;
813edf09 162#endif
24a23c35
VS
163 }
164 if ( (m_windowStyle & (wxSIMPLE_BORDER | wxNO_BORDER)) == 0 )
165 style |= wxTOPLEVEL_BORDER;
166 if ( m_windowStyle & (wxRESIZE_BORDER | wxTHICK_FRAME) )
167 style |= wxTOPLEVEL_RESIZEABLE;
7ee7c43f 168
24a23c35
VS
169 if ( IsMaximized() )
170 style |= wxTOPLEVEL_MAXIMIZED;
171 if ( GetIcon().Ok() )
172 style |= wxTOPLEVEL_ICON;
ea1b0d6c 173 if ( m_isActive )
24a23c35
VS
174 style |= wxTOPLEVEL_ACTIVE;
175
176 return style;
177}
178
813edf09
VS
179void wxTopLevelWindow::RefreshTitleBar()
180{
181 wxNcPaintEvent event(GetId());
182 event.SetEventObject(this);
183 GetEventHandler()->ProcessEvent(event);
184}
185
24a23c35
VS
186// ----------------------------------------------------------------------------
187// client area handling
188// ----------------------------------------------------------------------------
189
190wxPoint wxTopLevelWindow::GetClientAreaOrigin() const
191{
192 if ( ms_drawDecorations )
193 {
194 int w, h;
195 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
196 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
197 wxSize(w, h));
7ee7c43f 198 rect = m_renderer->GetFrameClientArea(rect,
24a23c35
VS
199 GetDecorationsStyle());
200 return rect.GetPosition();
201 }
202 else
203 {
204 return wxTopLevelWindowNative::GetClientAreaOrigin();
205 }
206}
207
208void wxTopLevelWindow::DoGetClientSize(int *width, int *height) const
209{
210 if ( ms_drawDecorations )
211 {
212 int w, h;
213 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
214 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
215 wxSize(w, h));
7ee7c43f 216 rect = m_renderer->GetFrameClientArea(rect,
24a23c35
VS
217 GetDecorationsStyle());
218 if ( width )
219 *width = rect.width;
220 if ( height )
221 *height = rect.height;
222 }
223 else
224 wxTopLevelWindowNative::DoGetClientSize(width, height);
225}
226
227void wxTopLevelWindow::DoSetClientSize(int width, int height)
228{
229 if ( ms_drawDecorations )
230 {
7ee7c43f 231 wxSize size = m_renderer->GetFrameTotalSize(wxSize(width, height),
24a23c35
VS
232 GetDecorationsStyle());
233 wxTopLevelWindowNative::DoSetClientSize(size.x, size.y);
234 }
235 else
236 wxTopLevelWindowNative::DoSetClientSize(width, height);
237}
238
239void wxTopLevelWindow::OnNcPaint(wxPaintEvent& event)
240{
241 if ( !ms_drawDecorations || !m_renderer )
242 event.Skip();
243 else
244 {
245 // get the window rect
246 wxRect rect;
247 wxSize size = GetSize();
248 rect.x =
249 rect.y = 0;
250 rect.width = size.x;
251 rect.height = size.y;
252
253 wxWindowDC dc(this);
7ee7c43f 254 m_renderer->DrawFrameTitleBar(dc, rect,
24a23c35 255 GetTitle(), m_titlebarIcon,
813edf09
VS
256 GetDecorationsStyle(),
257 m_pressedButton,
258 wxCONTROL_PRESSED);
24a23c35
VS
259 }
260}
261
813edf09
VS
262long wxTopLevelWindow::HitTest(const wxPoint& pt) const
263{
264 int w, h;
265 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
266 wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
7ee7c43f 267
badc44fe 268 return m_renderer->HitTestFrame(rect, pt+GetClientAreaOrigin(), GetDecorationsStyle());
813edf09
VS
269}
270
24a23c35
VS
271// ----------------------------------------------------------------------------
272// icons
273// ----------------------------------------------------------------------------
274
275void wxTopLevelWindow::SetIcon(const wxIcon& icon)
276{
277 wxTopLevelWindowNative::SetIcon(icon);
24a23c35 278
15678bec 279 if ( ms_drawDecorations && m_renderer )
24a23c35 280 {
15678bec
VS
281 wxSize size = m_renderer->GetFrameIconSize();
282
283 if ( !icon.Ok() || size.x == -1 )
24a23c35
VS
284 m_titlebarIcon = icon;
285 else
286 {
15678bec
VS
287 wxBitmap bmp1;
288 bmp1.CopyFromIcon(icon);
289 if ( !bmp1.Ok() )
290 m_titlebarIcon = wxNullIcon;
291 else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
292 m_titlebarIcon = icon;
293 else
294 {
295 wxImage img = bmp1.ConvertToImage();
296 img.Rescale(size.x, size.y);
297 m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
298 }
24a23c35
VS
299 }
300 }
301}
ea1b0d6c
VS
302
303// ----------------------------------------------------------------------------
304// actions
305// ----------------------------------------------------------------------------
306
813edf09
VS
307void wxTopLevelWindow::ClickTitleBarButton(long button)
308{
309 switch ( button )
310 {
311 case wxTOPLEVEL_BUTTON_CLOSE:
312 Close();
313 break;
314
315 case wxTOPLEVEL_BUTTON_ICONIZE:
316 Iconize();
317 break;
318
319 case wxTOPLEVEL_BUTTON_MAXIMIZE:
320 Maximize();
321 break;
322
323 case wxTOPLEVEL_BUTTON_RESTORE:
324 Restore();
325 break;
326
327 case wxTOPLEVEL_BUTTON_HELP:
328#if wxUSE_HELP
329 {
330 wxContextHelp contextHelp(this);
331 }
332#endif
333 break;
7ee7c43f 334
813edf09
VS
335 default:
336 wxFAIL_MSG(wxT("incorrect button specification"));
337 }
338}
339
ea1b0d6c
VS
340bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
341 long numArg,
342 const wxString& strArg)
343{
7ee7c43f
VZ
344 bool isActive = numArg != 0;
345
ea1b0d6c
VS
346 if ( action == wxACTION_TOPLEVEL_ACTIVATE )
347 {
7ee7c43f 348 if ( m_isActive != isActive )
ea1b0d6c 349 {
7ee7c43f 350 m_isActive = isActive;
b22d16ad 351 RefreshTitleBar();
ea1b0d6c
VS
352 }
353 return TRUE;
354 }
7ee7c43f 355
813edf09
VS
356 else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
357 {
358 m_pressedButton = numArg;
359 RefreshTitleBar();
360 return TRUE;
361 }
7ee7c43f 362
813edf09
VS
363 else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
364 {
365 m_pressedButton = 0;
366 RefreshTitleBar();
367 return TRUE;
368 }
7ee7c43f 369
813edf09
VS
370 else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
371 {
372 m_pressedButton = 0;
373 RefreshTitleBar();
374 ClickTitleBarButton(numArg);
375 return TRUE;
376 }
71e03035 377
b22d16ad
VS
378 else if ( action == wxACTION_TOPLEVEL_MOVE )
379 {
380 InteractiveMove(wxINTERACTIVE_MOVE);
381 return TRUE;
382 }
71e03035 383
b22d16ad
VS
384 else if ( action == wxACTION_TOPLEVEL_RESIZE )
385 {
386 int flags = wxINTERACTIVE_RESIZE;
387 if ( numArg & wxHT_TOPLEVEL_BORDER_N )
388 flags |= wxINTERACTIVE_RESIZE_N;
389 if ( numArg & wxHT_TOPLEVEL_BORDER_S )
390 flags |= wxINTERACTIVE_RESIZE_S;
391 if ( numArg & wxHT_TOPLEVEL_BORDER_W )
392 flags |= wxINTERACTIVE_RESIZE_W;
393 if ( numArg & wxHT_TOPLEVEL_BORDER_E )
394 flags |= wxINTERACTIVE_RESIZE_E;
395 InteractiveMove(flags);
396 return TRUE;
397 }
71e03035 398
ea1b0d6c
VS
399 else
400 return FALSE;
401}
402
403
404// ============================================================================
405// wxStdFrameInputHandler: handles focus, resizing and titlebar buttons clicks
406// ============================================================================
407
408wxStdFrameInputHandler::wxStdFrameInputHandler(wxInputHandler *inphand)
409 : wxStdInputHandler(inphand)
410{
813edf09
VS
411 m_winCapture = NULL;
412 m_winHitTest = 0;
413 m_winPressed = 0;
b22d16ad 414 m_borderCursorOn = FALSE;
ea1b0d6c
VS
415}
416
417bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
418 const wxMouseEvent& event)
419{
813edf09
VS
420 // the button has 2 states: pressed and normal with the following
421 // transitions between them:
422 //
423 // normal -> left down -> capture mouse and go to pressed state
424 // pressed -> left up inside -> generate click -> go to normal
425 // outside ------------------>
426 //
427 // the other mouse buttons are ignored
428 if ( event.Button(1) )
429 {
430 if ( event.ButtonDown(1) )
431 {
432 wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
433 long hit = w->HitTest(event.GetPosition());
7ee7c43f 434
813edf09
VS
435 if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
436 {
437 m_winCapture = w;
438 m_winCapture->CaptureMouse();
439 m_winHitTest = hit;
440 m_winPressed = hit;
441 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
442 return TRUE;
443 }
b22d16ad
VS
444 else if ( hit & wxHT_TOPLEVEL_TITLEBAR )
445 {
446 consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
447 return TRUE;
448 }
449 else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
450 && (hit & wxHT_TOPLEVEL_ANY_BORDER) )
451 {
452 consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
453 return TRUE;
454 }
813edf09
VS
455 }
456
457 else // up
458 {
459 if ( m_winCapture )
460 {
461 m_winCapture->ReleaseMouse();
462 m_winCapture = NULL;
463
464 if ( m_winHitTest == m_winPressed )
465 {
466 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
467 return TRUE;
468 }
469 }
470 //else: the mouse was released outside the window, this doesn't
471 // count as a click
472 }
473 }
474
ea1b0d6c
VS
475 return wxStdInputHandler::HandleMouse(consumer, event);
476}
477
7ee7c43f 478bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
ea1b0d6c
VS
479 const wxMouseEvent& event)
480{
813edf09
VS
481 if ( event.GetEventObject() == m_winCapture )
482 {
483 long hit = m_winCapture->HitTest(event.GetPosition());
484
485 if ( hit != m_winHitTest )
486 {
487 if ( hit != m_winPressed )
488 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
489 else
490 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
7ee7c43f 491
813edf09
VS
492 m_winHitTest = hit;
493 return TRUE;
494 }
495 }
b22d16ad
VS
496 else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
497 {
71e03035 498 wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
b22d16ad
VS
499 wxTopLevelWindow);
500 long hit = win->HitTest(event.GetPosition());
71e03035 501
b22d16ad
VS
502 if ( hit != m_winHitTest )
503 {
504 m_winHitTest = hit;
71e03035 505
b22d16ad
VS
506 if ( m_borderCursorOn )
507 {
508 m_borderCursorOn = FALSE;
509 win->SetCursor(m_origCursor);
510 }
71e03035 511
b22d16ad
VS
512 if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
513 {
514 m_borderCursorOn = TRUE;
515 wxCursor cur;
71e03035 516
b22d16ad
VS
517 switch (hit)
518 {
519 case wxHT_TOPLEVEL_BORDER_N:
520 case wxHT_TOPLEVEL_BORDER_S:
521 cur = wxCursor(wxCURSOR_SIZENS);
522 break;
523 case wxHT_TOPLEVEL_BORDER_W:
524 case wxHT_TOPLEVEL_BORDER_E:
525 cur = wxCursor(wxCURSOR_SIZEWE);
526 break;
527 case wxHT_TOPLEVEL_BORDER_NE:
528 case wxHT_TOPLEVEL_BORDER_SW:
529 cur = wxCursor(wxCURSOR_SIZENESW);
530 break;
531 case wxHT_TOPLEVEL_BORDER_NW:
532 case wxHT_TOPLEVEL_BORDER_SE:
533 cur = wxCursor(wxCURSOR_SIZENWSE);
534 break;
535 default:
536 m_borderCursorOn = FALSE;
537 break;
538 }
539 if ( m_borderCursorOn )
540 {
541 m_origCursor = win->GetCursor();
542 win->SetCursor(cur);
543 }
544 }
545 }
546 }
813edf09 547
ea1b0d6c
VS
548 return wxStdInputHandler::HandleMouseMove(consumer, event);
549}
550
7ee7c43f 551bool wxStdFrameInputHandler::HandleActivation(wxInputConsumer *consumer,
ea1b0d6c
VS
552 bool activated)
553{
b22d16ad
VS
554 if ( m_borderCursorOn )
555 {
556 consumer->GetInputWindow()->SetCursor(m_origCursor);
557 m_borderCursorOn = FALSE;
558 }
ea1b0d6c
VS
559 consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
560 return FALSE;
561}