Skip to content

Set Dock icon on the macosx backend #14930

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

Merged
merged 2 commits into from
Dec 11, 2021

Conversation

joelfrederico
Copy link
Contributor

@joelfrederico joelfrederico commented Jul 30, 2019

PR Summary

This issue is similar to #14850/#14927. The issue is not isolated to the macos backend. It also happens in Qt5 (at least, possibly others).

Turns out Qt5 broke setWindowIcon. It seems like it is similar to this bug report: https://bugreports.qt.io/browse/QTBUG-55932. It fails silently, you request an icon change and nothing happens on macOS.

I have doubts this will be fixed without some pretty large Qt5 changes. Apple's API doesn't support .svg files. It does support a wide variety of other graphics, including vector graphics: pdf, and postscript, for instance. But Qt's API only supports .svg vector graphics.

We can work around this with png's, etc., but we already have a far superior .pdf logo. Apple users have come to expect high-quality vector graphics on their Retina displays. We should use the vector .pdf logo.

We can work around by using the ctypes lib to call Apple routines directly to avoid adding any more dependencies. It's done fairly lazily, so as not to be a performance hit on non-Apple platforms.

This appears to work for me. Could use comments and/or tests, although I have no idea how to write a unit test for an app icon in macOS.

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant

@joelfrederico
Copy link
Contributor Author

I'm not sure about unit tests. Could somebody provide feedback? I don't really have a way to unit-test any of the code, aside from perhaps checking that the ctypes/Apple api's say that I did, in fact, successfully change the icon. It sort of seems like circular reasoning: "Do the API's say they worked?"

At any rate, the icon is set for every plot on macOS with Qt5, so in a sense we are piggy-backing on those unit tests too.

Thoughts?

@joelfrederico
Copy link
Contributor Author

I didn't see a reason to reset the icon, although that is also possible. Thoughts?

@tacaswell
Copy link
Member

My knee-jerk reaction as that this is too much complexity for the problem it is solving.

From the linked bug report it suggests that the issue is that the at-conversion of svg -> QIcon does not provide a list of available sizes and then there is a bug in the OSX specific code that results in no icon being shown. Could we create a QIcon and set the missing size information?

Failing that, rendering a hi-dpi png (which we may already have due to the other backends) and using that seems like a better option.

@joelfrederico
Copy link
Contributor Author

joelfrederico commented Jul 31, 2019

I did play around with trying to get the QIcon to render/rasterize the SVG and failed. I can make another pass at it.

I did check for a high-res png and came up empty. None of them were large enough on my display. I wouldn't be surprised if the default on other backends were to use SVG, that's what Qt5 uses. I would recommend generating a larger logo if we go this route. I'm not sure how much larger- I'd want to do some math for render sizes when using a 5k monitor. Maybe just follow Apple's recommended icon sizes.

Neither are perfectly ideal if the system supports vector icons and we're providing a raster. From a performance standpoint, I'd say creating the logo from scratch is worst, rastering a SVG is better, loading a high-res png is even better, and loading a vector graphic is best.

I can also put this in the macos backend code instead of ctypes. If we need the code for the macos backend anyways, then I could expose the Objective-C functionality as an internal Python API for other backends to use. Of course this also violates encapsulation of the backends, which may or may not be a big deal here, and might require a Python wrapper so that other platforms don't complain about the missing macos module.

I can implement everything except for generating a new icon. I could probably figure that out, I'm just not sure of the process for doing that and adding a photo to the repo.

What would you like me to do?

@tacaswell
Copy link
Member

I can also put this in the macos backend code instead of ctypes. If we need the code for the macos backend anyways, then I could expose the Objective-C functionality as an internal Python API for other backends to use. Of course this also violates encapsulation of the backends, which may or may not be a big deal here, and might require a Python wrapper so that other platforms don't complain about the missing macos module.

This seems like a promising path to explore.

generating (and caching) the png on the fly seems like a good option too.

@anntzer
Copy link
Contributor

anntzer commented Jul 31, 2019

The icons are generated with tools/make_icons.py (#14941 may help a bit). You'll need to edit it to generate bigger sized icons.

@joelfrederico
Copy link
Contributor Author

I can also put this in the macos backend code instead of ctypes. If we need the code for the macos backend anyways, then I could expose the Objective-C functionality as an internal Python API for other backends to use. Of course this also violates encapsulation of the backends, which may or may not be a big deal here, and might require a Python wrapper so that other platforms don't complain about the missing macos module.

This seems like a promising path to explore.

My last push went with this solution. If you like it, I'll add tests.

@joelfrederico joelfrederico changed the title Work around Qt5's bug/API issues setting Dock icon in macOS Set Dock icon in Qt5 and macosx backends on macOS Aug 1, 2019
@joelfrederico
Copy link
Contributor Author

joelfrederico commented Aug 1, 2019

Wrote tests, fixed a few things. This only addresses the matplotlib icon not showing up on macosx and Qt5Agg backgrounds on macOS. I haven’t tested or worked on other backends.

@joelfrederico
Copy link
Contributor Author

@anntzer Okay, pushed fixes, could use another review.

@joelfrederico
Copy link
Contributor Author

Okay @anntzer, another push another review?

@anntzer
Copy link
Contributor

anntzer commented Aug 2, 2019

looks fine to me, but now you need to find an actual mac user (ie not me) to test this :p

@joelfrederico
Copy link
Contributor Author

joelfrederico commented Aug 2, 2019

Any suggestions? I assume I don’t count

@anntzer
Copy link
Contributor

anntzer commented Aug 2, 2019

Tagged the PR, I'm sure they'll show up :p

@joelfrederico
Copy link
Contributor Author

@anntzer Should we bump this somehow? Seems like nobody has noticed, but I'm not sure how long that usually takes here.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

I've been away, but wasn't popping this to the top of my queue because I wasn't clear that Matplotlib is an application, and hence am not clear why we would set the dock icon.

@joelfrederico
Copy link
Contributor Author

@jklymak Honestly didn't consider it, since the Qt backends set the app icon on other platforms. Maybe the icon shouldn't be set in general?

@joelfrederico
Copy link
Contributor Author

I'm sure it needs cleanup and style changes. I'd welcome any suggestions/tweaks! There are quite a few choices that could be done many ways and I don't know what would be preferred.

Copy link
Contributor

@greglucas greglucas left a comment

Choose a reason for hiding this comment

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

I do get an icon showing up, which looks nice!

But, when interacting there is something else going on when I open new windows. I get a segfault when clicking on the subplot tool icon with this update, so something might not be working quite right between the manager and the new window that gets popped up with subplot tools.

Comment on lines 70 to 72
if 'com.adobe.pdf' in _macosx.FigureManager._get_image_types():
icon_path = str(cbook._get_data_path('images/matplotlib.pdf'))
_macosx.FigureManager.__init__(self, canvas, icon_path)
Copy link
Contributor

Choose a reason for hiding this comment

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

My personal preference would be to keep it as you had it before with an explicit _set_icon() function rather than changing the init signature. But, I'm not sure I have a huge preference, others may have stronger feelings around this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't have strong feelings, I'll do whatever the consensus is. (Or just use your suggestion if I don't hear anything within a day or two.)

@joelfrederico
Copy link
Contributor Author

I think the segfault you were experiencing was due to other code which has since been resolved. I rebased to a new point in main, could you test again?

Could we also modify the PR to not target Qt? I've moved Qt into another PR.

@greglucas greglucas changed the title Set Dock icon in Qt5 and macosx backends on macOS Set Dock icon on the macosx backend Nov 30, 2021
@greglucas
Copy link
Contributor

Yep, it seems to work well now without a segfault. Lets see if others have additional comments over the next few days about the architecture comments, but I think this is looking good and splitting it into separate PRs is also nice, thanks for doing that!

@joelfrederico joelfrederico marked this pull request as ready for review November 30, 2021 08:14
@joelfrederico
Copy link
Contributor Author

@greglucas I figured it's been long enough, so I went back to a set_icon method. I made it static because it doesn't reference any saved state.

@joelfrederico
Copy link
Contributor Author

@greglucas Should be good now?

Copy link
Contributor

@greglucas greglucas left a comment

Choose a reason for hiding this comment

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

Yep, this looks good to me and works well with multiple windows and subplot params!

I thought I made an earlier comment, but now I can't seem to find it, so I must not have hit enter... I was wondering if you think we should put a try/except clause around the Python set_icon() call? Right now if I put a bad file-path in (lets say someone removed the MPL data path), I get a Runtime Exception and MPL stops. QT5agg continues on without issue and tkagg logs the exception and continues on. I think that we should perhaps adopt the tkagg philosophy here and log this and continue on...

try:
window.iconphoto(False, icon_img)
except Exception as exc:
# log the failure (due e.g. to Tk version), but carry on
_log.info('Could not load matplotlib icon: %s', exc)

@joelfrederico
Copy link
Contributor Author

Right now passing tests let us know that set_icon is working. If you want to do that we'd have to add a test for set_icon because it would no longer be covered.

@joelfrederico
Copy link
Contributor Author

@greglucas What do I need to do to wrap this up?

@greglucas
Copy link
Contributor

You've got my approval, but someone else will need to test it out before merging still, so just waiting on the second review which can take a bit of time since it is all volunteer basis. Thanks for your patience!

@joelfrederico
Copy link
Contributor Author

@tacaswell @anntzer Any chance you’d know somebody who we could ping to merge this?

@anntzer
Copy link
Contributor

anntzer commented Dec 11, 2021

Perhaps @dstansby or @jklymak can help on that?

Copy link
Member

@dstansby dstansby left a comment

Choose a reason for hiding this comment

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

This works for me. Thanks a lot for this PR - after so many years using Matplotlib without a dock icon, it feels a bit surreal to finally see one!

@dstansby dstansby merged commit b0f7b8a into matplotlib:main Dec 11, 2021
@tacaswell
Copy link
Member

Thanks @joelfrederico for sticking with us and getting this done!

@joelfrederico joelfrederico deleted the macos-common-icon branch December 13, 2021 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants