]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/toplevel.cpp
Committing in .
[wxWidgets.git] / src / gtk / 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 (HasFlag(wxFRAME_FLOAT_ON_PARENT) || (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 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
642 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
643 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
644 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
645
646 if ((m_x != -1) || (m_y != -1))
647 {
648 if ((m_x != old_x) || (m_y != old_y))
649 {
650 gtk_widget_set_uposition( m_widget, m_x, m_y );
651 }
652 }
653
654 if ((m_width != old_width) || (m_height != old_height))
655 {
656 if (m_widget->window)
657 gdk_window_resize( m_widget->window, m_width, m_height );
658 else
659 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
660
661 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
662 done either directly before the frame is shown or in idle time
663 so that different calls to SetSize() don't lead to flicker. */
664 m_sizeSet = FALSE;
665 }
666
667 m_resizing = FALSE;
668 }
669
670 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
671 {
672 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
673
674 wxWindow::DoGetClientSize( width, height );
675 if (height)
676 {
677 // mini edge
678 *height -= m_miniEdge*2 + m_miniTitle;
679 }
680 if (width)
681 {
682 *width -= m_miniEdge*2;
683 }
684 }
685
686 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
687 {
688 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
689
690 DoSetSize(-1, -1,
691 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
692 }
693
694 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
695 int width, int height )
696 {
697 // due to a bug in gtk, x,y are always 0
698 // m_x = x;
699 // m_y = y;
700
701 // avoid recursions
702 if (m_resizing) return;
703 m_resizing = TRUE;
704
705 if ( m_wxwindow == NULL ) return;
706
707 m_width = width;
708 m_height = height;
709
710 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
711 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
712 set in wxFrame::Create so it is used to check what kind of frame we
713 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
714 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
715 importantly) m_mainWidget */
716
717 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
718 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
719 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
720 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
721
722 if (m_mainWidget)
723 {
724 // set size hints
725 gint flag = 0; // GDK_HINT_POS;
726 if ((m_minWidth != -1) || (m_minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
727 if ((m_maxWidth != -1) || (m_maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
728 GdkGeometry geom;
729 geom.min_width = m_minWidth;
730 geom.min_height = m_minHeight;
731 geom.max_width = m_maxWidth;
732 geom.max_height = m_maxHeight;
733 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
734 (GtkWidget*) NULL,
735 &geom,
736 (GdkWindowHints) flag );
737
738 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
739 * menubar, the toolbar and the client area, which is represented by
740 * m_wxwindow.
741 * this hurts in the eye, but I don't want to call SetSize()
742 * because I don't want to call any non-native functions here. */
743
744 int client_x = m_miniEdge;
745 int client_y = m_miniEdge + m_miniTitle;
746 int client_w = m_width - 2*m_miniEdge;
747 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
748 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
749 m_wxwindow,
750 client_x, client_y, client_w, client_h );
751 }
752 else
753 {
754 // If there is no m_mainWidget between m_widget and m_wxwindow there
755 // is no need to set the size or position of m_wxwindow.
756 }
757
758 m_sizeSet = TRUE;
759
760 // send size event to frame
761 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
762 event.SetEventObject( this );
763 GetEventHandler()->ProcessEvent( event );
764
765 m_resizing = FALSE;
766 }
767
768 void wxTopLevelWindowGTK::OnInternalIdle()
769 {
770 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
771 {
772 GtkOnSize( m_x, m_y, m_width, m_height );
773
774 // we'll come back later
775 if (g_isIdle)
776 wxapp_install_idle_handler();
777 return;
778 }
779
780 wxWindow::OnInternalIdle();
781 }
782
783
784 // ----------------------------------------------------------------------------
785 // frame title/icon
786 // ----------------------------------------------------------------------------
787
788 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
789 {
790 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
791
792 m_title = title;
793 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
794 }
795
796 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
797 {
798 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
799
800 wxTopLevelWindowBase::SetIcon(icon);
801
802 if ( !m_icon.Ok() )
803 return;
804
805 if (!m_widget->window)
806 return;
807
808 wxMask *mask = icon.GetMask();
809 GdkBitmap *bm = (GdkBitmap *) NULL;
810 if (mask) bm = mask->GetBitmap();
811
812 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
813 }
814
815 // ----------------------------------------------------------------------------
816 // frame state: maximized/iconized/normal
817 // ----------------------------------------------------------------------------
818
819 void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize))
820 {
821 wxFAIL_MSG( _T("not implemented") );
822 }
823
824 bool wxTopLevelWindowGTK::IsMaximized() const
825 {
826 // wxFAIL_MSG( _T("not implemented") );
827
828 // This is an approximation
829 return FALSE;
830 }
831
832 void wxTopLevelWindowGTK::Restore()
833 {
834 wxFAIL_MSG( _T("not implemented") );
835 }
836
837 void wxTopLevelWindowGTK::Iconize( bool iconize )
838 {
839 if (iconize)
840 {
841 GdkWindow *window = m_widget->window;
842
843 // you should do it later, for example from OnCreate() handler
844 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
845
846 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
847 GDK_WINDOW_XWINDOW( window ),
848 DefaultScreen( GDK_DISPLAY() ) );
849 }
850 }
851
852 bool wxTopLevelWindowGTK::IsIconized() const
853 {
854 return m_isIconized;
855 }
856
857 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
858 {
859 if ( iconize != m_isIconized )
860 {
861 m_isIconized = iconize;
862 (void)SendIconizeEvent(iconize);
863 }
864 }
865