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