]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/toplevel.cpp
Test the commit announcement bot some more by fixing more gtk signal callback handler...
[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 gboolean 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 gboolean 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 g_source_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 gboolean 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 gboolean 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 gboolean
269 gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget),
270 GdkEvent *WXUNUSED(event),
271 wxTopLevelWindowGTK *win )
272 {
273 if (g_isIdle)
274 wxapp_install_idle_handler();
275
276 if (win->IsEnabled() &&
277 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
278 win->IsGrabbed()))
279 win->Close();
280
281 return TRUE;
282 }
283 }
284
285
286 //-----------------------------------------------------------------------------
287 // "configure_event"
288 //-----------------------------------------------------------------------------
289
290 extern "C" {
291 static gboolean
292 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget),
293 GdkEventConfigure *WXUNUSED(event),
294 wxTopLevelWindowGTK *win )
295 {
296 if (g_isIdle)
297 wxapp_install_idle_handler();
298
299 if (!win->m_hasVMT || !win->IsShown())
300 return FALSE;
301
302
303 int x = 0;
304 int y = 0;
305 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
306 win->m_x = x;
307 win->m_y = y;
308
309 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
310 mevent.SetEventObject( win );
311 win->GetEventHandler()->ProcessEvent( mevent );
312
313 return FALSE;
314 }
315 }
316
317 //-----------------------------------------------------------------------------
318 // "realize" from m_widget
319 //-----------------------------------------------------------------------------
320
321 // we cannot MWM hints and icons before the widget has been realized,
322 // so we do this directly after realization
323
324 extern "C" {
325 static void
326 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
327 wxTopLevelWindowGTK *win )
328 {
329 if (g_isIdle)
330 wxapp_install_idle_handler();
331
332 // All this is for Motif Window Manager "hints" and is supposed to be
333 // recognized by other WM as well. Not tested.
334 gdk_window_set_decorations(win->m_widget->window,
335 (GdkWMDecoration)win->m_gdkDecor);
336 gdk_window_set_functions(win->m_widget->window,
337 (GdkWMFunction)win->m_gdkFunc);
338
339 // GTK's shrinking/growing policy
340 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
341 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
342 else
343 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
344
345 // reset the icon
346 wxIconBundle iconsOld = win->GetIcons();
347 if ( iconsOld.GetIcon(-1).Ok() )
348 {
349 win->SetIcon( wxNullIcon );
350 win->SetIcons( iconsOld );
351 }
352 }
353 }
354
355 //-----------------------------------------------------------------------------
356 // "map_event" from m_widget
357 //-----------------------------------------------------------------------------
358
359 extern "C" {
360 static void
361 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
362 GdkEvent * WXUNUSED(event),
363 wxTopLevelWindow *win )
364 {
365 win->SetIconizeState(false);
366 }
367 }
368
369 //-----------------------------------------------------------------------------
370 // "unmap_event" from m_widget
371 //-----------------------------------------------------------------------------
372
373 extern "C" {
374 static void
375 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
376 GdkEvent * WXUNUSED(event),
377 wxTopLevelWindow *win )
378 {
379 win->SetIconizeState(true);
380 }
381 }
382
383 //-----------------------------------------------------------------------------
384 // "expose_event" of m_client
385 //-----------------------------------------------------------------------------
386
387 extern "C" {
388 static gboolean
389 gtk_window_expose_callback( GtkWidget *widget,
390 GdkEventExpose *gdk_event,
391 wxWindow *win )
392 {
393 GtkPizza *pizza = GTK_PIZZA(widget);
394
395 gtk_paint_flat_box (win->m_widget->style,
396 pizza->bin_window, GTK_STATE_NORMAL,
397 GTK_SHADOW_NONE,
398 &gdk_event->area,
399 win->m_widget,
400 (char *)"base",
401 0, 0, -1, -1);
402
403 return FALSE;
404 }
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxTopLevelWindowGTK itself
409 // ----------------------------------------------------------------------------
410
411 //-----------------------------------------------------------------------------
412 // InsertChild for wxTopLevelWindowGTK
413 //-----------------------------------------------------------------------------
414
415 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
416 * C++ has no virtual methods in a constructor. We have to emulate a
417 * virtual function here as wxWidgets requires different ways to insert
418 * a child in container classes. */
419
420 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
421 {
422 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
423
424 if (!parent->m_insertInClientArea)
425 {
426 // these are outside the client area
427 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
428 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
429 GTK_WIDGET(child->m_widget),
430 child->m_x,
431 child->m_y,
432 child->m_width,
433 child->m_height );
434 }
435 else
436 {
437 // these are inside the client area
438 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
439 GTK_WIDGET(child->m_widget),
440 child->m_x,
441 child->m_y,
442 child->m_width,
443 child->m_height );
444 }
445
446 // resize on OnInternalIdle
447 parent->GtkUpdateSize();
448 }
449
450 // ----------------------------------------------------------------------------
451 // wxTopLevelWindowGTK creation
452 // ----------------------------------------------------------------------------
453
454 void wxTopLevelWindowGTK::Init()
455 {
456 m_sizeSet = false;
457 m_miniEdge = 0;
458 m_miniTitle = 0;
459 m_mainWidget = (GtkWidget*) NULL;
460 m_insertInClientArea = true;
461 m_isIconized = false;
462 m_fsIsShowing = false;
463 m_themeEnabled = true;
464 m_gdkDecor = m_gdkFunc = 0;
465 m_grabbed = false;
466
467 m_urgency_hint = -2;
468 }
469
470 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
471 wxWindowID id,
472 const wxString& title,
473 const wxPoint& pos,
474 const wxSize& sizeOrig,
475 long style,
476 const wxString &name )
477 {
478 // always create a frame of some reasonable, even if arbitrary, size (at
479 // least for MSW compatibility)
480 wxSize size = sizeOrig;
481 size.x = WidthDefault(size.x);
482 size.y = HeightDefault(size.y);
483
484 wxTopLevelWindows.Append( this );
485
486 m_needParent = false;
487
488 if (!PreCreation( parent, pos, size ) ||
489 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
490 {
491 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
492 return false;
493 }
494
495 m_title = title;
496
497 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
498
499 // NB: m_widget may be !=NULL if it was created by derived class' Create,
500 // e.g. in wxTaskBarIconAreaGTK
501 if (m_widget == NULL)
502 {
503 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
504 {
505 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
506 // Tell WM that this is a dialog window and make it center
507 // on parent by default (this is what GtkDialog ctor does):
508 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
509 GDK_WINDOW_TYPE_HINT_DIALOG);
510 gtk_window_set_position(GTK_WINDOW(m_widget),
511 GTK_WIN_POS_CENTER_ON_PARENT);
512 }
513 else
514 {
515 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
516 #if GTK_CHECK_VERSION(2,1,0)
517 if (!gtk_check_version(2,1,0))
518 {
519 if (style & wxFRAME_TOOL_WINDOW)
520 {
521 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
522 GDK_WINDOW_TYPE_HINT_UTILITY);
523
524 // On some WMs, like KDE, a TOOL_WINDOW will still show
525 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
526 // For consistency between WMs and with Windows, we
527 // should set the NO_TASKBAR flag which will apply
528 // the set_skip_taskbar_hint if it is available,
529 // ensuring no taskbar entry will appear.
530 style |= wxFRAME_NO_TASKBAR;
531 }
532 }
533 #endif
534 }
535 }
536
537 wxWindow *topParent = wxGetTopLevelParent(m_parent);
538 if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
539 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
540 (style & wxFRAME_FLOAT_ON_PARENT)))
541 {
542 gtk_window_set_transient_for( GTK_WINDOW(m_widget),
543 GTK_WINDOW(topParent->m_widget) );
544 }
545
546 #if GTK_CHECK_VERSION(2,2,0)
547 if (!gtk_check_version(2,2,0))
548 {
549 if (style & wxFRAME_NO_TASKBAR)
550 {
551 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
552 }
553 }
554 #endif
555
556 #ifdef __WXGTK24__
557 if (!gtk_check_version(2,4,0))
558 {
559 if (style & wxSTAY_ON_TOP)
560 {
561 gtk_window_set_keep_above(GTK_WINDOW(m_widget), TRUE);
562 }
563 }
564 #endif
565
566 if (!name.empty())
567 gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
568
569 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
570 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
571
572 g_signal_connect (m_widget, "delete_event",
573 G_CALLBACK (gtk_frame_delete_callback), this);
574
575 // m_mainWidget holds the toolbar, the menubar and the client area
576 m_mainWidget = gtk_pizza_new();
577 gtk_widget_show( m_mainWidget );
578 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
579 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
580
581 if (m_miniEdge == 0) // wxMiniFrame has its own version.
582 {
583 // For m_mainWidget themes
584 g_signal_connect (m_mainWidget, "expose_event",
585 G_CALLBACK (gtk_window_expose_callback), this);
586 }
587
588 // m_wxwindow only represents the client area without toolbar and menubar
589 m_wxwindow = gtk_pizza_new();
590 gtk_widget_show( m_wxwindow );
591 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
592
593 // we donm't allow the frame to get the focus as otherwise
594 // the frame will grab it at arbitrary focus changes
595 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
596
597 if (m_parent) m_parent->AddChild( this );
598
599 // the user resized the frame by dragging etc.
600 g_signal_connect (m_widget, "size_allocate",
601 G_CALLBACK (gtk_frame_size_callback), this);
602
603 PostCreation();
604
605 if ((m_x != -1) || (m_y != -1))
606 gtk_widget_set_uposition( m_widget, m_x, m_y );
607
608 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
609
610 // we cannot set MWM hints and icons before the widget has
611 // been realized, so we do this directly after realization
612 g_signal_connect (m_widget, "realize",
613 G_CALLBACK (gtk_frame_realized_callback), this);
614
615 // map and unmap for iconized state
616 g_signal_connect (m_widget, "map_event",
617 G_CALLBACK (gtk_frame_map_callback), this);
618 g_signal_connect (m_widget, "unmap_event",
619 G_CALLBACK (gtk_frame_unmap_callback), this);
620
621 // the only way to get the window size is to connect to this event
622 g_signal_connect (m_widget, "configure_event",
623 G_CALLBACK (gtk_frame_configure_callback), this);
624
625 // disable native tab traversal
626 g_signal_connect (m_widget, "focus",
627 G_CALLBACK (gtk_frame_focus_callback), this);
628
629 // activation
630 g_signal_connect_after (m_widget, "focus_in_event",
631 G_CALLBACK (gtk_frame_focus_in_callback), this);
632 g_signal_connect_after (m_widget, "focus_out_event",
633 G_CALLBACK (gtk_frame_focus_out_callback), this);
634
635 // decorations
636 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
637 {
638 m_gdkDecor = 0;
639 m_gdkFunc = 0;
640 }
641 else
642 {
643 m_gdkDecor = (long) GDK_DECOR_BORDER;
644 m_gdkFunc = (long) GDK_FUNC_MOVE;
645
646 // All this is for Motif Window Manager "hints" and is supposed to be
647 // recognized by other WMs as well.
648 if ((style & wxCAPTION) != 0)
649 {
650 m_gdkDecor |= GDK_DECOR_TITLE;
651 }
652 if ((style & wxCLOSE_BOX) != 0)
653 {
654 m_gdkFunc |= GDK_FUNC_CLOSE;
655 }
656 if ((style & wxSYSTEM_MENU) != 0)
657 {
658 m_gdkDecor |= GDK_DECOR_MENU;
659 }
660 if ((style & wxMINIMIZE_BOX) != 0)
661 {
662 m_gdkFunc |= GDK_FUNC_MINIMIZE;
663 m_gdkDecor |= GDK_DECOR_MINIMIZE;
664 }
665 if ((style & wxMAXIMIZE_BOX) != 0)
666 {
667 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
668 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
669 }
670 if ((style & wxRESIZE_BORDER) != 0)
671 {
672 m_gdkFunc |= GDK_FUNC_RESIZE;
673 m_gdkDecor |= GDK_DECOR_RESIZEH;
674 }
675 }
676
677 return true;
678 }
679
680 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
681 {
682 if (m_grabbed)
683 {
684 wxASSERT_MSG( false, _T("Window still grabbed"));
685 RemoveGrab();
686 }
687
688 m_isBeingDeleted = true;
689
690 // it may also be GtkScrolledWindow in the case of an MDI child
691 if (GTK_IS_WINDOW(m_widget))
692 {
693 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
694 }
695
696 if (g_activeFrame == this)
697 g_activeFrame = NULL;
698 if (g_lastActiveFrame == this)
699 g_lastActiveFrame = NULL;
700 }
701
702
703
704 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
705 {
706 if (show == m_fsIsShowing)
707 return false; // return what?
708
709 m_fsIsShowing = show;
710
711 wxX11FullScreenMethod method =
712 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
713 (WXWindow)GDK_ROOT_WINDOW());
714
715 #if GTK_CHECK_VERSION(2,2,0)
716 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
717 // to switch to fullscreen, which is not always available. We must
718 // check if WM supports the spec and use legacy methods if it
719 // doesn't.
720 if ( (method == wxX11_FS_WMSPEC) && !gtk_check_version(2,2,0) )
721 {
722 if (show)
723 gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
724 else
725 gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
726 }
727 else
728 #endif // GTK+ >= 2.2.0
729 {
730 GdkWindow *window = m_widget->window;
731
732 if (show)
733 {
734 m_fsSaveFlag = style;
735 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
736 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
737
738 int screen_width,screen_height;
739 wxDisplaySize( &screen_width, &screen_height );
740
741 gint client_x, client_y, root_x, root_y;
742 gint width, height;
743
744 if (method != wxX11_FS_WMSPEC)
745 {
746 // don't do it always, Metacity hates it
747 m_fsSaveGdkFunc = m_gdkFunc;
748 m_fsSaveGdkDecor = m_gdkDecor;
749 m_gdkFunc = m_gdkDecor = 0;
750 gdk_window_set_decorations(window, (GdkWMDecoration)0);
751 gdk_window_set_functions(window, (GdkWMFunction)0);
752 }
753
754 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
755 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
756 &width, &height, NULL);
757
758 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
759 screen_width + 1, screen_height + 1);
760
761 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
762 (WXWindow)GDK_ROOT_WINDOW(),
763 (WXWindow)GDK_WINDOW_XWINDOW(window),
764 show, &m_fsSaveFrame, method);
765 }
766 else // hide
767 {
768 if (method != wxX11_FS_WMSPEC)
769 {
770 // don't do it always, Metacity hates it
771 m_gdkFunc = m_fsSaveGdkFunc;
772 m_gdkDecor = m_fsSaveGdkDecor;
773 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
774 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
775 }
776
777 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
778 (WXWindow)GDK_ROOT_WINDOW(),
779 (WXWindow)GDK_WINDOW_XWINDOW(window),
780 show, &m_fsSaveFrame, method);
781
782 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
783 m_fsSaveFrame.width, m_fsSaveFrame.height);
784 }
785 }
786
787 // documented behaviour is to show the window if it's still hidden when
788 // showing it full screen
789 if ( show && !IsShown() )
790 Show();
791
792 return true;
793 }
794
795 // ----------------------------------------------------------------------------
796 // overridden wxWindow methods
797 // ----------------------------------------------------------------------------
798
799 bool wxTopLevelWindowGTK::Show( bool show )
800 {
801 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
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( m_x, m_y, m_width, m_height );
811 }
812
813 if (show)
814 gtk_widget_set_uposition( m_widget, m_x, m_y );
815
816 return wxWindow::Show( show );
817 }
818
819 void wxTopLevelWindowGTK::Raise()
820 {
821 gtk_window_present( GTK_WINDOW( m_widget ) );
822 }
823
824 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
825 {
826 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
827 }
828
829 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
830 {
831 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
832
833 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
834 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
835
836 // avoid recursions
837 if (m_resizing)
838 return;
839 m_resizing = true;
840
841 int old_x = m_x;
842 int old_y = m_y;
843
844 int old_width = m_width;
845 int old_height = m_height;
846
847 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
848 {
849 if (x != -1) m_x = x;
850 if (y != -1) m_y = y;
851 }
852 else
853 {
854 m_x = x;
855 m_y = y;
856 }
857 if (width != -1) m_width = width;
858 if (height != -1) m_height = height;
859
860 /*
861 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
862 {
863 if (width == -1) m_width = 80;
864 }
865
866 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
867 {
868 if (height == -1) m_height = 26;
869 }
870 */
871
872 int minWidth = GetMinWidth(),
873 minHeight = GetMinHeight(),
874 maxWidth = GetMaxWidth(),
875 maxHeight = GetMaxHeight();
876
877 #ifdef __WXGPE__
878 // GPE's window manager doesn't like size hints
879 // at all, esp. when the user has to use the
880 // virtual keyboard.
881 minWidth = -1;
882 minHeight = -1;
883 maxWidth = -1;
884 maxHeight = -1;
885 #endif
886
887 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
888 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
889 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
890 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
891
892 if ((m_x != -1) || (m_y != -1))
893 {
894 if ((m_x != old_x) || (m_y != old_y))
895 {
896 gtk_widget_set_uposition( m_widget, m_x, m_y );
897 }
898 }
899
900 if ((m_width != old_width) || (m_height != old_height))
901 {
902 if (m_widget->window)
903 gdk_window_resize( m_widget->window, m_width, m_height );
904 else
905 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
906
907 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
908 done either directly before the frame is shown or in idle time
909 so that different calls to SetSize() don't lead to flicker. */
910 m_sizeSet = false;
911 }
912
913 m_resizing = false;
914 }
915
916 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
917 {
918 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
919
920 wxWindow::DoGetClientSize( width, height );
921 if (height)
922 {
923 // mini edge
924 *height -= m_miniEdge*2 + m_miniTitle;
925 }
926 if (width)
927 {
928 *width -= m_miniEdge*2;
929 }
930 }
931
932 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
933 {
934 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
935
936 DoSetSize(-1, -1,
937 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
938 }
939
940 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
941 int width, int height )
942 {
943 // due to a bug in gtk, x,y are always 0
944 // m_x = x;
945 // m_y = y;
946
947 // avoid recursions
948 if (m_resizing) return;
949 m_resizing = true;
950
951 if ( m_wxwindow == NULL ) return;
952
953 m_width = width;
954 m_height = height;
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
1033 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
1034 m_wxwindow,
1035 client_x, client_y, client_w, client_h );
1036 }
1037 else
1038 {
1039 // If there is no m_mainWidget between m_widget and m_wxwindow there
1040 // is no need to set the size or position of m_wxwindow.
1041 }
1042
1043 m_sizeSet = true;
1044
1045 // send size event to frame
1046 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
1047 event.SetEventObject( this );
1048 GetEventHandler()->ProcessEvent( event );
1049
1050 m_resizing = false;
1051 }
1052
1053 void wxTopLevelWindowGTK::OnInternalIdle()
1054 {
1055 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
1056 {
1057 GtkOnSize( m_x, m_y, m_width, m_height );
1058
1059 // we'll come back later
1060 if (g_isIdle)
1061 wxapp_install_idle_handler();
1062 return;
1063 }
1064
1065 // set the focus if not done yet and if we can already do it
1066 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
1067 {
1068 if ( g_delayedFocus &&
1069 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
1070 {
1071 wxLogTrace(_T("focus"),
1072 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1073 g_delayedFocus->GetClassInfo()->GetClassName(),
1074 g_delayedFocus->GetLabel().c_str());
1075
1076 g_delayedFocus->SetFocus();
1077 g_delayedFocus = NULL;
1078 }
1079 }
1080
1081 wxWindow::OnInternalIdle();
1082
1083 // Synthetize activate events.
1084 if ( g_sendActivateEvent != -1 )
1085 {
1086 bool activate = g_sendActivateEvent != 0;
1087
1088 // if (!activate) wxPrintf( wxT("de") );
1089 // wxPrintf( wxT("activate\n") );
1090
1091 // do it only once
1092 g_sendActivateEvent = -1;
1093
1094 wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
1095 }
1096 }
1097
1098 // ----------------------------------------------------------------------------
1099 // frame title/icon
1100 // ----------------------------------------------------------------------------
1101
1102 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
1103 {
1104 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1105
1106 if ( title == m_title )
1107 return;
1108
1109 m_title = title;
1110
1111 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
1112 }
1113
1114 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
1115 {
1116 SetIcons( wxIconBundle( icon ) );
1117 }
1118
1119 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
1120 {
1121 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1122
1123 wxTopLevelWindowBase::SetIcons( icons );
1124
1125 GList *list = NULL;
1126 size_t max = icons.m_icons.GetCount();
1127
1128 for (size_t i = 0; i < max; i++)
1129 {
1130 if (icons.m_icons[i].Ok())
1131 {
1132 list = g_list_prepend(list, icons.m_icons[i].GetPixbuf());
1133 }
1134 }
1135 gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
1136 g_list_free(list);
1137 }
1138
1139 // ----------------------------------------------------------------------------
1140 // frame state: maximized/iconized/normal
1141 // ----------------------------------------------------------------------------
1142
1143 void wxTopLevelWindowGTK::Maximize(bool maximize)
1144 {
1145 if (maximize)
1146 gtk_window_maximize( GTK_WINDOW( m_widget ) );
1147 else
1148 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
1149 }
1150
1151 bool wxTopLevelWindowGTK::IsMaximized() const
1152 {
1153 if(!m_widget->window)
1154 return false;
1155
1156 return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
1157 }
1158
1159 void wxTopLevelWindowGTK::Restore()
1160 {
1161 // "Present" seems similar enough to "restore"
1162 gtk_window_present( GTK_WINDOW( m_widget ) );
1163 }
1164
1165 void wxTopLevelWindowGTK::Iconize( bool iconize )
1166 {
1167 if (iconize)
1168 gtk_window_iconify( GTK_WINDOW( m_widget ) );
1169 else
1170 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
1171 }
1172
1173 bool wxTopLevelWindowGTK::IsIconized() const
1174 {
1175 return m_isIconized;
1176 }
1177
1178 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
1179 {
1180 if ( iconize != m_isIconized )
1181 {
1182 m_isIconized = iconize;
1183 (void)SendIconizeEvent(iconize);
1184 }
1185 }
1186
1187 void wxTopLevelWindowGTK::AddGrab()
1188 {
1189 if (!m_grabbed)
1190 {
1191 m_grabbed = true;
1192 gtk_grab_add( m_widget );
1193 wxEventLoop().Run();
1194 gtk_grab_remove( m_widget );
1195 }
1196 }
1197
1198 void wxTopLevelWindowGTK::RemoveGrab()
1199 {
1200 if (m_grabbed)
1201 {
1202 gtk_main_quit();
1203 m_grabbed = false;
1204 }
1205 }
1206
1207
1208 // helper
1209 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
1210 {
1211 if (window)
1212 {
1213 if (region.IsEmpty())
1214 {
1215 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1216 }
1217 else
1218 {
1219 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
1220 return true;
1221 }
1222 }
1223 return false;
1224 }
1225
1226
1227 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1228 {
1229 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
1230 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1231
1232 GdkWindow *window = NULL;
1233 if (m_wxwindow)
1234 {
1235 window = GTK_PIZZA(m_wxwindow)->bin_window;
1236 do_shape_combine_region(window, region);
1237 }
1238 window = m_widget->window;
1239 return do_shape_combine_region(window, region);
1240 }
1241
1242 bool wxTopLevelWindowGTK::IsActive()
1243 {
1244 return (this == (wxTopLevelWindowGTK*)g_activeFrame);
1245 }
1246
1247 void wxTopLevelWindowGTK::RequestUserAttention(int flags)
1248 {
1249 bool new_hint_value = false;
1250
1251 // FIXME: This is a workaround to focus handling problem
1252 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1253 // yet been processed, and the internal focus system is not up to date yet.
1254 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1255 ::wxYieldIfNeeded();
1256
1257 if(m_urgency_hint >= 0)
1258 g_source_remove(m_urgency_hint);
1259
1260 m_urgency_hint = -2;
1261
1262 if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() )
1263 {
1264 new_hint_value = true;
1265
1266 if (flags & wxUSER_ATTENTION_INFO)
1267 {
1268 m_urgency_hint = g_timeout_add(5000, (GSourceFunc)gtk_frame_urgency_timer_callback, this);
1269 } else {
1270 m_urgency_hint = -1;
1271 }
1272 }
1273
1274 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,7,0)
1275 if(!gtk_check_version(2,7,0))
1276 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1277 else
1278 #endif
1279 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1280 }
1281
1282 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style )
1283 {
1284 // Store which styles were changed
1285 long styleChanges = style ^ m_windowStyle;
1286
1287 // Process wxWindow styles. This also updates the internal variable
1288 // Therefore m_windowStyle bits carry now the _new_ style values
1289 wxWindow::SetWindowStyleFlag(style);
1290
1291 // just return for now if widget does not exist yet
1292 if (!m_widget)
1293 return;
1294
1295 #ifdef __WXGTK24__
1296 if ( (styleChanges & wxSTAY_ON_TOP) && !gtk_check_version(2,4,0) )
1297 gtk_window_set_keep_above(GTK_WINDOW(m_widget), m_windowStyle & wxSTAY_ON_TOP);
1298 #endif // GTK+ 2.4
1299 #if GTK_CHECK_VERSION(2,2,0)
1300 if ( (styleChanges & wxFRAME_NO_TASKBAR) && !gtk_check_version(2,2,0) )
1301 {
1302 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), m_windowStyle & wxFRAME_NO_TASKBAR);
1303 }
1304 #endif // GTK+ 2.2
1305 }