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