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