global desktop mode feature

This commit is contained in:
Fabian Freund
2026-06-06 13:02:23 +02:00
parent ae7c9feb08
commit 4a12acab99
14 changed files with 229 additions and 4 deletions
@@ -23,6 +23,8 @@ import eu.weblibre.flutter_mozilla_components.pigeons.HttpsOnlyMode
import eu.weblibre.flutter_mozilla_components.pigeons.QueryParameterStripping
import eu.weblibre.flutter_mozilla_components.pigeons.TrackingScope
import eu.weblibre.flutter_mozilla_components.pigeons.WebContentIsolationStrategy
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.action.DefaultDesktopModeAction
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy
@@ -467,4 +469,36 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
override fun getUseExternalDownloadManager(): Boolean {
return GlobalComponents.useExternalDownloadManager
}
override fun setGlobalDesktopMode(enable: Boolean, applyToExistingTabs: Boolean) {
val store = components.core.store
// Updates BrowserState.desktopMode, the browser-wide default applied to
// newly created tabs/engine sessions.
store.dispatch(DefaultDesktopModeAction.DesktopModeUpdated(enable))
// Only an explicit user toggle should rewrite existing tabs. Skipping this
// on the initial replication fire (startup / service rebuild) avoids
// clobbering per-tab desktop/mobile overrides and reloading loaded tabs.
if (!applyToExistingTabs) {
return
}
// Apply the new value to all existing regular tabs so the change takes
// effect immediately instead of only on tabs opened afterwards.
store.state.tabs.forEach { tab ->
if (tab.content.desktopMode == enable) return@forEach
if (tab.engineState.engineSession != null) {
// Loaded tab: toggle the engine session's desktop mode and reload
// it so the page re-renders with the new user agent / viewport.
components.useCases.sessionUseCases.requestDesktopSite(enable, tab.id)
} else {
// Suspended tab (no engine session yet): only update the content
// state so the value is applied when the tab is next loaded,
// without force-creating a session and waking the tab now.
store.dispatch(ContentAction.UpdateTabDesktopMode(tab.id, enable))
}
}
}
}
@@ -7274,6 +7274,17 @@ interface GeckoEngineSettingsApi {
*/
fun setUseExternalDownloadManager(enabled: Boolean)
fun getUseExternalDownloadManager(): Boolean
/**
* Sets the browser-wide default desktop mode (BrowserState.desktopMode).
* Newly opened tabs inherit this default; a per-tab requestDesktopSite
* still overrides it for that tab.
*
* When [applyToExistingTabs] is true, the new value is also applied to all
* currently open tabs (loaded tabs are reloaded, suspended tabs are updated
* in place). This should only be requested for an explicit user toggle, not
* during startup/replication restore, to avoid clobbering per-tab overrides.
*/
fun setGlobalDesktopMode(enable: Boolean, applyToExistingTabs: Boolean)
companion object {
/** The codec used by GeckoEngineSettingsApi. */
@@ -7422,6 +7433,25 @@ interface GeckoEngineSettingsApi {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setGlobalDesktopMode$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val enableArg = args[0] as Boolean
val applyToExistingTabsArg = args[1] as Boolean
val wrapped: List<Any?> = try {
api.setGlobalDesktopMode(enableArg, applyToExistingTabsArg)
listOf(null)
} catch (exception: Throwable) {
GeckoPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
@@ -216,4 +216,18 @@ class GeckoEngineSettingsService {
Future<bool> getUseExternalDownloadManager() {
return _api.getUseExternalDownloadManager();
}
/// Sets the browser-wide default desktop mode (BrowserState.desktopMode).
/// Newly opened tabs inherit this default; a per-tab requestDesktopSite still
/// overrides it for that tab.
///
/// Set [applyToExistingTabs] to true only for an explicit user toggle so the
/// new value is also applied to currently open tabs. Leave it false during
/// startup/replication restore to avoid clobbering per-tab overrides.
Future<void> setGlobalDesktopMode(
bool enable, {
bool applyToExistingTabs = false,
}) {
return _api.setGlobalDesktopMode(enable, applyToExistingTabs);
}
}
@@ -7360,6 +7360,32 @@ class GeckoEngineSettingsApi {
;
return pigeonVar_replyValue! as bool;
}
/// Sets the browser-wide default desktop mode (BrowserState.desktopMode).
/// Newly opened tabs inherit this default; a per-tab requestDesktopSite
/// still overrides it for that tab.
///
/// When [applyToExistingTabs] is true, the new value is also applied to all
/// currently open tabs (loaded tabs are reloaded, suspended tabs are updated
/// in place). This should only be requested for an explicit user toggle, not
/// during startup/replication restore, to avoid clobbering per-tab overrides.
Future<void> setGlobalDesktopMode(bool enable, bool applyToExistingTabs) async {
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setGlobalDesktopMode$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[enable, applyToExistingTabs]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
)
;
}
}
class GeckoSessionApi {
@@ -1561,6 +1561,16 @@ abstract class GeckoEngineSettingsApi {
void setUseExternalDownloadManager(bool enabled);
bool getUseExternalDownloadManager();
/// Sets the browser-wide default desktop mode (BrowserState.desktopMode).
/// Newly opened tabs inherit this default; a per-tab requestDesktopSite
/// still overrides it for that tab.
///
/// When [applyToExistingTabs] is true, the new value is also applied to all
/// currently open tabs (loaded tabs are reloaded, suspended tabs are updated
/// in place). This should only be requested for an explicit user toggle, not
/// during startup/replication restore, to avoid clobbering per-tab overrides.
void setGlobalDesktopMode(bool enable, bool applyToExistingTabs);
}
@HostApi()