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