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