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