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