X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d7fa7eaa2dc8ef4154ac4d9d739bcfb6be1669ac..94a6f0f8d654d41867e85447432db5b88c1fd445:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index efc124ac8d..d3dac9b822 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -270,47 +270,13 @@ 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 +// the trace mask used for the focus debugging messages +#define TRACE_FOCUS _T("focus") + //----------------------------------------------------------------------------- // missing gdk functions //----------------------------------------------------------------------------- @@ -385,15 +351,6 @@ wxWindow *wxFindFocusedChild(wxWindowGTK *win) return (wxWindow *)NULL; } -// Returns toplevel grandparent of given window: -static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win) -{ - wxWindowGTK *p = win; - while (p && !p->IsTopLevel()) - p = p->GetParent(); - return p; -} - static void draw_frame( GtkWidget *widget, wxWindowGTK *win ) { // wxUniversal widgets draw the borders and scrollbars themselves @@ -551,35 +508,17 @@ static int gtk_window_expose_callback( GtkWidget *widget, } #endif -#ifndef __WXUNIVERSAL__ - 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, - (char *)"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 ); + win->m_clearRegion.Union( gdk_event->area.x, + gdk_event->area.y, + gdk_event->area.width, + gdk_event->area.height ); // Actual redrawing takes place in idle time. - win->Update(); + // win->GtkUpdate(); #ifdef __WXGTK20__ @@ -672,21 +611,13 @@ static void gtk_window_draw_callback( GtkWidget *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->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height ); win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); - // Actual redrawing takes place in idle time. - - win->Update(); + // Update immediately, not in idle time. + win->GtkUpdate(); #ifndef __WXUNIVERSAL__ // Redraw child widgets @@ -1014,7 +945,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event, KeySym keysym = gdk_event->keyval; - wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %d"), + wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"), event.GetEventType() == wxEVT_KEY_UP ? _T("release") : _T("press"), keysym); @@ -1084,7 +1015,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event, } } - wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %d"), key_code); + wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code); // sending unknown key events doesn't really make sense if ( !key_code ) @@ -1127,6 +1058,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, if (g_blockEventsOnDrag) return FALSE; + wxKeyEvent event( wxEVT_KEY_DOWN ); if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) { @@ -1134,6 +1066,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, return FALSE; } + // Emit KEY_DOWN event bool ret = win->GetEventHandler()->ProcessEvent( event ); #if wxUSE_ACCEL @@ -1156,10 +1089,11 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } #endif // wxUSE_ACCEL - /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x - will only be sent if it is not in an accelerator table. */ - if ( !ret ) + // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x + // will only be sent if it is not in an accelerator table. + if (!ret) { + // Find key code for EVT_CHAR and EVT_CHAR_HOOK events KeySym keysym = gdk_event->keyval; long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */); if ( !key_code ) @@ -1179,16 +1113,27 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, { 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; + + // Implement OnCharHook by checking ancesteror top level windows + wxWindow *parent = win; + while (parent && !parent->IsTopLevel()) + parent = parent->GetParent(); + if (parent) + { + event.SetEventType( wxEVT_CHAR_HOOK ); + ret = parent->GetEventHandler()->ProcessEvent( event ); + } - ret = win->GetEventHandler()->ProcessEvent( event ); + if (!ret) + { + event.SetEventType(wxEVT_CHAR); + ret = win->GetEventHandler()->ProcessEvent( event ); + } } } - /* win is a control: tab can be propagated up */ + // win is a control: tab can be propagated up 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 @@ -1201,15 +1146,15 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, { wxNavigationKeyEvent new_event; new_event.SetEventObject( win->GetParent() ); - /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ + // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB new_event.SetDirection( (gdk_event->keyval == GDK_Tab) ); - /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ + // CTRL-TAB changes the (parent) window, i.e. switch notebook page new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) ); new_event.SetCurrentFocus( win ); ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); } - /* generate wxID_CANCEL if has been pressed (typically in dialogs) */ + // generate wxID_CANCEL if has been pressed (typically in dialogs) if ( !ret && (gdk_event->keyval == GDK_Escape) ) { @@ -1218,9 +1163,9 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetEventHandler()->ProcessEvent( new_event ); } - /* Doesn't work. */ -#if 0 // (GTK_MINOR_VERSION > 0) - /* Pressing F10 will activate the menu bar of the top frame. */ + // Doesn't work. +#if 0 + // Pressing F10 will activate the menu bar of the top frame if ( (!ret) && (gdk_event->keyval == GDK_F10) ) { @@ -1253,7 +1198,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" ); return TRUE; } - + return FALSE; } @@ -1294,27 +1239,36 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, // 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 +// mouse event processing helpers // ---------------------------------------------------------------------------- +// init wxMouseEvent with the info from gdk_event +// +// NB: this has to be a macro as gdk_event type is different for different +// events we're used with +#define InitMouseEvent(/* wxWindowGTK * */ win, \ + /* wxMouseEvent& */ event, \ + /* GdkEventXXX * */ 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; \ + \ + event.SetEventObject( win ); \ + event.SetId( win->GetId() ); \ + event.SetTimestamp( gdk_event->time ); \ +} \ + static void AdjustEventButtonState(wxMouseEvent& event) { // GDK reports the old state of the button for a button press event, but @@ -1347,11 +1301,79 @@ static void AdjustEventButtonState(wxMouseEvent& event) } } +// find the window to send the mouse event too +static +wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) +{ + wxCoord xx = x; + wxCoord yy = y; + + if (win->m_wxwindow) + { + GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow); + xx += pizza->xoffset; + yy += pizza->yoffset; + } + + wxNode *node = win->GetChildren().First(); + while (node) + { + wxWindowGTK *child = (wxWindowGTK*)node->Data(); + + node = node->Next(); + if (!child->IsShown()) + continue; + + if (child->IsTransparentForMouse()) + { + // wxStaticBox is transparent in the box itself + int xx1 = child->m_x; + int yy1 = child->m_y; + int xx2 = child->m_x + child->m_width; + int yy2 = child->m_x + child->m_height; + + // left + if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) || + // right + ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) || + // top + ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) || + // bottom + ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2))) + { + win = child; + x -= child->m_x; + y -= child->m_y; + break; + } + + } + else + { + if ((child->m_wxwindow == (GtkWidget*) NULL) && + (child->m_x <= xx) && + (child->m_y <= yy) && + (child->m_x+child->m_width >= xx) && + (child->m_y+child->m_height >= yy)) + { + win = child; + x -= child->m_x; + y -= child->m_y; + break; + } + } + } + + return win; +} + //----------------------------------------------------------------------------- // "button_press_event" //----------------------------------------------------------------------------- -static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win ) +static gint gtk_window_button_press_callback( GtkWidget *widget, + GdkEventButton *gdk_event, + wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1422,79 +1444,15 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton 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; - } + // wxListBox actually get mouse events from the item, so we need to give it + // a chance to correct this + win->FixUpMouseEvent(widget, event.m_x, event.m_y); - // Some control don't have their own X window and thus cannot get - // any events. - - if (!g_captureWindow) - { - wxCoord x = event.m_x; - wxCoord y = event.m_y; - if (win->m_wxwindow) - { - GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow); - x += pizza->xoffset; - y += pizza->yoffset; - } - - wxNode *node = win->GetChildren().First(); - while (node) - { - wxWindowGTK *child = (wxWindowGTK*)node->Data(); - - node = node->Next(); - if (!child->IsShown()) - continue; - - if (child->m_isStaticBox) - { - // wxStaticBox is transparent in the box itself - int xx1 = child->m_x; - int yy1 = child->m_y; - int xx2 = child->m_x + child->m_width; - int yy2 = child->m_x + child->m_height; - - // left - if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) || - // right - ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) || - // top - ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) || - // bottom - ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2))) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - - } - else - { - if ((child->m_wxwindow == (GtkWidget*) NULL) && - (child->m_x <= x) && - (child->m_y <= y) && - (child->m_x+child->m_width >= x) && - (child->m_y+child->m_height >= y)) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - } - } - } - - event.SetEventObject( win ); + // find the correct window to send the event too: it may be a different one + // from the one which got it at GTK+ level because some control don't have + // their own X window and thus cannot get any events. + if ( !g_captureWindow ) + win = FindWindowForMouseEvent(win, event.m_x, event.m_y); gs_timeLastClick = gdk_event->time; @@ -1553,79 +1511,11 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto 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. - - if (!g_captureWindow) - { - wxCoord x = event.m_x; - wxCoord y = event.m_y; - if (win->m_wxwindow) - { - GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow); - x += pizza->xoffset; - y += pizza->yoffset; - } - - wxNode *node = win->GetChildren().First(); - while (node) - { - wxWindowGTK *child = (wxWindowGTK*)node->Data(); - - node = node->Next(); - if (!child->IsShown()) - continue; - - if (child->m_isStaticBox) - { - // wxStaticBox is transparent in the box itself - int xx1 = child->m_x; - int yy1 = child->m_y; - int xx2 = child->m_x + child->m_width; - int yy2 = child->m_x + child->m_height; - - // left - if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) || - // right - ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) || - // top - ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) || - // bottom - ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2))) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - - } - else - { - if ((child->m_wxwindow == (GtkWidget*) NULL) && - (child->m_x <= x) && - (child->m_y <= y) && - (child->m_x+child->m_width >= x) && - (child->m_y+child->m_height >= y)) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - } - } - } + // same wxListBox hack as above + win->FixUpMouseEvent(widget, event.m_x, event.m_y); - event.SetEventObject( win ); + if ( !g_captureWindow ) + win = FindWindowForMouseEvent(win, event.m_x, event.m_y); if (win->GetEventHandler()->ProcessEvent( event )) { @@ -1694,70 +1584,9 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, } else // no capture { - // Some control don't have their own X window and thus cannot get - // any events. - - wxCoord x = event.m_x; - wxCoord y = event.m_y; - if (win->m_wxwindow) - { - GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow); - x += pizza->xoffset; - y += pizza->yoffset; - } - - wxNode *node = win->GetChildren().First(); - while (node) - { - wxWindowGTK *child = (wxWindowGTK*)node->Data(); - - node = node->Next(); - if (!child->IsShown()) - continue; - - if (child->m_isStaticBox) - { - // wxStaticBox is transparent in the box itself - int xx1 = child->m_x; - int yy1 = child->m_y; - int xx2 = child->m_x + child->m_width; - int yy2 = child->m_x + child->m_height; - - // left - if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) || - // right - ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) || - // top - ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) || - // bottom - ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2))) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - - } - else - { - if ((child->m_wxwindow == (GtkWidget*) NULL) && - (child->m_x <= x) && - (child->m_y <= y) && - (child->m_x+child->m_width >= x) && - (child->m_y+child->m_height >= y)) - { - win = child; - event.m_x -= child->m_x; - event.m_y -= child->m_y; - break; - } - } - } + win = FindWindowForMouseEvent(win, event.m_x, event.m_y); } - event.SetEventObject( win ); - if (win->GetEventHandler()->ProcessEvent( event )) { gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" ); @@ -1771,6 +1600,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 ) @@ -1800,14 +1644,8 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, g_focusWindowLast = g_focusWindow = win; -#if 0 - printf( "OnSetFocus 2 from %s\n", win->GetName().c_str() ); -#endif - - // Notify the parent keeping track of focus for the kbd navigation - // purposes that we got it. - wxChildFocusEvent eventFocus(win); - (void)win->GetEventHandler()->ProcessEvent(eventFocus); + wxLogTrace(TRACE_FOCUS, + _T("%s: focus in"), win->GetName().c_str()); #ifdef HAVE_XIM if (win->m_ic) @@ -1847,14 +1685,17 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, // return TRUE; } - - wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() ); - event.SetEventObject( win ); - - if (win->GetEventHandler()->ProcessEvent( event )) + // does the window itself think that it has the focus? + if ( !win->m_hasFocus ) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); - return TRUE; + // not yet, notify it + win->m_hasFocus = TRUE; + + if ( DoSendFocusEvents(win) ) + { + gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); + return TRUE; + } } return FALSE; @@ -1874,9 +1715,8 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; -#if 0 - wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() ); -#endif + wxLogTrace( TRACE_FOCUS, + _T("%s: focus out"), win->GetName().c_str() ); if ( !g_activeFrameLostFocus && g_activeFrame ) { @@ -1885,7 +1725,7 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk // always) and makes using Mahogany quite annoying #if 0 wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, - wxT("unfocusing window that hasn't gained focus properly") ) + wxT("unfocusing window that hasn't gained focus properly") ); #endif // 0 g_activeFrameLostFocus = TRUE; @@ -1916,13 +1756,20 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk } #endif // wxUSE_CARET - wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); - event.SetEventObject( win ); - - if (win->GetEventHandler()->ProcessEvent( event )) + // don't send the window a kill focus event if it thinks that it doesn't + // have focus already + if ( win->m_hasFocus ) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" ); - return TRUE; + win->m_hasFocus = FALSE; + + wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); + event.SetEventObject( win ); + + if (win->GetEventHandler()->ProcessEvent( event )) + { + gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" ); + return TRUE; + } } return FALSE; @@ -1932,7 +1779,10 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk // "enter_notify_event" //----------------------------------------------------------------------------- -static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win ) +static +gint gtk_window_enter_callback( GtkWidget *widget, + GdkEventCrossing *gdk_event, + wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1944,16 +1794,13 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - wxMouseEvent event( wxEVT_ENTER_WINDOW ); - event.SetTimestamp( gdk_event->time ); - event.SetEventObject( win ); - int x = 0; int y = 0; GdkModifierType state = (GdkModifierType)0; gdk_window_get_pointer( widget->window, &x, &y, &state ); + wxMouseEvent event( wxEVT_ENTER_WINDOW ); InitMouseEvent(win, event, gdk_event); wxPoint pt = win->GetClientAreaOrigin(); event.m_x = x + pt.x; @@ -2037,7 +1884,8 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, win->m_oldVerticalPos = adjust->value; - wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget)); + GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); + wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar)); int value = (int)(adjust->value+0.5); @@ -2065,7 +1913,8 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust, float diff = adjust->value - win->m_oldHorizontalPos; if (fabs(diff) < 0.2) return; - wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget)); + GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget); + wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar)); win->m_oldHorizontalPos = adjust->value; @@ -2156,6 +2005,22 @@ wxWindow *wxWindowBase::FindFocus() return (wxWindow *)g_focusWindow; } +//----------------------------------------------------------------------------- +// "destroy" event +//----------------------------------------------------------------------------- + +// VZ: Robert commented the code using out so it generates warnings: should +// be either fixed or removed completely +#if 0 + +static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win ) +{ + wxWindowDestroyEvent event(win); + win->GetEventHandler()->ProcessEvent(event); +} + +#endif // 0 + //----------------------------------------------------------------------------- // "realize" from m_widget //----------------------------------------------------------------------------- @@ -2374,8 +2239,7 @@ static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child ) wxWindow *wxGetActiveWindow() { - // the cast is necessary when we compile in wxUniversal mode - return (wxWindow *)g_focusWindow; + return wxWindow::FindFocus(); } //----------------------------------------------------------------------------- @@ -2427,11 +2291,8 @@ void wxWindowGTK::Init() m_insertCallback = (wxInsertChildFunction) NULL; - m_isStaticBox = FALSE; - m_isRadioButton = FALSE; - m_isListBox = FALSE; - m_isFrame = FALSE; m_acceptsFocus = FALSE; + m_hasFocus = FALSE; m_clipPaintRegion = FALSE; @@ -2586,6 +2447,9 @@ wxWindowGTK::~wxWindowGTK() if (g_activeFrame == this) g_activeFrame = NULL; + if ( g_delayedFocus == this ) + g_delayedFocus = NULL; + m_isBeingDeleted = TRUE; m_hasVMT = FALSE; @@ -2631,17 +2495,17 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const w { wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") ); - /* this turns -1 into 20 so that a minimal window is - visible even although -1,-1 has been given as the - size of the window. the same trick is used in other - ports and should make debugging easier */ - m_width = WidthDefault(size.x); + // This turns -1 into 30 so that a minimal window is + // visible even although -1,-1 has been given as the + // size of the window. the same trick is used in other + // ports and should make debugging easier. + m_width = WidthDefault(size.x) ; m_height = HeightDefault(size.y); m_x = (int)pos.x; m_y = (int)pos.y; - /* some reasonable defaults */ + // some reasonable defaults if (!parent) { if (m_x == -1) @@ -2771,6 +2635,11 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event", GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this ); + + // This keeps crashing on me. RR. + // + // gtk_signal_connect( GTK_OBJECT(widget), "destroy", + // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this ); } bool wxWindowGTK::Destroy() @@ -2902,7 +2771,7 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags void wxWindowGTK::OnInternalIdle() { // Update invalidated regions. - Update(); + GtkUpdate(); // Synthetize activate events. if ( g_sendActivateEvent != -1 ) @@ -2928,15 +2797,6 @@ void wxWindowGTK::OnInternalIdle() g_activeFrameLostFocus = FALSE; } - if (g_delayedFocus == this) - { - if (GTK_WIDGET_REALIZED(m_widget)) - { - gtk_widget_grab_focus( m_widget ); - g_delayedFocus = NULL; - } - } - wxCursor cursor = m_cursor; if (g_globalCursor.Ok()) cursor = g_globalCursor; @@ -3289,7 +3149,13 @@ void wxWindowGTK::GetTextExtent( const wxString& string, void wxWindowGTK::SetFocus() { - wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); + wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); + + if ( m_hasFocus ) + { + // don't do anything if we already have focus + return; + } if (m_wxwindow) { @@ -3303,9 +3169,24 @@ void wxWindowGTK::SetFocus() if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) ) { if (!GTK_WIDGET_REALIZED(m_widget)) + { + // we can't set the focus to the widget now so we remember that + // it should be focused and will do it later, during the idle + // time, as soon as we can + wxLogTrace(TRACE_FOCUS, + _T("Delaying setting focus to %s(%s)"), + GetClassInfo()->GetClassName(), GetLabel().c_str()); + g_delayedFocus = this; + } else + { + wxLogTrace(TRACE_FOCUS, + _T("Setting focus to %s(%s)"), + GetClassInfo()->GetClassName(), GetLabel().c_str()); + gtk_widget_grab_focus (m_widget); + } } else if (GTK_IS_CONTAINER(m_widget)) { @@ -3313,7 +3194,9 @@ void wxWindowGTK::SetFocus() } else { - // ? + wxLogTrace(TRACE_FOCUS, + _T("Can't set focus to %s(%s)"), + GetClassInfo()->GetClassName(), GetLabel().c_str()); } } } @@ -3425,11 +3308,12 @@ void wxWindowGTK::WarpPointer( int x, int y ) gdk_window_warp_pointer( window, x, y ); } + void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) { if (!m_widget) return; if (!m_widget->window) return; - + #ifndef __WXGTK20__ if (g_isIdle) wxapp_install_idle_handler(); @@ -3500,6 +3384,11 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) } void wxWindowGTK::Update() +{ + GtkUpdate(); +} + +void wxWindowGTK::GtkUpdate() { #ifdef __WXGTK20__ if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window) @@ -3519,12 +3408,50 @@ void wxWindowGTK::GtkSendPaintEvents() 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 ); + if (m_clearRegion.IsEmpty()) + dc.SetClippingRegion( m_updateRegion ); + else + dc.SetClippingRegion( m_clearRegion ); wxEraseEvent erase_event( GetId(), &dc ); erase_event.SetEventObject( this ); @@ -3533,7 +3460,7 @@ void wxWindowGTK::GtkSendPaintEvents() { if (!g_eraseGC) { - g_eraseGC = gdk_gc_new( GTK_PIZZA(m_wxwindow)->bin_window ); + 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() ); @@ -3541,8 +3468,8 @@ void wxWindowGTK::GtkSendPaintEvents() wxRegionIterator upd( m_clearRegion ); while (upd) { - gdk_draw_rectangle( GTK_PIZZA(m_wxwindow)->bin_window, g_eraseGC, 1, - upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() ); + gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1, + upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() ); upd ++; } } @@ -3565,8 +3492,6 @@ void wxWindowGTK::GtkSendPaintEvents() // being redrawn because the wxWindows class is allowed to // paint over the window-less widgets. - GtkPizza *pizza = GTK_PIZZA(m_wxwindow); - GList *children = pizza->children; while (children) { @@ -3619,7 +3544,7 @@ void wxWindowGTK::Clear() m_clearRegion.Union( 0,0,size.x,size.y ); // Better do this in idle? - Update(); + GtkUpdate(); } } @@ -3651,12 +3576,9 @@ void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour ) // We need the pixel value e.g. for background clearing. m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) ); - if ((m_wxwindow) && - (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))) + if (m_wxwindow) { - /* wxMSW doesn't clear the window here. I don't do that either to - provide compatibility. call Clear() to do the job. */ - + // wxMSW doesn't clear the window here, either. gdk_window_set_background( window, m_backgroundColour.GetColor() ); } @@ -4234,7 +4156,7 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); - + // No scrolling requested. if ((dx == 0) && (dy == 0)) return; @@ -4258,7 +4180,6 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) GetClientSize( &cw, &ch ); m_clearRegion.Intersect( 0, 0, cw, ch ); } - m_clipPaintRegion = TRUE; gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); @@ -4347,3 +4268,4 @@ void wxWinModule::OnExit() gdk_gc_unref( g_eraseGC ); } +// vi:sts=4:sw=4:et