-
-
Notifications
You must be signed in to change notification settings - Fork 499
Add flatpak portal manager, autostart on flatpaks #1670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
0dc4ee2
Add flatpak portal manager, autostart on flatpaks
Zinkelburger 75fbb64
strategy pattern for linuxAutoLaunch, fix comments
Zinkelburger efbc347
move flatpak portal management code entirely to it, other small fixes
Zinkelburger 2b7a396
Copilot changes, refactor _waitForBusResponse
Zinkelburger 45bc24c
Refactor
hovancik d3e04bd
Only update settings on successful operation
hovancik 7546677
Fix smaller issues
hovancik 12bc506
Small improvements
hovancik aa01830
Simplify the params
hovancik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| import dbus from '@particle/dbus-next' | ||
| import log from 'electron-log/main.js' | ||
|
|
||
| const { Variant } = dbus | ||
|
|
||
| class FlatpakPortalManager { | ||
| constructor (settings) { | ||
| this.settings = settings | ||
| this.bus = null | ||
| this.portal = null | ||
| this.initialized = false | ||
| this.portalRequestTimeoutMs = 30000 | ||
| } | ||
|
|
||
| async initialize () { | ||
| if (this.initialized) return | ||
|
|
||
| if (this.bus) { | ||
| try { | ||
| this.bus.disconnect() | ||
| } catch { | ||
| // Ignore disconnect errors | ||
| } | ||
| this.bus = null | ||
| this.portal = null | ||
| } | ||
|
|
||
| try { | ||
| this.bus = dbus.sessionBus() | ||
| this.portal = await this.bus.getProxyObject( | ||
| 'org.freedesktop.portal.Desktop', | ||
| '/org/freedesktop/portal/desktop' | ||
| ) | ||
| this.initialized = true | ||
| log.info('Stretchly: XDG Background Portal initialized successfully') | ||
| } catch (error) { | ||
| log.error('Stretchly: Failed to initialize XDG Background Portal:', error) | ||
| this.initialized = false | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Sets the autostart status for the application using the XDG Background Portal. | ||
| * @param {boolean} enabled - True to enable autostart, false to disable. | ||
| * @returns {Promise<boolean>} - True if the autostart status was successfully set. | ||
| */ | ||
| async setAutostart (enabled) { | ||
| await this.initialize() | ||
|
|
||
| if (!this.initialized) { | ||
| log.error('Stretchly: Cannot set autostart - portal not initialized') | ||
| return false | ||
| } | ||
|
|
||
| try { | ||
| const background = this.portal.getInterface('org.freedesktop.portal.Background') | ||
| const handleToken = `stretchly_autostart_${Date.now()}_${Math.random().toString(36).substring(7)}` | ||
|
|
||
| const options = { | ||
| handle_token: new Variant('s', handleToken), | ||
| reason: new Variant('s', 'Stretchly needs to run in the background to remind you to take breaks'), | ||
| autostart: new Variant('b', enabled), | ||
| 'dbus-activatable': new Variant('b', false) | ||
| } | ||
|
|
||
| // When disabling autostart, the portal doesn't create a persistent request object. | ||
| // No Response signal is emitted, so we can return immediately. | ||
| if (!enabled) { | ||
| try { | ||
| await background.RequestBackground('', options) | ||
| log.info('Stretchly: Autostart disabled via XDG Portal') | ||
| return true | ||
| } catch (error) { | ||
| log.error('Stretchly: Failed to disable autostart via XDG Portal:', error) | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| // When enabling autostart, we must wait for the Response signal. | ||
| // We start listening BEFORE calling the method to avoid race conditions. | ||
| const responsePromise = this._waitForBusResponse(handleToken, enabled) | ||
|
|
||
| const requestPath = await background.RequestBackground('', options) | ||
| log.info(`Stretchly: RequestBackground called, request path: ${requestPath}`) | ||
|
|
||
| return await responsePromise | ||
| } catch (error) { | ||
| log.error(`Stretchly: Failed to set autostart=${enabled} via XDG Portal:`, error) | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Waits for the Portal Request Response signal. | ||
| * @private | ||
| */ | ||
| _waitForBusResponse (handleToken, expectingEnabled) { | ||
| return new Promise((resolve) => { | ||
| let timeoutId = null | ||
| let messageListener = null | ||
|
|
||
| const cleanup = () => { | ||
| if (timeoutId) { | ||
| clearTimeout(timeoutId) | ||
| timeoutId = null | ||
| } | ||
| if (messageListener && this.bus) { | ||
| this.bus.off('message', messageListener) | ||
| messageListener = null | ||
| } | ||
| } | ||
|
|
||
| messageListener = (msg) => { | ||
| if (msg.interface === 'org.freedesktop.portal.Request' && | ||
| msg.member === 'Response' && | ||
| msg.path.endsWith(handleToken)) { | ||
| const [response, results] = msg.body | ||
|
|
||
| cleanup() | ||
|
|
||
| log.info(`Stretchly: Portal Response signal received - response: ${response}, results:`, results) | ||
|
|
||
| // Response codes: 0 = success, 1 = user cancelled, 2 = other error | ||
| if (response === 0) { | ||
| const autostartGranted = results && results.autostart && results.autostart.value === expectingEnabled | ||
| if (autostartGranted) { | ||
| log.info('Stretchly: Autostart enabled via XDG Portal') | ||
| } else { | ||
| log.warn('Stretchly: Autostart status did not match request', results) | ||
| } | ||
| resolve(autostartGranted) | ||
| } else if (response === 1) { | ||
| log.warn('Stretchly: User cancelled the portal request') | ||
| resolve(false) | ||
| } else { | ||
| log.error(`Stretchly: Portal request failed with response code: ${response}`) | ||
| resolve(false) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| timeoutId = setTimeout(() => { | ||
| cleanup() | ||
| log.error(`Stretchly: Portal request timeout after ${this.portalRequestTimeoutMs / 1000} seconds`) | ||
| resolve(false) | ||
| }, this.portalRequestTimeoutMs) | ||
|
|
||
| this.bus.on('message', messageListener) | ||
| }) | ||
| } | ||
|
|
||
| async enableAutostart () { | ||
| try { | ||
| const success = await this.setAutostart(true) | ||
| if (success) { | ||
| this.settings.set('flatpakAutostart', true) | ||
| } | ||
| return success | ||
| } catch (error) { | ||
| log.error('Stretchly: Failed to set autostart (enable) via XDG Portal', error) | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| async disableAutostart () { | ||
| try { | ||
| const success = await this.setAutostart(false) | ||
| if (success) { | ||
| this.settings.set('flatpakAutostart', false) | ||
| } | ||
| return success | ||
| } catch (error) { | ||
| log.error('Stretchly: Failed to set autostart (disable) via XDG Portal', error) | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| async isAutostartEnabled () { | ||
| // XDG portals don't provide a reliable query method, so we read from our cache | ||
| return this.settings.get('flatpakAutostart') | ||
| } | ||
|
|
||
| disconnect () { | ||
| if (this.bus) { | ||
| this.bus.disconnect() | ||
| this.bus = null | ||
| this.portal = null | ||
| this.initialized = false | ||
| log.info('Stretchly: XDG Background Portal disconnected') | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export default FlatpakPortalManager | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.