[polari] main: Add GTK4 polyfill
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari] main: Add GTK4 polyfill
- Date: Fri, 3 Sep 2021 11:17:32 +0000 (UTC)
commit cf0854d24c0c3b9b0bf9a724184dbcc8a79c1325
Author: Florian Müllner <fmuellner gnome org>
Date: Fri Oct 9 21:45:49 2020 +0200
main: Add GTK4 polyfill
Some of the GTK4 changes are easy to implement as polyfill, so we
can port to them before doing the actual switch to the new version.
Part-of: <https://gitlab.gnome.org/GNOME/polari/-/merge_requests/228>
src/gtkShim.js | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.js | 3 +
src/meson.build | 1 +
3 files changed, 181 insertions(+)
---
diff --git a/src/gtkShim.js b/src/gtkShim.js
new file mode 100644
index 00000000..fedb8e47
--- /dev/null
+++ b/src/gtkShim.js
@@ -0,0 +1,177 @@
+import GLib from 'gi://GLib';
+import Graphene from 'gi://Graphene';
+import Pango from 'gi://Pango';
+
+import gi from 'gi';
+
+/* eslint brace-style: ["error", "1tbs", { "allowSingleLine": true }] */
+/* eslint-disable no-invalid-this */
+
+/** @returns {void} */
+export function init() {
+ let Gtk, Gdk;
+
+ try {
+ Gtk = gi.require('Gtk', '3.0');
+ Gdk = gi.require('Gdk', '3.0');
+ } catch (e) {
+ // assume we are already on GTK4
+ return;
+ }
+
+ Gtk.show_uri_full = function (window, uri, timestamp, cancellable, callback) {
+ GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
+ callback(window, { uri, timestamp });
+ return GLib.SOURCE_REMOVE;
+ });
+ };
+ Gtk.show_uri_full_finish = function (window, result) {
+ const { uri, timestamp } = result;
+ return Gtk.show_uri_on_window(window, uri, timestamp);
+ };
+
+ Gtk.EventController.prototype.get_current_event = function () {
+ return Gtk.get_current_event();
+ };
+ Gtk.EventControllerKey.prototype.forward = function (widget) {
+ widget.event(Gtk.get_current_event());
+ };
+ Gtk.GestureClick = Gtk.GestureMultiPress;
+
+ Gtk.Widget.prototype.add_css_class = function (cssClass) {
+ this.get_style_context().add_class(cssClass);
+ };
+ Gtk.Widget.prototype.remove_css_class = function (cssClass) {
+ this.get_style_context().remove_class(cssClass);
+ };
+
+ Gtk.StyleContext.add_provider_for_display = function (dsp, ...args) {
+ this.add_provider_for_screen(dsp.get_default_screen(), ...args);
+ };
+
+ Gtk.AccessibleProperty = { LABEL: 4 };
+ Gtk.Widget.prototype.update_property = function (props, values) {
+ const label = values[props.findIndex(p => p === 4)];
+ if (label)
+ this.get_accessible().set_name(label);
+ };
+
+ Gtk.Widget.prototype.get_root = Gtk.Widget.prototype.get_toplevel;
+
+ Gtk.Widget.prototype.measure = function (orientation) {
+ if (orientation === Gtk.Orientation.HORIZONTAL)
+ return this.get_preferred_width();
+ else
+ return this.get_preferred_height();
+ };
+
+ Gtk.Widget.prototype[Symbol.iterator] = function* () {
+ const children = this.get_children();
+ for (const c of children)
+ yield c;
+ };
+ Gtk.Widget.prototype.get_first_child = function () {
+ const [child] = this;
+ return child ?? null;
+ };
+ Gtk.Widget.prototype.get_clipboard = function () {
+ return Gtk.Clipboard.get_default(this.get_display());
+ };
+ Gtk.Clipboard.prototype.set = function (text) {
+ this.set_text(text, -1);
+ };
+
+ /* Widget-specific container-method replacements */
+ Gtk.Box.prototype.append = Gtk.Container.prototype.add;
+ Gtk.ListBox.prototype.append = Gtk.Container.prototype.add;
+
+ function setChild(child) {
+ if (child)
+ this.add(child);
+ else if ((child = this.get_first_child()))
+ this.remove(child);
+ }
+ Gtk.Revealer.prototype.set_child = setChild;
+ Gtk.Frame.prototype.set_child = setChild;
+ Gtk.ScrolledWindow.prototype.set_child = setChild;
+ Gtk.ListBoxRow.prototype.set_child = setChild;
+ Gtk.Overlay.prototype.set_child = setChild;
+ Gtk.Popover.prototype.set_child = setChild;
+
+ /* Other widget-specific replacements */
+ Gtk.Entry.prototype.get_delegate = function () {
+ return this;
+ };
+ Gtk.Entry.prototype.compute_cursor_extents = function (pos) {
+ const index = this.text_index_to_layout_index(pos);
+ const wordPos = this.get_layout().index_to_pos(index);
+ const [offX, offY_] = this.get_layout_offsets();
+ const extents = new Graphene.Rect();
+ extents.init(offX + wordPos.x / Pango.SCALE, 0, 0, 1);
+ return [extents, extents];
+ };
+ Gtk.Entry.prototype.compute_bounds = function () {
+ return [true, new Graphene.Rect()];
+ };
+ Gtk.Popover.prototype.get_parent = Gtk.Popover.prototype.get_relative_to;
+ Gtk.Popover.prototype.set_parent = Gtk.Popover.prototype.set_relative_to;
+ Gtk.Popover.prototype.unparent = function () {
+ this.relative_to = null;
+ };
+
+ Gtk.PopoverMenu.prototype.set_menu_model = function (menu) {
+ this.bind_model(menu, null);
+ };
+
+ Gtk.TextView.prototype.set_cursor_from_name = function (name) {
+ const cursor = Gdk.Cursor.new_from_name(this.get_display(), name);
+ this.get_window(Gtk.TextWindowType.TEXT).set_cursor(cursor);
+ };
+
+ Gtk.ListStore.prototype.insert_with_values = Gtk.ListStore.prototype.insert_with_valuesv;
+
+ /* Properties */
+ injectProperty(Gtk.Popover.prototype, 'autohide',
+ function () { return this.modal; },
+ function (value) { this.modal = value; });
+
+ injectProperty(Gtk.Spinner.prototype, 'spinning',
+ function () { return this.active; },
+ function (value) { this.active = value; });
+
+ injectProperty(Gtk.Button.prototype, 'has_frame',
+ function () { return this.relief !== Gtk.ReliefStyle.NONE; },
+ function (value) {
+ this.relief = value
+ ? Gtk.ReliefStyle.NORMAL : Gtk.ReliefStyle.NONE;
+ });
+
+ injectProperty(Gtk.ScrolledWindow.prototype, 'has_frame',
+ function () { return this.shadow_type !== Gtk.ShadowType.NONE; },
+ function (value) {
+ this.shadow_type = value
+ ? Gtk.ShadowType.ETCHED_IN : Gtk.ShadowType.NONE;
+ });
+}
+
+/**
+ * @param {prototype} prototype to be patched
+ * @param {string} name - property name
+ * @param {Function} get - getter funcition
+ * @param {Function} set - setter funcition
+ * @returns {void}
+ */
+function injectProperty(prototype, name, get, set) {
+ Object.defineProperty(prototype, name, { get, set });
+
+ const realInit = prototype._init;
+ prototype._init = function (params = {}) {
+ const injected = params[name];
+ delete params[name];
+
+ realInit.call(this, params);
+
+ if (injected !== undefined)
+ this[name] = injected;
+ };
+}
diff --git a/src/main.js b/src/main.js
index bf2cf104..0af2b10f 100755
--- a/src/main.js
+++ b/src/main.js
@@ -35,6 +35,9 @@ if (!pkg.checkSymbol('Soup', '3.0'))
import Application from './application.js';
+import * as GtkShim from './gtkShim.js';
+GtkShim.init();
+
let application = new Application();
if (GLib.getenv('POLARI_PERSIST'))
application.hold();
diff --git a/src/meson.build b/src/meson.build
index 275d9eda..164c272c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -12,6 +12,7 @@ js_sources = [
'chatView.js',
'connections.js',
'entryArea.js',
+ 'gtkShim.js',
'initialSetup.js',
'ircParser.js',
'joinDialog.js',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]