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