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