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