Merge branch 'gtk-enter-leave-window'
Fixes for wxGTK enter/leave window events. Closes #11848. See #24339.
This commit is contained in:
commit
b03ce7711b
37 changed files with 360 additions and 104 deletions
|
|
@ -88,6 +88,23 @@ template<typename T> void InitMouseEvent(wxWindowGTK *win,
|
|||
event.SetTimestamp( gdk_event->time );
|
||||
}
|
||||
|
||||
// Update the window currently known to be under the mouse pointer.
|
||||
//
|
||||
// Returns true if it was updated, false if this window was already known to
|
||||
// contain the mouse pointer.
|
||||
bool SetWindowUnderMouse(wxWindowGTK* win);
|
||||
|
||||
// Implementation of enter/leave window callbacks.
|
||||
gboolean
|
||||
WindowEnterCallback(GtkWidget* widget,
|
||||
GdkEventCrossing* event,
|
||||
wxWindowGTK* win);
|
||||
|
||||
gboolean
|
||||
WindowLeaveCallback(GtkWidget* widget,
|
||||
GdkEventCrossing* event,
|
||||
wxWindowGTK* win);
|
||||
|
||||
} // namespace wxGTKImpl
|
||||
|
||||
#endif // _GTK_PRIVATE_EVENT_H_
|
||||
|
|
|
|||
|
|
@ -171,14 +171,9 @@ public:
|
|||
virtual GtkWidget* GetConnectWidget();
|
||||
void ConnectWidget( GtkWidget *widget );
|
||||
|
||||
// Called from several event handlers, if it returns true or false, the
|
||||
// same value should be immediately returned by the handler without doing
|
||||
// anything else. If it returns -1, the handler should continue as usual
|
||||
int GTKCallbackCommonPrologue(struct _GdkEventAny *event) const;
|
||||
|
||||
// Simplified form of GTKCallbackCommonPrologue() which can be used from
|
||||
// GTK callbacks without return value to check if the event should be
|
||||
// ignored: if this returns true, the event shouldn't be handled
|
||||
// Returns true if GTK callbacks are blocked due to a drag event being in
|
||||
// progress.
|
||||
bool GTKShouldIgnoreEvent() const;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ void ActivityIndicatorWidgetsPage::RecreateWidget()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
GetAttrs().m_defaultFlags);
|
||||
|
||||
NotifyWidgetRecreation(m_indicator);
|
||||
|
||||
m_sizerIndicator->AddStretchSpacer();
|
||||
m_sizerIndicator->Add(m_indicator, wxSizerFlags().Centre());
|
||||
m_sizerIndicator->AddStretchSpacer();
|
||||
|
|
|
|||
|
|
@ -478,6 +478,8 @@ void BitmapComboBoxWidgetsPage::CreateCombo()
|
|||
m_combobox->SetPopupMaxHeight(600);
|
||||
#endif
|
||||
|
||||
NotifyWidgetRecreation(m_combobox);
|
||||
|
||||
unsigned int count = items.GetCount();
|
||||
for ( unsigned int n = 0; n < count; n++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -562,6 +562,8 @@ void ButtonWidgetsPage::CreateButton()
|
|||
m_sizerNote->Show(m_chkCommandLink->GetValue());
|
||||
#endif
|
||||
|
||||
NotifyWidgetRecreation(m_button);
|
||||
|
||||
if ( !showsBitmap && m_chkTextAndBitmap->GetValue() )
|
||||
{
|
||||
showsBitmap = true;
|
||||
|
|
|
|||
|
|
@ -276,6 +276,8 @@ void CheckBoxWidgetsPage::CreateCheckbox()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_checkbox);
|
||||
|
||||
m_sizerCheckbox->Add(0, 0, 1, wxCENTRE);
|
||||
m_sizerCheckbox->Add(m_checkbox, 1, wxCENTRE);
|
||||
m_sizerCheckbox->Add(0, 0, 1, wxCENTRE);
|
||||
|
|
|
|||
|
|
@ -303,6 +303,8 @@ void ChoiceWidgetsPage::CreateChoice()
|
|||
0, nullptr,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_choice);
|
||||
|
||||
m_choice->Set(items);
|
||||
m_sizerChoice->Add(m_choice, 0, wxGROW | wxALL, 5);
|
||||
m_sizerChoice->Layout();
|
||||
|
|
|
|||
|
|
@ -191,6 +191,8 @@ void ColourPickerWidgetsPage::CreatePicker()
|
|||
m_clrPicker = new wxColourPickerCtrl(this, PickerPage_Colour, *wxRED,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_clrPicker);
|
||||
}
|
||||
|
||||
void ColourPickerWidgetsPage::RecreatePicker()
|
||||
|
|
|
|||
|
|
@ -476,6 +476,8 @@ void ComboboxWidgetsPage::CreateCombo()
|
|||
delete m_combobox;
|
||||
m_combobox = newCb;
|
||||
m_combobox->SetId(ComboPage_Combo);
|
||||
|
||||
NotifyWidgetRecreation(m_combobox);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -285,6 +285,8 @@ void DatePickerWidgetsPage::CreateDatePicker()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_datePicker);
|
||||
|
||||
m_sizerDatePicker->Add(0, 0, 1, wxCENTRE);
|
||||
m_sizerDatePicker->Add(m_datePicker, 1, wxCENTRE);
|
||||
m_sizerDatePicker->Add(0, 0, 1, wxCENTRE);
|
||||
|
|
|
|||
|
|
@ -302,6 +302,8 @@ void DirCtrlWidgetsPage::CreateDirCtrl(bool defaultPath)
|
|||
delete m_dirCtrl;
|
||||
m_dirCtrl = dirCtrl;
|
||||
|
||||
NotifyWidgetRecreation(m_dirCtrl);
|
||||
|
||||
// relayout the sizer
|
||||
GetSizer()->Layout();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,6 +209,8 @@ void DirPickerWidgetsPage::CreatePicker()
|
|||
wxGetHomeDir(), "Hello!",
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_dirPicker);
|
||||
}
|
||||
|
||||
void DirPickerWidgetsPage::RecreatePicker()
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ void EditableListboxWidgetsPage::CreateLbox()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_lbox);
|
||||
|
||||
m_lbox->SetStrings(items);
|
||||
m_sizerLbox->Add(m_lbox, 1, wxGROW | wxALL, 5);
|
||||
m_sizerLbox->Layout();
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ void FileCtrlWidgetsPage::CreateFileCtrl()
|
|||
delete m_fileCtrl;
|
||||
m_fileCtrl = fileCtrl;
|
||||
|
||||
NotifyWidgetRecreation(m_fileCtrl);
|
||||
|
||||
// relayout the sizer
|
||||
GetSizer()->Layout();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ void FilePickerWidgetsPage::CreatePicker()
|
|||
"Hello!", "*",
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_filePicker);
|
||||
}
|
||||
|
||||
void FilePickerWidgetsPage::RecreatePicker()
|
||||
|
|
|
|||
|
|
@ -186,6 +186,8 @@ void FontPickerWidgetsPage::CreatePicker()
|
|||
*wxSWISS_FONT,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_fontPicker);
|
||||
}
|
||||
|
||||
void FontPickerWidgetsPage::RecreatePicker()
|
||||
|
|
|
|||
|
|
@ -307,6 +307,9 @@ void GaugeWidgetsPage::CreateGauge()
|
|||
m_gauge = new wxGauge(this, GaugePage_Gauge, m_range,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_gauge);
|
||||
|
||||
m_gauge->SetValue(val);
|
||||
|
||||
if ( flags & wxGA_VERTICAL )
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ void HeaderCtrlWidgetsPage::RecreateWidget()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_header);
|
||||
|
||||
m_header->Bind(wxEVT_HEADER_RESIZING, &HeaderCtrlWidgetsPage::OnResizing, this);
|
||||
m_header->Bind(wxEVT_HEADER_BEGIN_RESIZE, &HeaderCtrlWidgetsPage::OnBeginResize, this);
|
||||
m_header->Bind(wxEVT_HEADER_END_RESIZE, &HeaderCtrlWidgetsPage::OnEndResize, this);
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ void HyperlinkWidgetsPage::CreateHyperlink()
|
|||
delete m_hyperlink;
|
||||
m_hyperlink = hyp;
|
||||
|
||||
NotifyWidgetRecreation(m_hyperlink);
|
||||
|
||||
// relayout the sizer
|
||||
GetSizer()->Layout();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,6 +506,8 @@ void ListboxWidgetsPage::CreateLbox()
|
|||
flags);
|
||||
}
|
||||
|
||||
NotifyWidgetRecreation(m_lbox);
|
||||
|
||||
m_sizerLbox->Add(m_lbox, 1, wxGROW | wxALL, 5);
|
||||
m_sizerLbox->Layout();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ void NativeWidgetsPage::RecreateWidget()
|
|||
delete m_nativeWindow;
|
||||
m_nativeWindow = new NativeWindow(this);
|
||||
|
||||
NotifyWidgetRecreation(m_nativeWindow);
|
||||
|
||||
m_sizerCtrl->Clear();
|
||||
if ( m_chkExpand->IsChecked() )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -365,6 +365,8 @@ void BookWidgetsPage::RecreateBook()
|
|||
|
||||
m_book = CreateBook(flags);
|
||||
|
||||
NotifyWidgetRecreation(m_book);
|
||||
|
||||
CreateImageList();
|
||||
|
||||
if ( oldBook )
|
||||
|
|
|
|||
|
|
@ -527,6 +527,8 @@ void ODComboboxWidgetsPage::CreateCombo()
|
|||
0, nullptr,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_combobox);
|
||||
|
||||
unsigned int count = items.GetCount();
|
||||
for ( unsigned int n = 0; n < count; n++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -358,6 +358,8 @@ void RadioWidgetsPage::CreateRadio()
|
|||
majorDim,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_radio);
|
||||
|
||||
if ( sel >= 0 && (size_t)sel < count )
|
||||
{
|
||||
m_radio->SetSelection(sel);
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ void SearchCtrlWidgetsPage::CreateControl()
|
|||
|
||||
m_srchCtrl = new wxSearchCtrl(this, -1, wxEmptyString, wxDefaultPosition,
|
||||
FromDIP(wxSize(150, -1)), style);
|
||||
|
||||
NotifyWidgetRecreation(m_srchCtrl);
|
||||
}
|
||||
|
||||
void SearchCtrlWidgetsPage::RecreateWidget()
|
||||
|
|
|
|||
|
|
@ -517,6 +517,8 @@ void SliderWidgetsPage::CreateSlider()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_slider);
|
||||
|
||||
if ( m_slider->HasFlag(wxSL_VERTICAL) )
|
||||
{
|
||||
m_sizerSlider->AddStretchSpacer(1);
|
||||
|
|
|
|||
|
|
@ -416,6 +416,8 @@ void SpinBtnWidgetsPage::CreateSpin()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
|
||||
NotifyWidgetRecreation(m_spinbtn);
|
||||
|
||||
m_spinbtn->SetValue(val);
|
||||
m_spinbtn->SetRange(m_min, m_max);
|
||||
|
||||
|
|
@ -425,12 +427,16 @@ void SpinBtnWidgetsPage::CreateSpin()
|
|||
flags | textFlags,
|
||||
m_min, m_max, val);
|
||||
|
||||
NotifyWidgetRecreation(m_spinctrl);
|
||||
|
||||
m_spinctrldbl = new wxSpinCtrlDouble(this, SpinBtnPage_SpinCtrlDouble,
|
||||
wxString::Format("%d", val),
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
flags | textFlags,
|
||||
m_min, m_max, val, 0.1);
|
||||
|
||||
NotifyWidgetRecreation(m_spinctrldbl);
|
||||
|
||||
// Add spacers, labels and spin controls to the sizer.
|
||||
m_sizerSpin->Add(0, 0, 1);
|
||||
m_sizerSpin->Add(new wxStaticText(this, wxID_ANY, "wxSpinButton"),
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ void StatBmpWidgetsPage::RecreateWidget()
|
|||
style);
|
||||
}
|
||||
|
||||
NotifyWidgetRecreation(m_statbmp);
|
||||
|
||||
wxStaticBitmapBase::ScaleMode scaleMode = (wxStaticBitmapBase::ScaleMode) m_scaleRadio->GetSelection();
|
||||
m_statbmp->SetScaleMode(scaleMode);
|
||||
if ( m_statbmp->GetScaleMode() != scaleMode )
|
||||
|
|
|
|||
|
|
@ -525,9 +525,13 @@ void StaticWidgetsPage::CreateStatic()
|
|||
#endif // wxUSE_MARKUP
|
||||
}
|
||||
|
||||
NotifyWidgetRecreation(m_statText);
|
||||
|
||||
m_statText->SetToolTip("Tooltip for a label inside the box");
|
||||
|
||||
#if wxUSE_MARKUP
|
||||
NotifyWidgetRecreation(m_statMarkup);
|
||||
|
||||
m_statMarkup->SetLabelMarkup(m_textLabelWithMarkup->GetValue());
|
||||
|
||||
if ( m_chkGreen->GetValue() )
|
||||
|
|
@ -538,6 +542,8 @@ void StaticWidgetsPage::CreateStatic()
|
|||
m_statLine = new wxStaticLine(staticBox, wxID_ANY,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
isVert ? wxLI_VERTICAL : wxLI_HORIZONTAL);
|
||||
|
||||
NotifyWidgetRecreation(m_statLine);
|
||||
#endif // wxUSE_STATLINE
|
||||
|
||||
m_sizerStatBox->Add(m_statText, 0, wxGROW);
|
||||
|
|
|
|||
|
|
@ -787,6 +787,8 @@ void TextWidgetsPage::CreateText()
|
|||
|
||||
m_text = new WidgetsTextCtrl(m_sizerText->GetStaticBox(), TextPage_Textctrl, valueOld, flags);
|
||||
|
||||
NotifyWidgetRecreation(m_text);
|
||||
|
||||
#if 0
|
||||
if ( m_chkFilename->GetValue() )
|
||||
;
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ void TimePickerWidgetsPage::CreateTimePicker()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
style);
|
||||
|
||||
NotifyWidgetRecreation(m_timePicker);
|
||||
|
||||
m_sizerTimePicker->Add(0, 0, 1, wxCENTRE);
|
||||
m_sizerTimePicker->Add(m_timePicker, 1, wxCENTRE);
|
||||
m_sizerTimePicker->Add(0, 0, 1, wxCENTRE);
|
||||
|
|
|
|||
|
|
@ -461,6 +461,9 @@ void ToggleWidgetsPage::CreateToggle()
|
|||
wxDefaultPosition, wxDefaultSize,
|
||||
flags);
|
||||
}
|
||||
|
||||
NotifyWidgetRecreation(m_toggle);
|
||||
|
||||
m_toggle->SetValue(value);
|
||||
|
||||
#ifdef wxHAS_BITMAPTOGGLEBUTTON
|
||||
|
|
|
|||
|
|
@ -183,6 +183,10 @@ public:
|
|||
// real implementation of WidgetsPage method with the same name
|
||||
bool IsUsingLogWindow() const;
|
||||
|
||||
// connects handlers showing some interesting widget events to the given
|
||||
// widget
|
||||
void ConnectToWidgetEvents(wxWindow* w);
|
||||
|
||||
private:
|
||||
#if USE_LOG
|
||||
wxLog* m_logTarget;
|
||||
|
|
@ -253,11 +257,6 @@ protected:
|
|||
WidgetsPage *CurrentPage();
|
||||
|
||||
private:
|
||||
void OnWidgetFocus(wxFocusEvent& event);
|
||||
void OnWidgetContextMenu(wxContextMenuEvent& event);
|
||||
|
||||
void ConnectToWidgetEvents();
|
||||
|
||||
// the panel containing everything
|
||||
wxPanel *m_panel;
|
||||
|
||||
|
|
@ -430,6 +429,51 @@ bool WidgetsApp::IsUsingLogWindow() const
|
|||
#endif // USE_LOG
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void OnFocus(wxFocusEvent& event)
|
||||
{
|
||||
// Don't show annoying message boxes when starting or closing the sample,
|
||||
// only log these events in our own logger.
|
||||
if ( wxGetApp().IsUsingLogWindow() )
|
||||
{
|
||||
wxWindow* win = (wxWindow*)event.GetEventObject();
|
||||
wxLogMessage("Widget '%s' %s focus", win->GetClassInfo()->GetClassName(),
|
||||
event.GetEventType() == wxEVT_SET_FOCUS ? "got" : "lost");
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void WidgetsApp::ConnectToWidgetEvents(wxWindow* w)
|
||||
{
|
||||
w->Bind(wxEVT_SET_FOCUS, OnFocus);
|
||||
w->Bind(wxEVT_KILL_FOCUS, OnFocus);
|
||||
|
||||
w->Bind(wxEVT_ENTER_WINDOW, [w](wxMouseEvent& event)
|
||||
{
|
||||
wxLogMessage("Mouse entered into '%s'", w->GetClassInfo()->GetClassName());
|
||||
event.Skip();
|
||||
});
|
||||
w->Bind(wxEVT_LEAVE_WINDOW, [w](wxMouseEvent& event)
|
||||
{
|
||||
wxLogMessage("Mouse left '%s'", w->GetClassInfo()->GetClassName());
|
||||
event.Skip();
|
||||
});
|
||||
|
||||
w->Bind(wxEVT_CONTEXT_MENU, [w](wxContextMenuEvent& event)
|
||||
{
|
||||
wxLogMessage("Context menu event for '%s' at %dx%d",
|
||||
w->GetClassInfo()->GetClassName(),
|
||||
event.GetPosition().x,
|
||||
event.GetPosition().y);
|
||||
event.Skip();
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WidgetsFrame construction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -727,24 +771,6 @@ WidgetsPage *WidgetsFrame::CurrentPage()
|
|||
return wxStaticCast(page, WidgetsPage);
|
||||
}
|
||||
|
||||
void WidgetsFrame::ConnectToWidgetEvents()
|
||||
{
|
||||
const Widgets& widgets = CurrentPage()->GetWidgets();
|
||||
|
||||
for ( Widgets::const_iterator it = widgets.begin();
|
||||
it != widgets.end();
|
||||
++it )
|
||||
{
|
||||
wxWindow* const w = *it;
|
||||
wxCHECK_RET(w, "null widget");
|
||||
|
||||
w->Bind(wxEVT_SET_FOCUS, &WidgetsFrame::OnWidgetFocus, this);
|
||||
w->Bind(wxEVT_KILL_FOCUS, &WidgetsFrame::OnWidgetFocus, this);
|
||||
|
||||
w->Bind(wxEVT_CONTEXT_MENU, &WidgetsFrame::OnWidgetContextMenu, this);
|
||||
}
|
||||
}
|
||||
|
||||
WidgetsFrame::~WidgetsFrame()
|
||||
{
|
||||
#if USE_LOG
|
||||
|
|
@ -802,7 +828,18 @@ void WidgetsFrame::OnPageChanged(WidgetsBookCtrlEvent& event)
|
|||
curPage->SetScrollRate(10, 10);
|
||||
curPage->FitInside();
|
||||
|
||||
ConnectToWidgetEvents();
|
||||
auto& app = wxGetApp();
|
||||
for ( const auto w : CurrentPage()->GetWidgets() )
|
||||
{
|
||||
app.ConnectToWidgetEvents(w);
|
||||
}
|
||||
|
||||
// From now on, we're interested in these notifications as we'll need
|
||||
// to reconnect to the widget events if it's recreated (unfortunately
|
||||
// we can't rely getting them on creation as some page don't generate
|
||||
// them -- but neither can we rely on not getting them as some pages do
|
||||
// generate them, hence the use of m_notifyRecreate flag).
|
||||
curPage->EnableRecreationNotifications();
|
||||
}
|
||||
|
||||
// re-apply the attributes to the widget(s)
|
||||
|
|
@ -971,11 +1008,6 @@ void WidgetsFrame::OnSetBorder(wxCommandEvent& event)
|
|||
WidgetsPage *page = CurrentPage();
|
||||
|
||||
page->RecreateWidget();
|
||||
|
||||
ConnectToWidgetEvents();
|
||||
|
||||
// re-apply the attributes to the widget(s)
|
||||
page->SetUpWidget();
|
||||
}
|
||||
|
||||
void WidgetsFrame::OnSetVariant(wxCommandEvent& event)
|
||||
|
|
@ -1259,31 +1291,6 @@ void WidgetsFrame::OnSetHint(wxCommandEvent& WXUNUSED(event))
|
|||
|
||||
#endif // wxUSE_MENUS
|
||||
|
||||
void WidgetsFrame::OnWidgetFocus(wxFocusEvent& event)
|
||||
{
|
||||
// Don't show annoying message boxes when starting or closing the sample,
|
||||
// only log these events in our own logger.
|
||||
if ( wxGetApp().IsUsingLogWindow() )
|
||||
{
|
||||
wxWindow* win = (wxWindow*)event.GetEventObject();
|
||||
wxLogMessage("Widget '%s' %s focus", win->GetClassInfo()->GetClassName(),
|
||||
event.GetEventType() == wxEVT_SET_FOCUS ? "got" : "lost");
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WidgetsFrame::OnWidgetContextMenu(wxContextMenuEvent& event)
|
||||
{
|
||||
wxWindow* win = (wxWindow*)event.GetEventObject();
|
||||
wxLogMessage("Context menu event for %s at %dx%d",
|
||||
win->GetClassInfo()->GetClassName(),
|
||||
event.GetPosition().x,
|
||||
event.GetPosition().y);
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WidgetsPageInfo
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -1462,6 +1469,19 @@ wxCheckBox *WidgetsPage::CreateCheckBoxAndAddToSizer(wxSizer *sizer,
|
|||
return checkbox;
|
||||
}
|
||||
|
||||
void WidgetsPage::NotifyWidgetRecreation(wxWindow* widget)
|
||||
{
|
||||
if ( !m_notifyRecreate )
|
||||
{
|
||||
// We're in the process of initialization, don't notify yet.
|
||||
return;
|
||||
}
|
||||
|
||||
SetUpWidget();
|
||||
|
||||
wxGetApp().ConnectToWidgetEvents(widget);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WidgetsPage::IsUsingLogWindow()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,6 +149,13 @@ public:
|
|||
// this is currently used only to take into account the border flags
|
||||
virtual void RecreateWidget() = 0;
|
||||
|
||||
// notify the main window about the widget recreation if it didn't happen
|
||||
// due to a call to RecreateWidget()
|
||||
void NotifyWidgetRecreation(wxWindow* widget);
|
||||
|
||||
// enable notifications about the widget recreation disabled initially
|
||||
void EnableRecreationNotifications() { m_notifyRecreate = true; }
|
||||
|
||||
// apply current attributes to the widget(s)
|
||||
void SetUpWidget();
|
||||
|
||||
|
|
@ -191,6 +198,9 @@ protected:
|
|||
public:
|
||||
// the head of the linked list containinginfo about all pages
|
||||
static WidgetsPageInfo *ms_widgetPages;
|
||||
|
||||
private:
|
||||
bool m_notifyRecreate = false;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#endif
|
||||
|
||||
#include "wx/gtk/private.h"
|
||||
#include "wx/gtk/private/event.h"
|
||||
#include "wx/gtk/private/eventsdisabler.h"
|
||||
#include "wx/gtk/private/list.h"
|
||||
#include "wx/gtk/private/value.h"
|
||||
|
|
@ -33,6 +34,26 @@ gtk_choice_changed_callback( GtkWidget *WXUNUSED(widget), wxChoice *choice )
|
|||
choice->SendSelectionChangedEvent(wxEVT_CHOICE);
|
||||
}
|
||||
|
||||
#ifdef __WXGTK3__
|
||||
|
||||
static gboolean
|
||||
wx_gtk_choice_enter_notify(GtkWidget* widget,
|
||||
GdkEventCrossing* gdk_event,
|
||||
wxChoice *choice)
|
||||
{
|
||||
return wxGTKImpl::WindowEnterCallback(widget, gdk_event, choice);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wx_gtk_choice_leave_notify(GtkWidget* widget,
|
||||
GdkEventCrossing* gdk_event,
|
||||
wxChoice* choice)
|
||||
{
|
||||
return wxGTKImpl::WindowLeaveCallback(widget, gdk_event, choice);
|
||||
}
|
||||
|
||||
#endif // __WXGTK3__
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -104,6 +125,35 @@ bool wxChoice::Create( wxWindow *parent, wxWindowID id,
|
|||
g_signal_connect_after (m_widget, "changed",
|
||||
G_CALLBACK (gtk_choice_changed_callback), this);
|
||||
|
||||
#ifdef __WXGTK3__
|
||||
// Internal structure of GtkComboBoxText is complicated: it contains a
|
||||
// GtkBox which contains a GtkToggleButton which contains another GtkBox
|
||||
// which, in turn, contains GtkCellView (and more).
|
||||
//
|
||||
// And it's this internal GtkToggleButton which receives the mouse events
|
||||
// and not the main widget itself, so find it and connect to its events.
|
||||
|
||||
// We could find it either by using gtk_container_forall() to get the box
|
||||
// inside GtkComboBoxText and then get its only child, or by doing what we
|
||||
// do here and getting GtkCellView directly and then getting its parent,
|
||||
// which is simpler because GtkComboBoxText sets things up in such a way
|
||||
// that its only child is the GtkCellView (even if, again, this is not how
|
||||
// things really are internally).
|
||||
auto cellView = gtk_bin_get_child(GTK_BIN(m_widget));
|
||||
wxCHECK_MSG( cellView, true, "No cell view in GtkComboBoxText?" );
|
||||
|
||||
auto box = gtk_widget_get_parent(cellView);
|
||||
|
||||
auto button = gtk_widget_get_parent(box);
|
||||
wxCHECK_MSG( GTK_IS_TOGGLE_BUTTON(button), true,
|
||||
"Unexpected grandparent of GtkCellView in GtkComboBoxText" );
|
||||
|
||||
g_signal_connect(button, "enter_notify_event",
|
||||
G_CALLBACK(wx_gtk_choice_enter_notify), this);
|
||||
g_signal_connect(button, "leave_notify_event",
|
||||
G_CALLBACK(wx_gtk_choice_leave_notify), this);
|
||||
#endif // __WXGTK3__
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "wx/utils.h"
|
||||
#include "wx/gtk/private.h"
|
||||
#include "wx/gtk/private/event.h"
|
||||
#include "wx/gtk/private/gtk3-compat.h"
|
||||
|
||||
|
||||
|
|
@ -93,6 +94,28 @@ wx_gtk_icon_press(GtkEntry* WXUNUSED(entry),
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wx_gtk_entry_event(GtkEntry* WXUNUSED(entry),
|
||||
GdkEvent* event,
|
||||
wxSearchCtrl* ctrl)
|
||||
{
|
||||
if ( event->type == GDK_MOTION_NOTIFY )
|
||||
{
|
||||
// GtkEntry "event" signal handler ignores motion events happening over
|
||||
// inactive icons, but we want to notify the window about the mouse
|
||||
// entering it when they happen.
|
||||
if ( wxGTKImpl::SetWindowUnderMouse(ctrl) )
|
||||
{
|
||||
wxMouseEvent mouseEvent(wxEVT_ENTER_WINDOW);
|
||||
wxGTKImpl::InitMouseEvent(ctrl, mouseEvent, (GdkEventMotion*)event);
|
||||
|
||||
ctrl->GTKProcessEvent(mouseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -209,6 +232,8 @@ void wxSearchCtrl::GTKCreateSearchEntryWidget()
|
|||
}
|
||||
|
||||
g_signal_connect(m_entry, "icon-press", G_CALLBACK(wx_gtk_icon_press), this);
|
||||
|
||||
g_signal_connect(m_entry, "event", G_CALLBACK(wx_gtk_entry_event), this);
|
||||
}
|
||||
|
||||
GtkEditable *wxSearchCtrl::GetEditable() const
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ typedef guint KeySym;
|
|||
#define PANGO_VERSION_CHECK(a,b,c) 0
|
||||
#endif
|
||||
|
||||
constexpr const char* TRACE_MOUSE = "mouse";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// documentation on internals
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -232,6 +234,23 @@ static wxWindowGTK *gs_deferredFocusOut = nullptr;
|
|||
GdkEvent *g_lastMouseEvent = nullptr;
|
||||
int g_lastButtonNumber = 0;
|
||||
|
||||
static wxWindowGTK* g_windowUnderMouse = nullptr;
|
||||
|
||||
namespace wxGTKImpl
|
||||
{
|
||||
|
||||
bool SetWindowUnderMouse(wxWindowGTK* win)
|
||||
{
|
||||
if ( g_windowUnderMouse == win )
|
||||
return false;
|
||||
|
||||
g_windowUnderMouse = win;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wxGTKImpl
|
||||
|
||||
#ifdef wxHAS_XKB
|
||||
namespace
|
||||
{
|
||||
|
|
@ -1667,38 +1686,19 @@ bool wxWindowGTK::GTKShouldIgnoreEvent() const
|
|||
return g_blockEventsOnDrag;
|
||||
}
|
||||
|
||||
int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
|
||||
// Some callbacks check for just g_blockEventsOnDrag but others check for both
|
||||
// it and g_blockEventsOnScroll. It's not really clear why, but define a helper
|
||||
// function performing the latter check too for now to avoid changing the
|
||||
// behaviour of the existing code.
|
||||
namespace
|
||||
{
|
||||
if (g_blockEventsOnDrag)
|
||||
return TRUE;
|
||||
if (g_blockEventsOnScroll)
|
||||
return TRUE;
|
||||
|
||||
if (!GTKIsOwnWindow(event->window))
|
||||
return FALSE;
|
||||
|
||||
return -1;
|
||||
bool AreGTKEventsBlocked()
|
||||
{
|
||||
return g_blockEventsOnDrag || g_blockEventsOnScroll;
|
||||
}
|
||||
|
||||
// overloads for all GDK event types we use here: we need to have this as
|
||||
// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
|
||||
// derives from it in the sense that the structs have the same layout
|
||||
#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
|
||||
static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
|
||||
{ \
|
||||
return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
|
||||
}
|
||||
|
||||
wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton)
|
||||
wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion)
|
||||
wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
|
||||
|
||||
#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
|
||||
|
||||
#define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
|
||||
const int rc = wxGtkCallbackCommonPrologue(event, win); \
|
||||
if ( rc != -1 ) \
|
||||
return rc
|
||||
} // anonymous namespace
|
||||
|
||||
// all event handlers must have C linkage as they're called from GTK+ C code
|
||||
extern "C"
|
||||
|
|
@ -1722,7 +1722,8 @@ gtk_window_button_press_callback( GtkWidget* WXUNUSED_IN_GTK3(widget),
|
|||
|
||||
wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
|
||||
|
||||
wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
|
||||
if ( AreGTKEventsBlocked() )
|
||||
return FALSE;
|
||||
|
||||
g_lastButtonNumber = gdk_event->button;
|
||||
|
||||
|
|
@ -1856,7 +1857,8 @@ gtk_window_button_release_callback( GtkWidget *WXUNUSED(widget),
|
|||
{
|
||||
wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
|
||||
|
||||
wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
|
||||
if ( AreGTKEventsBlocked() )
|
||||
return FALSE;
|
||||
|
||||
g_lastButtonNumber = 0;
|
||||
|
||||
|
|
@ -1958,7 +1960,8 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
|
|||
{
|
||||
wxPROCESS_EVENT_ONCE(GdkEventMotion, gdk_event);
|
||||
|
||||
wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
|
||||
if ( AreGTKEventsBlocked() )
|
||||
return FALSE;
|
||||
|
||||
g_lastMouseEvent = (GdkEvent*) gdk_event;
|
||||
|
||||
|
|
@ -2243,19 +2246,49 @@ wx_window_focus_callback(GtkWidget *widget,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "enter_notify_event"
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static gboolean
|
||||
gtk_window_enter_callback( GtkWidget*,
|
||||
GdkEventCrossing *gdk_event,
|
||||
wxWindowGTK *win )
|
||||
gboolean
|
||||
wxGTKImpl::WindowEnterCallback(GtkWidget* widget,
|
||||
GdkEventCrossing* gdk_event,
|
||||
wxWindowGTK* win)
|
||||
{
|
||||
wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
|
||||
wxLogTrace(TRACE_MOUSE, "Window enter in %s (window %p) for window %p",
|
||||
wxDumpWindow(win), gtk_widget_get_window(widget), gdk_event->window);
|
||||
|
||||
if ( AreGTKEventsBlocked() )
|
||||
return FALSE;
|
||||
|
||||
// Event was emitted after a grab
|
||||
if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
|
||||
if (gdk_event->mode != GDK_CROSSING_NORMAL)
|
||||
{
|
||||
wxLogTrace(TRACE_MOUSE, "Ignore event with mode %d", gdk_event->mode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( g_windowUnderMouse == win )
|
||||
{
|
||||
// This can happen if the enter event was generated from another
|
||||
// callback, as is the case for wxSearchCtrl, for example.
|
||||
wxLogTrace(TRACE_MOUSE, "Reentering window %s", wxDumpWindow(win));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( g_windowUnderMouse )
|
||||
{
|
||||
// We must not have got the leave event for the previous window, so
|
||||
// generate it now -- better late than never.
|
||||
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
|
||||
InitMouseEvent(g_windowUnderMouse, event, gdk_event);
|
||||
|
||||
(void)g_windowUnderMouse->GTKProcessEvent(event);
|
||||
}
|
||||
|
||||
g_windowUnderMouse = win;
|
||||
|
||||
wxMouseEvent event( wxEVT_ENTER_WINDOW );
|
||||
InitMouseEvent(win, event, gdk_event);
|
||||
|
|
@ -2266,22 +2299,45 @@ gtk_window_enter_callback( GtkWidget*,
|
|||
return win->GTKProcessEvent(event);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static gboolean
|
||||
gtk_window_enter_callback( GtkWidget* widget,
|
||||
GdkEventCrossing *gdk_event,
|
||||
wxWindowGTK *win )
|
||||
{
|
||||
return wxGTKImpl::WindowEnterCallback(widget, gdk_event, win);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "leave_notify_event"
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static gboolean
|
||||
gtk_window_leave_callback( GtkWidget*,
|
||||
GdkEventCrossing *gdk_event,
|
||||
wxWindowGTK *win )
|
||||
gboolean
|
||||
wxGTKImpl::WindowLeaveCallback(GtkWidget* widget,
|
||||
GdkEventCrossing* gdk_event,
|
||||
wxWindowGTK* win)
|
||||
{
|
||||
wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
|
||||
wxLogTrace(TRACE_MOUSE, "Window leave in %s (window %p) for window %p",
|
||||
wxDumpWindow(win), gtk_widget_get_window(widget), gdk_event->window);
|
||||
|
||||
if ( AreGTKEventsBlocked() )
|
||||
return FALSE;
|
||||
|
||||
if (win->m_needCursorReset)
|
||||
win->GTKUpdateCursor();
|
||||
|
||||
// Event was emitted after an ungrab
|
||||
if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
|
||||
if (gdk_event->mode != GDK_CROSSING_NORMAL)
|
||||
{
|
||||
wxLogTrace(TRACE_MOUSE, "Ignore event with mode %d", gdk_event->mode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( win == g_windowUnderMouse )
|
||||
g_windowUnderMouse = nullptr;
|
||||
|
||||
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
|
||||
InitMouseEvent(win, event, gdk_event);
|
||||
|
|
@ -2289,6 +2345,16 @@ gtk_window_leave_callback( GtkWidget*,
|
|||
return win->GTKProcessEvent(event);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static gboolean
|
||||
gtk_window_leave_callback( GtkWidget* widget,
|
||||
GdkEventCrossing *gdk_event,
|
||||
wxWindowGTK *win )
|
||||
{
|
||||
return wxGTKImpl::WindowLeaveCallback(widget, gdk_event, win);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "value_changed" from scrollbar
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -2912,6 +2978,9 @@ wxWindowGTK::~wxWindowGTK()
|
|||
if ( g_captureWindow == this )
|
||||
g_captureWindow = nullptr;
|
||||
|
||||
if ( g_windowUnderMouse == this )
|
||||
g_windowUnderMouse = nullptr;
|
||||
|
||||
if (m_wxwindow)
|
||||
{
|
||||
GTKDisconnect(m_wxwindow);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue