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