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