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