GTK+ callbacks must have C linkage (patch 1157384)
[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 (style & wxFRAME_TOOL_WINDOW)
476 {
477 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
478 GDK_WINDOW_TYPE_HINT_UTILITY);
479
480 // On some WMs, like KDE, a TOOL_WINDOW will still show
481 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
482 // For consistency between WMs and with Windows, we
483 // should set the NO_TASKBAR flag which will apply
484 // the set_skip_taskbar_hint if it is available,
485 // ensuring no taskbar entry will appear.
486 style |= wxFRAME_NO_TASKBAR;
487 }
488 #endif
489
490 }
491 }
492
493 wxWindow *topParent = wxGetTopLevelParent(m_parent);
494 if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
495 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
496 (style & wxFRAME_FLOAT_ON_PARENT)))
497 {
498 gtk_window_set_transient_for( GTK_WINDOW(m_widget),
499 GTK_WINDOW(topParent->m_widget) );
500 }
501
502 #if GTK_CHECK_VERSION(2,2,0)
503 if (style & wxFRAME_NO_TASKBAR)
504 {
505 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
506 }
507 #endif
508
509 if (!name.IsEmpty())
510 gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
511
512 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
513 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
514
515 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
516 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
517
518 // m_mainWidget holds the toolbar, the menubar and the client area
519 m_mainWidget = gtk_pizza_new();
520 gtk_widget_show( m_mainWidget );
521 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
522 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
523
524 if (m_miniEdge == 0) // wxMiniFrame has its own version.
525 {
526 // For m_mainWidget themes
527 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
528 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
529 #ifndef __WXGTK20__
530 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
531 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
532 #endif
533 }
534
535 // m_wxwindow only represents the client area without toolbar and menubar
536 m_wxwindow = gtk_pizza_new();
537 gtk_widget_show( m_wxwindow );
538 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
539
540 // we donm't allow the frame to get the focus as otherwise
541 // the frame will grab it at arbitrary focus changes
542 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
543
544 if (m_parent) m_parent->AddChild( this );
545
546 // the user resized the frame by dragging etc.
547 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
548 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
549
550 PostCreation();
551
552 if ((m_x != -1) || (m_y != -1))
553 gtk_widget_set_uposition( m_widget, m_x, m_y );
554
555 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
556
557 // we cannot set MWM hints and icons before the widget has
558 // been realized, so we do this directly after realization
559 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
560 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
561
562 // the only way to get the window size is to connect to this event
563 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
564 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
565
566 // map and unmap for iconized state
567 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
568 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
569 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
570 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
571
572 // the only way to get the window size is to connect to this event
573 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
574 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
575
576 // disable native tab traversal
577 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
578 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
579
580 // activation
581 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
582 GTK_SIGNAL_FUNC(gtk_frame_focus_in_callback), (gpointer)this );
583 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
584 GTK_SIGNAL_FUNC(gtk_frame_focus_out_callback), (gpointer)this );
585
586 // decorations
587 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
588 {
589 m_gdkDecor = 0;
590 m_gdkFunc = 0;
591 }
592 else
593 {
594 m_gdkDecor = (long) GDK_DECOR_BORDER;
595 m_gdkFunc = (long) GDK_FUNC_MOVE;
596
597 // All this is for Motif Window Manager "hints" and is supposed to be
598 // recognized by other WMs as well.
599 if ((style & wxCAPTION) != 0)
600 {
601 m_gdkDecor |= GDK_DECOR_TITLE;
602 }
603 if ((style & wxCLOSE_BOX) != 0)
604 {
605 m_gdkFunc |= GDK_FUNC_CLOSE;
606 }
607 if ((style & wxSYSTEM_MENU) != 0)
608 {
609 m_gdkDecor |= GDK_DECOR_MENU;
610 }
611 if ((style & wxMINIMIZE_BOX) != 0)
612 {
613 m_gdkFunc |= GDK_FUNC_MINIMIZE;
614 m_gdkDecor |= GDK_DECOR_MINIMIZE;
615 }
616 if ((style & wxMAXIMIZE_BOX) != 0)
617 {
618 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
619 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
620 }
621 if ((style & wxRESIZE_BORDER) != 0)
622 {
623 m_gdkFunc |= GDK_FUNC_RESIZE;
624 m_gdkDecor |= GDK_DECOR_RESIZEH;
625 }
626 }
627
628 return TRUE;
629 }
630
631 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
632 {
633 if (m_grabbed)
634 {
635 wxASSERT_MSG( FALSE, _T("Window still grabbed"));
636 RemoveGrab();
637 }
638
639 m_isBeingDeleted = TRUE;
640
641 // it may also be GtkScrolledWindow in the case of an MDI child
642 if (GTK_IS_WINDOW(m_widget))
643 {
644 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
645 }
646
647 if (g_activeFrame == this)
648 g_activeFrame = NULL;
649 if (g_lastActiveFrame == this)
650 g_lastActiveFrame = NULL;
651 }
652
653
654
655 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
656 {
657 if (show == m_fsIsShowing)
658 return FALSE; // return what?
659
660 m_fsIsShowing = show;
661
662 wxX11FullScreenMethod method =
663 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
664 (WXWindow)GDK_ROOT_WINDOW());
665
666 #if GTK_CHECK_VERSION(2,2,0)
667 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
668 // to switch to fullscreen, which is not always available. We must
669 // check if WM supports the spec and use legacy methods if it
670 // doesn't.
671 if (method == wxX11_FS_WMSPEC)
672 {
673 if (show)
674 gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
675 else
676 gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
677
678 return TRUE;
679 }
680 else
681 #endif // GTK+ >= 2.2.0
682 {
683 GdkWindow *window = m_widget->window;
684
685 if (show)
686 {
687 m_fsSaveFlag = style;
688 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
689 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
690
691 int screen_width,screen_height;
692 wxDisplaySize( &screen_width, &screen_height );
693
694 gint client_x, client_y, root_x, root_y;
695 gint width, height;
696
697 if (method != wxX11_FS_WMSPEC)
698 {
699 // don't do it always, Metacity hates it
700 m_fsSaveGdkFunc = m_gdkFunc;
701 m_fsSaveGdkDecor = m_gdkDecor;
702 m_gdkFunc = m_gdkDecor = 0;
703 gdk_window_set_decorations(window, (GdkWMDecoration)0);
704 gdk_window_set_functions(window, (GdkWMFunction)0);
705 }
706
707 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
708 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
709 &width, &height, NULL);
710
711 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
712 screen_width + 1, screen_height + 1);
713
714 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
715 (WXWindow)GDK_ROOT_WINDOW(),
716 (WXWindow)GDK_WINDOW_XWINDOW(window),
717 show, &m_fsSaveFrame, method);
718 }
719 else
720 {
721 if (method != wxX11_FS_WMSPEC)
722 {
723 // don't do it always, Metacity hates it
724 m_gdkFunc = m_fsSaveGdkFunc;
725 m_gdkDecor = m_fsSaveGdkDecor;
726 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
727 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
728 }
729
730 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
731 (WXWindow)GDK_ROOT_WINDOW(),
732 (WXWindow)GDK_WINDOW_XWINDOW(window),
733 show, &m_fsSaveFrame, method);
734
735 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
736 m_fsSaveFrame.width, m_fsSaveFrame.height);
737 }
738 }
739
740 return TRUE;
741 }
742
743 // ----------------------------------------------------------------------------
744 // overridden wxWindow methods
745 // ----------------------------------------------------------------------------
746
747 bool wxTopLevelWindowGTK::Show( bool show )
748 {
749 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
750
751 if (show && !m_sizeSet)
752 {
753 /* by calling GtkOnSize here, we don't have to call
754 either after showing the frame, which would entail
755 much ugly flicker or from within the size_allocate
756 handler, because GTK 1.1.X forbids that. */
757
758 GtkOnSize( m_x, m_y, m_width, m_height );
759 }
760
761 if (show)
762 gtk_widget_set_uposition( m_widget, m_x, m_y );
763
764 return wxWindow::Show( show );
765 }
766
767 void wxTopLevelWindowGTK::Raise()
768 {
769 #ifdef __WXGTK20__
770 gtk_window_present( GTK_WINDOW( m_widget ) );
771 #else
772 wxWindow::Raise();
773 #endif
774 }
775
776 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
777 {
778 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
779 }
780
781 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
782 {
783 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
784
785 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
786 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
787
788 // avoid recursions
789 if (m_resizing)
790 return;
791 m_resizing = TRUE;
792
793 int old_x = m_x;
794 int old_y = m_y;
795
796 int old_width = m_width;
797 int old_height = m_height;
798
799 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
800 {
801 if (x != -1) m_x = x;
802 if (y != -1) m_y = y;
803 }
804 else
805 {
806 m_x = x;
807 m_y = y;
808 }
809 if (width != -1) m_width = width;
810 if (height != -1) m_height = height;
811
812 /*
813 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
814 {
815 if (width == -1) m_width = 80;
816 }
817
818 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
819 {
820 if (height == -1) m_height = 26;
821 }
822 */
823
824 int minWidth = GetMinWidth(),
825 minHeight = GetMinHeight(),
826 maxWidth = GetMaxWidth(),
827 maxHeight = GetMaxHeight();
828
829 #ifdef __WXGPE__
830 // GPE's window manager doesn't like size hints
831 // at all, esp. when the user has to use the
832 // virtual keyboard.
833 minWidth = -1;
834 minHeight = -1;
835 maxWidth = -1;
836 maxHeight = -1;
837 #endif
838
839 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
840 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
841 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
842 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
843
844 if ((m_x != -1) || (m_y != -1))
845 {
846 if ((m_x != old_x) || (m_y != old_y))
847 {
848 gtk_widget_set_uposition( m_widget, m_x, m_y );
849 }
850 }
851
852 if ((m_width != old_width) || (m_height != old_height))
853 {
854 if (m_widget->window)
855 gdk_window_resize( m_widget->window, m_width, m_height );
856 else
857 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
858
859 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
860 done either directly before the frame is shown or in idle time
861 so that different calls to SetSize() don't lead to flicker. */
862 m_sizeSet = FALSE;
863 }
864
865 m_resizing = FALSE;
866 }
867
868 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
869 {
870 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
871
872 wxWindow::DoGetClientSize( width, height );
873 if (height)
874 {
875 // mini edge
876 *height -= m_miniEdge*2 + m_miniTitle;
877 }
878 if (width)
879 {
880 *width -= m_miniEdge*2;
881 }
882 }
883
884 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
885 {
886 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
887
888 DoSetSize(-1, -1,
889 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
890 }
891
892 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
893 int width, int height )
894 {
895 // due to a bug in gtk, x,y are always 0
896 // m_x = x;
897 // m_y = y;
898
899 // avoid recursions
900 if (m_resizing) return;
901 m_resizing = TRUE;
902
903 if ( m_wxwindow == NULL ) return;
904
905 m_width = width;
906 m_height = height;
907
908 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
909 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
910 set in wxFrame::Create so it is used to check what kind of frame we
911 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
912 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
913 importantly) m_mainWidget */
914
915 int minWidth = GetMinWidth(),
916 minHeight = GetMinHeight(),
917 maxWidth = GetMaxWidth(),
918 maxHeight = GetMaxHeight();
919
920 #ifdef __WXGPE__
921 // GPE's window manager doesn't like size hints
922 // at all, esp. when the user has to use the
923 // virtual keyboard.
924 minWidth = -1;
925 minHeight = -1;
926 maxWidth = -1;
927 maxHeight = -1;
928 #endif
929
930 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
931 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
932 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
933 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
934
935 if (m_mainWidget)
936 {
937 // set size hints
938 gint flag = 0; // GDK_HINT_POS;
939 GdkGeometry geom;
940
941 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
942 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
943
944 geom.min_width = minWidth;
945 geom.min_height = minHeight;
946
947 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
948 // maxHeight or maxWidth is set, we must set them both, else the
949 // remaining -1 will be taken literally.
950
951 // I'm certain this also happens elsewhere, and is the probable
952 // cause of other such things as:
953 // Gtk-WARNING **: gtk_widget_size_allocate():
954 // attempt to allocate widget with width 65535 and height 600
955 // but I don't have time to track them all now..
956 //
957 // Really we need to encapulate all this height/width business and
958 // stop any old method from ripping at the members directly and
959 // scattering -1's without regard for who might resolve them later.
960
961 geom.max_width = ( maxHeight == -1 ) ? maxWidth
962 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
963 : maxWidth ;
964
965 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
966 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
967 : maxHeight ;
968
969 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
970 (GtkWidget*) NULL,
971 &geom,
972 (GdkWindowHints) flag );
973
974 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
975 * menubar, the toolbar and the client area, which is represented by
976 * m_wxwindow.
977 * this hurts in the eye, but I don't want to call SetSize()
978 * because I don't want to call any non-native functions here. */
979
980 int client_x = m_miniEdge;
981 int client_y = m_miniEdge + m_miniTitle;
982 int client_w = m_width - 2*m_miniEdge;
983 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
984
985 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
986 m_wxwindow,
987 client_x, client_y, client_w, client_h );
988 }
989 else
990 {
991 // If there is no m_mainWidget between m_widget and m_wxwindow there
992 // is no need to set the size or position of m_wxwindow.
993 }
994
995 m_sizeSet = TRUE;
996
997 // send size event to frame
998 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
999 event.SetEventObject( this );
1000 GetEventHandler()->ProcessEvent( event );
1001
1002 m_resizing = FALSE;
1003 }
1004
1005 void wxTopLevelWindowGTK::OnInternalIdle()
1006 {
1007 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
1008 {
1009 GtkOnSize( m_x, m_y, m_width, m_height );
1010
1011 // we'll come back later
1012 if (g_isIdle)
1013 wxapp_install_idle_handler();
1014 return;
1015 }
1016
1017 // set the focus if not done yet and if we can already do it
1018 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
1019 {
1020 if ( g_delayedFocus &&
1021 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
1022 {
1023 wxLogTrace(_T("focus"),
1024 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1025 g_delayedFocus->GetClassInfo()->GetClassName(),
1026 g_delayedFocus->GetLabel().c_str());
1027
1028 g_delayedFocus->SetFocus();
1029 g_delayedFocus = NULL;
1030 }
1031 }
1032
1033 wxWindow::OnInternalIdle();
1034
1035 // Synthetize activate events.
1036 if ( g_sendActivateEvent != -1 )
1037 {
1038 bool activate = g_sendActivateEvent != 0;
1039
1040 // if (!activate) wxPrintf( wxT("de") );
1041 // wxPrintf( wxT("activate\n") );
1042
1043 // do it only once
1044 g_sendActivateEvent = -1;
1045
1046 wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
1047 }
1048 }
1049
1050 // ----------------------------------------------------------------------------
1051 // frame title/icon
1052 // ----------------------------------------------------------------------------
1053
1054 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
1055 {
1056 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1057
1058 m_title = title;
1059 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
1060 }
1061
1062 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
1063 {
1064 SetIcons( wxIconBundle( icon ) );
1065 }
1066
1067 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
1068 {
1069 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1070
1071 wxTopLevelWindowBase::SetIcons( icons );
1072
1073 #ifdef __WXGTK20__
1074 GList *list = NULL;
1075 size_t max = icons.m_icons.GetCount();
1076
1077 for (size_t i = 0; i < max; i++)
1078 {
1079 if (icons.m_icons[i].Ok())
1080 {
1081 list = g_list_prepend(list, icons.m_icons[i].GetPixbuf());
1082 }
1083 }
1084 gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
1085 g_list_free(list);
1086
1087 #else // !__WXGTK20__
1088 GdkWindow* window = m_widget->window;
1089 if (!window)
1090 return;
1091
1092 wxIcon icon = icons.GetIcon(-1);
1093 if (icon.Ok())
1094 {
1095 wxMask *mask = icon.GetMask();
1096 GdkBitmap *bm = (GdkBitmap *) NULL;
1097 if (mask) bm = mask->GetBitmap();
1098
1099 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
1100 }
1101
1102 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
1103 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
1104 #endif // !__WXGTK20__
1105 }
1106
1107 // ----------------------------------------------------------------------------
1108 // frame state: maximized/iconized/normal
1109 // ----------------------------------------------------------------------------
1110
1111 void wxTopLevelWindowGTK::Maximize(bool maximize)
1112 {
1113 #ifdef __WXGTK20__
1114 if (maximize)
1115 gtk_window_maximize( GTK_WINDOW( m_widget ) );
1116 else
1117 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
1118 #else
1119 wxFAIL_MSG( _T("not implemented") );
1120 #endif
1121 }
1122
1123 bool wxTopLevelWindowGTK::IsMaximized() const
1124 {
1125 #ifdef __WXGTK20__
1126 if(!m_widget->window)
1127 return false;
1128
1129 return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
1130 #else
1131 // wxFAIL_MSG( _T("not implemented") );
1132
1133 // This is an approximation
1134 return FALSE;
1135 #endif
1136 }
1137
1138 void wxTopLevelWindowGTK::Restore()
1139 {
1140 #ifdef __WXGTK20__
1141 // "Present" seems similar enough to "restore"
1142 gtk_window_present( GTK_WINDOW( m_widget ) );
1143 #else
1144 wxFAIL_MSG( _T("not implemented") );
1145 #endif
1146 }
1147
1148 void wxTopLevelWindowGTK::Iconize( bool iconize )
1149 {
1150 #ifdef __WXGTK20__
1151 if (iconize)
1152 gtk_window_iconify( GTK_WINDOW( m_widget ) );
1153 else
1154 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
1155 #else
1156 if (iconize)
1157 {
1158 GdkWindow *window = m_widget->window;
1159
1160 // you should do it later, for example from OnCreate() handler
1161 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
1162
1163 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
1164 GDK_WINDOW_XWINDOW( window ),
1165 DefaultScreen( GDK_DISPLAY() ) );
1166 }
1167 #endif
1168 }
1169
1170 bool wxTopLevelWindowGTK::IsIconized() const
1171 {
1172 return m_isIconized;
1173 }
1174
1175 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
1176 {
1177 if ( iconize != m_isIconized )
1178 {
1179 m_isIconized = iconize;
1180 (void)SendIconizeEvent(iconize);
1181 }
1182 }
1183
1184 void wxTopLevelWindowGTK::AddGrab()
1185 {
1186 if (!m_grabbed)
1187 {
1188 m_grabbed = TRUE;
1189 gtk_grab_add( m_widget );
1190 gtk_main();
1191 gtk_grab_remove( m_widget );
1192 }
1193 }
1194
1195 void wxTopLevelWindowGTK::RemoveGrab()
1196 {
1197 if (m_grabbed)
1198 {
1199 gtk_main_quit();
1200 m_grabbed = FALSE;
1201 }
1202 }
1203
1204
1205 // helper
1206 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
1207 {
1208 if (window)
1209 {
1210 if (region.IsEmpty())
1211 {
1212 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1213 }
1214 else
1215 {
1216 #ifdef __WXGTK20__
1217 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
1218 #else
1219 wxBitmap bmp = region.ConvertToBitmap();
1220 bmp.SetMask(new wxMask(bmp, *wxBLACK));
1221 GdkBitmap* mask = bmp.GetMask()->GetBitmap();
1222 gdk_window_shape_combine_mask(window, mask, 0, 0);
1223 #endif
1224 return TRUE;
1225 }
1226 }
1227 return FALSE;
1228 }
1229
1230
1231 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1232 {
1233 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE,
1234 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1235
1236 GdkWindow *window = NULL;
1237 if (m_wxwindow)
1238 {
1239 window = GTK_PIZZA(m_wxwindow)->bin_window;
1240 do_shape_combine_region(window, region);
1241 }
1242 window = m_widget->window;
1243 return do_shape_combine_region(window, region);
1244 }
1245
1246 bool wxTopLevelWindowGTK::IsActive()
1247 {
1248 return (this == (wxTopLevelWindowGTK*)g_activeFrame);
1249 }
1250