]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/toplevel.cpp
wxMenu::Append (and similar) now return a pointer to the wxMenuItem
[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
39 #include <glib.h>
40 #include <gdk/gdk.h>
41 #include <gtk/gtk.h>
42 #include <gdk/gdkkeysyms.h>
43 #include <gdk/gdkx.h>
44
45 #include "wx/gtk/win_gtk.h"
46
47 #include "wx/unix/utilsx11.h"
48
49 // XA_CARDINAL
50 #include <X11/Xatom.h>
51
52 // ----------------------------------------------------------------------------
53 // idle system
54 // ----------------------------------------------------------------------------
55
56 extern void wxapp_install_idle_handler();
57 extern bool g_isIdle;
58
59 // ----------------------------------------------------------------------------
60 // data
61 // ----------------------------------------------------------------------------
62
63 extern wxList wxPendingDelete;
64
65 extern int g_openDialogs;
66 extern wxWindowGTK *g_delayedFocus;
67
68 //-----------------------------------------------------------------------------
69 // "focus" from m_window
70 //-----------------------------------------------------------------------------
71
72 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
73 {
74 if (g_isIdle)
75 wxapp_install_idle_handler();
76
77 // This disables GTK's tab traversal
78 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
79 return TRUE;
80 }
81
82 //-----------------------------------------------------------------------------
83 // "size_allocate"
84 //-----------------------------------------------------------------------------
85
86 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
87 {
88 if (g_isIdle)
89 wxapp_install_idle_handler();
90
91 if (!win->m_hasVMT)
92 return;
93
94 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
95 {
96 /*
97 wxPrintf( "OnSize from " );
98 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
99 wxPrintf( win->GetClassInfo()->GetClassName() );
100 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
101 (int)alloc->y,
102 (int)alloc->width,
103 (int)alloc->height );
104 */
105
106 win->m_width = alloc->width;
107 win->m_height = alloc->height;
108 win->m_queuedFullRedraw = TRUE;
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 wxWindows 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 if ( size.x == -1 || size.y == -1 )
330 {
331 wxSize sizeDpy = wxGetDisplaySize();
332 if ( size.x == -1 )
333 size.x = sizeDpy.x / 3;
334 if ( size.y == -1 )
335 size.y = sizeDpy.y / 5;
336 }
337
338 wxTopLevelWindows.Append( this );
339
340 m_needParent = FALSE;
341
342 if (!PreCreation( parent, pos, size ) ||
343 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
344 {
345 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
346 return FALSE;
347 }
348
349 m_title = title;
350
351 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
352
353 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
354
355 if (style & wxFRAME_TOOL_WINDOW)
356 win_type = GTK_WINDOW_POPUP;
357
358 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
359 {
360 // there is no more GTK_WINDOW_DIALOG in 2.0
361 #ifdef __WXGTK20__
362 win_type = GTK_WINDOW_TOPLEVEL;
363 #else
364 win_type = GTK_WINDOW_DIALOG;
365 #endif
366 }
367
368 m_widget = gtk_window_new( win_type );
369
370 if (m_parent && (((GTK_IS_WINDOW(m_parent->m_widget)) &&
371 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
372 (style & wxFRAME_FLOAT_ON_PARENT)))
373 {
374 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
375 }
376
377 if (!name.IsEmpty())
378 gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
379
380 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
381 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
382
383 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
384 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
385
386 // m_mainWidget holds the toolbar, the menubar and the client area
387 m_mainWidget = gtk_pizza_new();
388 gtk_widget_show( m_mainWidget );
389 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
390 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
391
392 if (m_miniEdge == 0) // wxMiniFrame has its own version.
393 {
394 // For m_mainWidget themes
395 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
396 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
397 #ifndef __WXGTK20__
398 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
399 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
400 #endif
401 }
402
403 // m_wxwindow only represents the client area without toolbar and menubar
404 m_wxwindow = gtk_pizza_new();
405 gtk_widget_show( m_wxwindow );
406 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
407
408 // we donm't allow the frame to get the focus as otherwise
409 // the frame will grab it at arbitrary focus changes
410 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
411
412 if (m_parent) m_parent->AddChild( this );
413
414 // the user resized the frame by dragging etc.
415 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
416 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
417
418 PostCreation();
419
420 if ((m_x != -1) || (m_y != -1))
421 gtk_widget_set_uposition( m_widget, m_x, m_y );
422
423 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
424
425 // we cannot set MWM hints and icons before the widget has
426 // been realized, so we do this directly after realization
427 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
428 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
429
430 // the only way to get the window size is to connect to this event
431 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
432 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
433
434 // map and unmap for iconized state
435 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
436 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
437 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
438 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
439
440 // the only way to get the window size is to connect to this event
441 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
442 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
443
444 // disable native tab traversal
445 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
446 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
447
448 // decorations
449 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
450 {
451 m_gdkDecor = 0;
452 m_gdkFunc = 0;
453 }
454 else
455 {
456 m_gdkDecor = (long) GDK_DECOR_BORDER;
457 m_gdkFunc = (long) GDK_FUNC_MOVE;
458
459 // All this is for Motif Window Manager "hints" and is supposed to be
460 // recognized by other WMs as well.
461 if ((style & wxCAPTION) != 0)
462 {
463 m_gdkDecor |= GDK_DECOR_TITLE;
464 }
465 if ((style & wxCLOSE_BOX) != 0)
466 {
467 m_gdkFunc |= GDK_FUNC_CLOSE;
468 }
469 if ((style & wxSYSTEM_MENU) != 0)
470 {
471 m_gdkDecor |= GDK_DECOR_MENU;
472 }
473 if ((style & wxMINIMIZE_BOX) != 0)
474 {
475 m_gdkFunc |= GDK_FUNC_MINIMIZE;
476 m_gdkDecor |= GDK_DECOR_MINIMIZE;
477 }
478 if ((style & wxMAXIMIZE_BOX) != 0)
479 {
480 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
481 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
482 }
483 if ((style & wxRESIZE_BORDER) != 0)
484 {
485 m_gdkFunc |= GDK_FUNC_RESIZE;
486 m_gdkDecor |= GDK_DECOR_RESIZEH;
487 }
488 }
489
490 return TRUE;
491 }
492
493 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
494 {
495 if (m_grabbed)
496 {
497 wxASSERT_MSG( FALSE, _T("Window still grabbed"));
498 RemoveGrab();
499 }
500
501 m_isBeingDeleted = TRUE;
502
503 // it may also be GtkScrolledWindow in the case of an MDI child
504 if (GTK_IS_WINDOW(m_widget))
505 {
506 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
507 }
508 }
509
510
511
512 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
513 {
514 if (show == m_fsIsShowing) return FALSE; // return what?
515
516 m_fsIsShowing = show;
517
518 GdkWindow *window = m_widget->window;
519 wxX11FullScreenMethod method =
520 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
521 (WXWindow)GDK_ROOT_WINDOW());
522
523 if (show)
524 {
525 m_fsSaveFlag = style;
526 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
527 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
528
529 int screen_width,screen_height;
530 wxDisplaySize( &screen_width, &screen_height );
531
532 gint client_x, client_y, root_x, root_y;
533 gint width, height;
534
535 if (method != wxX11_FS_WMSPEC)
536 {
537 // don't do it always, Metacity hates it
538 m_fsSaveGdkFunc = m_gdkFunc;
539 m_fsSaveGdkDecor = m_gdkDecor;
540 m_gdkFunc = m_gdkDecor = 0;
541 gdk_window_set_decorations(window, (GdkWMDecoration)0);
542 gdk_window_set_functions(window, (GdkWMFunction)0);
543 }
544
545 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
546 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
547 &width, &height, NULL);
548
549 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
550 screen_width + 1, screen_height + 1);
551
552 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
553 (WXWindow)GDK_ROOT_WINDOW(),
554 (WXWindow)GDK_WINDOW_XWINDOW(window),
555 show, &m_fsSaveFrame, method);
556 }
557 else
558 {
559 if (method != wxX11_FS_WMSPEC)
560 {
561 // don't do it always, Metacity hates it
562 m_gdkFunc = m_fsSaveGdkFunc;
563 m_gdkDecor = m_fsSaveGdkDecor;
564 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
565 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
566 }
567
568 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
569 (WXWindow)GDK_ROOT_WINDOW(),
570 (WXWindow)GDK_WINDOW_XWINDOW(window),
571 show, &m_fsSaveFrame, method);
572
573 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
574 m_fsSaveFrame.width, m_fsSaveFrame.height);
575 }
576
577
578 return TRUE;
579 }
580
581 // ----------------------------------------------------------------------------
582 // overridden wxWindow methods
583 // ----------------------------------------------------------------------------
584
585 bool wxTopLevelWindowGTK::Show( bool show )
586 {
587 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
588
589 if (show && !m_sizeSet)
590 {
591 /* by calling GtkOnSize here, we don't have to call
592 either after showing the frame, which would entail
593 much ugly flicker or from within the size_allocate
594 handler, because GTK 1.1.X forbids that. */
595
596 GtkOnSize( m_x, m_y, m_width, m_height );
597 }
598
599 return wxWindow::Show( show );
600 }
601
602 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
603 {
604 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
605 }
606
607 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
608 {
609 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
610
611 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
612 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
613
614 // avoid recursions
615 if (m_resizing)
616 return;
617 m_resizing = TRUE;
618
619 int old_x = m_x;
620 int old_y = m_y;
621
622 int old_width = m_width;
623 int old_height = m_height;
624
625 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
626 {
627 if (x != -1) m_x = x;
628 if (y != -1) m_y = y;
629 }
630 else
631 {
632 m_x = x;
633 m_y = y;
634 }
635 if (width != -1) m_width = width;
636 if (height != -1) m_height = height;
637
638 /*
639 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
640 {
641 if (width == -1) m_width = 80;
642 }
643
644 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
645 {
646 if (height == -1) m_height = 26;
647 }
648 */
649
650 int minWidth = GetMinWidth(),
651 minHeight = GetMinHeight(),
652 maxWidth = GetMaxWidth(),
653 maxHeight = GetMaxHeight();
654
655 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
656 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
657 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
658 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
659
660 if ((m_x != -1) || (m_y != -1))
661 {
662 if ((m_x != old_x) || (m_y != old_y))
663 {
664 gtk_widget_set_uposition( m_widget, m_x, m_y );
665 }
666 }
667
668 if ((m_width != old_width) || (m_height != old_height))
669 {
670 if (m_widget->window)
671 gdk_window_resize( m_widget->window, m_width, m_height );
672 else
673 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
674
675 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
676 done either directly before the frame is shown or in idle time
677 so that different calls to SetSize() don't lead to flicker. */
678 m_sizeSet = FALSE;
679 }
680
681 m_resizing = FALSE;
682 }
683
684 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
685 {
686 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
687
688 wxWindow::DoGetClientSize( width, height );
689 if (height)
690 {
691 // mini edge
692 *height -= m_miniEdge*2 + m_miniTitle;
693 }
694 if (width)
695 {
696 *width -= m_miniEdge*2;
697 }
698 }
699
700 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
701 {
702 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
703
704 DoSetSize(-1, -1,
705 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
706 }
707
708 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
709 int width, int height )
710 {
711 // due to a bug in gtk, x,y are always 0
712 // m_x = x;
713 // m_y = y;
714
715 // avoid recursions
716 if (m_resizing) return;
717 m_resizing = TRUE;
718
719 if ( m_wxwindow == NULL ) return;
720
721 m_width = width;
722 m_height = height;
723
724 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
725 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
726 set in wxFrame::Create so it is used to check what kind of frame we
727 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
728 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
729 importantly) m_mainWidget */
730
731 int minWidth = GetMinWidth(),
732 minHeight = GetMinHeight(),
733 maxWidth = GetMaxWidth(),
734 maxHeight = GetMaxHeight();
735
736 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
737 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
738 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
739 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
740
741 if (m_mainWidget)
742 {
743 // set size hints
744 gint flag = 0; // GDK_HINT_POS;
745 GdkGeometry geom;
746
747 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
748 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
749
750 geom.min_width = minWidth;
751 geom.min_height = minHeight;
752
753 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
754 // maxHeight or maxWidth is set, we must set them both, else the
755 // remaining -1 will be taken literally.
756
757 // I'm certain this also happens elsewhere, and is the probable
758 // cause of other such things as:
759 // Gtk-WARNING **: gtk_widget_size_allocate():
760 // attempt to allocate widget with width 65535 and height 600
761 // but I don't have time to track them all now..
762 //
763 // Really we need to encapulate all this height/width business and
764 // stop any old method from ripping at the members directly and
765 // scattering -1's without regard for who might resolve them later.
766
767 geom.max_width = ( maxHeight == -1 ) ? maxWidth
768 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
769 : maxWidth ;
770
771 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
772 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
773 : maxHeight ;
774
775 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
776 (GtkWidget*) NULL,
777 &geom,
778 (GdkWindowHints) flag );
779
780 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
781 * menubar, the toolbar and the client area, which is represented by
782 * m_wxwindow.
783 * this hurts in the eye, but I don't want to call SetSize()
784 * because I don't want to call any non-native functions here. */
785
786 int client_x = m_miniEdge;
787 int client_y = m_miniEdge + m_miniTitle;
788 int client_w = m_width - 2*m_miniEdge;
789 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
790
791 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
792 m_wxwindow,
793 client_x, client_y, client_w, client_h );
794 }
795 else
796 {
797 // If there is no m_mainWidget between m_widget and m_wxwindow there
798 // is no need to set the size or position of m_wxwindow.
799 }
800
801 m_sizeSet = TRUE;
802
803 // send size event to frame
804 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
805 event.SetEventObject( this );
806 GetEventHandler()->ProcessEvent( event );
807
808 m_resizing = FALSE;
809 }
810
811 void wxTopLevelWindowGTK::OnInternalIdle()
812 {
813 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
814 {
815 GtkOnSize( m_x, m_y, m_width, m_height );
816
817 // we'll come back later
818 if (g_isIdle)
819 wxapp_install_idle_handler();
820 return;
821 }
822
823 // set the focus if not done yet and if we can already do it
824 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
825 {
826 if ( g_delayedFocus &&
827 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
828 {
829 wxLogTrace(_T("focus"),
830 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
831 g_delayedFocus->GetClassInfo()->GetClassName(),
832 g_delayedFocus->GetLabel().c_str());
833
834 g_delayedFocus->SetFocus();
835 g_delayedFocus = NULL;
836 }
837 }
838
839 wxWindow::OnInternalIdle();
840 }
841
842 // ----------------------------------------------------------------------------
843 // frame title/icon
844 // ----------------------------------------------------------------------------
845
846 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
847 {
848 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
849
850 m_title = title;
851 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
852 }
853
854 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
855 {
856 if ( !icon.Ok() )
857 return;
858
859 if (!m_widget->window)
860 return;
861
862 wxMask *mask = icon.GetMask();
863 GdkBitmap *bm = (GdkBitmap *) NULL;
864 if (mask) bm = mask->GetBitmap();
865
866 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
867 }
868
869 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
870 {
871 SetIcons( wxIconBundle( icon ) );
872 }
873
874 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
875 {
876 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
877 GdkWindow* window = m_widget->window;
878
879 wxTopLevelWindowBase::SetIcons( icons );
880
881 DoSetIcon( icons.GetIcon( -1 ) );
882 if ( window )
883 {
884 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
885 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
886 }
887 }
888
889 // ----------------------------------------------------------------------------
890 // frame state: maximized/iconized/normal
891 // ----------------------------------------------------------------------------
892
893 void wxTopLevelWindowGTK::Maximize(bool maximize)
894 {
895 #ifdef __WXGTK20__
896 if (maximize)
897 gtk_window_maximize( GTK_WINDOW( m_widget ) );
898 else
899 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
900 #else
901 wxFAIL_MSG( _T("not implemented") );
902 #endif
903 }
904
905 bool wxTopLevelWindowGTK::IsMaximized() const
906 {
907 // wxFAIL_MSG( _T("not implemented") );
908
909 // This is an approximation
910 return FALSE;
911 }
912
913 void wxTopLevelWindowGTK::Restore()
914 {
915 #ifdef __GTK20__
916 // "Present" seems similar enough to "restore"
917 gtk_window_present( GTK_WINDOW( m_widget ) );
918 #else
919 wxFAIL_MSG( _T("not implemented") );
920 #endif
921 }
922
923 void wxTopLevelWindowGTK::Iconize( bool iconize )
924 {
925 #ifdef __WXGTK20__
926 if (iconize)
927 gtk_window_iconify( GTK_WINDOW( m_widget ) );
928 else
929 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
930 #else
931 if (iconize)
932 {
933 GdkWindow *window = m_widget->window;
934
935 // you should do it later, for example from OnCreate() handler
936 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
937
938 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
939 GDK_WINDOW_XWINDOW( window ),
940 DefaultScreen( GDK_DISPLAY() ) );
941 }
942 #endif
943 }
944
945 bool wxTopLevelWindowGTK::IsIconized() const
946 {
947 return m_isIconized;
948 }
949
950 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
951 {
952 if ( iconize != m_isIconized )
953 {
954 m_isIconized = iconize;
955 (void)SendIconizeEvent(iconize);
956 }
957 }
958
959 void wxTopLevelWindowGTK::AddGrab()
960 {
961 if (!m_grabbed)
962 {
963 m_grabbed = TRUE;
964 gtk_grab_add( m_widget );
965 gtk_main();
966 gtk_grab_remove( m_widget );
967 }
968 }
969
970 void wxTopLevelWindowGTK::RemoveGrab()
971 {
972 if (m_grabbed)
973 {
974 gtk_main_quit();
975 m_grabbed = FALSE;
976 }
977 }
978
979
980 // helper
981 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
982 {
983 if (window)
984 {
985 if (region.IsEmpty())
986 {
987 gdk_window_shape_combine_mask(window, NULL, 0, 0);
988 }
989 else
990 {
991 #ifdef __WXGTK20__
992 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
993 #else
994 wxBitmap bmp = region.ConvertToBitmap();
995 bmp.SetMask(new wxMask(bmp, *wxBLACK));
996 GdkBitmap* mask = bmp.GetMask()->GetBitmap();
997 gdk_window_shape_combine_mask(window, mask, 0, 0);
998 #endif
999 return TRUE;
1000 }
1001 }
1002 return FALSE;
1003 }
1004
1005
1006 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1007 {
1008 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE,
1009 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1010
1011 GdkWindow *window = NULL;
1012 if (m_wxwindow)
1013 {
1014 window = GTK_PIZZA(m_wxwindow)->bin_window;
1015 do_shape_combine_region(window, region);
1016 }
1017 window = m_widget->window;
1018 return do_shape_combine_region(window, region);
1019 }
1020
1021 // vi:sts=4:sw=4:et