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