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