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