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