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