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