I hope this isn’t troublesome, but I am riding high in this moment on successfully chasing down how to do something that’s not documented anywhere, at several levels.

What I wanted to do was change how Spell Assistant works such that i3 would display is by default as a floating window. Now, figuring out what I’m even supposed to do to make a window float by default in i3 isn’t easy. I know it’s possible, since if you hit ctrl-O in a web browser the “choose file” window that pops up is floating. I consulted the i3 userguide and the i3 hacking guide, but the only reference therein is this line in the userguide:

“Using [floating] mode violates the tiling paradigm but can be useful for some corner cases like “Save as” dialog windows, or toolbar windows (GIMP or similar). Those windows usually set the appropriate hint and are opened in floating mode by default.

So I know that I have to set SOME kind of “hint”, but I don’t know what those are, and I don’t know if I can even do that via Tkinter under Python.

Turns out, hints are a thing you can attach to an X11 window, like attributes, and there’s somewhat of a standard as to what those hints mean. Unfortunately, I don’t know what specific hint I need to set to what value to have things launch in floating mode. After some futile searching, I instead found someone who posted about how to to examine X11 attributes of windows using the tool xprop. So I used xprop to examine windows which open as tiling by default, and found that the hint I need is this:

_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DIALOG

If I can set the “WM_WINDOW_TYPE” attribute to “DIALOG” for my window, i3 will launch it by default as a floating window.

So now that I know what I want, I have to figure out how to do it. For this GUI, I’ve been using the package Tkinter for Python which provides a simple and straightforward set of GUI tools. However, the docs are old and aren’t hosted in a great format and they’re not even with the usual Python documentation. So I go spelunking through that and find nothing pointing me towards what I want. What I mostly discover is that those docs are BAD.

For example, under the WM header of the tkinter docs (http://effbot.org/tkinterbook/wm.htm), there’s a method called attributes which is described as “Sets or gets window attributes. See wm_attributes”, with “wm_attributes” being to an anchor link for elsewhere on the page, but the anchor link doesn’t work. So I manually search for “wm_attributes” and find that it’s description is “Sets or gets window attributes. See attributes for details.” Yes, that’s a referential loop.

I abandon the docs since they seem more intent on misleading than informing. Instead, I spy some functionality which may help me, which is a tkinter submodule which allows you to open file-picker dialogs. If I use that code, then I also get a floating window, so maybe I can search that source code for what I need.

Going through the Python source for tkinter, it’s apparent that it was probably last modified a decade ago. But soldiering through the ancient code, I find that Tkinter is truly just a wrapper around the TCL library called ‘Tk’, and that things like creating a file picker dialog are conducted by magic calls like:

Frame(self.master).w.tk.call('tk_getOpenFile')

At this point, I’ve lost some hope, as the only way I can do what I want is if there’s either a nice Python binding to set the option I want (which seems doubtful) or some way to use Python to hack at the original TCL datastructures or underlying code to get the TK library to do what I want. Turns out, the answer is the latter : (

So, armed with the knowlege that the TK tk_getOpenFile string is the way to make this happen, I now have to dive into the source code for TK, which is written in the 20+ year old language TCL. But fear not, it is still used and maintained, so there’s a github mirror of the source! Downloading the code, I start searching. The compressed version is that tk_getOpenFile is in tk.tcl, which calls tk_dialog which is in dialog.tcl and there, on line 76, is the line of code that does what we want:

wm attributes $w -type dialog

What the above is doing is setting the ‘-type’ attribute to have a value of ‘dialog’. Reviewing the Python API for Tkinter, the attributes() method can get or set window attributes, which before was not very informative, but now that we have some magic attributes to set, is all we need. So ultimately, getting this feature required a single additional line of code:

root.attributes('-type', 'dialog')