X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7317857df7deea8469f4a3572308bba22fe9d7bc..07d02e9ee0fe990aeb81e152a668d0011659b5c7:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index d94f9f2b0a..724b780866 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -17,38 +17,24 @@ #include "wx/window.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/radiobut.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" - -#if wxUSE_DRAG_AND_DROP - #include "wx/dnd.h" -#endif - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif - -#if wxUSE_CARET - #include "wx/caret.h" -#endif // wxUSE_CARET - +#include "wx/dnd.h" +#include "wx/tooltip.h" +#include "wx/caret.h" #include "wx/fontutil.h" #ifdef __WXDEBUG__ @@ -60,27 +46,16 @@ // 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 + #undef GTK_DISABLE_DEPRECATED + #include + #define GTK_DISABLE_DEPRECATED #endif #include "wx/gtk/private.h" -#include +#include "wx/gtk/win_gtk.h" #include #include -#include -#include - -#include "wx/gtk/win_gtk.h" - -#include - -#ifdef HAVE_XIM - #undef HAVE_XIM -#endif - -extern GtkContainerClass *pizza_parent_class; - //----------------------------------------------------------------------------- // documentation on internals //----------------------------------------------------------------------------- @@ -219,8 +194,6 @@ extern bool g_blockEventsOnDrag; extern bool g_blockEventsOnScroll; extern wxCursor g_globalCursor; -static GdkGC *g_eraseGC = NULL; - // mouse capture state: the window which has it and if the mouse is currently // inside it static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL; @@ -237,6 +210,11 @@ wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL; // yet, defer setting the focus to idle time. wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL; +// global variables because GTK+ DnD want to have the +// mouse event that caused it +GdkEvent *g_lastMouseEvent = (GdkEvent*) NULL; +int g_lastButtonNumber = 0; + extern bool g_mainThreadLocked; //----------------------------------------------------------------------------- @@ -343,14 +321,6 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) if (!win->m_hasVMT) return; - int dw = 0; - int dh = 0; - - if (win->m_hasScrolling) - { - GetScrollbarWidth(widget, dw, dh); - } - int dx = 0; int dy = 0; if (GTK_WIDGET_NO_WINDOW (widget)) @@ -359,6 +329,27 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) dy += widget->allocation.y; } + int x = dx; + int y = dy; + + int dw = 0; + int dh = 0; + if (win->m_hasScrolling) + { + GetScrollbarWidth(widget, dw, dh); + + if (win->GetLayoutDirection() == wxLayout_RightToLeft) + { + // This is actually wrong for old GTK+ version + // which do not display the scrollbar on the + // left side in RTL + x += dw; + } + } + + int w = widget->allocation.width-dw; + int h = widget->allocation.height-dh; + if (win->HasFlag(wxRAISED_BORDER)) { gtk_paint_shadow (widget->style, @@ -366,8 +357,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, NULL, NULL, // FIXME: No clipping? - dx, dy, - widget->allocation.width-dw, widget->allocation.height-dh ); + x, y, w, h ); return; } @@ -378,8 +368,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, NULL, NULL, // FIXME: No clipping? - dx, dy, - widget->allocation.width-dw, widget->allocation.height-dh ); + x, y, w, h ); return; } @@ -388,9 +377,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) GdkGC *gc; gc = gdk_gc_new( widget->window ); gdk_gc_set_foreground( gc, &widget->style->black ); - gdk_draw_rectangle( widget->window, gc, FALSE, - dx, dy, - widget->allocation.width-dw-1, widget->allocation.height-dh-1 ); + gdk_draw_rectangle( widget->window, gc, FALSE, x, y, w-1, h-1 ); g_object_unref (gc); return; } @@ -407,13 +394,9 @@ gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win ) { - if (gdk_event->count > 0) return FALSE; - - draw_frame( widget, win ); - - (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); - - return TRUE; + if (gdk_event->count == 0) + draw_frame(widget, win); + return false; } } @@ -460,10 +443,16 @@ void wxgtk_combo_size_request_callback(GtkWidget *widget, GtkRequisition entry_req; entry_req.width = 2; entry_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->entry) )->size_request ) + (gcombo->entry, &entry_req ); + + GtkRequisition button_req; + button_req.width = 2; + button_req.height = 2; (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request ) - (gcombo->button, &entry_req ); + (gcombo->button, &button_req ); - requisition->width = w - entry_req.width; + requisition->width = w - button_req.width; requisition->height = entry_req.height; } } @@ -480,15 +469,20 @@ gtk_window_expose_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal // This callback gets called in drawing-idle time under // GTK 2.0, so we don't need to defer anything to idle // time anymore. GtkPizza *pizza = GTK_PIZZA( widget ); - if (gdk_event->window != pizza->bin_window) return FALSE; + if (gdk_event->window != pizza->bin_window) + { + // block expose events on GTK_WIDGET(pizza)->window, + // all drawing is done on pizza->bin_window + return true; + } + #if 0 if (win->GetName()) @@ -519,10 +513,7 @@ gtk_window_expose_callback( GtkWidget *widget, win->GtkSendPaintEvents(); - // Let parent window draw window-less widgets - (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); - return FALSE; } } @@ -991,8 +982,7 @@ gtk_window_key_press_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (!win->m_hasVMT) return FALSE; @@ -1124,10 +1114,6 @@ gtk_window_key_press_callback( GtkWidget *widget, } } - - - - // win is a control: tab can be propagated up if ( !ret && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && @@ -1152,13 +1138,7 @@ gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); } - if (ret) - { - g_signal_stop_emission_by_name (widget, "key_press_event"); - return TRUE; - } - - return FALSE; + return ret; } } @@ -1178,7 +1158,7 @@ gtk_wxwindow_commit_cb (GtkIMContext *context, window, window->m_imData->lastKeyEvent); } - const wxWxCharBuffer data(wxGTK_CONV_BACK(str)); + const wxWxCharBuffer data(wxGTK_CONV_BACK_SYS(str)); if( !data ) return; @@ -1244,8 +1224,7 @@ gtk_window_key_release_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (!win->m_hasVMT) return FALSE; @@ -1260,11 +1239,7 @@ gtk_window_key_release_callback( GtkWidget *widget, return FALSE; } - if ( !win->GetEventHandler()->ProcessEvent( event ) ) - return FALSE; - - g_signal_stop_emission_by_name (widget, "key_release_event"); - return TRUE; + return win->GTKProcessEvent(event); } } @@ -1303,6 +1278,13 @@ template void InitMouseEvent(wxWindowGTK *win, event.m_x = (wxCoord)gdk_event->x - pt.x; event.m_y = (wxCoord)gdk_event->y - pt.y; + if ((win->m_wxwindow) && (win->GetLayoutDirection() == wxLayout_RightToLeft)) + { + // origin in the upper right corner + int window_width = gtk_pizza_get_rtl_offset( GTK_PIZZA(win->m_wxwindow) ); + event.m_x = window_width - event.m_x; + } + event.SetEventObject( win ); event.SetId( win->GetId() ); event.SetTimestamp( gdk_event->time ); @@ -1350,8 +1332,8 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) if (win->m_wxwindow) { GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow); - xx += pizza->xoffset; - yy += pizza->yoffset; + xx += gtk_pizza_get_xoffset( pizza ); + yy += gtk_pizza_get_yoffset( pizza ); } wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); @@ -1406,48 +1388,96 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) return win; } +// ---------------------------------------------------------------------------- +// common event handlers helpers +// ---------------------------------------------------------------------------- + +bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const +{ + // nothing special at this level + return GetEventHandler()->ProcessEvent(event); +} + +int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const +{ + DEBUG_MAIN_THREAD + + // don't need to install idle handler, its done from "event" signal + + if (!m_hasVMT) + return FALSE; + if (g_blockEventsOnDrag) + return TRUE; + if (g_blockEventsOnScroll) + return TRUE; + + if (!GTKIsOwnWindow(event->window)) + return FALSE; + + return -1; +} + +// overloads for all GDK event types we use here: we need to have this as +// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact, +// derives from it in the sense that the structs have the same layout +#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \ + static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \ + { \ + return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \ + } + +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton) +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion) +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing) + +#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD + +#define wxCOMMON_CALLBACK_PROLOGUE(event, win) \ + const int rc = wxGtkCallbackCommonPrologue(event, win); \ + if ( rc != -1 ) \ + return rc + +// send the wxChildFocusEvent and wxFocusEvent, common code of +// gtk_window_focus_in_callback() and SetFocus() +static bool DoSendFocusEvents(wxWindow *win) +{ + // Notify the parent keeping track of focus for the kbd navigation + // purposes that we got it. + wxChildFocusEvent eventChildFocus(win); + (void)win->GetEventHandler()->ProcessEvent(eventChildFocus); + + wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId()); + eventFocus.SetEventObject(win); + + return win->GetEventHandler()->ProcessEvent(eventFocus); +} + +// all event handlers must have C linkage as they're called from GTK+ C code +extern "C" +{ + //----------------------------------------------------------------------------- // "button_press_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); - if (g_isIdle) - wxapp_install_idle_handler(); - -/* - wxPrintf( wxT("1) OnButtonPress from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); -*/ - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return TRUE; - if (g_blockEventsOnScroll) return TRUE; - - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + g_lastButtonNumber = gdk_event->button; if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus()) { gtk_widget_grab_focus( win->m_wxwindow ); -/* - wxPrintf( wxT("GrabFocus from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); -*/ } // GDK sends surplus button down events // before a double click event. We // need to filter these out. - if (gdk_event->type == GDK_BUTTON_PRESS) + if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow)) { GdkEvent *peek_event = gdk_event_peek(); if (peek_event) @@ -1555,6 +1585,8 @@ gtk_window_button_press_callback( GtkWidget *widget, return FALSE; } + g_lastMouseEvent = (GdkEvent*) gdk_event; + wxMouseEvent event( event_type ); InitMouseEvent( win, event, gdk_event ); @@ -1574,11 +1606,10 @@ gtk_window_button_press_callback( GtkWidget *widget, event.SetEventObject( win ); event.SetId( win->GetId() ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "button_press_event"); + bool ret = win->GTKProcessEvent( event ); + g_lastMouseEvent = NULL; + if ( ret ) return TRUE; - } if (event_type == wxEVT_RIGHT_DOWN) { @@ -1594,33 +1625,24 @@ gtk_window_button_press_callback( GtkWidget *widget, win->GetId(), win->ClientToScreen(event.GetPosition())); evtCtx.SetEventObject(win); - return win->GetEventHandler()->ProcessEvent(evtCtx); + return win->GTKProcessEvent(evtCtx); } return FALSE; } -} //----------------------------------------------------------------------------- // "button_release_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - if (g_blockEventsOnScroll) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + g_lastButtonNumber = 0; wxEventType event_type = wxEVT_NULL; @@ -1643,6 +1665,8 @@ gtk_window_button_release_callback( GtkWidget *widget, return FALSE; } + g_lastMouseEvent = (GdkEvent*) gdk_event; + wxMouseEvent event( event_type ); InitMouseEvent( win, event, gdk_event ); @@ -1658,36 +1682,23 @@ gtk_window_button_release_callback( GtkWidget *widget, event.SetEventObject( win ); event.SetId( win->GetId() ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "button_release_event"); - return TRUE; - } + bool ret = win->GTKProcessEvent(event); - return FALSE; -} + g_lastMouseEvent = NULL; + + return ret; } //----------------------------------------------------------------------------- // "motion_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - if (g_blockEventsOnScroll) return FALSE; - - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); if (gdk_event->is_hint) { @@ -1699,12 +1710,7 @@ gtk_window_motion_notify_callback( GtkWidget *widget, gdk_event->y = y; } -/* - printf( "OnMotion from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - printf( win->GetClassInfo()->GetClassName() ); - printf( ".\n" ); -*/ + g_lastMouseEvent = (GdkEvent*) gdk_event; wxMouseEvent event( wxEVT_MOTION ); InitMouseEvent(win, event, gdk_event); @@ -1727,7 +1733,7 @@ gtk_window_motion_notify_callback( GtkWidget *widget, : wxEVT_LEAVE_WINDOW); InitMouseEvent(win, eventM, gdk_event); eventM.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(eventM); + win->GTKProcessEvent(eventM); } } else // no capture @@ -1742,34 +1748,29 @@ gtk_window_motion_notify_callback( GtkWidget *widget, if ( !g_captureWindow ) { wxSetCursorEvent cevent( event.m_x, event.m_y ); - if (win->GetEventHandler()->ProcessEvent( cevent )) + if (win->GTKProcessEvent( cevent )) { - // Rewrite cursor handling here (away from idle). + win->SetCursor( cevent.GetCursor() ); } } - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "motion_notify_event"); - return TRUE; - } + bool ret = win->GTKProcessEvent(event); - return FALSE; -} + g_lastMouseEvent = NULL; + + return ret; } //----------------------------------------------------------------------------- // "scroll_event", (mouse wheel event) //----------------------------------------------------------------------------- -extern "C" { static gboolean window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win) { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (gdk_event->direction != GDK_SCROLL_UP && gdk_event->direction != GDK_SCROLL_DOWN) @@ -1802,45 +1803,24 @@ window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win) event.SetId( win->GetId() ); event.SetTimestamp( gdk_event->time ); - return win->GetEventHandler()->ProcessEvent(event); -} + return win->GTKProcessEvent(event); } //----------------------------------------------------------------------------- // "popup-menu" //----------------------------------------------------------------------------- -extern "C" { + static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win) { - wxContextMenuEvent event( - wxEVT_CONTEXT_MENU, - win->GetId(), - wxPoint(-1, -1)); + wxContextMenuEvent event(wxEVT_CONTEXT_MENU, win->GetId(), wxPoint(-1, -1)); event.SetEventObject(win); - return win->GetEventHandler()->ProcessEvent(event); -} + return win->GTKProcessEvent(event); } //----------------------------------------------------------------------------- // "focus_in_event" //----------------------------------------------------------------------------- -// send the wxChildFocusEvent and wxFocusEvent, common code of -// gtk_window_focus_in_callback() and SetFocus() -static bool DoSendFocusEvents(wxWindow *win) -{ - // Notify the parent keeping track of focus for the kbd navigation - // purposes that we got it. - wxChildFocusEvent eventChildFocus(win); - (void)win->GetEventHandler()->ProcessEvent(eventChildFocus); - - wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId()); - eventFocus.SetEventObject(win); - - return win->GetEventHandler()->ProcessEvent(eventFocus); -} - -extern "C" { static gboolean gtk_window_focus_in_callback( GtkWidget *widget, GdkEventFocus *WXUNUSED(event), @@ -1848,8 +1828,7 @@ gtk_window_focus_in_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (win->m_imData) gtk_im_context_focus_in(win->m_imData->context); @@ -1860,11 +1839,6 @@ gtk_window_focus_in_callback( GtkWidget *widget, wxLogTrace(TRACE_FOCUS, _T("%s: focus in"), win->GetName().c_str()); -#ifdef HAVE_XIM - if (win->m_ic) - gdk_im_begin(win->m_ic, win->m_wxwindow->window); -#endif - #if wxUSE_CARET // caret needs to be informed about focus change wxCaret *caret = win->GetCaret(); @@ -1894,13 +1868,11 @@ gtk_window_focus_in_callback( GtkWidget *widget, return FALSE; } -} //----------------------------------------------------------------------------- // "focus_out_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, @@ -1908,8 +1880,7 @@ gtk_window_focus_out_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (win->m_imData) gtk_im_context_focus_out(win->m_imData->context); @@ -1924,11 +1895,6 @@ gtk_window_focus_out_callback( GtkWidget *widget, g_focusWindow = (wxWindowGTK *)NULL; -#ifdef HAVE_XIM - if (win->m_ic) - gdk_im_end(); -#endif - #if wxUSE_CARET // caret needs to be informed about focus change wxCaret *caret = win->GetCaret(); @@ -1949,7 +1915,7 @@ gtk_window_focus_out_callback( GtkWidget *widget, wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); event.SetEventObject( win ); - (void)win->GetEventHandler()->ProcessEvent( event ); + (void)win->GTKProcessEvent( event ); ret = TRUE; } @@ -1961,31 +1927,21 @@ gtk_window_focus_out_callback( GtkWidget *widget, return FALSE; } -} //----------------------------------------------------------------------------- // "enter_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); // Event was emitted after a grab if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - int x = 0; int y = 0; GdkModifierType state = (GdkModifierType)0; @@ -2001,45 +1957,29 @@ gtk_window_enter_callback( GtkWidget *widget, if ( !g_captureWindow ) { wxSetCursorEvent cevent( event.m_x, event.m_y ); - if (win->GetEventHandler()->ProcessEvent( cevent )) + if (win->GTKProcessEvent( cevent )) { - // Rewrite cursor handling here (away from idle). + win->SetCursor( cevent.GetCursor() ); } } - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "enter_notify_event"); - return TRUE; - } - - return FALSE; -} + return win->GTKProcessEvent(event); } //----------------------------------------------------------------------------- // "leave_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); // Event was emitted after an ungrab if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - wxMouseEvent event( wxEVT_LEAVE_WINDOW ); event.SetTimestamp( gdk_event->time ); event.SetEventObject( win ); @@ -2062,21 +2002,13 @@ gtk_window_leave_callback( GtkWidget *widget, event.m_x = x + pt.x; event.m_y = y + pt.y; - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "leave_notify_event"); - return TRUE; - } - - return FALSE; -} + return win->GTKProcessEvent(event); } //----------------------------------------------------------------------------- // "value_changed" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static void gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win) { @@ -2090,42 +2022,37 @@ gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win) wxWindowGTK::ScrollDir dir = win->ScrollDirFromRange(range); // generate the corresponding wx event - const int orient = win->OrientFromScrollDir(dir); + const int orient = wxWindow::OrientFromScrollDir(dir); wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient); event.SetEventObject(win); win->m_blockValueChanged[dir] = true; - win->GetEventHandler()->ProcessEvent(event); + win->GTKProcessEvent(event); win->m_blockValueChanged[dir] = false; } } -} //----------------------------------------------------------------------------- // "button_press_event" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win) { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal g_blockEventsOnScroll = true; win->m_mouseButtonDown = true; return false; } -} //----------------------------------------------------------------------------- // "event_after" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static void gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win) { @@ -2133,20 +2060,18 @@ gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win) { g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win); - const int orient = win->OrientFromScrollDir( + const int orient = wxWindow::OrientFromScrollDir( win->ScrollDirFromRange(range)); wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient); event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); + win->GTKProcessEvent(event); } } -} //----------------------------------------------------------------------------- // "button_release_event" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win) { @@ -2166,18 +2091,6 @@ gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* w return false; } -} - -// ---------------------------------------------------------------------------- -// this wxWindowBase function is implemented here (in platform-specific file) -// because it is static and so couldn't be made virtual -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::DoFindFocus() -{ - // the cast is necessary when we compile in wxUniversal mode - return (wxWindow *)g_focusWindow; -} //----------------------------------------------------------------------------- // "realize" from m_widget @@ -2186,7 +2099,6 @@ wxWindow *wxWindowBase::DoFindFocus() /* We cannot set colours and fonts before the widget has been realized, so we do this directly after realization. */ -extern "C" { static void gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) { @@ -2204,18 +2116,16 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) wxWindowCreateEvent event( win ); event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); -} + win->GTKProcessEvent( event ); } //----------------------------------------------------------------------------- // "size_allocate" //----------------------------------------------------------------------------- -extern "C" { static void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), - GtkAllocation *WXUNUSED(alloc), + GtkAllocation *alloc, wxWindow *win ) { if (g_isIdle) @@ -2227,6 +2137,12 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight)) return; + if ( !client_width && !client_height ) + { + // the window is currently unmapped, don't generate size events + return; + } + win->m_oldClientWidth = client_width; win->m_oldClientHeight = client_height; @@ -2234,137 +2150,21 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), { wxSizeEvent event( win->GetSize(), win->GetId() ); event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); - } -} -} - - -#ifdef HAVE_XIM - #define WXUNUSED_UNLESS_XIM(param) param -#else - #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param) -#endif - -/* Resize XIM window */ - -extern "C" { -static -void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), - GtkAllocation* WXUNUSED_UNLESS_XIM(alloc), - wxWindowGTK* WXUNUSED_UNLESS_XIM(win) ) -{ - if (g_isIdle) - wxapp_install_idle_handler(); - -#ifdef HAVE_XIM - if (!win->m_ic) - return; - - if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION) - { - gint 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); + win->GTKProcessEvent( event ); } -#endif // HAVE_XIM -} } -//----------------------------------------------------------------------------- -// "realize" from m_wxwindow -//----------------------------------------------------------------------------- +} // extern "C" -/* Initialize XIM support */ +// ---------------------------------------------------------------------------- +// this wxWindowBase function is implemented here (in platform-specific file) +// because it is static and so couldn't be made virtual +// ---------------------------------------------------------------------------- -extern "C" { -static void -gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), - wxWindowGTK * WXUNUSED_UNLESS_XIM(win) ) +wxWindow *wxWindowBase::DoFindFocus() { - if (g_isIdle) - wxapp_install_idle_handler(); - -#ifdef HAVE_XIM - 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; - - gint width, height; - GdkEventMask mask; - GdkColormap *colormap; - GdkICAttr *attr = win->m_icattr; - unsigned attrmask = GDK_IC_ALL_REQ; - GdkIMStyle style; - GdkIMStyle supported_style = (GdkIMStyle) - (GDK_IM_PREEDIT_NONE | - GDK_IM_PREEDIT_NOTHING | - GDK_IM_PREEDIT_POSITION | - GDK_IM_STATUS_NONE | - GDK_IM_STATUS_NOTHING); - - if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) - supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION); - - attr->style = style = gdk_im_decide_style (supported_style); - attr->client_window = widget->window; - - if ((colormap = gtk_widget_get_colormap (widget)) != - gtk_widget_get_default_colormap ()) - { - attrmask |= GDK_IC_PREEDIT_COLORMAP; - attr->preedit_colormap = colormap; - } - - attrmask |= GDK_IC_PREEDIT_FOREGROUND; - attrmask |= GDK_IC_PREEDIT_BACKGROUND; - attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL]; - attr->preedit_background = widget->style->base[GTK_STATE_NORMAL]; - - switch (style & GDK_IM_PREEDIT_MASK) - { - case GDK_IM_PREEDIT_POSITION: - if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) - { - g_warning ("over-the-spot style requires fontset"); - break; - } - - gdk_drawable_get_size (widget->window, &width, &height); - - attrmask |= GDK_IC_PREEDIT_POSITION_REQ; - attr->spot_location.x = 0; - attr->spot_location.y = height; - attr->preedit_area.x = 0; - attr->preedit_area.y = 0; - attr->preedit_area.width = width; - attr->preedit_area.height = height; - attr->preedit_fontset = widget->style->font; - - break; - } - - win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask); - - if (win->m_ic == NULL) - g_warning ("Can't create input context."); - else - { - mask = gdk_window_get_events (widget->window); - mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic)); - gdk_window_set_events (widget->window, mask); - - if (GTK_WIDGET_HAS_FOCUS(widget)) - gdk_im_begin (win->m_ic, widget->window); - } -#endif // HAVE_XIM -} + // the cast is necessary when we compile in wxUniversal mode + return (wxWindow *)g_focusWindow; } //----------------------------------------------------------------------------- @@ -2383,8 +2183,8 @@ static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child ) /* the window might have been scrolled already, do we have to adapt the position */ GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow); - child->m_x += pizza->xoffset; - child->m_y += pizza->yoffset; + child->m_x += gtk_pizza_get_xoffset( pizza ); + child->m_y += gtk_pizza_get_yoffset( pizza ); gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow), GTK_WIDGET(child->m_widget), @@ -2457,7 +2257,7 @@ void wxWindowGTK::Init() m_hasVMT = false; m_needParent = true; m_isBeingDeleted = false; - + m_showOnIdle= false; m_noExpose = false; @@ -2537,32 +2337,30 @@ bool wxWindowGTK::Create( wxWindow *parent, GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); scroll_class->scrollbar_spacing = 0; - gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + if (HasFlag(wxALWAYS_SHOW_SB)) + { + gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS ); + + scrolledWindow->hscrollbar_visible = TRUE; + scrolledWindow->vscrollbar_visible = TRUE; + } + else + { + gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + } m_scrollBar[ScrollDir_Horz] = GTK_RANGE(scrolledWindow->hscrollbar); m_scrollBar[ScrollDir_Vert] = GTK_RANGE(scrolledWindow->vscrollbar); + if (GetLayoutDirection() == wxLayout_RightToLeft) + gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE ); m_wxwindow = gtk_pizza_new(); #ifndef __WXUNIVERSAL__ - GtkPizza *pizza = GTK_PIZZA(m_wxwindow); - - if (HasFlag(wxRAISED_BORDER)) - { - gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT ); - } - else if (HasFlag(wxSUNKEN_BORDER)) - { - gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN ); - } - else if (HasFlag(wxSIMPLE_BORDER)) - { - gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN ); - } - else - { - gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE ); - } + if (HasFlag(wxSIMPLE_BORDER)) + gtk_container_set_border_width((GtkContainer*)m_wxwindow, 1); + else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) + gtk_container_set_border_width((GtkContainer*)m_wxwindow, 2); #endif // __WXUNIVERSAL__ gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow ); @@ -2633,13 +2431,6 @@ wxWindowGTK::~wxWindowGTK() if (m_widget) Show( false ); -#ifdef HAVE_XIM - if (m_ic) - gdk_ic_destroy (m_ic); - if (m_icattr) - gdk_ic_attr_destroy (m_icattr); -#endif - // delete before the widgets to avoid a crash on solaris delete m_imData; @@ -2681,12 +2472,11 @@ void wxWindowGTK::PostCreation() { // these get reported to wxWidgets -> wxPaintEvent - gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE ); - 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 ) ); + if (GetLayoutDirection() == wxLayout_LeftToRight) + gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) ); } // Create input method handler @@ -2742,14 +2532,6 @@ void wxWindowGTK::PostCreation() // Catch native resize events g_signal_connect (m_wxwindow, "size_allocate", G_CALLBACK (gtk_window_size_callback), this); - - // Initialize XIM support - g_signal_connect (m_wxwindow, "realize", - G_CALLBACK (gtk_wxwindow_realized_callback), this); - - // And resize XIM window - g_signal_connect (m_wxwindow, "size_allocate", - G_CALLBACK (gtk_wxwindow_size_callback), this); } if (GTK_IS_COMBO(m_widget)) @@ -2761,7 +2543,7 @@ void wxWindowGTK::PostCreation() this); } #ifdef GTK_IS_FILE_CHOOSER_BUTTON - else if (GTK_IS_FILE_CHOOSER_BUTTON(m_widget)) + else if (!gtk_check_version(2,6,0) && 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 @@ -2769,7 +2551,7 @@ void wxWindowGTK::PostCreation() // FIXME: what should be done here ? } #endif - else + else if ( !IsTopLevel() ) // top level windows use their own callback { // This is needed if we want to add our windows into native // GTK controls, such as the toolbar. With this callback, the @@ -2784,6 +2566,8 @@ void wxWindowGTK::PostCreation() m_hasVMT = true; + SetLayoutDirection(wxLayout_Default); + // unless the window was created initially hidden (i.e. Hide() had been // called before Create()), we should show it at GTK+ level as well if ( IsShown() ) @@ -2823,7 +2607,9 @@ bool wxWindowGTK::Destroy() void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height) { + // inform the parent to perform the move gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height ); + } void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags ) @@ -2831,10 +2617,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") ); wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") ); -/* - printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height ); -*/ - if (m_resizing) return; /* I don't like recursions */ m_resizing = true; @@ -2878,8 +2660,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags // 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 @@ -2896,13 +2676,13 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow); if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0) { - if (x != -1) m_x = x + pizza->xoffset; - if (y != -1) m_y = y + pizza->yoffset; + if (x != -1) m_x = x + gtk_pizza_get_xoffset( pizza ); + if (y != -1) m_y = y + gtk_pizza_get_yoffset( pizza ); } else { - m_x = x + pizza->xoffset; - m_y = y + pizza->yoffset; + m_x = x + gtk_pizza_get_xoffset( pizza ); + m_y = y + gtk_pizza_get_yoffset( pizza ); } int left_border = 0; @@ -2976,7 +2756,7 @@ bool wxWindowGTK::GtkShowFromOnIdle() m_showOnIdle = false; return true; } - + return false; } @@ -2998,9 +2778,6 @@ void wxWindowGTK::OnInternalIdle() SetBackgroundStyle(GetBackgroundStyle()); m_needsStyleChange = false; } - - // Update invalidated regions. - GtkUpdate(); wxCursor cursor = m_cursor; if (g_globalCursor.Ok()) cursor = g_globalCursor; @@ -3060,20 +2837,9 @@ void wxWindowGTK::DoSetClientSize( int width, int height ) GetScrollbarWidth(m_widget, dw, dh); } -#ifndef __WXUNIVERSAL__ - if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) - { - // shadow border size is 2 - dw += 2 * 2; - dh += 2 * 2; - } - if (HasFlag(wxSIMPLE_BORDER)) - { - // simple border size is 1 - dw += 1 * 2; - dh += 1 * 2; - } -#endif // __WXUNIVERSAL__ + const int border = GTK_CONTAINER(m_wxwindow)->border_width; + dw += 2 * border; + dh += 2 * border; width += dw; height += dh; @@ -3095,27 +2861,18 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const int dh = 0; if (m_hasScrolling) - { GetScrollbarWidth(m_widget, dw, dh); - } -#ifndef __WXUNIVERSAL__ - if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) - { - // shadow border size is 2 - dw += 2 * 2; - dh += 2 * 2; - } - if (HasFlag(wxSIMPLE_BORDER)) - { - // simple border size is 1 - dw += 1 * 2; - dh += 1 * 2; - } -#endif // __WXUNIVERSAL__ + const int border = GTK_CONTAINER(m_wxwindow)->border_width; + dw += 2 * border; + dh += 2 * border; w -= dw; h -= dh; + if (w < 0) + w = 0; + if (h < 0) + h = 0; } if (width) *width = w; @@ -3131,8 +2888,30 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const if (m_parent && m_parent->m_wxwindow) { GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow); - dx = pizza->xoffset; - dy = pizza->yoffset; + dx = gtk_pizza_get_xoffset( pizza ); + dy = gtk_pizza_get_yoffset( pizza ); + } + + if (m_x == -1 && m_y == -1) + { + GdkWindow *source = (GdkWindow *) NULL; + if (m_wxwindow) + source = GTK_PIZZA(m_wxwindow)->bin_window; + else + source = m_widget->window; + + if (source) + { + int org_x = 0; + int org_y = 0; + gdk_window_get_origin( source, &org_x, &org_y ); + + if (GetParent()) + GetParent()->ScreenToClient(&org_x, &org_y); + + wx_const_cast(wxWindowGTK*, this)->m_x = org_x; + wx_const_cast(wxWindowGTK*, this)->m_y = org_y; + } } if (x) (*x) = m_x - dx; @@ -3164,7 +2943,15 @@ void wxWindowGTK::DoClientToScreen( int *x, int *y ) const } } - if (x) *x += org_x; + + if (x) + { + if (GetLayoutDirection() == wxLayout_RightToLeft) + *x = (GetClientSize().x - *x) + org_x; + else + *x += org_x; + } + if (y) *y += org_y; } @@ -3193,7 +2980,13 @@ void wxWindowGTK::DoScreenToClient( int *x, int *y ) const } } - if (x) *x -= org_x; + if (x) + { + if (GetLayoutDirection() == wxLayout_RightToLeft) + *x = (GetClientSize().x - *x) - org_x; + else + *x -= org_x; + } if (y) *y -= org_y; } @@ -3375,6 +3168,22 @@ void wxWindowGTK::GetTextExtent( const wxString& string, g_object_unref (layout); } +bool wxWindowGTK::GTKSetDelayedFocusIfNeeded() +{ + if ( g_delayedFocus == this ) + { + if ( GTK_WIDGET_REALIZED(m_widget) ) + { + gtk_widget_grab_focus(m_widget); + g_delayedFocus = NULL; + + return true; + } + } + + return false; +} + void wxWindowGTK::SetFocus() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -3395,6 +3204,12 @@ void wxWindowGTK::SetFocus() { if (GTK_IS_CONTAINER(m_widget)) { + if (IsKindOf(CLASSINFO(wxRadioButton))) + { + gtk_widget_grab_focus (m_widget); + return; + } + gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD ); } else @@ -3466,7 +3281,7 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase ) m_showOnIdle = true; gtk_widget_hide( m_widget ); } - + /* insert GTK representation */ (*(newParent->m_insertCallback))(newParent, this); } @@ -3474,6 +3289,8 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase ) /* reverse: prevent GTK from deleting the widget arbitrarily */ gtk_widget_unref( m_widget ); + SetLayoutDirection(wxLayout_Default); + return true; } @@ -3508,6 +3325,63 @@ void wxWindowGTK::RemoveChild(wxWindowBase *child) wxapp_install_idle_handler(); } +/* static */ +wxLayoutDirection wxWindowGTK::GTKGetLayout(GtkWidget *widget) +{ + return gtk_widget_get_direction(GTK_WIDGET(widget)) == GTK_TEXT_DIR_RTL + ? wxLayout_RightToLeft + : wxLayout_LeftToRight; +} + +/* static */ +void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir) +{ + wxASSERT_MSG( dir != wxLayout_Default, _T("invalid layout direction") ); + + gtk_widget_set_direction(GTK_WIDGET(widget), + dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL + : GTK_TEXT_DIR_LTR); +} + +wxLayoutDirection wxWindowGTK::GetLayoutDirection() const +{ + return GTKGetLayout(m_widget); +} + +void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir) +{ + if ( dir == wxLayout_Default ) + { + const wxWindow *const parent = GetParent(); + if ( parent ) + { + // inherit layout from parent. + dir = parent->GetLayoutDirection(); + } + else // no parent, use global default layout + { + dir = wxTheApp->GetLayoutDirection(); + } + } + + if ( dir == wxLayout_Default ) + return; + + GTKSetLayout(m_widget, dir); + + if (m_wxwindow) + GTKSetLayout(m_wxwindow, dir); +} + +wxCoord +wxWindowGTK::AdjustForLayoutDirection(wxCoord x, + wxCoord WXUNUSED(width), + wxCoord WXUNUSED(widthTotal)) const +{ + // We now mirrors the coordinates of RTL windows in GtkPizza + return x; +} + void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move) { wxWindowBase::DoMoveInTabOrder(win, move); @@ -3618,18 +3492,41 @@ void wxWindowGTK::Lower() bool wxWindowGTK::SetCursor( const wxCursor &cursor ) { - wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") ); + if ( !wxWindowBase::SetCursor(cursor.Ok() ? cursor : *wxSTANDARD_CURSOR) ) + return false; - if (cursor == m_cursor) - return false; + GTKUpdateCursor(); - if (g_isIdle) - wxapp_install_idle_handler(); + return true; +} - if (cursor == wxNullCursor) - return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ); - else - return wxWindowBase::SetCursor( cursor ); +void wxWindowGTK::GTKUpdateCursor() +{ + wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor()); + if ( cursor.Ok() ) + { + wxArrayGdkWindows windowsThis; + GdkWindow * const winThis = GTKGetWindow(windowsThis); + if ( winThis ) + { + gdk_window_set_cursor(winThis, cursor.GetCursor()); + } + else + { + const size_t count = windowsThis.size(); + for ( size_t n = 0; n < count; n++ ) + { + GdkWindow *win = windowsThis[n]; + if ( !win ) + { + wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?")); + continue; + } + + gdk_window_set_cursor(win, cursor.GetCursor()); + } + } + } } void wxWindowGTK::WarpPointer( int x, int y ) @@ -3702,7 +3599,7 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) if (m_wxwindow) { if (!GTK_PIZZA(m_wxwindow)->bin_window) return; - + GdkRectangle gdk_rect, *p; if (rect) @@ -3711,6 +3608,9 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) gdk_rect.y = rect->y; gdk_rect.width = rect->width; gdk_rect.height = rect->height; + if (GetLayoutDirection() == wxLayout_RightToLeft) + gdk_rect.x = GetClientSize().x - gdk_rect.x - gdk_rect.width; + p = &gdk_rect; } else // invalidate everything @@ -3751,6 +3651,20 @@ void wxWindowGTK::GtkUpdate() } } +bool wxWindowGTK::DoIsExposed( int x, int y ) const +{ + return m_updateRegion.Contains(x, y) != wxOutRegion; +} + + +bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const +{ + if (GetLayoutDirection() == wxLayout_RightToLeft) + return m_updateRegion.Contains(x-w, y, w, h) != wxOutRegion; + else + return m_updateRegion.Contains(x, y, w, h) != wxOutRegion; +} + void wxWindowGTK::GtkSendPaintEvents() { if (!m_wxwindow) @@ -3762,6 +3676,33 @@ void wxWindowGTK::GtkSendPaintEvents() // Clip to paint region in wxClientDC m_clipPaintRegion = true; + m_nativeUpdateRegion = m_updateRegion; + + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + // Transform m_updateRegion under RTL + m_updateRegion.Clear(); + + gint width; + gdk_window_get_geometry( GTK_PIZZA(m_wxwindow)->bin_window, + NULL, NULL, &width, NULL, NULL ); + + wxRegionIterator upd( m_nativeUpdateRegion ); + while (upd) + { + wxRect rect; + rect.x = upd.GetX(); + rect.y = upd.GetY(); + rect.width = upd.GetWidth(); + rect.height = upd.GetHeight(); + + rect.x = width - rect.x - rect.width; + m_updateRegion.Union( rect ); + + ++upd; + } + } + // widget to draw on GtkPizza *pizza = GTK_PIZZA (m_wxwindow); @@ -3774,7 +3715,7 @@ void wxWindowGTK::GtkSendPaintEvents() if (GTK_WIDGET_MAPPED(parent->m_widget)) { - wxRegionIterator upd( m_updateRegion ); + wxRegionIterator upd( m_nativeUpdateRegion ); while (upd) { GdkRectangle rect; @@ -3797,7 +3738,6 @@ void wxWindowGTK::GtkSendPaintEvents() } } else - { wxWindowDC dc( (wxWindow*)this ); dc.SetClippingRegion( m_updateRegion ); @@ -3819,6 +3759,7 @@ void wxWindowGTK::GtkSendPaintEvents() m_clipPaintRegion = false; m_updateRegion.Clear(); + m_nativeUpdateRegion.Clear(); } void wxWindowGTK::SetDoubleBuffered( bool on ) @@ -3829,6 +3770,11 @@ void wxWindowGTK::SetDoubleBuffered( bool on ) gtk_widget_set_double_buffered( m_wxwindow, on ); } +bool wxWindowGTK::IsDoubleBuffered() const +{ + return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow ); +} + void wxWindowGTK::ClearBackground() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -3845,8 +3791,15 @@ void wxWindowGTK::DoSetToolTip( wxToolTip *tip ) void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip ) { - wxString tmp( tip ); - gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL ); + if (tip) + { + wxString tmp( tip ); + gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL ); + } + else + { + gtk_tooltips_set_tip( tips, GetConnectWidget(), NULL, NULL); + } } #endif // wxUSE_TOOLTIPS @@ -3916,45 +3869,54 @@ GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle) pango_font_description_copy( m_font.GetNativeFontInfo()->description ); } + int flagsNormal = 0, + flagsPrelight = 0, + flagsActive = 0, + flagsInsensitive = 0; + if ( m_foregroundColour.Ok() ) { const GdkColor *fg = m_foregroundColour.GetColor(); - style->fg[GTK_STATE_NORMAL] = *fg; - style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG; + style->fg[GTK_STATE_NORMAL] = + style->text[GTK_STATE_NORMAL] = *fg; + flagsNormal |= GTK_RC_FG | GTK_RC_TEXT; - style->fg[GTK_STATE_PRELIGHT] = *fg; - style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG; + style->fg[GTK_STATE_PRELIGHT] = + style->text[GTK_STATE_PRELIGHT] = *fg; + flagsPrelight |= GTK_RC_FG | GTK_RC_TEXT; - style->fg[GTK_STATE_ACTIVE] = *fg; - style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG; + style->fg[GTK_STATE_ACTIVE] = + style->text[GTK_STATE_ACTIVE] = *fg; + flagsActive |= GTK_RC_FG | GTK_RC_TEXT; } if ( m_backgroundColour.Ok() ) { const GdkColor *bg = m_backgroundColour.GetColor(); - style->bg[GTK_STATE_NORMAL] = *bg; + style->bg[GTK_STATE_NORMAL] = style->base[GTK_STATE_NORMAL] = *bg; - style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags) - (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE); + flagsNormal |= GTK_RC_BG | GTK_RC_BASE; - style->bg[GTK_STATE_PRELIGHT] = *bg; + style->bg[GTK_STATE_PRELIGHT] = style->base[GTK_STATE_PRELIGHT] = *bg; - style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags) - (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE); + flagsPrelight |= GTK_RC_BG | GTK_RC_BASE; - style->bg[GTK_STATE_ACTIVE] = *bg; + style->bg[GTK_STATE_ACTIVE] = style->base[GTK_STATE_ACTIVE] = *bg; - style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags) - (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE); + flagsActive |= GTK_RC_BG | GTK_RC_BASE; - style->bg[GTK_STATE_INSENSITIVE] = *bg; + style->bg[GTK_STATE_INSENSITIVE] = style->base[GTK_STATE_INSENSITIVE] = *bg; - style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags) - (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE); + flagsInsensitive |= GTK_RC_BG | GTK_RC_BASE; } + style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)flagsNormal; + style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)flagsPrelight; + style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)flagsActive; + style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)flagsInsensitive; + return style; } @@ -4043,12 +4005,18 @@ GtkWidget* wxWindowGTK::GetConnectWidget() return connect_widget; } -bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window ) +bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const { - if (m_wxwindow) - return (window == GTK_PIZZA(m_wxwindow)->bin_window); + wxArrayGdkWindows windowsThis; + GdkWindow * const winThis = GTKGetWindow(windowsThis); - return (window == m_widget->window); + return winThis ? window == winThis + : windowsThis.Index(window) != wxNOT_FOUND; +} + +GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const +{ + return m_wxwindow ? GTK_PIZZA(m_wxwindow)->bin_window : m_widget->window; } bool wxWindowGTK::SetFont( const wxFont &font ) @@ -4186,8 +4154,8 @@ void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh)) pos = max; if (pos < 0) pos = 0; - m_scrollPos[dir] = - adj->value = pos; + m_scrollPos[dir] = adj->value = pos; + // If a "value_changed" signal emission is not already in progress if (!m_blockValueChanged[dir]) { @@ -4240,7 +4208,9 @@ wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range) 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 @@ -4286,9 +4256,34 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) m_clipPaintRegion = true; - gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); + if (GetLayoutDirection() == wxLayout_RightToLeft) + gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), dx, -dy ); + else + gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); m_clipPaintRegion = false; + +#if wxUSE_CARET + bool restoreCaret = (GetCaret() != NULL && GetCaret()->IsVisible()); + if (restoreCaret) + { + wxRect caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize()); + if (dx > 0) + caretRect.width += dx; + else + { + caretRect.x += dx; caretRect.width -= dx; + } + if (dy > 0) + caretRect.height += dy; + else + { + caretRect.y += dy; caretRect.height -= dy; + } + + RefreshRect(caretRect); + } +#endif // wxUSE_CARET } void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget* w, int wxstyle) @@ -4369,33 +4364,3 @@ void wxRemoveGrab(wxWindow* window) { gtk_grab_remove( (GtkWidget*) window->GetHandle() ); } - -// ---------------------------------------------------------------------------- -// wxWinModule -// ---------------------------------------------------------------------------- - -class wxWinModule : public wxModule -{ -public: - bool OnInit(); - void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxWinModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule) - -bool wxWinModule::OnInit() -{ - // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() ); - // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); - - return true; -} - -void wxWinModule::OnExit() -{ - if (g_eraseGC) - g_object_unref (g_eraseGC); -}