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