wxFrame and wxTaskBarIcon taskbar event Mac OSX : callback not being triggered - c++

I have a derived class for wxFrame (MyFrame) (for OSX - Yosemite platform), where it calls:
Bind(wxEVT_TASKBAR_RIGHT_DOWN), &HandleTaskBarEvent, this);
The issue is HandleTaskBarEvent is not being invoked when I right click the icon in the dock.
I see the generic right click menu that Mac has (Open at Login, Keep in Dock, etc) for the main icon in the dock.
Also, I created a wxTaskBarIcon. I am guessing this will be utilized for the minimized icon in the dock after the frame is minimized.
systemIcon = new wxTaskBarIcon(); //declared in header
systemIcon.Bind(wxEVT_TASKBAR_RIGHT_DOWN, &HandleTaskBarEvent, this);
Popup = new wxMenu(); //declared in header
QuitMenu = new wxMenuItem(Popup, wxID_ANY, wxString(wxT("Quit")), wxEmptyString, wxITEM_NORMAL); //declared in header
Popup->Append(QuitMenu)
Popup->Bind(wxEVT_COMMAND_MENU_SELECTED, &CloseFunc, this, QuitMenu->GetId());
This is inside the same derived class(MyFrame).
I call Iconize() inside that MyFrame same function, which works as expected. It minimized the window.
This is the HandleTaskBarEvent function (virtual)
void MyFrame::HandleTaskBarEvent(wxTaskBarIconEvent& event)
{
if(event.GetEventType() == wxEVT_TASKBAR_RIGHT_DOWN)
{
systemIcon->PopupMenu(Popup);
}
}
I saw this post : Mouse Events of WxPython TaskBarIcon on Mac OSX are not triggering
and there seems to be a bug about it. But I am not able to find that bug or its status online. It is mentioned that the issue is with wxPython, but seems related to my problem.
Also I created a derived class for wxTaskBarIcon and overrode CreatePopupMenu and made systemIcon as an instance of MyTaskBarIcon, but that function is not being triggered for any clicks(left,right, etc). Also the main wxFrame 's Bind callback (HandleTaskBarEvent) is not being triggered, hence the systemIcon is not being able to popup the menu.
I am not using mouse for my Mac (using trackpad instead). Not sure if it should make any difference to right click code, but adding the information here anyways.
So I am thinking this could be wxWidget-OSX specific issue, because the code works on Windows as expected.
Does anyone know if this is purely wxWidget-OSX incomplete feature, if there is any open bugs about it, and more importantly if there is any solution to show the popup menu items for the minimized icon in the dock, and to handle the click events for the menu.
Thanks in advance.

This is a limitation of the OS X wxTaskBarIcon implementation. See wxTaskBarIcon on OSX - two-finger click does not send mouse event and related/linked issues.
The only way I know of (on OS X) is overriding wxTaskBarIcon::CreatePopupMenu().
You should be able to have something like:
MyApp::wxApp/
MyTaskBarIcon::wxTaskBarIcon (override CreatePopupMenu(), return a new wxMenu)
This is the model I use in a few applications and it works the same on Windows and OS X (albeit no specific click handlers as mentioned).

Related

Cross-platform Gtk3 app, menu bar unresponsive at first

I'm writing a cross-platform Gtk3 application in C++. Lately I've been working on the integration with MacOS:
Gtkmm 3.24 obtained via Homebrew;
XCode 12.0;
MacOS Catalina 10.15.
I have derived my application class from Gtk::Application. The application object overrides the 'on_startup()' which calls the base class 'on_startup() and then uses a Gtk builder resource to construct a Gio::Menu object from an XML file, and then 'Gtk::Application::set_app_menu()' to install it:
MyApplication::on_startup()
{
Gtk::Application::on_startup();
// skipping details: ... Gtk builder reads Gio::Menu object from resource file ...
set_app_menu( pMenu );
}
When I first launch my application:
the menu bar is unresponsive. The application menu appears next to the Apple menu in the bar at the top of the screen, but neither responds to mouse clicks;
except from the frozen menu bar, the application is functioning normally and its main window is responsive.
However, then:
click on any other open application's window, that application's menu bar appears;
click on my application's window to switch back to it, its menu bar returns and now works perfectly.
This is 100% reproducible (frozen at first, toggle away to another app and back and now the menu works).
I created another project in XCode and built the Gtkmm example "app_and_win_menus" and the example application behaves the exact same way.
So I think I'm really just looking for a workaround. I've been scouring the net for any information about this problem and saw others complaining generally about frozen menu bars on MacOS but none specific to Gtk (all other applications on this Mac work normally, it's only the apps that I build with Gtk+/Gtkmm 3.24 that exhibit this issue).
I realize this sounds a bit like a bug report and this may not be the place to bring it up, but I'm unsure where to go from here. Any information much appreciated.

wxWidgets dark mode on macOS

According to the release notes for 3.1.3 (https://raw.githubusercontent.com/wxWidgets/wxWidgets/v3.1.3/docs/changes.txt) dark mode support has been added to wxWidgets for Mojave+.
For the documentation for wxSysColourChanged, it still states that this is for Windows only but I thought the dark mode support for macOS should include this too? Dark mode is only a recent addition to Windows UWP apps and not Win32 (see dark mode on Windows 10 for a discussion of that on the forum).
In any case I cannot get the event to fire, although switching to dark mode does indeed correctly update the GUI elements eg. wxlistctrl and wxbutton without me having to manually enforce colour changes.
I am trying to capture the system colour change event so that I can manually redraw my own "owner-drawn" custom GUI elements correctly dark/light.
I hook up the Bind in the constructor to my event but nothing works:
Bind(wxEVT_SYS_COLOUR_CHANGED, &myFrame::OnSystemColourChanged, this);
void myFrame::OnSystemColourChanged(wxSysColourChangedEvent &event)
{
wxSystemAppearance s = wxSystemSettings::GetAppearance();
wxString dark = s.IsDark() ? "it's dark" : "it's light";
wxString m("System colour changed - ");
m += dark;
::wxMessageBox(m);
event.Skip();
}
I have got this open as a query on the forum (here) and they recommended the mailing list but I notice that wxWidgets questions are quickly addressed on here, particularly by VZ so here's hoping!
Am I missing some method of detecting colour changes?
OK, I managed to get the code to hit. I debugged it by adding a wxApp-level HandleEvent override function to see what events were being handled by the application (yes all events go through here):
void myApp::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const
{
wxApp::HandleEvent(handler, func, event);
}
wxSysColourChanged events are indeed passing through this.
I managed to get my main frame's handler to hit by hooking up differently. Instead of
Bind(wxEVT_SYS_COLOUR_CHANGED, &myFrame::OnSystemColourChanged, this);
I used this instead:
Bind(wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler(myFrame::OnSystemColourChanged), this);
I have no idea why &myFrame::OnSystemColourChanged wouldn't be recognised.
Also, I could not get any message boxes to show up in my event handler. ::wxMessageBox and wxMessageDialog did not show. cout output did show up but no popup GUI dialogs.
I am not going to be showing message boxes in this handler anyway so it isn't a problem but was trying to show a message for debugging/testing purposes.

Qt - minimizing and maximizing app without standard titlebar buttons

I have a Qt application where there is only one widget which is not a MainWindow, just a QLabel. It has not title bar (obtained through setWindowFlags(Qt::FramelessWindowHint)), thus the standard minimize and maximize buttons are not available. But there is a sidebar at the widget's side where we provide a minimize button that should behave as the standard minimize button.
How do I do it?
I tried the solutions at Minimizing a Qt application and Qt C++ minimize and maximize window. Neither works. I can hide the app of course, on clicking the minimize button. Problem is, how to restore it through standard mechanisms?
Scenarios:
On Mac, the dock icon is clicked. Thankfully, OS X native APIs can give me a notification when dock icon is clicked, so based on that, I can unhide the widget and make it active.
On Mac, the app icon is double clicked in /Applications, or clicked in Launchpad. How do I get a notification for this? The code doesn't even come to the main.cpp that I can unhide it from there if it is hidden.
On Windows, the application icon in the taskbar is clicked (the app does not have a tray icon). How do I get notification for that and unhide it?
On Windows, the app icon is double clicked either in Program Files, or may be a desktop shortcut icon. How do I get notification for this to unhide it?
If this aproach is not correct, how do I show and hide the app as per standard behavior on both Mac and Windows?
Platform - Qt 5.3.1, 32 bit.
This is not an answer, but it might help sorting out which events are triggered (points 1,2 and 3).
#include <QApplication>
class newapp : public QApplication {
Q_OBJECT
public:
newapp( int &argc, char **argv ) : QApplication(argc, argv) {}
protected:
bool event(QEvent *ev) {
std::cerr << "APPLICATION EVENT " << ev->type() << std::endl;
return QApplication::event(ev);
}
};
and in your main.cc you will have
newapp myapp(argc,argv);
instead of
QApplication myapp(argc,argv)
Once you identify the events triggered, you're almost done: you need to tell to you newapp to restore the size of the Qlabel (there are tons of ways to do this, so provide your implementation and you might get more focused help)
For point 4, it's something else due to the different behavior between OSes as in Windows double clicking for the second time an app, will launch another instance of the application (on OSx it will raise the first opened app). You might find something that suit you in this project HERE

Modal QMessageBox does not behave like native Windows dialogs

My application has a dialog that asks the user via a QMessageBox whether he wants to discard all changes he made or wants to keep editing. I want this dialog to be modal to the whole application.
I read somewhere that this is the standard behavior for a QMessageBox, so I dont have to set it explicitly with something like:
mbox.setWindowModality(Qt::ApplicationModal);
I wonder why it behaves differently from other modal dialogs in the OS (Windows 7 in my case). On the one hand it functions like it should, i.e. all other input methods in the application are blocked until the user answeres the dialog. However, it doesn't 'blink'* if the user clicks any other window of the application. Is there any way to get Qt to behave like a native Windows dialog?
Thanks in advance!
*If you don't know what I mean with this 'blinking': Just open notepad on a Windows OS, type some text and try to close it. A dialog pops up that asks to save, discard or keep editing. Now click somewhere on the editor window -> the border and titlebar of the dialog flashes/blinks a few times.
The problem arises when the message box has no parent. This works fine for me:
QMessageBox box(this);
box.setStandardButtons(QMessageBox::Close);
box.exec();
But this does not:
QMessageBox box;
box.setStandardButtons(QMessageBox::Close);
box.exec();
This makes sense... the message box can't blink unless it knows that its parent was clicked on.
A simple solution that comes into my mind and if you want to deploy your application only on windows you should #include <windows.h> and use the MessageBoxA API.
Besides that this works great for me in Windows and ubuntu
if (QMessageBox::question(this,"Close?","Close this dialog?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::Yes)
{
this->close();
}

QDialog as Popup does not hide on Mac when clicking out of the main window

I have a basic QDialog with it's WindowFlags set to Qt::Popup so that it appears as a typical popup overlay.
On Windows, everything works great and if you click outside the main window or really anywhere else it goes away. But on Mac OSX, if you click the menu bar at the top or resize the window, the popup just stays where it is. I have absolutely no internal handling of the mouse enter/leave/move/press events for the popup, so the closing of it is not something I'm even handling... it's just automatic on Windows.
Any idea I can get it to close when the main application is no longer the current context on the system?
You may install native event filter and to close active popup dialog (QApplication::activePopupWidget()) when user will click out of main window. See the following answer for information how to install native filter.