#include "wx/msgdlg.h"
#include "wx/module.h"
#include "wx/combobox.h"
+#if wxUSE_TOOLBAR_NATIVE
+#include "wx/toolbar.h"
+#endif
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#include "wx/math.h"
#include <ctype.h>
+// FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
+#include <gtk/gtkversion.h>
+#if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
+#undef GTK_DISABLE_DEPRECATED
+#endif
+
#include "wx/gtk/private.h"
#include <gdk/gdkprivate.h>
#include <gdk/gdkkeysyms.h>
}
}
-//-----------------------------------------------------------------------------
-// idle system
-//-----------------------------------------------------------------------------
-
-extern void wxapp_install_idle_handler();
-extern bool g_isIdle;
-
//-----------------------------------------------------------------------------
// local code (see below)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_own_expose_callback( GtkWidget *widget,
+ GdkEventExpose *gdk_event,
+ wxWindowGTK *win )
{
if (gdk_event->count > 0) return FALSE;
//-----------------------------------------------------------------------------
extern "C" {
-static int gtk_window_expose_callback( GtkWidget *widget,
- GdkEventExpose *gdk_event,
- wxWindow *win )
+static gboolean
+gtk_window_expose_callback( GtkWidget *widget,
+ GdkEventExpose *gdk_event,
+ wxWindow *win )
{
DEBUG_MAIN_THREAD
wxFillOtherKeyEventFields(event, win, gdk_event);
event.m_keyCode = key_code;
+#if wxUSE_UNICODE
+ if ( gdk_event->type == GDK_KEY_PRESS || gdk_event->type == GDK_KEY_RELEASE )
+ {
+ event.m_uniChar = key_code;
+ }
+#endif
return true;
}
};
extern "C" {
-static gint gtk_window_key_press_callback( GtkWidget *widget,
- GdkEventKey *gdk_event,
- wxWindow *win )
+static gboolean
+gtk_window_key_press_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindow *win )
{
DEBUG_MAIN_THREAD
if (intercepted_by_IM)
{
wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
- return true;
+ return TRUE;
}
}
if (return_after_IM)
- return false;
+ return FALSE;
#if wxUSE_ACCEL
if (!ret)
event.m_keyCode = key_code;
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if (event.ControlDown() && key_code >= 'a' && key_code <= 'z' )
+ {
+ event.m_keyCode = key_code - 'a' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
// Implement OnCharHook by checking ancestor top level windows
wxWindow *parent = win;
while (parent && !parent->IsTopLevel())
}
extern "C" {
-static void gtk_wxwindow_commit_cb (GtkIMContext *context,
- const gchar *str,
- wxWindow *window)
+static void
+gtk_wxwindow_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ wxWindow *window)
{
wxKeyEvent event( wxEVT_KEY_DOWN );
#else
event.m_keyCode = *pstr;
#endif // wxUSE_UNICODE
+
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if (event.ControlDown() && *pstr >= 'a' && *pstr <= 'z' )
+ {
+ event.m_keyCode = *pstr - 'a' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
if (parent)
{
event.SetEventType( wxEVT_CHAR_HOOK );
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_key_release_callback( GtkWidget *widget,
- GdkEventKey *gdk_event,
- wxWindowGTK *win )
+static gboolean
+gtk_window_key_release_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_button_press_callback( GtkWidget *widget,
- GdkEventButton *gdk_event,
- wxWindowGTK *win )
+static gboolean
+gtk_window_button_press_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_button_release_callback( GtkWidget *widget,
- GdkEventButton *gdk_event,
- wxWindowGTK *win )
+static gboolean
+gtk_window_button_release_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_motion_notify_callback( GtkWidget *widget,
- GdkEventMotion *gdk_event,
- wxWindowGTK *win )
+static gboolean
+gtk_window_motion_notify_callback( GtkWidget *widget,
+ GdkEventMotion *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
}
+ if ( !g_captureWindow )
+ {
+ wxSetCursorEvent cevent( event.m_x, event.m_y );
+ if (win->GetEventHandler()->ProcessEvent( cevent ))
+ {
+ // Rewrite cursor handling here (away from idle).
+ }
+ }
+
if (win->GetEventHandler()->ProcessEvent( event ))
{
g_signal_stop_emission_by_name (widget, "motion_notify_event");
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_wheel_callback (GtkWidget * widget,
- GdkEventScroll * gdk_event,
- wxWindowGTK * win)
+static gboolean
+gtk_window_wheel_callback (GtkWidget * widget,
+ GdkEventScroll * gdk_event,
+ wxWindowGTK * win)
{
DEBUG_MAIN_THREAD
}
extern "C" {
-static gint gtk_window_focus_in_callback( GtkWidget *widget,
- GdkEvent *WXUNUSED(event),
- wxWindow *win )
+static gboolean
+gtk_window_focus_in_callback( GtkWidget *widget,
+ GdkEventFocus *WXUNUSED(event),
+ wxWindow *win )
{
DEBUG_MAIN_THREAD
}
#endif // wxUSE_CARET
+ gboolean ret = FALSE;
+
// does the window itself think that it has the focus?
if ( !win->m_hasFocus )
{
// not yet, notify it
win->m_hasFocus = true;
- if ( DoSendFocusEvents(win) )
- {
- g_signal_stop_emission_by_name (widget, "focus_in_event");
- return TRUE;
- }
+ (void)DoSendFocusEvents(win);
+
+ ret = TRUE;
}
+ // Disable default focus handling for custom windows
+ // since the default GTK+ handler issues a repaint
+ if (win->m_wxwindow)
+ return ret;
+
return FALSE;
}
}
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_focus_out_callback( GtkWidget *widget,
+ GdkEventFocus *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
}
#endif // wxUSE_CARET
+ gboolean ret = FALSE;
+
// don't send the window a kill focus event if it thinks that it doesn't
// have focus already
if ( win->m_hasFocus )
wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
event.SetEventObject( win );
- // even if we did process the event in wx code, still let GTK itself
- // process it too as otherwise bad things happen, especially in GTK2
- // where the text control simply aborts the program if it doesn't get
- // the matching focus out event
(void)win->GetEventHandler()->ProcessEvent( event );
+
+ ret = TRUE;
}
+ // Disable default focus handling for custom windows
+ // since the default GTK+ handler issues a repaint
+ if (win->m_wxwindow)
+ return ret;
+
return FALSE;
}
}
//-----------------------------------------------------------------------------
extern "C" {
-static
-gint gtk_window_enter_callback( GtkWidget *widget,
- GdkEventCrossing *gdk_event,
- wxWindowGTK *win )
+static gboolean
+gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
event.m_x = x + pt.x;
event.m_y = y + pt.y;
+ if ( !g_captureWindow )
+ {
+ wxSetCursorEvent cevent( event.m_x, event.m_y );
+ if (win->GetEventHandler()->ProcessEvent( cevent ))
+ {
+ // Rewrite cursor handling here (away from idle).
+ }
+ }
+
if (win->GetEventHandler()->ProcessEvent( event ))
{
g_signal_stop_emission_by_name (widget, "enter_notify_event");
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_leave_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
- GdkEventButton *gdk_event,
- wxWindowGTK *win)
+static gboolean
+gtk_scrollbar_button_press_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win)
{
DEBUG_MAIN_THREAD
//-----------------------------------------------------------------------------
extern "C" {
-static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
- GdkEventButton *WXUNUSED(gdk_event),
- wxWindowGTK *win)
+static gboolean
+gtk_scrollbar_button_release_callback( GtkRange *widget,
+ GdkEventButton *WXUNUSED(gdk_event),
+ wxWindowGTK *win)
{
DEBUG_MAIN_THREAD
been realized, so we do this directly after realization. */
extern "C" {
-static gint
+static void
gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
{
DEBUG_MAIN_THREAD
wxWindowCreateEvent event( win );
event.SetEventObject( win );
win->GetEventHandler()->ProcessEvent( event );
-
- return FALSE;
}
}
/* Initialize XIM support */
extern "C" {
-static gint
+static void
gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
{
wxapp_install_idle_handler();
#ifdef HAVE_XIM
- if (win->m_ic) return FALSE;
- if (!widget) return FALSE;
- if (!gdk_im_ready()) return FALSE;
+ if (win->m_ic) return;
+ if (!widget) return;
+ if (!gdk_im_ready()) return;
win->m_icattr = gdk_ic_attr_new();
- if (!win->m_icattr) return FALSE;
+ if (!win->m_icattr) return;
gint width, height;
GdkEventMask mask;
gdk_im_begin (win->m_ic, widget->window);
}
#endif // HAVE_XIM
-
- return FALSE;
}
}
g_signal_connect (m_wxwindow, "expose_event",
G_CALLBACK (gtk_window_expose_callback), this);
- // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
+ gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
}
// Create input method handler
if (m_focusWidget == NULL)
m_focusWidget = m_widget;
- g_signal_connect (m_focusWidget, "focus_in_event",
+ if (m_wxwindow)
+ {
+ g_signal_connect (m_focusWidget, "focus_in_event",
G_CALLBACK (gtk_window_focus_in_callback), this);
- g_signal_connect_after (m_focusWidget, "focus_out_event",
+ g_signal_connect (m_focusWidget, "focus_out_event",
G_CALLBACK (gtk_window_focus_out_callback), this);
+ }
+ else
+ {
+ g_signal_connect_after (m_focusWidget, "focus_in_event",
+ G_CALLBACK (gtk_window_focus_in_callback), this);
+ g_signal_connect_after (m_focusWidget, "focus_out_event",
+ G_CALLBACK (gtk_window_focus_out_callback), this);
+ }
}
// connect to the various key and mouse handlers
y = currentY;
AdjustForParentClientOrigin(x, y, sizeFlags);
- if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
+ // calculate the best size if we should auto size the window
+ if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
+ ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
+ {
+ const wxSize sizeBest = GetBestSize();
+ if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
+ width = sizeBest.x;
+ if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
+ height = sizeBest.y;
+ }
+
+ if (width != -1)
+ m_width = width;
+ if (height != -1)
+ m_height = height;
+
+ int minWidth = GetMinWidth(),
+ minHeight = GetMinHeight(),
+ maxWidth = GetMaxWidth(),
+ maxHeight = GetMaxHeight();
+
+ if ((minWidth != -1) && (m_width < minWidth )) m_width = minWidth;
+ if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
+ if ((maxWidth != -1) && (m_width > maxWidth )) m_width = maxWidth;
+ if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
+
+#if wxUSE_TOOLBAR_NATIVE
+ if (wxDynamicCast(GetParent(), wxToolBar))
{
- /* don't set the size for children of wxNotebook, just take the values. */
+ // don't take the x,y values, they're wrong because toolbar sets them
+ GtkWidget *widget = GTK_WIDGET(m_widget);
+ gtk_widget_set_size_request (widget, m_width, m_height);
+ if (GTK_WIDGET_VISIBLE (widget))
+ gtk_widget_queue_resize (widget);
+ }
+ 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_y = y + pizza->yoffset;
}
- // calculate the best size if we should auto size the window
- if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
- ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
- {
- const wxSize sizeBest = GetBestSize();
- if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
- width = sizeBest.x;
- if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
- height = sizeBest.y;
- }
-
- if (width != -1)
- m_width = width;
- if (height != -1)
- m_height = height;
-
- int minWidth = GetMinWidth(),
- minHeight = GetMinHeight(),
- maxWidth = GetMaxWidth(),
- maxHeight = GetMaxHeight();
-
- if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
- if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
- if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
- if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
-
int left_border = 0;
int right_border = 0;
int top_border = 0;
void wxWindowGTK::OnInternalIdle()
{
if ( m_dirtyTabOrder )
+ {
+ m_dirtyTabOrder = false;
RealizeTabOrder();
+ }
// Update style if the window was not yet realized
// and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
wxapp_install_idle_handler();
}
+bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
+{
+ // none needed by default
+ return false;
+}
+
+void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
+{
+ // nothing to do by default since none is needed
+}
+
void wxWindowGTK::RealizeTabOrder()
{
if (m_wxwindow)
{
- if (m_children.size() > 0)
+ if ( !m_children.empty() )
{
+ // we don't only construct the correct focus chain but also use
+ // this opportunity to update the mnemonic widgets for the widgets
+ // that need them
+
GList *chain = NULL;
+ wxWindowGTK* mnemonicWindow = NULL;
- for (wxWindowList::const_iterator i = m_children.begin();
- i != m_children.end(); ++i)
+ for ( wxWindowList::const_iterator i = m_children.begin();
+ i != m_children.end();
+ ++i )
{
- chain = g_list_prepend(chain, (*i)->m_widget);
+ wxWindowGTK *win = *i;
+
+ if ( mnemonicWindow )
+ {
+ if ( win->AcceptsFocusFromKeyboard() )
+ {
+ // wxComboBox et al. needs to focus on on a different
+ // widget than m_widget, so if the main widget isn't
+ // focusable try the connect widget
+ GtkWidget* w = win->m_widget;
+ if ( !GTK_WIDGET_CAN_FOCUS(w) )
+ {
+ w = win->GetConnectWidget();
+ if ( !GTK_WIDGET_CAN_FOCUS(w) )
+ w = NULL;
+ }
+
+ if ( w )
+ {
+ mnemonicWindow->GTKWidgetDoSetMnemonic(w);
+ mnemonicWindow = NULL;
+ }
+ }
+ }
+ else if ( win->GTKWidgetNeedsMnemonic() )
+ {
+ mnemonicWindow = win;
+ }
+
+ chain = g_list_prepend(chain, win->m_widget);
}
chain = g_list_reverse(chain);
gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
g_list_free(chain);
}
- else
+ else // no children
{
gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
}
}
-
- m_dirtyTabOrder = false;
}
void wxWindowGTK::Raise()
gdk_window_warp_pointer( window, x, y );
}
+static bool wxScrollAdjust(GtkAdjustment* adj, double change)
+{
+ double value_start = adj->value;
+ double value = value_start + change;
+ double upper = adj->upper - adj->page_size;
+ if (value > upper)
+ {
+ value = upper;
+ }
+ // Lower bound will be checked by gtk_adjustment_set_value
+ gtk_adjustment_set_value(adj, value);
+ return adj->value != value_start;
+}
+
+bool wxWindowGTK::ScrollLines(int lines)
+{
+ return
+ m_vAdjust != NULL &&
+ wxScrollAdjust(m_vAdjust, lines * m_vAdjust->step_increment);
+}
+
+bool wxWindowGTK::ScrollPages(int pages)
+{
+ return
+ m_vAdjust != NULL &&
+ wxScrollAdjust(m_vAdjust, pages * m_vAdjust->page_increment);
+}
+
+void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment* adj)
+{
+ wxASSERT(m_vAdjust == NULL);
+ m_vAdjust = adj;
+}
void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
{