func (c *Client) Focused() { c.attnStop() c.frame.Active() c.state = frame.Active focus.SetFocus(c) ewmh.ActiveWindowSet(wm.X, c.Id()) c.addState("_NET_WM_STATE_FOCUSED") event.Notify(event.FocusedClient{c.Id()}) event.Notify(event.ChangedActiveClient{c.Id()}) c.FireHook(hook.Focused) }
func (c *Client) Unfocused() { wasFocused := c.state == frame.Active c.frame.Inactive() c.state = frame.Inactive ewmh.ActiveWindowSet(wm.X, 0) c.removeState("_NET_WM_STATE_FOCUSED") if wasFocused { event.Notify(event.UnfocusedClient{c.Id()}) event.Notify(event.ChangedActiveClient{0}) c.FireHook(hook.Unfocused) } }
func (c *Client) refreshName() { var newName string defer func() { if newName != c.name { c.name = newName c.frames.full.UpdateTitle() c.prompts.updateName() ewmh.WmVisibleNameSet(wm.X, c.Id(), c.name) event.Notify(event.ChangedClientName{c.Id()}) } }() newName, _ = ewmh.WmNameGet(wm.X, c.Id()) if len(newName) > 0 { return } newName, _ = icccm.WmNameGet(wm.X, c.Id()) if len(newName) > 0 { return } newName = "Unnamed Window" }
func (wrk *Workspace) AutoCycle() { if wrk.State == AutoTiling { wrk.curAutoTiler = (wrk.curAutoTiler + 1) % len(wrk.autoTilers) wrk.LayoutAutoTiler().Place() event.Notify(event.ChangedLayout{wrk.Name}) } }
func ewmhDesktopNames() { names := make([]string, len(Heads.Workspaces.Wrks)) for i, wrk := range Heads.Workspaces.Wrks { names[i] = wrk.Name } ewmh.DesktopNamesSet(X, names) event.Notify(event.ChangedWorkspaceNames{}) }
func (c *Client) Map() { if c.IsMapped() { return } c.win.Map() c.frame.Map() icccm.WmStateSet(wm.X, c.Id(), &icccm.WmState{State: icccm.StateNormal}) event.Notify(event.MappedClient{c.Id()}) }
func ewmhVisibleDesktops() { visibles := Heads.VisibleWorkspaces() desks := make([]uint, len(visibles)) for i, wrk := range visibles { desks[i] = uint(workspaceIndex(wrk)) } ewmh.VisibleDesktopsSet(X, desks) event.Notify(event.ChangedVisibleWorkspace{}) }
func (c *Client) Unmap() { if !c.IsMapped() { return } c.unmapIgnore++ c.frame.Unmap() c.win.Unmap() icccm.WmStateSet(wm.X, c.Id(), &icccm.WmState{State: icccm.StateIconic}) event.Notify(event.UnmappedClient{c.Id()}) }
func RemoveWorkspace(wrk *workspace.Workspace) error { if len(Heads.Workspaces.Wrks) == Heads.NumHeads() { return fmt.Errorf("Cannot have fewer workspaces than active monitors.") } if len(wrk.Clients) > 0 { return fmt.Errorf("Non-empty workspace '%s' cannot be removed.", wrk) } Heads.RemoveWorkspace(wrk) ewmhDesktopNames() ewmhNumberOfDesktops() ewmhVisibleDesktops() Heads.EwmhWorkarea() event.Notify(event.RemovedWorkspace{wrk.Name}) return nil }
func AddWorkspace(name string) error { if len(name) == 0 { return fmt.Errorf("workspaces must have a name of length at least one.") } if Heads.Workspaces.Find(name) != nil { return fmt.Errorf("a workspace with name '%s' already exists.", name) } wrk := Heads.NewWorkspace(name) wrk.PromptSlctGroup = Prompts.Slct.AddGroup(wrk) wrk.PromptSlctItem = Prompts.Slct.AddChoice(wrk) Heads.AddWorkspace(wrk) ewmhDesktopNames() ewmhNumberOfDesktops() ewmhVisibleDesktops() Heads.EwmhWorkarea() event.Notify(event.AddedWorkspace{wrk.Name}) return nil }
func (c *Client) unmanage() { wm.X.Grab() defer wm.X.Ungrab() go func() { c.frames.destroy() c.prompts.destroy() }() logger.Message.Printf("Unmanaging client: %s", c) infoWorkspace := c.workspace.String() infoClass := c.Class().Class infoInstance := c.Class().Instance infoName := c.Name() c.frame.Unmap() c.win.Detach() icccm.WmStateSet(wm.X, c.Id(), &icccm.WmState{State: icccm.StateWithdrawn}) focus.Remove(c) wm.FocusFallback() stack.Remove(c) c.workspace.Remove(c) wm.RemoveClient(c) c.attnStop() xproto.ChangeSaveSetChecked( wm.X.Conn(), xproto.SetModeDelete, c.Id()).Check() if c.hadStruts { wm.Heads.ApplyStruts(wm.Clients) } event.Notify(event.UnmanagedClient{ Id: c.Id(), Name: infoName, Workspace: infoWorkspace, Class: infoClass, Instance: infoInstance, }) }
func (wrk *Workspace) LayoutStateSet(state int) { if !wrk.IsVisible() { return } if state == wrk.State { // If it's an AutoTiler, then just call Place again. if wrk.State == AutoTiling { wrk.LayoutAutoTiler().Place() } return } // First undo the current layout. switch wrk.State { case Floating: wrk.LayoutFloater().Save() wrk.LayoutFloater().Unplace() case AutoTiling: wrk.LayoutAutoTiler().Unplace() default: panic("Layout state not implemented.") } // Now apply the new layout. switch state { case Floating: wrk.State = state wrk.LayoutFloater().Place() wrk.LayoutFloater().Reposition() case AutoTiling: wrk.State = state wrk.LayoutAutoTiler().Place() default: panic("Layout state not implemented.") } event.Notify(event.ChangedLayout{wrk.Name}) }
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 }
func ewmhCurrentDesktop() { ewmh.CurrentDesktopSet(X, uint(workspaceIndex(Workspace()))) event.Notify(event.ChangedWorkspace{}) }
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() if flagShowSocket { showSocketPath(X) return } // 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) // And start up the IPC event notifier. go event.Notifier(X, socketFilePath(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 { event.Notify(event.Restarting{}) for _, client := range wm.Clients { c := client.(*xclient.Client) if _, ok := c.Frame().(*frame.Full); ok { c.FrameNada() } } time.Sleep(1 * time.Second) // 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) } } }