// loadConfig reads all configuration files and loads them into the // a single config value. // // Most of this code is incredibly boring. func loadConfig() (*Configuration, error) { conf := newConfig() // globally defined in wingo.go type confFile struct { fpath string loadSection func(*Configuration, *wini.Data, string) } cfiles := []confFile{ { misc.ConfigFile("mouse.wini"), (*Configuration).loadMouseConfigSection, }, { misc.ConfigFile("key.wini"), (*Configuration).loadKeyConfigSection, }, { misc.ConfigFile("options.wini"), (*Configuration).loadOptionsConfigSection, }, // FYI hooks.wini is loaded in the hook package. } for _, cfile := range cfiles { cdata, err := wini.Parse(cfile.fpath) if err != nil { return nil, err } for _, section := range cdata.Sections() { cfile.loadSection(conf, cdata, section) } } return conf, nil }
func writeConfigFiles() { var configDir string xdgHome := os.Getenv("XDG_CONFIG_HOME") home := os.Getenv("HOME") if len(xdgHome) > 0 && strings.HasPrefix(xdgHome, "/") { configDir = path.Join(xdgHome, "wingo") } else if len(home) > 0 && strings.HasPrefix(home, "/") { configDir = path.Join(home, ".config", "wingo") } else { logger.Error.Fatalf("Something is screwy. Wingo could not detect "+ "valid values in your XDG_CONFIG_HOME ('%s') or HOME ('%s') "+ "environment variables.", xdgHome, home) } // If the directory already exists, we quit---avoid accidentally // overwriting an existing configuration! if _, err := os.Stat(configDir); err == nil || os.IsExist(err) { logger.Error.Fatalf("Writing config files failed. The directory '%s' "+ "already exists. Please remove it if you want a fresh set of "+ "configuration files.", configDir) } // Okay, we're all set to continue. Create the directory and copy all of // the configuration files. if err := os.MkdirAll(configDir, 0777); err != nil { logger.Error.Fatalf("Could not create directory '%s': %s", configDir, err) } files := []string{ "hooks.wini", "key.wini", "mouse.wini", "options.wini", "theme.wini", } for _, f := range files { dst := path.Join(configDir, f) if err := copyFile(dst, misc.ConfigFile(f)); err != nil { logger.Error.Fatalf("Could not copy file '%s' to '%s': %s", f, dst, err) } } }
func main() { if flagWriteConfig { writeConfigFiles() os.Exit(0) } X, err := xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Fatalln("Error connecting to X, quitting...") } defer X.Conn().Close() // Do this first! Attempt to retrieve window manager ownership. // This includes waiting for any existing window manager to die. // 'own' also sets up handlers for quitting when a window manager tries // to replace *us*. if err := own(X, flagReplace); err != nil { logger.Error.Fatalf( "Could not establish window manager ownership: %s", err) } if len(flagConfigDir) > 0 { misc.ConfigPaths.Override = flagConfigDir } if len(flagDataDir) > 0 { misc.DataPaths.Override = flagDataDir } misc.ReadData() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) cursors.Initialize(X) wm.Initialize(X, commands.Env, newHacks()) hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini")) // Listen to Root. It is all-important. err = xwindow.New(X, X.RootWin()).Listen( xproto.EventMaskPropertyChange | xproto.EventMaskFocusChange | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect) if err != nil { logger.Error.Fatalf("Could not listen to Root window events: %s", err) } // Update state when the root window changes size wm.RootGeomChangeFun().Connect(X, wm.Root.Id) // Oblige map request events xevent.MapRequestFun( func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) { xclient.New(ev.Window) }).Connect(X, wm.Root.Id) // Oblige configure requests from windows we don't manage. xevent.ConfigureRequestFun( func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) { // Make sure we aren't managing this client. if wm.FindManagedClient(ev.Window) != nil { return } xwindow.New(X, ev.Window).Configure(int(ev.ValueMask), int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height), ev.Sibling, ev.StackMode) }).Connect(X, wm.Root.Id) xevent.FocusInFun( func(X *xgbutil.XUtil, ev xevent.FocusInEvent) { if ignoreRootFocus(ev.Mode, ev.Detail) { return } if len(wm.Workspace().Clients) == 0 { return } wm.FocusFallback() }).Connect(X, wm.Root.Id) // Listen to Root client message events. This is how we handle all // of the EWMH bullshit. xevent.ClientMessageFun(handleClientMessages).Connect(X, wm.Root.Id) // Tell everyone what we support. setSupported() // Start up the IPC command listener. go ipc() // Just before starting the main event loop, check to see if there are // any clients that already exist that we should manage. manageExistingClients() // Now make sure that clients are in the appropriate visible state. for _, wrk := range wm.Heads.Workspaces.Wrks { if wrk.IsVisible() { wrk.Show() } else { wrk.Hide() } } wm.Heads.ApplyStruts(wm.Clients) wm.FocusFallback() wm.Startup = false pingBefore, pingAfter, pingQuit := xevent.MainPing(X) if len(flagCpuProfile) > 0 { f, err := os.Create(flagCpuProfile) if err != nil { logger.Error.Fatalf("%s\n", err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if flagWingoRestarted { hook.Fire(hook.Restarted, hook.Args{}) } else { hook.Fire(hook.Startup, hook.Args{}) } EVENTLOOP: for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case f := <-commands.SafeExec: commands.SafeReturn <- f() case <-pingQuit: break EVENTLOOP } } if wm.Restart { // We need to tell the next invocation of Wingo that it is being // *restarted*. (So that we don't refire the startup hook.) // Thus, search os.Args for "--wingo-restarted". If it doesn't exist, // add it. found := false for _, arg := range os.Args { if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" { found = true } } if !found { os.Args = append(os.Args, "--wingo-restarted") } logger.Message.Println("The user has told us to restart...\n\n\n") if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil { logger.Error.Fatalf("Could not exec '%s': %s", strings.Join(os.Args, " "), err) } } }
func loadTheme() (*ThemeConfig, error) { theme := newTheme() tdata, err := wini.Parse(misc.ConfigFile("theme.wini")) if err != nil { return nil, err } for _, section := range tdata.Sections() { switch section { case "misc": for _, key := range tdata.Keys(section) { loadMiscOption(theme, key) } case "full": for _, key := range tdata.Keys(section) { loadFullOption(theme, key) } case "borders": for _, key := range tdata.Keys(section) { loadBorderOption(theme, key) } case "slim": for _, key := range tdata.Keys(section) { loadSlimOption(theme, key) } case "prompt": for _, key := range tdata.Keys(section) { loadPromptOption(theme, key) } } } // re-color some images colorize := func(im *xgraphics.Image, clr render.Color) { var i int r, g, b := clr.RGB8() im.ForExp(func(x, y int) (uint8, uint8, uint8, uint8) { i = im.PixOffset(x, y) return r, g, b, im.Pix[i+3] }) } colorize(theme.Full.aCloseButton, theme.Full.aCloseColor) colorize(theme.Full.iCloseButton, theme.Full.iCloseColor) colorize(theme.Full.aMaximizeButton, theme.Full.aMaximizeColor) colorize(theme.Full.iMaximizeButton, theme.Full.iMaximizeColor) colorize(theme.Full.aMinimizeButton, theme.Full.aMinimizeColor) colorize(theme.Full.iMinimizeButton, theme.Full.iMinimizeColor) // Scale some images... theme.Full.aCloseButton = theme.Full.aCloseButton.Scale( theme.Full.titleSize, theme.Full.titleSize) theme.Full.iCloseButton = theme.Full.iCloseButton.Scale( theme.Full.titleSize, theme.Full.titleSize) theme.Full.aMaximizeButton = theme.Full.aMaximizeButton.Scale( theme.Full.titleSize, theme.Full.titleSize) theme.Full.iMaximizeButton = theme.Full.iMaximizeButton.Scale( theme.Full.titleSize, theme.Full.titleSize) theme.Full.aMinimizeButton = theme.Full.aMinimizeButton.Scale( theme.Full.titleSize, theme.Full.titleSize) theme.Full.iMinimizeButton = theme.Full.iMinimizeButton.Scale( theme.Full.titleSize, theme.Full.titleSize) return theme, nil }
func main() { if flagWriteConfig { writeConfigFiles() os.Exit(0) } X, err := xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Fatalln("Error connecting to X, quitting...") } defer X.Conn().Close() // Do this first! Attempt to retrieve window manager ownership. // This includes waiting for any existing window manager to die. // 'own' also sets up handlers for quitting when a window manager tries // to replace *us*. if err := own(X, flagReplace); err != nil { logger.Error.Fatalf( "Could not establish window manager ownership: %s", err) } if len(flagConfigDir) > 0 { misc.ConfigPaths.Override = flagConfigDir } if len(flagDataDir) > 0 { misc.DataPaths.Override = flagDataDir } misc.ReadData() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) cursors.Initialize(X) wm.Initialize(X, commands.Env, newHacks()) hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini")) // Initialize event handlers on the root window. rootInit(X) // Tell everyone what we support. setSupported() // Start up the IPC command listener. go ipc(X) // Just before starting the main event loop, check to see if there are // any clients that already exist that we should manage. manageExistingClients() // Now make sure that clients are in the appropriate visible state. for _, wrk := range wm.Heads.Workspaces.Wrks { if wrk.IsVisible() { wrk.Show() } else { wrk.Hide() } } wm.Heads.ApplyStruts(wm.Clients) wm.FocusFallback() wm.Startup = false pingBefore, pingAfter, pingQuit := xevent.MainPing(X) if len(flagCpuProfile) > 0 { f, err := os.Create(flagCpuProfile) if err != nil { logger.Error.Fatalf("%s\n", err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if flagWingoRestarted { hook.Fire(hook.Restarted, hook.Args{}) } else { hook.Fire(hook.Startup, hook.Args{}) } EVENTLOOP: for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case f := <-commands.SafeExec: commands.SafeReturn <- f() case <-pingQuit: break EVENTLOOP } } if wm.Restart { // We need to tell the next invocation of Wingo that it is being // *restarted*. (So that we don't refire the startup hook.) // Thus, search os.Args for "--wingo-restarted". If it doesn't exist, // add it. found := false for _, arg := range os.Args { if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" { found = true } } if !found { os.Args = append(os.Args, "--wingo-restarted") } logger.Message.Println("The user has told us to restart...\n\n\n") if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil { logger.Error.Fatalf("Could not exec '%s': %s", strings.Join(os.Args, " "), err) } } }