// Name: src/gtk/toplevel.cpp
// Purpose:
// Author: Robert Roebling
-// Id: $Id$
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// send any activate events at all
static int g_sendActivateEvent = -1;
+#ifdef GDK_WINDOWING_X11
// Whether _NET_REQUEST_FRAME_EXTENTS support is working
-// 0 == not tested yet, 1 == working, 2 == broken
-static int gs_requestFrameExtentsStatus;
+static enum {
+ RFE_STATUS_UNKNOWN, RFE_STATUS_WORKING, RFE_STATUS_BROKEN
+} gs_requestFrameExtentsStatus;
+
+static bool gs_decorCacheValid;
+#endif
//-----------------------------------------------------------------------------
// RequestUserAttention related functions
}
}
+// ----------------------------------------------------------------------------
+// "key_press_event"
+// ----------------------------------------------------------------------------
+
+extern "C" {
+static gboolean
+wxgtk_tlw_key_press_event(GtkWidget *widget, GdkEventKey *event)
+{
+ GtkWindow* const window = GTK_WINDOW(widget);
+
+ // By default GTK+ checks for the menu accelerators in this (top level)
+ // window first and then propagates the event to the currently focused
+ // child from where it bubbles up the window parent chain. In wxWidgets,
+ // however, we want the child window to have the event first but still
+ // handle it as an accelerator if it's not processed there, so we need to
+ // customize this by reversing the order of the steps done in the standard
+ // GTK+ gtk_window_key_press_event() handler.
+
+ if ( gtk_window_propagate_key_event(window, event) )
+ return TRUE;
+
+ if ( gtk_window_activate_key(window, event) )
+ return TRUE;
+
+ if (GTK_WIDGET_GET_CLASS(widget)->key_press_event(widget, event))
+ return TRUE;
+
+ return FALSE;
+}
+}
+
//-----------------------------------------------------------------------------
// "size_allocate" from m_wxwindow
//-----------------------------------------------------------------------------
static void
size_allocate(GtkWidget*, GtkAllocation* alloc, wxTopLevelWindowGTK* win)
{
- if (win->m_oldClientWidth != alloc->width ||
- win->m_oldClientHeight != alloc->height)
+ win->m_useCachedClientSize = true;
+ if (win->m_clientWidth != alloc->width ||
+ win->m_clientHeight != alloc->height)
{
- win->m_oldClientWidth = alloc->width;
- win->m_oldClientHeight = alloc->height;
+ win->m_clientWidth = alloc->width;
+ win->m_clientHeight = alloc->height;
GtkAllocation a;
gtk_widget_get_allocation(win->m_widget, &a);
wxSize size(a.width, a.height);
- size += win->m_decorSize;
+ size.x += win->m_decorSize.left + win->m_decorSize.right;
+ size.y += win->m_decorSize.top + win->m_decorSize.bottom;
win->m_width = size.x;
win->m_height = size.y;
extern "C" {
static gboolean
-gtk_frame_configure_callback( GtkWidget* widget,
- GdkEventConfigure *WXUNUSED(event),
+gtk_frame_configure_callback( GtkWidget*,
+ GdkEventConfigure* gdk_event,
wxTopLevelWindowGTK *win )
{
- if (!win->IsShown())
- return FALSE;
+ win->GTKConfigureEvent(gdk_event->x, gdk_event->y);
+ return false;
+}
+}
+void wxTopLevelWindowGTK::GTKConfigureEvent(int x, int y)
+{
wxPoint point;
- gtk_window_get_position((GtkWindow*)widget, &point.x, &point.y);
-
- win->m_x = point.x;
- win->m_y = point.y;
- wxMoveEvent mevent(point, win->GetId());
- mevent.SetEventObject( win );
- win->HandleWindowEvent( mevent );
+#ifdef GDK_WINDOWING_X11
+ if (gs_decorCacheValid)
+ {
+ const DecorSize& decorSize = GetCachedDecorSize();
+ point.x = x - decorSize.left;
+ point.y = y - decorSize.top;
+ }
+ else
+#endif
+ {
+ gtk_window_get_position(GTK_WINDOW(m_widget), &point.x, &point.y);
+ }
- return FALSE;
-}
+ if (m_x != point.x || m_y != point.y)
+ {
+ m_x = point.x;
+ m_y = point.y;
+ wxMoveEvent event(point, GetId());
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
+ }
}
//-----------------------------------------------------------------------------
gdk_window_set_functions(gtk_widget_get_window(m_widget),
(GdkWMFunction)m_gdkFunc);
- // GTK's shrinking/growing policy
- if ( !(m_gdkFunc & GDK_FUNC_RESIZE) )
- gtk_window_set_resizable(GTK_WINDOW(m_widget), FALSE);
-#ifndef __WXGTK3__
- else
- gtk_window_set_policy(GTK_WINDOW(m_widget), 1, 1, 1);
-#endif
-
const wxIconBundle& icons = GetIcons();
if (icons.GetIconCount())
SetIcons(icons);
// 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;
+ win->m_useCachedClientSize = false;
+ win->m_clientWidth = 0;
gtk_widget_queue_resize(win->m_wxwindow);
}
// it is possible for m_isShown to be false here, see bug #9909
if (win->m_netFrameExtentsTimerId)
{
// WM support for _NET_REQUEST_FRAME_EXTENTS is working
- gs_requestFrameExtentsStatus = 1;
+ gs_requestFrameExtentsStatus = RFE_STATUS_WORKING;
g_source_remove(win->m_netFrameExtentsTimerId);
win->m_netFrameExtentsTimerId = 0;
}
- wxSize decorSize = win->m_decorSize;
- int left, right, top, bottom;
- if (wxGetFrameExtents(event->window, &left, &right, &top, &bottom))
- decorSize.Set(left + right, top + bottom);
+ wxTopLevelWindowGTK::DecorSize decorSize = win->m_decorSize;
+ gs_decorCacheValid = wxGetFrameExtents(event->window,
+ &decorSize.left, &decorSize.right, &decorSize.top, &decorSize.bottom);
win->GTKUpdateDecorSize(decorSize);
}
static gboolean request_frame_extents_timeout(void* data)
{
// WM support for _NET_REQUEST_FRAME_EXTENTS is broken
- gs_requestFrameExtentsStatus = 2;
+ gs_requestFrameExtentsStatus = RFE_STATUS_BROKEN;
gdk_threads_enter();
wxTopLevelWindowGTK* win = static_cast<wxTopLevelWindowGTK*>(data);
win->m_netFrameExtentsTimerId = 0;
- wxSize decorSize = win->m_decorSize;
- int left, right, top, bottom;
- if (wxGetFrameExtents(gtk_widget_get_window(win->m_widget), &left, &right, &top, &bottom))
- decorSize.Set(left + right, top + bottom);
+ wxTopLevelWindowGTK::DecorSize decorSize = win->m_decorSize;
+ wxGetFrameExtents(gtk_widget_get_window(win->m_widget),
+ &decorSize.left, &decorSize.right, &decorSize.top, &decorSize.bottom);
win->GTKUpdateDecorSize(decorSize);
gdk_threads_leave();
return false;
m_updateDecorSize = true;
m_netFrameExtentsTimerId = 0;
m_incWidth = m_incHeight = 0;
+ memset(&m_decorSize, 0, sizeof(m_decorSize));
m_urgency_hint = -2;
}
long style,
const wxString &name )
{
- // always create a frame of some reasonable, even if arbitrary, size (at
- // least for MSW compatibility)
- wxSize size = sizeOrig;
- size.x = WidthDefault(size.x);
- size.y = HeightDefault(size.y);
+ const wxSize size(WidthDefault(sizeOrig.x), HeightDefault(sizeOrig.y));
wxTopLevelWindows.Append( this );
PostCreation();
#ifndef __WXGTK3__
- if ((m_x != -1) || (m_y != -1))
+ if (pos != wxDefaultPosition)
gtk_widget_set_uposition( m_widget, m_x, m_y );
#endif
g_signal_connect_after (m_widget, "focus_out_event",
G_CALLBACK (gtk_frame_focus_out_callback), this);
- // GTK processes key events at the top level first, which handles for
- // menu accelerators and shortcuts before passing the event on to the
- // focus child window to begin propagation. We want to propagate
- // first, so we connect gtk_window_propagate_key_event to
- // key_press_event.
+ // We need to customize the default GTK+ logic for key processing to make
+ // it conforming to wxWidgets event processing order.
g_signal_connect (m_widget, "key_press_event",
- G_CALLBACK (gtk_window_propagate_key_event), NULL);
+ G_CALLBACK (wxgtk_tlw_key_press_event), NULL);
#ifdef GDK_WINDOWING_X11
#ifdef __WXGTK3__
}
}
- // GTK sometimes chooses very small size if max size hint is not explicitly set
- DoSetSizeHints(m_minWidth, m_minHeight, m_maxWidth, m_maxHeight, m_incWidth, m_incHeight);
+ if ((style & wxRESIZE_BORDER) == 0)
+ gtk_window_set_resizable(GTK_WINDOW(m_widget), false);
+#ifndef __WXGTK3__
+ else
+ gtk_window_set_policy(GTK_WINDOW(m_widget), 1, 1, 1);
+#endif
m_decorSize = GetCachedDecorSize();
int w, h;
bool deferShow = show && !m_isShown && m_deferShow;
if (deferShow)
{
- deferShow = m_deferShowAllowed && gs_requestFrameExtentsStatus != 2 &&
+ deferShow = m_deferShowAllowed &&
+ gs_requestFrameExtentsStatus != RFE_STATUS_BROKEN &&
!gtk_widget_get_realized(m_widget) &&
g_signal_handler_find(m_widget,
GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
SubstructureNotifyMask | SubstructureRedirectMask,
(XEvent*)&xevent);
- if (gs_requestFrameExtentsStatus == 0)
+ if (gs_requestFrameExtentsStatus == RFE_STATUS_UNKNOWN)
{
// if WM does not respond to request within 1 second,
// we assume support for _NET_REQUEST_FRAME_EXTENTS is not working
void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const
{
wxSize size(m_width, m_height);
- size -= m_decorSize;
+ size.x -= m_decorSize.left + m_decorSize.right;
+ size.y -= m_decorSize.top + m_decorSize.bottom;
if (size.x < 0) size.x = 0;
if (size.y < 0) size.y = 0;
#if wxUSE_LIBHILDON2
if ( m_x != old_x || m_y != old_y )
{
gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
+ wxMoveEvent event(wxPoint(m_x, m_y), GetId());
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
}
const wxSize oldSize(m_width, m_height);
if (m_width != oldSize.x || m_height != oldSize.y)
{
m_deferShowAllowed = true;
+ m_useCachedClientSize = false;
int w, h;
GTKDoGetSize(&w, &h);
gtk_window_resize(GTK_WINDOW(m_widget), w, h);
- GetClientSize(&m_oldClientWidth, &m_oldClientHeight);
+ DoGetClientSize(&m_clientWidth, &m_clientHeight);
wxSizeEvent event(GetSize(), GetId());
event.SetEventObject(this);
HandleWindowEvent(event);
if ( height )
*height = 0;
}
+ else if (m_useCachedClientSize)
+ base_type::DoGetClientSize(width, height);
else
{
GTKDoGetSize(width, height);
hints.min_height = 1;
hints.max_width = INT_MAX;
hints.max_height = INT_MAX;
- if (minSize.x > m_decorSize.x)
- hints.min_width = minSize.x - m_decorSize.x;
- if (minSize.y > m_decorSize.y)
- hints.min_height = minSize.y - m_decorSize.y;
+ const int decorSize_x = m_decorSize.left + m_decorSize.right;
+ const int decorSize_y = m_decorSize.top + m_decorSize.bottom;
+ if (minSize.x > decorSize_x)
+ hints.min_width = minSize.x - decorSize_x;
+ if (minSize.y > decorSize_y)
+ hints.min_height = minSize.y - decorSize_y;
if (maxSize.x > 0)
{
- hints.max_width = maxSize.x - m_decorSize.x;
+ hints.max_width = maxSize.x - decorSize_x;
if (hints.max_width < hints.min_width)
hints.max_width = hints.min_width;
}
if (maxSize.y > 0)
{
- hints.max_height = maxSize.y - m_decorSize.y;
+ hints.max_height = maxSize.y - decorSize_y;
if (hints.max_height < hints.min_height)
hints.max_height = hints.min_height;
}
}
#ifdef GDK_WINDOWING_X11
-void wxTopLevelWindowGTK::GTKUpdateDecorSize(const wxSize& decorSize)
+void wxTopLevelWindowGTK::GTKUpdateDecorSize(const DecorSize& decorSize)
{
if (!IsMaximized() && !IsFullScreen())
GetCachedDecorSize() = decorSize;
- if (m_updateDecorSize && m_decorSize != decorSize)
+ if (m_updateDecorSize && memcmp(&m_decorSize, &decorSize, sizeof(DecorSize)))
{
- const wxSize diff = decorSize - m_decorSize;
+ m_useCachedClientSize = false;
+ const wxSize diff(
+ decorSize.left - m_decorSize.left + decorSize.right - m_decorSize.right,
+ decorSize.top - m_decorSize.top + decorSize.bottom - m_decorSize.bottom);
m_decorSize = decorSize;
bool resized = false;
if (m_minWidth > 0 || m_minHeight > 0 || m_maxWidth > 0 || m_maxHeight > 0)
int w, h;
GTKDoGetSize(&w, &h);
// but not if size would be less than minimum, it won't take effect
- if (w >= m_minWidth - decorSize.x && h >= m_minHeight - decorSize.y )
+ if (w >= m_minWidth - (decorSize.left + decorSize.right) &&
+ h >= m_minHeight - (decorSize.top + decorSize.bottom))
{
gtk_window_resize(GTK_WINDOW(m_widget), w, h);
resized = true;
m_height += diff.y;
if (m_width < 1) m_width = 1;
if (m_height < 1) m_height = 1;
- m_oldClientWidth = 0;
+ m_clientWidth = 0;
gtk_widget_queue_resize(m_wxwindow);
}
}
{
// gtk_widget_show() was deferred, do it now
m_deferShow = false;
- GetClientSize(&m_oldClientWidth, &m_oldClientHeight);
+ DoGetClientSize(&m_clientWidth, &m_clientHeight);
wxSizeEvent sizeEvent(GetSize(), GetId());
sizeEvent.SetEventObject(this);
HandleWindowEvent(sizeEvent);
}
#endif // GDK_WINDOWING_X11
-wxSize& wxTopLevelWindowGTK::GetCachedDecorSize()
+wxTopLevelWindowGTK::DecorSize& wxTopLevelWindowGTK::GetCachedDecorSize()
{
- static wxSize size[8];
+ static DecorSize size[8];
int index = 0;
// title bar