X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6522713c7527e5f683a107dff8f40e3ea19a4745..9f4de6b2cf06f53a98b28f53640f3b9ec8cf4182:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 15b54ffc16..bad1ac7648 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -25,6 +25,7 @@ #include "wx/utils.h" #include "wx/dialog.h" #include "wx/msgdlg.h" +#include "wx/module.h" #if wxUSE_DRAG_AND_DROP #include "wx/dnd.h" @@ -38,6 +39,10 @@ #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" @@ -50,8 +55,7 @@ #include -#include -#include +#include "wx/gtk/private.h" #include #include #include @@ -61,6 +65,22 @@ #include "wx/gtk/win_gtk.h" +#ifdef __WXGTK20__ + #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d)) +#else + #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d)) +#endif + +#ifdef __WXGTK20__ + #ifdef HAVE_XIM + #undef HAVE_XIM + #endif +#endif + +#ifdef __WXGTK20__ +extern GtkContainerClass *pizza_parent_class; +#endif + //----------------------------------------------------------------------------- // documentation on internals //----------------------------------------------------------------------------- @@ -200,6 +220,8 @@ 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; @@ -210,7 +232,16 @@ static bool g_captureWindowHasMouse = FALSE; // the last window which had the focus - this is normally never NULL (except // if we never had focus at all) as even when g_focusWindow is NULL it still // keeps its previous value -static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL; +static wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL; + +// the frame that is currently active (i.e. its child has focus). It is +// used to generate wxActivateEvents +static wxWindowGTK *g_activeFrame = (wxWindowGTK*) NULL; +static bool g_activeFrameLostFocus = FALSE; + +// If a window get the focus set but has not been realized +// yet, defer setting the focus to idle time. +wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL; // if we detect that the app has got/lost the focus, we set this variable to // either TRUE or FALSE and an activate event will be sent during the next @@ -239,43 +270,6 @@ extern bool g_mainThreadLocked; #else # define DEBUG_MAIN_THREAD #endif - -static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget), - GdkEvent *WXUNUSED(event), - const wxChar *WXUNUSED(name) ) -{ -/* - static bool s_done = FALSE; - if ( !s_done ) - { - wxLog::AddTraceMask("focus"); - s_done = TRUE; - } - wxLogTrace(wxT("FOCUS NOW AT: %s"), name); -*/ - - return FALSE; -} - -void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window ) -{ - // suppress warnings about gtk_debug_focus_in_callback being unused with - // this "if ( 0 )" - if ( 0 ) - { - wxString tmp = name; - tmp += wxT(" FROM "); - tmp += window; - - wxChar *s = new wxChar[tmp.Length()+1]; - - wxStrcpy( s, tmp ); - - gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event", - GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s ); - } -} - #else #define DEBUG_MAIN_THREAD #endif // Debug @@ -366,34 +360,34 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) if (win->m_hasScrolling) { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget); + 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 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 ); + 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) ); + 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->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 (scroll_window->hscrollbar_visible) + { + dh += hscroll_req.height; + dh += scroll_class->scrollbar_spacing; + } +} int dx = 0; int dy = 0; @@ -449,6 +443,11 @@ gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_even draw_frame( widget, win ); +#ifdef __WXGTK20__ + + (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); + +#endif return TRUE; } @@ -456,230 +455,14 @@ gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_even // "draw" of m_widget //----------------------------------------------------------------------------- +#ifndef __WXGTK20__ + static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win ) { draw_frame( widget, win ); } -//----------------------------------------------------------------------------- -// key code mapping routines -//----------------------------------------------------------------------------- - -static long map_to_unmodified_wx_keysym( GdkEventKey *event ) -{ - KeySym keysym = event->keyval; - guint key_code = 0; - - switch (keysym) - { - case GDK_Shift_L: - case GDK_Shift_R: key_code = WXK_SHIFT; break; - case GDK_Control_L: - case GDK_Control_R: key_code = WXK_CONTROL; break; - case GDK_Meta_L: - case GDK_Meta_R: - case GDK_Alt_L: - case GDK_Alt_R: - case GDK_Super_L: - case GDK_Super_R: key_code = WXK_ALT; break; - case GDK_Menu: key_code = WXK_MENU; break; - case GDK_Help: key_code = WXK_HELP; break; - case GDK_BackSpace: key_code = WXK_BACK; break; - case GDK_ISO_Left_Tab: - case GDK_Tab: key_code = WXK_TAB; break; - case GDK_Linefeed: key_code = WXK_RETURN; break; - case GDK_Clear: key_code = WXK_CLEAR; break; - case GDK_Return: key_code = WXK_RETURN; break; - case GDK_Pause: key_code = WXK_PAUSE; break; - case GDK_Scroll_Lock: key_code = WXK_SCROLL; break; - case GDK_Escape: key_code = WXK_ESCAPE; break; - case GDK_Delete: key_code = WXK_DELETE; break; - case GDK_Home: key_code = WXK_HOME; break; - case GDK_Left: key_code = WXK_LEFT; break; - case GDK_Up: key_code = WXK_UP; break; - case GDK_Right: key_code = WXK_RIGHT; break; - case GDK_Down: key_code = WXK_DOWN; break; - case GDK_Prior: key_code = WXK_PRIOR; break; -// case GDK_Page_Up: key_code = WXK_PAGEUP; break; - case GDK_Next: key_code = WXK_NEXT; break; -// case GDK_Page_Down: key_code = WXK_PAGEDOWN; break; - case GDK_End: key_code = WXK_END; break; - case GDK_Begin: key_code = WXK_HOME; break; - case GDK_Select: key_code = WXK_SELECT; break; - case GDK_Print: key_code = WXK_PRINT; break; - case GDK_Execute: key_code = WXK_EXECUTE; break; - case GDK_Insert: key_code = WXK_INSERT; break; - case GDK_Num_Lock: key_code = WXK_NUMLOCK; break; - - case GDK_KP_0: key_code = WXK_NUMPAD0; break; - case GDK_KP_1: key_code = WXK_NUMPAD1; break; - case GDK_KP_2: key_code = WXK_NUMPAD2; break; - case GDK_KP_3: key_code = WXK_NUMPAD3; break; - case GDK_KP_4: key_code = WXK_NUMPAD4; break; - case GDK_KP_5: key_code = WXK_NUMPAD5; break; - case GDK_KP_6: key_code = WXK_NUMPAD6; break; - case GDK_KP_7: key_code = WXK_NUMPAD7; break; - case GDK_KP_8: key_code = WXK_NUMPAD8; break; - case GDK_KP_9: key_code = WXK_NUMPAD9; break; - case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break; - case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break; - case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break; - case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break; - case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break; - case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break; - case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break; - case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break; - case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break; - case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break; - case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break; - case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break; - case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break; -// case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break; - case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break; -// case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break; - case GDK_KP_End: key_code = WXK_NUMPAD_END; break; - case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break; - case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break; - case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break; - case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break; - case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break; - case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break; - case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break; - case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break; - case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break; - case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break; - - case GDK_F1: key_code = WXK_F1; break; - case GDK_F2: key_code = WXK_F2; break; - case GDK_F3: key_code = WXK_F3; break; - case GDK_F4: key_code = WXK_F4; break; - case GDK_F5: key_code = WXK_F5; break; - case GDK_F6: key_code = WXK_F6; break; - case GDK_F7: key_code = WXK_F7; break; - case GDK_F8: key_code = WXK_F8; break; - case GDK_F9: key_code = WXK_F9; break; - case GDK_F10: key_code = WXK_F10; break; - case GDK_F11: key_code = WXK_F11; break; - case GDK_F12: key_code = WXK_F12; break; - default: - { - if (event->length == 1) - { - key_code = toupper( (unsigned char)*event->string ); - } - else if ((keysym & 0xFF) == keysym) - { - guint upper = gdk_keyval_to_upper( (guint)keysym ); - keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */ - key_code = (guint)keysym; - } - } - } - - return (key_code); -} - -static long map_to_wx_keysym( GdkEventKey *event ) -{ - KeySym keysym = event->keyval; - guint key_code = 0; - - switch (keysym) - { - case GDK_Menu: key_code = WXK_MENU; break; - case GDK_Help: key_code = WXK_HELP; break; - case GDK_BackSpace: key_code = WXK_BACK; break; - case GDK_ISO_Left_Tab: - case GDK_Tab: key_code = WXK_TAB; break; - case GDK_Linefeed: key_code = WXK_RETURN; break; - case GDK_Clear: key_code = WXK_CLEAR; break; - case GDK_Return: key_code = WXK_RETURN; break; - case GDK_Pause: key_code = WXK_PAUSE; break; - case GDK_Scroll_Lock: key_code = WXK_SCROLL; break; - case GDK_Escape: key_code = WXK_ESCAPE; break; - case GDK_Delete: key_code = WXK_DELETE; break; - case GDK_Home: key_code = WXK_HOME; break; - case GDK_Left: key_code = WXK_LEFT; break; - case GDK_Up: key_code = WXK_UP; break; - case GDK_Right: key_code = WXK_RIGHT; break; - case GDK_Down: key_code = WXK_DOWN; break; - case GDK_Prior: key_code = WXK_PRIOR; break; -// case GDK_Page_Up: key_code = WXK_PAGEUP; break; - case GDK_Next: key_code = WXK_NEXT; break; -// case GDK_Page_Down: key_code = WXK_PAGEDOWN; break; - case GDK_End: key_code = WXK_END; break; - case GDK_Begin: key_code = WXK_HOME; break; - case GDK_Select: key_code = WXK_SELECT; break; - case GDK_Print: key_code = WXK_PRINT; break; - case GDK_Execute: key_code = WXK_EXECUTE; break; - case GDK_Insert: key_code = WXK_INSERT; break; - case GDK_Num_Lock: key_code = WXK_NUMLOCK; break; - - case GDK_KP_0: key_code = '0'; break; - case GDK_KP_1: key_code = '1'; break; - case GDK_KP_2: key_code = '2'; break; - case GDK_KP_3: key_code = '3'; break; - case GDK_KP_4: key_code = '4'; break; - case GDK_KP_5: key_code = '5'; break; - case GDK_KP_6: key_code = '6'; break; - case GDK_KP_7: key_code = '7'; break; - case GDK_KP_8: key_code = '8'; break; - case GDK_KP_9: key_code = '9'; break; - case GDK_KP_Space: key_code = ' '; break; - case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */ - case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */ - case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break; - case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break; - case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break; - case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break; - case GDK_KP_Home: key_code = WXK_HOME; break; - case GDK_KP_Left: key_code = WXK_LEFT; break; - case GDK_KP_Up: key_code = WXK_UP; break; - case GDK_KP_Right: key_code = WXK_RIGHT; break; - case GDK_KP_Down: key_code = WXK_DOWN; break; - case GDK_KP_Prior: key_code = WXK_PRIOR; break; -// case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break; - case GDK_KP_Next: key_code = WXK_NEXT; break; -// case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break; - case GDK_KP_End: key_code = WXK_END; break; - case GDK_KP_Begin: key_code = WXK_HOME; break; - case GDK_KP_Insert: key_code = WXK_INSERT; break; - case GDK_KP_Delete: key_code = WXK_DELETE; break; - case GDK_KP_Equal: key_code = '='; break; - case GDK_KP_Multiply: key_code = '*'; break; - case GDK_KP_Add: key_code = '+'; break; - case GDK_KP_Separator: key_code = ','; break; - case GDK_KP_Subtract: key_code = '-'; break; - case GDK_KP_Decimal: key_code = '.'; break; - case GDK_KP_Divide: key_code = '/'; break; - - case GDK_F1: key_code = WXK_F1; break; - case GDK_F2: key_code = WXK_F2; break; - case GDK_F3: key_code = WXK_F3; break; - case GDK_F4: key_code = WXK_F4; break; - case GDK_F5: key_code = WXK_F5; break; - case GDK_F6: key_code = WXK_F6; break; - case GDK_F7: key_code = WXK_F7; break; - case GDK_F8: key_code = WXK_F8; break; - case GDK_F9: key_code = WXK_F9; break; - case GDK_F10: key_code = WXK_F10; break; - case GDK_F11: key_code = WXK_F11; break; - case GDK_F12: key_code = WXK_F12; break; - default: - { - if (event->length == 1) - { - key_code = (unsigned char)*event->string; - } - else if ((keysym & 0xFF) == keysym) - { - key_code = (guint)keysym; - } - } - } - - return (key_code); -} +#endif // GTK+ < 2.0 //----------------------------------------------------------------------------- // "size_request" of m_widget @@ -709,8 +492,8 @@ static int gtk_window_expose_callback( GtkWidget *widget, if (g_isIdle) wxapp_install_idle_handler(); -/* - if (win->GetName() == wxT("panel")) +#if 0 + if (win->GetName()) { wxPrintf( wxT("OnExpose from ") ); if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) @@ -720,89 +503,21 @@ static int gtk_window_expose_callback( GtkWidget *widget, (int)gdk_event->area.width, (int)gdk_event->area.height ); } -*/ - - GtkPizza *pizza = GTK_PIZZA (widget); - - if (win->GetThemeEnabled()) - { - 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, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1); - } +#endif win->GetUpdateRegion().Union( gdk_event->area.x, gdk_event->area.y, gdk_event->area.width, gdk_event->area.height ); - if (gdk_event->count == 0) - { - win->m_clipPaintRegion = TRUE; - - wxWindowDC dc(win); - dc.SetClippingRegion(win->GetUpdateRegion()); - wxEraseEvent eevent( win->GetId(), &dc ); - eevent.SetEventObject( win ); -#if 1 - (void)win->GetEventHandler()->ProcessEvent(eevent); -#else // 0 - if (!win->GetEventHandler()->ProcessEvent(eevent)) - { - wxClientDC dc( win ); - dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) ); - dc.SetPen( *wxTRANSPARENT_PEN ); - - wxRegionIterator upd( win->GetUpdateRegion() ); - while (upd) - { - dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() ); - upd ++; - } - } -#endif // 1/0 - - wxNcPaintEvent eventNc( win->GetId() ); - eventNc.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( eventNc ); - - wxPaintEvent event( win->GetId() ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); - - win->GetUpdateRegion().Clear(); - - win->m_clipPaintRegion = FALSE; - } + // Actual redrawing takes place in idle time. + win->GtkUpdate(); - /* The following code will result in all window-less widgets - being redrawn if the wxWindows class is given a chance to - paint *anything* because it will then be allowed to paint - over the window-less widgets */ - GList *children = pizza->children; - while (children) - { - GtkPizzaChild *child = (GtkPizzaChild*) children->data; - children = children->next; +#ifdef __WXGTK20__ - GdkEventExpose child_event = *gdk_event; + (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event); - if (GTK_WIDGET_NO_WINDOW (child->widget) && - GTK_WIDGET_DRAWABLE (child->widget) /* && - gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ ) - { - child_event.area.x = child->widget->allocation.x; - child_event.area.y = child->widget->allocation.y; - child_event.area.width = child->widget->allocation.width; - child_event.area.height = child->widget->allocation.height; - gtk_widget_event (child->widget, (GdkEvent*) &child_event); - } - } +#endif return TRUE; } @@ -811,11 +526,11 @@ static int gtk_window_expose_callback( GtkWidget *widget, // "event" of m_wxwindow //----------------------------------------------------------------------------- -/* 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. */ +// 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. gint gtk_window_event_event_callback( GtkWidget *widget, GdkEventExpose *event, @@ -834,8 +549,10 @@ gint gtk_window_event_event_callback( GtkWidget *widget, // "draw" of m_wxwindow //----------------------------------------------------------------------------- -/* This callback is a complete replacement of the gtk_pizza_draw() function, - which disabled. */ +#ifndef __WXGTK20__ + +// This callback is a complete replacement of the gtk_pizza_draw() function, +// which is disabled. static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, @@ -846,14 +563,16 @@ static void gtk_window_draw_callback( GtkWidget *widget, if (g_isIdle) wxapp_install_idle_handler(); + // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if + // there are no child windows. if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) && (win->GetChildren().GetCount() == 0)) { return; } -/* - if (win->GetName() == wxT("panel")) +#if 0 + if (win->GetName()) { wxPrintf( wxT("OnDraw from ") ); if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) @@ -863,8 +582,9 @@ static void gtk_window_draw_callback( GtkWidget *widget, (int)rect->width, (int)rect->height ); } -*/ +#endif +#ifndef __WXUNIVERSAL__ GtkPizza *pizza = GTK_PIZZA (widget); if (win->GetThemeEnabled()) @@ -875,79 +595,456 @@ static void gtk_window_draw_callback( GtkWidget *widget, 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, "base", 0, 0, -1, -1); + 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); + } + + + if (!(GTK_WIDGET_APP_PAINTABLE (widget)) && + (pizza->clear_on_draw)) + { + gdk_window_clear_area( pizza->bin_window, + rect->x, rect->y, rect->width, rect->height); + } +#endif + + win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); + + // Actual redrawing takes place 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 +} + +#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") + +// translates an X key symbol to WXK_XXX value +// +// if isChar is true it means that the value returned will be used for EVT_CHAR +// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide, +// for example, while if it is false it means that the value is going to be +// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to +// WXK_NUMPAD_DIVIDE +static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) +{ + long key_code; + + switch ( keysym ) + { + // Shift, Control and Alt don't generate the CHAR events at all + case GDK_Shift_L: + case GDK_Shift_R: + key_code = isChar ? 0 : WXK_SHIFT; + break; + case GDK_Control_L: + case GDK_Control_R: + key_code = isChar ? 0 : WXK_CONTROL; + break; + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Alt_L: + case GDK_Alt_R: + case GDK_Super_L: + case GDK_Super_R: + key_code = isChar ? 0 : WXK_ALT; + break; + + // neither do the toggle modifies + case GDK_Scroll_Lock: + key_code = isChar ? 0 : WXK_SCROLL; + break; + + case GDK_Caps_Lock: + key_code = isChar ? 0 : WXK_CAPITAL; + break; + + case GDK_Num_Lock: + key_code = isChar ? 0 : WXK_NUMLOCK; + break; + + + // various other special keys + case GDK_Menu: + key_code = WXK_MENU; + break; + + case GDK_Help: + key_code = WXK_HELP; + break; + + case GDK_BackSpace: + key_code = WXK_BACK; + break; + + case GDK_ISO_Left_Tab: + case GDK_Tab: + key_code = WXK_TAB; + break; + + case GDK_Linefeed: + case GDK_Return: + key_code = WXK_RETURN; + break; + + case GDK_Clear: + key_code = WXK_CLEAR; + break; + + case GDK_Pause: + key_code = WXK_PAUSE; + break; + + case GDK_Select: + key_code = WXK_SELECT; + break; + + case GDK_Print: + key_code = WXK_PRINT; + break; + + case GDK_Execute: + key_code = WXK_EXECUTE; + break; + + case GDK_Escape: + key_code = WXK_ESCAPE; + break; + + // cursor and other extended keyboard keys + case GDK_Delete: + key_code = WXK_DELETE; + break; + + case GDK_Home: + key_code = WXK_HOME; + break; + + case GDK_Left: + key_code = WXK_LEFT; + break; + + case GDK_Up: + key_code = WXK_UP; + break; + + case GDK_Right: + key_code = WXK_RIGHT; + break; + + case GDK_Down: + key_code = WXK_DOWN; + break; + + case GDK_Prior: // == GDK_Page_Up + key_code = WXK_PRIOR; + break; + + case GDK_Next: // == GDK_Page_Down + key_code = WXK_NEXT; + break; + + case GDK_End: + key_code = WXK_END; + break; + + case GDK_Begin: + key_code = WXK_HOME; + break; + + case GDK_Insert: + key_code = WXK_INSERT; + break; + + + // numpad keys + case GDK_KP_0: + case GDK_KP_1: + case GDK_KP_2: + case GDK_KP_3: + case GDK_KP_4: + case GDK_KP_5: + case GDK_KP_6: + case GDK_KP_7: + case GDK_KP_8: + case GDK_KP_9: + key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0; + break; + + case GDK_KP_Space: + key_code = isChar ? ' ' : WXK_NUMPAD_SPACE; + break; + + case GDK_KP_Tab: + key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB; + break; + + case GDK_KP_Enter: + key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER; + break; + + case GDK_KP_F1: + key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1; + break; + + case GDK_KP_F2: + key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2; + break; + + case GDK_KP_F3: + key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3; + break; + + case GDK_KP_F4: + key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4; + break; + + case GDK_KP_Home: + key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME; + break; + + case GDK_KP_Left: + key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT; + break; + + case GDK_KP_Up: + key_code = isChar ? WXK_UP : WXK_NUMPAD_UP; + break; + + case GDK_KP_Right: + key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT; + break; + + case GDK_KP_Down: + key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN; + break; + + case GDK_KP_Prior: // == GDK_KP_Page_Up + key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR; + break; + + case GDK_KP_Next: // == GDK_KP_Page_Down + key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT; + break; + + case GDK_KP_End: + key_code = isChar ? WXK_END : WXK_NUMPAD_END; + break; + + case GDK_KP_Begin: + key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN; + break; + + case GDK_KP_Insert: + key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT; + break; + + case GDK_KP_Delete: + key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE; + break; + + case GDK_KP_Equal: + key_code = isChar ? '=' : WXK_NUMPAD_EQUAL; + break; + + case GDK_KP_Multiply: + key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY; + break; + + case GDK_KP_Add: + key_code = isChar ? '+' : WXK_NUMPAD_ADD; + break; + + case GDK_KP_Separator: + // FIXME: what is this? + key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR; + break; + + case GDK_KP_Subtract: + key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT; + break; + + case GDK_KP_Decimal: + key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL; + break; + + case GDK_KP_Divide: + key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE; + break; + + + // function keys + case GDK_F1: + case GDK_F2: + case GDK_F3: + case GDK_F4: + case GDK_F5: + case GDK_F6: + case GDK_F7: + case GDK_F8: + case GDK_F9: + case GDK_F10: + case GDK_F11: + case GDK_F12: + key_code = WXK_F1 + keysym - GDK_F1; + break; + + default: + key_code = 0; } + return key_code; +} - if (!(GTK_WIDGET_APP_PAINTABLE (widget)) && - (pizza->clear_on_draw)) +static inline bool wxIsAsciiKeysym(KeySym ks) +{ + return ks < 256; +} + +static bool +wxTranslateGTKKeyEventToWx(wxKeyEvent& event, + wxWindowGTK *win, + GdkEventKey *gdk_event) +{ + // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string + // but only event->keyval which is quite useless to us, so remember + // the last character from GDK_KEY_PRESS and reuse it as last resort + // + // NB: should be MT-safe as we're always called from the main thread only + static struct { - gdk_window_clear_area( pizza->bin_window, - rect->x, rect->y, rect->width, rect->height); - } + KeySym keysym; + long keycode; + } s_lastKeyPress = { 0, 0 }; - win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); + KeySym keysym = gdk_event->keyval; - win->m_clipPaintRegion = TRUE; + wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %d"), + event.GetEventType() == wxEVT_KEY_UP ? _T("release") + : _T("press"), + keysym); - wxWindowDC dc(win); - dc.SetClippingRegion(win->GetUpdateRegion()); - wxEraseEvent eevent( win->GetId(), &dc ); - eevent.SetEventObject( win ); + long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */); -#if 1 - (void)win->GetEventHandler()->ProcessEvent(eevent); -#else - if (!win->GetEventHandler()->ProcessEvent(eevent)) + if ( !key_code ) { - if (!win->GetEventHandler()->ProcessEvent(eevent)) + // do we have the translation or is it a plain ASCII character? + if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) ) { - wxClientDC dc( win ); - dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) ); - dc.SetPen( *wxTRANSPARENT_PEN ); - - wxRegionIterator upd( win->GetUpdateRegion() ); - while (upd) + // we should use keysym if it is ASCII as X does some translations + // like "I pressed while Control is down" => "Ctrl-I" == "TAB" + // which we don't want here (but which we do use for OnChar()) + if ( !wxIsAsciiKeysym(keysym) ) { - dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() ); - upd ++; + keysym = (KeySym)gdk_event->string[0]; } + + // we want to always get the same key code when the same key is + // pressed regardless of the state of the modifies, i.e. on a + // standard US keyboard pressing '5' or '%' ('5' key with + // Shift) should result in the same key code in OnKeyDown(): + // '5' (although OnChar() will get either '5' or '%'). + // + // to do it we first translate keysym to keycode (== scan code) + // and then back but always using the lower register + Display *dpy = (Display *)wxGetDisplay(); + KeyCode keycode = XKeysymToKeycode(dpy, keysym); + + wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode); + + KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0); + + // use the normalized, i.e. lower register, keysym if we've + // got one + key_code = keysymNormalized ? keysymNormalized : keysym; + + // as explained above, we want to have lower register key codes + // normally but for the letter keys we want to have the upper ones + // + // NB: don't use XConvertCase() here, we want to do it for letters + // only + key_code = toupper(key_code); } - } -#endif + else // non ASCII key, what to do? + { + // by default, ignore it + key_code = 0; - wxNcPaintEvent eventNc( win->GetId() ); - eventNc.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( eventNc ); + // but if we have cached information from the last KEY_PRESS + if ( gdk_event->type == GDK_KEY_RELEASE ) + { + // then reuse it + if ( keysym == s_lastKeyPress.keysym ) + { + key_code = s_lastKeyPress.keycode; + } + } + } - wxPaintEvent event( win->GetId() ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + if ( gdk_event->type == GDK_KEY_PRESS ) + { + // remember it to be reused for KEY_UP event later + s_lastKeyPress.keysym = keysym; + s_lastKeyPress.keycode = key_code; + } + } - win->GetUpdateRegion().Clear(); + wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %d"), key_code); - win->m_clipPaintRegion = FALSE; + // sending unknown key events doesn't really make sense + if ( !key_code ) + return FALSE; + // now fill all the other fields + int x = 0; + int y = 0; + GdkModifierType state; + if (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); - GList *children = pizza->children; - while (children) - { - GtkPizzaChild *child = (GtkPizzaChild*) children->data; - children = children->next; + event.SetTimestamp( gdk_event->time ); + event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0; + event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0; + event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0; + event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0; + event.m_keyCode = key_code; + event.m_scanCode = gdk_event->keyval; + event.m_rawCode = (wxUint32) gdk_event->keyval; + event.m_rawFlags = 0; + event.m_x = x; + event.m_y = y; + event.SetEventObject( win ); - GdkRectangle child_area; - if (gtk_widget_intersect (child->widget, rect, &child_area)) - { - gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ ); - } - } + return TRUE; } -//----------------------------------------------------------------------------- -// "key_press_event" from any window -//----------------------------------------------------------------------------- - static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) @@ -957,40 +1054,19 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, if (g_isIdle) wxapp_install_idle_handler(); - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - - -/* - wxString tmp; - tmp += (char)gdk_event->keyval; - printf( "KeyDown-Code is: %s.\n", tmp.c_str() ); - printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval ); -*/ - - int x = 0; - int y = 0; - GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); - - bool ret = FALSE; - - long key_code = map_to_unmodified_wx_keysym( gdk_event ); - /* sending unknown key events doesn't really make sense */ - if (key_code == 0) return FALSE; + if (!win->m_hasVMT) + return FALSE; + if (g_blockEventsOnDrag) + return FALSE; wxKeyEvent event( wxEVT_KEY_DOWN ); - event.SetTimestamp( gdk_event->time ); - event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event.m_keyCode = key_code; - event.m_scanCode = gdk_event->keyval; - event.m_x = x; - event.m_y = y; - event.SetEventObject( win ); - ret = win->GetEventHandler()->ProcessEvent( event ); + if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) + { + // unknown key pressed, ignore (the event would be useless anyhow) + return FALSE; + } + + bool ret = win->GetEventHandler()->ProcessEvent( event ); #if wxUSE_ACCEL if (!ret) @@ -1012,39 +1088,48 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } #endif // wxUSE_ACCEL - /* wxMSW doesn't send char events with Alt pressed */ /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x will only be sent if it is not in an accelerator table. */ - key_code = map_to_wx_keysym( gdk_event ); + if ( !ret ) + { + KeySym keysym = gdk_event->keyval; + long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */); + if ( !key_code ) + { + if ( gdk_event->length == 1 ) + { + key_code = (unsigned char)gdk_event->string[0]; + } + else if ( wxIsAsciiKeysym(keysym) ) + { + // ASCII key + key_code = (unsigned char)keysym; + } + } - if ( (!ret) && - (key_code != 0)) - { - wxKeyEvent event2( wxEVT_CHAR ); - event2.SetTimestamp( gdk_event->time ); - event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event2.m_keyCode = key_code; - event2.m_scanCode = gdk_event->keyval; - event2.m_x = x; - event2.m_y = y; - event2.SetEventObject( win ); - ret = win->GetEventHandler()->ProcessEvent( event2 ); + if ( key_code ) + { + wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code); + + // reuse the same event object, just change its type and use the + // translated keycode instead of the raw one + event.SetEventType(wxEVT_CHAR); + event.m_keyCode = key_code; + + ret = win->GetEventHandler()->ProcessEvent( event ); + } } /* win is a control: tab can be propagated up */ - if ( (!ret) && + if ( !ret && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may // have this style, yet choose not to process this particular TAB in which // case TAB must still work as a navigational character #if 0 - (!win->HasFlag(wxTE_PROCESS_TAB)) && + !win->HasFlag(wxTE_PROCESS_TAB) && #endif // 0 - (win->GetParent()) && - (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) + win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { wxNavigationKeyEvent new_event; new_event.SetEventObject( win->GetParent() ); @@ -1057,7 +1142,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } /* generate wxID_CANCEL if has been pressed (typically in dialogs) */ - if ( (!ret) && + if ( !ret && (gdk_event->keyval == GDK_Escape) ) { wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); @@ -1065,10 +1150,9 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetEventHandler()->ProcessEvent( new_event ); } -#if (GTK_MINOR_VERSION > 0) - /* Pressing F10 will activate the menu bar of the top frame. */ /* Doesn't work. */ -/* +#if 0 // (GTK_MINOR_VERSION > 0) + /* Pressing F10 will activate the menu bar of the top frame. */ if ( (!ret) && (gdk_event->keyval == GDK_F10) ) { @@ -1094,8 +1178,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ancestor = ancestor->GetParent(); } } -*/ -#endif +#endif // 0 if (ret) { @@ -1110,60 +1193,56 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, // "key_release_event" from any window //----------------------------------------------------------------------------- -static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win ) +static gint gtk_window_key_release_callback( GtkWidget *widget, + GdkEventKey *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; - -/* - printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval ); - if (gdk_event->state & GDK_SHIFT_MASK) - printf( "ShiftDown.\n" ); - else - printf( "ShiftUp.\n" ); - if (gdk_event->state & GDK_CONTROL_MASK) - printf( "ControlDown.\n" ); - else - printf( "ControlUp.\n" ); - printf( "\n" ); -*/ - - long key_code = map_to_unmodified_wx_keysym( gdk_event ); - - /* sending unknown key events doesn't really make sense */ - if (key_code == 0) return FALSE; + if (!win->m_hasVMT) + return FALSE; - int x = 0; - int y = 0; - GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); + if (g_blockEventsOnDrag) + return FALSE; wxKeyEvent event( wxEVT_KEY_UP ); - event.SetTimestamp( gdk_event->time ); - event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event.m_keyCode = key_code; - event.m_scanCode = gdk_event->keyval; - event.m_x = x; - event.m_y = y; - event.SetEventObject( win ); - - if (win->GetEventHandler()->ProcessEvent( event )) + if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" ); - return TRUE; + // unknown key pressed, ignore (the event would be useless anyhow + return FALSE; } - return FALSE; + if ( !win->GetEventHandler()->ProcessEvent( event ) ) + return FALSE; + + gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" ); + return TRUE; } +// ============================================================================ +// the mouse events +// ============================================================================ + +// init wxMouseEvent with the info from gdk_event +#define InitMouseEvent(win, event, gdk_event) \ + { \ + event.SetTimestamp( gdk_event->time ); \ + event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \ + event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \ + event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \ + event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \ + event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \ + event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \ + event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \ +\ + wxPoint pt = win->GetClientAreaOrigin(); \ + event.m_x = (wxCoord)gdk_event->x - pt.x; \ + event.m_y = (wxCoord)gdk_event->y - pt.y; \ + } + // ---------------------------------------------------------------------------- // mouse event processing helper // ---------------------------------------------------------------------------- @@ -1223,20 +1302,15 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - if (win->m_wxwindow) + if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus()) { - if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) ) - { - gtk_widget_grab_focus (win->m_wxwindow); - + gtk_widget_grab_focus( win->m_wxwindow ); /* - wxPrintf( wxT("GrabFocus from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); + wxPrintf( wxT("GrabFocus from ") ); + if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) + wxPrintf( win->GetClassInfo()->GetClassName() ); + wxPrintf( wxT(".\n") ); */ - - } } wxEventType event_type = wxEVT_NULL; @@ -1276,20 +1350,18 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton } wxMouseEvent event( event_type ); - event.SetTimestamp( gdk_event->time ); - event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); - event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); - event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); - - event.m_x = (wxCoord)gdk_event->x; - event.m_y = (wxCoord)gdk_event->y; + InitMouseEvent( win, event, gdk_event ); AdjustEventButtonState(event); + // wxListBox actually get mouse events from the item + + if (win->m_isListBox) + { + event.m_x += widget->allocation.x; + event.m_y += widget->allocation.y; + } + // Some control don't have their own X window and thus cannot get // any events. @@ -1409,19 +1481,18 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto } wxMouseEvent event( event_type ); - event.SetTimestamp( gdk_event->time ); - event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); - event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); - event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); - event.m_x = (wxCoord)gdk_event->x; - event.m_y = (wxCoord)gdk_event->y; + InitMouseEvent( win, event, gdk_event ); AdjustEventButtonState(event); + // wxListBox actually get mouse events from the item + + if (win->m_isListBox) + { + event.m_x += widget->allocation.x; + event.m_y += widget->allocation.y; + } + // Some control don't have their own X window and thus cannot get // any events. @@ -1497,24 +1568,6 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto return FALSE; } -// ============================================================================ -// the mouse events -// ============================================================================ - -// init wxMouseEvent with the info from gdk_event -#define InitMouseEvent(event, gdk_event) \ - event.SetTimestamp( gdk_event->time ); \ - event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \ - event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \ - event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \ - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \ - event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \ - event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \ - event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \ -\ - event.m_x = (wxCoord)gdk_event->x; \ - event.m_y = (wxCoord)gdk_event->y \ - //----------------------------------------------------------------------------- // "motion_notify_event" //----------------------------------------------------------------------------- @@ -1552,7 +1605,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, */ wxMouseEvent event( wxEVT_MOTION ); - InitMouseEvent(event, gdk_event); + InitMouseEvent(win, event, gdk_event); if ( g_captureWindow ) { @@ -1566,7 +1619,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW : wxEVT_LEAVE_WINDOW); - InitMouseEvent(event, gdk_event); + InitMouseEvent(win, event, gdk_event); event.SetEventObject(win); win->GetEventHandler()->ProcessEvent(event); } @@ -1650,6 +1703,21 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, // "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); +} + static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win ) @@ -1665,7 +1733,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, switch ( g_sendActivateEvent ) { case -1: - // we've got focus from outside, synthtize wxActivateEvent + // we've got focus from outside, synthetize wxActivateEvent g_sendActivateEvent = 1; break; @@ -1679,20 +1747,9 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, g_focusWindowLast = g_focusWindow = win; -/* - printf( "OnSetFocus from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - printf( win->GetClassInfo()->GetClassName() ); - printf( " " ); - printf( WXSTRINGCAST win->GetLabel() ); - printf( ".\n" ); -*/ - - wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel); - if (panel) - { - panel->SetLastFocus(win); - } +#if 0 + printf( "OnSetFocus 2 from %s\n", win->GetName().c_str() ); +#endif #ifdef HAVE_XIM if (win->m_ic) @@ -1708,25 +1765,36 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, } #endif // wxUSE_CARET - if (win->IsTopLevel()) + g_activeFrameLostFocus = FALSE; + + wxWindowGTK *active = wxGetTopLevelParent(win); + if ( active != g_activeFrame ) { - wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() ); - event.SetEventObject( win ); + if ( g_activeFrame ) + { + wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame); + wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId()); + event.SetEventObject(g_activeFrame); + g_activeFrame->GetEventHandler()->ProcessEvent(event); + } - // ignore return value - win->GetEventHandler()->ProcessEvent( event ); + wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active); + g_activeFrame = active; + wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId()); + event.SetEventObject(g_activeFrame); + g_activeFrame->GetEventHandler()->ProcessEvent(event); + + // Don't send focus events in addition to activate + // if (win == g_activeFrame) + // return TRUE; } - wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() ); - event.SetEventObject( win ); - - if (win->GetEventHandler()->ProcessEvent( event )) + if ( DoSendFocusEvents(win) ) { gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); return TRUE; } - return FALSE; } @@ -1734,7 +1802,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, // "focus_out_event" //----------------------------------------------------------------------------- -static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win ) +static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1744,6 +1812,23 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; +#if 0 + wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() ); +#endif + + if ( !g_activeFrameLostFocus && g_activeFrame ) + { + // VZ: commenting this out because it does happen (although not easy + // to reproduce, I only see it when using wxMiniFrame and not + // always) and makes using Mahogany quite annoying +#if 0 + wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, + wxT("unfocusing window that hasn't gained focus properly") ) +#endif // 0 + + g_activeFrameLostFocus = TRUE; + } + // if the focus goes out of our app alltogether, OnIdle() will send // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset // g_sendActivateEvent to -1 @@ -1755,13 +1840,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED g_focusWindow = (wxWindowGTK *)NULL; -/* - printf( "OnKillFocus from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - printf( win->GetClassInfo()->GetClassName() ); - printf( ".\n" ); -*/ - #ifdef HAVE_XIM if (win->m_ic) gdk_im_end(); @@ -1776,15 +1854,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED } #endif // wxUSE_CARET - if (win->IsTopLevel()) - { - wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() ); - event.SetEventObject( win ); - - // ignore return value - win->GetEventHandler()->ProcessEvent( event ); - } - wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); event.SetEventObject( win ); @@ -1814,9 +1883,7 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; wxMouseEvent event( wxEVT_ENTER_WINDOW ); -#if (GTK_MINOR_VERSION > 0) event.SetTimestamp( gdk_event->time ); -#endif event.SetEventObject( win ); int x = 0; @@ -1825,10 +1892,10 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_ gdk_window_get_pointer( widget->window, &x, &y, &state ); - InitMouseEvent(event, gdk_event); - - event.m_x = x; - event.m_y = y; + InitMouseEvent(win, event, gdk_event); + wxPoint pt = win->GetClientAreaOrigin(); + event.m_x = x + pt.x; + event.m_y = y + pt.y; if (win->GetEventHandler()->ProcessEvent( event )) { @@ -1856,9 +1923,7 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; wxMouseEvent event( wxEVT_LEAVE_WINDOW ); -#if (GTK_MINOR_VERSION > 0) event.SetTimestamp( gdk_event->time ); -#endif event.SetEventObject( win ); int x = 0; @@ -1867,16 +1932,17 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ gdk_window_get_pointer( widget->window, &x, &y, &state ); - event.m_shiftDown = (state & GDK_SHIFT_MASK); - event.m_controlDown = (state & GDK_CONTROL_MASK); - event.m_altDown = (state & GDK_MOD1_MASK); - event.m_metaDown = (state & GDK_MOD2_MASK); - event.m_leftDown = (state & GDK_BUTTON1_MASK); - event.m_middleDown = (state & GDK_BUTTON2_MASK); - event.m_rightDown = (state & GDK_BUTTON3_MASK); + event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0; + event.m_controlDown = (state & GDK_CONTROL_MASK) != 0; + event.m_altDown = (state & GDK_MOD1_MASK) != 0; + event.m_metaDown = (state & GDK_MOD2_MASK) != 0; + event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0; + event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0; + event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0; - event.m_x = x; - event.m_y = y; + wxPoint pt = win->GetClientAreaOrigin(); + event.m_x = x + pt.x; + event.m_y = y + pt.y; if (win->GetEventHandler()->ProcessEvent( event )) { @@ -1891,7 +1957,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ // "value_changed" from m_vAdjust //----------------------------------------------------------------------------- -static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win ) +static void gtk_window_vscroll_callback( GtkAdjustment *adjust, + SCROLLBAR_CBACK_ARG + wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1907,14 +1975,8 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win win->m_oldVerticalPos = adjust->value; - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); - GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar ); - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; - else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; - else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; - else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); + wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar)); int value = (int)(adjust->value+0.5); @@ -1927,7 +1989,9 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win // "value_changed" from m_hAdjust //----------------------------------------------------------------------------- -static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win ) +static void gtk_window_hscroll_callback( GtkAdjustment *adjust, + SCROLLBAR_CBACK_ARG + wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1940,16 +2004,10 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win float diff = adjust->value - win->m_oldHorizontalPos; if (fabs(diff) < 0.2) return; - win->m_oldHorizontalPos = adjust->value; - - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); - GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar ); + GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); + wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar)); - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; - else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; - else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; - else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + win->m_oldHorizontalPos = adjust->value; int value = (int)(adjust->value+0.5); @@ -1973,7 +2031,11 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *widget, 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 return FALSE; } @@ -2050,10 +2112,10 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win ) wxapp_install_idle_handler(); if (win->m_delayedBackgroundColour) - win->SetBackgroundColour( win->GetBackgroundColour() ); + win->GtkSetBackgroundColour( win->GetBackgroundColour() ); if (win->m_delayedForegroundColour) - win->SetForegroundColour( win->GetForegroundColour() ); + win->GtkSetForegroundColour( win->GetForegroundColour() ); wxWindowCreateEvent event( win ); event.SetEventObject( win ); @@ -2276,6 +2338,7 @@ void wxWindowGTK::Init() // GTK specific m_widget = (GtkWidget *) NULL; m_wxwindow = (GtkWidget *) NULL; + m_focusWidget = (GtkWidget *) NULL; // position/size m_x = 0; @@ -2306,6 +2369,7 @@ void wxWindowGTK::Init() m_isStaticBox = FALSE; m_isRadioButton = FALSE; + m_isListBox = FALSE; m_isFrame = FALSE; m_acceptsFocus = FALSE; @@ -2354,6 +2418,9 @@ bool wxWindowGTK::Create( wxWindow *parent, } m_insertCallback = wxInsertChildInWindow; + + // always needed for background clearing + m_delayedBackgroundColour = TRUE; m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL ); GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS ); @@ -2370,10 +2437,7 @@ bool wxWindowGTK::Create( wxWindow *parent, m_wxwindow = gtk_pizza_new(); - gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow ); - #ifndef __WXUNIVERSAL__ -#if (GTK_MINOR_VERSION > 0) GtkPizza *pizza = GTK_PIZZA(m_wxwindow); if (HasFlag(wxRAISED_BORDER)) @@ -2392,33 +2456,13 @@ bool wxWindowGTK::Create( wxWindow *parent, { gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE ); } -#else // GTK_MINOR_VERSION == 0 - GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport); - - if (HasFlag(wxRAISED_BORDER)) - { - gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT ); - } - else if (HasFlag(wxSUNKEN_BORDER)) - { - gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN ); - } - else - { - gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE ); - } -#endif // GTK_MINOR_VERSION #endif // __WXUNIVERSAL__ + gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow ); + GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS ); m_acceptsFocus = TRUE; -#if (GTK_MINOR_VERSION == 0) - // shut the viewport up - gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ); - gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ); -#endif // GTK_MINOR_VERSION == 0 - // I _really_ don't want scrollbars in the beginning m_vAdjust->lower = 0.0; m_vAdjust->upper = 1.0; @@ -2465,6 +2509,8 @@ bool wxWindowGTK::Create( wxWindow *parent, if (m_parent) m_parent->DoAddChild( this ); + m_focusWidget = m_wxwindow; + PostCreation(); Show( TRUE ); @@ -2477,6 +2523,12 @@ wxWindowGTK::~wxWindowGTK() if (g_focusWindow == this) g_focusWindow = NULL; + if (g_activeFrame == this) + g_activeFrame = NULL; + + if ( g_delayedFocus == this ) + g_delayedFocus = NULL; + m_isBeingDeleted = TRUE; m_hasVMT = FALSE; @@ -2558,13 +2610,14 @@ void wxWindowGTK::PostCreation() { if (!m_noExpose) { - /* these get reported to wxWindows -> wxPaintEvent */ + // these get reported to wxWindows -> wxPaintEvent 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 ); @@ -2573,37 +2626,33 @@ void wxWindowGTK::PostCreation() 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( wxNO_FULL_REPAINT_ON_RESIZE ) ); +#endif } -#if (GTK_MINOR_VERSION > 0) - /* these are called when the "sunken" or "raised" borders are drawn */ + // 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 } - if (m_wxwindow && m_needParent) - { - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event", - GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); + // focus handling - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event", - GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this ); - } - else - { - // For dialogs and frames, we are interested mainly in - // m_widget's focus. + if (m_focusWidget == NULL) + m_focusWidget = m_widget; - gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event", - GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); + gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event", + GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); - gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event", - GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this ); - } + gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event", + GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this ); + + // connect to the various key and mouse handlers GtkWidget *connect_widget = GetConnectWidget(); @@ -2693,6 +2742,14 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags if (m_resizing) return; /* I don't like recursions */ m_resizing = TRUE; + int currentX, currentY; + GetPosition(¤tX, ¤tY); + if (x == -1) + x = currentX; + if (y == -1) + y = currentY; + AdjustForParentClientOrigin(x, y, sizeFlags); + if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */ { /* don't set the size for children of wxNotebook, just take the values. */ @@ -2704,7 +2761,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags else { GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow); - if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0) { if (x != -1) m_x = x + pizza->xoffset; @@ -2730,20 +2786,27 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags if (height == -1) m_height = 26; } - if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth; - if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight; - if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth; - if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight; + 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 border = 0; int bottom_border = 0; +#ifndef __WXGTK20__ if (GTK_WIDGET_CAN_DEFAULT(m_widget)) { /* the default button has a border around it */ border = 6; bottom_border = 5; } +#endif DoMoveWindow( m_x-border, m_y-border, @@ -2781,6 +2844,10 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags void wxWindowGTK::OnInternalIdle() { + // Update invalidated regions. + GtkUpdate(); + + // Synthetize activate events. if ( g_sendActivateEvent != -1 ) { bool activate = g_sendActivateEvent != 0; @@ -2789,13 +2856,21 @@ void wxWindowGTK::OnInternalIdle() g_sendActivateEvent = -1; wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast); - - wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId()); - event.SetEventObject(this); - - (void)GetEventHandler()->ProcessEvent(event); } + if ( g_activeFrameLostFocus ) + { + if ( g_activeFrame ) + { + wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame); + wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId()); + event.SetEventObject(g_activeFrame); + g_activeFrame->GetEventHandler()->ProcessEvent(event); + g_activeFrame = NULL; + } + g_activeFrameLostFocus = FALSE; + } + wxCursor cursor = m_cursor; if (g_globalCursor.Ok()) cursor = g_globalCursor; @@ -3153,25 +3228,42 @@ void wxWindowGTK::SetFocus() if (m_wxwindow) { if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow)) + { gtk_widget_grab_focus (m_wxwindow); - return; + } } - - if (m_widget) + else if (m_widget) { if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) ) { - gtk_widget_grab_focus (m_widget); + if (!GTK_WIDGET_REALIZED(m_widget)) + { + wxLogTrace(_T("focus"), + _T("Delaying setting focus to %s(%s)\n"), + GetClassInfo()->GetClassName(), GetLabel().c_str()); + + g_delayedFocus = this; + } + else + { + wxLogTrace(_T("focus"), + _T("Setting focus to %s(%s)\n"), + GetClassInfo()->GetClassName(), GetLabel().c_str()); + + gtk_widget_grab_focus (m_widget); + } } else if (GTK_IS_CONTAINER(m_widget)) { - gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD ); + SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD ); } else { // ? } } + + (void)DoSendFocusEvents((wxWindow*)this); } bool wxWindowGTK::AcceptsFocus() const @@ -3268,8 +3360,8 @@ void wxWindowGTK::WarpPointer( int x, int y ) { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); - /* we provide this function ourselves as it is - missing in GDK (top of this file) */ + // We provide this function ourselves as it is + // missing in GDK (top of this file). GdkWindow *window = (GdkWindow*) NULL; if (m_wxwindow) @@ -3286,107 +3378,234 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) if (!m_widget) return; if (!m_widget->window) return; - // temporarily hide the caret to avoid nasty interactions between caret - // drawing and the window contents redraw -#if 0 // def wxUSE_CARET -- doesn't seem to help :-( - wxCaretSuspend cs((wxWindow *)this); -#endif // wxUSE_CARET - +#ifndef __WXGTK20__ + if (g_isIdle) + wxapp_install_idle_handler(); + if (eraseBackground && m_wxwindow && m_wxwindow->window) { if (rect) { - gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window, - rect->x, rect->y, - rect->width, rect->height ); + // Schedule for later Updating in ::Update() or ::OnInternalIdle(). + m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height ); } else { - gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window ); + // Schedule for later Updating in ::Update() or ::OnInternalIdle(). + m_clearRegion.Clear(); + m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height ); } } - /* there is no GTK equivalent of "draw only, don't clear" so we - invent our own in the GtkPizza widget */ - - if (!rect) + if (rect) { if (m_wxwindow) { - -/* - GtkPizza *pizza = GTK_PIZZA(m_wxwindow); - gboolean old_clear = pizza->clear_on_draw; - gtk_pizza_set_clear( pizza, FALSE ); - gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL ); - gtk_pizza_set_clear( pizza, old_clear ); -*/ - GdkEventExpose gdk_event; - gdk_event.type = GDK_EXPOSE; - gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window; - gdk_event.count = 0; - gdk_event.area.x = 0; - gdk_event.area.y = 0; - gdk_event.area.width = m_wxwindow->allocation.width; - gdk_event.area.height = m_wxwindow->allocation.height; - gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this ); + // Schedule for later Updating in ::Update() or ::OnInternalIdle(). + m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height ); } else { - gtk_widget_draw( m_widget, (GdkRectangle*) NULL ); + 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) { -/* - GtkPizza *pizza = GTK_PIZZA(m_wxwindow); - gboolean old_clear = pizza->clear_on_draw; - gtk_pizza_set_clear( pizza, FALSE ); - + // Schedule for later Updating in ::Update() or ::OnInternalIdle(). + 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 + if (m_wxwindow) + { + if (rect) + { 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_wxwindow, &gdk_rect ); - gtk_window_draw_callback( m_wxwindow, &gdk_rect, this ); + gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE ); + } + else + { + gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE ); + } + } +#endif +} + +void wxWindowGTK::Update() +{ + GtkUpdate(); +} + +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 ); +#endif + + if (!m_updateRegion.IsEmpty()) + GtkSendPaintEvents(); +} + +void wxWindowGTK::GtkSendPaintEvents() +{ + if (!m_wxwindow) + { + m_clearRegion.Clear(); + m_updateRegion.Clear(); + return; + } + + // widget to draw on + GtkPizza *pizza = GTK_PIZZA (m_wxwindow); + + // Clip to paint region in wxClientDC + m_clipPaintRegion = TRUE; + + if (GetThemeEnabled()) + { + // find ancestor from which to steal background + wxWindow *parent = GetParent(); + while (parent && !parent->IsTopLevel()) + parent = parent->GetParent(); + if (!parent) + parent = (wxWindow*)this; + + wxRegionIterator upd( m_updateRegion ); + while (upd) + { + GdkRectangle rect; + rect.x = upd.GetX(); + rect.y = upd.GetY(); + rect.width = upd.GetWidth(); + rect.height = upd.GetHeight(); + + 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 ); + + upd ++; + } + } + else + // if (!m_clearRegion.IsEmpty()) // always send an erase event + { + wxWindowDC dc( (wxWindow*)this ); + dc.SetClippingRegion( m_clearRegion ); + + wxEraseEvent erase_event( GetId(), &dc ); + erase_event.SetEventObject( this ); + + if (!GetEventHandler()->ProcessEvent(erase_event)) + { + 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, m_backgroundColour.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(); + } + + wxNcPaintEvent nc_paint_event( GetId() ); + nc_paint_event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( nc_paint_event ); + + wxPaintEvent paint_event( GetId() ); + paint_event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( paint_event ); + + m_clipPaintRegion = FALSE; + +#ifndef __WXUNIVERSAL__ +#ifndef __WXGTK20__ + // The following code will result in all window-less widgets + // being redrawn because the wxWindows 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 ); - gtk_pizza_set_clear( pizza, old_clear ); -*/ GdkEventExpose gdk_event; gdk_event.type = GDK_EXPOSE; - gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window; + gdk_event.window = pizza->bin_window; gdk_event.count = 0; - gdk_event.area.x = rect->x; - gdk_event.area.y = rect->y; - gdk_event.area.width = rect->width; - gdk_event.area.height = rect->height; - gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this ); - } - 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 ); + + 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); + } + + upd ++; + } } } +#endif +#endif + + m_updateRegion.Clear(); } void wxWindowGTK::Clear() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - if (!m_widget->window) return; - if (m_wxwindow && m_wxwindow->window) { -// gdk_window_clear( m_wxwindow->window ); + m_clearRegion.Clear(); + wxSize size( GetClientSize() ); + m_clearRegion.Union( 0,0,size.x,size.y ); + + // Better do this in idle? + GtkUpdate(); } } @@ -3405,16 +3624,34 @@ void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip ) } #endif // wxUSE_TOOLTIPS +void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour ) +{ + GdkWindow *window = (GdkWindow*) NULL; + if (m_wxwindow) + window = GTK_PIZZA(m_wxwindow)->bin_window; + else + window = GetConnectWidget()->window; + + wxASSERT( window ); + + // We need the pixel value e.g. for background clearing. + m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) ); + + if (m_wxwindow) + { + // wxMSW doesn't clear the window here, either. + gdk_window_set_background( window, m_backgroundColour.GetColor() ); + } + + ApplyWidgetStyle(); +} + bool wxWindowGTK::SetBackgroundColour( const wxColour &colour ) { wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") ); if (!wxWindowBase::SetBackgroundColour(colour)) - { - // don't leave if the GTK widget has just - // been realized - if (!m_delayedBackgroundColour) return FALSE; - } + return FALSE; GdkWindow *window = (GdkWindow*) NULL; if (m_wxwindow) @@ -3428,24 +3665,29 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour ) // but it couldn't get applied as the // widget hasn't been realized yet. m_delayedBackgroundColour = TRUE; + return TRUE; } - - if ((m_wxwindow) && - (m_wxwindow->window) && - (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))) + else { - /* wxMSW doesn't clear the window here. I don't do that either to - provide compatibility. call Clear() to do the job. */ - - m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) ); - gdk_window_set_background( window, m_backgroundColour.GetColor() ); + GtkSetBackgroundColour( colour ); } - ApplyWidgetStyle(); - return TRUE; } +void wxWindowGTK::GtkSetForegroundColour( const wxColour &colour ) +{ + GdkWindow *window = (GdkWindow*) NULL; + if (m_wxwindow) + window = GTK_PIZZA(m_wxwindow)->bin_window; + else + window = GetConnectWidget()->window; + + wxASSERT( window ); + + ApplyWidgetStyle(); +} + bool wxWindowGTK::SetForegroundColour( const wxColour &colour ) { wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") ); @@ -3470,8 +3712,10 @@ bool wxWindowGTK::SetForegroundColour( const wxColour &colour ) // widget hasn't been realized yet. m_delayedForegroundColour = TRUE; } - - ApplyWidgetStyle(); + else + { + GtkSetForegroundColour( colour ); + } return TRUE; } @@ -3481,10 +3725,9 @@ GtkStyle *wxWindowGTK::GetWidgetStyle() if (m_widgetStyle) { GtkStyle *remake = gtk_style_copy( m_widgetStyle ); -#ifdef __WXGTK20__ - /* FIXME: is this necessary? */ - _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass); -#else + + // FIXME: no more klass in 2.0 +#ifndef __WXGTK20__ remake->klass = m_widgetStyle->klass; #endif @@ -3499,10 +3742,9 @@ GtkStyle *wxWindowGTK::GetWidgetStyle() def = gtk_widget_get_default_style(); m_widgetStyle = gtk_style_copy( def ); -#ifdef __WXGTK20__ - /* FIXME: is this necessary? */ - _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass); -#else + + // FIXME: no more klass in 2.0 +#ifndef __WXGTK20__ m_widgetStyle->klass = def->klass; #endif } @@ -3512,7 +3754,7 @@ GtkStyle *wxWindowGTK::GetWidgetStyle() void wxWindowGTK::SetWidgetStyle() { -#if DISABLE_STYLE_IF_BROKEN_THEM +#if DISABLE_STYLE_IF_BROKEN_THEME if (m_widget->style->engine_data) { static bool s_warningPrinted = FALSE; @@ -3528,16 +3770,15 @@ void wxWindowGTK::SetWidgetStyle() GtkStyle *style = GetWidgetStyle(); - if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT )) + if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT )) { - gdk_font_unref( style->font ); - style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) ); + SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 )); } if (m_foregroundColour.Ok()) { m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) ); - if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT)) + if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT)) { style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor(); style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor(); @@ -3563,7 +3804,7 @@ void wxWindowGTK::SetWidgetStyle() if (m_backgroundColour.Ok()) { m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) ); - if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)) + if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)) { style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor(); style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor(); @@ -3609,7 +3850,8 @@ void wxWindowGTK::ApplyWidgetStyle() #if wxUSE_MENUS_NATIVE -static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting ) +extern "C" +void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting ) { *is_waiting = FALSE; } @@ -3630,16 +3872,32 @@ static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win ) } } +// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to +// wxPopupMenuPositionCallback() +// +// should be safe even in the MT case as the user can hardly popup 2 menus +// simultaneously, can he? static gint gs_pop_x = 0; static gint gs_pop_y = 0; -static void pop_pos_callback( GtkMenu * WXUNUSED(menu), - gint *x, gint *y, - wxWindowGTK *win ) +extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu, + gint *x, gint *y, +#ifdef __WXGTK20__ + gboolean * WXUNUSED(whatever), +#endif + gpointer WXUNUSED(user_data) ) { - win->ClientToScreen( &gs_pop_x, &gs_pop_y ); - *x = gs_pop_x; - *y = gs_pop_y; + // ensure that the menu appears entirely on screen + GtkRequisition req; + gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req); + + wxSize sizeScreen = wxGetDisplaySize(); + + gint xmax = sizeScreen.x - req.width, + ymax = sizeScreen.y - req.height; + + *x = gs_pop_x < xmax ? gs_pop_x : xmax; + *y = gs_pop_y < ymax ? gs_pop_y : ymax; } bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y ) @@ -3654,20 +3912,23 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y ) gs_pop_x = x; gs_pop_y = y; + ClientToScreen( &gs_pop_x, &gs_pop_y ); bool is_waiting = TRUE; - gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide", - GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting ); + gtk_signal_connect( GTK_OBJECT(menu->m_menu), + "hide", + GTK_SIGNAL_FUNC(gtk_pop_hide_callback), + (gpointer)&is_waiting ); gtk_menu_popup( GTK_MENU(menu->m_menu), - (GtkWidget *) NULL, // parent menu shell - (GtkWidget *) NULL, // parent menu item - (GtkMenuPositionFunc) pop_pos_callback, - (gpointer) this, // client data - 0, // button used to activate it - gs_timeLastClick // the time of activation + (GtkWidget *) NULL, // parent menu shell + (GtkWidget *) NULL, // parent menu item + wxPopupMenuPositionCallback, // function to position it + NULL, // client data + 0, // button used to activate it + gs_timeLastClick // the time of activation ); while (is_waiting) @@ -3724,7 +3985,7 @@ bool wxWindowGTK::SetFont( const wxFont &font ) return FALSE; } - wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ); + wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ); if ( sysbg == m_backgroundColour ) { m_backgroundColour = wxNullColour; @@ -3739,19 +4000,17 @@ bool wxWindowGTK::SetFont( const wxFont &font ) return TRUE; } -void wxWindowGTK::CaptureMouse() +void wxWindowGTK::DoCaptureMouse() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") ); - GdkWindow *window = (GdkWindow*) NULL; if (m_wxwindow) window = GTK_PIZZA(m_wxwindow)->bin_window; else window = GetConnectWidget()->window; - if (!window) return; + wxCHECK_RET( window, _T("CaptureMouse() failed") ); wxCursor* cursor = & m_cursor; if (!cursor->Ok()) @@ -3770,11 +4029,13 @@ void wxWindowGTK::CaptureMouse() g_captureWindowHasMouse = TRUE; } -void wxWindowGTK::ReleaseMouse() +void wxWindowGTK::DoReleaseMouse() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") ); + wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") ); + + g_captureWindow = (wxWindowGTK*) NULL; GdkWindow *window = (GdkWindow*) NULL; if (m_wxwindow) @@ -3786,7 +4047,6 @@ void wxWindowGTK::ReleaseMouse() return; gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME ); - g_captureWindow = (wxWindowGTK*) NULL; } /* static */ @@ -3958,65 +4218,47 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); + // No scrolling requested. if ((dx == 0) && (dy == 0)) return; - m_clipPaintRegion = TRUE; - gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); - m_clipPaintRegion = FALSE; - -/* - if (m_children.GetCount() > 0) - { - gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); - } - else +#ifndef __WXGTK20__ + if (!m_updateRegion.IsEmpty()) { - GtkPizza *pizza = GTK_PIZZA(m_wxwindow); + m_updateRegion.Offset( dx, dy ); - pizza->xoffset -= dx; - pizza->yoffset -= dy; + int cw = 0; + int ch = 0; + GetClientSize( &cw, &ch ); + m_updateRegion.Intersect( 0, 0, cw, ch ); + } - GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window ); - gdk_gc_set_exposures( m_scrollGC, TRUE ); + if (!m_clearRegion.IsEmpty()) + { + m_clearRegion.Offset( dx, dy ); int cw = 0; int ch = 0; GetClientSize( &cw, &ch ); - int w = cw - abs(dx); - int h = ch - abs(dy); + m_clearRegion.Intersect( 0, 0, cw, ch ); + } - if ((h < 0) || (w < 0)) - { - Refresh(); - } - else - { - int s_x = 0; - int s_y = 0; - if (dx < 0) s_x = -dx; - if (dy < 0) s_y = -dy; - int d_x = 0; - int d_y = 0; - if (dx > 0) d_x = dx; - if (dy > 0) d_y = dy; + m_clipPaintRegion = TRUE; + + gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); - gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y, - pizza->bin_window, s_x, s_y, w, h ); + m_clipPaintRegion = FALSE; +#else - wxRect rect; - if (dx < 0) rect.x = cw+dx; else rect.x = 0; - if (dy < 0) rect.y = ch+dy; else rect.y = 0; - if (dy != 0) rect.width = cw; else rect.width = abs(dx); - if (dx != 0) rect.height = ch; else rect.height = abs(dy); + gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, dx, dy ); - Refresh( TRUE, &rect ); - } + GTK_PIZZA(m_wxwindow)->xoffset += dx; + GTK_PIZZA(m_wxwindow)->yoffset += dy; + +#endif - gdk_gc_unref( m_scrollGC ); - } -*/ } + // Find the wxWindow at the current mouse position, also returning the mouse // position. wxWindow* wxFindWindowAtPointer(wxPoint& pt) @@ -4058,3 +4300,34 @@ wxPoint wxGetMousePosition() } +// ---------------------------------------------------------------------------- +// wxDCModule +// ---------------------------------------------------------------------------- + +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_ROOT_PARENT() ); + // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); + + return TRUE; +} + +void wxWinModule::OnExit() +{ + if (g_eraseGC) + gdk_gc_unref( g_eraseGC ); +} + +// vi:sts=4:sw=4:et