"github.com/jezek/xgb/xinerama"
"github.com/jezek/xgb/xproto"
// -----------------------------------------------------------------------------
// Note: Since functions in this file are related to initialization and thus
// execute at a time when the program is still building toward a viable state,
// these functions intentionally exit via a series of explicit commands,
// cleaning up only what has already been initialized rather than simply
// calling the normal illi die/restart functions.
// -----------------------------------------------------------------------------
// Note: The caller is responsible for tracking the lifetime of the returned X
// connection and calling connection.Close() when appropriate.
func connectToXServer() *xgb
.Conn
{
connection
, err
:= xgb
.NewConn()
fmt
.Fprintf(os
.Stderr
, "ILLI: Failed to connect to X server: %s\n", err
.Error())
func getAttachedScreens(conn
*xgb
.Conn
) (screens
[]xinerama
.ScreenInfo
) {
// Attempt to use xinerama to obtain screen information.
err
:= xinerama
.Init(conn
)
fmt
.Fprintf(os
.Stderr
, "ILLI: Unable to initialize xinerama: %s\n", err
.Error())
} else { // Xinerama successfully initialized.
reply
, err
:= xinerama
.QueryScreens(conn
).Reply()
fmt
.Fprintf(os
.Stderr
, "ILLI: Unusable result when querying screens through xinerama: %s\n", err
.Error())
screens
= reply
.ScreenInfo
// Since we were unable to obtain the screen information via xinerama, we
// fall back to requesting ScreenInfo directly from the X server.
setup
:= xproto
.Setup(conn
)
if setup
== nil ||
len(setup
.Roots
) < 1 {
fmt
.Fprintf(os
.Stderr
, "ILLI: Unusable ScreenInfo received from X server.\n")
screens
= []xinerama
.ScreenInfo
{
Width
: setup
.Roots
[0].WidthInPixels
,
Height
: setup
.Roots
[0].HeightInPixels
,
return // Should be unreachable
func getXRoot(conn
*xgb
.Conn
) xproto
.ScreenInfo
{
setup
:= xproto
.Setup(conn
)
if setup
== nil ||
len(setup
.Roots
) < 1 {
fmt
.Fprintf(os
.Stderr
, "ILLI: Failed to determine X root.\n")
func getKeyboardMap(conn
*xgb
.Conn
) (keymap
[256][]xproto
.Keysym
) { // TODO: Why 256?
const ( // TODO: Why? How does the keymap work under the hood?
m
:= xproto
.GetKeyboardMapping(conn
, loKey
, hiKey
-loKey
+1)
if err
!= nil || r
== nil {
fmt
.Fprintf(os
.Stderr
, "ILLI: Failed to load keymap from X server: %s\n.", err
.Error())
for i
:= 0; i
< hiKey
-loKey
+1; i
++ {
keymap
[loKey
+i
] = r
.Keysyms
[i
*int(r
.KeysymsPerKeycode
) : (i
+1)*int(r
.KeysymsPerKeycode
)]
func registerForKeyEvents(conn
*xgb
.Conn
, root xproto
.ScreenInfo
, keymap
[256][]xproto
.Keysym
) {
// First we populate []grabs with the keysym and modifiers we seek.
// TODO: Need to define a config table and do both keysym grabs and
// main event loop using the config table rather than hardcoding key
// assignments throughout the code.
modifiers
: xproto
.ModMask1 | xproto
.ModMaskShift
,
modifiers
: xproto
.ModMask1 | xproto
.ModMaskShift
,
// Next we use the keymap provided by the X server to identify the keycodes
// corresponding to the keysyms in []grabs.
for i
, syms
:= range keymap
{
for _
, sym
:= range syms
{
grabs
[c
].codes
= append(grabs
[c
].codes
, xproto
.Keycode(i
))
// Finally, we register with the X server for each combo of
// keycode+modifiers in []grabs.
for _
, grabbed
:= range grabs
{
for _
, code
:= range grabbed
.codes
{
err
:= xproto
.GrabKeyChecked(
"ILLI: Failed to register keycode 0x%X with modifier(s) 0x%X: %s\n",
code
, grabbed
.modifiers
, err
.Error())
// In addition to the basic key/button press/release events, by registering for
// events like SubstructureRedirect, we are declaring our intent to act as
// window manager for this X server. Only one WM is allowed per X server, a
// policy enforced on the X server's side by refusing the registration request
// for events like SubstructureRedirect if an existing process already receives
// those events (i.e. is already the window manager).
func becomeWM(conn
*xgb
.Conn
, root xproto
.ScreenInfo
) {
err
:= xproto
.ChangeWindowAttributesChecked(
xproto
.EventMaskKeyPress |
xproto
.EventMaskKeyRelease |
xproto
.EventMaskButtonPress |
xproto
.EventMaskButtonRelease |
xproto
.EventMaskStructureNotify |
xproto
.EventMaskSubstructureRedirect
,
// TODO: Should we also register for EventMaskSubstructureNotify ?
// Where is the authoritative list of events located?
fmt
.Fprintf(os
.Stderr
, "ILLI: Unable to register as WM with X server: %s\n", err
.Error())