wxIconBundle implementation.
[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 wxIcon iconOld = win->GetIcon();
195 if ( iconOld != wxNullIcon )
196 {
197 wxIcon icon( iconOld );
198 win->SetIcon( wxNullIcon );
199 win->SetIcon( icon );
200 }
201
202 // we set the focus to the child that accepts the focus. this
203 // doesn't really have to be done in "realize" but why not?
204 wxWindowList::Node *node = win->GetChildren().GetFirst();
205 while (node)
206 {
207 wxWindow *child = node->GetData();
208 if (child->AcceptsFocus())
209 {
210 child->SetFocus();
211 break;
212 }
213
214 node = node->GetNext();
215 }
216 }
217
218 //-----------------------------------------------------------------------------
219 // "map_event" from m_widget
220 //-----------------------------------------------------------------------------
221
222 static void
223 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
224 GdkEvent * WXUNUSED(event),
225 wxTopLevelWindow *win )
226 {
227 win->SetIconizeState(FALSE);
228 }
229
230 //-----------------------------------------------------------------------------
231 // "unmap_event" from m_widget
232 //-----------------------------------------------------------------------------
233
234 static void
235 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
236 GdkEvent * WXUNUSED(event),
237 wxTopLevelWindow *win )
238 {
239 win->SetIconizeState(TRUE);
240 }
241
242 //-----------------------------------------------------------------------------
243 // "expose_event" of m_client
244 //-----------------------------------------------------------------------------
245
246 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
247 {
248 GtkPizza *pizza = GTK_PIZZA(widget);
249
250 gtk_paint_flat_box (win->m_widget->style,
251 pizza->bin_window, GTK_STATE_NORMAL,
252 GTK_SHADOW_NONE,
253 &gdk_event->area,
254 win->m_widget,
255 (char *)"base",
256 0, 0, -1, -1);
257
258 return TRUE;
259 }
260
261 //-----------------------------------------------------------------------------
262 // "draw" of m_client
263 //-----------------------------------------------------------------------------
264
265
266 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
267 {
268 GtkPizza *pizza = GTK_PIZZA(widget);
269
270 gtk_paint_flat_box (win->m_widget->style,
271 pizza->bin_window, GTK_STATE_NORMAL,
272 GTK_SHADOW_NONE,
273 rect,
274 win->m_widget,
275 (char *)"base",
276 0, 0, -1, -1);
277 }
278
279 // ----------------------------------------------------------------------------
280 // wxTopLevelWindowGTK itself
281 // ----------------------------------------------------------------------------
282
283 //-----------------------------------------------------------------------------
284 // InsertChild for wxTopLevelWindowGTK
285 //-----------------------------------------------------------------------------
286
287 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
288 * C++ has no virtual methods in a constructor. We have to emulate a
289 * virtual function here as wxWindows requires different ways to insert
290 * a child in container classes. */
291
292 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
293 {
294 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
295
296 if (!parent->m_insertInClientArea)
297 {
298 // these are outside the client area
299 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
300 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
301 GTK_WIDGET(child->m_widget),
302 child->m_x,
303 child->m_y,
304 child->m_width,
305 child->m_height );
306 }
307 else
308 {
309 // these are inside the client area
310 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
311 GTK_WIDGET(child->m_widget),
312 child->m_x,
313 child->m_y,
314 child->m_width,
315 child->m_height );
316 }
317
318 // resize on OnInternalIdle
319 parent->GtkUpdateSize();
320 }
321
322 // ----------------------------------------------------------------------------
323 // wxTopLevelWindowGTK creation
324 // ----------------------------------------------------------------------------
325
326 void wxTopLevelWindowGTK::Init()
327 {
328 m_sizeSet = FALSE;
329 m_miniEdge = 0;
330 m_miniTitle = 0;
331 m_mainWidget = (GtkWidget*) NULL;
332 m_insertInClientArea = TRUE;
333 m_isFrame = TRUE;
334 m_isIconized = FALSE;
335 m_fsIsShowing = FALSE;
336 m_themeEnabled = TRUE;
337 m_gdkDecor = m_gdkFunc = 0;
338 }
339
340 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
341 wxWindowID id,
342 const wxString& title,
343 const wxPoint& pos,
344 const wxSize& sizeOrig,
345 long style,
346 const wxString &name )
347 {
348 // always create a frame of some reasonable, even if arbitrary, size (at
349 // least for MSW compatibility)
350 wxSize size = sizeOrig;
351 if ( size.x == -1 || size.y == -1 )
352 {
353 wxSize sizeDpy = wxGetDisplaySize();
354 if ( size.x == -1 )
355 size.x = sizeDpy.x / 3;
356 if ( size.y == -1 )
357 size.y = sizeDpy.y / 5;
358 }
359
360 wxTopLevelWindows.Append( this );
361
362 m_needParent = FALSE;
363
364 if (!PreCreation( parent, pos, size ) ||
365 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
366 {
367 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
368 return FALSE;
369 }
370
371 m_title = title;
372
373 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
374
375 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
376
377 if (style & wxFRAME_TOOL_WINDOW)
378 win_type = GTK_WINDOW_POPUP;
379
380 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
381 {
382 // there is no more GTK_WINDOW_DIALOG in 2.0
383 #ifdef __WXGTK20__
384 win_type = GTK_WINDOW_TOPLEVEL;
385 #else
386 win_type = GTK_WINDOW_DIALOG;
387 #endif
388 }
389
390 m_widget = gtk_window_new( win_type );
391
392 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)) &&
393 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG))
394 {
395 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
396 }
397
398 if (!name.IsEmpty())
399 gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() );
400
401 #ifdef __WXDEBUG__
402 debug_focus_in( m_widget, wxT("wxTopLevelWindowGTK::m_widget"), name );
403 #endif
404
405 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
406 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
407
408 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
409 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
410
411 // m_mainWidget holds the toolbar, the menubar and the client area
412 m_mainWidget = gtk_pizza_new();
413 gtk_widget_show( m_mainWidget );
414 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
415 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
416
417 // for m_mainWidget themes
418 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
419 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
420 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
421 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
422
423 #ifdef __WXDEBUG__
424 debug_focus_in( m_mainWidget, wxT("wxTopLevelWindowGTK::m_mainWidget"), name );
425 #endif
426
427 // m_wxwindow only represents the client area without toolbar and menubar
428 m_wxwindow = gtk_pizza_new();
429 gtk_widget_show( m_wxwindow );
430 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
431
432 #ifdef __WXDEBUG__
433 debug_focus_in( m_wxwindow, wxT("wxTopLevelWindowGTK::m_wxwindow"), name );
434 #endif
435
436 // we donm't allow the frame to get the focus as otherwise
437 // the frame will grab it at arbitrary focus changes
438 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
439
440 if (m_parent) m_parent->AddChild( this );
441
442 // the user resized the frame by dragging etc.
443 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
444 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
445
446 PostCreation();
447
448 if ((m_x != -1) || (m_y != -1))
449 gtk_widget_set_uposition( m_widget, m_x, m_y );
450
451 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
452
453 // we cannot set MWM hints and icons before the widget has
454 // been realized, so we do this directly after realization
455 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
456 GTK_SIGNAL_FUNC(gtk_frame_realized_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 // map and unmap for iconized state
463 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
464 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
465 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
466 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
467
468 // the only way to get the window size is to connect to this event
469 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
470 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
471
472 // disable native tab traversal
473 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
474 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
475
476 // decorations
477 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
478 {
479 m_gdkDecor = 0;
480 m_gdkFunc = 0;
481 }
482 else
483 {
484 m_gdkDecor = (long) GDK_DECOR_BORDER;
485 m_gdkFunc = (long) GDK_FUNC_MOVE;
486
487 // All this is for Motif Window Manager "hints" and is supposed to be
488 // recognized by other WMs as well.
489 if ((style & wxCAPTION) != 0)
490 m_gdkDecor |= GDK_DECOR_TITLE;
491 if ((style & wxSYSTEM_MENU) != 0)
492 {
493 m_gdkFunc |= GDK_FUNC_CLOSE;
494 m_gdkDecor |= GDK_DECOR_MENU;
495 }
496 if ((style & wxMINIMIZE_BOX) != 0)
497 {
498 m_gdkFunc |= GDK_FUNC_MINIMIZE;
499 m_gdkDecor |= GDK_DECOR_MINIMIZE;
500 }
501 if ((style & wxMAXIMIZE_BOX) != 0)
502 {
503 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
504 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
505 }
506 if ((style & wxRESIZE_BORDER) != 0)
507 {
508 m_gdkFunc |= GDK_FUNC_RESIZE;
509 m_gdkDecor |= GDK_DECOR_RESIZEH;
510 }
511 }
512
513 return TRUE;
514 }
515
516 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
517 {
518 m_isBeingDeleted = TRUE;
519
520 // it may also be GtkScrolledWindow in the case of an MDI child
521 if (GTK_IS_WINDOW(m_widget))
522 {
523 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
524 }
525
526 wxTopLevelWindows.DeleteObject( this );
527
528 if (wxTheApp->GetTopWindow() == this)
529 wxTheApp->SetTopWindow( (wxWindow*) NULL );
530
531 if ((wxTopLevelWindows.Number() == 0) &&
532 (wxTheApp->GetExitOnFrameDelete()))
533 {
534 wxTheApp->ExitMainLoop();
535 }
536 }
537
538 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
539 {
540 if (show == m_fsIsShowing) return FALSE; // return what?
541
542 m_fsIsShowing = show;
543
544 if (show)
545 {
546 m_fsSaveGdkFunc = m_gdkFunc;
547 m_fsSaveGdkDecor = m_gdkDecor;
548 m_fsSaveFlag = style;
549 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
550 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
551
552 gtk_widget_hide( m_widget );
553 gtk_widget_unrealize( m_widget );
554
555 m_gdkDecor = (long) GDK_DECOR_BORDER;
556 m_gdkFunc = (long) GDK_FUNC_MOVE;
557
558 int x;
559 int y;
560 wxDisplaySize( &x, &y );
561 SetSize( 0, 0, x, y );
562
563 gtk_widget_realize( m_widget );
564 gtk_widget_show( m_widget );
565 }
566 else
567 {
568 gtk_widget_hide( m_widget );
569 gtk_widget_unrealize( m_widget );
570
571 m_gdkFunc = m_fsSaveGdkFunc;
572 m_gdkDecor = m_fsSaveGdkDecor;
573
574 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
575
576 gtk_widget_realize( m_widget );
577 gtk_widget_show( m_widget );
578 }
579
580 return TRUE;
581 }
582
583 // ----------------------------------------------------------------------------
584 // overridden wxWindow methods
585 // ----------------------------------------------------------------------------
586
587 bool wxTopLevelWindowGTK::Show( bool show )
588 {
589 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
590
591 if (show && !m_sizeSet)
592 {
593 /* by calling GtkOnSize here, we don't have to call
594 either after showing the frame, which would entail
595 much ugly flicker or from within the size_allocate
596 handler, because GTK 1.1.X forbids that. */
597
598 GtkOnSize( m_x, m_y, m_width, m_height );
599 }
600
601 return wxWindow::Show( show );
602 }
603
604 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
605 {
606 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
607 }
608
609 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
610 {
611 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
612
613 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
614 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
615
616 // avoid recursions
617 if (m_resizing)
618 return;
619 m_resizing = TRUE;
620
621 int old_x = m_x;
622 int old_y = m_y;
623
624 int old_width = m_width;
625 int old_height = m_height;
626
627 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
628 {
629 if (x != -1) m_x = x;
630 if (y != -1) m_y = y;
631 if (width != -1) m_width = width;
632 if (height != -1) m_height = height;
633 }
634 else
635 {
636 m_x = x;
637 m_y = y;
638 m_width = width;
639 m_height = height;
640 }
641
642 /*
643 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
644 {
645 if (width == -1) m_width = 80;
646 }
647
648 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
649 {
650 if (height == -1) m_height = 26;
651 }
652 */
653
654 int minWidth = GetMinWidth(),
655 minHeight = GetMinHeight(),
656 maxWidth = GetMaxWidth(),
657 maxHeight = GetMaxHeight();
658
659 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
660 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
661 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
662 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
663
664 if ((m_x != -1) || (m_y != -1))
665 {
666 if ((m_x != old_x) || (m_y != old_y))
667 {
668 gtk_widget_set_uposition( m_widget, m_x, m_y );
669 }
670 }
671
672 if ((m_width != old_width) || (m_height != old_height))
673 {
674 if (m_widget->window)
675 gdk_window_resize( m_widget->window, m_width, m_height );
676 else
677 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
678
679 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
680 done either directly before the frame is shown or in idle time
681 so that different calls to SetSize() don't lead to flicker. */
682 m_sizeSet = FALSE;
683 }
684
685 m_resizing = FALSE;
686 }
687
688 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
689 {
690 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
691
692 wxWindow::DoGetClientSize( width, height );
693 if (height)
694 {
695 // mini edge
696 *height -= m_miniEdge*2 + m_miniTitle;
697 }
698 if (width)
699 {
700 *width -= m_miniEdge*2;
701 }
702 }
703
704 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
705 {
706 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
707
708 DoSetSize(-1, -1,
709 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
710 }
711
712 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
713 int width, int height )
714 {
715 // due to a bug in gtk, x,y are always 0
716 // m_x = x;
717 // m_y = y;
718
719 // avoid recursions
720 if (m_resizing) return;
721 m_resizing = TRUE;
722
723 if ( m_wxwindow == NULL ) return;
724
725 m_width = width;
726 m_height = height;
727
728 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
729 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
730 set in wxFrame::Create so it is used to check what kind of frame we
731 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
732 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
733 importantly) m_mainWidget */
734
735 int minWidth = GetMinWidth(),
736 minHeight = GetMinHeight(),
737 maxWidth = GetMaxWidth(),
738 maxHeight = GetMaxHeight();
739
740 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
741 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
742 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
743 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
744
745 if (m_mainWidget)
746 {
747 // set size hints
748 gint flag = 0; // GDK_HINT_POS;
749 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
750 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
751 GdkGeometry geom;
752 geom.min_width = minWidth;
753 geom.min_height = minHeight;
754 geom.max_width = maxWidth;
755 geom.max_height = maxHeight;
756 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
757 (GtkWidget*) NULL,
758 &geom,
759 (GdkWindowHints) flag );
760
761 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
762 * menubar, the toolbar and the client area, which is represented by
763 * m_wxwindow.
764 * this hurts in the eye, but I don't want to call SetSize()
765 * because I don't want to call any non-native functions here. */
766
767 int client_x = m_miniEdge;
768 int client_y = m_miniEdge + m_miniTitle;
769 int client_w = m_width - 2*m_miniEdge;
770 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
771 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
772 m_wxwindow,
773 client_x, client_y, client_w, client_h );
774 }
775 else
776 {
777 // If there is no m_mainWidget between m_widget and m_wxwindow there
778 // is no need to set the size or position of m_wxwindow.
779 }
780
781 m_sizeSet = TRUE;
782
783 // send size event to frame
784 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
785 event.SetEventObject( this );
786 GetEventHandler()->ProcessEvent( event );
787
788 m_resizing = FALSE;
789 }
790
791 void wxTopLevelWindowGTK::OnInternalIdle()
792 {
793 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
794 {
795 GtkOnSize( m_x, m_y, m_width, m_height );
796
797 // we'll come back later
798 if (g_isIdle)
799 wxapp_install_idle_handler();
800 return;
801 }
802
803 wxWindow::OnInternalIdle();
804 }
805
806
807 // ----------------------------------------------------------------------------
808 // frame title/icon
809 // ----------------------------------------------------------------------------
810
811 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
812 {
813 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
814
815 m_title = title;
816 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
817 }
818
819 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
820 {
821 if ( !icon.Ok() )
822 return;
823
824 if (!m_widget->window)
825 return;
826
827 wxMask *mask = icon.GetMask();
828 GdkBitmap *bm = (GdkBitmap *) NULL;
829 if (mask) bm = mask->GetBitmap();
830
831 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
832 }
833
834 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
835 {
836 SetIcons( wxIconBundle( icon ) );
837 }
838
839 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
840 {
841 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
842 GdkWindow* window = m_widget->window;
843 wxCHECK_RET( window, _T("window not created yet - can't set icon") );
844
845 wxTopLevelWindowBase::SetIcons( icons );
846
847 DoSetIcon( icons.GetIcon( -1 ) );
848 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
849 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
850 }
851
852 // ----------------------------------------------------------------------------
853 // frame state: maximized/iconized/normal
854 // ----------------------------------------------------------------------------
855
856 void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize))
857 {
858 wxFAIL_MSG( _T("not implemented") );
859 }
860
861 bool wxTopLevelWindowGTK::IsMaximized() const
862 {
863 // wxFAIL_MSG( _T("not implemented") );
864
865 // This is an approximation
866 return FALSE;
867 }
868
869 void wxTopLevelWindowGTK::Restore()
870 {
871 wxFAIL_MSG( _T("not implemented") );
872 }
873
874 void wxTopLevelWindowGTK::Iconize( bool iconize )
875 {
876 if (iconize)
877 {
878 GdkWindow *window = m_widget->window;
879
880 // you should do it later, for example from OnCreate() handler
881 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
882
883 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
884 GDK_WINDOW_XWINDOW( window ),
885 DefaultScreen( GDK_DISPLAY() ) );
886 }
887 }
888
889 bool wxTopLevelWindowGTK::IsIconized() const
890 {
891 return m_isIconized;
892 }
893
894 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
895 {
896 if ( iconize != m_isIconized )
897 {
898 m_isIconized = iconize;
899 (void)SendIconizeEvent(iconize);
900 }
901 }
902