]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/toplevel.cpp
wxCocoa: Added preliminary Blit support
[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 #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 {
460 m_gdkDecor |= GDK_DECOR_TITLE;
461 }
462 if ((style & wxCLOSE_BOX) != 0)
463 {
464 m_gdkFunc |= GDK_FUNC_CLOSE;
465 }
466 if ((style & wxSYSTEM_MENU) != 0)
467 {
468 m_gdkDecor |= GDK_DECOR_MENU;
469 }
470 if ((style & wxMINIMIZE_BOX) != 0)
471 {
472 m_gdkFunc |= GDK_FUNC_MINIMIZE;
473 m_gdkDecor |= GDK_DECOR_MINIMIZE;
474 }
475 if ((style & wxMAXIMIZE_BOX) != 0)
476 {
477 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
478 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
479 }
480 if ((style & wxRESIZE_BORDER) != 0)
481 {
482 m_gdkFunc |= GDK_FUNC_RESIZE;
483 m_gdkDecor |= GDK_DECOR_RESIZEH;
484 }
485 }
486
487 return TRUE;
488 }
489
490 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
491 {
492 if (m_grabbed)
493 {
494 wxASSERT_MSG( FALSE, _T("Window still grabbed"));
495 RemoveGrab();
496 }
497
498 m_isBeingDeleted = TRUE;
499
500 // it may also be GtkScrolledWindow in the case of an MDI child
501 if (GTK_IS_WINDOW(m_widget))
502 {
503 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
504 }
505 }
506
507
508
509 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
510 {
511 if (show == m_fsIsShowing) return FALSE; // return what?
512
513 m_fsIsShowing = show;
514
515 GdkWindow *window = m_widget->window;
516 wxX11FullScreenMethod method =
517 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
518 (WXWindow)GDK_ROOT_WINDOW());
519
520 if (show)
521 {
522 m_fsSaveFlag = style;
523 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
524 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
525
526 int screen_width,screen_height;
527 wxDisplaySize( &screen_width, &screen_height );
528
529 gint client_x, client_y, root_x, root_y;
530 gint width, height;
531
532 if (method != wxX11_FS_WMSPEC)
533 {
534 // don't do it always, Metacity hates it
535 m_fsSaveGdkFunc = m_gdkFunc;
536 m_fsSaveGdkDecor = m_gdkDecor;
537 m_gdkFunc = m_gdkDecor = 0;
538 gdk_window_set_decorations(window, (GdkWMDecoration)0);
539 gdk_window_set_functions(window, (GdkWMFunction)0);
540 }
541
542 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
543 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
544 &width, &height, NULL);
545
546 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
547 screen_width + 1, screen_height + 1);
548
549 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
550 (WXWindow)GDK_ROOT_WINDOW(),
551 (WXWindow)GDK_WINDOW_XWINDOW(window),
552 show, &m_fsSaveFrame, method);
553 }
554 else
555 {
556 if (method != wxX11_FS_WMSPEC)
557 {
558 // don't do it always, Metacity hates it
559 m_gdkFunc = m_fsSaveGdkFunc;
560 m_gdkDecor = m_fsSaveGdkDecor;
561 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
562 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
563 }
564
565 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
566 (WXWindow)GDK_ROOT_WINDOW(),
567 (WXWindow)GDK_WINDOW_XWINDOW(window),
568 show, &m_fsSaveFrame, method);
569
570 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
571 m_fsSaveFrame.width, m_fsSaveFrame.height);
572 }
573
574
575 return TRUE;
576 }
577
578 // ----------------------------------------------------------------------------
579 // overridden wxWindow methods
580 // ----------------------------------------------------------------------------
581
582 bool wxTopLevelWindowGTK::Show( bool show )
583 {
584 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
585
586 if (show && !m_sizeSet)
587 {
588 /* by calling GtkOnSize here, we don't have to call
589 either after showing the frame, which would entail
590 much ugly flicker or from within the size_allocate
591 handler, because GTK 1.1.X forbids that. */
592
593 GtkOnSize( m_x, m_y, m_width, m_height );
594 }
595
596 return wxWindow::Show( show );
597 }
598
599 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
600 {
601 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
602 }
603
604 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
605 {
606 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
607
608 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
609 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
610
611 // avoid recursions
612 if (m_resizing)
613 return;
614 m_resizing = TRUE;
615
616 int old_x = m_x;
617 int old_y = m_y;
618
619 int old_width = m_width;
620 int old_height = m_height;
621
622 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
623 {
624 if (x != -1) m_x = x;
625 if (y != -1) m_y = y;
626 }
627 else
628 {
629 m_x = x;
630 m_y = y;
631 }
632 if (width != -1) m_width = width;
633 if (height != -1) m_height = height;
634
635 /*
636 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
637 {
638 if (width == -1) m_width = 80;
639 }
640
641 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
642 {
643 if (height == -1) m_height = 26;
644 }
645 */
646
647 int minWidth = GetMinWidth(),
648 minHeight = GetMinHeight(),
649 maxWidth = GetMaxWidth(),
650 maxHeight = GetMaxHeight();
651
652 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
653 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
654 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
655 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
656
657 if ((m_x != -1) || (m_y != -1))
658 {
659 if ((m_x != old_x) || (m_y != old_y))
660 {
661 gtk_widget_set_uposition( m_widget, m_x, m_y );
662 }
663 }
664
665 if ((m_width != old_width) || (m_height != old_height))
666 {
667 if (m_widget->window)
668 gdk_window_resize( m_widget->window, m_width, m_height );
669 else
670 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
671
672 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
673 done either directly before the frame is shown or in idle time
674 so that different calls to SetSize() don't lead to flicker. */
675 m_sizeSet = FALSE;
676 }
677
678 m_resizing = FALSE;
679 }
680
681 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
682 {
683 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
684
685 wxWindow::DoGetClientSize( width, height );
686 if (height)
687 {
688 // mini edge
689 *height -= m_miniEdge*2 + m_miniTitle;
690 }
691 if (width)
692 {
693 *width -= m_miniEdge*2;
694 }
695 }
696
697 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
698 {
699 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
700
701 DoSetSize(-1, -1,
702 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
703 }
704
705 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
706 int width, int height )
707 {
708 // due to a bug in gtk, x,y are always 0
709 // m_x = x;
710 // m_y = y;
711
712 // avoid recursions
713 if (m_resizing) return;
714 m_resizing = TRUE;
715
716 if ( m_wxwindow == NULL ) return;
717
718 m_width = width;
719 m_height = height;
720
721 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
722 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
723 set in wxFrame::Create so it is used to check what kind of frame we
724 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
725 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
726 importantly) m_mainWidget */
727
728 int minWidth = GetMinWidth(),
729 minHeight = GetMinHeight(),
730 maxWidth = GetMaxWidth(),
731 maxHeight = GetMaxHeight();
732
733 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
734 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
735 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
736 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
737
738 if (m_mainWidget)
739 {
740 // set size hints
741 gint flag = 0; // GDK_HINT_POS;
742 GdkGeometry geom;
743
744 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
745 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
746
747 geom.min_width = minWidth;
748 geom.min_height = minHeight;
749
750 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
751 // maxHeight or maxWidth is set, we must set them both, else the
752 // remaining -1 will be taken literally.
753
754 // I'm certain this also happens elsewhere, and is the probable
755 // cause of other such things as:
756 // Gtk-WARNING **: gtk_widget_size_allocate():
757 // attempt to allocate widget with width 65535 and height 600
758 // but I don't have time to track them all now..
759 //
760 // Really we need to encapulate all this height/width business and
761 // stop any old method from ripping at the members directly and
762 // scattering -1's without regard for who might resolve them later.
763
764 geom.max_width = ( maxHeight == -1 ) ? maxWidth
765 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
766 : maxWidth ;
767
768 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
769 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
770 : maxHeight ;
771
772 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
773 (GtkWidget*) NULL,
774 &geom,
775 (GdkWindowHints) flag );
776
777 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
778 * menubar, the toolbar and the client area, which is represented by
779 * m_wxwindow.
780 * this hurts in the eye, but I don't want to call SetSize()
781 * because I don't want to call any non-native functions here. */
782
783 int client_x = m_miniEdge;
784 int client_y = m_miniEdge + m_miniTitle;
785 int client_w = m_width - 2*m_miniEdge;
786 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
787
788 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
789 m_wxwindow,
790 client_x, client_y, client_w, client_h );
791 }
792 else
793 {
794 // If there is no m_mainWidget between m_widget and m_wxwindow there
795 // is no need to set the size or position of m_wxwindow.
796 }
797
798 m_sizeSet = TRUE;
799
800 // send size event to frame
801 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
802 event.SetEventObject( this );
803 GetEventHandler()->ProcessEvent( event );
804
805 m_resizing = FALSE;
806 }
807
808 void wxTopLevelWindowGTK::OnInternalIdle()
809 {
810 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
811 {
812 GtkOnSize( m_x, m_y, m_width, m_height );
813
814 // we'll come back later
815 if (g_isIdle)
816 wxapp_install_idle_handler();
817 return;
818 }
819
820 // set the focus if not done yet and if we can already do it
821 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
822 {
823 if ( g_delayedFocus &&
824 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
825 {
826 wxLogTrace(_T("focus"),
827 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
828 g_delayedFocus->GetClassInfo()->GetClassName(),
829 g_delayedFocus->GetLabel().c_str());
830
831 g_delayedFocus->SetFocus();
832 g_delayedFocus = NULL;
833 }
834 }
835
836 wxWindow::OnInternalIdle();
837 }
838
839 // ----------------------------------------------------------------------------
840 // frame title/icon
841 // ----------------------------------------------------------------------------
842
843 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
844 {
845 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
846
847 m_title = title;
848 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
849 }
850
851 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
852 {
853 if ( !icon.Ok() )
854 return;
855
856 if (!m_widget->window)
857 return;
858
859 wxMask *mask = icon.GetMask();
860 GdkBitmap *bm = (GdkBitmap *) NULL;
861 if (mask) bm = mask->GetBitmap();
862
863 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
864 }
865
866 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
867 {
868 SetIcons( wxIconBundle( icon ) );
869 }
870
871 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
872 {
873 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
874 GdkWindow* window = m_widget->window;
875
876 wxTopLevelWindowBase::SetIcons( icons );
877
878 DoSetIcon( icons.GetIcon( -1 ) );
879 if ( window )
880 {
881 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
882 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
883 }
884 }
885
886 // ----------------------------------------------------------------------------
887 // frame state: maximized/iconized/normal
888 // ----------------------------------------------------------------------------
889
890 void wxTopLevelWindowGTK::Maximize(bool maximize)
891 {
892 #ifdef __WXGTK20__
893 if (maximize)
894 gtk_window_maximize( GTK_WINDOW( m_widget ) );
895 else
896 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
897 #else
898 wxFAIL_MSG( _T("not implemented") );
899 #endif
900 }
901
902 bool wxTopLevelWindowGTK::IsMaximized() const
903 {
904 // wxFAIL_MSG( _T("not implemented") );
905
906 // This is an approximation
907 return FALSE;
908 }
909
910 void wxTopLevelWindowGTK::Restore()
911 {
912 #ifdef __GTK20__
913 // "Present" seems similar enough to "restore"
914 gtk_window_present( GTK_WINDOW( m_widget ) );
915 #else
916 wxFAIL_MSG( _T("not implemented") );
917 #endif
918 }
919
920 void wxTopLevelWindowGTK::Iconize( bool iconize )
921 {
922 #ifdef __WXGTK20__
923 if (iconize)
924 gtk_window_iconify( GTK_WINDOW( m_widget ) );
925 else
926 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
927 #else
928 if (iconize)
929 {
930 GdkWindow *window = m_widget->window;
931
932 // you should do it later, for example from OnCreate() handler
933 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
934
935 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
936 GDK_WINDOW_XWINDOW( window ),
937 DefaultScreen( GDK_DISPLAY() ) );
938 }
939 #endif
940 }
941
942 bool wxTopLevelWindowGTK::IsIconized() const
943 {
944 return m_isIconized;
945 }
946
947 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
948 {
949 if ( iconize != m_isIconized )
950 {
951 m_isIconized = iconize;
952 (void)SendIconizeEvent(iconize);
953 }
954 }
955
956 void wxTopLevelWindowGTK::AddGrab()
957 {
958 if (!m_grabbed)
959 {
960 m_grabbed = TRUE;
961 gtk_grab_add( m_widget );
962 gtk_main();
963 gtk_grab_remove( m_widget );
964 }
965 }
966
967 void wxTopLevelWindowGTK::RemoveGrab()
968 {
969 if (m_grabbed)
970 {
971 gtk_main_quit();
972 m_grabbed = FALSE;
973 }
974 }
975
976
977 // helper
978 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
979 {
980 if (window)
981 {
982 if (region.IsEmpty())
983 {
984 gdk_window_shape_combine_mask(window, NULL, 0, 0);
985 }
986 else
987 {
988 #ifdef __WXGTK20__
989 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
990 #else
991 wxBitmap bmp = region.ConvertToBitmap();
992 bmp.SetMask(new wxMask(bmp, *wxBLACK));
993 GdkBitmap* mask = bmp.GetMask()->GetBitmap();
994 gdk_window_shape_combine_mask(window, mask, 0, 0);
995 #endif
996 return TRUE;
997 }
998 }
999 return FALSE;
1000 }
1001
1002
1003 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1004 {
1005 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE,
1006 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1007
1008 GdkWindow *window = NULL;
1009 if (m_wxwindow)
1010 {
1011 window = GTK_PIZZA(m_wxwindow)->bin_window;
1012 do_shape_combine_region(window, region);
1013 }
1014 window = m_widget->window;
1015 return do_shape_combine_region(window, region);
1016 }
1017
1018 // vi:sts=4:sw=4:et