Пример #1
0
func (c *Client) handleProperty(name string) {
	switch name {
	case "_NET_WM_VISIBLE_NAME":
		fallthrough
	case "_NET_WM_NAME":
		fallthrough
	case "WM_NAME":
		c.refreshName()
	case "_NET_WM_ICON":
		c.refreshIcon()
	case "WM_HINTS":
		if hints, err := icccm.WmHintsGet(wm.X, c.Id()); err == nil {
			c.hints = hints
			c.refreshIcon()
		}
	case "WM_NORMAL_HINTS":
		if nhints, err := icccm.WmNormalHintsGet(wm.X, c.Id()); err == nil {
			c.nhints = nhints
		}
	case "WM_TRANSIENT_FOR":
		if trans, err := icccm.WmTransientForGet(wm.X, c.Id()); err == nil {
			if transCli := wm.FindManagedClient(trans); transCli != nil {
				c.transientFor = transCli.(*Client)
			}
		}
	case "_NET_WM_USER_TIME":
		if newTime, err := ewmh.WmUserTimeGet(wm.X, c.Id()); err == nil {
			c.time = xproto.Timestamp(newTime)
		}
	case "_NET_WM_STRUT_PARTIAL":
		c.maybeApplyStruts()
	case "_MOTIF_WM_HINTS":
		// This is a bit messed up. If a client is floating, we don't
		// really care what the decorations are, so we oblige blindly.
		// However, if we're tiling, then we don't want to mess with
		// the frames---but we also want to make sure that any states
		// the client might revert to have the proper frames.
		decor := c.shouldDecor()
		if _, ok := c.Layout().(layout.Floater); ok {
			if decor {
				c.FrameFull()
			} else {
				c.FrameNada()
			}
		} else {
			for k := range c.states {
				s := c.states[k]
				if decor {
					s.frame = c.frames.full
				} else {
					s.frame = c.frames.nada
				}
				c.states[k] = s
			}
		}
	}
}
Пример #2
0
func withClient(cArg gribble.Any, f func(c *xclient.Client)) gribble.Any {
	switch c := cArg.(type) {
	case int:
		if c == 0 {
			return ":void:"
		}
		for _, client_ := range wm.Clients {
			client := client_.(*xclient.Client)
			if int(client.Id()) == c {
				f(client)
				return int(client.Id())
			}
		}
		return ":void:"
	case string:
		switch c {
		case ":void:":
			return ":void:"
		case ":mouse:":
			wid := xproto.Window(wm.MouseClientClicked)
			if client := wm.FindManagedClient(wid); client != nil {
				c := client.(*xclient.Client)
				f(c)
				return int(c.Id())
			} else {
				f(nil)
				return ":void:"
			}
		default:
			for _, client_ := range wm.Clients {
				client := client_.(*xclient.Client)
				name := strings.ToLower(client.Name())
				if strings.Contains(name, strings.ToLower(c)) {
					f(client)
					return int(client.Id())
				}
			}
			return ":void:"
		}
	default:
		panic(fmt.Sprintf("BUG: Unknown Gribble return type: %T", c))
	}
	panic("unreachable")
}
Пример #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)
		}
	}
}
Пример #4
0
func rootInit(X *xgbutil.XUtil) {
	var err error

	// Listen to Root. It is all-important.
	evMasks := xproto.EventMaskPropertyChange |
		xproto.EventMaskFocusChange |
		xproto.EventMaskButtonPress |
		xproto.EventMaskButtonRelease |
		xproto.EventMaskStructureNotify |
		xproto.EventMaskSubstructureNotify |
		xproto.EventMaskSubstructureRedirect
	if wm.Config.FfmHead {
		evMasks |= xproto.EventMaskPointerMotion
	}
	err = xwindow.New(X, X.RootWin()).Listen(evMasks)
	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)

	// Check where the pointer is on motion events. If it's crossed a monitor
	// boundary, switch the focus of the head.
	if wm.Config.FfmHead {
		xevent.MotionNotifyFun(handleMotionNotify).Connect(X, wm.Root.Id)
	}
}
Пример #5
0
func New(id xproto.Window) *Client {
	wm.X.Grab()
	defer wm.X.Ungrab()

	// If this is an override redirect, skip...
	attrs, err := xproto.GetWindowAttributes(wm.X.Conn(), id).Reply()
	if err != nil {
		logger.Warning.Printf("Could not get window attributes for '%d': %s",
			id, err)
	} else {
		if attrs.OverrideRedirect {
			logger.Message.Printf(
				"Not managing override redirect window %d", id)
			return nil
		}
	}

	if client := wm.FindManagedClient(id); client != nil {
		logger.Message.Printf("Already managing client: %s", client)
		return nil
	}

	win := xwindow.New(wm.X, id)
	if _, err := win.Geometry(); err != nil {
		logger.Warning.Printf("Could not manage client %d because: %s", id, err)
		return nil
	}

	c := &Client{
		win:         win,
		name:        "N/A",
		state:       frame.Inactive,
		layer:       stack.LayerDefault,
		maximized:   false,
		iconified:   false,
		unmapIgnore: 0,
		floating:    false,
		fullscreen:  false,
		skipTaskbar: false,
		skipPager:   false,
		demanding:   false,
		attnQuit:    make(chan struct{}, 0),
	}

	c.manage()

	// We don't fire the managed hook on startup since it can lead to
	// unintuitive state changes.
	// If someone really wants it, we can add a new "startup_managed" hook
	// or something.
	if !wm.Startup {
		event.Notify(event.ManagedClient{c.Id()})
		c.FireHook(hook.Managed)
	}
	if !c.iconified {
		c.Map()
		if !wm.Startup && c.PrimaryType() == TypeNormal {
			if !wm.Config.Ffm || wm.Config.FfmStartupFocus {
				c.Focus()
			}
		}
	}

	return c
}
Пример #6
0
func (c *Client) fetchXProperties() {
	var err error

	c.hints, err = icccm.WmHintsGet(wm.X, c.Id())
	if err != nil {
		logger.Warning.Println(err)
		logger.Message.Printf("Using reasonable defaults for WM_HINTS for %X",
			c.Id())
		c.hints = &icccm.Hints{
			Flags:        icccm.HintInput | icccm.HintState,
			Input:        1,
			InitialState: icccm.StateNormal,
		}
	}

	c.nhints, err = icccm.WmNormalHintsGet(wm.X, c.Id())
	if err != nil {
		logger.Warning.Println(err)
		logger.Message.Printf("Using reasonable defaults for WM_NORMAL_HINTS "+
			"for %X", c.Id())
		c.nhints = &icccm.NormalHints{}
	}

	c.protocols, err = icccm.WmProtocolsGet(wm.X, c.Id())
	if err != nil {
		logger.Warning.Printf(
			"Window %X does not have WM_PROTOCOLS set.", c.Id())
	}

	c.winTypes, err = ewmh.WmWindowTypeGet(wm.X, c.Id())
	if err != nil {
		logger.Warning.Printf("Could not find window type for window %X, "+
			"using 'normal'.", c.Id())
		c.winTypes = []string{"_NET_WM_WINDOW_TYPE_NORMAL"}
	}

	c.winStates, err = ewmh.WmStateGet(wm.X, c.Id())
	if err != nil {
		c.winStates = []string{}
		ewmh.WmStateSet(wm.X, c.Id(), c.winStates)
	}

	c.class, err = icccm.WmClassGet(wm.X, c.Id())
	if err != nil {
		logger.Warning.Printf("Could not find window class for window %X: %s",
			c.Id(), err)
		c.class = &icccm.WmClass{
			Instance: "",
			Class:    "",
		}
	}

	trans, _ := icccm.WmTransientForGet(wm.X, c.Id())
	if trans == 0 {
		for _, c2_ := range wm.Clients {
			c2 := c2_.(*Client)
			if c2.transient(c) {
				c.transientFor = c2
				break
			}
		}
	} else if transCli := wm.FindManagedClient(trans); transCli != nil {
		c.transientFor = transCli.(*Client)
	}

	tmp, err := xprop.PropValNum(
		xprop.GetProperty(wm.X, c.Id(), "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"))
	if err == nil {
		c.gtkMaximizeNada = (tmp == 1)
	} else {
		c.gtkMaximizeNada = false
	}

	c.setShaped()
}