simplified and cleaned up wxGTK's focus handling
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
fe828a03f4
commit
bd2e08d065
@ -94,8 +94,6 @@ public:
|
||||
// From wxComboBoxBase:
|
||||
virtual int GetCurrentSelection() const;
|
||||
|
||||
virtual void SetFocus();
|
||||
|
||||
void OnChar( wxKeyEvent &event );
|
||||
|
||||
// Standard event handling
|
||||
|
@ -128,17 +128,12 @@ public:
|
||||
// implementation
|
||||
// --------------
|
||||
|
||||
void SetFocus();
|
||||
void GtkDisableEvents();
|
||||
void GtkEnableEvents();
|
||||
#if wxUSE_TOOLTIPS
|
||||
void ApplyToolTip( GtkTooltips *tips, const gchar *tip );
|
||||
#endif // wxUSE_TOOLTIPS
|
||||
|
||||
virtual void OnInternalIdle();
|
||||
|
||||
bool m_hasFocus,
|
||||
m_lostFocus;
|
||||
wxRadioBoxButtonsInfoList m_buttonsInfo;
|
||||
|
||||
protected:
|
||||
@ -151,12 +146,11 @@ protected:
|
||||
virtual void DoApplyWidgetStyle(GtkRcStyle *style);
|
||||
virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
|
||||
|
||||
virtual bool GTKNeedsToFilterSameWindowFocus() const { return true; }
|
||||
|
||||
virtual bool GTKWidgetNeedsMnemonic() const;
|
||||
virtual void GTKWidgetDoSetMnemonic(GtkWidget* w);
|
||||
|
||||
// common part of all ctors
|
||||
void Init();
|
||||
|
||||
private:
|
||||
DECLARE_DYNAMIC_CLASS(wxRadioBox)
|
||||
};
|
||||
|
@ -186,7 +186,17 @@ public:
|
||||
|
||||
GdkWindow* GTKGetDrawingWindow() const;
|
||||
|
||||
bool GTKHandleFocusIn();
|
||||
bool GTKHandleFocusOut();
|
||||
void GTKHandleFocusOutNoDeferring();
|
||||
static void GTKHandleDeferredFocusOut();
|
||||
|
||||
protected:
|
||||
// for controls composed of multiple GTK widgets, return true to eliminate
|
||||
// spurious focus events if the focus changes between GTK+ children within
|
||||
// the same wxWindow
|
||||
virtual bool GTKNeedsToFilterSameWindowFocus() const { return false; }
|
||||
|
||||
// Override GTKWidgetNeedsMnemonic and return true if your
|
||||
// needs to set its mnemonic widget, such as for a
|
||||
// GtkLabel for wxStaticText, then do the actual
|
||||
@ -206,12 +216,6 @@ protected:
|
||||
// Check if the given window makes part of this widget
|
||||
bool GTKIsOwnWindow(GdkWindow *window) const;
|
||||
|
||||
// Set the focus to this window if its setting was delayed because the
|
||||
// widget hadn't been realized when SetFocus() was called
|
||||
//
|
||||
// Return true if focus was set to us, false if nothing was done
|
||||
bool GTKSetDelayedFocusIfNeeded();
|
||||
|
||||
public:
|
||||
// Returns the default context which usually is anti-aliased
|
||||
PangoContext *GtkGetPangoDefaultContext();
|
||||
@ -287,7 +291,6 @@ public:
|
||||
bool m_noExpose:1; // wxGLCanvas has its own redrawing
|
||||
bool m_nativeSizeEvent:1; // wxGLCanvas sends wxSizeEvent upon "alloc_size"
|
||||
bool m_hasVMT:1;
|
||||
bool m_hasFocus:1; // true if == FindFocus()
|
||||
bool m_isScrolling:1; // dragging scrollbar thumb?
|
||||
bool m_clipPaintRegion:1; // true after ScrollWindow()
|
||||
wxRegion m_nativeUpdateRegion; // not transformed for RTL
|
||||
|
@ -170,17 +170,6 @@ wxComboBox::~wxComboBox()
|
||||
delete m_strings;
|
||||
}
|
||||
|
||||
void wxComboBox::SetFocus()
|
||||
{
|
||||
if ( m_hasFocus )
|
||||
{
|
||||
// don't do anything if we already have focus
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus( m_focusWidget );
|
||||
}
|
||||
|
||||
int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
|
||||
unsigned int pos,
|
||||
void **clientData, wxClientDataType type)
|
||||
|
@ -295,8 +295,6 @@ void wxControl::OnInternalIdle()
|
||||
if ( GTK_WIDGET_REALIZED(m_widget) )
|
||||
{
|
||||
GTKUpdateCursor();
|
||||
|
||||
GTKSetDelayedFocusIfNeeded();
|
||||
}
|
||||
|
||||
if ( wxUpdateUIEvent::CanUpdate(this) )
|
||||
|
@ -258,7 +258,6 @@ IMPLEMENT_DYNAMIC_CLASS( wxGtkFileCtrl, wxControl )
|
||||
|
||||
void wxGtkFileCtrl::Init()
|
||||
{
|
||||
m_hasFocus = false;
|
||||
m_checkNextSelEvent = false;
|
||||
|
||||
// ignore the first folder change event which is fired upon startup.
|
||||
|
@ -138,46 +138,33 @@ static gint gtk_radiobox_keypress_callback( GtkWidget *widget, GdkEventKey *gdk_
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static gint gtk_radiobutton_focus_in( GtkWidget * WXUNUSED(widget),
|
||||
GdkEvent *WXUNUSED(event),
|
||||
wxRadioBox *win )
|
||||
static gint gtk_radiobutton_focus_out( GtkWidget * WXUNUSED(widget),
|
||||
GdkEventFocus *WXUNUSED(event),
|
||||
wxRadioBox *win )
|
||||
{
|
||||
if ( win->m_lostFocus )
|
||||
{
|
||||
// no, we didn't really lose it
|
||||
win->m_lostFocus = FALSE;
|
||||
}
|
||||
else if ( !win->m_hasFocus )
|
||||
{
|
||||
win->m_hasFocus = true;
|
||||
|
||||
wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
|
||||
event.SetEventObject( win );
|
||||
|
||||
// never stop the signal emission, it seems to break the kbd handling
|
||||
// inside the radiobox
|
||||
(void)win->HandleWindowEvent( event );
|
||||
}
|
||||
// NB: This control is composed of several GtkRadioButton widgets and
|
||||
// when focus changes from one of them to another in the same
|
||||
// wxRadioBox, we get a focus-out event followed by focus-in for
|
||||
// another GtkRadioButton owned by the same control. We don't want
|
||||
// to generate two spurious wxEVT_SET_FOCUS events in this case,
|
||||
// so we defer sending wx events until idle time.
|
||||
win->GTKHandleFocusOut();
|
||||
|
||||
// never stop the signal emission, it seems to break the kbd handling
|
||||
// inside the radiobox
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static gint gtk_radiobutton_focus_out( GtkWidget * WXUNUSED(widget),
|
||||
GdkEvent *WXUNUSED(event),
|
||||
wxRadioBox *win )
|
||||
static gint gtk_radiobutton_focus_in( GtkWidget * WXUNUSED(widget),
|
||||
GdkEventFocus *WXUNUSED(event),
|
||||
wxRadioBox *win )
|
||||
{
|
||||
// wxASSERT_MSG( win->m_hasFocus, _T("got focus out without any focus in?") );
|
||||
// Replace with a warning, else we dump core a lot!
|
||||
// if (!win->m_hasFocus)
|
||||
// wxLogWarning(_T("Radiobox got focus out without any focus in.") );
|
||||
|
||||
// we might have lost the focus, but may be not - it may have just gone to
|
||||
// another button in the same radiobox, so we'll check for it in the next
|
||||
// idle iteration (leave m_hasFocus == true for now)
|
||||
win->m_lostFocus = true;
|
||||
win->GTKHandleFocusIn();
|
||||
|
||||
// never stop the signal emission, it seems to break the kbd handling
|
||||
// inside the radiobox
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -210,12 +197,6 @@ static void gtk_radiobutton_size_allocate( GtkWidget *widget,
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxRadioBox,wxControl)
|
||||
|
||||
void wxRadioBox::Init()
|
||||
{
|
||||
m_hasFocus =
|
||||
m_lostFocus = false;
|
||||
}
|
||||
|
||||
bool wxRadioBox::Create( wxWindow *parent, wxWindowID id,
|
||||
const wxString& title,
|
||||
const wxPoint &pos, const wxSize &size,
|
||||
@ -372,25 +353,6 @@ bool wxRadioBox::Show( bool show )
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxRadioBox::SetFocus()
|
||||
{
|
||||
wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
|
||||
|
||||
if (m_buttonsInfo.GetCount() == 0) return;
|
||||
|
||||
wxRadioBoxButtonsInfoList::compatibility_iterator node = m_buttonsInfo.GetFirst();
|
||||
while (node)
|
||||
{
|
||||
GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData()->button );
|
||||
if (button->active)
|
||||
{
|
||||
gtk_widget_grab_focus( GTK_WIDGET(button) );
|
||||
return;
|
||||
}
|
||||
node = node->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void wxRadioBox::SetSelection( int n )
|
||||
{
|
||||
wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
|
||||
@ -646,22 +608,6 @@ GdkWindow *wxRadioBox::GTKGetWindow(wxArrayGdkWindows& windows) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wxRadioBox::OnInternalIdle()
|
||||
{
|
||||
wxControl::OnInternalIdle();
|
||||
|
||||
if ( m_lostFocus )
|
||||
{
|
||||
m_hasFocus = false;
|
||||
m_lostFocus = false;
|
||||
|
||||
wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
|
||||
event.SetEventObject( this );
|
||||
|
||||
(void)HandleWindowEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
wxVisualAttributes
|
||||
wxRadioBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
|
||||
|
@ -57,8 +57,6 @@
|
||||
// this is incremented while a modal dialog is shown
|
||||
int wxOpenModalDialogsCount = 0;
|
||||
|
||||
extern wxWindowGTK *g_delayedFocus;
|
||||
|
||||
// the frame that is currently active (i.e. its child has focus). It is
|
||||
// used to generate wxActivateEvents
|
||||
static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
|
||||
@ -1032,22 +1030,6 @@ void wxTopLevelWindowGTK::GTKUpdateDecorSize(const wxSize& decorSize)
|
||||
|
||||
void wxTopLevelWindowGTK::OnInternalIdle()
|
||||
{
|
||||
// set the focus if not done yet and if we can already do it
|
||||
if ( GTK_WIDGET_REALIZED(m_wxwindow) )
|
||||
{
|
||||
if ( g_delayedFocus &&
|
||||
wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
|
||||
{
|
||||
wxLogTrace(_T("focus"),
|
||||
_T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
|
||||
g_delayedFocus->GetClassInfo()->GetClassName(),
|
||||
g_delayedFocus->GetLabel().c_str());
|
||||
|
||||
g_delayedFocus->SetFocus();
|
||||
g_delayedFocus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wxWindow::OnInternalIdle();
|
||||
|
||||
// Synthetize activate events.
|
||||
|
@ -185,11 +185,13 @@ extern wxCursor g_globalCursor;
|
||||
static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
|
||||
static bool g_captureWindowHasMouse = false;
|
||||
|
||||
wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
|
||||
// The window that currently has focus or is scheduled to get it in the next
|
||||
// event loop iteration
|
||||
static wxWindowGTK *gs_focusWindow = NULL;
|
||||
|
||||
// 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;
|
||||
// the window that has deferred focus-out event pending, if any (see
|
||||
// GTKAddDeferredFocusOut() for details)
|
||||
static wxWindowGTK *gs_deferredFocusOut = NULL;
|
||||
|
||||
// global variables because GTK+ DnD want to have the
|
||||
// mouse event that caused it
|
||||
@ -225,31 +227,6 @@ gdk_window_warp_pointer (GdkWindow *window,
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// local code (see below)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// returns the child of win which currently has focus or NULL if not found
|
||||
static wxWindow *wxFindFocusedChild(wxWindowGTK *win)
|
||||
{
|
||||
wxWindow *winFocus = wxWindowGTK::FindFocus();
|
||||
if ( !winFocus )
|
||||
return (wxWindow *)NULL;
|
||||
|
||||
if ( winFocus == win )
|
||||
return (wxWindow *)win;
|
||||
|
||||
for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
|
||||
node;
|
||||
node = node->GetNext() )
|
||||
{
|
||||
wxWindow *child = wxFindFocusedChild(node->GetData());
|
||||
if ( child )
|
||||
return child;
|
||||
}
|
||||
|
||||
return (wxWindow *)NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "size_request" of m_widget
|
||||
@ -1251,21 +1228,6 @@ wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
|
||||
if ( rc != -1 ) \
|
||||
return rc
|
||||
|
||||
// send the wxChildFocusEvent and wxFocusEvent, common code of
|
||||
// gtk_window_focus_in_callback() and SetFocus()
|
||||
static bool DoSendFocusEvents(wxWindow *win)
|
||||
{
|
||||
// Notify the parent keeping track of focus for the kbd navigation
|
||||
// purposes that we got it.
|
||||
wxChildFocusEvent eventChildFocus(win);
|
||||
(void)win->HandleWindowEvent(eventChildFocus);
|
||||
|
||||
wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
|
||||
eventFocus.SetEventObject(win);
|
||||
|
||||
return win->HandleWindowEvent(eventFocus);
|
||||
}
|
||||
|
||||
// all event handlers must have C linkage as they're called from GTK+ C code
|
||||
extern "C"
|
||||
{
|
||||
@ -1410,7 +1372,7 @@ gtk_window_button_press_callback( GtkWidget *widget,
|
||||
return TRUE;
|
||||
|
||||
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
|
||||
(g_focusWindow != win) /* && win->IsFocusable() */)
|
||||
(gs_focusWindow != win) /* && win->IsFocusable() */)
|
||||
{
|
||||
win->SetFocus();
|
||||
}
|
||||
@ -1610,44 +1572,9 @@ static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
|
||||
static gboolean
|
||||
gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
|
||||
GdkEventFocus *WXUNUSED(event),
|
||||
wxWindow *win )
|
||||
wxWindowGTK *win )
|
||||
{
|
||||
if (win->m_imData)
|
||||
gtk_im_context_focus_in(win->m_imData->context);
|
||||
|
||||
g_focusWindow = win;
|
||||
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
_T("%s: focus in"), win->GetName().c_str());
|
||||
|
||||
#if wxUSE_CARET
|
||||
// caret needs to be informed about focus change
|
||||
wxCaret *caret = win->GetCaret();
|
||||
if ( caret )
|
||||
{
|
||||
caret->OnSetFocus();
|
||||
}
|
||||
#endif // wxUSE_CARET
|
||||
|
||||
gboolean ret = FALSE;
|
||||
|
||||
// does the window itself think that it has the focus?
|
||||
if ( !win->m_hasFocus )
|
||||
{
|
||||
// not yet, notify it
|
||||
win->m_hasFocus = true;
|
||||
|
||||
(void)DoSendFocusEvents(win);
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
// Disable default focus handling for custom windows
|
||||
// since the default GTK+ handler issues a repaint
|
||||
if (win->m_wxwindow)
|
||||
return ret;
|
||||
|
||||
return FALSE;
|
||||
return win->GTKHandleFocusIn();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1659,53 +1586,13 @@ gtk_window_focus_out_callback( GtkWidget * WXUNUSED(widget),
|
||||
GdkEventFocus * WXUNUSED(gdk_event),
|
||||
wxWindowGTK *win )
|
||||
{
|
||||
if (win->m_imData)
|
||||
gtk_im_context_focus_out(win->m_imData->context);
|
||||
|
||||
wxLogTrace( TRACE_FOCUS,
|
||||
_T("%s: focus out"), win->GetName().c_str() );
|
||||
|
||||
|
||||
wxWindowGTK *winFocus = wxFindFocusedChild(win);
|
||||
if ( winFocus )
|
||||
win = winFocus;
|
||||
|
||||
g_focusWindow = (wxWindowGTK *)NULL;
|
||||
|
||||
#if wxUSE_CARET
|
||||
// caret needs to be informed about focus change
|
||||
wxCaret *caret = win->GetCaret();
|
||||
if ( caret )
|
||||
{
|
||||
caret->OnKillFocus();
|
||||
}
|
||||
#endif // wxUSE_CARET
|
||||
|
||||
// don't send the window a kill focus event if it thinks that it doesn't
|
||||
// have focus already
|
||||
if ( win->m_hasFocus )
|
||||
{
|
||||
// the event handler might delete the window when it loses focus, so
|
||||
// check whether this is a custom window before calling it
|
||||
const bool has_wxwindow = win->m_wxwindow != NULL;
|
||||
|
||||
win->m_hasFocus = false;
|
||||
|
||||
wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
|
||||
event.SetEventObject( win );
|
||||
|
||||
(void)win->GTKProcessEvent( event );
|
||||
|
||||
// Disable default focus handling for custom windows
|
||||
// since the default GTK+ handler issues a repaint
|
||||
if ( has_wxwindow )
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// continue with normal processing
|
||||
return FALSE;
|
||||
return win->GTKHandleFocusOut();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "focus"
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static gboolean
|
||||
wx_window_focus_callback(GtkWidget *widget,
|
||||
GtkDirectionType WXUNUSED(direction),
|
||||
@ -2005,7 +1892,7 @@ public:
|
||||
wxWindow *wxWindowBase::DoFindFocus()
|
||||
{
|
||||
// the cast is necessary when we compile in wxUniversal mode
|
||||
return (wxWindow *)g_focusWindow;
|
||||
return wx_static_cast(wxWindow*, gs_focusWindow);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -2117,8 +2004,6 @@ void wxWindowGTK::Init()
|
||||
|
||||
m_insertCallback = wxInsertChildInWindow;
|
||||
|
||||
m_hasFocus = false;
|
||||
|
||||
m_clipPaintRegion = false;
|
||||
|
||||
m_needsStyleChange = false;
|
||||
@ -2251,11 +2136,11 @@ wxWindowGTK::~wxWindowGTK()
|
||||
{
|
||||
SendDestroyEvent();
|
||||
|
||||
if (g_focusWindow == this)
|
||||
g_focusWindow = NULL;
|
||||
if (gs_focusWindow == this)
|
||||
gs_focusWindow = NULL;
|
||||
|
||||
if ( g_delayedFocus == this )
|
||||
g_delayedFocus = NULL;
|
||||
if ( gs_deferredFocusOut == this )
|
||||
gs_deferredFocusOut = NULL;
|
||||
|
||||
m_isBeingDeleted = true;
|
||||
m_hasVMT = false;
|
||||
@ -2614,6 +2499,9 @@ bool wxWindowGTK::GtkShowFromOnIdle()
|
||||
|
||||
void wxWindowGTK::OnInternalIdle()
|
||||
{
|
||||
if ( gs_deferredFocusOut )
|
||||
GTKHandleDeferredFocusOut();
|
||||
|
||||
// Check if we have to show window now
|
||||
if (GtkShowFromOnIdle()) return;
|
||||
|
||||
@ -2979,90 +2867,194 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
|
||||
{
|
||||
if ( g_delayedFocus == this )
|
||||
{
|
||||
if ( GTK_WIDGET_REALIZED(m_widget) )
|
||||
{
|
||||
gtk_widget_grab_focus(m_widget);
|
||||
g_delayedFocus = NULL;
|
||||
|
||||
return true;
|
||||
bool wxWindowGTK::GTKHandleFocusIn()
|
||||
{
|
||||
// Disable default focus handling for custom windows since the default GTK+
|
||||
// handler issues a repaint
|
||||
const bool retval = m_wxwindow ? true : false;
|
||||
|
||||
|
||||
// NB: if there's still unprocessed deferred focus-out event (see
|
||||
// GTKHandleFocusOut() for explanation), we need to process it first so
|
||||
// that the order of focus events -- focus-out first, then focus-in
|
||||
// elsewhere -- is preserved
|
||||
if ( gs_deferredFocusOut )
|
||||
{
|
||||
if ( GTKNeedsToFilterSameWindowFocus() &&
|
||||
gs_deferredFocusOut == this )
|
||||
{
|
||||
// GTK+ focus changed from this wxWindow back to itself, so don't
|
||||
// emit any events at all
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
"filtered out spurious focus change within %s(%p, %s)",
|
||||
GetClassInfo()->GetClassName(), this, GetLabel());
|
||||
gs_deferredFocusOut = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// otherwise we need to send focus-out first
|
||||
wxASSERT_MSG ( gs_deferredFocusOut != this,
|
||||
"GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
|
||||
GTKHandleDeferredFocusOut();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
"handling focus_in event for %s(%p, %s)",
|
||||
GetClassInfo()->GetClassName(), this, GetLabel());
|
||||
|
||||
if (m_imData)
|
||||
gtk_im_context_focus_in(m_imData->context);
|
||||
|
||||
// NB: SetFocus() does this assignment too, but not all focus changes
|
||||
// originate from SetFocus() call
|
||||
gs_focusWindow = this;
|
||||
|
||||
#if wxUSE_CARET
|
||||
// caret needs to be informed about focus change
|
||||
wxCaret *caret = GetCaret();
|
||||
if ( caret )
|
||||
{
|
||||
caret->OnSetFocus();
|
||||
}
|
||||
#endif // wxUSE_CARET
|
||||
|
||||
// Notify the parent keeping track of focus for the kbd navigation
|
||||
// purposes that we got it.
|
||||
wxChildFocusEvent eventChildFocus(this);
|
||||
GTKProcessEvent(eventChildFocus);
|
||||
|
||||
wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId());
|
||||
eventFocus.SetEventObject(this);
|
||||
GTKProcessEvent(eventFocus);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool wxWindowGTK::GTKHandleFocusOut()
|
||||
{
|
||||
// Disable default focus handling for custom windows since the default GTK+
|
||||
// handler issues a repaint
|
||||
const bool retval = m_wxwindow ? true : false;
|
||||
|
||||
|
||||
// NB: If a control is composed of several GtkWidgets and when focus
|
||||
// changes from one of them to another within the same wxWindow, we get
|
||||
// a focus-out event followed by focus-in for another GtkWidget owned
|
||||
// by the same wx control. We don't want to generate two spurious
|
||||
// wxEVT_SET_FOCUS events in this case, so we defer sending wx events
|
||||
// from GTKHandleFocusOut() until we know for sure it's not coming back
|
||||
// (i.e. in GTKHandleFocusIn() or at idle time).
|
||||
if ( GTKNeedsToFilterSameWindowFocus() )
|
||||
{
|
||||
wxASSERT_MSG( gs_deferredFocusOut == NULL,
|
||||
"deferred focus out event already pending" );
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
"deferring focus_out event for %s(%p, %s)",
|
||||
GetClassInfo()->GetClassName(), this, GetLabel());
|
||||
gs_deferredFocusOut = this;
|
||||
return retval;
|
||||
}
|
||||
|
||||
GTKHandleFocusOutNoDeferring();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void wxWindowGTK::GTKHandleFocusOutNoDeferring()
|
||||
{
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
"handling focus_out event for %s(%p, %s)",
|
||||
GetClassInfo()->GetClassName(), this, GetLabel());
|
||||
|
||||
if (m_imData)
|
||||
gtk_im_context_focus_out(m_imData->context);
|
||||
|
||||
if ( gs_focusWindow != this )
|
||||
{
|
||||
// Something is terribly wrong, gs_focusWindow is out of sync with the
|
||||
// real focus. We will reset it to NULL anyway, because after this
|
||||
// focus-out event is handled, one of the following with happen:
|
||||
//
|
||||
// * either focus will go out of the app altogether, in which case
|
||||
// gs_focusWindow _should_ be NULL
|
||||
//
|
||||
// * or it goes to another control, in which case focus-in event will
|
||||
// follow immediately and it will set gs_focusWindow to the right
|
||||
// value
|
||||
wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
|
||||
GetClassInfo()->GetClassName(), this, GetLabel());
|
||||
}
|
||||
gs_focusWindow = NULL;
|
||||
|
||||
#if wxUSE_CARET
|
||||
// caret needs to be informed about focus change
|
||||
wxCaret *caret = GetCaret();
|
||||
if ( caret )
|
||||
{
|
||||
caret->OnKillFocus();
|
||||
}
|
||||
#endif // wxUSE_CARET
|
||||
|
||||
wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
|
||||
event.SetEventObject( this );
|
||||
GTKProcessEvent( event );
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void wxWindowGTK::GTKHandleDeferredFocusOut()
|
||||
{
|
||||
// NB: See GTKHandleFocusOut() for explanation. This function is called
|
||||
// from either GTKHandleFocusIn() or OnInternalIdle() to process
|
||||
// deferred event.
|
||||
if ( gs_deferredFocusOut )
|
||||
{
|
||||
wxWindowGTK *win = gs_deferredFocusOut;
|
||||
gs_deferredFocusOut = NULL;
|
||||
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
"processing deferred focus_out event for %s(%p, %s)",
|
||||
win->GetClassInfo()->GetClassName(), win, win->GetLabel());
|
||||
|
||||
win->GTKHandleFocusOutNoDeferring();
|
||||
}
|
||||
}
|
||||
|
||||
void wxWindowGTK::SetFocus()
|
||||
{
|
||||
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
|
||||
if ( m_hasFocus )
|
||||
{
|
||||
// don't do anything if we already have focus
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_wxwindow)
|
||||
{
|
||||
// wxWindow::SetFocus() should really set the focus to
|
||||
// this control, whatever the flags are
|
||||
if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow))
|
||||
GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
|
||||
// Setting "physical" focus is not immediate in GTK+ and while
|
||||
// gtk_widget_is_focus ("determines if the widget is the focus widget
|
||||
// within its toplevel", i.e. returns true for one widget per TLW, not
|
||||
// globally) returns true immediately after grabbing focus,
|
||||
// GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
|
||||
// has focus at the moment) takes affect only after the window is shown
|
||||
// (if it was hidden at the moment of the call) or at the next event loop
|
||||
// iteration.
|
||||
//
|
||||
// Because we want to FindFocus() call immediately following
|
||||
// foo->SetFocus() to return foo, we have to keep track of "pending" focus
|
||||
// ourselves.
|
||||
gs_focusWindow = this;
|
||||
|
||||
if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
|
||||
{
|
||||
gtk_widget_grab_focus (m_wxwindow);
|
||||
}
|
||||
GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
|
||||
|
||||
if ( GTK_IS_CONTAINER(widget) &&
|
||||
!GTK_WIDGET_CAN_FOCUS(widget) )
|
||||
{
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
_T("Setting focus to a child of %s(%p, %s)"),
|
||||
GetClassInfo()->GetClassName(), this, GetLabel().c_str());
|
||||
gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
// wxWindow::SetFocus() should really set the focus to
|
||||
// this control, whatever the flags are
|
||||
if (!GTK_WIDGET_CAN_FOCUS(m_widget))
|
||||
GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
|
||||
|
||||
if (GTK_IS_CONTAINER(m_widget))
|
||||
{
|
||||
if (GTK_IS_RADIO_BUTTON(m_widget))
|
||||
{
|
||||
gtk_widget_grab_focus (m_widget);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
|
||||
}
|
||||
else
|
||||
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
|
||||
{
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
_T("Can't set focus to %s(%s)"),
|
||||
GetClassInfo()->GetClassName(), GetLabel().c_str());
|
||||
}
|
||||
wxLogTrace(TRACE_FOCUS,
|
||||
_T("Setting focus to %s(%p, %s)"),
|
||||
GetClassInfo()->GetClassName(), this, GetLabel().c_str());
|
||||
gtk_widget_grab_focus(widget);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user