Closed probonopd closed 3 years ago
First step is probably to move the menu defitions from main-win.ui
into a separate .ui file in resources like this:
https://forum.qt.io/topic/29102/how-to-move-the-qmenubar-definition-in-a-separate-ui-file/4
Then see if we can call (or factor out) theMainWindow::on_
actions from mainwindow.cpp
so that we can use them in desktopwindow.cpp
, too.
When you have a global menu bar, an application can have menus without a window (document) being open in the application.
For example, when Filer shows just the desktop without any windows open, we still want menus to do things with the icons on the desktop.
How to achieve this in Qt? Something like this?
#include <QtUiTools/QUiLoader>
# In DesktopWindow::DesktopWindow(int screenNum):
// probono: Add menu even though no windows are open, only the desktop is shown
QUiLoader loader;
QFile file(":/menu.ui");
file.open(QFile::ReadOnly);
QMenuBar* menuBar = qobject_cast<QMenuBar*>(loader.load(&file, this));
file.close();
Currently, when there is no window (1), then the menu bar (2) is empty and we cannot use it to manage e.g., the icons on the desktop.
https://doc.qt.io/qt-5/qmenubar.html#qmenubar-as-a-global-menu-bar
If you want all windows in a Mac application to share one menu bar, you must create a menu bar that does not have a parent. Create a parent-less menu bar this way:
QMenuBar *menuBar = new QMenuBar(nullptr); Note: Do not call QMainWindow::menuBar() to create the shared menu bar, because that menu bar will have the QMainWindow as its parent. That menu bar would only be displayed for the parent QMainWindow.
Note: On Linux, if the com.canonical.AppMenu.Registrar service is available on the D-Bus session bus, then Qt will communicate with it to install the application's menus into the global menu bar, as described.
So you want similar to what GNUStep did? Have the menu even if the application is closed?
We need the menu to be populated when Filer --desktop
just renders the desktop and the icons on it (before a file manager window is opened and after the last file manager window has been closed).
Like here:
No window is open, but the global menu is populated.
Just doing
QMenuBar *menuBar = new QMenuBar(nullptr);
QMenu *file = new QMenu();
file->addMenu("&File");
menuBar->addMenu(file);
qDebug() << "probono: FIXME: File menu should have been added. Has it?";
seems to do nothing visible on the screen. Am I missing something?
I might need more context. I will take a look at the code base.
The basic question is how to populate the menu without/before using a QMainWindow.
You don't need a QMainWindow, every QWidget can be a top level widget/window. Did you call something like menuBar->show()
?
Hi @ymau. Yes I tried it but my trouble already begins by not knowing where exactly I need to hook this menu in. It would be of tremendous help if you could send a proof-of-concept pull request, if this is not too much to ask. (Just one dummy menu entry...) Thanks!
@probonopd I had a short look at the code, so just to clarify the vision for it for me: Filer basically acts as the desktop and (if needed) opens a filemanager window like a dialog. The DesktopWindow will provide the desktop view and shall show the global menu bar on top, containing the entries from Filers (or more specifically: PCManFMs) menu bar.
IMHO .ui-Files shouldn't be used at all, as they produce code that contains lots of unnecessary objects and constructs that are bad performance-wise (for example stuf like QString::fromUtf8("some text")
which is quite slow and completely unnecessary for texts using only ascii/latin1 characters and especially if the code files are already encoded in UTF-8). Yes, using the Qt Designer
seems to make life easier, but it only increases complexity at the the cost of performance and maintainability.
So the way to go would be to implement the menus in C++ code instead, or is there a reason to strictly stick to using .ui-Files?
Another question comes to mind: How should external Qt applications be handled? IIRC Qt uses a DBus service on Linux systems that have a global menu bar to pull the toplevel menus from applications implemented in Qt and place them in the global menu bar. Given that DBus is an unwanted technology in hello, I don't see a way to do that in any other way unless you manage to implement it and get it upstream into Qt.
@probonopd I had a short look at the code, so just to clarify the vision for it for me: Filer basically acts as the desktop and (if needed) opens a filemanager window like a dialog. The DesktopWindow will provide the desktop view and shall show the global menu bar on top, containing the entries from Filers (or more specifically: PCManFMs) menu bar.
Yes: When (only) the desktop is shown, then there should also be menu entries (very similar to those which are currently already there when you have a window open).
So the way to go would be to implement the menus in C++ code instead, or is there a reason to strictly stick to using *.ui-Files?
It's inherited from pcmanfm-qt, which Filer is forked from.
Another question comes to mind: How should external Qt applications be handled? IIRC Qt uses a DBus service on Linux systems that have a global menu bar to pull the toplevel menus from applications implemented in Qt and place them in the global menu bar.
Right now we are using DBus because that's what everyone is using. But since we essentially use our own Qt plugin which sends the menus over Qt to the Menu, we could probably also implement another communication mechanism between the two. But then, probably we will need to keep DBus for compatiblity with existing applications anyway. (Even though we would prefer something simpler.) So for now we stick to DBus, but it is an implementation detail that could change later.
@ymau I don't see any issue in using .ui files at all. Even if the code is not optimized. C++ is a systems language and it is very fast. So I would not even consider porting the .ui files by hand. That's just too much engineering.
@antony-jr Loading a UI file at runtime as suggested in the comment further up certainly is not an optimal solution as well. My problem with using UI files is not only that they lead to suboptimal code but that they make the project structure more complex, less readable and thus less maintainable. Putting a menu into a UI file just to avoid creating a few lines of C++ code is not gonna help keeping it simple. From my experience UI files generally create more problems than they solve.
@probonopd Does the ISO file you release have all the qt dependencies? Because I want to build and test this out. Is it possible to test the menu bar with filer --desktop
in a linux distro or should I do it in hello os itself?
@antony-jr I'm using Ubuntu to build and test the Filer code. I had to install a few additional libs, though. cmake will tell you, what is missing.
Thanks for having a look @antony-jr and @ymau.
Does the ISO file you release have all the qt dependencies?
The developer files are not on the Live ISO, but if you can install the Live ISO then you can sudo pkg install qtcreator qt5
. Another option is to use your favorite Linux distribution. KDE neon devedition might do the trick.
@probonopd @ymau POC seems promising. The problem was the desktop mode never had any menu bars in the first place.
EDIT: I think this issue is pretty much solved. I will let @ymau continue from here. Thanks for the work @ymau :+1:
Polite ping @ymau - did you get it to work with an existing Global Menu application such as the appmenu plasmoid in KDE or https://github.com/helloSystem/Menu?
I was a bit busy lately, so I just got to it today. On Ubuntu I seem to be missing the Qt5ThemeSupport cmake module for building the QtPlugin and I couldn't figure out, which package I'm missing (btw. the Menu has build errors, like missing a QDebug include in main.cpp and some undeclared variables). On FreeBSD (GhostBSD) I didn't get the Menu to show up. It's running but it's not visible. 🤔 Maybe I need to o install KDE as well.
Or you could give https://github.com/helloSystem/ISO/releases a try... :)
Or you could give https://github.com/helloSystem/ISO/releases a try... :)
The major drawback for us is that dev environment is very hard to setup. In opensuse tumbleweed I have to pull 2 GiB of dependencies to somewhat build a broken menu bar in my distro. So I think we need to device a new method to encourage new developers and get started without having to hunt dependencies. Can we use docker and vnc for this? Might be viable. Arch linux gives almost all packages required by MenuBar and other tools for Hello Systems. Or we could go with chroot and alpine linux.
I moved to FreeBSD exactly because I didn't want to adjust everything to work on 1,001 different distributions that are all slightly different/broken. I guess that out of all Linux distributions, KDE neon Developer Edition probably comes with most dependencies preinstalled.
@probonopd so you're using FreeBSD for development and testing? I'd prefer something where I can run an IDE (prefereably QtCreator) and test the results in the same environment. @antony-jr is right, getting a working environment with all the dependencies AND a working Menubar, Filer etc would prevent discouraging new developers. And maybe another goal of the project should be to remove as many external dependencies as possible.
@probonopd so you're using FreeBSD for development and testing? I'd prefer something where I can run an IDE (prefereably QtCreator) and test the results in the same environment.
Me too :+1:
My basic problem is that I cannot get menu entries to show up when only the desktop is shown but no window is open.
I tried adding
QMenuBar *menubar = new QMenuBar();
QMenu *file_menu = new QMenu();
file_menu->setTitle("File");
menubar->addMenu(file_menu);
menubar->show();
file_menu->show();
right after
but the File menu does not get shown in the gloabal menu bar. Am I doing it wrong?
This is what I would like to get at when no Filer window is open, just the desktop:
Are you using the code from my fork/pull request? Currently all actions are defined in the MenuBar class, that is added to the desktop in void DesktopWindow::installMenuBar(..)
. But for a 'shared' menu there should be a central action registry or model class, as mentioned here, that provides the actions to the menu bar depending on its context.
But also haven't had any luck with the global menu bar yet, I'm still stuck at trying to get a decent dev environment running. I'm currently trying to get the hello ISO to start up in VMWare Player (I gave up on trying to install any kind of FreeBSD to my notebook as I just couldn't figure out hwo to do it without compromising my other OS. I'm just not used to do that kind of stuff.), but it somehow gets stuck in a shell right after start :sigh:
Are you using the code from my fork/pull request? Currently all actions are defined in the MenuBar class, that is added to the desktop in
void DesktopWindow::installMenuBar(..)
. But for a 'shared' menu there should be a central action registry or model class, as mentioned here, that provides the actions to the menu bar depending on its context. But also haven't had any luck with the global menu bar yet, I'm still stuck at trying to get a decent dev environment running. I'm currently trying to get the hello ISO to start up in VMWare Player (I gave up on trying to install any kind of FreeBSD to my notebook as I just couldn't figure out hwo to do it without compromising my other OS. I'm just not used to do that kind of stuff.), but it somehow gets stuck in a shell right after start :sigh:
I will look at that if I time. I will also try to build some dev environment scripts to make this easier for future developers. I'm thinking of using Docker(Alpine Linux) and VNC to build and show the result. A simple python tool like how postmarketOS folks use.
I have tried a couple of things to attempt to get a menubar visible in the global menu:
QMainWindow
, with the existing desktop widget as a member, adding the menubar with setMenuBar()
layout()->setMenuBar()
The first made no difference.
The second I managed to get a menubar visible but only without the global menu (this was actually built and running on Linux to test).
There seems to be a problem with the global menu, perhaps that the desktop window doesn't get the focus in the same way as regular windows?
I tried to look at other projects for hints. I think plasma desktop has a working global menubar for the desktop widget - I couldn't find anything in the Dolphin code that looks like it gets QApplication::desktop()
so maybe it isn't using Dolphin directly.
Also, regarding the actual separation of the menubar from the UI of MainWindow
- the other option is to have a dummy instance of MainWindow
in desktopwindow and retrieve the menubar from it with a getter.
The advantage is that we can still use Designer to edit the menu, as long as the slots are updated/added in both classes.
I tested that as well when trying to get the menubar visible, and it works fine (once we sort out the global menu problem)
I confirm your suspicion that Menu simply doesn't notice when the FIler desktop gets active.
Kill menubar
by Ctrl+Alt+Esc and clicking on the global menu, then in another Terminal run it from the command line with /System/Menu.AppDir/usr/bin/menubar
. Then run ./filer/filer-qt --desktop
.
Watch the Terminal output for menubar
as you click on different windows. You will see things like
probono: WM_CLASS "qterminal"
probono: WM_CLASS "Falkon Browser"
probono: WM_CLASS "qterminal"
But there is no probono: WM_CLASS "filer-qt"
when you click on the desktop. So the menu has no clue that it should refresh the menus. The probono: WM_CLASS
message is coming fro the updateMenuFromWindowIfHasMenu
method in src/appmenu/appmenumodel.cpp
, which probably means that this method doesn't get called when the desktop should take over.
Turns out that the Menu specifically filtered out windows with NET::DesktopMask
(we had inherited this from panda-topbar
). Fixed!
Turns out that the Menu specifically filtered out windows with
NET::DesktopMask
(we had inherited this frompanda-topbar
). Fixed!
Ah, excellent!
No I hadn't committed the testing I did on the menubar being taken from the MainWindow
- needs some work, especially doing stuff in the slots (also the getter needs to disconnect the slots in MainWindow
when it's taken in this way)
I will hopefully have time to finish all this at the weekend.
Thank you very much @moochris, the Filer is now starting to feel like a "proper desktop" :+1:
So satisfying!
Show menu when no window is open (in
--desktop
mode). You can do most things you can do in a Filer window also on the desktop.