]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/toplevel.cpp
partial implementation of wxTLW's decorations
[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 #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() & wxTOPLEVEL_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 /* All this is for Motif Window Manager "hints" and is supposed to be
192 recognized by other WM as well. Not tested. */
193 gdk_window_set_decorations(win->m_widget->window,
194 (GdkWMDecoration)win->m_gdkDecor);
195 gdk_window_set_functions(win->m_widget->window,
196 (GdkWMFunction)win->m_gdkFunc);
197
198 /* GTK's shrinking/growing policy */
199 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
200 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
201 else
202 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
203
204 /* reset the icon */
205 wxIcon iconOld = win->GetIcon();
206 if ( iconOld != wxNullIcon )
207 {
208 wxIcon icon( iconOld );
209 win->SetIcon( wxNullIcon );
210 win->SetIcon( icon );
211 }
212
213 /* we set the focus to the child that accepts the focus. this
214 doesn't really have to be done in "realize" but why not? */
215 wxWindowList::Node *node = win->GetChildren().GetFirst();
216 while (node)
217 {
218 wxWindow *child = node->GetData();
219 if (child->AcceptsFocus())
220 {
221 child->SetFocus();
222 break;
223 }
224
225 node = node->GetNext();
226 }
227 }
228
229 //-----------------------------------------------------------------------------
230 // "map_event" from m_widget
231 //-----------------------------------------------------------------------------
232
233 static void
234 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
235 GdkEvent * WXUNUSED(event),
236 wxTopLevelWindow *win )
237 {
238 win->SetIconizeState(FALSE);
239 }
240
241 //-----------------------------------------------------------------------------
242 // "unmap_event" from m_widget
243 //-----------------------------------------------------------------------------
244
245 static void
246 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
247 GdkEvent * WXUNUSED(event),
248 wxTopLevelWindow *win )
249 {
250 win->SetIconizeState(TRUE);
251 }
252
253 //-----------------------------------------------------------------------------
254 // "expose_event" of m_client
255 //-----------------------------------------------------------------------------
256
257 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
258 {
259 GtkPizza *pizza = GTK_PIZZA(widget);
260
261 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
262 GTK_SHADOW_NONE, &gdk_event->area, win->m_widget, "base", 0, 0, -1, -1);
263
264 return TRUE;
265 }
266
267 //-----------------------------------------------------------------------------
268 // "draw" of m_client
269 //-----------------------------------------------------------------------------
270
271
272 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
273 {
274 GtkPizza *pizza = GTK_PIZZA(widget);
275
276 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
277 GTK_SHADOW_NONE, rect, win->m_widget, "base", 0, 0, -1, -1);
278 }
279
280 // ----------------------------------------------------------------------------
281 // wxTopLevelWindowGTK itself
282 // ----------------------------------------------------------------------------
283
284 //-----------------------------------------------------------------------------
285 // InsertChild for wxTopLevelWindowGTK
286 //-----------------------------------------------------------------------------
287
288 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
289 * C++ has no virtual methods in a constructor. We have to emulate a
290 * virtual function here as wxWindows requires different ways to insert
291 * a child in container classes. */
292
293 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
294 {
295 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
296
297 if (!parent->m_insertInClientArea)
298 {
299 /* these are outside the client area */
300 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
301 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
302 GTK_WIDGET(child->m_widget),
303 child->m_x,
304 child->m_y,
305 child->m_width,
306 child->m_height );
307 }
308 else
309 {
310 /* these are inside the client area */
311 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
312 GTK_WIDGET(child->m_widget),
313 child->m_x,
314 child->m_y,
315 child->m_width,
316 child->m_height );
317 }
318
319 /* resize on OnInternalIdle */
320 parent->GtkUpdateSize();
321 }
322
323 // ----------------------------------------------------------------------------
324 // wxTopLevelWindowGTK creation
325 // ----------------------------------------------------------------------------
326
327 void wxTopLevelWindowGTK::Init()
328 {
329 m_sizeSet = FALSE;
330 m_miniEdge = 0;
331 m_miniTitle = 0;
332 m_mainWidget = (GtkWidget*) NULL;
333 m_insertInClientArea = TRUE;
334 m_isFrame = TRUE;
335 m_isIconized = FALSE;
336 m_fsIsShowing = FALSE;
337 m_themeEnabled = TRUE;
338 m_gdkDecor = m_gdkFunc = 0;
339 }
340
341 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
342 wxWindowID id,
343 const wxString& title,
344 const wxPoint& pos,
345 const wxSize& sizeOrig,
346 long style,
347 const wxString &name )
348 {
349 // always create a frame of some reasonable, even if arbitrary, size (at
350 // least for MSW compatibility)
351 wxSize size = sizeOrig;
352 if ( size.x == -1 || size.y == -1 )
353 {
354 wxSize sizeDpy = wxGetDisplaySize();
355 if ( size.x == -1 )
356 size.x = sizeDpy.x / 3;
357 if ( size.y == -1 )
358 size.y = sizeDpy.y / 5;
359 }
360
361 wxTopLevelWindows.Append( this );
362
363 m_needParent = FALSE;
364
365 if (!PreCreation( parent, pos, size ) ||
366 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
367 {
368 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
369 return FALSE;
370 }
371
372 m_title = title;
373
374 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
375
376 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
377
378 if (style & wxFRAME_TOOL_WINDOW)
379 win_type = GTK_WINDOW_POPUP;
380
381 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
382 win_type = GTK_WINDOW_DIALOG;
383
384 m_widget = gtk_window_new( win_type );
385
386 if ((m_parent) && (HasFlag(wxFRAME_FLOAT_ON_PARENT)) && (GTK_IS_WINDOW(m_parent->m_widget)))
387 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
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 gtk_widget_set_usize( m_widget, m_width, m_height );
442
443 /* we cannot set MWM hints and icons before the widget has
444 been realized, so we do this directly after realization */
445 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
446 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
447
448 /* the only way to get the window size is to connect to this event */
449 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
450 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
451
452 /* map and unmap for iconized state */
453 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
454 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
455 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
456 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
457
458 /* the only way to get the window size is to connect to this event */
459 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
460 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
461
462 /* disable native tab traversal */
463 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
464 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
465
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 WM as well. Not tested.
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 wxTopLevelWindows.DeleteObject( this );
512
513 if (wxTheApp->GetTopWindow() == this)
514 wxTheApp->SetTopWindow( (wxWindow*) NULL );
515
516 if ((wxTopLevelWindows.Number() == 0) &&
517 (wxTheApp->GetExitOnFrameDelete()))
518 {
519 wxTheApp->ExitMainLoop();
520 }
521 }
522
523 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
524 {
525 if (show == m_fsIsShowing) return FALSE; // return what?
526
527 m_fsIsShowing = show;
528
529 if (show)
530 {
531 m_fsSaveStyle = m_windowStyle;
532 m_fsSaveFlag = style;
533 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
534 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
535
536 gtk_widget_hide( m_widget );
537 gtk_widget_unrealize( m_widget );
538
539 m_windowStyle = wxSIMPLE_BORDER;
540
541 int x;
542 int y;
543 wxDisplaySize( &x, &y );
544 SetSize( 0, 0, x, y );
545
546 gtk_widget_realize( m_widget );
547 gtk_widget_show( m_widget );
548 }
549 else
550 {
551 gtk_widget_hide( m_widget );
552 gtk_widget_unrealize( m_widget );
553
554 m_windowStyle = m_fsSaveStyle;
555
556 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
557
558 gtk_widget_realize( m_widget );
559 gtk_widget_show( m_widget );
560 }
561
562 return TRUE;
563 }
564
565 // ----------------------------------------------------------------------------
566 // overridden wxWindow methods
567 // ----------------------------------------------------------------------------
568
569 bool wxTopLevelWindowGTK::Show( bool show )
570 {
571 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
572
573 if (show && !m_sizeSet)
574 {
575 /* by calling GtkOnSize here, we don't have to call
576 either after showing the frame, which would entail
577 much ugly flicker or from within the size_allocate
578 handler, because GTK 1.1.X forbids that. */
579
580 GtkOnSize( m_x, m_y, m_width, m_height );
581 }
582
583 return wxWindow::Show( show );
584 }
585
586 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
587 {
588 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
589 }
590
591 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
592 {
593 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
594
595 /* this shouldn't happen: wxFrameGTK, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
596 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
597
598 /* avoid recursions */
599 if (m_resizing)
600 return;
601 m_resizing = TRUE;
602
603 int old_x = m_x;
604 int old_y = m_y;
605
606 int old_width = m_width;
607 int old_height = m_height;
608
609 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
610 {
611 if (x != -1) m_x = x;
612 if (y != -1) m_y = y;
613 if (width != -1) m_width = width;
614 if (height != -1) m_height = height;
615 }
616 else
617 {
618 m_x = x;
619 m_y = y;
620 m_width = width;
621 m_height = height;
622 }
623
624 /*
625 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
626 {
627 if (width == -1) m_width = 80;
628 }
629
630 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
631 {
632 if (height == -1) m_height = 26;
633 }
634 */
635
636 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
637 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
638 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
639 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
640
641 if ((m_x != -1) || (m_y != -1))
642 {
643 if ((m_x != old_x) || (m_y != old_y))
644 {
645 gtk_widget_set_uposition( m_widget, m_x, m_y );
646 }
647 }
648
649 if ((m_width != old_width) || (m_height != old_height))
650 {
651 gtk_widget_set_usize( m_widget, m_width, m_height );
652
653 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
654 done either directly before the frame is shown or in idle time
655 so that different calls to SetSize() don't lead to flicker. */
656 m_sizeSet = FALSE;
657 }
658
659 m_resizing = FALSE;
660 }
661
662 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
663 {
664 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
665
666 wxWindow::DoGetClientSize( width, height );
667 if (height)
668 {
669 /* mini edge */
670 *height -= m_miniEdge*2 + m_miniTitle;
671 }
672 if (width)
673 {
674 *width -= m_miniEdge*2;
675 }
676 }
677
678 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
679 {
680 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
681
682 DoSetSize(-1, -1,
683 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
684 }
685
686 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
687 int width, int height )
688 {
689 // due to a bug in gtk, x,y are always 0
690 // m_x = x;
691 // m_y = y;
692
693 /* avoid recursions */
694 if (m_resizing) return;
695 m_resizing = TRUE;
696
697 if ( m_wxwindow == NULL ) return;
698
699 m_width = width;
700 m_height = height;
701
702 /* wxMDIChildFrame derives from wxFrameGTK but it _is_ a wxWindow as it uses
703 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
704 set in wxFrameGTK::Create so it is used to check what kind of frame we
705 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
706 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
707 importantly) m_mainWidget */
708
709 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
710 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
711 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
712 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
713
714 if (m_mainWidget)
715 {
716 /* set size hints */
717 gint flag = 0; // GDK_HINT_POS;
718 if ((m_minWidth != -1) || (m_minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
719 if ((m_maxWidth != -1) || (m_maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
720 GdkGeometry geom;
721 geom.min_width = m_minWidth;
722 geom.min_height = m_minHeight;
723 geom.max_width = m_maxWidth;
724 geom.max_height = m_maxHeight;
725 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
726 (GtkWidget*) NULL,
727 &geom,
728 (GdkWindowHints) flag );
729
730 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
731 * menubar, the toolbar and the client area, which is represented by
732 * m_wxwindow.
733 * this hurts in the eye, but I don't want to call SetSize()
734 * because I don't want to call any non-native functions here. */
735
736 int client_x = m_miniEdge;
737 int client_y = m_miniEdge + m_miniTitle;
738 int client_w = m_width - 2*m_miniEdge;
739 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
740 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
741 m_wxwindow,
742 client_x, client_y, client_w, client_h );
743 }
744 else
745 {
746 /* if there is no m_mainWidget between m_widget and m_wxwindow there
747 is no need to set the size or position of m_wxwindow. */
748 }
749
750 m_sizeSet = TRUE;
751
752 // send size event to frame
753 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
754 event.SetEventObject( this );
755 GetEventHandler()->ProcessEvent( event );
756
757 m_resizing = FALSE;
758 }
759
760 void wxTopLevelWindowGTK::OnInternalIdle()
761 {
762 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
763 {
764 GtkOnSize( m_x, m_y, m_width, m_height );
765
766 // we'll come back later
767 if (g_isIdle)
768 wxapp_install_idle_handler();
769 return;
770 }
771
772 wxWindow::OnInternalIdle();
773 }
774
775
776 // ----------------------------------------------------------------------------
777 // frame title/icon
778 // ----------------------------------------------------------------------------
779
780 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
781 {
782 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
783
784 m_title = title;
785 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
786 }
787
788 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
789 {
790 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
791
792 wxTopLevelWindowBase::SetIcon(icon);
793
794 if ( !m_icon.Ok() )
795 return;
796
797 if (!m_widget->window)
798 return;
799
800 wxMask *mask = icon.GetMask();
801 GdkBitmap *bm = (GdkBitmap *) NULL;
802 if (mask) bm = mask->GetBitmap();
803
804 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
805 }
806
807 // ----------------------------------------------------------------------------
808 // frame state: maximized/iconized/normal
809 // ----------------------------------------------------------------------------
810
811 void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize))
812 {
813 wxFAIL_MSG( _T("not implemented") );
814 }
815
816 bool wxTopLevelWindowGTK::IsMaximized() const
817 {
818 // wxFAIL_MSG( _T("not implemented") );
819
820 // This is an approximation
821 return FALSE;
822 }
823
824 void wxTopLevelWindowGTK::Restore()
825 {
826 wxFAIL_MSG( _T("not implemented") );
827 }
828
829 void wxTopLevelWindowGTK::Iconize( bool iconize )
830 {
831 if (iconize)
832 {
833 GdkWindow *window = m_widget->window;
834
835 // you should do it later, for example from OnCreate() handler
836 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
837
838 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
839 GDK_WINDOW_XWINDOW( window ),
840 DefaultScreen( GDK_DISPLAY() ) );
841 }
842 }
843
844 bool wxTopLevelWindowGTK::IsIconized() const
845 {
846 return m_isIconized;
847 }
848
849 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
850 {
851 if ( iconize != m_isIconized )
852 {
853 m_isIconized = iconize;
854 (void)SendIconizeEvent(iconize);
855 }
856 }
857