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