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:
@@ -94,8 +94,6 @@ public:
|
|||||||
// From wxComboBoxBase:
|
// From wxComboBoxBase:
|
||||||
virtual int GetCurrentSelection() const;
|
virtual int GetCurrentSelection() const;
|
||||||
|
|
||||||
virtual void SetFocus();
|
|
||||||
|
|
||||||
void OnChar( wxKeyEvent &event );
|
void OnChar( wxKeyEvent &event );
|
||||||
|
|
||||||
// Standard event handling
|
// Standard event handling
|
||||||
|
@@ -128,17 +128,12 @@ public:
|
|||||||
// implementation
|
// implementation
|
||||||
// --------------
|
// --------------
|
||||||
|
|
||||||
void SetFocus();
|
|
||||||
void GtkDisableEvents();
|
void GtkDisableEvents();
|
||||||
void GtkEnableEvents();
|
void GtkEnableEvents();
|
||||||
#if wxUSE_TOOLTIPS
|
#if wxUSE_TOOLTIPS
|
||||||
void ApplyToolTip( GtkTooltips *tips, const gchar *tip );
|
void ApplyToolTip( GtkTooltips *tips, const gchar *tip );
|
||||||
#endif // wxUSE_TOOLTIPS
|
#endif // wxUSE_TOOLTIPS
|
||||||
|
|
||||||
virtual void OnInternalIdle();
|
|
||||||
|
|
||||||
bool m_hasFocus,
|
|
||||||
m_lostFocus;
|
|
||||||
wxRadioBoxButtonsInfoList m_buttonsInfo;
|
wxRadioBoxButtonsInfoList m_buttonsInfo;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -151,12 +146,11 @@ protected:
|
|||||||
virtual void DoApplyWidgetStyle(GtkRcStyle *style);
|
virtual void DoApplyWidgetStyle(GtkRcStyle *style);
|
||||||
virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
|
virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const;
|
||||||
|
|
||||||
|
virtual bool GTKNeedsToFilterSameWindowFocus() const { return true; }
|
||||||
|
|
||||||
virtual bool GTKWidgetNeedsMnemonic() const;
|
virtual bool GTKWidgetNeedsMnemonic() const;
|
||||||
virtual void GTKWidgetDoSetMnemonic(GtkWidget* w);
|
virtual void GTKWidgetDoSetMnemonic(GtkWidget* w);
|
||||||
|
|
||||||
// common part of all ctors
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_DYNAMIC_CLASS(wxRadioBox)
|
DECLARE_DYNAMIC_CLASS(wxRadioBox)
|
||||||
};
|
};
|
||||||
|
@@ -186,7 +186,17 @@ public:
|
|||||||
|
|
||||||
GdkWindow* GTKGetDrawingWindow() const;
|
GdkWindow* GTKGetDrawingWindow() const;
|
||||||
|
|
||||||
|
bool GTKHandleFocusIn();
|
||||||
|
bool GTKHandleFocusOut();
|
||||||
|
void GTKHandleFocusOutNoDeferring();
|
||||||
|
static void GTKHandleDeferredFocusOut();
|
||||||
|
|
||||||
protected:
|
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
|
// Override GTKWidgetNeedsMnemonic and return true if your
|
||||||
// needs to set its mnemonic widget, such as for a
|
// needs to set its mnemonic widget, such as for a
|
||||||
// GtkLabel for wxStaticText, then do the actual
|
// GtkLabel for wxStaticText, then do the actual
|
||||||
@@ -206,12 +216,6 @@ protected:
|
|||||||
// Check if the given window makes part of this widget
|
// Check if the given window makes part of this widget
|
||||||
bool GTKIsOwnWindow(GdkWindow *window) const;
|
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:
|
public:
|
||||||
// Returns the default context which usually is anti-aliased
|
// Returns the default context which usually is anti-aliased
|
||||||
PangoContext *GtkGetPangoDefaultContext();
|
PangoContext *GtkGetPangoDefaultContext();
|
||||||
@@ -287,7 +291,6 @@ public:
|
|||||||
bool m_noExpose:1; // wxGLCanvas has its own redrawing
|
bool m_noExpose:1; // wxGLCanvas has its own redrawing
|
||||||
bool m_nativeSizeEvent:1; // wxGLCanvas sends wxSizeEvent upon "alloc_size"
|
bool m_nativeSizeEvent:1; // wxGLCanvas sends wxSizeEvent upon "alloc_size"
|
||||||
bool m_hasVMT:1;
|
bool m_hasVMT:1;
|
||||||
bool m_hasFocus:1; // true if == FindFocus()
|
|
||||||
bool m_isScrolling:1; // dragging scrollbar thumb?
|
bool m_isScrolling:1; // dragging scrollbar thumb?
|
||||||
bool m_clipPaintRegion:1; // true after ScrollWindow()
|
bool m_clipPaintRegion:1; // true after ScrollWindow()
|
||||||
wxRegion m_nativeUpdateRegion; // not transformed for RTL
|
wxRegion m_nativeUpdateRegion; // not transformed for RTL
|
||||||
|
@@ -170,17 +170,6 @@ wxComboBox::~wxComboBox()
|
|||||||
delete m_strings;
|
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,
|
int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
|
||||||
unsigned int pos,
|
unsigned int pos,
|
||||||
void **clientData, wxClientDataType type)
|
void **clientData, wxClientDataType type)
|
||||||
|
@@ -295,8 +295,6 @@ void wxControl::OnInternalIdle()
|
|||||||
if ( GTK_WIDGET_REALIZED(m_widget) )
|
if ( GTK_WIDGET_REALIZED(m_widget) )
|
||||||
{
|
{
|
||||||
GTKUpdateCursor();
|
GTKUpdateCursor();
|
||||||
|
|
||||||
GTKSetDelayedFocusIfNeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( wxUpdateUIEvent::CanUpdate(this) )
|
if ( wxUpdateUIEvent::CanUpdate(this) )
|
||||||
|
@@ -258,7 +258,6 @@ IMPLEMENT_DYNAMIC_CLASS( wxGtkFileCtrl, wxControl )
|
|||||||
|
|
||||||
void wxGtkFileCtrl::Init()
|
void wxGtkFileCtrl::Init()
|
||||||
{
|
{
|
||||||
m_hasFocus = false;
|
|
||||||
m_checkNextSelEvent = false;
|
m_checkNextSelEvent = false;
|
||||||
|
|
||||||
// ignore the first folder change event which is fired upon startup.
|
// 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" {
|
extern "C" {
|
||||||
static gint gtk_radiobutton_focus_in( GtkWidget * WXUNUSED(widget),
|
static gint gtk_radiobutton_focus_out( GtkWidget * WXUNUSED(widget),
|
||||||
GdkEvent *WXUNUSED(event),
|
GdkEventFocus *WXUNUSED(event),
|
||||||
wxRadioBox *win )
|
wxRadioBox *win )
|
||||||
{
|
{
|
||||||
if ( win->m_lostFocus )
|
// NB: This control is composed of several GtkRadioButton widgets and
|
||||||
{
|
// when focus changes from one of them to another in the same
|
||||||
// no, we didn't really lose it
|
// wxRadioBox, we get a focus-out event followed by focus-in for
|
||||||
win->m_lostFocus = FALSE;
|
// another GtkRadioButton owned by the same control. We don't want
|
||||||
}
|
// to generate two spurious wxEVT_SET_FOCUS events in this case,
|
||||||
else if ( !win->m_hasFocus )
|
// so we defer sending wx events until idle time.
|
||||||
{
|
win->GTKHandleFocusOut();
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// never stop the signal emission, it seems to break the kbd handling
|
||||||
|
// inside the radiobox
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static gint gtk_radiobutton_focus_out( GtkWidget * WXUNUSED(widget),
|
static gint gtk_radiobutton_focus_in( GtkWidget * WXUNUSED(widget),
|
||||||
GdkEvent *WXUNUSED(event),
|
GdkEventFocus *WXUNUSED(event),
|
||||||
wxRadioBox *win )
|
wxRadioBox *win )
|
||||||
{
|
{
|
||||||
// wxASSERT_MSG( win->m_hasFocus, _T("got focus out without any focus in?") );
|
win->GTKHandleFocusIn();
|
||||||
// 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;
|
|
||||||
|
|
||||||
|
// never stop the signal emission, it seems to break the kbd handling
|
||||||
|
// inside the radiobox
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,12 +197,6 @@ static void gtk_radiobutton_size_allocate( GtkWidget *widget,
|
|||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxRadioBox,wxControl)
|
IMPLEMENT_DYNAMIC_CLASS(wxRadioBox,wxControl)
|
||||||
|
|
||||||
void wxRadioBox::Init()
|
|
||||||
{
|
|
||||||
m_hasFocus =
|
|
||||||
m_lostFocus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxRadioBox::Create( wxWindow *parent, wxWindowID id,
|
bool wxRadioBox::Create( wxWindow *parent, wxWindowID id,
|
||||||
const wxString& title,
|
const wxString& title,
|
||||||
const wxPoint &pos, const wxSize &size,
|
const wxPoint &pos, const wxSize &size,
|
||||||
@@ -372,25 +353,6 @@ bool wxRadioBox::Show( bool show )
|
|||||||
return true;
|
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 )
|
void wxRadioBox::SetSelection( int n )
|
||||||
{
|
{
|
||||||
wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
|
wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
|
||||||
@@ -646,22 +608,6 @@ GdkWindow *wxRadioBox::GTKGetWindow(wxArrayGdkWindows& windows) const
|
|||||||
return NULL;
|
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
|
// static
|
||||||
wxVisualAttributes
|
wxVisualAttributes
|
||||||
wxRadioBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
|
wxRadioBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
|
||||||
|
@@ -57,8 +57,6 @@
|
|||||||
// this is incremented while a modal dialog is shown
|
// this is incremented while a modal dialog is shown
|
||||||
int wxOpenModalDialogsCount = 0;
|
int wxOpenModalDialogsCount = 0;
|
||||||
|
|
||||||
extern wxWindowGTK *g_delayedFocus;
|
|
||||||
|
|
||||||
// the frame that is currently active (i.e. its child has focus). It is
|
// the frame that is currently active (i.e. its child has focus). It is
|
||||||
// used to generate wxActivateEvents
|
// used to generate wxActivateEvents
|
||||||
static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
|
static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
|
||||||
@@ -1032,22 +1030,6 @@ void wxTopLevelWindowGTK::GTKUpdateDecorSize(const wxSize& decorSize)
|
|||||||
|
|
||||||
void wxTopLevelWindowGTK::OnInternalIdle()
|
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();
|
wxWindow::OnInternalIdle();
|
||||||
|
|
||||||
// Synthetize activate events.
|
// Synthetize activate events.
|
||||||
|
@@ -185,11 +185,13 @@ extern wxCursor g_globalCursor;
|
|||||||
static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
|
static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
|
||||||
static bool g_captureWindowHasMouse = false;
|
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
|
// the window that has deferred focus-out event pending, if any (see
|
||||||
// yet, defer setting the focus to idle time.
|
// GTKAddDeferredFocusOut() for details)
|
||||||
wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
|
static wxWindowGTK *gs_deferredFocusOut = NULL;
|
||||||
|
|
||||||
// global variables because GTK+ DnD want to have the
|
// global variables because GTK+ DnD want to have the
|
||||||
// mouse event that caused it
|
// 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
|
// "size_request" of m_widget
|
||||||
@@ -1251,21 +1228,6 @@ wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
|
|||||||
if ( rc != -1 ) \
|
if ( rc != -1 ) \
|
||||||
return rc
|
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
|
// all event handlers must have C linkage as they're called from GTK+ C code
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@@ -1410,7 +1372,7 @@ gtk_window_button_press_callback( GtkWidget *widget,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
|
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
|
||||||
(g_focusWindow != win) /* && win->IsFocusable() */)
|
(gs_focusWindow != win) /* && win->IsFocusable() */)
|
||||||
{
|
{
|
||||||
win->SetFocus();
|
win->SetFocus();
|
||||||
}
|
}
|
||||||
@@ -1610,44 +1572,9 @@ static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
|
|||||||
static gboolean
|
static gboolean
|
||||||
gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
|
gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
|
||||||
GdkEventFocus *WXUNUSED(event),
|
GdkEventFocus *WXUNUSED(event),
|
||||||
wxWindow *win )
|
wxWindowGTK *win )
|
||||||
{
|
{
|
||||||
if (win->m_imData)
|
return win->GTKHandleFocusIn();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -1659,53 +1586,13 @@ gtk_window_focus_out_callback( GtkWidget * WXUNUSED(widget),
|
|||||||
GdkEventFocus * WXUNUSED(gdk_event),
|
GdkEventFocus * WXUNUSED(gdk_event),
|
||||||
wxWindowGTK *win )
|
wxWindowGTK *win )
|
||||||
{
|
{
|
||||||
if (win->m_imData)
|
return win->GTKHandleFocusOut();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// "focus"
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
wx_window_focus_callback(GtkWidget *widget,
|
wx_window_focus_callback(GtkWidget *widget,
|
||||||
GtkDirectionType WXUNUSED(direction),
|
GtkDirectionType WXUNUSED(direction),
|
||||||
@@ -2005,7 +1892,7 @@ public:
|
|||||||
wxWindow *wxWindowBase::DoFindFocus()
|
wxWindow *wxWindowBase::DoFindFocus()
|
||||||
{
|
{
|
||||||
// the cast is necessary when we compile in wxUniversal mode
|
// 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_insertCallback = wxInsertChildInWindow;
|
||||||
|
|
||||||
m_hasFocus = false;
|
|
||||||
|
|
||||||
m_clipPaintRegion = false;
|
m_clipPaintRegion = false;
|
||||||
|
|
||||||
m_needsStyleChange = false;
|
m_needsStyleChange = false;
|
||||||
@@ -2251,11 +2136,11 @@ wxWindowGTK::~wxWindowGTK()
|
|||||||
{
|
{
|
||||||
SendDestroyEvent();
|
SendDestroyEvent();
|
||||||
|
|
||||||
if (g_focusWindow == this)
|
if (gs_focusWindow == this)
|
||||||
g_focusWindow = NULL;
|
gs_focusWindow = NULL;
|
||||||
|
|
||||||
if ( g_delayedFocus == this )
|
if ( gs_deferredFocusOut == this )
|
||||||
g_delayedFocus = NULL;
|
gs_deferredFocusOut = NULL;
|
||||||
|
|
||||||
m_isBeingDeleted = true;
|
m_isBeingDeleted = true;
|
||||||
m_hasVMT = false;
|
m_hasVMT = false;
|
||||||
@@ -2614,6 +2499,9 @@ bool wxWindowGTK::GtkShowFromOnIdle()
|
|||||||
|
|
||||||
void wxWindowGTK::OnInternalIdle()
|
void wxWindowGTK::OnInternalIdle()
|
||||||
{
|
{
|
||||||
|
if ( gs_deferredFocusOut )
|
||||||
|
GTKHandleDeferredFocusOut();
|
||||||
|
|
||||||
// Check if we have to show window now
|
// Check if we have to show window now
|
||||||
if (GtkShowFromOnIdle()) return;
|
if (GtkShowFromOnIdle()) return;
|
||||||
|
|
||||||
@@ -2979,90 +2867,194 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
|
|||||||
g_object_unref (layout);
|
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()
|
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)
|
// Setting "physical" focus is not immediate in GTK+ and while
|
||||||
{
|
// gtk_widget_is_focus ("determines if the widget is the focus widget
|
||||||
// wxWindow::SetFocus() should really set the focus to
|
// within its toplevel", i.e. returns true for one widget per TLW, not
|
||||||
// this control, whatever the flags are
|
// globally) returns true immediately after grabbing focus,
|
||||||
if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow))
|
// GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
|
||||||
GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
|
// 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))
|
GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
|
||||||
{
|
|
||||||
gtk_widget_grab_focus (m_wxwindow);
|
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
|
else
|
||||||
{
|
{
|
||||||
// wxWindow::SetFocus() should really set the focus to
|
wxLogTrace(TRACE_FOCUS,
|
||||||
// this control, whatever the flags are
|
_T("Setting focus to %s(%p, %s)"),
|
||||||
if (!GTK_WIDGET_CAN_FOCUS(m_widget))
|
GetClassInfo()->GetClassName(), this, GetLabel().c_str());
|
||||||
GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
|
gtk_widget_grab_focus(widget);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user