New implementation of ShowFullScreen(). It works
[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 // XA_CARDINAL
44 #include <X11/Xatom.h>
45
46 // ----------------------------------------------------------------------------
47 // idle system
48 // ----------------------------------------------------------------------------
49
50 extern void wxapp_install_idle_handler();
51 extern bool g_isIdle;
52
53 // ----------------------------------------------------------------------------
54 // data
55 // ----------------------------------------------------------------------------
56
57 extern wxList wxPendingDelete;
58
59 extern int g_openDialogs;
60 extern wxWindowGTK *g_delayedFocus;
61
62 //-----------------------------------------------------------------------------
63 // "focus" from m_window
64 //-----------------------------------------------------------------------------
65
66 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
67 {
68 if (g_isIdle)
69 wxapp_install_idle_handler();
70
71 // This disables GTK's tab traversal
72 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
73 return TRUE;
74 }
75
76 //-----------------------------------------------------------------------------
77 // "size_allocate"
78 //-----------------------------------------------------------------------------
79
80 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
81 {
82 if (g_isIdle)
83 wxapp_install_idle_handler();
84
85 if (!win->m_hasVMT)
86 return;
87
88 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
89 {
90 /*
91 wxPrintf( "OnSize from " );
92 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
93 wxPrintf( win->GetClassInfo()->GetClassName() );
94 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
95 (int)alloc->y,
96 (int)alloc->width,
97 (int)alloc->height );
98 */
99
100 win->m_width = alloc->width;
101 win->m_height = alloc->height;
102 win->m_queuedFullRedraw = TRUE;
103 win->GtkUpdateSize();
104 }
105 }
106
107 //-----------------------------------------------------------------------------
108 // "delete_event"
109 //-----------------------------------------------------------------------------
110
111 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxTopLevelWindowGTK *win )
112 {
113 if (g_isIdle)
114 wxapp_install_idle_handler();
115
116 if (win->IsEnabled() &&
117 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
118 win->IsGrabbed()))
119 win->Close();
120
121 return TRUE;
122 }
123
124
125 //-----------------------------------------------------------------------------
126 // "configure_event"
127 //-----------------------------------------------------------------------------
128
129 static gint
130 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxTopLevelWindowGTK *win )
131 {
132 if (g_isIdle)
133 wxapp_install_idle_handler();
134
135 if (!win->m_hasVMT || !win->IsShown())
136 return FALSE;
137
138 int x = 0;
139 int y = 0;
140 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
141 win->m_x = x;
142 win->m_y = y;
143
144 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
145 mevent.SetEventObject( win );
146 win->GetEventHandler()->ProcessEvent( mevent );
147
148 return FALSE;
149 }
150
151 //-----------------------------------------------------------------------------
152 // "realize" from m_widget
153 //-----------------------------------------------------------------------------
154
155 // we cannot MWM hints and icons before the widget has been realized,
156 // so we do this directly after realization
157
158 static void
159 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
160 wxTopLevelWindowGTK *win )
161 {
162 if (g_isIdle)
163 wxapp_install_idle_handler();
164
165 // All this is for Motif Window Manager "hints" and is supposed to be
166 // recognized by other WM as well. Not tested.
167 gdk_window_set_decorations(win->m_widget->window,
168 (GdkWMDecoration)win->m_gdkDecor);
169 gdk_window_set_functions(win->m_widget->window,
170 (GdkWMFunction)win->m_gdkFunc);
171
172 // GTK's shrinking/growing policy
173 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
174 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
175 else
176 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
177
178 // reset the icon
179 wxIconBundle iconsOld = win->GetIcons();
180 if ( iconsOld.GetIcon(-1).Ok() )
181 {
182 win->SetIcon( wxNullIcon );
183 win->SetIcons( iconsOld );
184 }
185 }
186
187 //-----------------------------------------------------------------------------
188 // "map_event" from m_widget
189 //-----------------------------------------------------------------------------
190
191 static void
192 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
193 GdkEvent * WXUNUSED(event),
194 wxTopLevelWindow *win )
195 {
196 win->SetIconizeState(FALSE);
197 }
198
199 //-----------------------------------------------------------------------------
200 // "unmap_event" from m_widget
201 //-----------------------------------------------------------------------------
202
203 static void
204 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
205 GdkEvent * WXUNUSED(event),
206 wxTopLevelWindow *win )
207 {
208 win->SetIconizeState(TRUE);
209 }
210
211 //-----------------------------------------------------------------------------
212 // "expose_event" of m_client
213 //-----------------------------------------------------------------------------
214
215 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
216 {
217 GtkPizza *pizza = GTK_PIZZA(widget);
218
219 gtk_paint_flat_box (win->m_widget->style,
220 pizza->bin_window, GTK_STATE_NORMAL,
221 GTK_SHADOW_NONE,
222 &gdk_event->area,
223 win->m_widget,
224 (char *)"base",
225 0, 0, -1, -1);
226
227 return TRUE;
228 }
229
230 //-----------------------------------------------------------------------------
231 // "draw" of m_client
232 //-----------------------------------------------------------------------------
233
234 #ifndef __WXGTK20__
235
236 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
237 {
238 GtkPizza *pizza = GTK_PIZZA(widget);
239
240 gtk_paint_flat_box (win->m_widget->style,
241 pizza->bin_window, GTK_STATE_NORMAL,
242 GTK_SHADOW_NONE,
243 rect,
244 win->m_widget,
245 (char *)"base",
246 0, 0, -1, -1);
247 }
248
249 #endif // GTK+ 1.x
250
251 // ----------------------------------------------------------------------------
252 // wxTopLevelWindowGTK itself
253 // ----------------------------------------------------------------------------
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_isIconized = FALSE;
306 m_fsIsShowing = FALSE;
307 m_themeEnabled = TRUE;
308 m_gdkDecor = m_gdkFunc = 0;
309 m_grabbed = FALSE;
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 if (m_grabbed)
481 {
482 wxASSERT_MSG( FALSE, "Window still grabbed");
483 RemoveGrab();
484 }
485
486 m_isBeingDeleted = TRUE;
487
488 // it may also be GtkScrolledWindow in the case of an MDI child
489 if (GTK_IS_WINDOW(m_widget))
490 {
491 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
492 }
493
494 wxTopLevelWindows.DeleteObject( this );
495
496 if (wxTheApp->GetTopWindow() == this)
497 wxTheApp->SetTopWindow( (wxWindow*) NULL );
498
499 if ((wxTopLevelWindows.Number() == 0) &&
500 (wxTheApp->GetExitOnFrameDelete()))
501 {
502 wxTheApp->ExitMainLoop();
503 }
504 }
505
506
507 // X11 ICCCM values for window layers
508 #define WIN_LAYER_NORMAL 4
509 #define WIN_LAYER_ABOVE_DOCK 10
510
511 // X11 window manager property name
512 #define XA_WIN_LAYER "_WIN_LAYER"
513
514 // X11 window manager property name atom
515 static Atom gs_XA_WIN_LAYER = 0;
516
517
518 static void wx_win_hints_set_layer(GtkWidget *window, int layer)
519 {
520 XEvent xev;
521 GdkWindowPrivate *priv;
522 gint prev_error;
523
524 prev_error = gdk_error_warnings;
525 gdk_error_warnings = 0;
526 priv = (GdkWindowPrivate*)(GTK_WIDGET(window)->window);
527
528 if (GTK_WIDGET_MAPPED(window))
529 {
530 xev.type = ClientMessage;
531 xev.xclient.type = ClientMessage;
532 xev.xclient.window = priv->xwindow;
533 xev.xclient.message_type = gs_XA_WIN_LAYER;
534 xev.xclient.format = 32;
535 xev.xclient.data.l[0] = (long)layer;
536 xev.xclient.data.l[1] = gdk_time_get();
537
538 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
539 SubstructureNotifyMask, (XEvent*) &xev);
540 }
541 else
542 {
543 long data[1];
544
545 data[0] = layer;
546 XChangeProperty(GDK_DISPLAY(), priv->xwindow, gs_XA_WIN_LAYER,
547 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data,
548 1);
549 }
550 gdk_error_warnings = prev_error;
551 }
552
553 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
554 {
555 if (show == m_fsIsShowing) return FALSE; // return what?
556
557 if (gs_XA_WIN_LAYER == 0)
558 {
559 // Initialose X11 Atom only once
560 gs_XA_WIN_LAYER = XInternAtom( GDK_DISPLAY(), XA_WIN_LAYER, False );
561 }
562
563 m_fsIsShowing = show;
564
565 if (show)
566 {
567 m_fsSaveGdkFunc = m_gdkFunc;
568 m_fsSaveGdkDecor = m_gdkDecor;
569 m_fsSaveFlag = style;
570 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
571 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
572
573 int screen_width,screen_height;
574 wxDisplaySize( &screen_width, &screen_height );
575
576 gint client_x, client_y, root_x, root_y;
577 gint width, height;
578
579 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
580 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
581 &width, &height, NULL);
582
583 wx_win_hints_set_layer( m_widget, WIN_LAYER_ABOVE_DOCK );
584
585 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
586 screen_width + 1, screen_height + 1);
587 }
588 else
589 {
590 wx_win_hints_set_layer( m_widget, WIN_LAYER_NORMAL );
591
592 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
593 }
594
595 return TRUE;
596 }
597
598 // ----------------------------------------------------------------------------
599 // overridden wxWindow methods
600 // ----------------------------------------------------------------------------
601
602 bool wxTopLevelWindowGTK::Show( bool show )
603 {
604 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
605
606 if (show && !m_sizeSet)
607 {
608 /* by calling GtkOnSize here, we don't have to call
609 either after showing the frame, which would entail
610 much ugly flicker or from within the size_allocate
611 handler, because GTK 1.1.X forbids that. */
612
613 GtkOnSize( m_x, m_y, m_width, m_height );
614 }
615
616 return wxWindow::Show( show );
617 }
618
619 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
620 {
621 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
622 }
623
624 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
625 {
626 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
627
628 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
629 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
630
631 // avoid recursions
632 if (m_resizing)
633 return;
634 m_resizing = TRUE;
635
636 int old_x = m_x;
637 int old_y = m_y;
638
639 int old_width = m_width;
640 int old_height = m_height;
641
642 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
643 {
644 if (x != -1) m_x = x;
645 if (y != -1) m_y = y;
646 }
647 else
648 {
649 m_x = x;
650 m_y = y;
651 }
652 if (width != -1) m_width = width;
653 if (height != -1) m_height = height;
654
655 /*
656 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
657 {
658 if (width == -1) m_width = 80;
659 }
660
661 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
662 {
663 if (height == -1) m_height = 26;
664 }
665 */
666
667 int minWidth = GetMinWidth(),
668 minHeight = GetMinHeight(),
669 maxWidth = GetMaxWidth(),
670 maxHeight = GetMaxHeight();
671
672 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
673 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
674 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
675 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
676
677 if ((m_x != -1) || (m_y != -1))
678 {
679 if ((m_x != old_x) || (m_y != old_y))
680 {
681 gtk_widget_set_uposition( m_widget, m_x, m_y );
682 }
683 }
684
685 if ((m_width != old_width) || (m_height != old_height))
686 {
687 if (m_widget->window)
688 gdk_window_resize( m_widget->window, m_width, m_height );
689 else
690 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
691
692 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
693 done either directly before the frame is shown or in idle time
694 so that different calls to SetSize() don't lead to flicker. */
695 m_sizeSet = FALSE;
696 }
697
698 m_resizing = FALSE;
699 }
700
701 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
702 {
703 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
704
705 wxWindow::DoGetClientSize( width, height );
706 if (height)
707 {
708 // mini edge
709 *height -= m_miniEdge*2 + m_miniTitle;
710 }
711 if (width)
712 {
713 *width -= m_miniEdge*2;
714 }
715 }
716
717 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
718 {
719 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
720
721 DoSetSize(-1, -1,
722 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
723 }
724
725 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
726 int width, int height )
727 {
728 // due to a bug in gtk, x,y are always 0
729 // m_x = x;
730 // m_y = y;
731
732 // avoid recursions
733 if (m_resizing) return;
734 m_resizing = TRUE;
735
736 if ( m_wxwindow == NULL ) return;
737
738 m_width = width;
739 m_height = height;
740
741 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
742 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
743 set in wxFrame::Create so it is used to check what kind of frame we
744 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
745 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
746 importantly) m_mainWidget */
747
748 int minWidth = GetMinWidth(),
749 minHeight = GetMinHeight(),
750 maxWidth = GetMaxWidth(),
751 maxHeight = GetMaxHeight();
752
753 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
754 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
755 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
756 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
757
758 if (m_mainWidget)
759 {
760 // set size hints
761 gint flag = 0; // GDK_HINT_POS;
762 GdkGeometry geom;
763
764 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
765 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
766
767 geom.min_width = minWidth;
768 geom.min_height = minHeight;
769
770 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
771 // maxHeight or maxWidth is set, we must set them both, else the
772 // remaining -1 will be taken literally.
773
774 // I'm certain this also happens elsewhere, and is the probable
775 // cause of other such things as:
776 // Gtk-WARNING **: gtk_widget_size_allocate():
777 // attempt to allocate widget with width 65535 and height 600
778 // but I don't have time to track them all now..
779 //
780 // Really we need to encapulate all this height/width business and
781 // stop any old method from ripping at the members directly and
782 // scattering -1's without regard for who might resolve them later.
783
784 geom.max_width = ( maxHeight == -1 ) ? maxWidth
785 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
786 : maxWidth ;
787
788 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
789 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
790 : maxHeight ;
791
792 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
793 (GtkWidget*) NULL,
794 &geom,
795 (GdkWindowHints) flag );
796
797 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
798 * menubar, the toolbar and the client area, which is represented by
799 * m_wxwindow.
800 * this hurts in the eye, but I don't want to call SetSize()
801 * because I don't want to call any non-native functions here. */
802
803 int client_x = m_miniEdge;
804 int client_y = m_miniEdge + m_miniTitle;
805 int client_w = m_width - 2*m_miniEdge;
806 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
807
808 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
809 m_wxwindow,
810 client_x, client_y, client_w, client_h );
811 }
812 else
813 {
814 // If there is no m_mainWidget between m_widget and m_wxwindow there
815 // is no need to set the size or position of m_wxwindow.
816 }
817
818 m_sizeSet = TRUE;
819
820 // send size event to frame
821 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
822 event.SetEventObject( this );
823 GetEventHandler()->ProcessEvent( event );
824
825 m_resizing = FALSE;
826 }
827
828 void wxTopLevelWindowGTK::OnInternalIdle()
829 {
830 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
831 {
832 GtkOnSize( m_x, m_y, m_width, m_height );
833
834 // we'll come back later
835 if (g_isIdle)
836 wxapp_install_idle_handler();
837 return;
838 }
839
840 // set the focus if not done yet and if we can already do it
841 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
842 {
843 if ( g_delayedFocus &&
844 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
845 {
846 g_delayedFocus->SetFocus();
847 g_delayedFocus = NULL;
848 }
849 }
850
851 wxWindow::OnInternalIdle();
852 }
853
854 // ----------------------------------------------------------------------------
855 // frame title/icon
856 // ----------------------------------------------------------------------------
857
858 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
859 {
860 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
861
862 m_title = title;
863 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
864 }
865
866 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
867 {
868 if ( !icon.Ok() )
869 return;
870
871 if (!m_widget->window)
872 return;
873
874 wxMask *mask = icon.GetMask();
875 GdkBitmap *bm = (GdkBitmap *) NULL;
876 if (mask) bm = mask->GetBitmap();
877
878 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
879 }
880
881 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
882 {
883 SetIcons( wxIconBundle( icon ) );
884 }
885
886 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
887 {
888 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
889 GdkWindow* window = m_widget->window;
890
891 wxTopLevelWindowBase::SetIcons( icons );
892
893 DoSetIcon( icons.GetIcon( -1 ) );
894 if ( window )
895 {
896 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
897 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
898 }
899 }
900
901 // ----------------------------------------------------------------------------
902 // frame state: maximized/iconized/normal
903 // ----------------------------------------------------------------------------
904
905 void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize))
906 {
907 wxFAIL_MSG( _T("not implemented") );
908 }
909
910 bool wxTopLevelWindowGTK::IsMaximized() const
911 {
912 // wxFAIL_MSG( _T("not implemented") );
913
914 // This is an approximation
915 return FALSE;
916 }
917
918 void wxTopLevelWindowGTK::Restore()
919 {
920 wxFAIL_MSG( _T("not implemented") );
921 }
922
923 void wxTopLevelWindowGTK::Iconize( bool iconize )
924 {
925 if (iconize)
926 {
927 GdkWindow *window = m_widget->window;
928
929 // you should do it later, for example from OnCreate() handler
930 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
931
932 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
933 GDK_WINDOW_XWINDOW( window ),
934 DefaultScreen( GDK_DISPLAY() ) );
935 }
936 }
937
938 bool wxTopLevelWindowGTK::IsIconized() const
939 {
940 return m_isIconized;
941 }
942
943 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
944 {
945 if ( iconize != m_isIconized )
946 {
947 m_isIconized = iconize;
948 (void)SendIconizeEvent(iconize);
949 }
950 }
951
952 void wxTopLevelWindowGTK::AddGrab()
953 {
954 if (!m_grabbed)
955 {
956 m_grabbed = TRUE;
957 gtk_grab_add( m_widget );
958 gtk_main();
959 gtk_grab_remove( m_widget );
960 }
961 }
962
963 void wxTopLevelWindowGTK::RemoveGrab()
964 {
965 if (m_grabbed)
966 {
967 gtk_main_quit();
968 m_grabbed = FALSE;
969 }
970 }
971
972 // vi:sts=4:sw=4:et