X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ff654490b7cb185631a1dc4621094d88643ccf41..dc0c395d837af5097f3fb52bdc37a1faaa33869b:/src/gtk/toplevel.cpp diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index acaec2299a..bde85936ac 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -45,11 +45,18 @@ // XA_CARDINAL #include +#if wxUSE_LIBHILDON + #include + #include +#endif // wxUSE_LIBHILDON + // ---------------------------------------------------------------------------- // data // ---------------------------------------------------------------------------- -extern int g_openDialogs; +// this is incremented while a modal dialog is shown +int wxOpenModalDialogsCount = 0; + extern wxWindowGTK *g_delayedFocus; // the frame that is currently active (i.e. its child has focus). It is @@ -156,7 +163,7 @@ static gboolean gtk_frame_focus_in_callback( GtkWidget *widget, wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame); wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId()); event.SetEventObject(g_activeFrame); - g_activeFrame->GetEventHandler()->ProcessEvent(event); + g_activeFrame->HandleWindowEvent(event); return FALSE; } @@ -186,7 +193,7 @@ gboolean gtk_frame_focus_out_callback(GtkWidget * WXUNUSED(widget), wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame); wxActivateEvent event(wxEVT_ACTIVATE, false, g_activeFrame->GetId()); event.SetEventObject(g_activeFrame); - g_activeFrame->GetEventHandler()->ProcessEvent(event); + g_activeFrame->HandleWindowEvent(event); g_activeFrame = NULL; } @@ -227,16 +234,19 @@ size_allocate(GtkWidget*, GtkAllocation* alloc, wxTopLevelWindowGTK* win) { win->m_oldClientWidth = alloc->width; win->m_oldClientHeight = alloc->height; - wxSize sizeDecor; + + wxSize size(win->m_widget->allocation.width, + win->m_widget->allocation.height); if (!win->IsFullScreen()) - sizeDecor = GetDecorSize(win->m_gdkDecor); - win->m_width = win->m_widget->allocation.width + sizeDecor.x; - win->m_height = win->m_widget->allocation.height + sizeDecor.y; + size += win->m_decorSize; + win->m_width = size.x; + win->m_height = size.y; + if (!win->IsIconized()) { - wxSizeEvent event(win->GetSize(), win->GetId()); + wxSizeEvent event(size, win->GetId()); event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); + win->HandleWindowEvent(event); } // else the window is currently unmapped, don't generate size events } @@ -270,7 +280,7 @@ gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), wxTopLevelWindowGTK *win ) { if (win->IsEnabled() && - (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) || + (wxOpenModalDialogsCount == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) || win->IsGrabbed())) win->Close(); @@ -299,7 +309,7 @@ gtk_frame_configure_callback( GtkWidget* widget, win->m_y = point.y; wxMoveEvent mevent(point, win->GetId()); mevent.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( mevent ); + win->HandleWindowEvent( mevent ); return FALSE; } @@ -358,21 +368,33 @@ gtk_frame_map_callback( GtkWidget* widget, gdk_window_get_frame_extents(widget->window, &rect); int w, h; gdk_drawable_get_size(widget->window, &w, &h); - wxSize& decorSize = GetDecorSize(win->m_gdkDecor); - const wxSize size = wxSize(rect.width - w, rect.height - h); - if (decorSize.x != size.x || decorSize.y != size.y) + const wxSize decorSize = wxSize(rect.width - w, rect.height - h); + if (win->m_decorSize != decorSize) { // Update window size and frame extents cache win->m_width = rect.width; win->m_height = rect.height; - decorSize = size; - wxSizeEvent event(win->GetSize(), win->GetId()); - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); + win->m_decorSize = decorSize; + GetDecorSize(win->m_gdkDecor) = decorSize; } } + const bool wasIconized = win->IsIconized(); + win->SetIconizeState(false); + + if (wasIconized) + { + // Because GetClientSize() returns (0,0) when IsIconized() is true, + // a size event must be generated, just in case GetClientSize() was + // called while iconized. This specifically happens when restoring a + // tlw that was "rolled up" with some WMs. + // Queue a resize rather than sending size event directly to allow + // children to be made visible first. + win->m_oldClientWidth = 0; + gtk_widget_queue_resize(win->m_wxwindow); + } + return false; } } @@ -419,20 +441,42 @@ static gboolean property_notify_event( &type, &format, &nitems, &bytes_after, (guchar**)&data); if (status == Success && data && nitems == 4) { - wxSize& decorSize = GetDecorSize(win->m_gdkDecor); - const wxSize size = + const wxSize decorSize = wxSize(int(data[0] + data[1]), int(data[2] + data[3])); - if (decorSize.x != size.x || decorSize.y != size.y) + if (win->m_decorSize != decorSize) { - // Update window size and frame extents cache - win->m_width += size.x - decorSize.x; - win->m_height += size.y - decorSize.y; - if (win->m_width < 0) win->m_width = 0; - if (win->m_height < 0) win->m_height = 0; - decorSize = size; - wxSizeEvent event(win->GetSize(), win->GetId()); - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); + const wxSize diff = win->m_decorSize - decorSize; + win->m_decorSize = decorSize; + GetDecorSize(win->m_gdkDecor) = decorSize; + if (GTK_WIDGET_VISIBLE(win->m_widget)) + { + // adjust overall size to match change in frame extents + win->m_width -= diff.x; + win->m_height -= diff.y; + if (win->m_width < 0) win->m_width = 0; + if (win->m_height < 0) win->m_height = 0; + win->m_oldClientWidth = 0; + gtk_widget_queue_resize(win->m_wxwindow); + } + else + { + // Window not yet visible, adjust client size. This would + // cause an obvious size change if window was visible. + int w, h; + win->GTKDoGetSize(&w, &h); + gtk_window_resize(GTK_WINDOW(win->m_widget), w, h); + } + } + if (!GTK_WIDGET_VISIBLE(win->m_widget)) + { + // gtk_widget_show() was deferred, do it now + wxSizeEvent sizeEvent(win->GetSize(), win->GetId()); + sizeEvent.SetEventObject(win); + win->HandleWindowEvent(sizeEvent); + gtk_widget_show(win->m_widget); + wxShowEvent showEvent(win->GetId(), true); + showEvent.SetEventObject(win); + win->HandleWindowEvent(showEvent); } } if (data) @@ -492,6 +536,14 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, // e.g. in wxTaskBarIconAreaGTK if (m_widget == NULL) { +#if wxUSE_LIBHILDON + // we must create HildonWindow and not a normal GtkWindow as the latter + // doesn't look correctly in Maemo environment and it must also be + // registered with the main program object + m_widget = hildon_window_new(); + hildon_program_add_window(wxTheApp->GetHildonProgram(), + HILDON_WINDOW(m_widget)); +#else // !wxUSE_LIBHILDON m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) { @@ -518,6 +570,7 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, style |= wxFRAME_NO_TASKBAR; } } +#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON } wxWindow *topParent = wxGetTopLevelParent(m_parent); @@ -557,7 +610,7 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget ); // m_wxwindow is the client area - m_wxwindow = gtk_pizza_new_no_scroll(); + m_wxwindow = wxPizza::New(); gtk_widget_show( m_wxwindow ); gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow ); @@ -644,7 +697,9 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, } } - // m_gdkDecor needs to be set before calling GTKDoGetSize + m_decorSize = GetDecorSize(m_gdkDecor); + + // m_sizeDecor needs to be set before calling GTKDoGetSize int w, h; GTKDoGetSize(&w, &h); gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h); @@ -654,6 +709,15 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, wxTopLevelWindowGTK::~wxTopLevelWindowGTK() { +#if wxUSE_LIBHILDON + // it can also be a (standard) dialog + if ( HILDON_IS_WINDOW(m_widget) ) + { + hildon_program_remove_window(wxTheApp->GetHildonProgram(), + HILDON_WINDOW(m_widget)); + } +#endif // wxUSE_LIBHILDON + if (m_grabbed) { wxFAIL_MSG(_T("Window still grabbed")); @@ -775,14 +839,64 @@ bool wxTopLevelWindowGTK::Show( bool show ) { wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") ); - if (show && !IsShown()) + if (show && !GTK_WIDGET_REALIZED(m_widget)) { + // Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer + // calling gtk_widget_show() until _NET_FRAME_EXTENTS property + // notification is received, so correct frame extents are known. + // This allows resizing m_widget to keep the overall size in sync with + // what wxWidgets expects it to be without an obvious change in the + // window size immediately after it becomes visible. + + // Realize m_widget, so m_widget->window can be used. Realizing causes + // the widget tree to be size_allocated, which generates size events in + // the wrong order. So temporarily remove child from m_widget while + // realizing. + GtkWidget* child = GTK_BIN(m_widget)->child; + if (child) + { + g_object_ref(child); + gtk_container_remove(GTK_CONTAINER(m_widget), child); + } + gtk_widget_realize(m_widget); + if (child) + { + gtk_container_add(GTK_CONTAINER(m_widget), child); + g_object_unref(child); + } + + // if WM supports _NET_REQUEST_FRAME_EXTENTS + GdkAtom request_extents = + gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false); + GdkScreen* screen = gdk_drawable_get_screen(m_widget->window); + if (gdk_x11_screen_supports_net_wm_hint(screen, request_extents)) + { + // send _NET_REQUEST_FRAME_EXTENTS + XClientMessageEvent xevent; + memset(&xevent, 0, sizeof(xevent)); + xevent.type = ClientMessage; + xevent.window = gdk_x11_drawable_get_xid(m_widget->window); + xevent.message_type = gdk_x11_atom_to_xatom_for_display( + gdk_drawable_get_display(m_widget->window), request_extents); + xevent.format = 32; + Display* display = gdk_x11_drawable_get_xdisplay(m_widget->window); + XSendEvent(display, DefaultRootWindow(display), false, + SubstructureNotifyMask | SubstructureRedirectMask, + (XEvent*)&xevent); + + // defer calling gtk_widget_show() + m_isShown = true; + return true; + } + // WM does not support _NET_REQUEST_FRAME_EXTENTS, overall size may + // change when correct frame extents become known. + // size_allocate signals occur in reverse order (bottom to top). // Things work better if the initial wxSizeEvents are sent (from the // top down), before the initial size_allocate signals occur. wxSizeEvent event(GetSize(), GetId()); event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } bool change = wxTopLevelWindowBase::Show(show); @@ -817,7 +931,7 @@ void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const wxSize size(m_width, m_height); if (!IsFullScreen()) { - size -= GetDecorSize(m_gdkDecor); + size -= m_decorSize; if (size.x < 0) size.x = 0; if (size.y < 0) size.y = 0; } @@ -829,10 +943,6 @@ void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int si { wxCHECK_RET( m_widget, wxT("invalid frame") ); - // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow - wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") ); - - // deal with the position first int old_x = m_x; int old_y = m_y; @@ -871,7 +981,7 @@ void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int si GetClientSize(&m_oldClientWidth, &m_oldClientHeight); wxSizeEvent event(GetSize(), GetId()); event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } } @@ -904,24 +1014,23 @@ void wxTopLevelWindowGTK::DoSetSizeHints( int minW, int minH, const wxSize maxSize = GetMaxSize(); GdkGeometry hints; int hints_mask = 0; - const wxSize sizeDecor = GetDecorSize(m_gdkDecor); if (minSize.x > 0 || minSize.y > 0) { hints_mask |= GDK_HINT_MIN_SIZE; - hints.min_width = minSize.x - sizeDecor.x; + hints.min_width = minSize.x - m_decorSize.x; if (hints.min_width < 0) hints.min_width = 0; - hints.min_height = minSize.y - sizeDecor.y; + hints.min_height = minSize.y - m_decorSize.y; if (hints.min_height < 0) hints.min_height = 0; } if (maxSize.x > 0 || maxSize.y > 0) { hints_mask |= GDK_HINT_MAX_SIZE; - hints.max_width = maxSize.x - sizeDecor.x; + hints.max_width = maxSize.x - m_decorSize.x; if (hints.max_width < 0) hints.max_width = INT_MAX; - hints.max_height = maxSize.y - sizeDecor.y; + hints.max_height = maxSize.y - m_decorSize.y; if (hints.max_height < 0) hints.max_height = INT_MAX; } @@ -1105,8 +1214,7 @@ bool wxTopLevelWindowGTK::SetShape(const wxRegion& region) GdkWindow *window = NULL; if (m_wxwindow) { - window = GTK_PIZZA(m_wxwindow)->bin_window; - do_shape_combine_region(window, region); + do_shape_combine_region(m_wxwindow->window, region); } window = m_widget->window; return do_shape_combine_region(window, region);