#include <gtk/gtk.h>
#include <gdk/gdkx.h>
-#include "wx/gtk/win_gtk.h"
+#include "wx/gtk/private/win_gtk.h"
#include "wx/unix/utilsx11.h"
// 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
// used to generate wxActivateEvents
static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
}
}
-
//-----------------------------------------------------------------------------
// "configure_event"
//-----------------------------------------------------------------------------
win->SetIcon( wxNullIcon );
win->SetIcons( iconsOld );
}
+
+ if (win->HasFlag(wxFRAME_SHAPED))
+ win->SetShape(win->m_shape); // it will really set the window shape now
}
}
}
}
+//-----------------------------------------------------------------------------
+
+bool wxGetFrameExtents(GdkWindow* window, int* left, int* right, int* top, int* bottom)
+{
+ static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false);
+ Atom xproperty = gdk_x11_atom_to_xatom_for_display(
+ gdk_drawable_get_display(window), property);
+ Atom type;
+ int format;
+ gulong nitems, bytes_after;
+ guchar* data;
+ Status status = XGetWindowProperty(
+ gdk_x11_drawable_get_xdisplay(window),
+ gdk_x11_drawable_get_xid(window),
+ xproperty,
+ 0, 4, false, XA_CARDINAL,
+ &type, &format, &nitems, &bytes_after, &data);
+ const bool success = status == Success && data && nitems == 4;
+ if (success)
+ {
+ long* p = (long*)data;
+ if (left) *left = int(p[0]);
+ if (right) *right = int(p[1]);
+ if (top) *top = int(p[2]);
+ if (bottom) *bottom = int(p[3]);
+ }
+ if (data)
+ XFree(data);
+ return success;
+}
+
//-----------------------------------------------------------------------------
// "property_notify_event" from m_widget
//-----------------------------------------------------------------------------
static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false);
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);
- Atom type;
- int format;
- gulong nitems, bytes_after;
- long* data = NULL;
- Status status = XGetWindowProperty(
- gdk_x11_drawable_get_xdisplay(event->window),
- gdk_x11_drawable_get_xid(event->window),
- xproperty,
- 0, 4, false, XA_CARDINAL,
- &type, &format, &nitems, &bytes_after, (guchar**)&data);
- if (status == Success && data && nitems == 4)
+ int left, right, top, bottom;
+ if (wxGetFrameExtents(event->window, &left, &right, &top, &bottom))
{
const wxSize decorSize =
- wxSize(int(data[0] + data[1]), int(data[2] + data[3]));
- if (win->m_decorSize != decorSize)
- {
- const wxSize diff = win->m_decorSize - decorSize;
- win->m_decorSize = decorSize;
- if (!win->m_deferShow)
- {
- // 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 (win->m_deferShow)
- {
- // gtk_widget_show() was deferred, do it now
- win->m_deferShow = false;
- 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);
- }
+ wxSize(left + right, top + bottom);
+ win->GTKUpdateDecorSize(decorSize);
}
- if (data)
- XFree(data);
}
return false;
}
EVT_SYS_COLOUR_CHANGED(wxTopLevelWindowGTK::OnSysColourChanged)
END_EVENT_TABLE()
-
// ----------------------------------------------------------------------------
// wxTopLevelWindowGTK creation
// ----------------------------------------------------------------------------
}
}
- gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
+ m_decorSize = GetCachedDecorSize();
+ int w, h;
+ GTKDoGetSize(&w, &h);
+ gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h);
return true;
}
{
wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
- const bool wasRealized = GTK_WIDGET_REALIZED(m_widget);
- bool deferShow = show && m_deferShow && !wasRealized;
+ bool deferShow = show && m_deferShow && !m_isShown;
+ if (deferShow)
+ {
+ m_deferShow =
+ deferShow = !GTK_WIDGET_REALIZED(m_widget) &&
+ gdk_x11_screen_supports_net_wm_hint(
+ gtk_widget_get_screen(m_widget),
+ gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false)) &&
+ g_signal_handler_find(m_widget,
+ GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
+ g_signal_lookup("property_notify_event", GTK_TYPE_WIDGET),
+ 0, NULL, NULL, this);
+ }
if (deferShow)
{
// Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer
// 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);
- }
+ // Realize m_widget, so m_widget->window can be used. Realizing normally
+ // causes the widget tree to be size_allocated, which generates size
+ // events in the wrong order. However, the size_allocates will not be
+ // done if the allocation is not the default (1,1).
+ const int alloc_width = m_widget->allocation.width;
+ if (alloc_width == 1)
+ m_widget->allocation.width = 2;
gtk_widget_realize(m_widget);
- if (child)
- {
- gtk_container_add(GTK_CONTAINER(m_widget), child);
- g_object_unref(child);
- }
+ if (alloc_width == 1)
+ m_widget->allocation.width = 1;
- 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));
return true;
}
- if (show && !wasRealized)
+ if (show && !GTK_WIDGET_REALIZED(m_widget))
{
// size_allocate signals occur in reverse order (bottom to top).
// Things work better if the initial wxSizeEvents are sent (from the
}
}
+void wxTopLevelWindowGTK::DoSetClientSize(int width, int height)
+{
+ if (m_deferShow && !m_isShown)
+ // Since client size is being explicitly set, don't change it later
+ m_deferShow = false;
+ wxTopLevelWindowBase::DoSetClientSize(width, height);
+}
+
void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
{
wxASSERT_MSG(m_widget, wxT("invalid frame"));
(GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask);
}
-void wxTopLevelWindowGTK::OnInternalIdle()
+void wxTopLevelWindowGTK::GTKUpdateDecorSize(const wxSize& decorSize)
{
- // set the focus if not done yet and if we can already do it
- if ( GTK_WIDGET_REALIZED(m_wxwindow) )
+ if (!IsMaximized() && !IsFullScreen())
+ GetCachedDecorSize() = decorSize;
+ if (m_decorSize != decorSize)
{
- if ( g_delayedFocus &&
- wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
+ const wxSize diff = decorSize - m_decorSize;
+ m_decorSize = decorSize;
+ bool resized = false;
+ if (m_deferShow)
{
- wxLogTrace(_T("focus"),
- _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
- g_delayedFocus->GetClassInfo()->GetClassName(),
- g_delayedFocus->GetLabel().c_str());
-
- g_delayedFocus->SetFocus();
- g_delayedFocus = NULL;
+ // keep overall size unchanged by shrinking m_widget
+ int w, h;
+ GTKDoGetSize(&w, &h);
+ // but not if size would be less than minimum, it won't take effect
+ const wxSize minSize = GetMinSize();
+ if (w >= minSize.x && h >= minSize.y)
+ {
+ gtk_window_resize(GTK_WINDOW(m_widget), w, h);
+ resized = true;
+ }
+ }
+ if (!resized)
+ {
+ // adjust overall size to match change in frame extents
+ m_width += diff.x;
+ m_height += diff.y;
+ if (m_width < 0) m_width = 0;
+ if (m_height < 0) m_height = 0;
+ m_oldClientWidth = 0;
+ gtk_widget_queue_resize(m_wxwindow);
}
}
+ if (m_deferShow)
+ {
+ // gtk_widget_show() was deferred, do it now
+ m_deferShow = false;
+ GetClientSize(&m_oldClientWidth, &m_oldClientHeight);
+ wxSizeEvent sizeEvent(GetSize(), GetId());
+ sizeEvent.SetEventObject(this);
+ HandleWindowEvent(sizeEvent);
+
+ gtk_widget_show(m_widget);
+
+ wxShowEvent showEvent(GetId(), true);
+ showEvent.SetEventObject(this);
+ HandleWindowEvent(showEvent);
+ }
+}
+wxSize& wxTopLevelWindowGTK::GetCachedDecorSize()
+{
+ static wxSize size[8];
+
+ int index = 0;
+ // title bar
+ if (m_gdkDecor & (GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE | GDK_DECOR_TITLE))
+ index = 1;
+ // border
+ if (m_gdkDecor & GDK_DECOR_BORDER)
+ index |= 2;
+ // utility window decor can be different
+ if (m_windowStyle & wxFRAME_TOOL_WINDOW)
+ index |= 4;
+ return size[index];
+}
+
+void wxTopLevelWindowGTK::OnInternalIdle()
+{
wxWindow::OnInternalIdle();
// Synthetize activate events.
wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
_T("Shaped windows must be created with the wxFRAME_SHAPED style."));
- GdkWindow *window = NULL;
- if (m_wxwindow)
+ if ( GTK_WIDGET_REALIZED(m_widget) )
+ {
+ if ( m_wxwindow )
+ do_shape_combine_region(m_wxwindow->window, region);
+
+ return do_shape_combine_region(m_widget->window, region);
+ }
+ else // not realized yet
{
- do_shape_combine_region(m_wxwindow->window, region);
+ // store the shape to set, it will be really set once we're realized
+ m_shape = region;
+
+ // we don't know if we're going to succeed or fail, be optimistic by
+ // default
+ return true;
}
- window = m_widget->window;
- return do_shape_combine_region(window, region);
}
bool wxTopLevelWindowGTK::IsActive()