X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b9f2926155e550191fd91ec45943382e4252365a..1c405bb51093fc7812fb66e7d47faac5707e02b5:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 1c2d765a7e..a6f5fa3652 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -216,6 +216,11 @@ static bool g_captureWindowHasMouse = FALSE; // keeps its previous value 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 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 // OnIdle() call and it is reset to -1: this value means that we shouldn't @@ -358,6 +363,16 @@ 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 @@ -471,10 +486,21 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU static long map_to_unmodified_wx_keysym( GdkEventKey *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 resue it as last resort + // + // NB: should be MT-neutral as always called from main thread only + static struct + { + KeySym keysym; + long keycode; + } s_lastKeyPress = { 0, 0 }; + KeySym keysym = event->keyval; - guint key_code = 0; + long key_code; - switch (keysym) + switch ( keysym ) { case GDK_Shift_L: case GDK_Shift_R: key_code = WXK_SHIFT; break; @@ -567,20 +593,45 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event ) 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) + // do we have the translation? + if ( event->length == 1 ) { - guint upper = gdk_keyval_to_upper( (guint)keysym ); - keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */ - key_code = (guint)keysym; + keysym = (KeySym)event->string[0]; + } + else if ( (keysym & 0xFF) != keysym ) + { + // non ASCII key, what to do? + + if ( event->type == GDK_KEY_RELEASE ) + { + // reuse the one from the last keypress if any + if ( keysym == s_lastKeyPress.keysym ) + { + key_code = s_lastKeyPress.keycode; + + // skip "return 0" + break; + } + } + + // ignore this one, we don't know it + return 0; + } + //else: ASCII key, ok + + guint upper = gdk_keyval_to_upper( (guint)keysym ); + key_code = upper ? upper : keysym; + + if ( event->type == GDK_KEY_PRESS ) + { + // remember it to be reused below later + s_lastKeyPress.keysym = keysym; + s_lastKeyPress.keycode = key_code; } } } - return (key_code); + return key_code; } static long map_to_wx_keysym( GdkEventKey *event ) @@ -670,19 +721,17 @@ static long map_to_wx_keysym( GdkEventKey *event ) 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) + if (event->length == 1) + { + key_code = (unsigned char)*event->string; + } + else if ((keysym & 0xFF) == keysym) { key_code = (guint)keysym; } - } } - return (key_code); + return key_code; } //----------------------------------------------------------------------------- @@ -736,8 +785,14 @@ static int gtk_window_expose_callback( GtkWidget *widget, 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); + 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); } win->GetUpdateRegion().Union( gdk_event->area.x, @@ -879,8 +934,14 @@ 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); } @@ -952,6 +1013,9 @@ static void gtk_window_draw_callback( GtkWidget *widget, // "key_press_event" from any window //----------------------------------------------------------------------------- +// turn on to see the key event codes on the console +#undef DEBUG_KEY_EVENTS + static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) @@ -965,23 +1029,23 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, 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); + 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 ); + +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ - if (key_code == 0) return FALSE; + if (key_code == 0) + return FALSE; wxKeyEvent event( wxEVT_KEY_DOWN ); event.SetTimestamp( gdk_event->time ); @@ -1016,39 +1080,37 @@ 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 ) + { + key_code = map_to_wx_keysym( gdk_event ); - 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 ) + { +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Char event: %ld\n"), key_code); +#endif // DEBUG_KEY_EVENTS + + // reuse the ame 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() ); @@ -1061,7 +1123,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); @@ -1069,10 +1131,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) ) { @@ -1098,8 +1159,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ancestor = ancestor->GetParent(); } } -*/ -#endif +#endif // 0 if (ret) { @@ -1124,28 +1184,20 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk 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 ); +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ if (key_code == 0) 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 (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); wxKeyEvent event( wxEVT_KEY_UP ); event.SetTimestamp( gdk_event->time ); @@ -1168,6 +1220,27 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk return FALSE; } +// ============================================================================ +// 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 // ---------------------------------------------------------------------------- @@ -1280,20 +1353,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. @@ -1413,19 +1484,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. @@ -1501,24 +1571,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" //----------------------------------------------------------------------------- @@ -1556,7 +1608,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 ) { @@ -1570,7 +1622,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); } @@ -1709,14 +1761,25 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, } #endif // wxUSE_CARET - if (win->IsTopLevel()) + 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); } + g_activeFrameLostFocus = FALSE; + wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() ); event.SetEventObject( win ); @@ -1735,6 +1798,8 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, // "focus_out_event" //----------------------------------------------------------------------------- +static GtkWidget *gs_widgetLastFocus = NULL; + static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win ) { DEBUG_MAIN_THREAD @@ -1745,6 +1810,31 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; + // VZ: this is really weird but GTK+ seems to call us from inside + // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to + // this widget and then "focus_in". This is totally unexpected and + // completely breaks wxUniv code so ignore this dummy event (we can't + // be losing focus if we're about to acquire it!) + if ( widget == gs_widgetLastFocus ) + { + gs_widgetLastFocus = NULL; + + return FALSE; + } + + 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 @@ -1777,15 +1867,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 ); @@ -1824,10 +1905,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 )) { @@ -1872,8 +1953,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ event.m_middleDown = (state & GDK_BUTTON2_MASK); event.m_rightDown = (state & GDK_BUTTON3_MASK); - 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 )) { @@ -2288,7 +2370,7 @@ void wxWindowGTK::Init() m_noExpose = FALSE; m_nativeSizeEvent = FALSE; - + m_hasScrolling = FALSE; m_isScrolling = FALSE; @@ -2304,6 +2386,7 @@ void wxWindowGTK::Init() m_isStaticBox = FALSE; m_isRadioButton = FALSE; + m_isListBox = FALSE; m_isFrame = FALSE; m_acceptsFocus = FALSE; @@ -2462,7 +2545,7 @@ bool wxWindowGTK::Create( wxWindow *parent, if (m_parent) m_parent->DoAddChild( this ); - + m_focusWidget = m_wxwindow; PostCreation(); @@ -2477,6 +2560,9 @@ wxWindowGTK::~wxWindowGTK() if (g_focusWindow == this) g_focusWindow = NULL; + if (g_activeFrame == this) + g_activeFrame = NULL; + m_isBeingDeleted = TRUE; m_hasVMT = FALSE; @@ -2553,7 +2639,7 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const w void wxWindowGTK::PostCreation() { wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") ); - + if (m_wxwindow) { if (!m_noExpose) @@ -2796,6 +2882,19 @@ void wxWindowGTK::OnInternalIdle() wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast); } + 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; @@ -2988,21 +3087,9 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const dx = pizza->xoffset; dy = pizza->yoffset; } - - int nx = m_x - dx; - int ny = m_y - dy; - - if ( !IsTopLevel() && m_parent ) - { - // We may be faking the client origin. So a window that's really at (0, - // 30) may appear (to wxWin apps) to be at (0, 0). - wxPoint pt(m_parent->GetClientAreaOrigin()); - nx -= pt.x; - ny -= pt.y; - } - if (x) (*x) = nx; - if (y) (*y) = ny; + if (x) (*x) = m_x - dx; + if (y) (*y) = m_y - dy; } void wxWindowGTK::DoClientToScreen( int *x, int *y ) const @@ -3162,14 +3249,23 @@ void wxWindowGTK::SetFocus() { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); +#if 0 + wxPrintf( "SetFocus from " ); + if (GetClassInfo() && GetClassInfo()->GetClassName()) + wxPrintf( GetClassInfo()->GetClassName() ); + wxPrintf( ".\n" ); +#endif + if (m_wxwindow) { if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow)) + { + // see comment in gtk_window_focus_out_callback() + gs_widgetLastFocus = 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) ) { @@ -3184,6 +3280,14 @@ void wxWindowGTK::SetFocus() // ? } } + +#if 0 + wxPrintf( "SetFocus finished in " ); + if (GetClassInfo() && GetClassInfo()->GetClassName()) + wxPrintf( GetClassInfo()->GetClassName() ); + wxPrintf( ".\n" ); +#endif + } bool wxWindowGTK::AcceptsFocus() const @@ -3444,7 +3548,7 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour ) if ((m_wxwindow) && (m_wxwindow->window) && - (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))) + (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))) { /* wxMSW doesn't clear the window here. I don't do that either to provide compatibility. call Clear() to do the job. */ @@ -3540,7 +3644,7 @@ 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 ) ); @@ -3549,7 +3653,7 @@ void wxWindowGTK::SetWidgetStyle() 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(); @@ -3575,7 +3679,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(); @@ -3621,7 +3725,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; } @@ -3642,16 +3747,29 @@ 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, + 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 ) @@ -3666,20 +3784,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) @@ -3736,7 +3857,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; @@ -3751,7 +3872,7 @@ bool wxWindowGTK::SetFont( const wxFont &font ) return TRUE; } -void wxWindowGTK::CaptureMouse() +void wxWindowGTK::DoCaptureMouse() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -3780,12 +3901,14 @@ 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("can't release mouse - not captured") ); + g_captureWindow = (wxWindowGTK*) NULL; + GdkWindow *window = (GdkWindow*) NULL; if (m_wxwindow) window = GTK_PIZZA(m_wxwindow)->bin_window; @@ -3796,7 +3919,6 @@ void wxWindowGTK::ReleaseMouse() return; gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME ); - g_captureWindow = (wxWindowGTK*) NULL; } /* static */