X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1dabdced0ebd3fb19419b5a4737e2e30d0c8bd12..7f81dfa1a01ad34d59923a48868732de8de282ff:/src/gtk/window.cpp?ds=sidebyside diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index dc244f803a..ee7f1f9f46 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: gtk/window.cpp +// Name: src/gtk/window.cpp // Purpose: // Author: Robert Roebling // Id: $Id$ @@ -15,15 +15,25 @@ #endif #include "wx/window.h" -#include "wx/dcclient.h" -#include "wx/frame.h" -#include "wx/app.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/frame.h" + #include "wx/dcclient.h" + #include "wx/menu.h" +#endif + #include "wx/layout.h" -#include "wx/utils.h" #include "wx/dialog.h" #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" @@ -41,11 +51,8 @@ #include "wx/textctrl.h" #endif -#include "wx/menu.h" #include "wx/statusbr.h" -#include "wx/intl.h" #include "wx/settings.h" -#include "wx/log.h" #include "wx/fontutil.h" #ifdef __WXDEBUG__ @@ -55,6 +62,12 @@ #include "wx/math.h" #include +// FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0 +#include +#if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0) +#undef GTK_DISABLE_DEPRECATED +#endif + #include "wx/gtk/private.h" #include #include @@ -260,7 +273,7 @@ gdk_window_warp_pointer (GdkWindow *window, gint y) { if (!window) - window = GDK_ROOT_PARENT(); + window = gdk_get_default_root_window(); if (!GDK_WINDOW_DESTROYED(window)) { @@ -272,13 +285,6 @@ gdk_window_warp_pointer (GdkWindow *window, } } -//----------------------------------------------------------------------------- -// idle system -//----------------------------------------------------------------------------- - -extern void wxapp_install_idle_handler(); -extern bool g_isIdle; - //----------------------------------------------------------------------------- // local code (see below) //----------------------------------------------------------------------------- @@ -307,6 +313,35 @@ wxWindow *wxFindFocusedChild(wxWindowGTK *win) return (wxWindow *)NULL; } +static void GetScrollbarWidth(GtkWidget* widget, int& w, int& h) +{ + GtkScrolledWindow* scroll_window = GTK_SCROLLED_WINDOW(widget); + GtkScrolledWindowClass* scroll_class = GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window)); + GtkRequisition scroll_req; + + w = 0; + if (scroll_window->vscrollbar_visible) + { + scroll_req.width = 2; + scroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) + (scroll_window->vscrollbar, &scroll_req ); + w = scroll_req.width + + scroll_class->scrollbar_spacing; + } + + h = 0; + if (scroll_window->hscrollbar_visible) + { + scroll_req.width = 2; + scroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) + (scroll_window->hscrollbar, &scroll_req ); + h = scroll_req.height + + scroll_class->scrollbar_spacing; + } +} + static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) { // wxUniversal widgets draw the borders and scrollbars themselves @@ -319,33 +354,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) if (win->m_hasScrolling) { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget); - - GtkRequisition vscroll_req; - vscroll_req.width = 2; - vscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) - (scroll_window->vscrollbar, &vscroll_req ); - - GtkRequisition hscroll_req; - hscroll_req.width = 2; - hscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) - (scroll_window->hscrollbar, &hscroll_req ); - - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) ); - - if (scroll_window->vscrollbar_visible) - { - dw += vscroll_req.width; - dw += scroll_class->scrollbar_spacing; - } - - if (scroll_window->hscrollbar_visible) - { - dh += hscroll_req.height; - dh += scroll_class->scrollbar_spacing; - } + GetScrollbarWidth(widget, dw, dh); } int dx = 0; @@ -388,7 +397,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) gdk_draw_rectangle( widget->window, gc, FALSE, dx, dy, widget->allocation.width-dw-1, widget->allocation.height-dh-1 ); - gdk_gc_unref( gc ); + g_object_unref (gc); return; } #endif // __WXUNIVERSAL__ @@ -399,7 +408,10 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) //----------------------------------------------------------------------------- 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; @@ -467,9 +479,10 @@ void wxgtk_combo_size_request_callback(GtkWidget *widget, //----------------------------------------------------------------------------- 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 @@ -645,11 +658,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) break; case GDK_Prior: // == GDK_Page_Up - key_code = WXK_PRIOR; + key_code = WXK_PAGEUP; break; case GDK_Next: // == GDK_Page_Down - key_code = WXK_NEXT; + key_code = WXK_PAGEDOWN; break; case GDK_End: @@ -728,11 +741,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) break; case GDK_KP_Prior: // == GDK_KP_Page_Up - key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR; + key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP; break; case GDK_KP_Next: // == GDK_KP_Page_Down - key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT; + key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN; break; case GDK_KP_End: @@ -830,10 +843,6 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event, event.m_rawFlags = 0; #if wxUSE_UNICODE event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval); - if ( gdk_event->type == GDK_KEY_PRESS || gdk_event->type == GDK_KEY_RELEASE ) - { - event.m_uniChar = toupper(event.m_uniChar); - } #endif wxGetMousePosition( &x, &y ); win->ScreenToClient( &x, &y ); @@ -941,6 +950,12 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event, 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; } @@ -958,14 +973,15 @@ struct wxGtkIMData } ~wxGtkIMData() { - g_object_unref(context); + g_object_unref (context); } }; 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 @@ -1015,12 +1031,12 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, 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) @@ -1078,7 +1094,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, #if wxUSE_UNICODE event.m_uniChar = event.m_keyCode; #endif - } + } // Implement OnCharHook by checking ancestor top level windows wxWindow *parent = win; @@ -1174,9 +1190,10 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } 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 ); @@ -1188,13 +1205,8 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, window, window->m_imData->lastKeyEvent); } -#if wxUSE_UNICODE - const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str ); -#else - const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str ); - const wxCharBuffer data = wxConvLocal.cWC2MB( wdata ); -#endif // wxUSE_UNICODE - if( !(const wxChar*)data ) + const wxWxCharBuffer data(wxGTK_CONV_BACK(str)); + if( !data ) return; bool ret = false; @@ -1222,8 +1234,8 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, event.m_keyCode = *pstr - 'a' + 1; #if wxUSE_UNICODE event.m_uniChar = event.m_keyCode; -#endif - } +#endif + } if (parent) { @@ -1246,9 +1258,10 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, //----------------------------------------------------------------------------- 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 @@ -1419,9 +1432,10 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) //----------------------------------------------------------------------------- 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 @@ -1577,6 +1591,10 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, if ( !g_captureWindow ) win = FindWindowForMouseEvent(win, event.m_x, event.m_y); + // reset the event object and id in case win changed. + event.SetEventObject( win ); + event.SetId( win->GetId() ); + if (win->GetEventHandler()->ProcessEvent( event )) { g_signal_stop_emission_by_name (widget, "button_press_event"); @@ -1609,9 +1627,10 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, //----------------------------------------------------------------------------- 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 @@ -1656,6 +1675,10 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, if ( !g_captureWindow ) win = FindWindowForMouseEvent(win, event.m_x, event.m_y); + // reset the event object and id in case win changed. + event.SetEventObject( win ); + event.SetId( win->GetId() ); + if (win->GetEventHandler()->ProcessEvent( event )) { g_signal_stop_emission_by_name (widget, "button_release_event"); @@ -1671,9 +1694,10 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, //----------------------------------------------------------------------------- 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 @@ -1730,6 +1754,19 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, else // no capture { win = FindWindowForMouseEvent(win, event.m_x, event.m_y); + + // reset the event object and id in case win changed. + event.SetEventObject( win ); + event.SetId( win->GetId() ); + } + + 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 )) @@ -1743,28 +1780,25 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, } //----------------------------------------------------------------------------- -// "mouse_wheel_event" +// "scroll_event", (mouse wheel event) //----------------------------------------------------------------------------- extern "C" { -static gint gtk_window_wheel_callback (GtkWidget * widget, - GdkEventScroll * gdk_event, - wxWindowGTK * win) +static gboolean +window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win) { DEBUG_MAIN_THREAD if (g_isIdle) wxapp_install_idle_handler(); - wxEventType event_type = wxEVT_NULL; - if (gdk_event->direction == GDK_SCROLL_UP) - event_type = wxEVT_MOUSEWHEEL; - else if (gdk_event->direction == GDK_SCROLL_DOWN) - event_type = wxEVT_MOUSEWHEEL; - else - return FALSE; + if (gdk_event->direction != GDK_SCROLL_UP && + gdk_event->direction != GDK_SCROLL_DOWN) + { + return false; + } - wxMouseEvent event( event_type ); + wxMouseEvent event(wxEVT_MOUSEWHEEL); // Can't use InitMouse macro because scroll events don't have button event.SetTimestamp( gdk_event->time ); event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); @@ -1789,13 +1823,7 @@ static gint gtk_window_wheel_callback (GtkWidget * widget, event.SetId( win->GetId() ); event.SetTimestamp( gdk_event->time ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "scroll_event"); - return TRUE; - } - - return FALSE; + return win->GetEventHandler()->ProcessEvent(event); } } @@ -1834,9 +1862,10 @@ static bool DoSendFocusEvents(wxWindow *win) } 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 @@ -1866,19 +1895,24 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, } #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; } } @@ -1888,7 +1922,10 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, //----------------------------------------------------------------------------- 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 @@ -1922,6 +1959,8 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk } #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 ) @@ -1931,13 +1970,16 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk 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; } } @@ -1947,10 +1989,10 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk //----------------------------------------------------------------------------- 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 @@ -1977,6 +2019,15 @@ gint gtk_window_enter_callback( GtkWidget *widget, 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"); @@ -1992,7 +2043,10 @@ gint gtk_window_enter_callback( GtkWidget *widget, //----------------------------------------------------------------------------- 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 @@ -2040,65 +2094,23 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ } //----------------------------------------------------------------------------- -// "value_changed" from m_vAdjust +// "value_changed" from scrollbar //----------------------------------------------------------------------------- extern "C" { -static void gtk_window_vscroll_callback( GtkAdjustment *adjust, - wxWindowGTK *win ) +static void +gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (g_blockEventsOnDrag) return; - - if (!win->m_hasVMT) return; - - float diff = adjust->value - win->m_oldVerticalPos; - if (fabs(diff) < 0.2) return; - - win->m_oldVerticalPos = adjust->value; - - wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP); - - int value = (int)(adjust->value+0.5); - - wxScrollWinEvent event( command, value, wxVERTICAL ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); -} -} - -//----------------------------------------------------------------------------- -// "value_changed" from m_hAdjust -//----------------------------------------------------------------------------- - -extern "C" { -static void gtk_window_hscroll_callback( GtkAdjustment *adjust, - wxWindowGTK *win ) -{ - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (g_blockEventsOnDrag) return; - if (!win->m_hasVMT) return; - - float diff = adjust->value - win->m_oldHorizontalPos; - if (fabs(diff) < 0.2) return; - - wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP); - - win->m_oldHorizontalPos = adjust->value; - - int value = (int)(adjust->value+0.5); - - wxScrollWinEvent event( command, value, wxHORIZONTAL ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + wxEventType eventType = win->GetScrollEventType(range); + if (eventType != wxEVT_NULL) + { + // Convert scroll event type to scrollwin event type + eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP; + const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL; + wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient); + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event); + } } } @@ -2107,24 +2119,18 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust, //----------------------------------------------------------------------------- extern "C" { -static gint gtk_scrollbar_button_press_callback( GtkRange *widget, - GdkEventButton *gdk_event, - wxWindowGTK *win) +static gboolean +gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win) { DEBUG_MAIN_THREAD if (g_isIdle) wxapp_install_idle_handler(); - g_blockEventsOnScroll = true; + win->m_mouseButtonDown = true; -// FIXME: there is no 'slider' field in GTK+ 2.0 any more -#if 0 - win->m_isScrolling = (gdk_event->window == widget->slider); -#endif - - return FALSE; + return false; } } @@ -2133,45 +2139,24 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *widget, //----------------------------------------------------------------------------- extern "C" { -static gint gtk_scrollbar_button_release_callback( GtkRange *widget, - GdkEventButton *WXUNUSED(gdk_event), - wxWindowGTK *win) +static gboolean +gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win) { DEBUG_MAIN_THREAD -// don't test here as we can release the mouse while being over -// a different window than the slider -// -// if (gdk_event->window != widget->slider) return FALSE; - g_blockEventsOnScroll = false; - + win->m_mouseButtonDown = false; + // If thumb tracking if (win->m_isScrolling) { - wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE; - int value = -1; - int dir = -1; - - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); - if (widget == GTK_RANGE(scrolledWindow->hscrollbar)) - { - value = (int)(win->m_hAdjust->value+0.5); - dir = wxHORIZONTAL; - } - if (widget == GTK_RANGE(scrolledWindow->vscrollbar)) - { - value = (int)(win->m_vAdjust->value+0.5); - dir = wxVERTICAL; - } - - wxScrollWinEvent event( command, value, dir ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + win->m_isScrolling = false; + const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL; + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient); + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event); } - win->m_isScrolling = false; - - return FALSE; + return false; } } @@ -2194,7 +2179,7 @@ wxWindow *wxWindowBase::DoFindFocus() 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 @@ -2212,8 +2197,6 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) wxWindowCreateEvent event( win ); event.SetEventObject( win ); win->GetEventHandler()->ProcessEvent( event ); - - return FALSE; } } @@ -2230,8 +2213,6 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), if (g_isIdle) wxapp_install_idle_handler(); - if (!win->m_hasScrolling) return; - int client_width = 0; int client_height = 0; win->GetClientSize( &client_width, &client_height ); @@ -2276,7 +2257,7 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), { gint width, height; - gdk_window_get_size (widget->window, &width, &height); + gdk_drawable_get_size (widget->window, &width, &height); win->m_icattr->preedit_area.width = width; win->m_icattr->preedit_area.height = height; gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA); @@ -2292,7 +2273,7 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), /* Initialize XIM support */ extern "C" { -static gint +static void gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), wxWindowGTK * WXUNUSED_UNLESS_XIM(win) ) { @@ -2300,12 +2281,12 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), 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; @@ -2347,7 +2328,7 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), break; } - gdk_window_get_size (widget->window, &width, &height); + gdk_drawable_get_size (widget->window, &width, &height); attrmask |= GDK_IC_PREEDIT_POSITION_REQ; attr->spot_location.x = 0; @@ -2375,8 +2356,6 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), gdk_im_begin (win->m_ic, widget->window); } #endif // HAVE_XIM - - return FALSE; } } @@ -2476,11 +2455,14 @@ void wxWindowGTK::Init() m_hasScrolling = false; m_isScrolling = false; + m_mouseButtonDown = false; + m_blockScrollEvent = false; + + m_scrollBar[0] = + m_scrollBar[1] = NULL; + m_scrollPos[0] = + m_scrollPos[1] = 0; - m_hAdjust = (GtkAdjustment*) NULL; - m_vAdjust = (GtkAdjustment*) NULL; - m_oldHorizontalPos = - m_oldVerticalPos = 0.0; m_oldClientWidth = m_oldClientHeight = 0; @@ -2544,8 +2526,8 @@ bool wxWindowGTK::Create( wxWindow *parent, gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); - m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) ); - m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) ); + m_scrollBar[0] = GTK_RANGE(scrolledWindow->hscrollbar); + m_scrollBar[1] = GTK_RANGE(scrolledWindow->vscrollbar); m_wxwindow = gtk_pizza_new(); @@ -2575,42 +2557,24 @@ bool wxWindowGTK::Create( wxWindow *parent, GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS ); m_acceptsFocus = true; - // I _really_ don't want scrollbars in the beginning - m_vAdjust->lower = 0.0; - m_vAdjust->upper = 1.0; - m_vAdjust->value = 0.0; - m_vAdjust->step_increment = 1.0; - m_vAdjust->page_increment = 1.0; - m_vAdjust->page_size = 5.0; - g_signal_emit_by_name (m_vAdjust, "changed"); - m_hAdjust->lower = 0.0; - m_hAdjust->upper = 1.0; - m_hAdjust->value = 0.0; - m_hAdjust->step_increment = 1.0; - m_hAdjust->page_increment = 1.0; - m_hAdjust->page_size = 5.0; - g_signal_emit_by_name (m_hAdjust, "changed"); - // these handlers block mouse events to any window during scrolling such as // motion events and prevent GTK and wxWidgets from fighting over where the // slider should be - g_signal_connect (scrolledWindow->vscrollbar, "button_press_event", - G_CALLBACK (gtk_scrollbar_button_press_callback), this); - g_signal_connect (scrolledWindow->hscrollbar, "button_press_event", - G_CALLBACK (gtk_scrollbar_button_press_callback), this); - g_signal_connect (scrolledWindow->vscrollbar, "button_release_event", - G_CALLBACK (gtk_scrollbar_button_release_callback), this); - g_signal_connect (scrolledWindow->hscrollbar, "button_release_event", - G_CALLBACK (gtk_scrollbar_button_release_callback), this); - - // these handlers get notified when screen updates are required either when - // scrolling or when the window size (and therefore scrollbar configuration) - // has changed - - g_signal_connect (m_hAdjust, "value_changed", - G_CALLBACK (gtk_window_hscroll_callback), this); - g_signal_connect (m_vAdjust, "value_changed", - G_CALLBACK (gtk_window_vscroll_callback), this); + g_signal_connect(m_scrollBar[0], "button_press_event", + G_CALLBACK(gtk_scrollbar_button_press_event), this); + g_signal_connect(m_scrollBar[1], "button_press_event", + G_CALLBACK(gtk_scrollbar_button_press_event), this); + g_signal_connect(m_scrollBar[0], "button_release_event", + G_CALLBACK(gtk_scrollbar_button_release_event), this); + g_signal_connect(m_scrollBar[1], "button_release_event", + G_CALLBACK(gtk_scrollbar_button_release_event), this); + + // these handlers get notified when scrollbar slider moves + + g_signal_connect(m_scrollBar[0], "value_changed", + G_CALLBACK(gtk_scrollbar_value_changed), this); + g_signal_connect(m_scrollBar[1], "value_changed", + G_CALLBACK(gtk_scrollbar_value_changed), this); gtk_widget_show( m_wxwindow ); @@ -2708,7 +2672,7 @@ void wxWindowGTK::PostCreation() 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 @@ -2732,10 +2696,20 @@ void wxWindowGTK::PostCreation() 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 (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_signal_connect_after (m_focusWidget, "focus_out_event", G_CALLBACK (gtk_window_focus_out_callback), this); + } } // connect to the various key and mouse handlers @@ -2806,7 +2780,7 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) g_signal_connect (widget, "motion_notify_event", G_CALLBACK (gtk_window_motion_notify_callback), this); g_signal_connect (widget, "scroll_event", - G_CALLBACK (gtk_window_wheel_callback), this); + G_CALLBACK (window_scroll_event), this); g_signal_connect (widget, "popup_menu", G_CALLBACK (wxgtk_window_popup_menu_callback), this); g_signal_connect (widget, "enter_notify_event", @@ -2849,9 +2823,46 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags 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) ) { - /* don't set the size for children of wxNotebook, just take the values. */ + 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 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; @@ -2871,32 +2882,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags 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; @@ -2954,7 +2939,10 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags 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 @@ -3017,135 +3005,76 @@ void wxWindowGTK::DoSetClientSize( int width, int height ) { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); - if (!m_wxwindow) - { - SetSize( width, height ); - } - else + if (m_wxwindow) { int dw = 0; int dh = 0; + if (m_hasScrolling) + { + GetScrollbarWidth(m_widget, dw, dh); + } + #ifndef __WXUNIVERSAL__ if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) { - /* when using GTK 1.2 we set the shadow border size to 2 */ + // shadow border size is 2 dw += 2 * 2; dh += 2 * 2; } if (HasFlag(wxSIMPLE_BORDER)) { - /* when using GTK 1.2 we set the simple border size to 1 */ + // simple border size is 1 dw += 1 * 2; dh += 1 * 2; } #endif // __WXUNIVERSAL__ - if (m_hasScrolling) - { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - - GtkRequisition vscroll_req; - vscroll_req.width = 2; - vscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) - (scroll_window->vscrollbar, &vscroll_req ); - - GtkRequisition hscroll_req; - hscroll_req.width = 2; - hscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) - (scroll_window->hscrollbar, &hscroll_req ); - - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); - - if (scroll_window->vscrollbar_visible) - { - dw += vscroll_req.width; - dw += scroll_class->scrollbar_spacing; - } - - if (scroll_window->hscrollbar_visible) - { - dh += hscroll_req.height; - dh += scroll_class->scrollbar_spacing; - } - } - - SetSize( width+dw, height+dh ); + width += dw; + height += dh; } + + SetSize(width, height); } void wxWindowGTK::DoGetClientSize( int *width, int *height ) const { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); - if (!m_wxwindow) - { - if (width) (*width) = m_width; - if (height) (*height) = m_height; - } - else + int w = m_width; + int h = m_height; + + if (m_wxwindow) { int dw = 0; int dh = 0; + if (m_hasScrolling) + { + GetScrollbarWidth(m_widget, dw, dh); + } + #ifndef __WXUNIVERSAL__ if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) { - /* when using GTK 1.2 we set the shadow border size to 2 */ + // shadow border size is 2 dw += 2 * 2; dh += 2 * 2; } if (HasFlag(wxSIMPLE_BORDER)) { - /* when using GTK 1.2 we set the simple border size to 1 */ + // simple border size is 1 dw += 1 * 2; dh += 1 * 2; } #endif // __WXUNIVERSAL__ - if (m_hasScrolling) - { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - - GtkRequisition vscroll_req; - vscroll_req.width = 2; - vscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) - (scroll_window->vscrollbar, &vscroll_req ); - - GtkRequisition hscroll_req; - hscroll_req.width = 2; - hscroll_req.height = 2; - (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) - (scroll_window->hscrollbar, &hscroll_req ); - - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); - - if (scroll_window->vscrollbar_visible) - { - dw += vscroll_req.width; - dw += scroll_class->scrollbar_spacing; - } - - if (scroll_window->hscrollbar_visible) - { - dh += hscroll_req.height; - dh += scroll_class->scrollbar_spacing; - } - } - - if (width) (*width) = m_width - dw; - if (height) (*height) = m_height - dh; + w -= dw; + h -= dh; } -/* - printf( "GetClientSize, name %s ", GetName().c_str() ); - if (width) printf( " width = %d", (*width) ); - if (height) printf( " height = %d", (*height) ); - printf( "\n" ); -*/ + if (width) *width = w; + if (height) *height = h; } void wxWindowGTK::DoGetPosition( int *x, int *y ) const @@ -3305,7 +3234,7 @@ int wxWindowGTK::GetCharHeight() const PangoRectangle rect; pango_layout_line_get_extents(line, NULL, &rect); - g_object_unref( G_OBJECT( layout ) ); + g_object_unref (layout); return (int) PANGO_PIXELS(rect.height); } @@ -3333,7 +3262,7 @@ int wxWindowGTK::GetCharWidth() const PangoRectangle rect; pango_layout_line_get_extents(line, NULL, &rect); - g_object_unref( G_OBJECT( layout ) ); + g_object_unref (layout); return (int) PANGO_PIXELS(rect.width); } @@ -3371,14 +3300,9 @@ void wxWindowGTK::GetTextExtent( const wxString& string, PangoLayout *layout = pango_layout_new(context); pango_layout_set_font_description(layout, desc); { -#if wxUSE_UNICODE - const wxCharBuffer data = wxConvUTF8.cWC2MB( string ); - pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); -#else - const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string ); - const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); - pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); -#endif + const wxCharBuffer data = wxGTK_CONV( string ); + if ( data ) + pango_layout_set_text(layout, data, strlen(data)); } PangoRectangle rect; @@ -3395,7 +3319,7 @@ void wxWindowGTK::GetTextExtent( const wxString& string, } if (externalLeading) (*externalLeading) = 0; // ?? - g_object_unref( G_OBJECT( layout ) ); + g_object_unref (layout); } void wxWindowGTK::SetFocus() @@ -3533,18 +3457,64 @@ void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move) 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); @@ -3552,13 +3522,11 @@ void wxWindowGTK::RealizeTabOrder() 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() @@ -3622,6 +3590,33 @@ void wxWindowGTK::WarpPointer( int x, int y ) gdk_window_warp_pointer( window, x, y ); } +bool wxWindowGTK::ScrollLines(int lines) +{ + bool changed = false; + GtkRange* range = m_scrollBar[1]; + if (range != NULL) + { + GtkAdjustment* adj = range->adjustment; + const int pos = int(adj->value + 0.5); + gtk_range_set_value(range, pos + lines); + changed = pos != int(adj->value + 0.5); + } + return changed; +} + +bool wxWindowGTK::ScrollPages(int pages) +{ + bool changed = false; + GtkRange* range = m_scrollBar[1]; + if (range != NULL) + { + GtkAdjustment* adj = range->adjustment; + const int pos = int(adj->value + 0.5); + gtk_range_set_value(range, pos + pages * adj->page_size); + changed = pos != int(adj->value + 0.5); + } + return changed; +} void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) { @@ -3996,7 +3991,7 @@ void wxWindowGTK::DoCaptureMouse() wxCHECK_RET( window, _T("CaptureMouse() failed") ); - wxCursor* cursor = & m_cursor; + const wxCursor* cursor = &m_cursor; if (!cursor->Ok()) cursor = wxSTANDARD_CURSOR; @@ -4044,80 +4039,47 @@ bool wxWindowGTK::IsRetained() const 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 refresh ) + int range, bool ) { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); - m_hasScrolling = true; - - if (orient == wxHORIZONTAL) + if (range > 0) { - float fpos = (float)pos; - float frange = (float)range; - float fthumb = (float)thumbVisible; - if (fpos > frange-fthumb) fpos = frange-fthumb; - if (fpos < 0.0) fpos = 0.0; - - if ((fabs(frange-m_hAdjust->upper) < 0.2) && - (fabs(fthumb-m_hAdjust->page_size) < 0.2)) - { - SetScrollPos( orient, pos, refresh ); - return; - } - - m_oldHorizontalPos = fpos; - - m_hAdjust->lower = 0.0; - m_hAdjust->upper = frange; - m_hAdjust->value = fpos; - m_hAdjust->step_increment = 1.0; - m_hAdjust->page_increment = (float)(wxMax(fthumb,0)); - m_hAdjust->page_size = fthumb; + m_hasScrolling = true; } else { - float fpos = (float)pos; - float frange = (float)range; - float fthumb = (float)thumbVisible; - if (fpos > frange-fthumb) fpos = frange-fthumb; - if (fpos < 0.0) fpos = 0.0; - - if ((fabs(frange-m_vAdjust->upper) < 0.2) && - (fabs(fthumb-m_vAdjust->page_size) < 0.2)) - { - SetScrollPos( orient, pos, refresh ); - return; - } - - m_oldVerticalPos = fpos; - - m_vAdjust->lower = 0.0; - m_vAdjust->upper = frange; - m_vAdjust->value = fpos; - m_vAdjust->step_increment = 1.0; - m_vAdjust->page_increment = (float)(wxMax(fthumb,0)); - m_vAdjust->page_size = fthumb; + // GtkRange requires upper > lower + range = + thumbVisible = 1; } - if (orient == wxHORIZONTAL) - g_signal_emit_by_name (m_hAdjust, "changed"); - else - g_signal_emit_by_name (m_vAdjust, "changed"); -} + const int i = orient == wxVERTICAL; + GtkAdjustment* adj = m_scrollBar[i]->adjustment; + adj->value = pos; + adj->step_increment = 1; + adj->page_increment = + adj->page_size = thumbVisible; -void wxWindowGTK::GtkUpdateScrollbar(int orient) -{ - GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust; - gpointer fn = orient == wxHORIZONTAL - ? (gpointer) gtk_window_hscroll_callback - : (gpointer) gtk_window_vscroll_callback; - - g_signal_handlers_disconnect_by_func (adj, fn, this); - g_signal_emit_by_name (adj, "value_changed"); - g_signal_connect (adj, "value_changed", G_CALLBACK (fn), this); + BlockScrollEvent(); + // automatically clamps value to [0,range-page_size], and emits change events + gtk_range_set_range(m_scrollBar[i], 0, range); + UnblockScrollEvent(); + m_scrollPos[i] = adj->value; } void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) @@ -4125,58 +4087,98 @@ void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); - GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust; - - float fpos = (float)pos; - if (fpos > adj->upper - adj->page_size) - fpos = adj->upper - adj->page_size; - if (fpos < 0.0) - fpos = 0.0; - *(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos; - - if (fabs(fpos-adj->value) < 0.2) - return; - adj->value = fpos; - - if ( m_wxwindow->window ) + // This check is more than an optimization. Without it, the slider + // will not move smoothly while tracking when using wxScrollHelper. + if (GetScrollPos(orient) != pos) { + const int i = orient == wxVERTICAL; + BlockScrollEvent(); + gtk_range_set_value(m_scrollBar[i], pos); + UnblockScrollEvent(); + m_scrollPos[i] = m_scrollBar[i]->adjustment->value; } } int wxWindowGTK::GetScrollThumb( int orient ) const { wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); - wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - if (orient == wxHORIZONTAL) - return (int)(m_hAdjust->page_size+0.5); - else - return (int)(m_vAdjust->page_size+0.5); + const int i = orient == wxVERTICAL; + return int(m_scrollBar[i]->adjustment->page_size); } int wxWindowGTK::GetScrollPos( int orient ) const { wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); - wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - if (orient == wxHORIZONTAL) - return (int)(m_hAdjust->value+0.5); - else - return (int)(m_vAdjust->value+0.5); + const int i = orient == wxVERTICAL; + return int(m_scrollBar[i]->adjustment->value + 0.5); } int wxWindowGTK::GetScrollRange( int orient ) const { wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); - wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - if (orient == wxHORIZONTAL) - return (int)(m_hAdjust->upper+0.5); - else - return (int)(m_vAdjust->upper+0.5); + const int i = orient == wxVERTICAL; + return int(m_scrollBar[i]->adjustment->upper); +} + +// Determine if increment is the same as +/-x, allowing for some small +// difference due to possible inexactness in floating point arithmetic +static inline bool IsScrollIncrement(double increment, double x) +{ + wxASSERT(increment > 0); + const double tolerance = 1.0 / 1024; + return fabs(increment - fabs(x)) < tolerance; +} + +wxEventType wxWindow::GetScrollEventType(GtkRange* range) +{ + DEBUG_MAIN_THREAD + + if (g_isIdle) + wxapp_install_idle_handler(); + + wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]); + + const int barIndex = range == m_scrollBar[1]; + GtkAdjustment* adj = range->adjustment; + const int value = int(adj->value + 0.5); + // save previous position + const double oldPos = m_scrollPos[barIndex]; + // update current position + m_scrollPos[barIndex] = adj->value; + // If event should be ignored, or integral position has not changed + if (!m_hasVMT || g_blockEventsOnDrag || m_blockScrollEvent || value == int(oldPos + 0.5)) + { + return wxEVT_NULL; + } + + wxEventType eventType = wxEVT_SCROLL_THUMBTRACK; + if (!m_isScrolling) + { + // Difference from last change event + const double diff = adj->value - oldPos; + const bool isDown = diff > 0; + + if (IsScrollIncrement(adj->step_increment, diff)) + { + eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP; + } + else if (IsScrollIncrement(adj->page_increment, diff)) + { + eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP; + } + else if (m_mouseButtonDown) + { + // Assume track event + m_isScrolling = true; + } + } + return eventType; } void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) @@ -4195,6 +4197,29 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) m_clipPaintRegion = false; } +void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget* w, int wxstyle) +{ + //RN: Note that static controls usually have no border on gtk, so maybe + //it makes sense to treat that as simply no border at the wx level + //as well... + if (!(wxstyle & wxNO_BORDER) && !(wxstyle & wxBORDER_STATIC)) + { + GtkShadowType gtkstyle; + + if(wxstyle & wxBORDER_RAISED) + gtkstyle = GTK_SHADOW_OUT; + else if (wxstyle & wxBORDER_SUNKEN) + gtkstyle = GTK_SHADOW_IN; + else if (wxstyle & wxBORDER_DOUBLE) + gtkstyle = GTK_SHADOW_ETCHED_IN; + else //default + gtkstyle = GTK_SHADOW_IN; + + gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w), + gtkstyle ); + } +} + void wxWindowGTK::SetWindowStyleFlag( long style ) { // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already @@ -4269,7 +4294,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule) bool wxWinModule::OnInit() { - // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() ); + // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() ); // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); return true; @@ -4278,6 +4303,5 @@ bool wxWinModule::OnInit() void wxWinModule::OnExit() { if (g_eraseGC) - gdk_gc_unref( g_eraseGC ); + g_object_unref (g_eraseGC); } -