I'm currently in the design stage of writing a utility library that will make interaction with the x-go-binding a bit easier. (I've done this before with Python and xpyb.) For example, it will help with querying information defined in the EWMH spec and binding keys to callback functions. (And much more.) So as my initial idea for a package layout, consider:
Where each is its own package. (Similar to how the standard library's image package is setup.)
What's unique about my situation is that almost every x-go-binding call requires some combination of an xgb connection object or a root window identifier. Therefore, it makes sense to me to store this information in a struct like so:
type XUtilConnection struct {
conn xgb.Conn
root xgb.Id
// a few other things, like a mapping of events to callbacks
}
So that I'd have a factory that could be used like so:
xconn = xutil.NewXUtilConnection(blah blah)
And it could be used like:
xconn.get_active_window()
xconn.bind_key("Shift-a", my_callback_fun)
There may also be functions like:
keybind.get_keycode("a")
ewmh.get_atom("_NET_ACTIVE_WINDOW")
My problem of course is that receivers, to my knowledge, can only be of types that have been declared in the same package. If I separate my packages, I cannot use my XUtilConnection type as a receiver in any of my sub-packages.
I suspect that my answer is going to be making this one big package separated into different logical files, but I fear that this might lead to namespace clutter. (For example, implementing the EWMH spec is probably on the order of 100+ functions.)
I am also aware that I could define a new container type in each sub-package for my XUtilConnection object. (I've heard that this should be a struct containing a single member XUtilConnection to avoid casting.) But this seems like a really messy situation to me, and would prevent the kind of semantics I'd like. (i.e., using an XUtilConnection struct to call methods in several different modules.)
I would suggest to use embedding.
In package xutil
:
type XUtilConnection struct {
*ewmh.EWMH // Embed all methods of *ewmh.EWMH
*keybind.KeyBind // Embed all methods of *keybind.KeyBind
}
In package xutil/ewmh
:
type EWMH struct {
Conn xgb.Conn
Root xgb.Id
// and any additional fields that are needed
}
// Some EWMH methods:
func (e *EWMH) GetAtom(name string) { ... }
func (e *EWMH) ...
In package xutil/keybind
:
type KeyBind struct {
Conn xgb.Conn
Root xgb.Id
// and any additional fields that are needed
}
// Some keybind methods:
func (k *KeyBind) GetKeyCode(s string) { ... }
func (k *KeyBind) ...
This will enable you to directly call EWMH
's and KeyBind
's methods on values of type *XUtilConnection
:
var c *XUtilConnection = ...
c.GetAtom("_NET_ACTIVE_WINDOW") // Call (*emwh.EWMH).GetAtom(string)
c.GetKeyCode("a") // Call (*keybind.KeyBind).GetKeyCode(string)