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