дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(window): show the window buttons in full screen on macOS (#2015)
Native full screen moves a window's buttons into the bar revealed with the menu bar, and a project tab shown in its group's full-screen Space has none, so the title bar's slot for them stayed empty. The title bar now draws them there while the window fills the screen: close closes that project's tab, the green button leaves full screen, and minimize is disabled.
Цей коміт міститься в:
1 джерело
257fb0f50f
коміт
429b8f0efe
16 files changed
+205
-7
No files matched your search
@@ -903,6 +903,11 @@ export const commands = {
|
||||
windowFlashTaskbar: (flash: boolean) => typedError<null, IdeError>(__TAURI_INVOKE("window_flash_taskbar", { flash })),
|
||||
/** Height of the web title bar in native logical pixels (CSS height × IDE zoom). */
|
||||
windowSetTitlebarHeight: (height: number | null) => typedError<null, IdeError>(__TAURI_INVOKE("window_set_titlebar_height", { height })),
|
||||
/**
|
||||
* Whether this window fills the screen: in native full screen, or (macOS) shown in its window
|
||||
* group's full-screen Space.
|
||||
*/
|
||||
windowIsFullscreen: () => __TAURI_INVOKE<boolean>("window_is_fullscreen"),
|
||||
/**
|
||||
* Starts dragging `window` while the primary mouse button is still down; returns whether a drag began.
|
||||
*
|
||||
@@ -4479,7 +4484,9 @@ export type IdeError = {
|
||||
|
||||
export type IdeEvent =
|
||||
/** Project window membership or selection changed. */
|
||||
{ type: "windowGroupsChanged" } | { type: "projectTrustChanged"; root: IpcPath; trusted: boolean } |
|
||||
{ type: "windowGroupsChanged" } |
|
||||
/** A window entered or left full screen, itself or as a member of a full-screen window group. */
|
||||
{ type: "windowFullscreenChanged" } | { type: "projectTrustChanged"; root: IpcPath; trusted: boolean } |
|
||||
/** Files or directories changed on disk (after debouncing, ignore rules applied). */
|
||||
{ type: "fsChanged"; created: IpcPath[]; modified: IpcPath[]; removed: IpcPath[] } |
|
||||
/** Excluded or ignored folders whose contents changed; they stay out of `FsChanged`. */
|
||||
|
||||
@@ -196,6 +196,7 @@
|
||||
"window.caption.minimize": "Minimize",
|
||||
"window.caption.maximize": "Maximize",
|
||||
"window.caption.restore": "Restore Down",
|
||||
"window.caption.exitFullScreen": "Exit Full Screen",
|
||||
"window.caption.close": "Close",
|
||||
"menu.help.keymapReference": "Keymap Reference",
|
||||
"menu.help.showLog": "{os, select, macos {Show Log in Finder} windows {Show Log in Explorer} other {Show Log in Files}}",
|
||||
|
||||
@@ -196,6 +196,7 @@
|
||||
"window.caption.minimize": "最小化",
|
||||
"window.caption.maximize": "最大化",
|
||||
"window.caption.restore": "向下还原",
|
||||
"window.caption.exitFullScreen": "退出全屏",
|
||||
"window.caption.close": "关闭",
|
||||
"menu.help.keymapReference": "快捷键参考",
|
||||
"menu.help.showLog": "{os, select, macos {在访达中显示日志} windows {在资源管理器中显示日志} other {在文件管理器中显示日志}}",
|
||||
|
||||
@@ -436,6 +436,16 @@ html {
|
||||
--fg-caption-close-hover: #ffffff;
|
||||
}
|
||||
|
||||
/* macOS window buttons drawn by the web title bar in full screen: the system colours in every theme. */
|
||||
:root {
|
||||
--mac-window-close: #ff5f57;
|
||||
--mac-window-minimize: #febc2e;
|
||||
--mac-window-zoom: #28c840;
|
||||
--mac-window-glyph: rgb(0 0 0 / 55%);
|
||||
--mac-window-edge: rgb(0 0 0 / 12%);
|
||||
--mac-window-inactive: color-mix(in srgb, var(--fg-strong) 22%, transparent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Islands Light. Every colour token of :root is redefined here. Values are
|
||||
* PyCharm's own; its secondary greys, comment / metadata colours, line numbers
|
||||
|
||||
@@ -248,6 +248,9 @@ const ICONS = {
|
||||
"window-maximize": "openidea/general/windowMaximize",
|
||||
"window-restore": "openidea/general/windowRestore",
|
||||
"window-close": "openidea/general/windowClose",
|
||||
"mac-window-close": "openidea/general/macWindowClose",
|
||||
"mac-window-minimize": "openidea/general/macWindowMinimize",
|
||||
"mac-window-exit-full-screen": "openidea/general/macWindowExitFullScreen",
|
||||
hide: "general/hide",
|
||||
pin: "general/pin",
|
||||
eye: "general/show",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<!-- OpenIDEA: macOS window button glyph (close), drawn in the full-screen title bar. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.5 4.5L11.5 11.5M11.5 4.5L4.5 11.5" stroke="#6C707E" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
Після Ширина: | Висота: | Розмір: 299 B |
@@ -0,0 +1,5 @@
|
||||
<!-- OpenIDEA: macOS window button glyph (exit full screen), drawn in the full-screen title bar. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.75 2.5V7.25H13.5L8.75 2.5Z" fill="#6C707E"/>
|
||||
<path d="M7.25 13.5V8.75H2.5L7.25 13.5Z" fill="#6C707E"/>
|
||||
</svg>
|
||||
|
Після Ширина: | Висота: | Розмір: 319 B |
@@ -0,0 +1,4 @@
|
||||
<!-- OpenIDEA: macOS window button glyph (minimize), drawn in the full-screen title bar. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.5 8H12.5" stroke="#6C707E" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
Після Ширина: | Висота: | Розмір: 277 B |
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* macOS window buttons in the title bar's slot while the window fills the screen. Native full
|
||||
* screen moves the system's buttons into the bar revealed with the menu bar, and a project tab
|
||||
* shown in its group's full-screen Space has none, so the slot kept for them would be empty.
|
||||
* Close closes this project's tab, the green button leaves full screen, minimize is disabled.
|
||||
* Like the system's, they take no keyboard focus.
|
||||
*/
|
||||
import { useEffect, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { t } from "@/platform/i18n";
|
||||
import { commands, onIdeEvent } from "@/platform/ipc";
|
||||
import { Icon } from "@/ui";
|
||||
import styles from "./TitleBar.module.css";
|
||||
|
||||
type AppWindow = import("@tauri-apps/api/window").Window;
|
||||
|
||||
function useFullscreenWindow(): { fullscreen: boolean; active: boolean } {
|
||||
const [fullscreen, setFullscreen] = useState(false);
|
||||
const [active, setActive] = useState(() => document.hasFocus());
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
const offs: (() => void)[] = [];
|
||||
const sync = () => void commands.windowIsFullscreen().then((on) => !disposed && setFullscreen(on));
|
||||
sync();
|
||||
offs.push(onIdeEvent("windowFullscreenChanged", sync));
|
||||
void import("@tauri-apps/api/window").then(async ({ getCurrentWindow }) => {
|
||||
const w: AppWindow = getCurrentWindow();
|
||||
const listeners = await Promise.all([
|
||||
w.onResized(sync),
|
||||
w.onFocusChanged(({ payload }) => {
|
||||
setActive(payload);
|
||||
sync();
|
||||
}),
|
||||
]);
|
||||
if (disposed) listeners.forEach((off) => off());
|
||||
else offs.push(...listeners);
|
||||
});
|
||||
return () => {
|
||||
disposed = true;
|
||||
offs.forEach((off) => off());
|
||||
};
|
||||
}, []);
|
||||
return { fullscreen, active };
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
void import("@tauri-apps/api/window").then(({ getCurrentWindow }) => getCurrentWindow().close());
|
||||
}
|
||||
|
||||
export function MacWindowButtons() {
|
||||
const { fullscreen, active } = useFullscreenWindow();
|
||||
if (!fullscreen) return null;
|
||||
return (
|
||||
<div
|
||||
className={clsx(styles.macButtons, !active && styles.macButtonsInactive)}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className={clsx(styles.macButton, styles.macClose)}
|
||||
aria-label={t("window.caption.close")}
|
||||
onClick={closeWindow}
|
||||
>
|
||||
<Icon name="mac-window-close" size={8} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className={clsx(styles.macButton, styles.macMinimize)}
|
||||
aria-label={t("window.caption.minimize")}
|
||||
disabled
|
||||
>
|
||||
<Icon name="mac-window-minimize" size={8} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className={clsx(styles.macButton, styles.macZoom)}
|
||||
aria-label={t("window.caption.exitFullScreen")}
|
||||
onClick={() => void commands.windowToggleFullscreen()}
|
||||
>
|
||||
<Icon name="mac-window-exit-full-screen" size={8} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -195,3 +195,52 @@
|
||||
background: var(--caption-close-pressed);
|
||||
color: var(--fg-caption-close-hover);
|
||||
}
|
||||
|
||||
/* macOS window buttons drawn in the traffic-light slot while the window fills the screen. */
|
||||
.macButtons {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: var(--h-titlebar);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-left: 12px;
|
||||
zoom: calc(1 / var(--titlebar-zoom, 1));
|
||||
z-index: 1;
|
||||
}
|
||||
.macButton {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--mac-window-glyph);
|
||||
box-shadow: inset 0 0 0 0.5px var(--mac-window-edge);
|
||||
}
|
||||
.macButton > * {
|
||||
opacity: 0;
|
||||
}
|
||||
.macButtons:hover .macButton:not(:disabled) > * {
|
||||
opacity: 1;
|
||||
}
|
||||
.macClose {
|
||||
background: var(--mac-window-close);
|
||||
}
|
||||
.macMinimize {
|
||||
background: var(--mac-window-minimize);
|
||||
}
|
||||
.macZoom {
|
||||
background: var(--mac-window-zoom);
|
||||
}
|
||||
.macButton:active:not(:disabled) {
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
/* Disabled in full screen, and every button of an inactive window, are grey as AppKit draws them. */
|
||||
.macButton:disabled,
|
||||
.macButtonsInactive:not(:hover) .macButton {
|
||||
background: var(--mac-window-inactive);
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
widgetTitle,
|
||||
} from "./mainToolbar";
|
||||
import { WindowControls } from "./WindowControls";
|
||||
import { MacWindowButtons } from "./MacWindowButtons";
|
||||
import { usePlatform } from "@/platform/platformInfo";
|
||||
import { projectInitials } from "./projectColor";
|
||||
import { keymapItems, themeItems, themePreview, type ThemePreview, VIEW_MODE_ITEMS } from "./quickSwitch";
|
||||
@@ -301,6 +302,7 @@ export function TitleBar({
|
||||
if (bare)
|
||||
return (
|
||||
<header ref={setBar} className={className} {...windowDragRegion} data-titlebar="bare">
|
||||
{overlay && <MacWindowButtons />}
|
||||
{frameless && (
|
||||
<>
|
||||
<MainMenu />
|
||||
@@ -323,6 +325,7 @@ export function TitleBar({
|
||||
showContextMenu(e, menu);
|
||||
}}
|
||||
>
|
||||
{overlay && <MacWindowButtons />}
|
||||
{frameless && !minimal && <MainMenu onExpandedChange={setMenuExpanded} />}
|
||||
{title && (
|
||||
<span className={styles.windowTitle} {...windowDragRegion}>
|
||||
|
||||
Reference in new issue
Заблокувати користувача