Example #1
0
// 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
}
Example #2
0
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)
		}
	}
}
Example #3
0
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)
		}
	}
}
Example #4
0
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
}
Example #5
0
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)
		}
	}
}