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