respect minimal wxTLW size in wxUniv
[wxWidgets.git] / src / gtk1 / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: toplevel.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #ifdef __GNUG__
19 #pragma implementation "toplevel.h"
20 #endif
21
22 #ifdef __VMS
23 #define XIconifyWindow XICONIFYWINDOW
24 #endif
25
26 #include "wx/defs.h"
27
28 #include "wx/dialog.h"
29 #include "wx/control.h"
30 #include "wx/app.h"
31 #include "wx/dcclient.h"
32
33 #include <glib.h>
34 #include <gdk/gdk.h>
35 #include <gtk/gtk.h>
36 #include <gdk/gdkkeysyms.h>
37 #include <gdk/gdkx.h>
38
39 #include "wx/gtk/win_gtk.h"
40
41 // ----------------------------------------------------------------------------
42 // idle system
43 // ----------------------------------------------------------------------------
44
45 extern void wxapp_install_idle_handler();
46 extern bool g_isIdle;
47 extern int g_openDialogs;
48
49 // ----------------------------------------------------------------------------
50 // event tables
51 // ----------------------------------------------------------------------------
52
53 // ----------------------------------------------------------------------------
54 // data
55 // ----------------------------------------------------------------------------
56
57 extern wxList wxPendingDelete;
58
59 // ----------------------------------------------------------------------------
60 // debug
61 // ----------------------------------------------------------------------------
62
63 #ifdef __WXDEBUG__
64
65 extern void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window );
66
67 #endif
68
69 // ============================================================================
70 // implementation
71 // ============================================================================
72
73 // ----------------------------------------------------------------------------
74 // GTK callbacks
75 // ----------------------------------------------------------------------------
76
77 //-----------------------------------------------------------------------------
78 // "focus" from m_window
79 //-----------------------------------------------------------------------------
80
81 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
82 {
83 if (g_isIdle)
84 wxapp_install_idle_handler();
85
86 // This disables GTK's tab traversal
87 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
88 return TRUE;
89 }
90
91 //-----------------------------------------------------------------------------
92 // "size_allocate"
93 //-----------------------------------------------------------------------------
94
95 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
96 {
97 if (g_isIdle)
98 wxapp_install_idle_handler();
99
100 if (!win->m_hasVMT)
101 return;
102
103 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
104 {
105 /*
106 wxPrintf( "OnSize from " );
107 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
108 wxPrintf( win->GetClassInfo()->GetClassName() );
109 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
110 (int)alloc->y,
111 (int)alloc->width,
112 (int)alloc->height );
113 */
114
115 win->m_width = alloc->width;
116 win->m_height = alloc->height;
117 win->m_queuedFullRedraw = TRUE;
118 win->GtkUpdateSize();
119 }
120 }
121
122 //-----------------------------------------------------------------------------
123 // "delete_event"
124 //-----------------------------------------------------------------------------
125
126 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxTopLevelWindowGTK *win )
127 {
128 if (g_isIdle)
129 wxapp_install_idle_handler();
130
131 if (win->IsEnabled() &&
132 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)))
133 win->Close();
134
135 return TRUE;
136 }
137
138
139 //-----------------------------------------------------------------------------
140 // "configure_event"
141 //-----------------------------------------------------------------------------
142
143 static gint
144 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxTopLevelWindowGTK *win )
145 {
146 if (g_isIdle)
147 wxapp_install_idle_handler();
148
149 if (!win->m_hasVMT || !win->IsShown())
150 return FALSE;
151
152 int x = 0;
153 int y = 0;
154 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
155 win->m_x = x;
156 win->m_y = y;
157
158 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
159 mevent.SetEventObject( win );
160 win->GetEventHandler()->ProcessEvent( mevent );
161
162 return FALSE;
163 }
164
165 //-----------------------------------------------------------------------------
166 // "realize" from m_widget
167 //-----------------------------------------------------------------------------
168
169 // we cannot MWM hints and icons before the widget has been realized,
170 // so we do this directly after realization
171
172 static void
173 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget), wxTopLevelWindowGTK *win )
174 {
175 if (g_isIdle)
176 wxapp_install_idle_handler();
177
178 // All this is for Motif Window Manager "hints" and is supposed to be
179 // recognized by other WM as well. Not tested.
180 gdk_window_set_decorations(win->m_widget->window,
181 (GdkWMDecoration)win->m_gdkDecor);
182 gdk_window_set_functions(win->m_widget->window,
183 (GdkWMFunction)win->m_gdkFunc);
184
185 // GTK's shrinking/growing policy
186 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
187 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
188 else
189 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
190
191 // reset the icon
192 wxIcon iconOld = win->GetIcon();
193 if ( iconOld != wxNullIcon )
194 {
195 wxIcon icon( iconOld );
196 win->SetIcon( wxNullIcon );
197 win->SetIcon( icon );
198 }
199
200 // we set the focus to the child that accepts the focus. this
201 // doesn't really have to be done in "realize" but why not?
202 wxWindowList::Node *node = win->GetChildren().GetFirst();
203 while (node)
204 {
205 wxWindow *child = node->GetData();
206 if (child->AcceptsFocus())
207 {
208 child->SetFocus();
209 break;
210 }
211
212 node = node->GetNext();
213 }
214 }
215
216 //-----------------------------------------------------------------------------
217 // "map_event" from m_widget
218 //-----------------------------------------------------------------------------
219
220 static void
221 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
222 GdkEvent * WXUNUSED(event),
223 wxTopLevelWindow *win )
224 {
225 win->SetIconizeState(FALSE);
226 }
227
228 //-----------------------------------------------------------------------------
229 // "unmap_event" from m_widget
230 //-----------------------------------------------------------------------------
231
232 static void
233 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
234 GdkEvent * WXUNUSED(event),
235 wxTopLevelWindow *win )
236 {
237 win->SetIconizeState(TRUE);
238 }
239
240 //-----------------------------------------------------------------------------
241 // "expose_event" of m_client
242 //-----------------------------------------------------------------------------
243
244 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
245 {
246 GtkPizza *pizza = GTK_PIZZA(widget);
247
248 gtk_paint_flat_box (win->m_widget->style,
249 pizza->bin_window, GTK_STATE_NORMAL,
250 GTK_SHADOW_NONE,
251 &gdk_event->area,
252 win->m_widget,
253 (char *)"base",
254 0, 0, -1, -1);
255
256 return TRUE;
257 }
258
259 //-----------------------------------------------------------------------------
260 // "draw" of m_client
261 //-----------------------------------------------------------------------------
262
263
264 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
265 {
266 GtkPizza *pizza = GTK_PIZZA(widget);
267
268 gtk_paint_flat_box (win->m_widget->style,
269 pizza->bin_window, GTK_STATE_NORMAL,
270 GTK_SHADOW_NONE,
271 rect,
272 win->m_widget,
273 (char *)"base",
274 0, 0, -1, -1);
275 }
276
277 // ----------------------------------------------------------------------------
278 // wxTopLevelWindowGTK itself
279 // ----------------------------------------------------------------------------
280
281 //-----------------------------------------------------------------------------
282 // InsertChild for wxTopLevelWindowGTK
283 //-----------------------------------------------------------------------------
284
285 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
286 * C++ has no virtual methods in a constructor. We have to emulate a
287 * virtual function here as wxWindows requires different ways to insert
288 * a child in container classes. */
289
290 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
291 {
292 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
293
294 if (!parent->m_insertInClientArea)
295 {
296 // these are outside the client area
297 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
298 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
299 GTK_WIDGET(child->m_widget),
300 child->m_x,
301 child->m_y,
302 child->m_width,
303 child->m_height );
304 }
305 else
306 {
307 // these are inside the client area
308 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
309 GTK_WIDGET(child->m_widget),
310 child->m_x,
311 child->m_y,
312 child->m_width,
313 child->m_height );
314 }
315
316 // resize on OnInternalIdle
317 parent->GtkUpdateSize();
318 }
319
320 // ----------------------------------------------------------------------------
321 // wxTopLevelWindowGTK creation
322 // ----------------------------------------------------------------------------
323
324 void wxTopLevelWindowGTK::Init()
325 {
326 m_sizeSet = FALSE;
327 m_miniEdge = 0;
328 m_miniTitle = 0;
329 m_mainWidget = (GtkWidget*) NULL;
330 m_insertInClientArea = TRUE;
331 m_isFrame = TRUE;
332 m_isIconized = FALSE;
333 m_fsIsShowing = FALSE;
334 m_themeEnabled = TRUE;
335 m_gdkDecor = m_gdkFunc = 0;
336 }
337
338 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
339 wxWindowID id,
340 const wxString& title,
341 const wxPoint& pos,
342 const wxSize& sizeOrig,
343 long style,
344 const wxString &name )
345 {
346 // always create a frame of some reasonable, even if arbitrary, size (at
347 // least for MSW compatibility)
348 wxSize size = sizeOrig;
349 if ( size.x == -1 || size.y == -1 )
350 {
351 wxSize sizeDpy = wxGetDisplaySize();
352 if ( size.x == -1 )
353 size.x = sizeDpy.x / 3;
354 if ( size.y == -1 )
355 size.y = sizeDpy.y / 5;
356 }
357
358 wxTopLevelWindows.Append( this );
359
360 m_needParent = FALSE;
361
362 if (!PreCreation( parent, pos, size ) ||
363 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
364 {
365 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
366 return FALSE;
367 }
368
369 m_title = title;
370
371 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
372
373 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
374
375 if (style & wxFRAME_TOOL_WINDOW)
376 win_type = GTK_WINDOW_POPUP;
377
378 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
379 win_type = GTK_WINDOW_DIALOG;
380
381 m_widget = gtk_window_new( win_type );
382
383 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)) &&
384 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG))
385 {
386 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
387 }
388
389 if (!name.IsEmpty())
390 gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() );
391
392 #ifdef __WXDEBUG__
393 debug_focus_in( m_widget, wxT("wxTopLevelWindowGTK::m_widget"), name );
394 #endif
395
396 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
397 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
398
399 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
400 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
401
402 // m_mainWidget holds the toolbar, the menubar and the client area
403 m_mainWidget = gtk_pizza_new();
404 gtk_widget_show( m_mainWidget );
405 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
406 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
407
408 // for m_mainWidget themes
409 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
410 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
411 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
412 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
413
414 #ifdef __WXDEBUG__
415 debug_focus_in( m_mainWidget, wxT("wxTopLevelWindowGTK::m_mainWidget"), name );
416 #endif
417
418 // m_wxwindow only represents the client area without toolbar and menubar
419 m_wxwindow = gtk_pizza_new();
420 gtk_widget_show( m_wxwindow );
421 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
422
423 #ifdef __WXDEBUG__
424 debug_focus_in( m_wxwindow, wxT("wxTopLevelWindowGTK::m_wxwindow"), name );
425 #endif
426
427 // we donm't allow the frame to get the focus as otherwise
428 // the frame will grab it at arbitrary focus changes
429 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
430
431 if (m_parent) m_parent->AddChild( this );
432
433 // the user resized the frame by dragging etc.
434 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
435 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
436
437 PostCreation();
438
439 if ((m_x != -1) || (m_y != -1))
440 gtk_widget_set_uposition( m_widget, m_x, m_y );
441
442 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
443
444 // we cannot set MWM hints and icons before the widget has
445 // been realized, so we do this directly after realization
446 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
447 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
448
449 // the only way to get the window size is to connect to this event
450 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
451 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
452
453 // map and unmap for iconized state
454 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
455 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
456 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
457 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
458
459 // the only way to get the window size is to connect to this event
460 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
461 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
462
463 // disable native tab traversal
464 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
465 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
466
467 // decorations
468 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
469 {
470 m_gdkDecor = 0;
471 m_gdkFunc = 0;
472 }
473 else
474 {
475 m_gdkDecor = (long) GDK_DECOR_BORDER;
476 m_gdkFunc = (long) GDK_FUNC_MOVE;
477
478 // All this is for Motif Window Manager "hints" and is supposed to be
479 // recognized by other WMs as well.
480 if ((style & wxCAPTION) != 0)
481 m_gdkDecor |= GDK_DECOR_TITLE;
482 if ((style & wxSYSTEM_MENU) != 0)
483 {
484 m_gdkFunc |= GDK_FUNC_CLOSE;
485 m_gdkDecor |= GDK_DECOR_MENU;
486 }
487 if ((style & wxMINIMIZE_BOX) != 0)
488 {
489 m_gdkFunc |= GDK_FUNC_MINIMIZE;
490 m_gdkDecor |= GDK_DECOR_MINIMIZE;
491 }
492 if ((style & wxMAXIMIZE_BOX) != 0)
493 {
494 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
495 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
496 }
497 if ((style & wxRESIZE_BORDER) != 0)
498 {
499 m_gdkFunc |= GDK_FUNC_RESIZE;
500 m_gdkDecor |= GDK_DECOR_RESIZEH;
501 }
502 }
503
504 return TRUE;
505 }
506
507 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
508 {
509 m_isBeingDeleted = TRUE;
510
511 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
512
513 wxTopLevelWindows.DeleteObject( this );
514
515 if (wxTheApp->GetTopWindow() == this)
516 wxTheApp->SetTopWindow( (wxWindow*) NULL );
517
518 if ((wxTopLevelWindows.Number() == 0) &&
519 (wxTheApp->GetExitOnFrameDelete()))
520 {
521 wxTheApp->ExitMainLoop();
522 }
523 }
524
525 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
526 {
527 if (show == m_fsIsShowing) return FALSE; // return what?
528
529 m_fsIsShowing = show;
530
531 if (show)
532 {
533 m_fsSaveGdkFunc = m_gdkFunc;
534 m_fsSaveGdkDecor = m_gdkDecor;
535 m_fsSaveFlag = style;
536 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
537 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
538
539 gtk_widget_hide( m_widget );
540 gtk_widget_unrealize( m_widget );
541
542 m_gdkDecor = (long) GDK_DECOR_BORDER;
543 m_gdkFunc = (long) GDK_FUNC_MOVE;
544
545 int x;
546 int y;
547 wxDisplaySize( &x, &y );
548 SetSize( 0, 0, x, y );
549
550 gtk_widget_realize( m_widget );
551 gtk_widget_show( m_widget );
552 }
553 else
554 {
555 gtk_widget_hide( m_widget );
556 gtk_widget_unrealize( m_widget );
557
558 m_gdkFunc = m_fsSaveGdkFunc;
559 m_gdkDecor = m_fsSaveGdkDecor;
560
561 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
562
563 gtk_widget_realize( m_widget );
564 gtk_widget_show( m_widget );
565 }
566
567 return TRUE;
568 }
569
570 // ----------------------------------------------------------------------------
571 // overridden wxWindow methods
572 // ----------------------------------------------------------------------------
573
574 bool wxTopLevelWindowGTK::Show( bool show )
575 {
576 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
577
578 if (show && !m_sizeSet)
579 {
580 /* by calling GtkOnSize here, we don't have to call
581 either after showing the frame, which would entail
582 much ugly flicker or from within the size_allocate
583 handler, because GTK 1.1.X forbids that. */
584
585 GtkOnSize( m_x, m_y, m_width, m_height );
586 }
587
588 return wxWindow::Show( show );
589 }
590
591 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
592 {
593 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
594 }
595
596 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
597 {
598 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
599
600 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
601 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
602
603 // avoid recursions
604 if (m_resizing)
605 return;
606 m_resizing = TRUE;
607
608 int old_x = m_x;
609 int old_y = m_y;
610
611 int old_width = m_width;
612 int old_height = m_height;
613
614 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
615 {
616 if (x != -1) m_x = x;
617 if (y != -1) m_y = y;
618 if (width != -1) m_width = width;
619 if (height != -1) m_height = height;
620 }
621 else
622 {
623 m_x = x;
624 m_y = y;
625 m_width = width;
626 m_height = height;
627 }
628
629 /*
630 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
631 {
632 if (width == -1) m_width = 80;
633 }
634
635 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
636 {
637 if (height == -1) m_height = 26;
638 }
639 */
640
641 int minWidth = GetMinWidth(),
642 minHeight = GetMinHeight(),
643 maxWidth = GetMaxWidth(),
644 maxHeight = GetMaxHeight();
645
646 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
647 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
648 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
649 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
650
651 if ((m_x != -1) || (m_y != -1))
652 {
653 if ((m_x != old_x) || (m_y != old_y))
654 {
655 gtk_widget_set_uposition( m_widget, m_x, m_y );
656 }
657 }
658
659 if ((m_width != old_width) || (m_height != old_height))
660 {
661 if (m_widget->window)
662 gdk_window_resize( m_widget->window, m_width, m_height );
663 else
664 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
665
666 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
667 done either directly before the frame is shown or in idle time
668 so that different calls to SetSize() don't lead to flicker. */
669 m_sizeSet = FALSE;
670 }
671
672 m_resizing = FALSE;
673 }
674
675 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
676 {
677 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
678
679 wxWindow::DoGetClientSize( width, height );
680 if (height)
681 {
682 // mini edge
683 *height -= m_miniEdge*2 + m_miniTitle;
684 }
685 if (width)
686 {
687 *width -= m_miniEdge*2;
688 }
689 }
690
691 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
692 {
693 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
694
695 DoSetSize(-1, -1,
696 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
697 }
698
699 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
700 int width, int height )
701 {
702 // due to a bug in gtk, x,y are always 0
703 // m_x = x;
704 // m_y = y;
705
706 // avoid recursions
707 if (m_resizing) return;
708 m_resizing = TRUE;
709
710 if ( m_wxwindow == NULL ) return;
711
712 m_width = width;
713 m_height = height;
714
715 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
716 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
717 set in wxFrame::Create so it is used to check what kind of frame we
718 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
719 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
720 importantly) m_mainWidget */
721
722 int minWidth = GetMinWidth(),
723 minHeight = GetMinHeight(),
724 maxWidth = GetMaxWidth(),
725 maxHeight = GetMaxHeight();
726
727 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
728 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
729 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
730 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
731
732 if (m_mainWidget)
733 {
734 // set size hints
735 gint flag = 0; // GDK_HINT_POS;
736 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
737 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
738 GdkGeometry geom;
739 geom.min_width = minWidth;
740 geom.min_height = minHeight;
741 geom.max_width = maxWidth;
742 geom.max_height = maxHeight;
743 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
744 (GtkWidget*) NULL,
745 &geom,
746 (GdkWindowHints) flag );
747
748 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
749 * menubar, the toolbar and the client area, which is represented by
750 * m_wxwindow.
751 * this hurts in the eye, but I don't want to call SetSize()
752 * because I don't want to call any non-native functions here. */
753
754 int client_x = m_miniEdge;
755 int client_y = m_miniEdge + m_miniTitle;
756 int client_w = m_width - 2*m_miniEdge;
757 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
758 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
759 m_wxwindow,
760 client_x, client_y, client_w, client_h );
761 }
762 else
763 {
764 // If there is no m_mainWidget between m_widget and m_wxwindow there
765 // is no need to set the size or position of m_wxwindow.
766 }
767
768 m_sizeSet = TRUE;
769
770 // send size event to frame
771 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
772 event.SetEventObject( this );
773 GetEventHandler()->ProcessEvent( event );
774
775 m_resizing = FALSE;
776 }
777
778 void wxTopLevelWindowGTK::OnInternalIdle()
779 {
780 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
781 {
782 GtkOnSize( m_x, m_y, m_width, m_height );
783
784 // we'll come back later
785 if (g_isIdle)
786 wxapp_install_idle_handler();
787 return;
788 }
789
790 wxWindow::OnInternalIdle();
791 }
792
793
794 // ----------------------------------------------------------------------------
795 // frame title/icon
796 // ----------------------------------------------------------------------------
797
798 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
799 {
800 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
801
802 m_title = title;
803 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
804 }
805
806 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
807 {
808 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
809
810 wxTopLevelWindowBase::SetIcon(icon);
811
812 if ( !m_icon.Ok() )
813 return;
814
815 if (!m_widget->window)
816 return;
817
818 wxMask *mask = icon.GetMask();
819 GdkBitmap *bm = (GdkBitmap *) NULL;
820 if (mask) bm = mask->GetBitmap();
821
822 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
823 }
824
825 // ----------------------------------------------------------------------------
826 // frame state: maximized/iconized/normal
827 // ----------------------------------------------------------------------------
828
829 void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize))
830 {
831 wxFAIL_MSG( _T("not implemented") );
832 }
833
834 bool wxTopLevelWindowGTK::IsMaximized() const
835 {
836 // wxFAIL_MSG( _T("not implemented") );
837
838 // This is an approximation
839 return FALSE;
840 }
841
842 void wxTopLevelWindowGTK::Restore()
843 {
844 wxFAIL_MSG( _T("not implemented") );
845 }
846
847 void wxTopLevelWindowGTK::Iconize( bool iconize )
848 {
849 if (iconize)
850 {
851 GdkWindow *window = m_widget->window;
852
853 // you should do it later, for example from OnCreate() handler
854 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
855
856 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
857 GDK_WINDOW_XWINDOW( window ),
858 DefaultScreen( GDK_DISPLAY() ) );
859 }
860 }
861
862 bool wxTopLevelWindowGTK::IsIconized() const
863 {
864 return m_isIconized;
865 }
866
867 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
868 {
869 if ( iconize != m_isIconized )
870 {
871 m_isIconized = iconize;
872 (void)SendIconizeEvent(iconize);
873 }
874 }
875