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