1
0
Fork 0
Browse Source

Add Gnome extension GSConnect

master
Emanuele HF 2 years ago
parent
commit
918e8dcee0
  1. 19
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/config.js
  2. 431
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/extension.js
  3. 112
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/gsconnect-preferences
  4. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ar/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  5. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/be/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  6. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ca/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  7. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/cs/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  8. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/da/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  9. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/de/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  10. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/es/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  11. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/et/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  12. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  13. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/gl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  14. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/hu/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  15. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/it/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  16. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/lt/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  17. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_BE/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  18. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_NL/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  19. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  20. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pt_BR/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  21. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ru/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  22. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  23. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  24. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr@latin/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  25. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/tr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  26. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/uk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  27. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_CN/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  28. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_TW/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo
  29. 11
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/metadata.json
  30. 183
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/nautilus-gsconnect.py
  31. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/org.gnome.Shell.Extensions.GSConnect.gresource
  32. 41
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/__init__.js
  33. 1088
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/device.js
  34. 312
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/keybindings.js
  35. 657
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/service.js
  36. 29
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/prefs.js
  37. BIN
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/gschemas.compiled
  38. 179
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/org.gnome.Shell.Extensions.GSConnect.gschema.xml
  39. 401
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/__init__.js
  40. 976
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/backends/lan.js
  41. 67
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/__init__.js
  42. 312
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/atspi.js
  43. 283
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/clipboard.js
  44. 703
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/contacts.js
  45. 641
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/input.js
  46. 1029
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/mpris.js
  47. 440
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/notification.js
  48. 265
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/pulseaudio.js
  49. 116
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/session.js
  50. 185
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/sound.js
  51. 226
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/upower.js
  52. 738
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/core.js
  53. 728
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js
  54. 1047
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/device.js
  55. 500
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/manager.js
  56. 215
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/nativeMessagingHost.js
  57. 258
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugin.js
  58. 394
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/battery.js
  59. 178
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/clipboard.js
  60. 456
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/contacts.js
  61. 245
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/findmyphone.js
  62. 319
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mousepad.js
  63. 878
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mpris.js
  64. 713
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/notification.js
  65. 241
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/photo.js
  66. 69
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/ping.js
  67. 52
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/presenter.js
  68. 240
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/runcommand.js
  69. 555
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sftp.js
  70. 481
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/share.js
  71. 527
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sms.js
  72. 200
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/systemvolume.js
  73. 241
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/telephony.js
  74. 49
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/__init__.js
  75. 638
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/contacts.js
  76. 223
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/legacyMessaging.js
  77. 1312
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/messaging.js
  78. 299
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/mousepad.js
  79. 174
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/notification.js
  80. 248
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/service.js
  81. 279
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/dbus.js
  82. 167
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/uri.js
  83. 43
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/__init__.js
  84. 380
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/clipboard.js
  85. 246
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/device.js
  86. 649
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/gmenu.js
  87. 102
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/keybindings.js
  88. 439
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/notification.js
  89. 302
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/tooltip.js
  90. 216
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/utils.js
  91. 109
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/stylesheet.css
  92. 516
      .local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/utils/remote.js

19
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/config.js

@ -0,0 +1,19 @@
var PACKAGE_VERSION = 44;
var PACKAGE_URL = 'https://github.com/andyholmes/gnome-shell-extension-gsconnect';
var PACKAGE_BUGREPORT = 'https://github.com/andyholmes/gnome-shell-extension-gsconnect/issues/new';
var PACKAGE_DATADIR = '/usr/local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io';
var PACKAGE_LOCALEDIR = '/usr/local/share/locale';
var GSETTINGS_SCHEMA_DIR = '/usr/local/share/glib-2.0/schemas';
var GNOME_SHELL_LIBDIR = '/usr/lib64/';
var APP_ID = 'org.gnome.Shell.Extensions.GSConnect';
var APP_PATH = '/org/gnome/Shell/Extensions/GSConnect';
var IS_USER = false;
// External binary paths
var OPENSSL_PATH = 'openssl';
var SSHADD_PATH = 'ssh-add';
var SSHKEYGEN_PATH = 'ssh-keygen';
var FFMPEG_PATH = 'ffmpeg';

431
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/extension.js

@ -0,0 +1,431 @@
'use strict';
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const AggregateMenu = Main.panel.statusArea.aggregateMenu;
// Bootstrap
const Extension = imports.misc.extensionUtils.getCurrentExtension();
const Utils = Extension.imports.shell.utils;
// eslint-disable-next-line no-redeclare
const _ = Extension._;
const Clipboard = Extension.imports.shell.clipboard;
const Config = Extension.imports.config;
const Device = Extension.imports.shell.device;
const Keybindings = Extension.imports.shell.keybindings;
const Notification = Extension.imports.shell.notification;
const Remote = Extension.imports.utils.remote;
Extension.getIcon = Utils.getIcon;
/**
* A System Indicator used as the hub for spawning device indicators and
* indicating that the extension is active when there are none.
*/
const ServiceIndicator = GObject.registerClass({
GTypeName: 'GSConnectServiceIndicator',
}, class ServiceIndicator extends PanelMenu.SystemIndicator {
_init() {
super._init();
this._menus = {};
this._keybindings = new Keybindings.Manager();
// GSettings
this.settings = new Gio.Settings({
settings_schema: Config.GSCHEMA.lookup(
'org.gnome.Shell.Extensions.GSConnect',
null
),
path: '/org/gnome/shell/extensions/gsconnect/',
});
this._enabledId = this.settings.connect(
'changed::enabled',
this._onEnabledChanged.bind(this)
);
this._panelModeId = this.settings.connect(
'changed::show-indicators',
this._sync.bind(this)
);
// Service Proxy
this.service = new Remote.Service();
this._deviceAddedId = this.service.connect(
'device-added',
this._onDeviceAdded.bind(this)
);
this._deviceRemovedId = this.service.connect(
'device-removed',
this._onDeviceRemoved.bind(this)
);
this._serviceChangedId = this.service.connect(
'notify::active',
this._onServiceChanged.bind(this)
);
// Service Indicator
this._indicator = this._addIndicator();
this._indicator.gicon = Extension.getIcon(
'org.gnome.Shell.Extensions.GSConnect-symbolic'
);
this._indicator.visible = false;
AggregateMenu._indicators.insert_child_at_index(this, 0);
AggregateMenu._gsconnect = this;
// Service Menu
this._item = new PopupMenu.PopupSubMenuMenuItem(_('Mobile Devices'), true);
this._item.icon.gicon = this._indicator.gicon;
this._item.label.clutter_text.x_expand = true;
this.menu.addMenuItem(this._item);
// Find current index of network menu
const menuItems = AggregateMenu.menu._getMenuItems();
const networkMenuIndex = menuItems.indexOf(AggregateMenu._network.menu);
const menuIndex = networkMenuIndex > -1 ? networkMenuIndex : 3;
// Place our menu below the network menu
AggregateMenu.menu.addMenuItem(this.menu, menuIndex + 1);
// Service Menu -> Devices Section
this.deviceSection = new PopupMenu.PopupMenuSection();
this.deviceSection.actor.add_style_class_name('gsconnect-device-section');
this.settings.bind(
'show-indicators',
this.deviceSection.actor,
'visible',
Gio.SettingsBindFlags.INVERT_BOOLEAN
);
this._item.menu.addMenuItem(this.deviceSection);
// Service Menu -> Separator
this._item.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
// Service Menu -> "Turn On/Off"
this._enableItem = this._item.menu.addAction(
_('Turn On'),
this._enable.bind(this)
);
// Service Menu -> "Mobile Settings"
this._item.menu.addAction(_('Mobile Settings'), this._preferences);
// Prime the service
this._initService();
}
async _initService() {
try {
if (this.settings.get_boolean('enabled'))
await this.service.start();
else
await this.service.reload();
} catch (e) {
logError(e, 'GSConnect');
}
}
_enable() {
try {
const enabled = this.settings.get_boolean('enabled');
// If the service state matches the enabled setting, we should
// toggle the service by toggling the setting
if (this.service.active === enabled)
this.settings.set_boolean('enabled', !enabled);
// Otherwise, we should change the service to match the setting
else if (this.service.active)
this.service.stop();
else
this.service.start();
} catch (e) {
logError(e, 'GSConnect');
}
}
_preferences() {
Gio.Subprocess.new([`${Extension.path}/gsconnect-preferences`], 0);
}
_sync() {
const available = this.service.devices.filter(device => {
return (device.connected && device.paired);
});
const panelMode = this.settings.get_boolean('show-indicators');
// Hide status indicator if in Panel mode or no devices are available
this._indicator.visible = (!panelMode && available.length);
// Show device indicators in Panel mode if available
for (const device of this.service.devices) {
const isAvailable = available.includes(device);
const indicator = Main.panel.statusArea[device.g_object_path];
indicator.visible = panelMode && isAvailable;
const menu = this._menus[device.g_object_path];
menu.actor.visible = !panelMode && isAvailable;
menu._title.actor.visible = !panelMode && isAvailable;
}
// One connected device in User Menu mode
if (!panelMode && available.length === 1) {
const device = available[0];
// Hide the menu title and move it to the submenu item
this._menus[device.g_object_path]._title.actor.visible = false;
this._item.label.text = device.name;
// Destroy any other device's battery
if (this._item._battery && this._item._battery.device !== device) {
this._item._battery.destroy();
this._item._battery = null;
}
// Add the battery to the submenu item
if (!this._item._battery) {
this._item._battery = new Device.Battery({
device: device,
opacity: 128,
});
this._item.actor.insert_child_below(
this._item._battery,
this._item._triangleBin
);
}
} else {
if (available.length > 1) {
// TRANSLATORS: %d is the number of devices connected
this._item.label.text = Extension.ngettext(
'%d Connected',
'%d Connected',
available.length
).format(available.length);
} else {
this._item.label.text = _('Mobile Devices');
}
// Destroy any battery in the submenu item
if (this._item._battery) {
this._item._battery.destroy();
this._item._battery = null;
}
}
}
_onDeviceChanged(device, changed, invalidated) {
try {
const properties = changed.deepUnpack();
if (properties.hasOwnProperty('Connected') ||
properties.hasOwnProperty('Paired'))
this._sync();
} catch (e) {
logError(e, 'GSConnect');
}
}
_onDeviceAdded(service, device) {
try {
// Device Indicator
const indicator = new Device.Indicator({device: device});
Main.panel.addToStatusArea(device.g_object_path, indicator);
// Device Menu
const menu = new Device.Menu({
device: device,
menu_type: 'list',
});
this._menus[device.g_object_path] = menu;
this.deviceSection.addMenuItem(menu);
// Device Settings
device.settings = new Gio.Settings({
settings_schema: Config.GSCHEMA.lookup(
'org.gnome.Shell.Extensions.GSConnect.Device',
true
),
path: `/org/gnome/shell/extensions/gsconnect/device/${device.id}/`,
});
// Keyboard Shortcuts
device.__keybindingsChangedId = device.settings.connect(
'changed::keybindings',
this._onDeviceKeybindingsChanged.bind(this, device)
);
this._onDeviceKeybindingsChanged(device);
// Watch the for status changes
device.__deviceChangedId = device.connect(
'g-properties-changed',
this._onDeviceChanged.bind(this)
);
this._sync();
} catch (e) {
logError(e, 'GSConnect');
}
}
_onDeviceRemoved(service, device, sync = true) {
try {
// Stop watching for status changes
if (device.__deviceChangedId)
device.disconnect(device.__deviceChangedId);
// Release keybindings
if (device.__keybindingsChangedId) {
device.settings.disconnect(device.__keybindingsChangedId);
device._keybindings.map(id => this._keybindings.remove(id));
}
// Destroy the indicator
Main.panel.statusArea[device.g_object_path].destroy();
// Destroy the menu
this._menus[device.g_object_path].destroy();
delete this._menus[device.g_object_path];
if (sync)
this._sync();
} catch (e) {
logError(e, 'GSConnect');
}
}
_onDeviceKeybindingsChanged(device) {
try {
// Reset any existing keybindings
if (device.hasOwnProperty('_keybindings'))
device._keybindings.map(id => this._keybindings.remove(id));
device._keybindings = [];
// Get the keybindings
const keybindings = device.settings.get_value('keybindings').deepUnpack();
// Apply the keybindings
for (const [action, accelerator] of Object.entries(keybindings)) {
const [, name, parameter] = Gio.Action.parse_detailed_name(action);
const actionId = this._keybindings.add(
accelerator,
() => device.action_group.activate_action(name, parameter)
);
if (actionId !== 0)
device._keybindings.push(actionId);
}
} catch (e) {
logError(e, 'GSConnect');
}
}
async _onEnabledChanged(settings, key) {
try {
if (this.settings.get_boolean('enabled'))
await this.service.start();
else
await this.service.stop();
} catch (e) {
logError(e, 'GSConnect');
}
}
async _onServiceChanged(service, pspec) {
try {
if (this.service.active) {
// TRANSLATORS: A menu option to deactivate the extension
this._enableItem.label.text = _('Turn Off');
} else {
// TRANSLATORS: A menu option to activate the extension
this._enableItem.label.text = _('Turn On');
// If it's enabled, we should try to restart now
if (this.settings.get_boolean('enabled'))
await this.service.start();
}
} catch (e) {
logError(e, 'GSConnect');
}
}
destroy() {
// Unhook from Remote.Service
if (this.service) {
this.service.disconnect(this._serviceChangedId);
this.service.disconnect(this._deviceAddedId);
this.service.disconnect(this._deviceRemovedId);
for (const device of this.service.devices)
this._onDeviceRemoved(this.service, device, false);
this.service.destroy();
}
// Disconnect any keybindings
this._keybindings.destroy();
// Disconnect from any GSettings changes
this.settings.disconnect(this._enabledId);
this.settings.disconnect(this._panelModeId);
this.settings.run_dispose();
// Destroy the PanelMenu.SystemIndicator actors
this._item.destroy();
this.menu.destroy();
delete AggregateMenu._gsconnect;
super.destroy();
}
});
var serviceIndicator = null;
function init() {
// If installed as a user extension, this will install the Desktop entry,
// DBus and systemd service files necessary for DBus activation and
// GNotifications. Since there's no uninit()/uninstall() hook for extensions
// and they're only used *by* GSConnect, they should be okay to leave.
Utils.installService();
// These modify the notification source for GSConnect's GNotifications and
// need to be active even when the extension is disabled (eg. lock screen).
// Since they *only* affect notifications from GSConnect, it should be okay
// to leave them applied.
Notification.patchGSConnectNotificationSource();
Notification.patchGtkNotificationDaemon();
// This watches for the service to start and exports a custom clipboard
// portal for use on Wayland
Clipboard.watchService();
}
function enable() {
serviceIndicator = new ServiceIndicator();
Notification.patchGtkNotificationSources();
}
function disable() {
serviceIndicator.destroy();
serviceIndicator = null;
Notification.unpatchGtkNotificationSources();
}

112
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/gsconnect-preferences

@ -0,0 +1,112 @@
#!/usr/bin/env gjs
'use strict';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gio = '2.0';
imports.gi.versions.GLib = '2.0';
imports.gi.versions.GObject = '2.0';
imports.gi.versions.Gtk = '3.0';
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
// Bootstrap
function get_datadir() {
let m = /@(.+):\d+/.exec((new Error()).stack.split('\n')[1]);
return Gio.File.new_for_path(m[1]).get_parent().get_path();
}
imports.searchPath.unshift(get_datadir());
imports.config.PACKAGE_DATADIR = imports.searchPath[0];
// Local Imports
const Config = imports.config;
const Settings = imports.preferences.service;
/**
* Class representing the GSConnect service daemon.
*/
const Preferences = GObject.registerClass({
GTypeName: 'GSConnectPreferences',
}, class Preferences extends Gtk.Application {
_init() {
super._init({
application_id: 'org.gnome.Shell.Extensions.GSConnect.Preferences',
resource_base_path: '/org/gnome/Shell/Extensions/GSConnect',
});
GLib.set_prgname('gsconnect-preferences');
GLib.set_application_name(_('GSConnect Preferences'));
}
vfunc_activate() {
if (this._window === undefined) {
this._window = new Settings.Window({
application: this,
});
}
this._window.present();
}
vfunc_startup() {
super.vfunc_startup();
// Init some resources
let provider = new Gtk.CssProvider();
provider.load_from_resource(`${Config.APP_PATH}/application.css`);
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
let actions = [
['refresh', null],
['connect', GLib.VariantType.new('s')],
];
for (let [name, type] of actions) {
let action = new Gio.SimpleAction({
name: name,
parameter_type: type,
});
this.add_action(action);
}
}
vfunc_activate_action(action_name, parameter) {
try {
let paramArray = [];
if (parameter instanceof GLib.Variant)
paramArray[0] = parameter;
this.get_dbus_connection().call(
'org.gnome.Shell.Extensions.GSConnect',
'/org/gnome/Shell/Extensions/GSConnect',
'org.freedesktop.Application',
'ActivateAction',
GLib.Variant.new('(sava{sv})', [action_name, paramArray, {}]),
null,
Gio.DBusCallFlags.NONE,
-1,
null,
null
);
} catch (e) {
logError(e);
}
}
});
(new Preferences()).run([imports.system.programInvocationName].concat(ARGV));

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ar/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/be/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ca/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/cs/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/da/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/de/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/es/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/et/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/gl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/hu/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/it/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/lt/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_BE/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_NL/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pt_BR/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ru/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr@latin/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/tr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/uk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_CN/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_TW/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo

Binary file not shown.

11
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/metadata.json

@ -0,0 +1,11 @@
{
"_generated": "Generated by SweetTooth, do not edit",
"description": "GSConnect is a complete implementation of KDE Connect especially for GNOME Shell with Nautilus, Chrome and Firefox integration. It does not rely on the KDE Connect desktop application and will not work with it installed.\n\nKDE Connect allows devices to securely share content like notifications or files and other features like SMS messaging and remote control. The KDE Connect team has applications for Linux, BSD, Android, Sailfish and Windows.\n\nPlease restart GNOME Shell after updating!\n\nPlease report issues on Github!",
"name": "GSConnect",
"shell-version": [
"3.38"
],
"url": "https://github.com/andyholmes/gnome-shell-extension-gsconnect/wiki",
"uuid": "gsconnect@andyholmes.github.io",
"version": 44
}

183
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/nautilus-gsconnect.py

@ -0,0 +1,183 @@
"""
nautilus-gsconnect.py - A Nautilus extension for sending files via GSConnect.
A great deal of credit and appreciation is owed to the indicator-kdeconnect
developers for the sister Python script 'kdeconnect-send-nautilus.py':
https://github.com/Bajoja/indicator-kdeconnect/blob/master/data/extensions/kdeconnect-send-nautilus.py
"""
import gettext
import os.path
import sys
import gi
gi.require_version('Gio', '2.0')
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
from gi.repository import Gio, GLib, GObject
# Host application detection
#
# Nemo seems to reliably identify itself as 'nemo' in argv[0], so we
# can test for that. Nautilus detection is less reliable, so don't try.
# See https://github.com/linuxmint/nemo-extensions/issues/330
if "nemo" in sys.argv[0].lower():
# Host runtime is nemo-python
gi.require_version('Nemo', '3.0')
from gi.repository import Nemo as FileManager
else:
# Otherwise, just assume it's nautilus-python
gi.require_version('Nautilus', '3.0')
from gi.repository import Nautilus as FileManager
SERVICE_NAME = 'org.gnome.Shell.Extensions.GSConnect'
SERVICE_PATH = '/org/gnome/Shell/Extensions/GSConnect'
# Init gettext translations
LOCALE_DIR = os.path.join(GLib.get_user_data_dir(),
'gnome-shell', 'extensions',
'gsconnect@andyholmes.github.io', 'locale')
if not os.path.exists(LOCALE_DIR):
LOCALE_DIR = None
try:
i18n = gettext.translation(SERVICE_NAME,
localedir=LOCALE_DIR)
_ = i18n.gettext
except (IOError, OSError) as e:
print('GSConnect: {0}'.format(e.strerror))
i18n = gettext.translation(SERVICE_NAME,
localedir=LOCALE_DIR,
fallback=True)
_ = i18n.gettext
class GSConnectShareExtension(GObject.Object, FileManager.MenuProvider):
"""A context menu for sending files via GSConnect."""
def __init__(self):
"""Initialize the DBus ObjectManager"""
GObject.Object.__init__(self)
self.devices = {}
Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION,
Gio.DBusProxyFlags.DO_NOT_AUTO_START,
None,
SERVICE_NAME,
SERVICE_PATH,
'org.freedesktop.DBus.ObjectManager',
None,
self._init_async,
None)
def _init_async(self, proxy, res, user_data):
proxy = proxy.new_for_bus_finish(res)
proxy.connect('notify::g-name-owner', self._on_name_owner_changed)
proxy.connect('g-signal', self._on_g_signal)
self._on_name_owner_changed(proxy, None)
def _on_g_signal(self, proxy, sender_name, signal_name, parameters):
# Wait until the service is ready
if proxy.props.g_name_owner is None:
return
objects = parameters.unpack()
if signal_name == 'InterfacesAdded':
for object_path, props in objects.items():
props = props['org.gnome.Shell.Extensions.GSConnect.Device']
self.devices[object_path] = (props['Name'],
Gio.DBusActionGroup.get(
proxy.get_connection(),
SERVICE_NAME,
object_path))
elif signal_name == 'InterfacesRemoved':
for object_path in objects:
try:
del self.devices[object_path]
except KeyError:
pass
def _on_name_owner_changed(self, proxy, pspec):
# Wait until the service is ready
if proxy.props.g_name_owner is None:
self.devices = {}
else:
proxy.call('GetManagedObjects',
None,
Gio.DBusCallFlags.NO_AUTO_START,
-1,
None,
self._get_managed_objects,
None)
def _get_managed_objects(self, proxy, res, user_data):
objects = proxy.call_finish(res)[0]
for object_path, props in objects.items():
props = props['org.gnome.Shell.Extensions.GSConnect.Device']
self.devices[object_path] = (props['Name'],
Gio.DBusActionGroup.get(
proxy.get_connection(),
SERVICE_NAME,
object_path))
def send_files(self, menu, files, action_group):
"""Send *files* to *device_id*"""
for file in files:
variant = GLib.Variant('(sb)', (file.get_uri(), False))
action_group.activate_action('shareFile', variant)
def get_file_items(self, window, files):
"""Return a list of select files to be sent"""
# Only accept regular files
for uri in files:
if uri.get_uri_scheme() != 'file' or uri.is_directory():
return ()
# Enumerate capable devices
devices = []
for name, action_group in self.devices.values():
if action_group.get_action_enabled('shareFile'):
devices.append([name, action_group])
# No capable devices; don't show menu entry
if not devices:
return ()
# Context Menu Item
menu = FileManager.MenuItem(
name='GSConnectShareExtension::Devices',
label=_('Send To Mobile Device')
)
# Context Submenu
submenu = FileManager.Menu()
menu.set_submenu(submenu)
# Context Submenu Items
for name, action_group in devices:
item = FileManager.MenuItem(
name='GSConnectShareExtension::Device' + name,
label=name
)
item.connect('activate', self.send_files, files, action_group)
submenu.append_item(item)
return (menu,)

BIN
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/org.gnome.Shell.Extensions.GSConnect.gresource

Binary file not shown.

41
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/__init__.js

@ -0,0 +1,41 @@
'use strict';
const Gettext = imports.gettext;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Config = imports.config;
// Ensure config.js is setup properly
const userDir = GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']);
if (Config.PACKAGE_DATADIR.startsWith(userDir)) {
Config.IS_USER = true;
Config.PACKAGE_LOCALEDIR = `${Config.PACKAGE_DATADIR}/locale`;
Config.GSETTINGS_SCHEMA_DIR = `${Config.PACKAGE_DATADIR}/schemas`;
}
// Init Gettext
String.prototype.format = imports.format.format;
Gettext.bindtextdomain(Config.APP_ID, Config.PACKAGE_LOCALEDIR);
globalThis._ = GLib.dgettext.bind(null, Config.APP_ID);
globalThis.ngettext = GLib.dngettext.bind(null, Config.APP_ID);
// Init GResources
Gio.Resource.load(
GLib.build_filenamev([Config.PACKAGE_DATADIR, `${Config.APP_ID}.gresource`])
)._register();
// Init GSchema
Config.GSCHEMA = Gio.SettingsSchemaSource.new_from_directory(
Config.GSETTINGS_SCHEMA_DIR,
Gio.SettingsSchemaSource.get_default(),
false
);

1088
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/device.js

File diff suppressed because it is too large Load Diff

312
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/keybindings.js

@ -0,0 +1,312 @@
'use strict';
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
/*
* A list of modifier keysyms we ignore
*/
const _MODIFIERS = [
Gdk.KEY_Alt_L,
Gdk.KEY_Alt_R,
Gdk.KEY_Caps_Lock,
Gdk.KEY_Control_L,
Gdk.KEY_Control_R,
Gdk.KEY_Meta_L,
Gdk.KEY_Meta_R,
Gdk.KEY_Num_Lock,
Gdk.KEY_Shift_L,
Gdk.KEY_Shift_R,
Gdk.KEY_Super_L,
Gdk.KEY_Super_R,
];
/**
* Response enum for ShortcutChooserDialog
*/
var ResponseType = {
CANCEL: Gtk.ResponseType.CANCEL,
SET: Gtk.ResponseType.APPLY,
UNSET: 2,
};
/**
* A simplified version of the shortcut editor from GNOME Control Center
*/
var ShortcutChooserDialog = GObject.registerClass({
GTypeName: 'GSConnectPreferencesShortcutEditor',
Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-shortcut-editor.ui',
Children: [
'cancel-button', 'set-button',
'stack', 'summary-label',
'shortcut-label', 'conflict-label',
],
}, class ShortcutChooserDialog extends Gtk.Dialog {
_init(params) {
super._init({
transient_for: Gio.Application.get_default().get_active_window(),
use_header_bar: true,
});
this._seat = Gdk.Display.get_default().get_default_seat();
// Current accelerator or %null
this.accelerator = params.accelerator;
// TRANSLATORS: Summary of a keyboard shortcut function
// Example: Enter a new shortcut to change Messaging
this.summary = _('Enter a new shortcut to change <b>%s</b>').format(
params.summary
);
}
get accelerator() {
return this.shortcut_label.accelerator;
}
set accelerator(value) {
this.shortcut_label.accelerator = value;
}
get summary() {
return this.summary_label.label;
}
set summary(value) {
this.summary_label.label = value;
}
vfunc_key_press_event(event) {
let keyvalLower = Gdk.keyval_to_lower(event.keyval);
let realMask = event.state & Gtk.accelerator_get_default_mod_mask();
// TODO: Critical: 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed
if (_MODIFIERS.includes(keyvalLower))
return true;
// Normalize Tab
if (keyvalLower === Gdk.KEY_ISO_Left_Tab)
keyvalLower = Gdk.KEY_Tab;
// Put shift back if it changed the case of the key, not otherwise.
if (keyvalLower !== event.keyval)
realMask |= Gdk.ModifierType.SHIFT_MASK;
// HACK: we don't want to use SysRq as a keybinding (but we do want
// Alt+Print), so we avoid translation from Alt+Print to SysRq
if (keyvalLower === Gdk.KEY_Sys_Req && (realMask & Gdk.ModifierType.MOD1_MASK) !== 0)
keyvalLower = Gdk.KEY_Print;
// A single Escape press cancels the editing
if (realMask === 0 && keyvalLower === Gdk.KEY_Escape) {
this.response(ResponseType.CANCEL);
return false;
}
// Backspace disables the current shortcut
if (realMask === 0 && keyvalLower === Gdk.KEY_BackSpace) {
this.response(ResponseType.UNSET);
return false;
}
// CapsLock isn't supported as a keybinding modifier, so keep it from
// confusing us
realMask &= ~Gdk.ModifierType.LOCK_MASK;
if (keyvalLower !== 0 && realMask !== 0) {
this._ungrab();
// Set the accelerator property/label
this.accelerator = Gtk.accelerator_name(keyvalLower, realMask);
// TRANSLATORS: When a keyboard shortcut is unavailable
// Example: [Ctrl]+[S] is already being used
this.conflict_label.label = _('%s is already being used').format(
Gtk.accelerator_get_label(keyvalLower, realMask)
);
// Show Cancel button and switch to confirm/conflict page
this.cancel_button.visible = true;
this.stack.visible_child_name = 'confirm';
this._check();
}
return true;
}
async _check() {
try {
const available = await checkAccelerator(this.accelerator);
this.set_button.visible = available;
this.conflict_label.visible = !available;
} catch (e) {
logError(e);
this.response(ResponseType.CANCEL);
}
}
_grab() {
const success = this._seat.grab(
this.get_window(),
Gdk.SeatCapabilities.KEYBOARD,
true, // owner_events
null, // cursor
null, // event
null
);
if (success !== Gdk.GrabStatus.SUCCESS)
return this.response(ResponseType.CANCEL);
if (!this._seat.get_keyboard() && !this._seat.get_pointer())
return this.response(ResponseType.CANCEL);
this.grab_add();
}
_ungrab() {
this._seat.ungrab();
this.grab_remove();
}
// Override to use our own ungrab process
response(response_id) {
this.hide();
this._ungrab();
return super.response(response_id);
}
// Override with a non-blocking version of Gtk.Dialog.run()
run() {
this.show();
// Wait a bit before attempting grab
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => {
this._grab();
return GLib.SOURCE_REMOVE;
});
}
});
/**
* Check the availability of an accelerator using GNOME Shell's DBus interface.
*
* @param {string} accelerator - An accelerator
* @param {number} [modeFlags] - Mode Flags
* @param {number} [grabFlags] - Grab Flags
* @param {boolean} %true if available, %false on error or unavailable
*/
async function checkAccelerator(accelerator, modeFlags = 0, grabFlags = 0) {
try {
let result = false;
// Try to grab the accelerator
const action = await new Promise((resolve, reject) => {
Gio.DBus.session.call(
'org.gnome.Shell',
'/org/gnome/Shell',
'org.gnome.Shell',
'GrabAccelerator',
new GLib.Variant('(suu)', [accelerator, modeFlags, grabFlags]),
null,
Gio.DBusCallFlags.NONE,
-1,
null,
(connection, res) => {
try {
res = connection.call_finish(res);
resolve(res.deepUnpack()[0]);
} catch (e) {
reject(e);
}
}
);
});
// If successful, use the result of ungrabbing as our return
if (action !== 0) {
result = await new Promise((resolve, reject) => {
Gio.DBus.session.call(
'org.gnome.Shell',
'/org/gnome/Shell',
'org.gnome.Shell',
'UngrabAccelerator',
new GLib.Variant('(u)', [action]),
null,
Gio.DBusCallFlags.NONE,
-1,
null,
(connection, res) => {
try {
res = connection.call_finish(res);
resolve(res.deepUnpack()[0]);
} catch (e) {
reject(e);
}
}
);
});
}
return result;
} catch (e) {
logError(e);
return false;
}
}
/**
* Show a dialog to get a keyboard shortcut from a user.
*
* @param {string} summary - A description of the keybinding's function
* @param {string} accelerator - An accelerator as taken by Gtk.ShortcutLabel
* @return {string} An accelerator or %null if it should be unset.
*/
async function getAccelerator(summary, accelerator = null) {
try {
const dialog = new ShortcutChooserDialog({
summary: summary,
accelerator: accelerator,
});
accelerator = await new Promise((resolve, reject) => {
dialog.connect('response', (dialog, response) => {
switch (response) {
case ResponseType.SET:
accelerator = dialog.accelerator;
break;
case ResponseType.UNSET:
accelerator = null;
break;
case ResponseType.CANCEL:
// leave the accelerator as passed in
break;
}
dialog.destroy();
resolve(accelerator);
});
dialog.run();
});
return accelerator;
} catch (e) {
logError(e);
return accelerator;
}
}

657
.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/service.js

@ -0,0 +1,657 @@
'use strict';
const Gdk = imports.gi.Gdk;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Config = imports.config;
const Device = imports.preferences.device;
const Remote = imports.utils.remote;
/*
* Header for support logs
*/
const LOG_HEADER = new GLib.Bytes(`
GSConnect: ${Config.PACKAGE_VERSION} (${Config.IS_USER ? 'user' : 'system'})
GJS: ${imports.system.version}
Session: ${GLib.getenv('XDG_SESSION_TYPE')}
OS: ${GLib.get_os_info('PRETTY_NAME')}
--------------------------------------------------------------------------------
`);
/**
* Generate a support log.
*
* @param {string} time - Start time as a string (24-hour notation)
*/
async function generateSupportLog(time) {
try {
const [file, stream] = Gio.File.new_tmp('gsconnect.XXXXXX');
const logFile = stream.get_output_stream();
await new Promise((resolve, reject) => {
logFile.write_bytes_async(LOG_HEADER, 0, null, (file, res) => {
try {
resolve(file.write_bytes_finish(res));
} catch (e) {
reject(e);
}
});
});
// FIXME: BSD???
const proc = new Gio.Subprocess({
flags: (Gio.SubprocessFlags.STDOUT_PIPE |
Gio.SubprocessFlags.STDERR_MERGE),
argv: ['journalctl', '--no-host', '--since', time],
});
proc.init(null);
logFile.splice_async(
proc.get_stdout_pipe(),
Gio.OutputStreamSpliceFlags.CLOSE_TARGET,
GLib.PRIORITY_DEFAULT,
null,
(source, res) => {
try {
source.splice_finish(res);
} catch (e) {
logError(e);
}
}
);
await new Promise((resolve, reject) => {
proc.wait_check_async(null, (proc, res) => {
try {
resolve(proc.wait_finish(res));
} catch (e) {
reject(e);
}
});
});
const uri = file.get_uri();
Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null);
} catch (e) {
logError(e);
}
}
/**
* "Connect to..." Dialog
*/
var ConnectDialog = GObject.registerClass({
GTypeName: 'GSConnectConnectDialog',
Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/connect-dialog.ui',
Children: [
'cancel-button', 'connect-button',
'lan-grid', 'lan-ip', 'lan-port',
],
}, class ConnectDialog extends Gtk.Dialog {
_init(params = {}) {
super._init(Object.assign({
use_header_bar: true,
}, params));
}
vfunc_response(response_id) {
if (response_id === Gtk.ResponseType.OK) {
try {
let address;
// Lan host/port entered
if (this.lan_ip.text) {
const host = this.lan_ip.text;
const port = this.lan_port.value;
address = GLib.Variant.new_string(`lan://${host}:${port}`);
} else {
return false;
}
this.application.activate_action('connect', address);
} catch (e) {
logError(e);
}
}
this.destroy();
return false;
}
});
function rowSeparators(row, before) {
const header = row.get_header();
if (before === null) {
if (header !== null)
header.destroy();
return;
}
if (header === null)
row.set_header(new Gtk.Separator({visible: true}));
}
var Window = GObject.registerClass({
GTypeName: 'GSConnectPreferencesWindow',
Properties: {
'display-mode': GObject.ParamSpec.string(
'display-mode',
'Display Mode',
'Display devices in either the Panel or User Menu',
GObject.ParamFlags.READWRITE,
null
),
},
Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-window.ui',
Children: [
// HeaderBar
'headerbar', 'infobar', 'stack',
'service-menu', 'service-edit', 'refresh-button',
'device-menu', 'prev-button',
// Popover
'rename-popover', 'rename', 'rename-label', 'rename-entry', 'rename-submit',
// Focus Box
'service-window', 'service-box',
// Device List
'device-list', 'device-list-spinner', 'device-list-placeholder',
],
}, class PreferencesWindow extends Gtk.ApplicationWindow {
_init(params = {}) {
super._init(params);
// Service Settings
this.settings = new Gio.Settings({
settings_schema: Config.GSCHEMA.lookup(
'org.gnome.Shell.Extensions.GSConnect',
true
),
});
// Service Proxy
this.service = new Remote.Service();
this._deviceAddedId = this.service.connect(
'device-added',
this._onDeviceAdded.bind(this)
);
this._deviceRemovedId = this.service.connect(
'device-removed',
this._onDeviceRemoved.bind(this)
<