Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client systray support #565

Merged
merged 36 commits into from
May 14, 2019
Merged

Client systray support #565

merged 36 commits into from
May 14, 2019

Conversation

townsend2010
Copy link
Contributor

@townsend2010 townsend2010 commented Jan 18, 2019

Add a client systray icon and menu. This allows:

  • Getting a list of all instances and state.
  • The ability to open a shell to an instance.
  • Stopping an instance.
  • Getting version information.
  • Displaying when an update to Multipass is available.

@townsend2010 townsend2010 changed the title Client systray support WIP - Client systray support Jan 18, 2019
@townsend2010 townsend2010 force-pushed the client-systray-support branch from 17ae950 to bdb2b82 Compare January 18, 2019 21:18
@townsend2010
Copy link
Contributor Author

To @gerboland's comments in #564, I wonder if the main event loop I added is indeed unnecessary.

My question is if we can use a local QEventLoop in Systray::run() and Qt will be happy processing events? If so, then the first commit in this can be removed. I think I'll experiment with that.

@townsend2010 townsend2010 force-pushed the client-systray-support branch from bdb2b82 to aabc29b Compare January 22, 2019 14:26
@@ -48,7 +48,7 @@ std::string get_server_address()

int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
QApplication app(argc, argv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you check if the command line runs when no display server is running (i.e. "DISPLAY=")

QApplication subclasses QGuiApplication, which loads Qt platform backends for various graphical shells. Those are needed for the systray icon ofc, but for a pure command-line util, I'm unsure if it'll run or just bail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't:( Offhand, do you if there is some way to load the platfrom backends after the fact, like when only the systray command runs? I'll do some research, but hoping you have a quick answer:)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backends load on Q{Gui,}Application construction.

One workaround might be to read the CLI very early looking for systray:

if (!argv_has_systray())
    setenv("QT_QPA_PLATFORM", "minimal");

QApplication app(argc, argv);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That did the trick. Thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to have a separate command altogether then? Just a separate main instead of the if?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ricab,
I want to use the same binary, ie, multipass for the cli, systray icon, and the down-the-road full blown gui, so I think the simple if will do the trick.

@townsend2010 townsend2010 force-pushed the client-systray-support branch from a096ae9 to 3617b87 Compare February 1, 2019 16:24
@townsend2010
Copy link
Contributor Author

BTW, the design of this is based closely on https://github.com/CanonicalLtd/multipass-design#status-menu with added changes as I saw necessary.

Copy link
Collaborator

@ricab ricab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detail: systray missing autocompletion

@ricab
Copy link
Collaborator

ricab commented Feb 5, 2019

OK, so I finally managed to build the snap and launch multipass from it... but crash again :/

$ multipass systray
This application failed to start because it could not find or load the Qt platform plugin "xcb"
in "".

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb.

Reinstalling the application may fix this problem.
Aborted (core dumped)

gdb /snap/multipass/x1/bin/multipass core says.

Some more research here and here does not help much...

@ricab
Copy link
Collaborator

ricab commented Feb 5, 2019

OK, the issue seems to be a missing "xinerama" library. Here is the output from Qt itself with QT_DEBUG_PLUGINS=1 (see towards the end). So we just need a new multipass dependency I guess...

Copy link
Collaborator

@Saviq Saviq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on Ubuntu:

When there's no instances, there's a stray blank section:
stray section
It seems to disappear during the transition when the menu is closed. Maybe it's the separator?

I wouldn't put the instance status verbatim in the menu:
obraz
If there's no way to add the status like designed (right-aligned and greyed out), maybe we could add some Unicode trickery. We may need to go platform-dependent on this? Doesn't have to be this PR of course.


void mcp::open_multipass_shell(const QString& instance_name)
{
QProcess::startDetached("xterm", {"-e", "multipass", "shell", instance_name});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no way to detect whether the command being run in xterm failed (in case the shell command failed for some reason), in which case there's zero feedback… Maybe add || read to the command being run?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I had planned on giving extra feedback when the terminal cannot be started for whatever reason. Ideally, I'd like it to pop up a window with the failure and reason, but for a short term solution, your idea will work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid windows whenever possible to keep the experience coherent. Multipass is anchored in command line usage so it shouldn't be surprising that we don't have many dialogs and windows. Those are always focus hogs.

src/platform/client/client_platform_linux.cpp Outdated Show resolved Hide resolved
src/platform/client/client_platform_linux.cpp Outdated Show resolved Hide resolved
@townsend2010
Copy link
Contributor Author

I wouldn't put the instance status verbatim in the menu

Right, I have plans to fix that. I do think we should be consistent with the output of multipass list though, so we should fix it there and then carry it over here.

It seems to disappear during the transition when the menu is closed. Maybe it's the separator?

Yeah, I'm sure it's the separator and I missed that. Will fix.

If there's no way to add the status like designed (right-aligned and greyed out), maybe we could add some Unicode trickery.

I think this is going to be real tricky. I spent some time trying to make it work like the design with no luck. I may end up having to subclass QMenu and try some things in that in forcing Qt to display it how we want to.

@townsend2010
Copy link
Contributor Author

Detail: systray missing autocompletion

Ack, will add that to the autocompletions.

OK, the issue seems to be a missing "xinerama" library.

I think once we switch the snap to use base: core18, then I can use the desktop-qt5 remote part and that should pull in all of the dependencies and such that we need.

@Saviq
Copy link
Collaborator

Saviq commented Feb 5, 2019

clang on Mac says:

../src/client/cmd/systray.cpp:105:77: error: lambda capture 'this' is not used [-Werror,-Wunused-lambda-capture]
            QObject::connect(instance_actions.back(), &QAction::triggered, [this, name] {
                                                                            ^
../src/client/cmd/systray.cpp:178:24: error: lambda capture 'this' is not used [-Werror,-Wunused-lambda-capture]
    auto on_success = [this, &list_reply](ListReply& reply) {
                       ^
2 errors generated.

@townsend2010
Copy link
Contributor Author

@Saviq,

When there's no instances, there's a stray blank section:

Would it be better to display something like "No instances" or "No instances defined" or something when there are no instances? When it just has 'About' and 'Quit' there, it kind of looks like it's missing something.

@Saviq
Copy link
Collaborator

Saviq commented Feb 5, 2019

@townsend2010 there ultimately will be a Launch, won't there? And the whole pet story…

@townsend2010
Copy link
Contributor Author

@Saviq,

I'm not under the impression that Launch will be part of the systray drop down menu. I don't see that in the design of the systray icon either. I do think Launch would be part of the main UI though.

Regarding the pet story, the only thing we would add is a specific action with a hotkey attached to it for opening the shell.

@Saviq
Copy link
Collaborator

Saviq commented Feb 5, 2019

@townsend2010 right, but that means there will always be an item above About - and there will never be "No instances" in that sense.

@ricab
Copy link
Collaborator

ricab commented Feb 6, 2019

Some things that I noticed (but could belong in polishing PRs):

  • The contents of the menu are sometimes updated, sometimes not:
    • when clicking "start" on an instance and then clicking again to monitor its state: it will go from STOPPED to STARTING, but will never update to RUNNING in the menu. So STOPPED-->STARTING-/->RUNNING. The RUNNING state is only shown after clicking outside and clicking the widget again.
    • the same happens when clicking suspend: RUNNING-->SUSPENDING-/->SUSPENDED
    • I tried sending commands from the terminal and immediately clicking on the icon. The same thing happens.
      • Clicking it right after launch, no new instance appears (until click out and in)
    • stop seems to be good: RUNNING-->STOPPED directly
  • When the contents of the menu are updated, it briefly flickers out-of and into existence. It would be nice if the transition could be smooth.

@Saviq
Copy link
Collaborator

Saviq commented Feb 6, 2019

When the contents of the menu are updated, it briefly flickers out-of and into existence. It would be nice if the transition could be smooth.

What desktop environment is this? I don't think we can influence how they deal with this (unless in fact we're deleting the whole menu and recreating it).

@ricab
Copy link
Collaborator

ricab commented Feb 6, 2019

Regarding:

$ multipass systray
QStandardPaths: XDG_RUNTIME_DIR points to non-existing path '/run/user/1000/snap.multipass', please create it with 0700 permissions.

This says:

$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.

I noticed it is mentioned here and from some quick googling I got the impression it is relevant for security concerns.

@ricab
Copy link
Collaborator

ricab commented Feb 6, 2019

@Saviq Unity on 16.04 here. Do you see something else?

@ricab
Copy link
Collaborator

ricab commented Feb 6, 2019

@Saviq other similar menus update continuously here (e.g. system monitor)

@townsend2010
Copy link
Contributor Author

@ricab,

Thanks for the feedback. In general, there is much work to be done on this:) But to reply to your feedback:

The contents of the menu are sometimes updated, sometimes not:

Yes, there is absolutely no polling or event handling when the menu has been opened. Currently, the only way to refresh the states is to close the menu and then reopen it. Polling will be implemented first and then eventually some event driven model.

When the contents of the menu are updated, it briefly flickers out-of and into existence. It would be nice if the transition could be smooth.

Right, this will be fixed. But what you are seeing is the static menu from the last query, ie, the last time you opened the menu, and then once the client receives the list info from the daemon, it clears the menu and then creates a new one based on what it received.

Copy link
Contributor

@gerboland gerboland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much cleaner, I like this. I've a couple of small comments inline.

Nitpick: there's many files in src/client/cmd that are getting solely formatting changes, making the diff a lot bigger than it needs to be. Has clang-format changed its mind about some things?

src/client/gui/gui_cmd.cpp Outdated Show resolved Hide resolved
src/client/gui/main.cpp Outdated Show resolved Hide resolved
src/client/gui/main.cpp Outdated Show resolved Hide resolved
src/client/gui/argparser.h Outdated Show resolved Hide resolved
@townsend2010
Copy link
Contributor Author

@gerboland,

Thanks for the review. Glad you like this iteration better. Now that I put in the hard work, I think it's better too:)

Nitpick: there's many files in src/client/cmd that are getting solely formatting changes, making the diff a lot bigger than it needs to be. Has clang-format changed its mind about some things?

Yes, silly clang-format decided to change a bunch of things and I really didn't want to have to keep backing those out. Not sure why it decided to change now, but it did:/

@townsend2010 townsend2010 force-pushed the client-systray-support branch 2 times, most recently from a59c2a4 to 8d11394 Compare February 20, 2019 06:42
@townsend2010 townsend2010 force-pushed the client-systray-support branch from d7229a6 to 4bfb15f Compare March 5, 2019 15:04
@townsend2010 townsend2010 force-pushed the client-systray-support branch from ef8afaf to 5883ff6 Compare May 10, 2019 16:34
- Use status enum instead of strings for status comparisons.
- Remove "Retrieving instances" message which makes "About" happy when there
  are no instances.
- Fix clang copy elision error.
@townsend2010 townsend2010 force-pushed the client-systray-support branch from 5883ff6 to c35516f Compare May 10, 2019 19:16
@gerboland
Copy link
Contributor

"About" issue fixed.

New issue: when VM in "Stopped" state, I am shown useless "Open Shell" option. I cannot restart VM from the UI.

@Saviq
Copy link
Collaborator

Saviq commented May 13, 2019

New issue: when VM in "Stopped" state, I am shown useless "Open Shell" option.

It shouldn't be useless, it should start the instance when invoked.

I cannot restart VM from the UI.

It would be better to replace with Start, when stopped, indeed.

@gerboland
Copy link
Contributor

New issue: when VM in "Stopped" state, I am shown useless "Open Shell" option.

It shouldn't be useless, it should start the instance when invoked.

Maybe so, but that's not obvious from the UI.

@townsend2010
Copy link
Contributor Author

Regarding Open shell, it's analogous to multipass shell foo, which will automatically start the instance if it's not running and then once running, it will connect. This is no different and we all agreed that is the behavior we wanted. However, I'm not really sure we really want to force the user to go through 2 separate steps in the Ui to open the shell, ie, an explicit Start, then make them wait and then an explicit Open shell.

Maybe if the instance is stopped, then it says Start & open shell there? And if it's already running, it just says, Open shell like now?

@gerboland
Copy link
Contributor

I like that, it tells you what it will do.

@Saviq
Copy link
Collaborator

Saviq commented May 13, 2019

then it says Start & open shell there?

A bit verbose, but OK…

@townsend2010
Copy link
Contributor Author

townsend2010 commented May 13, 2019

A bit verbose, but OK…

I agree, but not sure what else to do since having an active action is not enough to signal to the user they can do something.

@Saviq
Copy link
Collaborator

Saviq commented May 13, 2019

I agree, but not sure what else to do since having an active action is not enough to signal to the user they can do something.

In a well-designed UI, isn't it? ;)

@townsend2010
Copy link
Contributor Author

In a well-designed UI, isn't it? ;)

Not sure what you mean? I thought it was clear that if the Open shell action is active, ie, clickable, that a user would click on it if the instance is even stopped and then they would see the terminal open with start status and then the shell is connected once the start succeeds.

But @gerboland disagrees and he's a UI guy, so not sure what else to do except say Start & open shell. Otherwise, we make the user do two explicit steps.

@ricab
Copy link
Collaborator

ricab commented May 13, 2019

In this case, I think I'd go with open shell only. I normally prefer explicit stuff, but Start & open shell seems verbose for a UI button.

I understand it may feel unclear at first, because start is also offered to the user separately. But, as @townsend2010 pointed out, shell already starts in the CLI. In both cases, I think it is reasonable to view shell opening as an end goal that may require implicit intermediary steps. And client consistency has some non-negligable value IMO. Just my two cents.

@ricab
Copy link
Collaborator

ricab commented May 13, 2019

I just went to check the design for this. Why not use "Connect" as described there?

@townsend2010
Copy link
Contributor Author

I just went to check the design for this. Why not use "Connect" as described there?

Because the "Connect" verbiage has been deprecated in favor of "Shell" like in the CLI and the design doc was never updated...at least that is how I took it when we switched the CLI from using connect to shell for this.

@ricab
Copy link
Collaborator

ricab commented May 13, 2019

@townsend2010 Ah ok, fair enough. I have the feeling you had said so already? Sorry if that was the case, I did not memorize that history bit.

@townsend2010
Copy link
Contributor Author

@ricab, I don't think I mentioned that already:) Just getting you up to speed and also leaving it open a bit that "Connect" in the GUI is still what is wanted. Things change and move yet docs aren't updates, so I'm not always sure:)

@Saviq Saviq force-pushed the client-systray-support branch from 5d62e92 to 7ef094d Compare May 13, 2019 19:26
CPack doesn't handle hyphens in the target name well
@Saviq Saviq force-pushed the client-systray-support branch from 7ef094d to ccea4d9 Compare May 13, 2019 19:54
@gerboland
Copy link
Contributor

Overall I'm ok with this, and we can apply any polish in later PRs
bors r+

bors bot added a commit that referenced this pull request May 14, 2019
565: Client systray support r=gerboland a=townsend2010

Add a client systray icon and menu.  This allows:
- Getting a list of all instances and state.
- The ability to open a shell to an instance.
- Stopping an instance.
- Getting version information.
- Displaying when an update to Multipass is available.

Co-authored-by: Chris Townsend <[email protected]>
@bors
Copy link
Contributor

bors bot commented May 14, 2019

Build failed

@townsend2010 townsend2010 merged commit ccea4d9 into master May 14, 2019
@bors bors bot deleted the client-systray-support branch May 14, 2019 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants