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