Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dbfbb44

Browse files
committed
Set Win32 AppUserModelId to fix taskbar icons.
1 parent 5445d77 commit dbfbb44

File tree

7 files changed

+86
-0
lines changed

7 files changed

+86
-0
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,8 @@ def new_figure_manager_given_figure(cls, num, figure):
845845
Create a new figure manager instance for the given figure.
846846
"""
847847
with _restore_foreground_window_at_end():
848+
if cbook._get_running_interactive_framework() is None:
849+
cbook._setup_new_guiapp()
848850
window = tk.Tk(className="matplotlib")
849851
window.withdraw()
850852

lib/matplotlib/backends/backend_gtk3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,4 +927,5 @@ def trigger_manager_draw(manager):
927927
@staticmethod
928928
def mainloop():
929929
if Gtk.main_level() == 0:
930+
cbook._setup_new_guiapp()
930931
Gtk.main()

lib/matplotlib/backends/backend_qt5.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def _create_qApp():
127127
pass
128128
qApp = QtWidgets.QApplication(["matplotlib"])
129129
qApp.lastWindowClosed.connect(qApp.quit)
130+
cbook._setup_new_guiapp()
130131
else:
131132
qApp = app
132133

lib/matplotlib/backends/backend_wx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,7 @@ def new_figure_manager(cls, num, *args, **kwargs):
16451645
if wxapp is None:
16461646
wxapp = wx.App(False)
16471647
wxapp.SetExitOnFrameDelete(True)
1648+
cbook._setup_new_guiapp()
16481649
# Retain a reference to the app object so that it does not get
16491650
# garbage collected.
16501651
_BackendWx._theWxApp = wxapp

lib/matplotlib/cbook/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import numpy as np
2929

3030
import matplotlib
31+
from matplotlib import _c_internal_utils
3132
from .deprecation import (
3233
deprecated, warn_deprecated,
3334
_rename_parameter, _delete_parameter, _make_keyword_only,
@@ -2319,3 +2320,17 @@ def _backend_module_name(name):
23192320
"""
23202321
return (name[9:] if name.startswith("module://")
23212322
else "matplotlib.backends.backend_{}".format(name.lower()))
2323+
2324+
2325+
def _setup_new_guiapp():
2326+
"""
2327+
Perform OS-dependent setup when Matplotlib creates a new GUI application.
2328+
"""
2329+
# Windows: If not explicit app user model id has been set yet (so we're not
2330+
# already embedded), then set it to "matplotlib", so that taskbar icons are
2331+
# correct.
2332+
try:
2333+
_c_internal_utils.Win32_GetCurrentProcessExplicitAppUserModelID()
2334+
except OSError:
2335+
_c_internal_utils.Win32_SetCurrentProcessExplicitAppUserModelID(
2336+
"matplotlib")

setupext.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,11 @@ def get_extensions(self):
338338
add_libagg_flags_and_sources(ext)
339339
FreeType().add_flags(ext)
340340
yield ext
341+
# c_internal_utils
342+
ext = Extension(
343+
"matplotlib._c_internal_utils", ["src/_c_internal_utils.c"],
344+
libraries={"win32": ["ole32", "shell32"]}.get(sys.platform, []))
345+
yield ext
341346
# contour
342347
ext = Extension(
343348
"matplotlib._contour", [

src/_c_internal_utils.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#define PY_SSIZE_T_CLEAN
2+
#include <Python.h>
3+
#ifdef _WIN32
4+
#include <Objbase.h>
5+
#include <Shobjidl.h>
6+
#endif
7+
8+
static PyObject* mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
9+
{
10+
#ifdef _WIN32
11+
wchar_t* appid = NULL;
12+
HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
13+
if (FAILED(hr)) {
14+
return PyErr_SetFromWindowsErr(hr);
15+
}
16+
PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
17+
CoTaskMemFree(appid);
18+
return py_appid;
19+
#else
20+
Py_RETURN_NONE;
21+
#endif
22+
}
23+
24+
static PyObject* mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
25+
{
26+
#ifdef _WIN32
27+
wchar_t* appid = PyUnicode_AsWideCharString(arg, NULL);
28+
if (!appid) {
29+
return NULL;
30+
}
31+
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
32+
PyMem_Free(appid);
33+
if (FAILED(hr)) {
34+
return PyErr_SetFromWindowsErr(hr);
35+
}
36+
Py_RETURN_NONE;
37+
#else
38+
Py_RETURN_NONE;
39+
#endif
40+
}
41+
42+
static PyMethodDef functions[] = {
43+
{"Win32_GetCurrentProcessExplicitAppUserModelID",
44+
(PyCFunction)mpl_GetCurrentProcessExplicitAppUserModelID, METH_NOARGS,
45+
"Win32_GetCurrentProcessExplicitAppUserModelID()\n--\n\n"
46+
"Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID. On \n"
47+
"non-Windows platforms, always returns None."},
48+
{"Win32_SetCurrentProcessExplicitAppUserModelID",
49+
(PyCFunction)mpl_SetCurrentProcessExplicitAppUserModelID, METH_O,
50+
"Win32_SetCurrentProcessExplicitAppUserModelID(appid, /)\n--\n\n"
51+
"Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID. On \n"
52+
"non-Windows platforms, a no-op."},
53+
{NULL, NULL}}; // sentinel.
54+
static PyModuleDef util_module = {
55+
PyModuleDef_HEAD_INIT, "_c_internal_utils", "", 0, functions, NULL, NULL, NULL, NULL};
56+
57+
#pragma GCC visibility push(default)
58+
PyMODINIT_FUNC PyInit__c_internal_utils(void)
59+
{
60+
return PyModule_Create(&util_module);
61+
}

0 commit comments

Comments
 (0)