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