Skip to content

Commit 994e7d6

Browse files
committed
Exposed set_icon in _macosx, wrapped for other backends, used in Qt5
1 parent 16e2d2f commit 994e7d6

File tree

3 files changed

+113
-37
lines changed

3 files changed

+113
-37
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import sys
2+
3+
if sys.platform != "darwin":
4+
def set_mac_icon(path):
5+
pass
6+
else:
7+
from . import _macosx
8+
def set_mac_icon(path):
9+
_macosx.set_icon(path)

lib/matplotlib/backends/backend_qt5.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,12 @@ def __init__(self, canvas, num):
540540

541541
self.window.setWindowTitle("Figure %d" % num)
542542
image = str(cbook._get_data_path('images/matplotlib.svg'))
543+
544+
if sys.platform == "darwin":
545+
from . import backend_macos_common
546+
image = str(cbook._get_data_path('images/matplotlib.pdf'))
547+
backend_macos_common.set_mac_icon(image)
548+
543549
self.window.setWindowIcon(QtGui.QIcon(image))
544550

545551
# Give the keyboard focus to the figure instead of the

src/_macosx.m

Lines changed: 98 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -178,76 +178,129 @@ static int wait_for_stdin(void)
178178
return 1;
179179
}
180180

181-
static int set_icon(void)
181+
PyObject* _get_pdf_icon_path(void)
182182
{
183183
PyObject* mpl = PyImport_ImportModule("matplotlib");
184184
if (!mpl)
185185
{
186-
return -1;
186+
return NULL;
187187
}
188188

189189
PyObject* get_data_path = PyObject_GetAttrString(mpl, "get_data_path");
190190
if (!get_data_path)
191191
{
192-
Py_DECREF(mpl);
193-
return -1;
192+
Py_DECREF(mpl);
193+
return NULL;
194194
}
195195

196196
PyObject* arg = PyTuple_New(0);
197197
if (!arg)
198198
{
199-
Py_DECREF(mpl);
200-
Py_DECREF(get_data_path);
201-
return -1;
199+
Py_DECREF(mpl);
200+
Py_DECREF(get_data_path);
201+
return NULL;
202202
}
203203

204204
PyObject* path = PyObject_Call(get_data_path, arg, NULL);
205205
if (!path)
206206
{
207-
Py_DECREF(mpl);
208-
Py_DECREF(get_data_path);
209-
Py_DECREF(arg);
210-
return -1;
207+
Py_DECREF(mpl);
208+
Py_DECREF(get_data_path);
209+
Py_DECREF(arg);
210+
return NULL;
211211
}
212212

213213
PyObject* pdf_rel = PyUnicode_FromString("/images/matplotlib.pdf");
214+
if (!pdf_rel)
215+
{
216+
Py_DECREF(mpl);
217+
Py_DECREF(get_data_path);
218+
Py_DECREF(arg);
219+
Py_DECREF(path);
220+
return NULL;
221+
}
222+
214223
PyObject* pdf_absolute = PyUnicode_Concat(path, pdf_rel);
215-
if (!pdf_absolute)
224+
225+
Py_DECREF(mpl);
226+
Py_DECREF(get_data_path);
227+
Py_DECREF(arg);
228+
Py_DECREF(path);
229+
Py_DECREF(pdf_rel);
230+
231+
return pdf_absolute;
232+
}
233+
234+
static PyObject* set_icon(PyObject* ignored, PyObject* path)
235+
{
236+
if (!path)
216237
{
217-
Py_DECREF(mpl);
218-
Py_DECREF(get_data_path);
219-
Py_DECREF(arg);
220-
Py_DECREF(path);
221-
Py_DECREF(pdf_rel);
238+
PyErr_SetString(PyExc_RuntimeError, "No path passed");
239+
return NULL;
222240
}
223241

224242
Py_ssize_t size;
225-
const char* path_string = PyUnicode_AsUTF8AndSize(pdf_absolute, &size);
243+
// API indicates Python owns path_string; we don't need to free it
244+
const char* path_string = PyUnicode_AsUTF8AndSize(path, &size);
226245
if (!path_string)
227246
{
228-
Py_DECREF(mpl);
229-
Py_DECREF(get_data_path);
230-
Py_DECREF(arg);
231-
Py_DECREF(path);
232-
Py_DECREF(pdf_rel);
233-
Py_DECREF(pdf_absolute);
234-
return -1;
247+
PyErr_SetString(PyExc_TypeError, "bad argument type, must be UTF-8 "
248+
"path to icon");
249+
return NULL;
235250
}
236251

237-
NSString* path_nsstring =
238-
[[NSString alloc] initWithUTF8String: path_string];
252+
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
239253

240-
NSImage* image = [[NSImage alloc] initByReferencingFile: path_nsstring];
254+
NSImage* image;
255+
@try
256+
{
257+
NSString* path_nsstring =
258+
[[NSString alloc] initWithUTF8String: path_string];
241259

242-
NSApplication* app = [NSApplication sharedApplication];
243-
app.applicationIconImage = image;
260+
image =
261+
[[NSImage alloc] initByReferencingFile: path_nsstring];
262+
}
263+
@catch (NSException *e)
264+
{
244265

245-
Py_DECREF(mpl);
246-
Py_DECREF(get_data_path);
247-
Py_DECREF(arg);
248-
Py_DECREF(path);
249-
Py_DECREF(pdf_rel);
250-
Py_DECREF(pdf_absolute);
266+
PyErr_SetString(PyExc_RuntimeError, "could not load icon");
267+
[pool drain];
268+
return NULL;
269+
}
270+
271+
@try
272+
{
273+
NSApplication* app = [NSApplication sharedApplication];
274+
app.applicationIconImage = image;
275+
}
276+
@catch (NSException *e)
277+
{
278+
PyErr_SetString(PyExc_RuntimeError, "could not set icon");
279+
[pool drain];
280+
return NULL;
281+
}
282+
283+
[pool drain];
284+
Py_RETURN_NONE;
285+
}
286+
287+
static int _set_icon(void)
288+
{
289+
PyObject* pdf_path = _get_pdf_icon_path();
290+
if (!pdf_path)
291+
{
292+
return -1;
293+
}
294+
295+
PyObject* result = set_icon(NULL, pdf_path);
296+
if (!result)
297+
{
298+
Py_DECREF(pdf_path);
299+
return -1;
300+
}
301+
302+
Py_DECREF(pdf_path);
303+
Py_DECREF(result);
251304
return 0;
252305
}
253306

@@ -813,7 +866,10 @@ static CGFloat _get_device_scale(CGContextRef cr)
813866

814867
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
815868

816-
set_icon();
869+
if (_set_icon() != 0)
870+
{
871+
return -1;
872+
}
817873

818874
self->window = [self->window initWithContentRect: rect
819875
styleMask: NSTitledWindowMask
@@ -2702,6 +2758,11 @@ static bool verify_framework(void)
27022758
METH_VARARGS,
27032759
"Sets the active cursor."
27042760
},
2761+
{"set_icon",
2762+
set_icon,
2763+
METH_O,
2764+
"Sets the Dock icon in macOS"
2765+
},
27052766
{NULL, NULL, 0, NULL} /* sentinel */
27062767
};
27072768

0 commit comments

Comments
 (0)