<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>DevMemo – mac</title><link>https://devmemo.gitlab.io/tags/mac/</link><description>Recent content in mac on DevMemo</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 14 Jan 2023 14:55:09 -0800</lastBuildDate><atom:link href="https://devmemo.gitlab.io/tags/mac/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: Efficient Mac Window Management</title><link>https://devmemo.gitlab.io/blog/mac_window_management/</link><pubDate>Sat, 14 Jan 2023 14:55:09 -0800</pubDate><guid>https://devmemo.gitlab.io/blog/mac_window_management/</guid><description>
&lt;p>As a software engineer, you might need to open up multiple windows at the same time when doing development work, e.g., a terminal window, a browser, a IDE window, a chat application, etc. You might also have multiple monitors as well. Window management becomes a neccessary part of your work. Unfortunately, mac doesn&amp;rsquo;t come with a decent solution to this.&lt;/p>
&lt;p>In this article, I&amp;rsquo;ll talk about how you can effectively manage your windows on your mac. I&amp;rsquo;ll cover two topics specifically:&lt;/p>
&lt;ul>
&lt;li>How to switch between windows?&lt;/li>
&lt;li>How to place the target window on the desired position?&lt;/li>
&lt;/ul>
&lt;h2 id="window-switching">Window Switching&lt;/h2>
&lt;p>Switching between windows is probably one of the most common operations you&amp;rsquo;ll need when using any kind of operating system.&lt;/p>
&lt;p>If you&amp;rsquo;ve used a Windows Operating System before, you&amp;rsquo;ll know that it provides a pretty good solution to switch among windows, which is &lt;code>ctrl + tab&lt;/code>. Whenever you press &lt;code>ctrl + tab&lt;/code>, you&amp;rsquo;ll see a window poping up in the middle of your screen, presenting you all the current visible windows. By selecting the target window, you can switch to it pretty easily.&lt;/p>
&lt;p>This feature works really well on Windows, and Linux also provides the same feature. However, for some reason, mac doesn&amp;rsquo;t do that by default. Mac has a &lt;code>cmd + tab&lt;/code> hotkey, and it pops up a similar window. However, that window presents active applications in your system, and those active applications might include ones without a window. In most cases, you won&amp;rsquo;t care about them, but it is annoying. I typically only have a few windows opened when I&amp;rsquo;m working on mac. I&amp;rsquo;d like to see a clean list, instead of a whole bunch of background running applications, which makes windows switching a lot more inefficient.&lt;/p>
&lt;p>Over years, I&amp;rsquo;ve always tried to find softwares that can provide similar feature as Windows and Linux do. I found two of them work really well.&lt;/p>
&lt;h3 id="hyperswitch">HyperSwitch&lt;/h3>
&lt;p>A few years ago, I found this software called &lt;a href="https://bahoom.com/hyperswitch">HyperSwitch&lt;/a>, and it does exactly what I want. It works pretty well, just like Windows and Linux.&lt;/p>
&lt;p>HyperSwitch has been pretty reliable before I switched to use the M1 macbook air from my x86 based macbook pro. On M1, I&amp;rsquo;ve encounter cases where HyperSwitch just failed to find certain windows. I&amp;rsquo;m not sure why that happened. I also noticed that HyperSwitch is not under active maintenance anymore. The last time it was updated was before 2021. Then I started to search for other solutions.&lt;/p>
&lt;h3 id="alttab">AltTab&lt;/h3>
&lt;p>&lt;a href="https://alt-tab-macos.netlify.app/">AltTab&lt;/a> is another software that provides similar feature. It pretty much does the same thing, but it has richer features. AltTab is also opened sourced at &lt;a href="https://github.com/lwouis/alt-tab-macos">github&lt;/a>.&lt;/p>
&lt;p>I started to use AltTab ever since 2021. It works pretty good, and I&amp;rsquo;m still using it now. &lt;strong>&lt;a href="https://alt-tab-macos.netlify.app/">AltTab&lt;/a> is definitely my recommended solution to mac window switching.&lt;/strong>&lt;/p>
&lt;h2 id="window-placement">Window Placement&lt;/h2>
&lt;p>Another big topic of window management is window placement. If you&amp;rsquo;ve used Windows before, you&amp;rsquo;ll noticed it provides a few pretty handy window management hotkeys:&lt;/p>
&lt;ul>
&lt;li>&lt;code>win + left&lt;/code>: Place window on the left part of the screen.&lt;/li>
&lt;li>&lt;code>win + right&lt;/code>: Place window on the right part of the screen.&lt;/li>
&lt;li>&lt;code>win + up&lt;/code>: Maximize the window.&lt;/li>
&lt;li>&lt;code>win + down&lt;/code>: Restore the previous window position if it is currently maximized, otherwise, minimize the window.&lt;/li>
&lt;/ul>
&lt;p>I wish mac had come with these features by default, but it had never came. Then I started to search solutions for that.&lt;/p>
&lt;p>There are tools to do that, e.g., &lt;a href="https://apps.apple.com/app/id441258766">Magnet&lt;/a>, &lt;a href="https://apps.apple.com/app/bettersnaptool/id417375580">BetterSnapTool&lt;/a>, &lt;a href="https://hazeover.com/">HazeOver&lt;/a>, etc. But as a software engineer, I definitely can&amp;rsquo;t accept these solutions, because they not customizable enough.&lt;/p>
&lt;p>And then I found &lt;a href="https://www.hammerspoon.org/">hammerspoon&lt;/a>, which is truely a game changer on mac. Hammerspoon is not a window management tool. Instead, it is a powerful automation framework on mac. Hammerspoon connects a lot of system APIs with lua script. In other words, you can use lua script to call system APIs to implement your feature.&lt;/p>
&lt;p>This is a great tool for us to define some window management tricks. Based on that, I wrote a script to help me place windows. It is similar to the one on Windows and Linux, but there is a little bit difference.&lt;/p>
&lt;ul>
&lt;li>&lt;code>win + left&lt;/code>: Place window on the left part of the screen. If your window is already on the left side of the screen, it will be moved to the monitor to the left (if there is any).&lt;/li>
&lt;li>&lt;code>win + right&lt;/code>: Place window on the right part of the screen. If your window is already on the right side of the screen, it will be moved to the monitor to the right (if there is any).&lt;/li>
&lt;li>&lt;code>win + up&lt;/code>: Maximize the window.&lt;/li>
&lt;li>&lt;code>win + down&lt;/code>: Place the window in the center.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Window placement with hammerspoon is definitely the most preferred solution to me&lt;/strong>. I attached the script on the bottom. To use it, install hammerspoon (follow this &lt;a href="https://www.hammerspoon.org/">page&lt;/a>) first, then copy the following content to &lt;code>~/.hammerspoon/init.lua&lt;/code>, and restart hammerspoon.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-lua" data-lang="lua">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- The following script comes from https://devmemo.gitlab.io/blog/mac_window_management/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">local&lt;/span> devmemo_config &lt;span style="color:#f92672">=&lt;/span> { }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Window Management&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">focused_window&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> hs.window.focusedWindow()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">set_frame&lt;/span>(unit)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> devmemo_config.focused_window():setFrame(unit, &lt;span style="color:#ae81ff">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">maximize_window&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> sf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> sf.x, y &lt;span style="color:#f92672">=&lt;/span> sf.y, w &lt;span style="color:#f92672">=&lt;/span> sf.w, h &lt;span style="color:#f92672">=&lt;/span> sf.h })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">center_window&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> sf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> sf.x &lt;span style="color:#f92672">+&lt;/span> sf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>, y &lt;span style="color:#f92672">=&lt;/span> sf.y &lt;span style="color:#f92672">+&lt;/span> sf.h &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>, w &lt;span style="color:#f92672">=&lt;/span> sf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, h &lt;span style="color:#f92672">=&lt;/span> sf.h &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">send_window_left&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> sf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> old_wf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> sf.x, y &lt;span style="color:#f92672">=&lt;/span> sf.y, w &lt;span style="color:#f92672">=&lt;/span> sf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, h &lt;span style="color:#f92672">=&lt;/span> sf.h })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> old_wf &lt;span style="color:#f92672">==&lt;/span> devmemo_config.focused_window():frame() &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> west_screen &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():toWest()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> west_screen &lt;span style="color:#f92672">~=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> wsf &lt;span style="color:#f92672">=&lt;/span> west_screen:frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> wsf.x &lt;span style="color:#f92672">+&lt;/span> wsf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, y &lt;span style="color:#f92672">=&lt;/span> wsf.y, w &lt;span style="color:#f92672">=&lt;/span> wsf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, h &lt;span style="color:#f92672">=&lt;/span> wsf.h })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">devmemo_config&lt;/span>.&lt;span style="color:#a6e22e">send_window_right&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> sf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> old_wf &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> sf.x &lt;span style="color:#f92672">+&lt;/span> sf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, y &lt;span style="color:#f92672">=&lt;/span> sf.y, w &lt;span style="color:#f92672">=&lt;/span> sf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, h &lt;span style="color:#f92672">=&lt;/span> sf.h })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> old_wf &lt;span style="color:#f92672">==&lt;/span> devmemo_config.focused_window():frame() &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> east_screen &lt;span style="color:#f92672">=&lt;/span> devmemo_config.focused_window():screen():toEast()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> east_screen &lt;span style="color:#f92672">~=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">local&lt;/span> esf &lt;span style="color:#f92672">=&lt;/span> east_screen:frame()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> devmemo_config.set_frame({ x &lt;span style="color:#f92672">=&lt;/span> esf.x, y &lt;span style="color:#f92672">=&lt;/span> esf.y, w &lt;span style="color:#f92672">=&lt;/span> esf.w &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>, h &lt;span style="color:#f92672">=&lt;/span> esf.h })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Key Bindings and Taps&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------------------------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey.bind({&lt;span style="color:#e6db74">&amp;#34;cmd&amp;#34;&lt;/span>}, &lt;span style="color:#e6db74">&amp;#34;Left&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() devmemo_config.send_window_left() &lt;span style="color:#66d9ef">end&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey.bind({&lt;span style="color:#e6db74">&amp;#34;cmd&amp;#34;&lt;/span>}, &lt;span style="color:#e6db74">&amp;#34;Right&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() devmemo_config.send_window_right() &lt;span style="color:#66d9ef">end&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey.bind({&lt;span style="color:#e6db74">&amp;#34;cmd&amp;#34;&lt;/span>}, &lt;span style="color:#e6db74">&amp;#34;Up&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() devmemo_config.maximize_window() &lt;span style="color:#66d9ef">end&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey.bind({&lt;span style="color:#e6db74">&amp;#34;cmd&amp;#34;&lt;/span>}, &lt;span style="color:#e6db74">&amp;#34;Down&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() devmemo_config.center_window() &lt;span style="color:#66d9ef">end&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>