#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/app.h"
- #include "wx/frame.h"
+ #include "wx/toplevel.h"
#include "wx/dcclient.h"
#include "wx/menu.h"
#include "wx/settings.h"
#include "wx/msgdlg.h"
- #include "wx/textctrl.h"
- #include "wx/radiobut.h"
- #include "wx/toolbar.h"
- #include "wx/combobox.h"
- #include "wx/layout.h"
#include "wx/math.h"
#endif
#include "wx/tooltip.h"
#include "wx/caret.h"
#include "wx/fontutil.h"
+#include "wx/sysopt.h"
#ifdef __WXDEBUG__
#include "wx/thread.h"
// make it extern because wxStaticText needs to disconnect this one
extern "C" {
-void wxgtk_window_size_request_callback(GtkWidget *widget,
+void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
GtkRequisition *requisition,
- wxWindow *win)
+ wxWindow * win)
{
int w, h;
win->GetSize( &w, &h );
extern "C" {
static
-void wxgtk_combo_size_request_callback(GtkWidget *widget,
+void wxgtk_combo_size_request_callback(GtkWidget * WXUNUSED(widget),
GtkRequisition *requisition,
- wxComboBox *win)
+ wxWindow* win)
{
// This callback is actually hooked into the text entry
// of the combo box, not the GtkHBox.
if (g_blockEventsOnDrag)
return FALSE;
+ // GTK+ sends keypress events to the focus widget and then
+ // to all its parent and grandparent widget. We only want
+ // the key events from the focus widget.
+ if (!GTK_WIDGET_HAS_FOCUS(widget))
+ return FALSE;
wxKeyEvent event( wxEVT_KEY_DOWN );
bool ret = false;
return_after_IM = true;
}
- // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
- // When we get a key_press event here, it could be originate
- // from the current widget or its child widgets. However, only the widget
- // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
- // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
- // originated from its child widgets and shouldn't be passed to IM context.
- // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
- // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
- // widgets has both IM context and input focus, the event should be filtered
- // by gtk_im_context_filter_keypress().
- // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
- if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+ if ((!ret) && (win->m_imData != NULL))
{
// We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
// docs, if IM filter returns true, no further processing should be done.
extern "C" {
static void
-gtk_wxwindow_commit_cb (GtkIMContext *context,
+gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
const gchar *str,
wxWindow *window)
{
extern "C" {
static gboolean
-gtk_window_key_release_callback( GtkWidget *widget,
+gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
GdkEventKey *gdk_event,
wxWindowGTK *win )
{
g_lastButtonNumber = gdk_event->button;
- if (win->m_wxwindow && (g_focusWindow != win) && win->IsFocusable())
- {
- gtk_widget_grab_focus( win->m_wxwindow );
- }
-
// GDK sends surplus button down events
// before a double click event. We
// need to filter these out.
if ( ret )
return TRUE;
- if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
- (g_focusWindow != win) && win->IsFocusable())
+ if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
+ (g_focusWindow != win) /* && win->IsFocusable() */)
{
- gtk_widget_grab_focus( win->m_wxwindow );
+ win->SetFocus();
}
if (event_type == wxEVT_RIGHT_DOWN)
//-----------------------------------------------------------------------------
static gboolean
-gtk_window_motion_notify_callback( GtkWidget *widget,
+gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
GdkEventMotion *gdk_event,
wxWindowGTK *win )
{
//-----------------------------------------------------------------------------
static gboolean
-gtk_window_focus_in_callback( GtkWidget *widget,
+gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
GdkEventFocus *WXUNUSED(event),
wxWindow *win )
{
//-----------------------------------------------------------------------------
static gboolean
-gtk_window_focus_out_callback( GtkWidget *widget,
- GdkEventFocus *gdk_event,
+gtk_window_focus_out_callback( GtkWidget * WXUNUSED(widget),
+ GdkEventFocus * WXUNUSED(gdk_event),
wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
static gboolean
wx_window_focus_callback(GtkWidget *widget,
- GtkDirectionType direction,
+ GtkDirectionType WXUNUSED(direction),
wxWindowGTK *win)
{
// the default handler for focus signal in GtkPizza (or, rather, in
const int orient = wxWindow::OrientFromScrollDir(
win->ScrollDirFromRange(range));
- wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient);
- event.SetEventObject(win);
- win->GTKProcessEvent(event);
+ wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBRELEASE,
+ win->GetScrollPos(orient), orient);
+ evt.SetEventObject(win);
+ win->GTKProcessEvent(evt);
}
}
}
//-----------------------------------------------------------------------------
-// "size_allocate"
+// "size_allocate" from m_wxwindow or m_widget
//-----------------------------------------------------------------------------
-static
-void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
- GtkAllocation *alloc,
- wxWindow *win )
+static void
+size_allocate(GtkWidget*, GtkAllocation* alloc, wxWindow* win)
{
- int client_width = 0;
- int client_height = 0;
- win->GetClientSize( &client_width, &client_height );
- if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
- return;
-
- if ( !client_width && !client_height )
- {
- // the window is currently unmapped, don't generate size events
- return;
- }
-
- win->m_oldClientWidth = client_width;
- win->m_oldClientHeight = client_height;
-
- if (!win->m_nativeSizeEvent)
+ int w = alloc->width;
+ int h = alloc->height;
+ if (win->m_wxwindow)
{
- wxSizeEvent event( win->GetSize(), win->GetId() );
- event.SetEventObject( win );
- win->GTKProcessEvent( event );
+ const int border = GTK_CONTAINER(win->m_wxwindow)->border_width;
+ w -= 2 * border;
+ h -= 2 * border;
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ }
+ if (win->m_oldClientWidth != w || win->m_oldClientHeight != h)
+ {
+ win->m_oldClientWidth = w;
+ win->m_oldClientHeight = h;
+ // this callback can be connected to m_wxwindow,
+ // so always get size from m_widget->allocation
+ win->m_width = win->m_widget->allocation.width;
+ win->m_height = win->m_widget->allocation.height;
+ if (!win->m_nativeSizeEvent)
+ {
+ wxSizeEvent event(win->GetSize(), win->GetId());
+ event.SetEventObject(win);
+ win->GTKProcessEvent(event);
+ }
}
}
//-----------------------------------------------------------------------------
-// "grab_broken"
+// "grab_broken"
//-----------------------------------------------------------------------------
-#ifdef __WXGTK210__
-static void
-gtk_window_grab_broken( GtkWidget *m_widget,
+#if GTK_CHECK_VERSION(2, 8, 0)
+static gboolean
+gtk_window_grab_broken( GtkWidget*,
GdkEventGrabBroken *event,
wxWindow *win )
{
// Mouse capture has been lost involuntarily, notify the application
- if( !event->keyboard && win && wxWindow::GetCapture() == win )
+ if(!event->keyboard && wxWindow::GetCapture() == win)
{
wxMouseCaptureLostEvent evt( win->GetId() );
evt.SetEventObject( win );
win->GetEventHandler()->ProcessEvent( evt );
}
+ return false;
}
#endif
+//-----------------------------------------------------------------------------
+// "style_set"
+//-----------------------------------------------------------------------------
+
+static
+void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
+ GtkStyle *previous_style,
+ wxWindow* win )
+{
+ //wxLogDebug(wxT("gtk_window_style_set_callback"));
+ if (win && previous_style)
+ {
+ wxString name(win->GetName());
+ //wxLogDebug(wxT("gtk_window_style_set_callback %s"), name.c_str());
+ wxSysColourChangedEvent event;
+ event.SetEventObject(win);
+
+ win->GTKProcessEvent( event );
+ }
+}
} // extern "C"
+// Connect/disconnect style-set
+
+void wxConnectStyleSet(wxWindow* win)
+{
+ if (win->m_wxwindow)
+ g_signal_connect (win->m_wxwindow, "style_set",
+ G_CALLBACK (gtk_window_style_set_callback), win);
+}
+
+void wxDisconnectStyleSet(wxWindow* win)
+{
+ if (win->m_wxwindow)
+ g_signal_handlers_disconnect_by_func (win->m_wxwindow,
+ (gpointer) gtk_window_style_set_callback,
+ win);
+}
+
+// Helper to suspend colour change event event processing while we change a widget's style
+class wxSuspendStyleEvents
+{
+public:
+ wxSuspendStyleEvents(wxWindow* win)
+ {
+ m_win = win;
+ if (win->IsTopLevel())
+ wxDisconnectStyleSet(win);
+ }
+ ~wxSuspendStyleEvents()
+ {
+ if (m_win->IsTopLevel())
+ wxConnectStyleSet(m_win);
+ }
+
+ wxWindow* m_win;
+};
+
// ----------------------------------------------------------------------------
// this wxWindowBase function is implemented here (in platform-specific file)
// because it is static and so couldn't be made virtual
m_hasScrolling = false;
m_isScrolling = false;
m_mouseButtonDown = false;
- m_blockScrollEvent = false;
// initialize scrolling stuff
for ( int dir = 0; dir < ScrollDir_Max; dir++ )
m_oldClientWidth =
m_oldClientHeight = 0;
- m_resizing = false;
-
m_insertCallback = wxInsertChildInWindow;
m_hasFocus = false;
g_signal_connect (connect_widget, "realize",
G_CALLBACK (gtk_window_realized_callback), this);
+ if (!IsTopLevel())
+ {
+ g_signal_connect(m_wxwindow ? m_wxwindow : m_widget, "size_allocate",
+ G_CALLBACK(size_allocate), this);
+ }
+
if (m_wxwindow)
{
- // Catch native resize events
- g_signal_connect (m_wxwindow, "size_allocate",
- G_CALLBACK (gtk_window_size_callback), this);
-#ifdef __WXGTK210__
+#if GTK_CHECK_VERSION(2, 8, 0)
if (!gtk_check_version(2,8,0))
{
// Make sure we can notify the app when mouse capture is lost
if ( connect_widget != m_wxwindow )
{
-#ifdef __WXGTK210__
+#if GTK_CHECK_VERSION(2, 8, 0)
if (!gtk_check_version(2,8,0))
{
// Make sure we can notify app code when mouse capture is lost
G_CALLBACK (gtk_window_enter_callback), this);
g_signal_connect (widget, "leave_notify_event",
G_CALLBACK (gtk_window_leave_callback), this);
+
+ if (IsTopLevel() && m_wxwindow)
+ g_signal_connect (m_wxwindow, "style_set",
+ G_CALLBACK (gtk_window_style_set_callback), this);
}
bool wxWindowGTK::Destroy()
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
- if (m_resizing) return; /* I don't like recursions */
- m_resizing = true;
-
int currentX, currentY;
GetPosition(¤tX, ¤tY);
if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
height = sizeBest.y;
}
+ const wxSize oldSize(m_width, m_height);
if (width != -1)
m_width = width;
if (height != -1)
ConstrainSize();
-#if wxUSE_TOOLBAR_NATIVE
- if (wxDynamicCast(GetParent(), wxToolBar))
- {
- // don't take the x,y values, they're wrong because toolbar sets them
- GtkWidget *widget = m_widget;
- gtk_widget_set_size_request (widget, m_width, m_height);
- }
- else
-#endif
- if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook
- {
- // don't set the size for children of wxNotebook, just take the values.
- m_x = x;
- m_y = y;
- m_width = width;
- m_height = height;
- }
- else
+ if (m_parent->m_wxwindow)
{
GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
- if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
- {
- if (x != -1) m_x = x + gtk_pizza_get_xoffset( pizza );
- if (y != -1) m_y = y + gtk_pizza_get_yoffset( pizza );
- }
- else
- {
- m_x = x + gtk_pizza_get_xoffset( pizza );
- m_y = y + gtk_pizza_get_yoffset( pizza );
- }
+ m_x = x + gtk_pizza_get_xoffset(pizza);
+ m_y = y + gtk_pizza_get_yoffset(pizza);
int left_border = 0;
int right_border = 0;
m_height+top_border+bottom_border );
}
- if (m_hasScrolling)
+ if (m_width != oldSize.x || m_height != oldSize.y)
{
- /* Sometimes the client area changes size without the
- whole windows's size changing, but if the whole
- windows's size doesn't change, no wxSizeEvent will
- normally be sent. Here we add an extra test if
- the client test has been changed and this will
- be used then. */
+ // update these variables to keep size_allocate handler
+ // from sending another size event for this change
GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
- }
-
-/*
- wxPrintf( "OnSize sent from " );
- if (GetClassInfo() && GetClassInfo()->GetClassName())
- wxPrintf( GetClassInfo()->GetClassName() );
- wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
-*/
- if (!m_nativeSizeEvent)
- {
- wxSizeEvent event( wxSize(m_width,m_height), GetId() );
- event.SetEventObject( this );
- GetEventHandler()->ProcessEvent( event );
+ gtk_widget_queue_resize(m_widget);
+ if (!m_nativeSizeEvent)
+ {
+ wxSizeEvent event( wxSize(m_width,m_height), GetId() );
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( event );
+ }
}
-
- m_resizing = false;
}
bool wxWindowGTK::GtkShowFromOnIdle()
}
}
- if (wxUpdateUIEvent::CanUpdate(this))
+ if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}
int dx = 0;
int dy = 0;
- if (m_parent && m_parent->m_wxwindow)
+ if (!IsTopLevel() && m_parent && m_parent->m_wxwindow)
{
GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
dx = gtk_pizza_get_xoffset( pizza );
wxFont font = GetFont();
wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
- PangoContext *context = NULL;
- if (m_widget)
- context = gtk_widget_get_pango_context( m_widget );
+ PangoContext* context = gtk_widget_get_pango_context(m_widget);
if (!context)
return 0;
wxFont font = GetFont();
wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
- PangoContext *context = NULL;
- if (m_widget)
- context = gtk_widget_get_pango_context( m_widget );
+ PangoContext* context = gtk_widget_get_pango_context(m_widget);
if (!context)
return 0;
if (m_wxwindow)
{
+ // wxWindow::SetFocus() should really set the focus to
+ // this control, whatever the flags are
+ if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow))
+ GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+
if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
{
gtk_widget_grab_focus (m_wxwindow);
}
}
- else if (m_widget)
+ else
{
+ // wxWindow::SetFocus() should really set the focus to
+ // this control, whatever the flags are
+ if (!GTK_WIDGET_CAN_FOCUS(m_widget))
+ GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
+
if (GTK_IS_CONTAINER(m_widget))
{
-#if wxUSE_RADIOBTN
- if (IsKindOf(CLASSINFO(wxRadioButton)))
+ if (GTK_IS_RADIO_BUTTON(m_widget))
{
gtk_widget_grab_focus (m_widget);
return;
}
-#endif // wxUSE_RADIOBTN
gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
}
return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Page, pages);
}
-void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
+void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
+ const wxRect *rect)
{
if (!m_widget)
return;
wxWindowDC dc( (wxWindow*)this );
dc.SetClippingRegion( m_updateRegion );
+ // Work around gtk-qt <= 0.60 bug whereby the window colour
+ // remains grey
+ if (GetBackgroundStyle() == wxBG_STYLE_COLOUR && GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
+ {
+ dc.SetBackground(wxBrush(GetBackgroundColour()));
+ dc.Clear();
+ }
+
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
{
+ wxSuspendStyleEvents s(this);
+
if (m_wxwindow)
gtk_widget_modify_style(m_wxwindow, style);
else
return false;
}
-void wxWindowGTK::BlockScrollEvent()
-{
- wxASSERT(!m_blockScrollEvent);
- m_blockScrollEvent = true;
-}
-
-void wxWindowGTK::UnblockScrollEvent()
-{
- wxASSERT(m_blockScrollEvent);
- m_blockScrollEvent = false;
-}
-
void wxWindowGTK::SetScrollbar(int orient,
int pos,
int thumbVisible,
int range,
bool WXUNUSED(update))
{
- GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
+ const int dir = ScrollDirFromOrient(orient);
+ GtkRange* const sb = m_scrollBar[dir];
wxCHECK_RET( sb, _T("this window is not scrollable") );
if (range > 0)
thumbVisible = 1;
}
- if (pos > range - thumbVisible)
- pos = range - thumbVisible;
- if (pos < 0)
- pos = 0;
GtkAdjustment * const adj = sb->adjustment;
adj->step_increment = 1;
adj->page_increment =
adj->page_size = thumbVisible;
- adj->upper = range;
- SetScrollPos(orient, pos);
- gtk_adjustment_changed(adj);
+ adj->value = pos;
+
+ g_signal_handlers_block_by_func(
+ sb, (void*)gtk_scrollbar_value_changed, this);
+
+ gtk_range_set_range(sb, 0, range);
+ m_scrollPos[dir] = sb->adjustment->value;
+
+ g_signal_handlers_unblock_by_func(
+ sb, (void*)gtk_scrollbar_value_changed, this);
}
void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
// will not move smoothly while tracking when using wxScrollHelper.
if (GetScrollPos(orient) != pos)
{
- GtkAdjustment* adj = sb->adjustment;
- const int max = int(adj->upper - adj->page_size);
- if (pos > max)
- pos = max;
- if (pos < 0)
- pos = 0;
- m_scrollPos[dir] = adj->value = pos;
-
- g_signal_handlers_block_by_func(m_scrollBar[dir],
- (gpointer)gtk_scrollbar_value_changed, this);
+ g_signal_handlers_block_by_func(
+ sb, (void*)gtk_scrollbar_value_changed, this);
- gtk_adjustment_value_changed(adj);
+ gtk_range_set_value(sb, pos);
+ m_scrollPos[dir] = sb->adjustment->value;
- g_signal_handlers_unblock_by_func(m_scrollBar[dir],
- (gpointer)gtk_scrollbar_value_changed, this);
+ g_signal_handlers_unblock_by_func(
+ sb, (void*)gtk_scrollbar_value_changed, this);
}
}
// No scrolling requested.
if ((dx == 0) && (dy == 0)) return;
-
+
m_clipPaintRegion = true;
if (GetLayoutDirection() == wxLayout_RightToLeft)
gtkstyle = GTK_SHADOW_OUT;
else if (wxstyle & wxBORDER_SUNKEN)
gtkstyle = GTK_SHADOW_IN;
+#if 0
+ // Now obsolete
else if (wxstyle & wxBORDER_DOUBLE)
gtkstyle = GTK_SHADOW_ETCHED_IN;
+#endif
else //default
gtkstyle = GTK_SHADOW_IN;