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