├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── .vscodeignore
├── CHANGELOG.md
├── README.md
├── extension.js
├── jsconfig.json
├── package.json
├── resources
├── before-after.png
├── before-after.psd
├── dont-show-again.png
├── logo.png
└── preview.png
└── workbench.main.css
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": false,
4 | "commonjs": true,
5 | "es6": true,
6 | "node": true
7 | },
8 | "parserOptions": {
9 | "sourceType": "module"
10 | },
11 | "rules": {
12 | "no-const-assign": "warn",
13 | "no-this-before-super": "warn",
14 | "no-undef": "warn",
15 | "no-unreachable": "warn",
16 | "no-unused-vars": "warn",
17 | "constructor-super": "warn",
18 | "valid-typeof": "warn"
19 | }
20 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behavior to automatically normalize line endings.
2 | * text=auto
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode-test/
3 | *.vsix
4 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "lehni.vscode-fix-checksums",
6 | "be5invis.vscode-custom-css"
7 | ]
8 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that launches the extension inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "runtimeExecutable": "${execPath}",
13 | "args": [
14 | "--extensionDevelopmentPath=${workspaceFolder}"
15 | ]
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "typescript.surveys.enabled": false
4 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .gitignore
3 | jsconfig.json
4 | .eslintrc.json
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## Version 1.10.5
4 |
5 | - Update instructions for [Custom UI
6 | Style](https://marketplace.visualstudio.com/items?itemName=subframe7536.custom-ui-style)
7 | extension
8 |
9 |
10 | ## Version 1.10.4
11 |
12 | - Update instructions for [Apc Customize
13 | UI++](https://marketplace.visualstudio.com/items?itemName=drcika.apc-extension)
14 | extension
15 |
16 | ## Version 1.10.3
17 |
18 | - Add instructions for replacement with [Apc Customize
19 | UI++](https://marketplace.visualstudio.com/items?itemName=drcika.apc-extension)
20 | extension
21 |
22 | ## Version 1.10.2
23 |
24 | - Remove stylesheet tweak again, now that Customize UI integrates it
25 |
26 | ## Version 1.10.1
27 |
28 | - Improve instructions for replacement with [Customize
29 | UI](https://marketplace.visualstudio.com/items?itemName=iocave.customize-ui)
30 | extension
31 |
32 | ## Version 1.10.0
33 |
34 | - Deprecate extension in favor of [Customize
35 | UI](https://marketplace.visualstudio.com/items?itemName=iocave.customize-ui)
36 |
37 | ## Version 1.9.1
38 |
39 | - Make new patch adjustments actually for VSCode v1.33.0, not just v1.34.0 🤦
40 |
41 | ## Version 1.9.0
42 |
43 | - Adjust patches for VSCode v1.33.0
44 |
45 | ## Version 1.8.1
46 |
47 | - Adjust patch for latest VSCode Insiders v1.32.0
48 |
49 | ## Version 1.8.0
50 |
51 | - Fix bug that causes an empty application window in VSCode v1.31.0
52 |
53 | ## Version 1.7.1
54 |
55 | - Adjust patch for latest VSCode Insiders v1.30.0
56 |
57 | ## Version 1.7.0
58 |
59 | - Fix random drag failures on tabs
60 | - Adjust patch for latest VSCode Insiders v1.30.0
61 |
62 | ## Version 1.6.4
63 |
64 | - Adjust patch for latest VSCode Insiders v1.29.0
65 |
66 | ## Version 1.6.3
67 |
68 | - Improve breadcrumb styling to not affect tabs scrolling
69 |
70 | ## Version 1.6.2
71 |
72 | - Adjust patch for latest VSCode Insiders v1.29.0
73 |
74 | ## Version 1.6.1
75 |
76 | - Improve positioning of breadcrumbs under tabs (#18)
77 |
78 | ## Version 1.6.0
79 |
80 | - Adjust patch for latest VSCode Insiders v1.28.0
81 |
82 | ## Version 1.5.2
83 |
84 | - Disable file dragging on draggable tabs containers
85 |
86 | ## Version 1.5.1
87 |
88 | - Don't activate extension when VSCode is running as an Extension Development
89 | Host
90 |
91 | ## Version 1.5.0
92 |
93 | - Improve handling of draggable tab bars
94 |
95 | ## Version 1.4.1
96 |
97 | - Fix fullscreen view when side-bar is displayed right
98 |
99 | ## Version 1.4.0
100 |
101 | - Correctly handle layout when no side-bar, activity-bar, or tab-bar is
102 | displayed
103 |
104 | ## Version 1.3.3
105 |
106 | - Improve README
107 | - Add recommendations
108 |
109 | ## Version 1.3.2
110 |
111 | - Include link to lehni.vscode-fix-checksums extension
112 |
113 | ## Version 1.3.1
114 |
115 | - Do not move first tab in additional split views
116 |
117 | ## Version 1.3.0
118 |
119 | - Add support for side-bar on the right
120 |
121 | ## Version 1.2.0
122 |
123 | - Support Electron 2.0 in VSCode 1.26.0-insider and newer
124 |
125 | ## Version 1.1.0
126 |
127 | - Add proper support for zoom levels
128 |
129 | ## Version 1.0.11
130 |
131 | - Add support for latest VSCode Insiders version by removing reliance on
132 | `.titlebar-style-custom` CSS class.
133 |
134 | ## Version 1.0.10
135 |
136 | - Avoid invalid restores over newer versions of VSCode by using VSCode version
137 | for versioned backups.
138 |
139 | ## Version 1.0.9
140 |
141 | - Improve robustness of enable / disable commands.
142 |
143 | ## Version 1.0.8
144 |
145 | - Add support for fullscreen mode.
146 | - Only apply styling overrides if `"window.titleBarStyle"` setting is set to
147 | `"custom"`.
148 | - Read activity-bar width from CSS variable, so it can optionally be changed / overridden
149 | with the [Custom CSS and JS Loader](https://marketplace.visualstudio.com/items?itemName=be5invis.vscode-custom-css)
150 | extension (e.g. when using the `"window.zoomLevel"` setting).
151 |
152 | ## Version 1.0.7
153 |
154 | - Move badges in activity-bar close to original location in relation to icon.
155 | - Fix dragging on area around traffic lights on activity-bar.
156 |
157 | ## Version 1.0.6
158 |
159 | - Fix dragging on area around traffic lights when activity-bar is hidden.
160 |
161 | ## Version 1.0.5
162 |
163 | - Support dragging tab-bar in recent versions of VSCode.
164 |
165 | ## Version 1.0.4
166 |
167 | - Add disclaimer and notes about updating extension and VSCode to README.
168 |
169 | ## Version 1.0.3
170 |
171 | - Improve restoration of patched files when disabling titlebar-less mode.
172 | - Correct title-bar styling for any combination of invisible activity-bar /
173 | side-bar (#1).
174 | - Add paragraph about required user settings to README (#2).
175 |
176 | ## Version 1.0.2
177 |
178 | - Fix display name.
179 |
180 | ## Version 1.0.1
181 |
182 | - Documentation tweaks.
183 |
184 | ## Version 1.0.0
185 |
186 | - Initial release.
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Titlebar-less VSCode for macOS
3 |
4 |
5 |
6 |
7 |
8 | Originally extension, and now a recommended combination of third party
9 | extensions and settings, designed to hide the titlebar on VSCode for macOS, and
10 | inline the traffic lights (= window controls).
11 |
12 | ## Deprecation Notice
13 |
14 | This extension does not work on VSCode 1.40 or newer, and has therefore been
15 | deprecated.
16 |
17 | ## Recommended Replacement
18 |
19 | ### Custom UI Style
20 |
21 | As of VSCode 1.94, you may use [Custom UI Style](https://marketplace.visualstudio.com/items?itemName=subframe7536.custom-ui-style)
22 | instead, which you can configure to achieve the same UI style by adding these
23 | settings in your `settings.json` file, see [Issue #16](https://github.com/subframe7536/vscode-custom-ui-style/issues/16):
24 |
25 | ```jsonc
26 | {
27 | "window.titleBarStyle": "native",
28 | "window.customTitleBarVisibility": "never",
29 | "custom-ui-style.electron": {
30 | "titleBarStyle": "hiddenInset"
31 | },
32 | "custom-ui-style.stylesheet": {
33 | ".monaco-workbench": {
34 | "--activitybar-width": "77px",
35 | "--titlebar-height": "37px",
36 |
37 | // Titlebar
38 | ".part.sidebar.left .composite.title": {
39 | "&, .title-actions, .global-actions, .monaco-toolbar": {
40 | "height": "var(--titlebar-height)"
41 | },
42 |
43 | ".title-label": {
44 | "line-height": "var(--titlebar-height)"
45 | }
46 | },
47 |
48 | // Tabs
49 | ".title.tabs": {
50 | "--editor-group-tab-height": "var(--titlebar-height) !important",
51 | },
52 |
53 | // Wide activity bar
54 | ".split-view-view:has(> .part.activitybar.left)": {
55 | "&, .part.activitybar.left, .content": {
56 | "min-width": "var(--activitybar-width)",
57 | },
58 |
59 | // Make the split-view after the wide activity bar smaller.
60 | // Also handle the situation where the sidebar is hidden,
61 | // in which case the editor itself needs to shrink / auto-size.
62 | "& + .split-view-view.visible, & + .split-view-view:not(.visible) + .split-view-view.visible": {
63 | "--offset": "calc(var(--activitybar-width) - 48px)",
64 | "margin-left": "var(--offset)",
65 |
66 | "> *:first-child": {
67 | "width": "auto",
68 | "margin-right": "var(--offset)",
69 |
70 | // Auto-size the editor when the sidebar is hidden.
71 | ".content": {
72 | "&, .split-view-view": {
73 | "&, .monaco-editor": {
74 | "&, .overflow-guard, .overlayWidgets" : {
75 | "&, .monaco-scrollable-element, .sticky-widget": {
76 | "width": "unset !important",
77 | "left": "0",
78 | "right": "0"
79 | },
80 |
81 | ".sticky-widget": {
82 | "right": "14px !important"
83 | }
84 | }
85 | }
86 | }
87 | }
88 | },
89 | }
90 | },
91 |
92 | // Search-Widget
93 | ".search-view .search-widget": {
94 | ".replace-container": {
95 | "width": "calc(100% - 18px)",
96 |
97 | ".replace-input": {
98 | "&, .monaco-findInput": {
99 | "width": "100% !important"
100 | }
101 | }
102 | }
103 | },
104 |
105 | ".monaco-sash.vertical.minimum": {
106 | // TODO: Improve collapsing of the sidebar.
107 | "left": "calc(var(--activitybar-width) - var(--vscode-sash-size) / 2) !important"
108 | },
109 |
110 | ".part.activitybar.left": {
111 | ".monaco-action-bar": {
112 | ".action-label": {
113 | "width": "var(--activitybar-width)"
114 | }
115 | }
116 | },
117 |
118 | "&:not(.fullscreen)": {
119 | // Make room for traffic lights.
120 | ".part.activitybar.left > .content": {
121 | "padding-top": "var(--titlebar-height)"
122 | },
123 |
124 | // Move editor title when side-bar is hidden, when side-bar is on the
125 | // right or when activity-bar is hidden and side-bar is not on the right
126 | "&:has(.sidebar.right)": {
127 | ".monaco-split-view2.horizontal .split-view-view:not(.visible) + .split-view-view.visible .editor .title .tabs-and-actions-container": {
128 | "padding-left": "var(--activitybar-width)"
129 | },
130 |
131 | ".auxiliarybar.left .composite.title": {
132 | "padding-left": "var(--activitybar-width)"
133 | }
134 | },
135 |
136 | // Allow dragging on the activity-bar, status-bar, tabs-container, side-bar title...
137 | ".activitybar, .statusbar, .tabs-container, .sidebar .composite.title": {
138 | "-webkit-app-region": "drag",
139 |
140 | // ...but still allow to click actions and items without dragging.
141 | ".content .monaco-action-bar, .statusbar-item, .tab, .title .title-actions .action-label": {
142 | "-webkit-app-region": "no-drag"
143 | }
144 | }
145 | },
146 |
147 | ".statusbar": {
148 | // Don't indent the statusbar items.
149 | "> .items-container > .statusbar-item.left.first-visible-item": {
150 | "padding-left": "0"
151 | },
152 |
153 | // Show the host button again, and make it as wide as the .activitybar.
154 | "#status\\.host": {
155 | "&": {
156 | "display": "block !important",
157 | "width": "calc(var(--activitybar-width) - 1px)"
158 | },
159 | ".codicon": {
160 | "margin": "0 auto"
161 | }
162 | }
163 | }
164 | },
165 |
166 | // Make line numbers a bit smaller.
167 | ".editor .margin-view-overlays .line-numbers": {
168 | "font-size": "85%"
169 | },
170 |
171 | // Show search inputs and results in monospaced font.
172 | ".search-widget textarea, .find-widget textarea, .search-view .results .match": {
173 | "font-family": "var(--cus-monospace-font) !important"
174 | }
175 | }
176 | }
177 | ```
178 |
179 | ## Replacement History
180 |
181 | ### Apc Customize UI++
182 |
183 | Before `Custom UI Style`, [Apc Customize UI++](https://marketplace.visualstudio.com/items?itemName=drcika.apc-extension)
184 | was recommended as a replacement, which you could configure to achieve the same
185 | UI style by adding these settings in your `settings.json` file, see
186 | [Issue #52](https://github.com/drcika/apc-extension/issues/52):
187 |
188 | ```jsonc
189 | {
190 | "window.titleBarStyle": "native",
191 | "window.customTitleBarVisibility": "never",
192 | "window.density.editorTabHeight": "compact",
193 | "apc.electron": {
194 | "titleBarStyle": "hiddenInset",
195 | },
196 | "apc.header": {
197 | "height": 37
198 | },
199 | "apc.sidebar.titlebar": {
200 | "height": 37
201 | },
202 | "apc.activityBar": {
203 | "size": 77,
204 | "itemSize": 48,
205 | "itemMargin": 0
206 | },
207 | "apc.stylesheet": {
208 | // Don't indent the sidebar title.
209 | ".custom-sidebar-titlebar .sidebar .composite.title": "padding-left: 0;",
210 | // Don't indent the statusbar items.
211 | ".monaco-workbench .part.statusbar>.items-container>.statusbar-item.left.first-visible-item": "padding-left: 0;",
212 | // Show the host button, and make it as wide as the .activitybar.
213 | ".statusbar #status\\.host": "display: block !important; width: calc(var(--activity-bar-action-size) - 1px); background: #555 !important;",
214 | ".statusbar #status\\.host .codicon": "margin: 0 auto;",
215 | }
216 | }
217 | ```
218 |
219 | ### Customize UI
220 |
221 | Before `Apc Customize UI++`, [Customize UI](https://marketplace.visualstudio.com/items?itemName=iocave.customize-ui)
222 | was recommended as a replacement, which you could configure to achieve the same
223 | UI style by adding these settings in your `settings.json` file:
224 |
225 | ```jsonc
226 | {
227 | "window.titleBarStyle": "native",
228 | "customizeUI.titleBar": "inline",
229 | "customizeUI.activityBar": "wide",
230 | "customizeUI.stylesheet": {
231 | // Center action items in .activitybar.
232 | ".monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label": "margin: 0 auto;",
233 | // Show the host button, and make it as wide as the .activitybar.
234 | ".statusbar #status\\.host": "width: 76px; background: #555 !important;",
235 | ".statusbar #status\\.host .codicon": "margin: 0 auto;"
236 | }
237 | }
238 | ```
239 |
240 | ## Deprecated Installation Instructions
241 |
242 | Follow the instructions in the
243 | [Marketplace](https://marketplace.visualstudio.com/items?itemName=lehni.vscode-titlebar-less-macos),
244 | or run the following in the command palette:
245 |
246 | ```shell
247 | ext install lehni.vscode-titlebar-less-macos
248 | ```
249 |
250 | Alternatively, you can run this command in the command line:
251 |
252 | ```sh
253 | code --install-extension lehni.vscode-titlebar-less-macos
254 | ```
255 |
256 | ## Usage
257 |
258 | The extension adds 2 new commands to the command palette:
259 |
260 | ```js
261 | Titlebar-Less: Enable // Enable titlebar-less mode on macOS (patches core files)
262 | Titlebar-Less: Disable // Disable titlebar-less mode on macOS (restores core files)
263 | ```
264 |
265 | After executing either of these commands, you need to fully restart VSCode in
266 | order to see the extension's effect. Simply reloading the window is not enough.
267 |
268 | If VSCode complains about it being corrupted after the restart, you have two
269 | options:
270 |
271 | 1. Install the
272 | [vscode-fix-checksums](https://marketplace.visualstudio.com/items?itemName=lehni.vscode-fix-checksums)
273 | extension and adjust the internal checksums to prevent this error from being
274 | displayed. This will also solve the display of `[Unsupported]` in titles and
275 | menus.
276 |
277 | 2. Choose `Don't Show Again`:
278 |
279 |
280 |
281 |
282 | See [Disclaimer / A Word of Caution](#disclaimer--a-word-of-caution) for
283 | details.
284 |
285 | See [Required User Settings](#required-user-settings), if the title bar doesn't look right after the restart.
286 |
287 | ## Required User Settings
288 |
289 | This extension only works with the following User Settings. In order to change
290 | them, choose `Code` > `Preferences` > `Settings` in the menu, and add / change
291 | these lines:
292 |
293 | ```json
294 | "window.titleBarStyle": "custom",
295 | "window.nativeTabs": false,
296 | ```
297 |
298 | ## Applying the Patches as Root
299 |
300 | Due to security restrictions on some systems, VSCode may need to run as root
301 | in order to be able to apply the patches. To do so, open the `Terminal.app` and
302 | run:
303 |
304 | ```sh
305 | sudo "/Applications/Visual Studio Code.app/Contents/MacOS/Electron"
306 | ```
307 |
308 | Or this if you're using VSCode Insiders:
309 |
310 | ```sh
311 | sudo "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron"
312 | ```
313 |
314 | Once you ave applied the patches by executing `Titlebar-Less: Enable` as root,
315 | quit VSCode and start it normally without root privileges again.
316 |
317 | ## Disclaimer / A Word of Caution
318 |
319 | This extension modifies files that are part of the core of VSCode, so use it at
320 | your own risk.
321 |
322 | This extension creates backup files before modifying the core files, and these
323 | can be restored at any time using the `Titlebar-Less: Disable` command.
324 |
325 | If anything goes wrong, you can always reinstall VSCode from
326 | [code.visualstudio.com](https://code.visualstudio.com/download) without loosing
327 | any settings or installed extensions.
328 |
329 | ## Updating VSCode / Titlebar-Less
330 |
331 | When either VSCode or this extension is updated to a newer version, you can
332 | reapply the extension's modifications of the core files simply by running this
333 | command again, followed by a restart of the full application:
334 |
335 | ```js
336 | Titlebar-Less: Enable
337 | ```
338 |
339 | ## Before / After
340 |
341 |
342 |
343 |
344 |
345 | ## Inspiration
346 |
347 | https://github.com/Microsoft/vscode/issues/12377
348 |
349 | In particular, [@orta](https://github.com/orta)'s work on a similar fork.
350 |
351 | ## License
352 |
353 | MIT © Jürg Lehni, 2018
354 |
--------------------------------------------------------------------------------
/extension.js:
--------------------------------------------------------------------------------
1 | const vscode = require('vscode')
2 | const fs = require('fs')
3 | const path = require('path')
4 |
5 | const appDir = path.dirname(require.main.filename)
6 | const fsOptions = { encoding: 'utf8' }
7 |
8 | const version = parseFloat(vscode.version)
9 |
10 | const { showTrafficLights } = vscode.workspace.getConfiguration('titlebarLess')
11 |
12 | const patches = {
13 | 'vs/code/electron-main/main.js': [
14 | // Override the Electron BrowserWindow options:
15 | // https://electronjs.org/docs/api/frameless-window
16 | [
17 | '.titleBarStyle="hidden",',
18 | showTrafficLights
19 | ? `.titleBarStyle="${version < 1.26 ? 'hidden-inset' : 'hiddenInset'}",`
20 | : '.frame=false,'
21 | ]
22 | ],
23 | 'vs/workbench/workbench.main.js': [
24 | // Never show the TITLEBAR_PART when "window.titleBarStyle" is "custom"
25 | [
26 | new RegExp([
27 | // TODO: Remove support for older versions once they are in a distant past
28 | // 1.33.0 <= v
29 | 'return"native"!==\\w\\.getTitleBarStyle\\(this\\.configurationService,this\\.environmentService\\)(&&\\(!this\\.state\\.fullscreen)',
30 | // 1.30.0 <= v < 1.33.0
31 | 'return!!this\\.useCustomTitleBarStyle\\(\\)(&&\\(!\\w\\.isFullscreen\\(\\))',
32 | // v < 1.30.0
33 | 'return"custom"===this\\.getCustomTitleBarStyle\\(\\)(&&\\(!\\w\\.isFullscreen\\(\\))'
34 | ].join('|')),
35 | 'return false$1$2$3'
36 | ],
37 | // Handle setting of traffic-lights size and .titlebar-less class on .monaco-workbench
38 | [
39 | // Patch the full layout function in layout.ts, and parse it to retrieve
40 | // its parameter and the object on which to call `getZoomFactor()`:
41 | // Use `[^}]*` at the beginning and end of the body, to match any code
42 | // that doesn't involve any changing nesting. This is required to loosely
43 | // match smaller changes in different version of VSCode, as well as random
44 | // line-breaks inserted by the minifier.
45 | // Also, `this\.contextViewService\.layout\(\))` can't be matched anymore,
46 | // since that's now called further down in workbench.main.js too.
47 | // TODO: Replace `(\.layout=function\(\w+\)\{|layout\(\w+\)\{)` with `(layout\(\w+\)\{)` once VSCode v1.31.0 is in a distant past
48 | /(\.layout=function\(\w+\)\{|layout\(\w+\)\{)([^}]*this\.workbenchSize=[\s\S]*(\w+)\.getZoomFactor\(\)[\s\S]*this\.parts\.activitybar\.layout\([^)]*\)[^}]*)}/m,
49 | (all, func, body, browser) => {
50 | return `${func}
51 | var layoutService = (
52 | // TODO: Remove support for older versions once they are in a distant past
53 | // 1.33.0 <= v
54 | this.layoutService ||
55 | // v < 1.33.0
56 | this.partService
57 | )
58 | var editorGroupService = layoutService && (
59 | // TODO: Remove support for older versions once they are in a distant past
60 | // 1.33.0 <= v
61 | this.editorGroupService ||
62 | // 1.31.0 <= v < 1.33.0
63 | layoutService.editorGroupService ||
64 | // v < 1.31.0
65 | layoutService.workbenchLayout && layoutService.workbenchLayout.editorGroupService
66 | );
67 | var configurationService = layoutService && layoutService.configurationService;
68 | var environmentService = layoutService && layoutService.environmentService;
69 | if (!layoutService) {
70 | console.error('Unable to retrieve layoutService');
71 | } else if (!editorGroupService) {
72 | console.error('Unable to retrieve editorGroupService');
73 | } else if (!configurationService) {
74 | console.error('Unable to retrieve configurationService');
75 | } else if (!environmentService) {
76 | console.error('Unable to retrieve environmentService');
77 | } else if (
78 | // Only activate titlebar-less mode if "window.titleBarStyle" is set to "custom",
79 | // and VSCode isn't running as an Extension Development Host:
80 | !environmentService.isExtensionDevelopment &&
81 | "custom" === configurationService.getValue().window.titleBarStyle
82 | ) {
83 | // Add .titlebar-less to .monaco-workbench, see workbench.main.css
84 | this.workbenchContainer.classList.add("titlebar-less");
85 | ${showTrafficLights
86 | ? `// Set traffic-lights size, taking zoom-factor into account:
87 | var factor = ${browser}.getZoomFactor();
88 | var width = 78 / factor;
89 | var height = 35 / factor;
90 | this.partLayoutInfo.activitybar.width = width;`
91 |
92 | : `var width = 0;
93 | var height = 0;`
94 | }
95 | var style = document.documentElement.style;
96 | style.setProperty("--traffic-lights-width", width + "px");
97 | style.setProperty("--traffic-lights-height", height + "px");
98 | // Install handlers on editorGroupService to determine the draggable titles with tabs,
99 | // by adding the .titlebar-less-draggable CSS class only to the titles at the top of the window:
100 | if (!this.titlebarLessHandlers) {
101 | var handleDraggableTitles = () => process.nextTick(() => {
102 | for (const title of Array.from(global.document.querySelectorAll('.editor .title'))) {
103 | title.classList.toggle('titlebar-less-draggable', !title.getBoundingClientRect().top);
104 | }
105 | });
106 | var handlers = this.titlebarLessHandlers = [];
107 | editorGroupService.onDidLayout(handleDraggableTitles ,null, handlers);
108 | editorGroupService.onDidAddGroup(handleDraggableTitles ,null, handlers);
109 | editorGroupService.onDidMoveGroup(handleDraggableTitles ,null, handlers);
110 | editorGroupService.onDidRemoveGroup(handleDraggableTitles ,null, handlers);
111 | }
112 | }
113 | ${body}
114 | }`
115 | }
116 | ]
117 | ],
118 | 'vs/workbench/workbench.main.css': [
119 | // Add our CSS modifications to the end of the main file
120 | [
121 | /$/g, // Append to the end of the file
122 | readFile('workbench.main.css')
123 | ]
124 | ]
125 | }
126 |
127 | const messages = {
128 | success: verb => `Titlebar-less mode ${verb}. Please restart VSCode to see effect.`,
129 | fail: (verb, result) => `Unable to ${verb} all patches (${result.applied}/${result.total})`
130 | }
131 |
132 | exports.activate = function activate(context) {
133 | context.subscriptions.push(
134 | vscode.commands.registerCommand('titlebarLess.enable', enable),
135 | vscode.commands.registerCommand('titlebarLess.disable', disable)
136 | )
137 | cleanupOrigFiles()
138 | }
139 |
140 | function enable() {
141 | // Always try to disable before enabling, but ignore if nothing was there to
142 | // disable (= it was already disabled before).
143 | let result = applyPatches(false)
144 | if (result.success || result.applied === 0) {
145 | result = applyPatches(true)
146 | vscode.window.showInformationMessage(result.success
147 | ? messages.success('enabled')
148 | : messages.fail('apply', result)
149 | )
150 | } else {
151 | vscode.window.showInformationMessage(messages.fail('remove', result))
152 | }
153 | }
154 |
155 | function disable() {
156 | const result = applyPatches(false)
157 | // Ignore if nothing was there to disable (= it was already disabled before).
158 | vscode.window.showInformationMessage(result.success || result.applied === 0
159 | ? messages.success('disabled')
160 | : messages.fail('remove', result)
161 | )
162 | }
163 |
164 | function applyPatches(enable) {
165 | let applied = 0
166 | let total = 0
167 | for (const [filePath, filePatches] of Object.entries(patches)) {
168 | const file = getFilePath(filePath)
169 | const orig = `${file}.orig.${vscode.version}`
170 | try {
171 | const amount = filePatches.length
172 | total += amount
173 | if (enable) {
174 | let content = fs.readFileSync(file, fsOptions)
175 | let found = 0
176 | for (const [find, replace] of filePatches) {
177 | const patched = content.replace(find, replace)
178 | if (patched !== content) {
179 | content = patched
180 | found++
181 | } else {
182 | console.error(`Unable to apply patch: ${find}`)
183 | }
184 | }
185 | if (found === amount) {
186 | fs.renameSync(file, orig)
187 | fs.writeFileSync(file, content, fsOptions)
188 | applied += amount
189 | }
190 | } else {
191 | if (fs.existsSync(orig)) {
192 | fs.unlinkSync(file)
193 | fs.renameSync(orig, file)
194 | applied += amount
195 | }
196 | }
197 | } catch (err) {
198 | console.error(err)
199 | }
200 | }
201 | return {
202 | success: applied === total,
203 | applied,
204 | total
205 | }
206 | }
207 |
208 | function cleanupOrigFiles() {
209 | // Remove all old backup files that aren't related to the current version
210 | // of VSCode anymore.
211 | for (const filePath of Object.keys(patches)) {
212 | const dir = path.dirname(getFilePath(filePath))
213 | const oldOrigFiles = fs.readdirSync(dir)
214 | .filter(file => /\.orig\./.test(file))
215 | .filter(file => !file.endsWith(vscode.version))
216 | for (const file of oldOrigFiles) {
217 | fs.unlinkSync(path.join(dir, file))
218 | }
219 | }
220 | }
221 |
222 | function getFilePath(filePath) {
223 | return path.join(appDir, ...filePath.split('/'))
224 | }
225 |
226 | function readFile(filename) {
227 | return fs.readFileSync(path.join(__dirname, filename), fsOptions)
228 | }
229 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "checkJs": false,
6 | "lib": [
7 | "es6"
8 | ]
9 | },
10 | "exclude": [
11 | "node_modules"
12 | ]
13 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-titlebar-less-macos",
3 | "displayName": "Titlebar-Less VSCode for macOS",
4 | "description": "An extension for a titlebar-less VSCode on macOS",
5 | "icon": "resources/logo.png",
6 | "version": "1.10.5",
7 | "license": "MIT",
8 | "main": "./extension",
9 | "publisher": "lehni",
10 | "author": {
11 | "name": "Jürg Lehni",
12 | "email": "juerg@scratchdisk.com"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/lehni/vscode-titlebar-less-macos/issues"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/lehni/vscode-titlebar-less-macos"
20 | },
21 | "engines": {
22 | "vscode": "^1.25.0"
23 | },
24 | "keywords": [
25 | "vscode",
26 | "vsc",
27 | "extension",
28 | "titlebar",
29 | "macos"
30 | ],
31 | "categories": [
32 | "Other"
33 | ],
34 | "activationEvents": [
35 | "onCommand:titlebarLess.enable",
36 | "onCommand:titlebarLess.disable"
37 | ],
38 | "contributes": {
39 | "configuration": {
40 | "title": "Titlebar-Less",
41 | "properties": {
42 | "titlebarLess.showTrafficLights": {
43 | "type": "boolean",
44 | "default": true,
45 | "description": "Toggles the macOS window control buttons. (requires restart)"
46 | }
47 | }
48 | },
49 | "commands": [
50 | {
51 | "command": "titlebarLess.enable",
52 | "title": "Titlebar-Less: Enable"
53 | },
54 | {
55 | "command": "titlebarLess.disable",
56 | "title": "Titlebar-Less: Disable"
57 | }
58 | ]
59 | },
60 | "scripts": {
61 | "postinstall": "node ./node_modules/vscode/bin/install"
62 | },
63 | "devDependencies": {
64 | "@types/node": "^7.0.43",
65 | "@types/mocha": "^2.2.42",
66 | "eslint": "^4.11.0",
67 | "vscode": "^1.1.6"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/resources/before-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lehni/vscode-titlebar-less-macos/84eb3e88219c08afaded32d0e6d30c3b9387f22f/resources/before-after.png
--------------------------------------------------------------------------------
/resources/before-after.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lehni/vscode-titlebar-less-macos/84eb3e88219c08afaded32d0e6d30c3b9387f22f/resources/before-after.psd
--------------------------------------------------------------------------------
/resources/dont-show-again.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lehni/vscode-titlebar-less-macos/84eb3e88219c08afaded32d0e6d30c3b9387f22f/resources/dont-show-again.png
--------------------------------------------------------------------------------
/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lehni/vscode-titlebar-less-macos/84eb3e88219c08afaded32d0e6d30c3b9387f22f/resources/logo.png
--------------------------------------------------------------------------------
/resources/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lehni/vscode-titlebar-less-macos/84eb3e88219c08afaded32d0e6d30c3b9387f22f/resources/preview.png
--------------------------------------------------------------------------------
/workbench.main.css:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Styles added by vscode-titlebar-less-macos extension
4 | * https://marketplace.visualstudio.com/items?itemName=lehni.vscode-titlebar-less-macos
5 | */
6 |
7 | :root {
8 | --traffic-lights-width: 78px;
9 | --traffic-lights-height: 35px;
10 | }
11 |
12 | /**
13 | * Extension requires "window.titleBarStyle" to be set to "custom",
14 | * so use .titlebar-style-custom as a filter for all modifications.
15 | */
16 |
17 | /* Make activity-bar wider to align with traffic lights */
18 | .monaco-workbench.titlebar-less .activitybar,
19 | .monaco-workbench.titlebar-less .activitybar .content {
20 | width: var(--traffic-lights-width);
21 | }
22 |
23 | /* Move activity-bar .content down to not be covered by traffic lights */
24 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar:not(.right) .content .monaco-action-bar.vertical {
25 | margin-top: var(--traffic-lights-height);
26 | }
27 |
28 | /* Move editor title when side-bar is hidden... */
29 | .monaco-workbench.titlebar-less:not(.fullscreen).nosidebar .editor .title,
30 | /* ...or when side-bar is on the right... */
31 | .monaco-workbench.titlebar-less:not(.fullscreen) .sidebar.right + .editor .title,
32 | /* ...also move side-bar title when activity-bar is hidden and side-bar is not on the right... */
33 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar[aria-hidden="true"] + .sidebar:not(.right) > .title {
34 | padding-left: var(--traffic-lights-width);
35 | }
36 | /* ... and for all the selectors above, move nested .tabs-breadcrumbs back by the same amount. */
37 | .monaco-workbench.titlebar-less:not(.fullscreen).nosidebar .editor .title .tabs-breadcrumbs,
38 | .monaco-workbench.titlebar-less:not(.fullscreen) .sidebar.right + .editor .title .tabs-breadcrumbs,
39 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar[aria-hidden="true"] + .sidebar:not(.right) > .title .tabs-breadcrumbs {
40 | margin-left: calc(-1 * var(--traffic-lights-width));
41 | }
42 |
43 | /* ...but when activity-bar is visible and side-bar is hidden... */
44 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar:not([aria-hidden="true"]) + .sidebar:not(.right) + .editor .title,
45 | /* ...or when there's a split-view with multiple tabs, don't move .tabs-container... */
46 | .monaco-workbench.titlebar-less .split-view-container .split-view-view + .split-view-view .title {
47 | padding-left: 0 !important;
48 | }
49 | /* ... and for all the selectors above, clear moving of nested .tabs-breadcrumbs. */
50 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar:not([aria-hidden="true"]) + .sidebar:not(.right) + .editor .title .tabs-breadcrumbs,
51 | .monaco-workbench.titlebar-less .split-view-container .split-view-view + .split-view-view .title .tabs-breadcrumbs {
52 | margin-left: 0 !important;
53 | }
54 |
55 | .monaco-workbench.titlebar-less .activitybar .content .monaco-action-bar .action-label {
56 | width: auto;
57 | background-position: center;
58 | padding: 0;
59 | }
60 |
61 | .monaco-workbench.titlebar-less .activitybar .content .monaco-action-bar .action-item::before {
62 | width: auto;
63 | right: 0;
64 | }
65 |
66 | .monaco-workbench.titlebar-less .activitybar .content .monaco-action-bar .badge {
67 | width: 100%;
68 | }
69 |
70 | .monaco-workbench.titlebar-less .activitybar .content .monaco-action-bar .badge .badge-content {
71 | left: calc(50% + 0.5em); /* Relative to font-size, so it works on all zoom levels */
72 | right: auto;
73 | }
74 |
75 | /* Allow dragging on the activity-bar... */
76 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar {
77 | -webkit-app-region: drag;
78 | }
79 |
80 | /* ...but still allow to click actions without dragging */
81 | .monaco-workbench.titlebar-less:not(.fullscreen) .activitybar .content .monaco-action-bar {
82 | -webkit-app-region: no-drag;
83 | }
84 |
85 | /* Allow dragging on side-bar title... */
86 | .monaco-workbench.titlebar-less:not(.fullscreen) .sidebar .composite.title {
87 | -webkit-app-region: drag;
88 | }
89 | /* ...but still allow to click actions without dragging. */
90 | .monaco-workbench.titlebar-less:not(.fullscreen) .sidebar .title .title-actions .action-label {
91 | -webkit-app-region: no-drag;
92 | }
93 |
94 | /* Allow dragging on titles with tabs at the top of the window... */
95 | .monaco-workbench.titlebar-less:not(.fullscreen) .titlebar-less-draggable.title {
96 | -webkit-app-region: drag;
97 | -webkit-user-drag: none;
98 | }
99 |
100 | /* ...but still allow dragging the tabs themselves to re-order. */
101 | .monaco-workbench.titlebar-less:not(.fullscreen) .titlebar-less-draggable.title .tablist,
102 | .monaco-workbench.titlebar-less:not(.fullscreen) .titlebar-less-draggable.title .tab {
103 | -webkit-app-region: no-drag;
104 | }
105 |
--------------------------------------------------------------------------------