From: Aaron Taylor Date: Sat, 4 Mar 2023 09:41:03 +0000 (-0800) Subject: New milestone: can launch and display an xterm X-Git-Url: http://git.subgeniuskitty.com/illi/.git/commitdiff_plain/ec873d07bbcd0a4d0d42a705aa383720963704cc New milestone: can launch and display an xterm ---- Illi is now able to connect to the X server, get a list of clients, register for (and handle) basic events. --- diff --git a/illi.go b/illi.go index ad324c1..e527d65 100644 --- a/illi.go +++ b/illi.go @@ -7,6 +7,7 @@ import ( "os/exec" "github.com/jezek/xgb" + "github.com/jezek/xgb/xinerama" "github.com/jezek/xgb/xproto" ) @@ -16,57 +17,57 @@ const ( XK_Return = 0xff0d ) +type display struct { + screen xinerama.ScreenInfo + windows []xproto.Window +} + func main() { - fmt.Println("ILLI: Execution begins") + // Set ourselves up as the new window manager ------------------------------ xconn := connectToXServer() - attachedScreens := getAttachedScreens(xconn) xroot := getXRoot(xconn) keymap := getKeyboardMap(xconn) registerForKeyEvents(xconn, xroot, keymap) becomeWM(xconn, xroot) - // Build a list of windows needing management ------------------------------ + // Build a list of output devices ------------------------------------------ - if len(attachedScreens) > 0 { - fmt.Println("The Go compiler is waaaaay too picky about unused variables...") + var attachedDisplays []display + for _, screen := range getAttachedScreens(xconn) { + attachedDisplays = append(attachedDisplays, display{screen: screen}) } + // TODO: Verify some displays actually exist and we don't have an empty array. Otherwise, die here. + // TODO: Should this all go in its own function and simply return attachedDisplays[] here instead? What will my fundamental data structure be? + // Build a list of windows needing management ------------------------------ + + // TODO: The following should all be an initialization function. It should not be here. tree, err := xproto.QueryTree(xconn, xroot.Root).Reply() if err != nil { + // TODO: Better error log.Fatal(err) } if tree != nil { - //workspaces = make(map[string]*Workspace) - //defaultw := &Workspace{mu: &sync.Mutex{}} for _, c := range tree.Children { if isMappedWindow(xconn, c) { -// err := defaultw.Add(c) -// if err != nil { -// log.Println(err) -// } - fmt.Println("ILLI: Found a client.") + // For now, dump any pre-existing windows into the first + // display. Later we can add functionality for tracking window + // attributes across window manager restarts. + attachedDisplays[0].windows = append(attachedDisplays[0].windows, c) } } - -// if len(attachedScreens) > 0 { -// defaultw.Screen = &attachedScreens[0] -// } -// -// workspaces["default"] = defaultw -// -// if err := defaultw.TileWindows(); err != nil { -// log.Println(err) -// } - + // TODO: Try tiling/displaying/whatever with any existing windows before entering the event loop. } // Main program loop reacts to X events ------------------------------------ eventloop: for { + fmt.Printf("ILLI: attachedDisplays: ") + fmt.Println(attachedDisplays) xevent, err := xconn.WaitForEvent() if err != nil { log.Println(err) @@ -74,11 +75,55 @@ eventloop: } switch e := xevent.(type) { case xproto.KeyPressEvent: + fmt.Printf("ILLI: Received xproto.KeyPressEvent\n") if err := handleKeyPressEvent(keymap, e); err != nil { break eventloop } + case xproto.KeyReleaseEvent: + fmt.Printf("ILLI: Received xproto.KeyReleaseEvent\n") + case xproto.DestroyNotifyEvent: + fmt.Printf("ILLI: Received xproto.DestroyNotifyEvent\n") + case xproto.ConfigureRequestEvent: + fmt.Printf("ILLI: Received xproto.ConfigureRequestEvent\n") + rewrittenEvent := xproto.ConfigureNotifyEvent{ + Event: e.Window, + Window: e.Window, + AboveSibling: 0, + X: e.X, + Y: e.Y, + Width: e.Width, + Height: e.Height, + BorderWidth: 0, + OverrideRedirect: false, + } + xproto.SendEventChecked(xconn, false, e.Window, xproto.EventMaskStructureNotify, string(rewrittenEvent.Bytes())) + case xproto.MapRequestEvent: + fmt.Printf("ILLI: Received xproto.MapRequestEvent\n") + if windowAttributes, err := xproto.GetWindowAttributes(xconn, e.Window).Reply(); err != nil || !windowAttributes.OverrideRedirect { + xproto.MapWindowChecked(xconn, e.Window) + attachedDisplays[0].windows = append(attachedDisplays[0].windows, e.Window) + + if err := xproto.ConfigureWindowChecked ( + xconn, + attachedDisplays[0].windows[0], + xproto.ConfigWindowX | + xproto.ConfigWindowY | + xproto.ConfigWindowWidth | + xproto.ConfigWindowHeight, + []uint32{ + uint32(100), // TODO: Temporarily hardcoding for testing. + uint32(100), // TODO: Temporarily hardcoding for testing. + uint32(1720), // TODO: Temporarily hardcoding for testing. + uint32(1000), // TODO: Temporarily hardcoding for testing. + }).Check(); err != nil { + fmt.Println("ILLI: Failed to handle MapRequestEvent") + } + + } + case xproto.EnterNotifyEvent: + fmt.Printf("ILLI: Received xproto.EnterNotifyEvent\n") default: - log.Println(xevent) + fmt.Printf("ILLI: Unknown X event received: %s\n", xevent) } } }