Background button: Create thumbnail asynchronously
This commit is contained in:
@@ -11,14 +11,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<class name="image-button"/>
|
<class name="image-button"/>
|
||||||
</style>
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkPicture">
|
<object class="GtkPicture" id="thumbnail">
|
||||||
<binding name="paintable">
|
|
||||||
<closure function="getThumbnail" type="GdkPaintable">
|
|
||||||
<lookup name="uri">BackgroundButton</lookup>
|
|
||||||
<lookup name="thumb-width">BackgroundButton</lookup>
|
|
||||||
<lookup name="thumb-height">BackgroundButton</lookup>
|
|
||||||
</closure>
|
|
||||||
</binding>
|
|
||||||
<property name="can-shrink">False</property>
|
<property name="can-shrink">False</property>
|
||||||
<property name="width-request" bind-source="BackgroundButton" bind-property="thumb-width" bind-flags="sync-create"/>
|
<property name="width-request" bind-source="BackgroundButton" bind-property="thumb-width" bind-flags="sync-create"/>
|
||||||
<property name="height-request" bind-source="BackgroundButton" bind-property="thumb-height" bind-flags="sync-create"/>
|
<property name="height-request" bind-source="BackgroundButton" bind-property="thumb-height" bind-flags="sync-create"/>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const _ = extensionUtils.gettext;
|
|||||||
var BackgroundButton = GObject.registerClass({
|
var BackgroundButton = GObject.registerClass({
|
||||||
GTypeName: 'BackgroundButton',
|
GTypeName: 'BackgroundButton',
|
||||||
Template: 'resource:///org/gnome/shell/extensions/nightthemeswitcher/preferences/ui/BackgroundButton.ui',
|
Template: 'resource:///org/gnome/shell/extensions/nightthemeswitcher/preferences/ui/BackgroundButton.ui',
|
||||||
InternalChildren: ['filechooser'],
|
InternalChildren: ['filechooser', 'thumbnail'],
|
||||||
Properties: {
|
Properties: {
|
||||||
uri: GObject.ParamSpec.string(
|
uri: GObject.ParamSpec.string(
|
||||||
'uri',
|
'uri',
|
||||||
@@ -20,7 +20,7 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
GObject.ParamFlags.READWRITE,
|
GObject.ParamFlags.READWRITE,
|
||||||
null
|
null
|
||||||
),
|
),
|
||||||
thumb_width: GObject.ParamSpec.int(
|
thumbWidth: GObject.ParamSpec.int(
|
||||||
'thumb-width',
|
'thumb-width',
|
||||||
'Thumbnail width',
|
'Thumbnail width',
|
||||||
'Width of the displayed thumbnail',
|
'Width of the displayed thumbnail',
|
||||||
@@ -28,7 +28,7 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
0, 600,
|
0, 600,
|
||||||
180
|
180
|
||||||
),
|
),
|
||||||
thumb_height: GObject.ParamSpec.int(
|
thumbHeight: GObject.ParamSpec.int(
|
||||||
'thumb-height',
|
'thumb-height',
|
||||||
'Thumbnail height',
|
'Thumbnail height',
|
||||||
'Height of the displayed thumbnail',
|
'Height of the displayed thumbnail',
|
||||||
@@ -38,6 +38,8 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
}, class BackgroundButton extends Gtk.Button {
|
}, class BackgroundButton extends Gtk.Button {
|
||||||
|
#uri;
|
||||||
|
|
||||||
constructor(props = {}) {
|
constructor(props = {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.#setupSize();
|
this.#setupSize();
|
||||||
@@ -45,15 +47,30 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
this.#setupFileChooserFilter();
|
this.#setupFileChooserFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uri() {
|
||||||
|
return this.#uri || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set uri(uri) {
|
||||||
|
if (uri === this.#uri)
|
||||||
|
return;
|
||||||
|
this.#uri = uri;
|
||||||
|
this.notify('uri');
|
||||||
|
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
|
||||||
|
this.#updateThumbnail();
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#setupSize() {
|
#setupSize() {
|
||||||
const display = Gdk.Display.get_default();
|
const display = Gdk.Display.get_default();
|
||||||
const monitor = display.get_monitors().get_item(0);
|
const monitor = display.get_monitors().get_item(0);
|
||||||
if (monitor.width_mm === 0 || monitor.height_mm === 0)
|
if (monitor.width_mm === 0 || monitor.height_mm === 0)
|
||||||
return;
|
return;
|
||||||
if (monitor.width_mm > monitor.height_mm)
|
if (monitor.width_mm > monitor.height_mm)
|
||||||
this.thumb_height *= monitor.height_mm / monitor.width_mm;
|
this.thumbHeight *= monitor.height_mm / monitor.width_mm;
|
||||||
else
|
else
|
||||||
this.thumb_width *= monitor.width_mm / monitor.height_mm;
|
this.thumbWidth *= monitor.width_mm / monitor.height_mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
#setupDropTarget() {
|
#setupDropTarget() {
|
||||||
@@ -113,15 +130,17 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
this.openFileChooser();
|
this.openFileChooser();
|
||||||
}
|
}
|
||||||
|
|
||||||
getThumbnail(_widget, uri, width, height) {
|
#updateThumbnail() {
|
||||||
if (!uri)
|
this._thumbnail.paintable = null;
|
||||||
return null;
|
|
||||||
|
|
||||||
const file = Gio.File.new_for_uri(uri);
|
if (!this.uri)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const file = Gio.File.new_for_uri(this.uri);
|
||||||
const contentType = Gio.content_type_guess(file.get_basename(), null)[0];
|
const contentType = Gio.content_type_guess(file.get_basename(), null)[0];
|
||||||
|
|
||||||
if (!this.#isContentTypeSupported(contentType))
|
if (!this.#isContentTypeSupported(contentType))
|
||||||
return null;
|
return;
|
||||||
|
|
||||||
let path;
|
let path;
|
||||||
if (Gio.content_type_equals(contentType, 'application/xml')) {
|
if (Gio.content_type_equals(contentType, 'application/xml')) {
|
||||||
@@ -129,26 +148,28 @@ var BackgroundButton = GObject.registerClass({
|
|||||||
const contents = decoder.decode(file.load_contents(null)[1]);
|
const contents = decoder.decode(file.load_contents(null)[1]);
|
||||||
try {
|
try {
|
||||||
path = contents.match(/<file>(.+)<\/file>/m)[1];
|
path = contents.match(/<file>(.+)<\/file>/m)[1];
|
||||||
|
if (!this.#isContentTypeSupported(Gio.content_type_guess(path, null)[0]))
|
||||||
|
throw new Error();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(`[${Me.metadata.name}] No suitable background file found in ${file.get_path()}`);
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
path = file.get_path();
|
path = file.get_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pixbuf = GdkPixbuf.Pixbuf.new_from_file(path);
|
const pixbuf = GdkPixbuf.Pixbuf.new_from_file(path);
|
||||||
const scale = pixbuf.width / pixbuf.height > width / height ? height / pixbuf.height : width / pixbuf.width;
|
const scale = pixbuf.width / pixbuf.height > this.thumbWidth / this.thumbHeight ? this.thumbHeight / pixbuf.height : this.thumbWidth / pixbuf.width;
|
||||||
const thumbPixbuf = GdkPixbuf.Pixbuf.new(pixbuf.colorspace, pixbuf.has_alpha, pixbuf.bits_per_sample, width, height);
|
const thumbPixbuf = GdkPixbuf.Pixbuf.new(pixbuf.colorspace, pixbuf.has_alpha, pixbuf.bits_per_sample, this.thumbWidth, this.thumbHeight);
|
||||||
pixbuf.scale(
|
pixbuf.scale(
|
||||||
thumbPixbuf,
|
thumbPixbuf,
|
||||||
0, 0,
|
0, 0,
|
||||||
width, height,
|
this.thumbWidth, this.thumbHeight,
|
||||||
-(pixbuf.width * scale - width) / 2, -(pixbuf.height * scale - height) / 2,
|
-(pixbuf.width * scale - this.thumbWidth) / 2, -(pixbuf.height * scale - this.thumbHeight) / 2,
|
||||||
scale, scale,
|
scale, scale,
|
||||||
GdkPixbuf.InterpType.TILES
|
GdkPixbuf.InterpType.TILES
|
||||||
);
|
);
|
||||||
|
|
||||||
return Gdk.Texture.new_for_pixbuf(thumbPixbuf);
|
this._thumbnail.paintable = Gdk.Texture.new_for_pixbuf(thumbPixbuf);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user