惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
GbyAI
GbyAI
博客园 - Franky
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
人人都是产品经理
人人都是产品经理
Microsoft Azure Blog
Microsoft Azure Blog
The Register - Security
The Register - Security
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
博客园 - 【当耐特】
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Project Zero
Project Zero
量子位
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
美团技术团队
Attack and Defense Labs
Attack and Defense Labs
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Blog of Author Tim Ferriss
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
罗磊的独立博客
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
L
LINUX DO - 最新话题
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
博客园 - 聂微东
A
About on SuperTechFans
PCI Perspectives
PCI Perspectives
D
Docker

文章 - 硬盘在歌唱 on 硬盘在歌唱

Open Prompt:AI 时代的 PR 协作新范式 记一例浮点数精度问题 AI 辅助编程时代,哪些编程语言会更流行? 从认知心理学看代码可读性 父子对谈30则 都2024了,你还没随身带录音笔吗? 写段子的窍门 给TiDB(MySQL)写一个代理网关 论怎么与基层干部打成一片 怎么做一个匿名论坛 Go语言泛型初体验 双中心主从模式 TrueTime和原子钟 价值6万元的TiDB Hackathon创意 价值10万元的TiDB Hackathon创意 TiDB1024谜题解题报告 Paxos从入门到学会Raft 一个小故事,关于科幻,关于老师 beancount 复式记账实践
适合程序员的桌面窗口管理方案
2022-03-15 · via 文章 - 硬盘在歌唱 on 硬盘在歌唱

介绍下我在办公室使用的桌面窗口管理方案。

先说下硬件:我的工作电脑是一台 13 英寸的 Macbook Pro,外接了一个 27 英寸的显示器,使用了一个电脑支架把笔记本架起来了,这样两个显示器差不多是并排的样子。

然后看下我的窗口布局规划,可能会比较特殊一点,不过是经过精心考虑的。

桌面布局示意

右边的大显示器我按 1:2 分成两列,左边这一列是最大的显示空间,我把它当作“主空间”来使用,一般我在编码状态下会把编辑器放在这个位置,非编码状态下这里通常就是浏览器了。因为本来两个显示器的大小是不一样的,这样进行划分,主空间两侧的空间反而是比较均衡的状态了。显示器和电脑屏幕在桌子上的摆放也是非对称的,当我坐下时,正对着的是这个“主空间”的正中央,这样也避免一个常见问题:两个一样大的显示器对称排布时,正对着的位置恰好是两个显示器中间的缝,于是工作中几乎时刻是扭着头的,时间一长脖子就受不了了。

左边笔记本的屏幕没有做切分,这块空间一般在编码的时候放浏览器看文档资料,或者放个 Terminal 调试,也可以是另一份代码,使用完整的屏幕保证它总是够用的,不至于不得不把窗口拉大然后频繁切换窗口。

大显示器右边的 1/3 被一分为二,这两块空间主要用来放IM软件,包括飞书、Telegram、微信、QQ、Twitter桌面版……IM软件也平铺出来也是为了减少切换窗口,我只需要在干正事的时候时不时瞟一眼就行了,有需要关注的消息时再去处理。必要的时候这个小格也可以临时放一下 Terminal 之类的小窗口。

再说窗口管理软件方面,可能我的搞法比较变态,我也没找到合适的软件,最后使用的方案是 HammerSpoon 一点脚本,HammerSpoon 大体上就是 Mac 版的 AHK,功能是弱了很多,不过在窗口管理这一块还是完全够用的。我的脚本很简单,使用 4 个快捷键,分别把窗口移动到 4 个格子:

 1hs.hotkey.bind("cmd", "1", function()
 2    local sf = hs.screen.primaryScreen():frame()
 3    hs.window.focusedWindow():setFrame(hs.geometry.new(sf.x, sf.y, sf.w*2/3, sf.h))
 4end)
 5
 6hs.hotkey.bind("cmd", "2", function()
 7    hs.window.focusedWindow():setFrame(hs.screen.allScreens()[2]:frame())
 8end)
 9
10hs.hotkey.bind("cmd", "3", function()
11    local sf = hs.screen.primaryScreen():frame()
12    hs.window.focusedWindow():setFrame(hs.geometry.new(sf.x+sf.w*2/3, sf.y, sf.w/3, sf.h/2))
13end)
14
15hs.hotkey.bind("cmd", "4", function()
16    local sf = hs.screen.primaryScreen():frame()
17    hs.window.focusedWindow():setFrame(hs.geometry.new(sf.x+sf.w*2/3, sf.y+sf.h/2, sf.w/3, sf.h/2))
18end)

最后还有一个问题,就是我平时需要启动的 IM 太多了,虽然大部分消息都是不需要实时处理的,但是为了不错过重要消息,不得不隔一段时间手动检查一遍。解决这个问题我还是用 HammerSpoon 脚本,我会把各种不需要实时关心的IM窗口全扔到4号格子里,然后用脚本开个定时器,隔一段时间就把这一坨里在最下面的窗口给捞到最前面。3号窗口是固定不切换的,预留给比较重要的IM窗口,比如飞书。

这个切换窗口的 HammerSpoon 脚本也分享一下。Hammerspoon的lua引擎似乎有点问题,定时器跑一段时间就跑没了,所以干脆直接在每次触发后把脚本重载一下。

 1local myTimer = hs.timer.new(120, function()
 2    local sf = hs.screen.primaryScreen():frame()
 3    local windows = hs.window.orderedWindows()
 4    local bottom_win = nil
 5    for i, win in ipairs(windows) do
 6        local fm = win:frame()
 7        if math.abs(fm.x-(sf.x+sf.w*2/3))<1 and math.abs(fm.y-(sf.y+sf.h/2))<1 then
 8            if win:id() == hs.window.focusedWindow():id() then
 9                break
10            end
11            bottom_win = win
12        end
13    end
14    if bottom_win ~= nil then bottom_win:raise() end
15    hs.reload()
16end)
17myTimer:start()