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