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