X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/224016a800a9939332cb87401304c476fefe6664..582f07c2532e6e2d7d1ccb235354548e9bada9bf:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 1e9038e20a..e9ba04cdfe 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,27 @@ #endif #include "wx/window.h" -#include "wx/dcclient.h" -#include "wx/frame.h" -#include "wx/app.h" -#include "wx/layout.h" -#include "wx/utils.h" -#include "wx/dialog.h" -#include "wx/msgdlg.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" + #include "wx/dialog.h" + #include "wx/settings.h" + #include "wx/msgdlg.h" + #include "wx/textctrl.h" + #include "wx/toolbar.h" + #include "wx/combobox.h" + #include "wx/layout.h" + #include "wx/statusbr.h" + #include "wx/math.h" +#endif + #include "wx/module.h" -#include "wx/combobox.h" #if wxUSE_DRAG_AND_DROP #include "wx/dnd.h" @@ -37,24 +49,20 @@ #include "wx/caret.h" #endif // wxUSE_CARET -#if wxUSE_TEXTCTRL - #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__ #include "wx/thread.h" #endif -#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 @@ -65,20 +73,13 @@ #include "wx/gtk/win_gtk.h" -#ifdef __WXGTK20__ #include -#endif - -#ifdef __WXGTK20__ - #ifdef HAVE_XIM - #undef HAVE_XIM - #endif +#ifdef HAVE_XIM + #undef HAVE_XIM #endif -#ifdef __WXGTK20__ extern GtkContainerClass *pizza_parent_class; -#endif //----------------------------------------------------------------------------- // documentation on internals @@ -214,7 +215,6 @@ extern GtkContainerClass *pizza_parent_class; // data //----------------------------------------------------------------------------- -extern wxList wxPendingDelete; extern bool g_blockEventsOnDrag; extern bool g_blockEventsOnScroll; extern wxCursor g_globalCursor; @@ -237,12 +237,6 @@ wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL; // yet, defer setting the focus to idle time. wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL; -// hack: we need something to pass to gtk_menu_popup, so we store the time of -// the last click here (extern: used from gtk/menu.cpp) -#ifndef __WXGTK20__ -guint32 wxGtkTimeLastClick = 0; -#endif - extern bool g_mainThreadLocked; //----------------------------------------------------------------------------- @@ -272,14 +266,9 @@ gdk_window_warp_pointer (GdkWindow *window, gint x, gint y) { -#ifndef __WXGTK20__ - GdkWindowPrivate *priv; -#endif - if (!window) - window = GDK_ROOT_PARENT(); + window = gdk_get_default_root_window(); -#ifdef __WXGTK20__ if (!GDK_WINDOW_DESTROYED(window)) { XWarpPointer (GDK_WINDOW_XDISPLAY(window), @@ -288,27 +277,8 @@ gdk_window_warp_pointer (GdkWindow *window, 0, 0, 0, 0, /* not source window -> move from anywhere */ x, y ); } -#else - priv = (GdkWindowPrivate*) window; - - if (!priv->destroyed) - { - XWarpPointer (priv->xdisplay, - None, /* not source window -> move from anywhere */ - priv->xwindow, /* dest window */ - 0, 0, 0, 0, /* not source window -> move from anywhere */ - x, y ); - } -#endif } -//----------------------------------------------------------------------------- -// idle system -//----------------------------------------------------------------------------- - -extern void wxapp_install_idle_handler(); -extern bool g_isIdle; - //----------------------------------------------------------------------------- // local code (see below) //----------------------------------------------------------------------------- @@ -337,6 +307,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 @@ -349,33 +348,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,23 +361,25 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) if (win->HasFlag(wxRAISED_BORDER)) { - gtk_draw_shadow( widget->style, - widget->window, - GTK_STATE_NORMAL, - GTK_SHADOW_OUT, - dx, dy, - widget->allocation.width-dw, widget->allocation.height-dh ); + gtk_paint_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + NULL, NULL, NULL, // FIXME: No clipping? + dx, dy, + widget->allocation.width-dw, widget->allocation.height-dh ); return; } if (win->HasFlag(wxSUNKEN_BORDER)) { - gtk_draw_shadow( widget->style, - widget->window, - GTK_STATE_NORMAL, - GTK_SHADOW_IN, - dx, dy, - widget->allocation.width-dw, widget->allocation.height-dh ); + gtk_paint_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_IN, + NULL, NULL, NULL, // FIXME: No clipping? + dx, dy, + widget->allocation.width-dw, widget->allocation.height-dh ); return; } @@ -416,7 +391,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__ @@ -427,36 +402,21 @@ 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; draw_frame( widget, win ); -#ifdef __WXGTK20__ - (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); -#endif return TRUE; } } -//----------------------------------------------------------------------------- -// "draw" of m_widget -//----------------------------------------------------------------------------- - -#ifndef __WXGTK20__ - -extern "C" { -static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win ) -{ - draw_frame( widget, win ); -} -} - -#endif // GTK+ < 2.0 - //----------------------------------------------------------------------------- // "size_request" of m_widget //----------------------------------------------------------------------------- @@ -513,16 +473,16 @@ 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 if (g_isIdle) wxapp_install_idle_handler(); -#ifdef __WXGTK20__ // This callback gets called in drawing-idle time under // GTK 2.0, so we don't need to defer anything to idle // time anymore. @@ -562,150 +522,26 @@ static int gtk_window_expose_callback( GtkWidget *widget, // Let parent window draw window-less widgets (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); -#else - // This gets called immediately after an expose event - // under GTK 1.2 so we collect the calls and wait for - // the idle handler to pick things up. - - win->GetUpdateRegion().Union( gdk_event->area.x, - gdk_event->area.y, - gdk_event->area.width, - gdk_event->area.height ); - win->m_clearRegion.Union( gdk_event->area.x, - gdk_event->area.y, - gdk_event->area.width, - gdk_event->area.height ); - - // Actual redrawing takes place in idle time. - // win->GtkUpdate(); -#endif return FALSE; } } //----------------------------------------------------------------------------- -// "event" of m_wxwindow +// "key_press_event" from any window //----------------------------------------------------------------------------- -#ifndef __WXGTK20__ - -// GTK thinks it is clever and filters out a certain amount of "unneeded" -// expose events. We need them, of course, so we override the main event -// procedure in GtkWidget by giving our own handler for all system events. -// There, we look for expose events ourselves whereas all other events are -// handled normally. - -extern "C" { -static -gint gtk_window_event_event_callback( GtkWidget *widget, - GdkEventExpose *event, - wxWindow *win ) +// These are used when transforming Ctrl-alpha to ascii values 1-26 +inline bool wxIsLowerChar(int code) { - if (event->type == GDK_EXPOSE) - { - gint ret = gtk_window_expose_callback( widget, event, win ); - return ret; - } - - return FALSE; + return (code >= 'a' && code <= 'z' ); } -} - -#endif // !GTK+ 2 - -//----------------------------------------------------------------------------- -// "draw" of m_wxwindow -//----------------------------------------------------------------------------- - -#ifndef __WXGTK20__ -// This callback is a complete replacement of the gtk_pizza_draw() function, -// which is disabled. - -extern "C" { -static void gtk_window_draw_callback( GtkWidget *widget, - GdkRectangle *rect, - wxWindow *win ) +inline bool wxIsUpperChar(int code) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - // if there are any children we must refresh everything - // - // VZ: why? - if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) && - win->GetChildren().IsEmpty() ) - { - return; - } - -#if 0 - if (win->GetName()) - { - wxPrintf( wxT("OnDraw from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x, - (int)rect->y, - (int)rect->width, - (int)rect->height ); - } -#endif - -#ifndef __WXUNIVERSAL__ - GtkPizza *pizza = GTK_PIZZA (widget); - - if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM) - { - wxWindow *parent = win->GetParent(); - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - if (!parent) - parent = win; - - gtk_paint_flat_box (parent->m_widget->style, - pizza->bin_window, - GTK_STATE_NORMAL, - GTK_SHADOW_NONE, - rect, - parent->m_widget, - (char *)"base", - 0, 0, -1, -1); - } -#endif - - win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height ); - win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); - - // Update immediately, not in idle time. - win->GtkUpdate(); - -#ifndef __WXUNIVERSAL__ - // Redraw child widgets - GList *children = pizza->children; - while (children) - { - GtkPizzaChild *child = (GtkPizzaChild*) children->data; - children = children->next; - - GdkRectangle child_area; - if (gtk_widget_intersect (child->widget, rect, &child_area)) - { - gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ ); - } - } -#endif -} + return (code >= 'A' && code <= 'Z' ); } -#endif - -//----------------------------------------------------------------------------- -// "key_press_event" from any window -//----------------------------------------------------------------------------- // set WXTRACE to this to see the key event codes on the console #define TRACE_KEYS _T("keyevent") @@ -828,11 +664,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: @@ -911,11 +747,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: @@ -1120,12 +956,17 @@ 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; } -#ifdef __WXGTK20__ struct wxGtkIMData { GtkIMContext *context; @@ -1138,15 +979,15 @@ struct wxGtkIMData } ~wxGtkIMData() { - g_object_unref(context); + g_object_unref (context); } }; -#endif 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 @@ -1175,7 +1016,6 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, return_after_IM = true; } -#ifdef __WXGTK20__ // 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 @@ -1197,73 +1037,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; - } - } -#endif - if (return_after_IM) - return false; - -#ifndef __WXGTK20__ - // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done - // in the "commit" handler. - - // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw). - // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose - // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are - // composed of more than one character, which means gdk_event->length will always - // greater than one. When gtk_event->length == 1, this may be an ASCII character - // and can be translated by wx. However, when MBCS characters are sent by IM, - // gdk_event->length will >= 2. So neither should we pass it to accelerator table, - // nor should we pass it to controls. The following explanation was excerpted - // from GDK documentation. - // gint length : the length of string. - // gchar *string : a null-terminated multi-byte string containing the composed - // characters resulting from the key press. When text is being input, in a GtkEntry - // for example, it is these characters which should be added to the input buffer. - // When using Input Methods to support internationalized text input, the composed - // characters appear here after the pre-editing has been completed. - - if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM. - { - // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN. - #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based. - const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string ); - if( !string ) - return false; - #else - const char* string = gdk_event->string; - #endif - - // Implement OnCharHook by checking ancestor top level windows - wxWindow *parent = win; - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - - for( const wxChar* pstr = string; *pstr; pstr++ ) - { - #if wxUSE_UNICODE - event.m_uniChar = *pstr; - // Backward compatible for ISO-8859-1 - event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0; - #else - event.m_keyCode = *pstr; - #endif - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->GetEventHandler()->ProcessEvent( event ); - } - if (!ret) - { - event.SetEventType(wxEVT_CHAR); - win->GetEventHandler()->ProcessEvent( event ); - } + return TRUE; } - return true; } -#endif // #ifndef __WXGTK20__ + if (return_after_IM) + return FALSE; #if wxUSE_ACCEL if (!ret) @@ -1313,6 +1092,20 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, 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() && + ( wxIsLowerChar(key_code) || wxIsUpperChar(key_code) )) + { + if ( wxIsLowerChar(key_code) ) + event.m_keyCode = key_code - 'a' + 1; + if ( wxIsUpperChar(key_code) ) + 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()) @@ -1398,7 +1191,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, if (ret) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" ); + g_signal_stop_emission_by_name (widget, "key_press_event"); return TRUE; } @@ -1406,11 +1199,11 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } } -#ifdef __WXGTK20__ 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 ); @@ -1422,13 +1215,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; @@ -1448,6 +1236,23 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, #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() && + ( wxIsLowerChar(*pstr) || wxIsUpperChar(*pstr) )) + { + if ( wxIsLowerChar(*pstr) ) + event.m_keyCode = *pstr - 'a' + 1; + if ( wxIsUpperChar(*pstr) ) + event.m_keyCode = *pstr - 'A' + 1; + + event.m_keyCode = *pstr - 'a' + 1; +#if wxUSE_UNICODE + event.m_uniChar = event.m_keyCode; +#endif + } + if (parent) { event.SetEventType( wxEVT_CHAR_HOOK ); @@ -1462,7 +1267,6 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, } } } -#endif //----------------------------------------------------------------------------- @@ -1470,9 +1274,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 @@ -1495,7 +1300,7 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, if ( !win->GetEventHandler()->ProcessEvent( event ) ) return FALSE; - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" ); + g_signal_stop_emission_by_name (widget, "key_release_event"); return TRUE; } } @@ -1643,9 +1448,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 @@ -1801,25 +1607,13 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, if ( !g_captureWindow ) win = FindWindowForMouseEvent(win, event.m_x, event.m_y); -#ifndef __WXGTK20__ - wxGtkTimeLastClick = gdk_event->time; - - if (event_type == wxEVT_LEFT_DCLICK) - { - // GTK 1.2 crashes when intercepting double - // click events from both wxSpinButton and - // wxSpinCtrl - if (GTK_IS_SPIN_BUTTON(win->m_widget)) - { - // Just disable this event for now. - return FALSE; - } - } -#endif // !__WXGTK20__ + // reset the event object and id in case win changed. + event.SetEventObject( win ); + event.SetId( win->GetId() ); if (win->GetEventHandler()->ProcessEvent( event )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" ); + g_signal_stop_emission_by_name (widget, "button_press_event"); return TRUE; } @@ -1849,9 +1643,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 @@ -1896,9 +1691,13 @@ 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 )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" ); + g_signal_stop_emission_by_name (widget, "button_release_event"); return TRUE; } @@ -1911,9 +1710,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 @@ -1970,11 +1770,24 @@ 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 )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" ); + g_signal_stop_emission_by_name (widget, "motion_notify_event"); return TRUE; } @@ -1982,30 +1795,26 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, } } -#ifdef __WXGTK20__ //----------------------------------------------------------------------------- -// "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); @@ -2030,13 +1839,7 @@ static gint gtk_window_wheel_callback (GtkWidget * widget, event.SetId( win->GetId() ); event.SetTimestamp( gdk_event->time ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" ); - return TRUE; - } - - return FALSE; + return win->GetEventHandler()->ProcessEvent(event); } } @@ -2054,7 +1857,6 @@ static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win) return win->GetEventHandler()->ProcessEvent(event); } } -#endif // __WXGTK20__ //----------------------------------------------------------------------------- // "focus_in_event" @@ -2076,19 +1878,18 @@ 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 if (g_isIdle) wxapp_install_idle_handler(); -#ifdef __WXGTK20__ if (win->m_imData) gtk_im_context_focus_in(win->m_imData->context); -#endif g_focusWindowLast = g_focusWindow = win; @@ -2110,19 +1911,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) ) - { - gtk_signal_emit_stop_by_name( GTK_OBJECT(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; } } @@ -2132,17 +1938,18 @@ 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 if (g_isIdle) wxapp_install_idle_handler(); -#ifdef __WXGTK20__ if (win->m_imData) gtk_im_context_focus_out(win->m_imData->context); -#endif wxLogTrace( TRACE_FOCUS, _T("%s: focus out"), win->GetName().c_str() ); @@ -2168,6 +1975,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 ) @@ -2177,13 +1986,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; } } @@ -2193,10 +2005,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 @@ -2223,9 +2035,18 @@ 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 )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" ); + g_signal_stop_emission_by_name (widget, "enter_notify_event"); return TRUE; } @@ -2238,7 +2059,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 @@ -2277,7 +2101,7 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ if (win->GetEventHandler()->ProcessEvent( event )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" ); + g_signal_stop_emission_by_name (widget, "leave_notify_event"); return TRUE; } @@ -2286,99 +2110,66 @@ 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, - SCROLLBAR_CBACK_ARG - 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; - -#ifndef __WXGTK20__ - GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); -#endif - wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar)); - - int value = (int)(adjust->value+0.5); - - wxScrollWinEvent event( command, value, wxVERTICAL ); - 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; + const int i = orient == wxVERTICAL; + wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient); + event.SetEventObject(win); + win->m_blockValueChanged[i] = true; + win->GetEventHandler()->ProcessEvent(event); + win->m_blockValueChanged[i] = false; + } } } //----------------------------------------------------------------------------- -// "value_changed" from m_hAdjust +// "button_press_event" from scrollbar //----------------------------------------------------------------------------- extern "C" { -static void gtk_window_hscroll_callback( GtkAdjustment *adjust, - SCROLLBAR_CBACK_ARG - wxWindowGTK *win ) +static gboolean +gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, 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_oldHorizontalPos; - if (fabs(diff) < 0.2) return; - -#ifndef __WXGTK20__ - GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); -#endif - wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar)); - - win->m_oldHorizontalPos = adjust->value; - - int value = (int)(adjust->value+0.5); + g_blockEventsOnScroll = true; + win->m_mouseButtonDown = true; - wxScrollWinEvent event( command, value, wxHORIZONTAL ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + return false; } } //----------------------------------------------------------------------------- -// "button_press_event" from scrollbar +// "event_after" from scrollbar //----------------------------------------------------------------------------- extern "C" { -static gint gtk_scrollbar_button_press_callback( GtkRange *widget, - GdkEventButton *gdk_event, - wxWindowGTK *win) +static void +gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - - g_blockEventsOnScroll = true; - - // FIXME: there is no 'slider' field in GTK+ 2.0 any more -#ifndef __WXGTK20__ - win->m_isScrolling = (gdk_event->window == widget->slider); -#endif + if (event->type == GDK_BUTTON_RELEASE) + { + g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win); - return 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); + } } } @@ -2387,45 +2178,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; + // Hook up handler to send thumb release event after this emission is finished. + // To allow setting scroll position from event handler, sending event must + // be deferred until after the GtkRange handler for this signal has run + g_signal_handlers_unblock_by_func(range, (void*)gtk_scrollbar_event_after, win); } - win->m_isScrolling = false; - - return FALSE; + return false; } } @@ -2448,7 +2218,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 @@ -2456,20 +2226,16 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) if (g_isIdle) wxapp_install_idle_handler(); -#ifdef __WXGTK20__ if (win->m_imData) { GtkPizza *pizza = GTK_PIZZA( m_widget ); gtk_im_context_set_client_window( win->m_imData->context, pizza->bin_window ); } -#endif wxWindowCreateEvent event( win ); event.SetEventObject( win ); win->GetEventHandler()->ProcessEvent( event ); - - return FALSE; } } @@ -2486,8 +2252,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 ); @@ -2532,7 +2296,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); @@ -2548,7 +2312,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) ) { @@ -2556,12 +2320,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; @@ -2603,7 +2367,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; @@ -2631,8 +2395,6 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), gdk_im_begin (win->m_ic, widget->window); } #endif // HAVE_XIM - - return FALSE; } } @@ -2672,6 +2434,31 @@ wxWindow *wxGetActiveWindow() return wxWindow::FindFocus(); } + +wxMouseState wxGetMouseState() +{ + wxMouseState ms; + + gint x; + gint y; + GdkModifierType mask; + + gdk_window_get_pointer(NULL, &x, &y, &mask); + + ms.SetX(x); + ms.SetY(y); + ms.SetLeftDown(mask & GDK_BUTTON1_MASK); + ms.SetMiddleDown(mask & GDK_BUTTON2_MASK); + ms.SetRightDown(mask & GDK_BUTTON3_MASK); + + ms.SetControlDown(mask & GDK_CONTROL_MASK); + ms.SetShiftDown(mask & GDK_SHIFT_MASK); + ms.SetAltDown(mask & GDK_MOD1_MASK); + ms.SetMetaDown(mask & GDK_MOD2_MASK); + + return ms; +} + //----------------------------------------------------------------------------- // wxWindowGTK //----------------------------------------------------------------------------- @@ -2707,11 +2494,16 @@ 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_blockValueChanged[0] = + m_blockValueChanged[1] = false; - m_hAdjust = (GtkAdjustment*) NULL; - m_vAdjust = (GtkAdjustment*) NULL; - m_oldHorizontalPos = - m_oldVerticalPos = 0.0; m_oldClientWidth = m_oldClientHeight = 0; @@ -2728,15 +2520,8 @@ void wxWindowGTK::Init() m_cursor = *wxSTANDARD_CURSOR; -#ifdef __WXGTK20__ m_imData = NULL; m_dirtyTabOrder = false; -#else -#ifdef HAVE_XIM - m_ic = (GdkIC*) NULL; - m_icattr = (GdkICAttr*) NULL; -#endif -#endif } wxWindowGTK::wxWindowGTK() @@ -2782,8 +2567,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(); @@ -2813,46 +2598,31 @@ 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; - gtk_signal_emit_by_name( GTK_OBJECT(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; - gtk_signal_emit_by_name( GTK_OBJECT(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 - - gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event", - (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); - - gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event", - (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); - - gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event", - (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); - - gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event", - (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); - - // these handlers get notified when screen updates are required either when - // scrolling or when the window size (and therefore scrollbar configuration) - // has changed - - gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", - (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this ); - gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", - (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) 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); + gulong handler_id; + handler_id = g_signal_connect( + m_scrollBar[0], "event_after", G_CALLBACK(gtk_scrollbar_event_after), this); + g_signal_handler_block(m_scrollBar[0], handler_id); + handler_id = g_signal_connect( + m_scrollBar[1], "event_after", G_CALLBACK(gtk_scrollbar_event_after), this); + g_signal_handler_block(m_scrollBar[1], handler_id); + + // 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 ); @@ -2886,10 +2656,12 @@ wxWindowGTK::~wxWindowGTK() // propagated to this (soon to be) dead object if (m_focusWidget != NULL) { - gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget), - (GtkSignalFunc) gtk_window_focus_in_callback, (gpointer) this ); - gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget), - (GtkSignalFunc) gtk_window_focus_out_callback, (gpointer) this ); + g_signal_handlers_disconnect_by_func (m_focusWidget, + (gpointer) gtk_window_focus_in_callback, + this); + g_signal_handlers_disconnect_by_func (m_focusWidget, + (gpointer) gtk_window_focus_out_callback, + this); } if (m_widget) @@ -2902,10 +2674,8 @@ wxWindowGTK::~wxWindowGTK() gdk_ic_attr_destroy (m_icattr); #endif -#ifdef __WXGTK20__ // delete before the widgets to avoid a crash on solaris delete m_imData; -#endif if (m_wxwindow) { @@ -2947,42 +2717,24 @@ void wxWindowGTK::PostCreation() gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE ); - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event", - GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this ); - -#ifndef __WXGTK20__ - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw", - GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this ); + g_signal_connect (m_wxwindow, "expose_event", + G_CALLBACK (gtk_window_expose_callback), this); - if (!HasFlag(wxFULL_REPAINT_ON_RESIZE)) - { - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event", - GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this ); - } -#else - // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) ); -#endif + gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) ); } -#ifdef __WXGTK20__ // Create input method handler m_imData = new wxGtkIMData; // Cannot handle drawing preedited text yet gtk_im_context_set_use_preedit( m_imData->context, FALSE ); - g_signal_connect (G_OBJECT (m_imData->context), "commit", + g_signal_connect (m_imData->context, "commit", G_CALLBACK (gtk_wxwindow_commit_cb), this); -#endif // these are called when the "sunken" or "raised" borders are drawn - gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event", - GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this ); - -#ifndef __WXGTK20__ - gtk_signal_connect( GTK_OBJECT(m_widget), "draw", - GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this ); -#endif + g_signal_connect (m_widget, "expose_event", + G_CALLBACK (gtk_window_own_expose_callback), this); } // focus handling @@ -2992,11 +2744,20 @@ void wxWindowGTK::PostCreation() if (m_focusWidget == NULL) m_focusWidget = m_widget; - gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event", - GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); - - gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event", - GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this ); + 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_CALLBACK (gtk_window_focus_out_callback), this); + } } // connect to the various key and mouse handlers @@ -3007,41 +2768,50 @@ void wxWindowGTK::PostCreation() /* We cannot set colours, fonts and cursors before the widget has been realized, so we do this directly after realization */ - gtk_signal_connect( GTK_OBJECT(connect_widget), "realize", - GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this ); + g_signal_connect (connect_widget, "realize", + G_CALLBACK (gtk_window_realized_callback), this); if (m_wxwindow) { // Catch native resize events - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate", - GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this ); + g_signal_connect (m_wxwindow, "size_allocate", + G_CALLBACK (gtk_window_size_callback), this); // Initialize XIM support - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize", - GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this ); + g_signal_connect (m_wxwindow, "realize", + G_CALLBACK (gtk_wxwindow_realized_callback), this); // And resize XIM window - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate", - GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this ); + g_signal_connect (m_wxwindow, "size_allocate", + G_CALLBACK (gtk_wxwindow_size_callback), this); } if (GTK_IS_COMBO(m_widget)) { GtkCombo *gcombo = GTK_COMBO(m_widget); - gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request", - GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback), - (gpointer) this ); + g_signal_connect (gcombo->entry, "size_request", + G_CALLBACK (wxgtk_combo_size_request_callback), + this); + } +#ifdef GTK_IS_FILE_CHOOSER_BUTTON + else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget)) + { + // If we connect to the "size_request" signal of a GtkFileChooserButton + // then that control won't be sized properly when placed inside sizers + // (this can be tested removing this elseif and running XRC or WIDGETS samples) + // FIXME: what should be done here ? } +#endif else { // This is needed if we want to add our windows into native // GTK controls, such as the toolbar. With this callback, the // toolbar gets to know the correct size (the one set by the // programmer). Sadly, it misbehaves for wxComboBox. - gtk_signal_connect( GTK_OBJECT(m_widget), "size_request", - GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback), - (gpointer) this ); + g_signal_connect (m_widget, "size_request", + G_CALLBACK (wxgtk_window_size_request_callback), + this); } InheritAttributes(); @@ -3056,33 +2826,24 @@ void wxWindowGTK::PostCreation() void wxWindowGTK::ConnectWidget( GtkWidget *widget ) { - gtk_signal_connect( GTK_OBJECT(widget), "key_press_event", - GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this ); - - gtk_signal_connect( GTK_OBJECT(widget), "key_release_event", - GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this ); - - gtk_signal_connect( GTK_OBJECT(widget), "button_press_event", - GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this ); - - gtk_signal_connect( GTK_OBJECT(widget), "button_release_event", - GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this ); - - gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event", - GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this ); - -#ifdef __WXGTK20__ - gtk_signal_connect( GTK_OBJECT(widget), "scroll_event", - GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this ); - g_signal_connect(widget, "popup_menu", - G_CALLBACK(wxgtk_window_popup_menu_callback), this); -#endif - - gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event", - GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this ); - - gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event", - GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this ); + g_signal_connect (widget, "key_press_event", + G_CALLBACK (gtk_window_key_press_callback), this); + g_signal_connect (widget, "key_release_event", + G_CALLBACK (gtk_window_key_release_callback), this); + g_signal_connect (widget, "button_press_event", + G_CALLBACK (gtk_window_button_press_callback), this); + g_signal_connect (widget, "button_release_event", + G_CALLBACK (gtk_window_button_release_callback), this); + g_signal_connect (widget, "motion_notify_event", + G_CALLBACK (gtk_window_motion_notify_callback), this); + g_signal_connect (widget, "scroll_event", + 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", + G_CALLBACK (gtk_window_enter_callback), this); + g_signal_connect (widget, "leave_notify_event", + G_CALLBACK (gtk_window_leave_callback), this); } bool wxWindowGTK::Destroy() @@ -3119,9 +2880,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; @@ -3141,32 +2939,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; @@ -3175,7 +2947,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags /* the default button has a border around it */ if (GTK_WIDGET_CAN_DEFAULT(m_widget)) { -#ifdef __WXGTK20__ GtkBorder *default_border = NULL; gtk_widget_style_get( m_widget, "default_border", &default_border, NULL ); if (default_border) @@ -3186,12 +2957,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags bottom_border += default_border->bottom; g_free( default_border ); } -#else - left_border = 6; - right_border = 6; - top_border = 6; - bottom_border = 5; -#endif } DoMoveWindow( m_x-top_border, @@ -3230,10 +2995,12 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags void wxWindowGTK::OnInternalIdle() { -#ifdef __WXGTK20__ if ( m_dirtyTabOrder ) + { + m_dirtyTabOrder = false; RealizeTabOrder(); -#endif + } + // Update style if the window was not yet realized // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called if (m_needsStyleChange) @@ -3295,135 +3062,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 @@ -3567,7 +3275,6 @@ int wxWindowGTK::GetCharHeight() const wxFont font = GetFont(); wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") ); -#ifdef __WXGTK20__ PangoContext *context = NULL; if (m_widget) context = gtk_widget_get_pango_context( m_widget ); @@ -3584,14 +3291,9 @@ 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); -#else - GdkFont *gfont = font.GetInternalFont( 1.0 ); - - return gfont->ascent + gfont->descent; -#endif } int wxWindowGTK::GetCharWidth() const @@ -3601,7 +3303,6 @@ int wxWindowGTK::GetCharWidth() const wxFont font = GetFont(); wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") ); -#ifdef __WXGTK20__ PangoContext *context = NULL; if (m_widget) context = gtk_widget_get_pango_context( m_widget ); @@ -3618,14 +3319,9 @@ 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); -#else - GdkFont *gfont = font.GetInternalFont( 1.0 ); - - return gdk_string_width( gfont, "g" ); -#endif } void wxWindowGTK::GetTextExtent( const wxString& string, @@ -3646,7 +3342,6 @@ void wxWindowGTK::GetTextExtent( const wxString& string, return; } -#ifdef __WXGTK20__ PangoContext *context = NULL; if (m_widget) context = gtk_widget_get_pango_context( m_widget ); @@ -3662,14 +3357,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; @@ -3686,14 +3376,7 @@ void wxWindowGTK::GetTextExtent( const wxString& string, } if (externalLeading) (*externalLeading) = 0; // ?? - g_object_unref( G_OBJECT( layout ) ); -#else - GdkFont *font = fontToUse.GetInternalFont( 1.0 ); - if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) ); - if (y) (*y) = font->ascent + font->descent; - if (descent) (*descent) = font->descent; - if (externalLeading) (*externalLeading) = 0; // ?? -#endif + g_object_unref (layout); } void wxWindowGTK::SetFocus() @@ -3714,13 +3397,11 @@ void wxWindowGTK::SetFocus() } else if (m_widget) { -#ifdef __WXGTK20__ if (GTK_IS_CONTAINER(m_widget)) { gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD ); } else -#endif if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) ) { @@ -3745,13 +3426,6 @@ void wxWindowGTK::SetFocus() } } else -#ifndef __WXGTK20__ - if (GTK_IS_CONTAINER(m_widget)) - { - gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD ); - } - else -#endif { wxLogTrace(TRACE_FOCUS, _T("Can't set focus to %s(%s)"), @@ -3816,8 +3490,6 @@ void wxWindowGTK::DoAddChild(wxWindowGTK *child) (*m_insertCallback)(this, child); } -#ifdef __WXGTK20__ - void wxWindowGTK::AddChild(wxWindowBase *child) { wxWindowBase::AddChild(child); @@ -3842,18 +3514,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); @@ -3861,17 +3579,13 @@ 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; } -#endif // __WXGTK20__ - void wxWindowGTK::Raise() { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); @@ -3933,6 +3647,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 ) { @@ -3941,67 +3682,6 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) if (!m_widget->window) return; -#ifndef __WXGTK20__ - if (g_isIdle) - wxapp_install_idle_handler(); - - wxRect myRect; - if (m_wxwindow && rect) - { - myRect.SetSize(wxSize( m_wxwindow->allocation.width, - m_wxwindow->allocation.height)); - if ( myRect.Intersect(*rect).IsEmpty() ) - { - // nothing to do, rectangle is empty - return; - } - - rect = &myRect; - } - - // schedule the area for later updating in GtkUpdate() - if (eraseBackground && m_wxwindow && m_wxwindow->window) - { - if (rect) - { - m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height ); - } - else - { - m_clearRegion.Clear(); - m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height ); - } - } - - if (rect) - { - if (m_wxwindow) - { - m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height ); - } - else - { - GdkRectangle gdk_rect; - gdk_rect.x = rect->x; - gdk_rect.y = rect->y; - gdk_rect.width = rect->width; - gdk_rect.height = rect->height; - gtk_widget_draw( m_widget, &gdk_rect ); - } - } - else - { - if (m_wxwindow) - { - m_updateRegion.Clear(); - m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height ); - } - else - { - gtk_widget_draw( m_widget, (GdkRectangle*) NULL ); - } - } -#else // GTK+ 2 if (m_wxwindow) { GdkRectangle gdk_rect, @@ -4021,7 +3701,6 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE ); } -#endif // GTK+ 1/2 } void wxWindowGTK::Update() @@ -4037,13 +3716,8 @@ void wxWindowGTK::Update() void wxWindowGTK::GtkUpdate() { -#ifdef __WXGTK20__ if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window) gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE ); -#else - if (!m_updateRegion.IsEmpty()) - GtkSendPaintEvents(); -#endif // for consistency with other platforms (and also because it's convenient // to be able to update an entire TLW by calling Update() only once), we @@ -4060,9 +3734,6 @@ void wxWindowGTK::GtkSendPaintEvents() { if (!m_wxwindow) { -#ifndef __WXGTK20__ - m_clearRegion.Clear(); -#endif m_updateRegion.Clear(); return; } @@ -4106,7 +3777,6 @@ void wxWindowGTK::GtkSendPaintEvents() } else -#ifdef __WXGTK20__ { wxWindowDC dc( (wxWindow*)this ); dc.SetClippingRegion( m_updateRegion ); @@ -4116,38 +3786,6 @@ void wxWindowGTK::GtkSendPaintEvents() GetEventHandler()->ProcessEvent(erase_event); } -#else - // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2 - { - wxWindowDC dc( (wxWindow*)this ); - if (m_clearRegion.IsEmpty()) - dc.SetClippingRegion( m_updateRegion ); - else - dc.SetClippingRegion( m_clearRegion ); - - wxEraseEvent erase_event( GetId(), &dc ); - erase_event.SetEventObject( this ); - - if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM) - { - if (!g_eraseGC) - { - g_eraseGC = gdk_gc_new( pizza->bin_window ); - gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); - } - gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() ); - - wxRegionIterator upd( m_clearRegion ); - while (upd) - { - gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1, - upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() ); - upd ++; - } - } - m_clearRegion.Clear(); - } -#endif wxNcPaintEvent nc_paint_event( GetId() ); nc_paint_event.SetEventObject( this ); @@ -4159,67 +3797,20 @@ void wxWindowGTK::GtkSendPaintEvents() m_clipPaintRegion = false; -#if !defined(__WXUNIVERSAL__) && !defined(__WXGTK20__) - // The following code will result in all window-less widgets - // being redrawn because the wxWidgets class is allowed to - // paint over the window-less widgets. - - GList *children = pizza->children; - while (children) - { - GtkPizzaChild *child = (GtkPizzaChild*) children->data; - children = children->next; - - if (GTK_WIDGET_NO_WINDOW (child->widget) && - GTK_WIDGET_DRAWABLE (child->widget)) - { - // Get intersection of widget area and update region - wxRegion region( m_updateRegion ); - - GdkEventExpose gdk_event; - gdk_event.type = GDK_EXPOSE; - gdk_event.window = pizza->bin_window; - gdk_event.count = 0; - gdk_event.send_event = TRUE; - - wxRegionIterator upd( m_updateRegion ); - while (upd) - { - GdkRectangle rect; - rect.x = upd.GetX(); - rect.y = upd.GetY(); - rect.width = upd.GetWidth(); - rect.height = upd.GetHeight(); - - if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area)) - { - gtk_widget_event (child->widget, (GdkEvent*) &gdk_event); - } + m_updateRegion.Clear(); +} - upd ++; - } - } - } -#endif // native GTK 1 +void wxWindowGTK::SetDoubleBuffered( bool on ) +{ + wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); - m_updateRegion.Clear(); + if ( m_wxwindow ) + gtk_widget_set_double_buffered( m_wxwindow, on ); } void wxWindowGTK::ClearBackground() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - -#ifndef __WXGTK20__ - if (m_wxwindow && m_wxwindow->window) - { - m_clearRegion.Clear(); - wxSize size( GetClientSize() ); - m_clearRegion.Union( 0,0,size.x,size.y ); - - // Better do this in idle? - GtkUpdate(); - } -#endif } #if wxUSE_TOOLTIPS @@ -4281,12 +3872,10 @@ bool wxWindowGTK::SetForegroundColour( const wxColour &colour ) return true; } -#ifdef __WXGTK20__ PangoContext *wxWindowGTK::GtkGetPangoDefaultContext() { return gtk_widget_get_pango_context( m_widget ); } -#endif GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle) { @@ -4302,18 +3891,13 @@ GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle) if ( m_font.Ok() ) { -#ifdef __WXGTK20__ style->font_desc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); -#else - wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName(); - style->fontset_name = g_strdup(xfontname.c_str()); -#endif } if ( m_foregroundColour.Ok() ) { - GdkColor *fg = m_foregroundColour.GetColor(); + const GdkColor *fg = m_foregroundColour.GetColor(); style->fg[GTK_STATE_NORMAL] = *fg; style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG; @@ -4327,7 +3911,7 @@ GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle) if ( m_backgroundColour.Ok() ) { - GdkColor *bg = m_backgroundColour.GetColor(); + const GdkColor *bg = m_backgroundColour.GetColor(); style->bg[GTK_STATE_NORMAL] = *bg; style->base[GTK_STATE_NORMAL] = *bg; @@ -4472,7 +4056,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; @@ -4520,80 +4104,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) - gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); - else - gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" ); -} - -void wxWindowGTK::GtkUpdateScrollbar(int orient) -{ - GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust; - GtkSignalFunc fn = orient == wxHORIZONTAL - ? (GtkSignalFunc)gtk_window_hscroll_callback - : (GtkSignalFunc)gtk_window_vscroll_callback; - - gtk_signal_disconnect_by_func(GTK_OBJECT(adj), fn, (gpointer)this); - gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed"); - gtk_signal_connect(GTK_OBJECT(adj), "value_changed", fn, (gpointer)this); + if (pos > range - thumbVisible) + pos = range - thumbVisible; + if (pos < 0) + pos = 0; + const int i = orient == wxVERTICAL; + GtkAdjustment* adj = m_scrollBar[i]->adjustment; + adj->step_increment = 1; + adj->page_increment = + adj->page_size = thumbVisible; + adj->upper = range; + SetScrollPos(orient, pos); + gtk_adjustment_changed(adj); } void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) @@ -4601,90 +4152,117 @@ 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; + GtkAdjustment* adj = m_scrollBar[i]->adjustment; + const int max = int(adj->upper - adj->page_size); + if (pos > max) + pos = max; + if (pos < 0) + pos = 0; + m_scrollPos[i] = + adj->value = pos; + // If a "value_changed" signal emission is not already in progress + if (!m_blockValueChanged[i]) + { + gtk_adjustment_value_changed(adj); + } } } 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); } -void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) +// 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) { - wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); + wxASSERT(increment > 0); + const double tolerance = 1.0 / 1024; + return fabs(increment - fabs(x)) < tolerance; +} - wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); +wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range) +{ + DEBUG_MAIN_THREAD - // No scrolling requested. - if ((dx == 0) && (dy == 0)) return; + if (g_isIdle) + wxapp_install_idle_handler(); -#ifndef __WXGTK20__ - if (!m_updateRegion.IsEmpty()) - { - m_updateRegion.Offset( dx, dy ); + wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]); - int cw = 0; - int ch = 0; - GetClientSize( &cw, &ch ); - m_updateRegion.Intersect( 0, 0, cw, ch ); + 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 || value == int(oldPos + 0.5)) + { + return wxEVT_NULL; } - if (!m_clearRegion.IsEmpty()) + wxEventType eventType = wxEVT_SCROLL_THUMBTRACK; + if (!m_isScrolling) { - m_clearRegion.Offset( dx, dy ); + // Difference from last change event + const double diff = adj->value - oldPos; + const bool isDown = diff > 0; - int cw = 0; - int ch = 0; - GetClientSize( &cw, &ch ); - m_clearRegion.Intersect( 0, 0, cw, ch ); + 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; + } } -#endif + return eventType; +} + +void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) +{ + wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); + + wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); + + // No scrolling requested. + if ((dx == 0) && (dy == 0)) return; m_clipPaintRegion = true; @@ -4693,6 +4271,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 @@ -4767,7 +4368,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; @@ -4776,6 +4377,5 @@ bool wxWinModule::OnInit() void wxWinModule::OnExit() { if (g_eraseGC) - gdk_gc_unref( g_eraseGC ); + g_object_unref (g_eraseGC); } -