}
}
-//-----------------------------------------------------------------------------
-
-// Get cached size of WM decorations for given GdkWMDecoration.
-static wxSize& GetDecorSize(int decor)
-{
- // In testing, only the title bar and GDK_DECOR_BORDER made a difference.
- // 4 possible combinations of title bar and border
- static wxSize size[4];
-
- int index = 0;
- // title bar
- if (decor & (GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE | GDK_DECOR_TITLE))
- index = 1;
- // border
- if (decor & GDK_DECOR_BORDER)
- index |= 2;
- return size[index];
-}
-
//-----------------------------------------------------------------------------
// "size_allocate" from m_wxwindow
//-----------------------------------------------------------------------------
wxSize size(win->m_widget->allocation.width,
win->m_widget->allocation.height);
- if (!win->IsFullScreen())
- size += win->m_decorSize;
+ size += win->m_decorSize;
win->m_width = size.x;
win->m_height = size.y;
extern "C" {
static gboolean
-gtk_frame_map_callback( GtkWidget* widget,
+gtk_frame_map_callback( GtkWidget*,
GdkEvent * WXUNUSED(event),
wxTopLevelWindow *win )
{
- // Calculate size of WM decorations.
- // Done here in case WM does not support the _NET_FRAME_EXTENTS property.
- if (win->IsDecorCacheable() && !win->IsFullScreen())
- {
- GdkRectangle rect;
- gdk_window_get_frame_extents(widget->window, &rect);
- int w, h;
- gdk_drawable_get_size(widget->window, &w, &h);
- 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;
- win->m_decorSize = decorSize;
- GetDecorSize(win->m_gdkDecor) = decorSize;
- }
- }
-
const bool wasIconized = win->IsIconized();
win->SetIconizeState(false);
{
// Watch for changes to _NET_FRAME_EXTENTS property
static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false);
- if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property &&
- win->IsDecorCacheable() && !win->IsFullScreen())
+ if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property)
{
Atom xproperty = gdk_x11_atom_to_xatom_for_display(
gdk_drawable_get_display(event->window), property);
wxSize(int(data[0] + data[1]), int(data[2] + data[3]));
if (win->m_decorSize != decorSize)
{
- // Update window size and frame extents cache
- win->m_width += decorSize.x - win->m_decorSize.x;
- win->m_height += decorSize.y - win->m_decorSize.y;
- if (win->m_width < 0) win->m_width = 0;
- if (win->m_height < 0) win->m_height = 0;
+ const wxSize diff = decorSize - win->m_decorSize;
win->m_decorSize = decorSize;
- GetDecorSize(win->m_gdkDecor) = decorSize;
- win->m_oldClientWidth = 0;
- gtk_widget_queue_resize(win->m_wxwindow);
+ bool resized = false;
+ if (win->m_deferShow)
+ {
+ // keep overall size unchanged by shrinking m_widget,
+ // if min size will allow it
+ const wxSize minSize = win->GetMinSize();
+ int w, h;
+ win->GTKDoGetSize(&w, &h);
+ if (w >= minSize.x && h >= minSize.y)
+ {
+ gtk_window_resize(GTK_WINDOW(win->m_widget), w, h);
+ resized = true;
+ }
+ }
+ if (!resized)
+ {
+ // 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;
+ if (!win->m_deferShow)
+ {
+ win->m_oldClientWidth = 0;
+ gtk_widget_queue_resize(win->m_wxwindow);
+ }
+ }
+ }
+ if (win->m_deferShow)
+ {
+ // gtk_widget_show() was deferred, do it now
+ win->m_deferShow = false;
+ win->GetClientSize(
+ &win->m_oldClientWidth, &win->m_oldClientHeight);
+ 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)
m_themeEnabled = true;
m_gdkDecor = m_gdkFunc = 0;
m_grabbed = false;
+ m_deferShow = true;
m_urgency_hint = -2;
}
}
}
- 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);
+ gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
return true;
}
{
wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
- if (show && !IsShown())
+ const bool wasRealized = GTK_WIDGET_REALIZED(m_widget);
+ bool deferShow = show && m_deferShow && !wasRealized;
+ if (deferShow)
+ {
+ // 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);
+ }
+
+ m_deferShow =
+ deferShow = gdk_x11_screen_supports_net_wm_hint(
+ gdk_drawable_get_screen(m_widget->window),
+ gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false)) != 0;
+ }
+ if (deferShow)
+ {
+ // 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),
+ gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false));
+ 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;
+ }
+
+ if (show && !wasRealized)
{
// size_allocate signals occur in reverse order (bottom to top).
// Things work better if the initial wxSizeEvents are sent (from the
void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const
{
wxSize size(m_width, m_height);
- if (!IsFullScreen())
- {
- size -= m_decorSize;
- if (size.x < 0) size.x = 0;
- if (size.y < 0) size.y = 0;
- }
+ size -= m_decorSize;
+ if (size.x < 0) size.x = 0;
+ if (size.y < 0) size.y = 0;
if (width) *width = size.x;
if (height) *height = size.y;
}
(GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask);
}
-bool wxTopLevelWindowGTK::IsDecorCacheable() const
-{
- return true;
-}
-
void wxTopLevelWindowGTK::OnInternalIdle()
{
// set the focus if not done yet and if we can already do it