diff -Nru juno-nvidia-drivers-0.3.14/debian/changelog juno-nvidia-drivers-0.3.18/debian/changelog --- juno-nvidia-drivers-0.3.14/debian/changelog 2023-07-03 08:01:52.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/debian/changelog 2024-04-10 08:01:52.000000000 +0000 @@ -1,5 +1,5 @@ -juno-nvidia-drivers (0.3.14) jammy; urgency=low +juno-nvidia-drivers (0.3.18) jammy; urgency=low - * NEW: Nvidia 535 + * NEW: Nvidia 550 - -- Juno Mon, 3 Jul 2023 08:01:52 +0000 + -- Juno Tue, 10 Apr 2024 08:01:52 +0000 diff -Nru juno-nvidia-drivers-0.3.14/debian/control juno-nvidia-drivers-0.3.18/debian/control --- juno-nvidia-drivers-0.3.14/debian/control 2023-07-03 08:01:52.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/debian/control 2024-04-10 08:01:52.000000000 +0000 @@ -8,6 +8,6 @@ Section: metapackages Priority: optional Architecture: amd64 -Depends: nvidia-driver-535 +Depends: nvidia-driver-550 Homepage: https://junocomputers.com Description: Juno Computers NVidia Drivers. diff -Nru juno-nvidia-drivers-0.3.14/debian/copyright juno-nvidia-drivers-0.3.18/debian/copyright --- juno-nvidia-drivers-0.3.14/debian/copyright 2023-01-30 15:48:36.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/debian/copyright 2024-03-17 19:59:03.000000000 +0000 @@ -1,2 +1,2 @@ -Copyright 2023, Juno Computers Ltd -Copyright 2023, Juno Computers, Inc +Copyright 2024, Juno Computers Ltd +Copyright 2024, Juno Computers USA, LLC diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/assets/prime-menu-default-symbolic.svg juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/assets/prime-menu-default-symbolic.svg --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/assets/prime-menu-default-symbolic.svg 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/assets/prime-menu-default-symbolic.svg 2021-11-04 17:35:09.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/icons.js juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/icons.js --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/icons.js 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/icons.js 2021-11-04 17:35:09.000000000 +0000 @@ -0,0 +1,53 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// Strict mode. +'use strict'; + +// Import modules. +const {GObject, Gio} = imports.gi; +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +/** + * Default icon. + * + * @type {String} + */ +var DEFAULT = 'prime-menu-default-symbolic'; + +/** + * Get icon path (directory name). If filename argument is + * provided it will be appended to path. Note that there + * is no file exists check here. + * + * @param {Mixed} filename (optional) + * @return {String} + */ +var path = (filename=null) => { + let dirname = `${Me.path}/assets`, + suffix = filename ? `/${filename}` : ''; + + return dirname + suffix; +}; + +/** + * Icons.Icon extends Gio.FileIcon. + */ +var Icon = GObject.registerClass({ + GTypeName: 'PrimeIndicatorIconsIcon', +}, class Icon extends Gio.FileIcon { + /** + * Constructor. + * + * @param {Mixed} icon + * @return {Void} + */ + _init(icon=null) { + let iconName = icon || DEFAULT, + iconPath = path(`${iconName}.svg`), + file = Gio.File.new_for_path(iconPath); + + return super._init({ file: file }); + } + + /* --- */ +}); diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/log.js juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/log.js --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/log.js 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/log.js 2021-11-04 17:35:09.000000000 +0000 @@ -0,0 +1,92 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// strict mode +'use strict'; + +// import modules +const {Gio, GLib} = imports.gi; +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +/** + * Proxy for global.log. + * + * @param {String} widget + * @param {...String} message + * @return {Void} + */ +var journal = (widget, ...message) => { + let prefix = Me.metadata.uuid; + prefix += widget ? '.' + widget : ''; + prefix = '[' + prefix + ']'; + + let args = [ prefix + (message.length ? ' ' + message.shift() : '') ]; + if (message.length) + args = args.concat(message); + + global.log.apply(global, args); +}; + +/** + * Append log to ~/.{Me.metadata.uuid}.log. + * + * @param {...String} message + * @return {Void} + */ +var file = (...message) => { + let dir = GLib.getenv('HOME'), + path = dir + '/' + Me.metadata.uuid + '.log', + data = message.join(', '); + + _appendToFile(path, data); +}; + +/** + * Append log to /tmp/.{Me.metadata.uuid}.log + * + * @param {...String} message + * @return {Void} + */ +var tmp = (...message) => { + let dir = GLib.get_tmp_dir(), + path = dir + '/' + Me.metadata.uuid + '.log', + data = message.join(', '); + + _appendToFile(path, data); +}; + +/** + * Get current time. + * + * @return {String} + */ +const _getCurrentTime = () => { + let date = new Date(), + result = date.getFullYear() + + '-' + ('0' + (date.getMonth() + 1)).substr(-2) + + '-' + ('0' + date.getDate()).substr(-2) + + ' ' + ('0' + date.getHours()).substr(-2) + + ':' + ('0' + date.getMinutes()).substr(-2) + + ':' + ('0' + date.getSeconds()).substr(-2) + + '.' + date.getMilliseconds(); + + return result; +}; + +/** + * Append data to file. + * + * @param {String} path + * @param {String} data + * @return {Void} + */ +const _appendToFile = (path, data) => { + let file = Gio.File.new_for_path(path), + stream = file.append_to(Gio.FileCreateFlags.NONE, null), + append = '' + + '[' + _getCurrentTime() + ']' + (data ? ' ' : '') + + data + + '\n'; + + stream.write(append, null); + stream.close(null); +}; diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/menu.js juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/menu.js --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/menu.js 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/menu.js 2021-11-04 18:03:25.000000000 +0000 @@ -0,0 +1,325 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// Strict mode. +'use strict'; + +// Import modules. +const {GLib, GObject} = imports.gi; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const GnomeSession = imports.misc.gnomeSession; +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const Prime = Me.imports.prime; +const Icons = Me.imports.icons; +const Log = Me.imports.log; +const _ = ExtensionUtils.gettext || imports.gettext.gettext; + +/** + * Widget extends PopupMenu.PopupSubMenuMenuItem. + */ +var Widget = GObject.registerClass({ + GTypeName: 'PrimeIndicatorMenuWidget', +}, class Widget extends PopupMenu.PopupSubMenuMenuItem { + /** + * Constructor. + * + * @return {Void} + */ + _init() { + super._init(_("Prime Select"), true); + + this._settings = ExtensionUtils.getSettings(); + this.settings.connect('changed', this._handleSettings.bind(this)); + + this._switch = new Prime.Switch(); + this.switch.connect('gpu-change', this._handlePrimeGpuChange.bind(this)); + this.switch.monitor(); + + this._timeoutSourceId = null; + this._pending = false; + this._loggingOut = false; + + this.icon.set_gicon(new Icons.Icon(Icons.DEFAULT)); + + this._ui = {}; + let switches = this.switch.switches; + if (switches.includes('intel')) { + this._ui.intel = new PopupMenu.PopupMenuItem(_("Intel")); + this._ui.intel.connect('activate', this._handleMenuItemClick.bind(this)); + this.menu.addMenuItem(this._ui.intel); + } + if (switches.includes('nvidia')) { + this._ui.nvidia = new PopupMenu.PopupMenuItem(_("NVidia")); + this._ui.nvidia.connect('activate', this._handleMenuItemClick.bind(this)); + this.menu.addMenuItem(this._ui.nvidia); + } + if (switches.includes('on-demand')) { + this._ui.demand = new PopupMenu.PopupMenuItem(_("NVidia On-Demand")); + this._ui.demand.connect('activate', this._handleMenuItemClick.bind(this)); + this.menu.addMenuItem(this._ui.demand); + } + if (!switches.length) + this.set_reactive(false); + + this._ui.separator = new PopupMenu.PopupSeparatorMenuItem(); + this.menu.addMenuItem(this._ui.separator); + + this._ui.messagePending = new PopupMenu.PopupMenuItem(_("Please wait for the operation\nto complete")); + this._ui.messagePending.setSensitive(false); + this.menu.addMenuItem(this._ui.messagePending); + + //this._ui.messageRestart = new PopupMenu.PopupMenuItem(_("Please restart the system\nto apply the changes")); + this._ui.messageRestart = new PopupMenu.PopupMenuItem(_("Please log out and log back in\nto apply the changes")); + this._ui.messageRestart.setSensitive(false); + this.menu.addMenuItem(this._ui.messageRestart); + + this._ui.messageLoggingOut = new PopupMenu.PopupMenuItem(_("Logging out...")); + this._ui.messageLoggingOut.setSensitive(false); + this.menu.addMenuItem(this._ui.messageLoggingOut); + + //this._ui.preferences = new PopupMenu.PopupMenuItem(_("Preferences")); + //this._ui.preferences.connect('activate', (actor, event) => { + // ExtensionUtils.openPrefs(); + //}); + //this.menu.addMenuItem(this._ui.preferences); + + this._attach(); + this._refresh(); + + if (!this.switch.command('sudo')) + this._log('can\'t find sudo frontend command, switch disabled'); + if (!this.switch.command('select')) + this._log('can\'t find prime-select command, query/switch disabled'); + if (!this.switch.command('management')) + this._log('can\'t find prime-smi command, logout notification disabled'); + if (!this.switch.command('settings')) + this._log('can\'t find nvidia-settings command, settings disabled'); + if (!switches.length) + this._log('can\'t find any prime switch, select disabled'); + } + + /** + * Destructor. + * + * @return {Void} + */ + destroy() { + this.switch.destroy(); + this.settings.run_dispose(); + + this._delayClear(); + + delete this._loggingOut; + delete this._pending; + delete this._timeoutSourceId + delete this._switch; + delete this._settings; + + super.destroy(); + } + + /** + * Settings property getter. + * + * @return {Gio.Settings} + */ + get settings() { + return this._settings; + } + + /** + * Switch property getter. + * + * @return {Prime.Switch} + */ + get switch() { + return this._switch; + } + + /** + * Logout gnome session. + * + * @return {Void} + */ + logout() { + let sessionManager = new GnomeSession.SessionManager(), + mode = 1; + // 0: Normal. + // 1: No confirmation inferface should be shown. + // 2: Forcefully logout. No confirmation will be shown and any inhibitors will be ignored. + + this._log('gnome session logout'); + sessionManager.LogoutRemote(mode); + } + + /** + * Proxy for global.log(). + * + * @param {...String} message + * @return {Void} + */ + _log(...message) { + Log.journal('Menu.Widget', message); + } + + /** + * Attach widget to aggregate menu. + * + * @return {Void} + */ + _attach() { + let items = Main.panel.statusArea.aggregateMenu.menu._getMenuItems(); + Main.panel.statusArea.aggregateMenu.menu.addMenuItem(this, items.length - 1); + } + + /** + * Clear any main loop timeout sources. + * + * @return {Void} + */ + _delayClear() { + if (!this._timeoutSourceId) + return; + + GLib.Source.remove(this._timeoutSourceId); + this._timeoutSourceId = null; + } + + /** + * Execute callback with delay. + * + * @param {Number} timeout + * @param {Function} callback + * @param {...Mixed} args + * @return {Void} + */ + _delayExecute(timeout, callback, ...args) { + if (this._timeoutSourceId) + throw new Error('Timeout already in use'); + + this._timeoutSourceId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, () => { + this._timeoutSourceId = null; + + if (typeof callback === 'function') + callback.apply(this, args); + + // Stop repeating. + return GLib.SOURCE_REMOVE; + }); + } + + /** + * Refresh widget menu: + * set items sensitivity and show/hide logout message. + * + * @return {Void} + */ + _refresh() { + let query = this.switch.query, + pending = this._pending, + loggingOut = this._loggingOut, + isRestartNeeded = this.switch.isRestartNeeded, + sensitive = (!pending && !loggingOut) ? this.switch.command('sudo') && this.switch.command('select') : false; + + if (this._ui.nvidia) { + this._ui.nvidia.setSensitive(sensitive); + this._ui.nvidia.setOrnament(query === 'nvidia' ? PopupMenu.Ornament.CHECK : PopupMenu.Ornament.NONE); + } + if (this._ui.intel) { + this._ui.intel.setSensitive(sensitive); + this._ui.intel.setOrnament(query === 'intel' ? PopupMenu.Ornament.CHECK : PopupMenu.Ornament.NONE); + } + if (this._ui.demand) { + this._ui.demand.setSensitive(sensitive); + this._ui.demand.setOrnament(query === 'on-demand' ? PopupMenu.Ornament.CHECK : PopupMenu.Ornament.NONE); + } + + this._ui.separator.actor.visible = pending || isRestartNeeded || loggingOut; + this._ui.messagePending.actor.visible = loggingOut ? false : pending; + this._ui.messageRestart.actor.visible = (loggingOut || pending) ? false : isRestartNeeded; + this._ui.messageLoggingOut.actor.visible = loggingOut; + } + + /** + * Switch GPU. + * + * @param {String} gpu + * @return {Void} + */ + _switchGpu(gpu) { + this._pending = true; + this._refresh(); + + this.switch.switch(gpu, (e) => { + let doRestart = true + && e.result + && this.settings.get_boolean('auto-logout') + && this.switch.isRestartNeeded; + if (!doRestart) { + this._pending = false; + this._refresh(); + + return; + } + + this._log('logout on gpu switch enabled, logging out'); + this._pending = false; + this._loggingOut = true; + this._refresh(); + + // Logout with delay. + this._delayExecute(1000, this.logout.bind(this)); + }); + } + + /** + * Settings changed event handler. + * + * @param {Object} actor + * @param {String} key + * @return {Void} + */ + _handleSettings(actor, key) { + // pass + } + + /** + * Menu item click event handler. + * + * @param {PopupMenuItem} widget + * @param {Clutter.Event} event + * @return {Void} + */ + _handleMenuItemClick(actor, event) { + if (actor._ornament !== PopupMenu.Ornament.NONE) + return; + + let gpu = null; + if (this._ui.nvidia && this._ui.nvidia === actor) + gpu = 'nvidia'; + else if (this._ui.intel && this._ui.intel === actor) + gpu = 'intel'; + else if (this._ui.demand && this._ui.demand === actor) + gpu = 'on-demand'; + else + throw new Error('Unknown GPU switch'); + + // Switch with delay, making sure that refresh occurs after aggregate + // menu fadeout. + this._delayExecute(50, this._switchGpu.bind(this), gpu); + } + + /** + * Prime switch gpu change event handler. + * + * @param {Object} actor + * @param {String} gpu + * @return {Void} + */ + _handlePrimeGpuChange(actor, gpu) { + this._refresh(); + } + + /* --- */ +}); diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prefs.css juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prefs.css --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prefs.css 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prefs.css 2021-11-04 17:35:09.000000000 +0000 @@ -0,0 +1,8 @@ +.prime-indicator-prefs-box, +.prime-indicator-prefs-box > border { border: 0 none; } +.prime-indicator-prefs-input { padding: 0.5em; } +.prime-indicator-prefs-page { padding: 2em; } +.prime-indicator-prefs-page-about-title { padding-bottom: 2em; font-weight: bold; } +.prime-indicator-prefs-page-about-icon { min-height: 64px; min-width: 64px; } +.prime-indicator-prefs-page-about-description { padding: 2em; } +.prime-indicator-prefs-page-about-license { font-size: 0.8em; padding-top: 2.5em; } diff -Nru juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prime.js juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prime.js --- juno-nvidia-drivers-0.3.14/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prime.js 1970-01-01 00:00:00.000000000 +0000 +++ juno-nvidia-drivers-0.3.18/prime-indicator@gnome-shell-exstensions.fffilo.github.com/prime.js 2021-11-04 17:35:09.000000000 +0000 @@ -0,0 +1,360 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// Strict mode. +'use strict'; + +// Import modules. +const {GLib, Gio} = imports.gi; +const Signals = imports.signals; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Log = Me.imports.log; + +/** + * Switch: + * prime profiles manipulation. + */ +var Switch = class Switch { + /** + * Constructor. + * + * @return {Void} + */ + constructor() { + this._commands = null; + this._gpu = null; + this._listener = null; + + this._commands = { + sudo: this._which('pkexec') || this._which('gksudo'), + select: this._which('prime-select'), + management: this._which('nvidia-smi'), + settings: this._which('nvidia-settings'), + } + + // Make getter store default query (if not already done so). + this.defaultQuery; + } + + /** + * Destructor. + * + * @return {Void} + */ + destroy() { + this.unmonitor(); + + delete this._listener; + delete this._gpu; + delete this._commands; + } + + /** + * Proxy for global.log(). + * + * @param {...String} message + * @return {Void} + */ + _log(...message) { + Log.journal('Prime.Switch', message); + } + + /** + * `which $command` result. + * + * @param {String} command + * @return {Mixed} + */ + _which(command) { + let exec = this._shellExec('which ' + command); + return exec.stdout.trim() || exec.stderr.trim(); + } + + /** + * Shell execute command. + * + * @param {String} command + * @return {Object} + */ + _shellExec(command) { + let result = { + status: -1, + stdin: command, + stdout: '', + stderr: '', + }; + + try { + let subprocess = new Gio.Subprocess({ + argv: command.split(' '), + flags: Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE, + }); + subprocess.init(null); + + let [, stdout, stderr] = subprocess.communicate_utf8(null, null); + result.status = subprocess.get_exit_status();; + result.stdout = stdout; + result.stderr = stderr; + } + catch(e) { + result.stderr = e.toString(); + } + + return result; + } + + /** + * Shell execute command. + * + * @param {String} command + * @param {Function} callback (optional) + * @return {Void} + */ + _shellExecAsync(command, callback) { + try { + let subprocess = new Gio.Subprocess({ + argv: command.split(' '), + flags: Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE, + }); + + subprocess.init(null); + subprocess.communicate_utf8_async(null, null, (source, resource) => { + let status = source.get_exit_status(), + [, stdout, stderr] = source.communicate_utf8_finish(resource); + + if (typeof callback === 'function') + callback.call(this, { + status: status, + stdin: command, + stdout: stdout, + stderr: stderr, + }); + }); + } + catch(e) { + if (typeof callback === 'function') + callback.call(this, { + status: -1, + stdin: command, + stdout: '', + stderr: e.toString(), + }); + } + } + + /** + * File with prime status. + * + * @type {String} + */ + get index() { + return '/etc/prime-discrete'; + } + + /** + * Property gpu getter: + * if `nvidia-smi -q` shell command exit code is non-zero, 'nvidia' is not + * in use. + * + * @return {String} + */ + get gpu() { + if (this._gpu) + return this._gpu; + + let cmd = this.command('management'); + if (cmd) { + let exec = this._shellExec(cmd + ' -L'); + this._gpu = exec.status ? 'intel' : 'nvidia'; + } + else + this._gpu = 'unknown'; + + return this.gpu; + } + + /** + * Property query getter: + * shell command `prime-select query` result. + * + * @return {String} + */ + get query() { + let cmd = this.command('select'); + if (cmd) { + let exec = this._shellExec(cmd + ' query'); + return exec.stdout.trim() || exec.stderr.trim() || 'unknown'; + } + + return 'unknown'; + } + + /** + * Property default query getter: + * query on system init. + * + * @return {String} + */ + get defaultQuery() { + let result = GLib.getenv('PRIME_INDICATOR_DEFAULT_QUERY'); + if (result) + return result; + + result = this.query; + GLib.setenv('PRIME_INDICATOR_DEFAULT_QUERY', result, true); + this._log('detected ' + result + ' as default prime option'); + + return this.defaultQuery; + } + + /** + * Get switches (valid arguments for switch command). + * + * @return {Array} + */ + get switches() { + if (this._switches) + return this._switches.slice(); + + let command = this.command('select'); + if (command) { + let exec = this._shellExec(command), + output = exec.stdout || exec.stderr, + args = output.trim().split(' ').pop().split('|'); + if (args.length) + this._switches = args.filter(item => item !== 'query'); + else + this._switches = [ 'nvidia', 'intel' ]; + } + else { + this._switches = []; + } + + return this.switches; + } + + /** + * Does sysem need restarting: + * we store query value on initialization, and if this value differs from + * current one means that we need restart. + + * Warning: + * This may not be 100% accurate. User can switch gpu (without restart) + * and then install extension. In this case defaultQuery variable will be + * invalid. + * + * @return {Boolean} + */ + get isRestartNeeded() { + return this.query !== this.defaultQuery && this.command('select'); + } + + /** + * Get shell command. + * + * @param {String} cmd sudo|select|management|settings + * @return {String} null on fail + */ + command(cmd) { + if (cmd in this._commands) + return this._commands[cmd]; + + return null; + } + + /** + * GPU switch: + * shell command `prime-select $gpu`, where gpu is 'intel' or 'nvidia'. + * + * @param {String} gpu intel|nvidia + * @param {Function} logout (optional) + * @return {Void} + */ + switch(gpu, callback) { + let sudo = this.command('sudo'); + if (!sudo) + return; + + let select = this.command('select'); + if (!select) + return; + + if (this.query === gpu) + return; + + let cmd = sudo + + ' ' + select + + ' ' + gpu; + + this._log('switching to ' + gpu); + this._shellExecAsync(cmd, (e) => { + if (!e.status) + this._log('switched to ' + gpu); + else + this._log('not switched to ' + gpu + ' (' + e.stderr.trim() + ')'); + + if (!e.status && this.isRestartNeeded) + this._log('system restart required'); + + if (typeof callback === 'function') + callback.call(this, { + gpu: gpu, + result: !e.status, + }); + }); + } + + /** + * Start nvidia-settings. + * + * @return {Void} + */ + settings() { + let cmd = this.command('settings'); + if (!cmd) + return; + + this._shellExecAsync(cmd); + } + + /** + * Start file monitoring. + * + * @return {Void} + */ + monitor() { + if (this._listener) + return; + + this._listener = Gio.File.new_for_path(this.index).monitor_file(Gio.FileMonitorFlags.NONE, null); + this._listener.connect('changed', this._handleListener.bind(this)); + } + + /** + * Stop file monitoring. + * + * @return {Void} + */ + unmonitor() { + if (!this._listener) + return; + + this._listener.cancel(); + this._listener = null; + } + + /** + * File monitor change event handler. + * + * @param {Object} file + * @param {Object} otherFile + * @param {Object} eventType + * @return {Void} + */ + _handleListener(file, otherFile, eventType) { + this.emit('gpu-change', this.query); + } + + /* --- */ +}; + +Signals.addSignalMethods(Switch.prototype);