From 4bbfee4cec7adcb2f6de86e23674851ef1347e48 Mon Sep 17 00:00:00 2001 From: Hampus Date: Tue, 18 Aug 2026 19:40:35 +0200 Subject: [PATCH] fix(app): make click-through the default and move animation pausing to Accessibility (#1722) --- fluxer_app/src/app/App.module.css | 11 --- fluxer_app/src/app/App.tsx | 16 +--- .../accessibility/state/Accessibility.ts | 10 -- .../channel/components/MessageActionBar.tsx | 19 ---- .../src/features/platform/types/Electron.ts | 1 - .../ui/utils/WindowFocusInteractionGuard.ts | 23 +---- .../tabs/AdvancedSettingDirectControls.tsx | 15 +-- .../tabs/accessibility_tab/MotionTab.tsx | 15 +++ .../AdvancedAccessibilityControls.tsx | 17 ++++ .../AdvancedDesktopControls.tsx | 36 ------- .../search_index/AccessibilityIndex.ts | 55 +++++++++++ .../search_index/DesktopSettingsIndex.ts | 94 ------------------- .../voice/components/PiPOverlay.module.css | 4 - fluxer_app/src/types/electron.d.ts | 1 - fluxer_desktop/src/common/DesktopConfig.ts | 10 -- fluxer_desktop/src/common/Types.ts | 1 - fluxer_desktop/src/main/DesktopDebugInfo.ts | 1 - fluxer_desktop/src/main/IpcHandlers.ts | 5 - fluxer_desktop/src/main/Window.ts | 10 +- 19 files changed, 96 insertions(+), 248 deletions(-) diff --git a/fluxer_app/src/app/App.module.css b/fluxer_app/src/app/App.module.css index b8d2fbf97..e90ffc5c9 100644 --- a/fluxer_app/src/app/App.module.css +++ b/fluxer_app/src/app/App.module.css @@ -16,11 +16,6 @@ background: transparent; } -:global(html.platform-native.window-focus-activation-guard:not(.first-click-passthrough-when-unfocused)) - :local(.appContainer) { - pointer-events: none; -} - :global(html.is-standalone:not(.auth-page)) :local(.appContainer) { padding-top: env(safe-area-inset-top); } @@ -86,12 +81,6 @@ --skip-link-titlebar-offset: var(--native-titlebar-height); --skip-link-traffic-lights-offset: 4.5rem; } -:global(html.platform-native.window-focus-activation-guard:not(.first-click-passthrough-when-unfocused)) - :local(.overlayScope) - > :not([data-overlay-pass-through]) { - pointer-events: none; -} - .quickSwitcherPortal { position: fixed; inset: 0; diff --git a/fluxer_app/src/app/App.tsx b/fluxer_app/src/app/App.tsx index 670c91a1e..87ce8cd6c 100644 --- a/fluxer_app/src/app/App.tsx +++ b/fluxer_app/src/app/App.tsx @@ -45,15 +45,9 @@ import {getActivePortalHost, setActivePortalHost} from '@app/features/ui/overlay import MobileLayout from '@app/features/ui/state/MobileLayout'; import Modal from '@app/features/ui/state/Modal'; import Popout from '@app/features/ui/state/Popout'; -import { - getDesktopWindowBehaviorSettings, - setDesktopWindowBehaviorSettings, -} from '@app/features/ui/utils/DesktopWindowBehaviorUtils'; +import {getDesktopWindowBehaviorSettings} from '@app/features/ui/utils/DesktopWindowBehaviorUtils'; import {attachExternalLinkInterceptor, isDesktop} from '@app/features/ui/utils/NativeUtils'; -import { - FIRST_CLICK_PASSTHROUGH_WHEN_UNFOCUSED_CLASS, - UNFOCUSED_FULLY_INTERACTIVE_CLASS, -} from '@app/features/ui/utils/WindowFocusInteractionGuard'; +import {UNFOCUSED_FULLY_INTERACTIVE_CLASS} from '@app/features/ui/utils/WindowFocusInteractionGuard'; import UserSettings from '@app/features/user/state/UserSettings'; import {IncomingCallManager} from '@app/features/voice/components/IncomingCallManager'; import {VoiceLiveKitRoot} from '@app/features/voice/components/VoiceLiveKitRoot'; @@ -86,7 +80,6 @@ export const AppWrapper = observer(({children}: AppWrapperProps) => { const {i18n} = useLingui(); const reducedMotion = Accessibility.useReducedMotion; const stayInteractiveWhenUnfocused = Accessibility.stayInteractiveWhenUnfocused; - const firstClickPassThroughWhenUnfocused = Accessibility.firstClickPassThroughWhenUnfocused; const {platform, isNative} = useNativePlatform(); const useSystemTitleBar = useNativeTitleBar(); const messageDisplayCompact = UserSettings.getMessageDisplayCompact(); @@ -163,11 +156,6 @@ export const AppWrapper = observer(({children}: AppWrapperProps) => { useDocumentClassToggle('reduced-motion', reducedMotion); useDocumentClassToggle('mobile-layout', MobileLayout.platformMobileDetected || MobileLayout.enabled); useDocumentClassToggle(UNFOCUSED_FULLY_INTERACTIVE_CLASS, stayInteractiveWhenUnfocused); - useDocumentClassToggle(FIRST_CLICK_PASSTHROUGH_WHEN_UNFOCUSED_CLASS, firstClickPassThroughWhenUnfocused); - useEffect(() => { - if (!isNative) return; - void setDesktopWindowBehaviorSettings({firstClickPassThroughWhenUnfocused}); - }, [isNative, firstClickPassThroughWhenUnfocused]); useDesktopAllowTransparency(isNative); useWindowEventListeners({preventDocumentScroll: !isNative}); useRemScaleTracking(); diff --git a/fluxer_app/src/features/accessibility/state/Accessibility.ts b/fluxer_app/src/features/accessibility/state/Accessibility.ts index 5d5501723..f34a12a36 100644 --- a/fluxer_app/src/features/accessibility/state/Accessibility.ts +++ b/fluxer_app/src/features/accessibility/state/Accessibility.ts @@ -600,7 +600,6 @@ export interface AccessibilitySettings { hdrDisplayMode: HdrDisplayMode; preserveEditDraft: boolean; stayInteractiveWhenUnfocused: boolean; - firstClickPassThroughWhenUnfocused: boolean; scrollToBottomOnMessageSend: boolean; sequentialFileSend: boolean; showNeko: boolean; @@ -718,7 +717,6 @@ class Accessibility { hdrDisplayMode = HdrDisplayMode.FULL; preserveEditDraft = false; stayInteractiveWhenUnfocused = false; - firstClickPassThroughWhenUnfocused = false; scrollToBottomOnMessageSend = true; sequentialFileSend = false; showNeko = false; @@ -829,7 +827,6 @@ class Accessibility { 'hdrDisplayMode', 'preserveEditDraft', 'stayInteractiveWhenUnfocused', - 'firstClickPassThroughWhenUnfocused', 'scrollToBottomOnMessageSend', 'sequentialFileSend', ], @@ -890,7 +887,6 @@ class Accessibility { hdrDisplayMode: HDR_TO_PROTO[s.hdrDisplayMode], preserveEditDraft: s.preserveEditDraft, stayInteractiveWhenUnfocused: s.stayInteractiveWhenUnfocused, - firstClickPassThroughWhenUnfocused: s.firstClickPassThroughWhenUnfocused, scrollToBottomOnMessageSend: s.scrollToBottomOnMessageSend, sequentialFileSend: s.sequentialFileSend, }), @@ -980,8 +976,6 @@ class Accessibility { if (m.preserveEditDraft !== undefined) s.preserveEditDraft = m.preserveEditDraft; if (m.stayInteractiveWhenUnfocused !== undefined) s.stayInteractiveWhenUnfocused = m.stayInteractiveWhenUnfocused; - if (m.firstClickPassThroughWhenUnfocused !== undefined) - s.firstClickPassThroughWhenUnfocused = m.firstClickPassThroughWhenUnfocused; if (m.scrollToBottomOnMessageSend !== undefined) s.scrollToBottomOnMessageSend = m.scrollToBottomOnMessageSend; if (m.sequentialFileSend !== undefined) s.sequentialFileSend = m.sequentialFileSend; }, @@ -1316,8 +1310,6 @@ class Accessibility { if (validated.preserveEditDraft !== undefined) this.preserveEditDraft = validated.preserveEditDraft; if (validated.stayInteractiveWhenUnfocused !== undefined) this.stayInteractiveWhenUnfocused = validated.stayInteractiveWhenUnfocused; - if (validated.firstClickPassThroughWhenUnfocused !== undefined) - this.firstClickPassThroughWhenUnfocused = validated.firstClickPassThroughWhenUnfocused; if (validated.scrollToBottomOnMessageSend !== undefined) this.scrollToBottomOnMessageSend = validated.scrollToBottomOnMessageSend; if (validated.sequentialFileSend !== undefined) this.sequentialFileSend = validated.sequentialFileSend; @@ -1418,8 +1410,6 @@ class Accessibility { hdrDisplayMode: data.hdrDisplayMode ?? this.hdrDisplayMode, preserveEditDraft: data.preserveEditDraft ?? this.preserveEditDraft, stayInteractiveWhenUnfocused: data.stayInteractiveWhenUnfocused ?? this.stayInteractiveWhenUnfocused, - firstClickPassThroughWhenUnfocused: - data.firstClickPassThroughWhenUnfocused ?? this.firstClickPassThroughWhenUnfocused, scrollToBottomOnMessageSend: data.scrollToBottomOnMessageSend ?? this.scrollToBottomOnMessageSend, sequentialFileSend: data.sequentialFileSend ?? this.sequentialFileSend, showNeko: data.showNeko ?? this.showNeko, diff --git a/fluxer_app/src/features/channel/components/MessageActionBar.tsx b/fluxer_app/src/features/channel/components/MessageActionBar.tsx index 7f85286a8..2ce1dffcb 100644 --- a/fluxer_app/src/features/channel/components/MessageActionBar.tsx +++ b/fluxer_app/src/features/channel/components/MessageActionBar.tsx @@ -67,7 +67,6 @@ import {Popout} from '@app/features/ui/popover/PopoverPopout'; import ContextMenu from '@app/features/ui/state/ContextMenu'; import KeyboardMode from '@app/features/ui/state/KeyboardMode'; import {Tooltip} from '@app/features/ui/tooltip/Tooltip'; -import {canUseWindowFocusedActivationClick} from '@app/features/ui/utils/WindowFocusInteractionGuard'; import UserSettings from '@app/features/user/state/UserSettings'; import * as AvatarUtils from '@app/features/user/utils/AvatarUtils'; import {MessageStates} from '@fluxer/constants/src/ChannelConstants'; @@ -187,14 +186,6 @@ const useShiftKey = (enabled: boolean) => { }, [enabled]); return useSyncExternalStore(subscribe, getSnapshot, shiftKeyManager.getServerSnapshot); }; -const suppressBlockedActivationClick = (event: React.SyntheticEvent): boolean => { - if (canUseWindowFocusedActivationClick()) { - return false; - } - event.preventDefault(); - event.stopPropagation(); - return true; -}; interface MessageActionBarButtonProps { label: string; @@ -211,9 +202,6 @@ const MessageActionBarButton = React.forwardRef { const handleClick = useCallback( (event: React.MouseEvent | React.KeyboardEvent) => { - if (suppressBlockedActivationClick(event)) { - return; - } event.preventDefault(); event.stopPropagation(); onClick?.(event); @@ -222,9 +210,6 @@ const MessageActionBarButton = React.forwardRef { - if (suppressBlockedActivationClick(event)) { - return; - } onPointerDownCapture?.(event); }, [onPointerDownCapture], @@ -275,9 +260,6 @@ const QuickReactionButton = observer( const {url: displayUrl} = getEmojiDisplayData(emoji); const handleClick = useCallback( (event: React.MouseEvent | React.KeyboardEvent) => { - if (suppressBlockedActivationClick(event)) { - return; - } event.preventDefault(); event.stopPropagation(); EmojiPickerCommands.trackEmojiUsage(emoji); @@ -700,7 +682,6 @@ export const MessageActionBarCore: React.FC = observe uniqueId={`emoji_picker-actionbar-${message.id}`} shouldAutoUpdate={false} animationType="none" - shouldOpenOnClick={() => canUseWindowFocusedActivationClick()} onOpen={handleEmojiPickerOpen} onClose={handleEmojiPickerClose} data-flx="channel.message-action-bar.message-action-bar-core.popout" diff --git a/fluxer_app/src/features/platform/types/Electron.ts b/fluxer_app/src/features/platform/types/Electron.ts index e06c3c1fb..fb79fdf98 100644 --- a/fluxer_app/src/features/platform/types/Electron.ts +++ b/fluxer_app/src/features/platform/types/Electron.ts @@ -76,7 +76,6 @@ export interface DesktopWindowBehaviorSettings { activeSmoothScrolling: boolean; middleClickAutoscroll: boolean; activeMiddleClickAutoscroll: boolean; - firstClickPassThroughWhenUnfocused: boolean; } export interface ThemeLocalFileReference { diff --git a/fluxer_app/src/features/ui/utils/WindowFocusInteractionGuard.ts b/fluxer_app/src/features/ui/utils/WindowFocusInteractionGuard.ts index 5d3cf1e45..6c222f1b1 100644 --- a/fluxer_app/src/features/ui/utils/WindowFocusInteractionGuard.ts +++ b/fluxer_app/src/features/ui/utils/WindowFocusInteractionGuard.ts @@ -3,7 +3,6 @@ export const WINDOW_FOCUSED_CLASS = 'window-focused'; export const WINDOW_FOCUS_ACTIVATION_GUARD_CLASS = 'window-focus-activation-guard'; export const UNFOCUSED_FULLY_INTERACTIVE_CLASS = 'unfocused-fully-interactive'; -export const FIRST_CLICK_PASSTHROUGH_WHEN_UNFOCUSED_CLASS = 'first-click-passthrough-when-unfocused'; export const WINDOW_HOVER_CONTROLS_CHANGE_EVENT = 'fluxer-window-hover-controls-change'; const DEFAULT_GUARD_TIMEOUT_MS = 250; const DEFAULT_RELEASE_CLEAR_DELAY_MS = 50; @@ -32,16 +31,6 @@ export function isUnfocusedFullyInteractive(root: HTMLElement = document.documen return root.classList.contains(UNFOCUSED_FULLY_INTERACTIVE_CLASS); } -export function shouldBlockActivationClick(root: HTMLElement = document.documentElement): boolean { - return ( - isWindowFocusActivationGuardActive(root) && !root.classList.contains(FIRST_CLICK_PASSTHROUGH_WHEN_UNFOCUSED_CLASS) - ); -} - -export function canUseWindowFocusedActivationClick(root: HTMLElement = document.documentElement): boolean { - return !shouldBlockActivationClick(root); -} - export function canUseWindowFocusedHoverControls(root: HTMLElement = document.documentElement): boolean { if (isUnfocusedFullyInteractive(root)) { return !isWindowFocusActivationGuardActive(root); @@ -132,20 +121,12 @@ export function createWindowFocusInteractionGuard({ clearActivationGuard(); }, releaseClearDelayMs); }; - const suppressActivationEvent = (event: Event) => { - if (!shouldBlockActivationClick(root)) return; - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - }; - const handlePointerStart: EventListener = (event) => { + const handlePointerStart: EventListener = () => { if (wasBlurred || !focused || isWindowFocusActivationGuardActive(root)) { beginActivationGuard(true); } - suppressActivationEvent(event); }; - const handlePointerEnd: EventListener = (event) => { - suppressActivationEvent(event); + const handlePointerEnd: EventListener = () => { scheduleClearAfterActivationClick(); }; windowTarget.addEventListener('pointerdown', handlePointerStart, true); diff --git a/fluxer_app/src/features/user/components/modals/tabs/AdvancedSettingDirectControls.tsx b/fluxer_app/src/features/user/components/modals/tabs/AdvancedSettingDirectControls.tsx index c4ed1a9c8..126dc858f 100644 --- a/fluxer_app/src/features/user/components/modals/tabs/AdvancedSettingDirectControls.tsx +++ b/fluxer_app/src/features/user/components/modals/tabs/AdvancedSettingDirectControls.tsx @@ -3,6 +3,7 @@ import { MiddleClickAutoscrollControl, SmoothScrollingControl, + StayInteractiveUnfocusedControl, TextSelectionControl, VideoSeekThumbnailsControl, } from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls'; @@ -34,10 +35,8 @@ import { } from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedChatControls'; import {DeveloperModeControl} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedClientDeveloperControls'; import { - FirstClickPassThroughControl, HardwareAccelerationControl, NativeTitleBarControl, - StayInteractiveUnfocusedControl, } from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls'; import {UnreadBadgeCustomizationControl} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedExperimentalControls'; import { @@ -90,8 +89,7 @@ export const DIRECT_CONTROL_ITEM_IDS = new Set([ 'voice-video-screen-share-encoder-controls', 'advanced-unread-badge-customization', 'client-developer-mode', - 'advanced-stay-interactive-unfocused', - 'first-click-pass-through', + 'accessibility-stay-interactive-unfocused', 'advanced-native-title-bar', 'advanced-hardware-acceleration', ]); @@ -126,8 +124,7 @@ export const COMPACT_SWITCH_CONTROL_ITEM_IDS = new Set([ 'voice-video-openh264-codec', 'advanced-unread-badge-customization', 'client-developer-mode', - 'advanced-stay-interactive-unfocused', - 'first-click-pass-through', + 'accessibility-stay-interactive-unfocused', 'advanced-native-title-bar', 'advanced-hardware-acceleration', ]); @@ -298,14 +295,10 @@ export const AdvancedSettingControl = observer(({item}: {item: SearchableSetting return ( ); - case 'advanced-stay-interactive-unfocused': + case 'accessibility-stay-interactive-unfocused': return ( ); - case 'first-click-pass-through': - return ( - - ); case 'advanced-native-title-bar': return ( diff --git a/fluxer_app/src/features/user/components/modals/tabs/accessibility_tab/MotionTab.tsx b/fluxer_app/src/features/user/components/modals/tabs/accessibility_tab/MotionTab.tsx index dee9b6096..bf03b919a 100644 --- a/fluxer_app/src/features/user/components/modals/tabs/accessibility_tab/MotionTab.tsx +++ b/fluxer_app/src/features/user/components/modals/tabs/accessibility_tab/MotionTab.tsx @@ -32,6 +32,14 @@ const CONTENT_ANIMATIONS_STAY_IN_ANIMATION_TAB_DESCRIPTOR = msg({ message: 'Animated emojis, GIFs and stickers stay under your control in the Animation tab.', comment: 'Extra hint shown beneath the reduce motion toggle while reduced motion is active.', }); +const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({ + message: 'Stay fully interactive when unfocused', + comment: 'Label in the motion tab.', +}); +const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_RUNNING_DESCRIPTOR = msg({ + message: 'Keep animations, GIF playback, hover effects, and tooltips running while the window is unfocused.', + comment: 'Description text in the motion tab.', +}); export const MotionTabContent: React.FC = observer(() => { const {i18n} = useLingui(); const syncReducedMotionWithSystem = Accessibility.syncReducedMotionWithSystem; @@ -60,6 +68,13 @@ export const MotionTabContent: React.FC = observer(() => { onChange={(value) => AccessibilityCommands.update({reducedMotionOverride: value})} data-flx="user.accessibility-tab.motion-tab.motion-tab-content.switch.update--2" /> + AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})} + data-flx="user.accessibility-tab.motion-tab.motion-tab-content.switch.update--3" + /> ); }); diff --git a/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls.tsx b/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls.tsx index 7ea2708dd..4d3b10bdc 100644 --- a/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls.tsx +++ b/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls.tsx @@ -32,6 +32,10 @@ const SMOOTH_SCROLLING_DESCRIPTOR = msg({ message: 'Smooth scrolling', comment: 'Short label for an advanced desktop scrolling toggle.', }); +const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({ + message: 'Stay fully interactive when unfocused', + comment: 'Short label for an advanced app interaction toggle.', +}); const USE_AUTOSCROLLING_DESCRIPTOR = msg({ message: 'Use autoscrolling', comment: 'Short label for an advanced desktop scrolling toggle.', @@ -135,6 +139,19 @@ export const TextSelectionControl = observer(() => { ); }); +export const StayInteractiveUnfocusedControl = observer(() => { + const {i18n} = useLingui(); + return ( + AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})} + compact + data-flx="user.advanced-settings-tab.switch.stay-interactive-unfocused" + /> + ); +}); + export const VideoSeekThumbnailsControl = observer(() => { const {i18n} = useLingui(); return ( diff --git a/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls.tsx b/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls.tsx index 5326e7066..9298bdc2b 100644 --- a/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls.tsx +++ b/fluxer_app/src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls.tsx @@ -1,7 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -import * as AccessibilityCommands from '@app/features/accessibility/commands/AccessibilityCommands'; -import Accessibility from '@app/features/accessibility/state/Accessibility'; import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal'; import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants'; import { @@ -25,14 +23,6 @@ import {Trans, useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; import {useCallback, useLayoutEffect, useState} from 'react'; -const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({ - message: 'Stay fully interactive when unfocused', - comment: 'Short label for an advanced desktop preference.', -}); -const FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR = msg({ - message: 'First click pass-through when unfocused', - comment: 'Short label for an advanced desktop preference.', -}); const USE_NATIVE_TITLE_BAR_DESCRIPTOR = msg({ message: 'Use native title bar', comment: 'Short label for an advanced desktop preference.', @@ -128,32 +118,6 @@ function useDesktopTroubleshootingSettings() { }; } -export const StayInteractiveUnfocusedControl = observer(() => { - const {i18n} = useLingui(); - return ( - AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})} - compact - data-flx="user.advanced-settings-tab.switch.stay-interactive-unfocused" - /> - ); -}); - -export const FirstClickPassThroughControl = observer(() => { - const {i18n} = useLingui(); - return ( - AccessibilityCommands.update({firstClickPassThroughWhenUnfocused: value})} - compact - data-flx="user.advanced-settings-tab.switch.first-click-pass-through" - /> - ); -}); - export const NativeTitleBarControl = observer(() => { const {i18n} = useLingui(); const {desktopWindowBehavior, desktopWindowBehaviorBusy, updateDesktopWindowBehavior} = diff --git a/fluxer_app/src/features/user/components/settings_utils/search_index/AccessibilityIndex.ts b/fluxer_app/src/features/user/components/settings_utils/search_index/AccessibilityIndex.ts index 648addc2d..ca2d32063 100644 --- a/fluxer_app/src/features/user/components/settings_utils/search_index/AccessibilityIndex.ts +++ b/fluxer_app/src/features/user/components/settings_utils/search_index/AccessibilityIndex.ts @@ -342,6 +342,43 @@ const CONTROL_MIDDLE_CLICK_AUTOSCROLLING_DESCRIPTOR = msg({ message: 'Control Chromium middle-click autoscrolling in the desktop app', comment: 'Settings search entry description. One-line summary of what the settings search entry controls.', }); +const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({ + message: 'Stay fully interactive when unfocused', + comment: 'Settings search entry label. Names the settings search entry in the settings UI.', +}); +const UNFOCUSED_DESCRIPTOR = msg({ + message: 'Unfocused', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const WINDOW_FOCUS_DESCRIPTOR = msg({ + message: 'Window focus', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR = msg({ + message: 'Animations while unfocused', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const ANIMATION_PLAYBACK_DESCRIPTOR = msg({ + message: 'Animation playback', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const HOVER_EFFECTS_DESCRIPTOR = msg({ + message: 'Hover effects', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const TOOLTIPS_DESCRIPTOR = msg({ + message: 'Tooltips', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const POWER_SAVING_DESCRIPTOR = msg({ + message: 'Power saving', + comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', +}); +const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR = msg({ + message: 'Keep animations, GIF playback, hover effects, and tooltips running while the window is unfocused.', + comment: 'Settings search entry description. One-line summary of what the settings search entry controls.', +}); + export const accessibilityIndex: Array = [ { id: 'accessibility-confirm-calls', @@ -486,6 +523,24 @@ export const accessibilityIndex: Array = [ ], description: DISPLAY_A_VISIBLE_FOCUS_INDICATOR_AROUND_THE_MESSAGE_DESCRIPTOR, }, + { + id: 'accessibility-stay-interactive-unfocused', + tabType: 'accessibility', + sectionId: 'motion', + label: STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR, + keywords: [ + UNFOCUSED_DESCRIPTOR, + WINDOW_FOCUS_DESCRIPTOR, + ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR, + ANIMATION_PLAYBACK_DESCRIPTOR, + HOVER_EFFECTS_DESCRIPTOR, + TOOLTIPS_DESCRIPTOR, + POWER_SAVING_DESCRIPTOR, + ], + description: KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR, + audience: 'advanced', + tags: ['accessibility'], + }, { id: 'accessibility-sync-reduced-motion', tabType: 'accessibility', diff --git a/fluxer_app/src/features/user/components/settings_utils/search_index/DesktopSettingsIndex.ts b/fluxer_app/src/features/user/components/settings_utils/search_index/DesktopSettingsIndex.ts index 17771f4bb..47983e7fd 100644 --- a/fluxer_app/src/features/user/components/settings_utils/search_index/DesktopSettingsIndex.ts +++ b/fluxer_app/src/features/user/components/settings_utils/search_index/DesktopSettingsIndex.ts @@ -7,66 +7,6 @@ import type {SearchableSettingDescriptor} from '@app/features/user/components/se import {BACKGROUND_DESCRIPTOR} from '@app/features/user/components/settings_utils/search_index/SharedDescriptors'; import {msg} from '@lingui/core/macro'; -const FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR = msg({ - message: 'First click pass-through when unfocused', - comment: 'Settings search entry label. Names the settings search entry in the settings UI.', -}); -const FIRST_CLICK_DESCRIPTOR = msg({ - message: 'First click', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const CLICK_THROUGH_DESCRIPTOR = msg({ - message: 'Click through', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const UNFOCUSED_DESCRIPTOR = msg({ - message: 'Unfocused', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const WINDOW_FOCUS_DESCRIPTOR = msg({ - message: 'Window focus', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const FOCUS_CLICK_DESCRIPTOR = msg({ - message: 'Focus click', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const ACTIVATION_CLICK_DESCRIPTOR = msg({ - message: 'Activation click', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const LET_THE_CLICK_THAT_FOCUSES_ALSO_ACTIVATE_THE_DESCRIPTOR = msg({ - message: 'Let focus clicks activate controls.', - comment: 'Settings search entry description. One-line summary of what the settings search entry controls.', -}); -const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({ - message: 'Stay fully interactive when unfocused', - comment: 'Settings search entry label. Names the settings search entry in the settings UI.', -}); -const ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR = msg({ - message: 'Animations while unfocused', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const ANIMATION_PLAYBACK_DESCRIPTOR = msg({ - message: 'Animation playback', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const HOVER_EFFECTS_DESCRIPTOR = msg({ - message: 'Hover effects', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const TOOLTIPS_DESCRIPTOR = msg({ - message: 'Tooltips', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const POWER_SAVING_DESCRIPTOR = msg({ - message: 'Power saving', - comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.', -}); -const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR = msg({ - message: 'Keep animations, GIFs, hover, and tooltips running unfocused', - comment: 'Settings search entry description. One-line summary of what the settings search entry controls.', -}); const HARDWARE_ACCELERATION_DESCRIPTOR = msg({ message: 'Hardware acceleration', comment: 'Settings search entry label. Names the settings search entry in the settings UI.', @@ -280,40 +220,6 @@ const KEEP_RUNNING_WHEN_THE_WINDOW_IS_CLOSED_DESCRIPTOR = msg({ comment: 'Settings search entry description. One-line summary of what the settings search entry controls.', }); export const desktopSettingsIndex: Array = [ - { - id: 'first-click-pass-through', - tabType: 'desktop_settings', - label: FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR, - keywords: [ - FIRST_CLICK_DESCRIPTOR, - CLICK_THROUGH_DESCRIPTOR, - UNFOCUSED_DESCRIPTOR, - WINDOW_FOCUS_DESCRIPTOR, - FOCUS_CLICK_DESCRIPTOR, - ACTIVATION_CLICK_DESCRIPTOR, - ], - description: LET_THE_CLICK_THAT_FOCUSES_ALSO_ACTIVATE_THE_DESCRIPTOR, - audience: 'advanced', - tags: ['desktop'], - isVisible: isDesktop, - }, - { - id: 'advanced-stay-interactive-unfocused', - tabType: 'desktop_settings', - label: STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR, - keywords: [ - UNFOCUSED_DESCRIPTOR, - WINDOW_FOCUS_DESCRIPTOR, - ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR, - ANIMATION_PLAYBACK_DESCRIPTOR, - HOVER_EFFECTS_DESCRIPTOR, - TOOLTIPS_DESCRIPTOR, - POWER_SAVING_DESCRIPTOR, - ], - description: KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR, - tags: ['desktop'], - isVisible: isDesktop, - }, { id: 'advanced-hardware-acceleration', tabType: 'desktop_settings', diff --git a/fluxer_app/src/features/voice/components/PiPOverlay.module.css b/fluxer_app/src/features/voice/components/PiPOverlay.module.css index a3f222c78..360596eb8 100644 --- a/fluxer_app/src/features/voice/components/PiPOverlay.module.css +++ b/fluxer_app/src/features/voice/components/PiPOverlay.module.css @@ -24,10 +24,6 @@ contain: layout style; } -:global(html.platform-native.window-focus-activation-guard:not(.first-click-passthrough-when-unfocused)) .container { - pointer-events: none; -} - .container:active { cursor: grabbing; } diff --git a/fluxer_app/src/types/electron.d.ts b/fluxer_app/src/types/electron.d.ts index 61f5575d3..5614228e4 100644 --- a/fluxer_app/src/types/electron.d.ts +++ b/fluxer_app/src/types/electron.d.ts @@ -93,7 +93,6 @@ export interface DesktopWindowBehaviorSettings { activeSmoothScrolling: boolean; middleClickAutoscroll: boolean; activeMiddleClickAutoscroll: boolean; - firstClickPassThroughWhenUnfocused: boolean; } export interface ThemeLocalFileReference { diff --git a/fluxer_desktop/src/common/DesktopConfig.ts b/fluxer_desktop/src/common/DesktopConfig.ts index bd5ef4b1a..efd82e146 100644 --- a/fluxer_desktop/src/common/DesktopConfig.ts +++ b/fluxer_desktop/src/common/DesktopConfig.ts @@ -31,7 +31,6 @@ interface PersistedDesktopWindowBehaviorSettings { allowTransparency?: boolean; smoothScrolling?: boolean; middleClickAutoscroll?: boolean; - firstClickPassThroughWhenUnfocused?: boolean; } interface PersistedDesktopTroubleshootingSettings { @@ -62,7 +61,6 @@ function getDefaultDesktopWindowBehaviorSettings(): DesktopWindowBehaviorSetting activeSmoothScrolling: true, middleClickAutoscroll: false, activeMiddleClickAutoscroll: false, - firstClickPassThroughWhenUnfocused: false, }; } @@ -95,9 +93,6 @@ function sanitizePersistedDesktopWindowBehaviorSettings( if (typeof value.middleClickAutoscroll === 'boolean') { settings.middleClickAutoscroll = value.middleClickAutoscroll; } - if (typeof value.firstClickPassThroughWhenUnfocused === 'boolean') { - settings.firstClickPassThroughWhenUnfocused = value.firstClickPassThroughWhenUnfocused; - } const minimizeToTrayV2 = value[MINIMIZE_TO_TRAY_STORAGE_KEY_V2]; if (typeof minimizeToTrayV2 === 'boolean') { settings.minimizeToTrayV2 = minimizeToTrayV2; @@ -238,10 +233,6 @@ function normalizeDesktopWindowBehaviorSettings( : typeof normalizedSettings?.middleClickAutoscroll === 'boolean' ? normalizedSettings.middleClickAutoscroll : defaults.middleClickAutoscroll, - firstClickPassThroughWhenUnfocused: - typeof normalizedSettings?.firstClickPassThroughWhenUnfocused === 'boolean' - ? normalizedSettings.firstClickPassThroughWhenUnfocused - : defaults.firstClickPassThroughWhenUnfocused, }; if (!normalized.showTrayIcon) { normalized.minimizeToTray = false; @@ -260,7 +251,6 @@ function serializeDesktopWindowBehaviorSettings( allowTransparency: settings.allowTransparency, smoothScrolling: settings.smoothScrolling, middleClickAutoscroll: settings.middleClickAutoscroll, - firstClickPassThroughWhenUnfocused: settings.firstClickPassThroughWhenUnfocused, [MINIMIZE_TO_TRAY_STORAGE_KEY_V2]: settings.minimizeToTray, [CLOSE_TO_TRAY_STORAGE_KEY_V2]: settings.closeToTray, }; diff --git a/fluxer_desktop/src/common/Types.ts b/fluxer_desktop/src/common/Types.ts index 3c1604d07..744f2aaee 100644 --- a/fluxer_desktop/src/common/Types.ts +++ b/fluxer_desktop/src/common/Types.ts @@ -120,7 +120,6 @@ export interface DesktopWindowBehaviorSettings { activeSmoothScrolling: boolean; middleClickAutoscroll: boolean; activeMiddleClickAutoscroll: boolean; - firstClickPassThroughWhenUnfocused: boolean; } export interface ThemeLocalFileReference { diff --git a/fluxer_desktop/src/main/DesktopDebugInfo.ts b/fluxer_desktop/src/main/DesktopDebugInfo.ts index 5963ecba3..17883c43e 100644 --- a/fluxer_desktop/src/main/DesktopDebugInfo.ts +++ b/fluxer_desktop/src/main/DesktopDebugInfo.ts @@ -322,7 +322,6 @@ function formatWindowBehavior(settings: DesktopWindowBehaviorSettings): string { `activeSmoothScrolling=${settings.activeSmoothScrolling}`, `middleClickAutoscroll=${settings.middleClickAutoscroll}`, `activeMiddleClickAutoscroll=${settings.activeMiddleClickAutoscroll}`, - `firstClickPassThroughWhenUnfocused=${settings.firstClickPassThroughWhenUnfocused}`, ].join(', '); } diff --git a/fluxer_desktop/src/main/IpcHandlers.ts b/fluxer_desktop/src/main/IpcHandlers.ts index 660370e60..190bdde95 100644 --- a/fluxer_desktop/src/main/IpcHandlers.ts +++ b/fluxer_desktop/src/main/IpcHandlers.ts @@ -62,7 +62,6 @@ import { import { clearSavedWindowBounds, closeThemeStudioPopoutWindow, - desktopFirstClickPassThroughPendingRestart, desktopTransparencyPendingRestart, desktopUseNativeTitleBarPendingRestart, focusThemeStudioPopoutWindow, @@ -123,9 +122,6 @@ function normalizeDesktopWindowBehaviorUpdate(value: unknown): Partial { return ( desktopTrayChangePendingRestart() || - desktopFirstClickPassThroughPendingRestart() || desktopUseNativeTitleBarPendingRestart() || desktopTransparencyPendingRestart() ); diff --git a/fluxer_desktop/src/main/Window.ts b/fluxer_desktop/src/main/Window.ts index 1cd6cf1bb..8f820773c 100644 --- a/fluxer_desktop/src/main/Window.ts +++ b/fluxer_desktop/src/main/Window.ts @@ -145,7 +145,6 @@ interface CreateWindowOptions { let mainWindow: BrowserWindow | null = null; let windowStateFile: string; let isQuitting = false; -let initialAcceptFirstMouseOnFocus: boolean | null = null; let initialUseNativeTitleBar: boolean | null = null; let initialAllowTransparency: boolean | null = null; let themeStudioPopoutWindow: BrowserWindow | null = null; @@ -331,12 +330,6 @@ export function getMainWindow(): BrowserWindow | null { return mainWindow; } -export function desktopFirstClickPassThroughPendingRestart(): boolean { - if (process.platform !== 'darwin') return false; - if (initialAcceptFirstMouseOnFocus === null) return false; - return getDesktopWindowBehaviorSettings().firstClickPassThroughWhenUnfocused !== initialAcceptFirstMouseOnFocus; -} - export function getActiveUseNativeTitleBar(): boolean { return initialUseNativeTitleBar ?? false; } @@ -730,8 +723,7 @@ export function createWindow(options: CreateWindowOptions = {}): BrowserWindow { const desktopWindowBehavior = getDesktopWindowBehaviorSettings(); const allowTransparency = desktopWindowBehavior.allowTransparency; const useNativeTitleBar = getEffectiveUseNativeTitleBar(desktopWindowBehavior); - const acceptFirstMouseOnFocus = isMac && desktopWindowBehavior.firstClickPassThroughWhenUnfocused; - initialAcceptFirstMouseOnFocus = acceptFirstMouseOnFocus; + const acceptFirstMouseOnFocus = isMac; initialUseNativeTitleBar = useNativeTitleBar; initialAllowTransparency = allowTransparency; const appUrl = getAppUrl();