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