// drag around windows with the mouse. func MakeDraggable(X *xgbutil.XUtil, win xproto.Window) { // utility window for movement xwin := xwindow.New(X, win) // state var offsetX, offsetY int var lastX, lastY int // saves initial click location startDrag := func(X *xgbutil.XUtil, rootX, rootY, eventX, eventY int) (bool, xproto.Cursor) { offsetX = eventX offsetY = eventY lastX = rootX lastY = rootY // apparently the cursor is just ID 0 return true, 0 } // moves the window stepDrag := func(X *xgbutil.XUtil, rootX, rootY, eventX, eventY int) { // maintain mouse position within window toX := rootX - offsetX toY := rootY - offsetY // move window xwin.Move(toX, toY) } stopDrag := func(X *xgbutil.XUtil, rx, ry, ex, ey int) {} // actually bind handler to window mousebind.Drag(X, win, win, "1", true, startDrag, stepDrag, stopDrag) log.Printf("MakeDraggable: activated window %v\n", xwin) }
func (app *RuntimeApp) detachXid(xid xproto.Window) { if info, ok := app.xids[xid]; ok { xwindow.New(XU, xid).Listen(xproto.EventMaskNoEvent) xevent.Detach(XU, xid) if len(app.xids) == 1 { ENTRY_MANAGER.destroyRuntimeApp(app) } else { delete(app.xids, xid) if info == app.CurrentInfo { for _, nextInfo := range app.xids { if nextInfo != nil { app.CurrentInfo = nextInfo app.updateState(app.CurrentInfo.Xid) app.notifyChanged() } else { ENTRY_MANAGER.destroyRuntimeApp(app) } break } } } } if len(app.xids) == 0 { app.setChangedCB(nil) } else { app.notifyChanged() } }
func Root() { rwin := xwindow.New(X, X.RootWin()) for _, c := range Clients { c.Unfocused() } rwin.Focus() }
func (m *TrayManager) addTrayIcon(xid xproto.Window) { m.checkValid() for _, id := range m.TrayIcons { if xproto.Window(id) == xid { return } } if d, err := damage.NewDamageId(TrayXU.Conn()); err != nil { return } else { m.dmageInfo[xid] = d if err := damage.CreateChecked(TrayXU.Conn(), d, xproto.Drawable(xid), damage.ReportLevelRawRectangles).Check(); err != nil { logger.Debug("DamageCreate Failed:", err) return } } composite.RedirectWindow(TrayXU.Conn(), xid, composite.RedirectAutomatic) m.TrayIcons = append(m.TrayIcons, uint32(xid)) icon := xwindow.New(TrayXU, xid) icon.Listen(xproto.EventMaskVisibilityChange | damage.Notify | xproto.EventMaskStructureNotify) icon.Change(xproto.CwBackPixel, 0) name, err := ewmh.WmNameGet(TrayXU, xid) if err != nil { logger.Debug("WmNameGet failed:", err, xid) } m.nameInfo[xid] = name m.notifyInfo[xid] = true dbus.Emit(m, "Added", uint32(xid)) logger.Infof("Added try icon: \"%s\"(%d)", name, uint32(xid)) }
func isWindowOnPrimaryScreen(xid xproto.Window) bool { var err error win := xwindow.New(XU, xid) // include shadow gemo, err := win.DecorGeometry() if err != nil { logger.Debug(err) return false } displayRectX := (int)(displayRect.X) displayRectY := (int)(displayRect.Y) displayRectWidth := (int)(displayRect.Width) displayRectHeight := (int)(displayRect.Height) SHADOW_OFFSET := 10 gemoX := gemo.X() + SHADOW_OFFSET gemoY := gemo.Y() + SHADOW_OFFSET isOnPrimary := gemoX+SHADOW_OFFSET >= displayRectX && gemoX < displayRectX+displayRectWidth && gemoY >= displayRectY && gemoY < displayRectY+displayRectHeight logger.Debugf("isWindowOnPrimaryScreen: %dx%d, %dx%d, %v", gemo.X(), gemo.Y(), displayRect.X, displayRect.Y, isOnPrimary) return isOnPrimary }
func isWindowOverlapDock(xid xproto.Window) bool { win := xwindow.New(XU, xid) rect, err := win.DecorGeometry() if err != nil { logger.Warning(err) return false } winX := int32(rect.X()) winY := int32(rect.Y()) winWidth := int32(rect.Width()) winHeight := int32(rect.Height()) dockX := int32(displayRect.X) + (int32(displayRect.Width)- dockProperty.PanelWidth)/2 dockY := int32(displayRect.Y) + int32(displayRect.Height) - dockProperty.Height dockWidth := int32(displayRect.Width) if DisplayModeType(setting.GetDisplayMode()) == DisplayModeModernMode { dockWidth = dockProperty.PanelWidth } // TODO: dock on the other side like top, left. return dockY < winY+winHeight && dockX < winX+winWidth && dockX+dockWidth > winX }
func createNotify(X *xgbutil.XUtil, event xgb.Event) { ev := event.(xproto.CreateNotifyEvent) // values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE; // xcb_change_window_attributes(wm->conn, id, XCB_CW_EVENT_MASK, values); win := xwindow.New(X, ev.Window) win.Listen(xproto.EventMaskPropertyChange) XWins[ev.Window] = &XWin{ surfaceId: 0, } }
func headGeom(X *xgbutil.XUtil) xrect.Rect { if X.ExtInitialized("XINERAMA") { heads, err := xinerama.PhysicalHeads(X) if err == nil { return heads[0] } } geom, err := xwindow.New(X, X.RootWin()).Geometry() fatal(err) return geom }
// currentTime forcefully causes a PropertyNotify event to fire on the root // window, then scans the event queue and picks up the time. // // It is NOT SAFE to call this function in a place other than Wingo's // initialization. Namely, this function subverts xevent's queue and reads // events directly from X. func currentTime(X *xgbutil.XUtil) (xproto.Timestamp, error) { wmClassAtom, err := xprop.Atm(X, "WM_CLASS") if err != nil { return 0, err } stringAtom, err := xprop.Atm(X, "STRING") if err != nil { return 0, err } // Make sure we're listening to PropertyChange events on the root window. err = xwindow.New(X, X.RootWin()).Listen(xproto.EventMaskPropertyChange) if err != nil { return 0, fmt.Errorf( "Could not listen to Root window events (PropertyChange): %s", err) } // Do a zero-length append on a property as suggested by ICCCM 2.1. err = xproto.ChangePropertyChecked( X.Conn(), xproto.PropModeAppend, X.RootWin(), wmClassAtom, stringAtom, 8, 0, nil).Check() if err != nil { return 0, err } // Now look for the PropertyNotify generated by that zero-length append // and return the timestamp attached to that event. // Note that we do this outside of xgbutil/xevent, since ownership // is literally the first thing we do after connecting to X. // (i.e., we don't have our event handling system initialized yet.) timeout := time.After(3 * time.Second) for { select { case <-timeout: return 0, fmt.Errorf( "Expected a PropertyNotify event to get a valid timestamp, " + "but never received one.") default: ev, err := X.Conn().PollForEvent() if err != nil { continue } if propNotify, ok := ev.(xproto.PropertyNotifyEvent); ok { X.TimeSet(propNotify.Time) // why not? return propNotify.Time, nil } time.Sleep(100 * time.Millisecond) } } panic("unreachable") }
func NewSocket(X *xgbutil.XUtil, wid xproto.Window) (*XEmbedSocket, error) { sock := &XEmbedSocket{ Window: xwindow.New(X, wid), id: wid, X: X, } if err := sock.load(); err != nil { return nil, err } return sock, nil }
func configureRequest(X *xgbutil.XUtil, event xgb.Event) { ev := event.(xproto.ConfigureRequestEvent) win := xwindow.New(X, ev.Window) win.Configure( xproto.ConfigWindowX| xproto.ConfigWindowY| xproto.ConfigWindowWidth| xproto.ConfigWindowHeight, (int)(ev.X), (int)(ev.Y), (int)(ev.Width), (int)(ev.Height), ev.Sibling, ev.StackMode, ) log.Info("configure request:", ev) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Start generating other source events. otherChan := otherSource() // Start generating X events (by sending client messages to root window). go xSource(X) // Listen to those X events. xwindow.New(X, X.RootWin()).Listen(xproto.EventMaskSubstructureNotify) // Respond to those X events. xevent.ClientMessageFun( func(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) { atmName, err := xprop.AtomName(X, ev.Type) if err != nil { log.Fatal(err) } fmt.Printf("ClientMessage: %d. %s\n", ev.Data.Data32[0], atmName) }).Connect(X, X.RootWin()) // Instead of using the usual xevent.Main, we use xevent.MainPing. // It runs the main event loop inside a goroutine and returns ping // channels, which are sent benign values right before an event is // dequeued and right after that event has finished running all callbacks // associated with it, respectively. pingBefore, pingAfter, pingQuit := xevent.MainPing(X) for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case otherVal := <-otherChan: fmt.Printf("Processing other event: %d\n", otherVal) case <-pingQuit: fmt.Printf("xevent loop has quit") return } } }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Get a list of all client ids. clientids, err := ewmh.ClientListGet(X) if err != nil { log.Fatal(err) } // Iterate through each client, find its name and find its size. for _, clientid := range clientids { name, err := ewmh.WmNameGet(X, clientid) // If there was a problem getting _NET_WM_NAME or if its empty, // try the old-school version. if err != nil || len(name) == 0 { name, err = icccm.WmNameGet(X, clientid) // If we still can't find anything, give up. if err != nil || len(name) == 0 { name = "N/A" } } // Now find the geometry, including decorations, of the client window. // Note that DecorGeometry actually traverses the window tree by // issuing QueryTree requests until a top-level window (i.e., its // parent is the root window) is found. The geometry of *that* window // is then returned. dgeom, err := xwindow.New(X, clientid).DecorGeometry() if err != nil { log.Printf("Could not get geometry for %s (0x%X) because: %s", name, clientid, err) continue } fmt.Printf("%s (0x%x)\n", name, clientid) fmt.Printf("\tGeometry: %s\n", dgeom) } }
func (wa *fullScreenWorkaround) start() { var runner func() runner = func() { w, _ := ewmh.ActiveWindowGet(wa.xu) wa.detectTarget(w) time.AfterFunc(time.Second*5, runner) } runner() root := xwindow.New(wa.xu, wa.xu.RootWin()) root.Listen(xproto.EventMaskPropertyChange) xevent.PropertyNotifyFun(func(XU *xgbutil.XUtil, ev xevent.PropertyNotifyEvent) { if wa.activeWindowAtom == ev.Atom { w, _ := ewmh.ActiveWindowGet(XU) wa.detectTarget(w) } }).Connect(wa.xu, root.Id) xevent.Main(wa.xu) }
func main() { var err error X, err = xgbutil.NewConn() if err != nil { log.Fatal(err) } clientids, err := ewmh.ClientListGet(X) if err != nil { log.Fatal(err) } for _, clientid := range clientids { name, err := ewmh.WmNameGet(X, clientid) if err != nil { continue } if name == "Super Hexagon" { HexWindow = xwindow.New(X, clientid) break } } if HexWindow == nil { log.Fatal("Couldn't find Super Hexagon window.") } //Create a window DisplayWindow, err = xwindow.Generate(X) if err != nil { log.Fatalf("Could not generate a new window X id: %s", err) } dgeom, _ := HexWindow.DecorGeometry() DisplayWindow.Create(X.RootWin(), 0, 0, dgeom.Width(), dgeom.Height(), xproto.CwBackPixel, 0) DisplayWindow.Map() //Start the routine that updates the window go updater() xevent.Main(X) }
func getViewport() (geom string) { // new X server connection X, err := xgbutil.NewConn() if err != nil { log.Error(err) } // get root window root := xwindow.New(X, X.RootWin()) // geometry of the root window rgeom, err := root.Geometry() if err != nil { log.Error(err) } // Get the rectangles for each of the active physical heads. // These are returned sorted in order from left to right and then top // to bottom. // But first check if Xinerama is enabled. If not, use root geometry. var heads xinerama.Heads if X.ExtInitialized("XINERAMA") { heads, err = xinerama.PhysicalHeads(X) if err != nil { log.Error(err) } } else { heads = xinerama.Heads{rgeom} } // looking for the first screen, position X: 0, Y: 0 for _, head := range heads { if head.X() == 0 && head.Y() == 0 { screenWidth = head.Width() screenHeight = head.Height() } } geom = fmt.Sprintf("%dx%d", screenWidth-165, screenHeight-165) return geom }
func (l *Listener) Initialize() error { if l.X == nil { return fmt.Errorf("X must not be nil.") } if typeAtom == 0 && typeAtomBegin == 0 { var err error typeAtom, err = xprop.Atom(l.X, "_NET_STARTUP_INFO", false) if err != nil { return err } typeAtomBegin, err = xprop.Atom(l.X, "_NET_STARTUP_INFO_BEGIN", false) if err != nil { return err } } if l.Callbacks == nil { return fmt.Errorf("Callbacks must not be nil") } if err := xwindow.New(l.X, l.X.RootWin()).Listen(xproto.EventMaskPropertyChange); err != nil { return err } l.msgBuff = make(map[xproto.Window][]byte) xevent.HookFun(func(_ *xgbutil.XUtil, ev interface{}) bool { return l.hook(ev) }).Connect(l.X) return nil }
func newClient(X *xgbutil.XUtil, id xproto.Window) *client { X.Grab() defer X.Ungrab() if client := wingo.findManagedClient(id); client != nil { logger.Message.Printf("Already managing client: %s", client) return nil } win := xwindow.New(X, id) if _, err := win.Geometry(); err != nil { logger.Warning.Printf("Could not manage client %d because: %s", id, err) return nil } c := &client{ X: X, win: win, name: "N/A", state: frame.Inactive, layer: stack.LayerDefault, maximized: false, iconified: false, unmapIgnore: 0, floating: false, } c.manage() if !c.iconified { c.Map() if c.primaryType == clientTypeNormal { focus.Focus(c) } } return c }
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 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) } }
func xwmInit(fd uintptr) { X := fromFd(fd) defer X.Conn().Close() root := xwindow.New(X, X.RootWin()) if _, err := root.Geometry(); err != nil { panic(err) } // if names, _ := ewmh.DesktopNamesGet(X); len(names) > 0 { // println(names) // } composite.Init(X.Conn()) atomNames := []string{ "WL_SURFACE_ID", "WM_DELETE_WINDOW", "WM_PROTOCOLS", "WM_S0", "WM_NORMAL_HINTS", "WM_TAKE_FOCUS", "WM_STATE", "WM_CLIENT_MACHINE", "_NET_WM_CM_S0", "_NET_WM_NAME", "_NET_WM_PID", "_NET_WM_ICON", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_USER_TIME", "_NET_WM_ICON_NAME", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK", "_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU", "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", "_NET_WM_WINDOW_TYPE_POPUP_MENU", "_NET_WM_WINDOW_TYPE_TOOLTIP", "_NET_WM_WINDOW_TYPE_NOTIFICATION", "_NET_WM_WINDOW_TYPE_COMBO", "_NET_WM_WINDOW_TYPE_DND", "_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_MOVERESIZE", "_NET_SUPPORTING_WM_CHECK", "_NET_SUPPORTED", "_MOTIF_WM_HINTS", "CLIPBOARD", "CLIPBOARD_MANAGER", "TARGETS", "UTF8_STRING", "_WL_SELECTION", "INCR", "TIMESTAMP", "MULTIPLE", "UTF8_STRING", "COMPOUND_TEXT", "TEXT", "STRING", "text/plain;charset=utf-8", "text/plain", "XdndSelection", "XdndAware", "XdndEnter", "XdndLeave", "XdndDrop", "XdndStatus", "XdndFinished", "XdndTypeList", "XdndActionCopy", } cookies := make([]xproto.InternAtomCookie, len(atomNames)) for i := 0; i < len(atomNames); i++ { cookies[i] = xproto.InternAtom(X.Conn(), false, uint16(len(atomNames[i])), atomNames[i]) } /* Try to select for substructure redirect. */ evMasks := xproto.EventMaskPropertyChange | xproto.EventMaskFocusChange | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect root.Listen(evMasks) composite.RedirectSubwindows(X.Conn(), root.Id, composite.RedirectManual) // change config // data := []byte{1} // propAtom, _ := xprop.Atm(X, "_NET_SUPPORTED") // var format byte = 32 // xproto.ChangePropertyChecked(X.Conn(), xproto.PropModeReplace, // root.Id, propAtom, xproto.AtomAtom, format, // uint32(len(data)/(int(format)/8)), data) ewmh.SupportedSet(X, []string{ "_NET_SUPPORTED", "_NET_CLIENT_LIST", "_NET_NUMBER_OF_DESKTOPS", "_NET_DESKTOP_GEOMETRY", "_NET_CURRENT_DESKTOP", "_NET_VISIBLE_DESKTOPS", "_NET_DESKTOP_NAMES", "_NET_ACTIVE_WINDOW", "_NET_SUPPORTING_WM_CHECK", "_NET_CLOSE_WINDOW", "_NET_MOVERESIZE_WINDOW", "_NET_RESTACK_WINDOW", "_NET_WM_NAME", "_NET_WM_DESKTOP", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK", "_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU", "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", "_NET_WM_WINDOW_TYPE_POPUP_MENU", "_NET_WM_WINDOW_TYPE_TOOLTIP", "_NET_WM_WINDOW_TYPE_NOTIFICATION", "_NET_WM_WINDOW_TYPE_COMBO", "_NET_WM_WINDOW_TYPE_DND", "_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_STATE", "_NET_WM_STATE_STICKY", "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ", "_NET_WM_STATE_SKIP_TASKBAR", "_NET_WM_STATE_SKIP_PAGER", "_NET_WM_STATE_HIDDEN", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW", "_NET_WM_STATE_DEMANDS_ATTENTION", "_NET_WM_STATE_FOCUSED", "_NET_WM_ALLOWED_ACTIONS", "_NET_WM_ACTION_MOVE", "_NET_WM_ACTION_RESIZE", "_NET_WM_ACTION_MINIMIZE", "_NET_WM_ACTION_STICK", "_NET_WM_ACTION_MAXIMIZE_HORZ", "_NET_WM_ACTION_MAXIMIZE_VERT", "_NET_WM_ACTION_FULLSCREEN", "_NET_WM_ACTION_CHANGE_DESKTOP", "_NET_WM_ACTION_CLOSE", "_NET_WM_ACTION_ABOVE", "_NET_AM_ACTION_BELOW", "_NET_WM_STRUT_PARTIAL", "_NET_WM_ICON", "_NET_FRAME_EXTENTS", "WM_TRANSIENT_FOR", }) // create wm window win, _ := xwindow.Create(X, root.Id) xproto.MapWindow(X.Conn(), win.Id) atomValues := make([]xproto.Atom, len(atomNames)) for num, cookie := range cookies { reply, _ := cookie.Reply() atomValues[num] = reply.Atom } /* take WM_S0 selection last, which * signals to Xwayland that we're done with setup. */ xproto.SetSelectionOwner(X.Conn(), win.Id, atomValues[3], xproto.TimeCurrentTime, ) mapResquest := func(event xgb.Event) { ev, _ := event.(xproto.MapRequestEvent) log.Info("MapRequest: ", ev) xproto.MapWindow(X.Conn(), ev.Window) icccm.WmStateSet(X, ev.Window, &icccm.WmState{ State: icccm.StateNormal, Icon: ev.Window, }) // TODO: set _net_wm_state } for { x := X.Conn() ev, xerr := x.WaitForEvent() if ev == nil && xerr == nil { fmt.Println("Both event and error are nil. Exiting...") return } // if ev != nil { // fmt.Printf("Event: %s\n", ev) // } if xerr != nil { fmt.Printf("Error: %s\n", xerr) } switch ev.(type) { case xproto.CreateNotifyEvent: createNotify(X, ev) fmt.Printf("Event: %s\n", ev) case xproto.DestroyNotifyEvent: destroyNotify(X, ev) fmt.Printf("Event: %s\n", ev) case xproto.MapRequestEvent: mapResquest(ev) case xproto.ConfigureNotifyEvent: configureNotify(X, ev) case xproto.PropertyNotifyEvent: fmt.Printf("Event: %s\n", ev) case xproto.ClientMessageEvent: clientMessage(X, ev) case xproto.ConfigureRequestEvent: configureRequest(X, ev) case xproto.UnmapNotifyEvent: unmapNotify(X, ev) default: log.Info("Event:", ev) } } // xevent.MapRequestFun( // func(X *xgbutil.XUtil, e xevent.MapRequestEvent) { // println(e.Window) // }).Connect(X, root.Id) // xevent.ConfigureNotifyFun( // func(X *xgbutil.XUtil, e xevent.ConfigureNotifyEvent) { // fmt.Printf("(%d, %d) %dx%d\n", e.X, e.Y, e.Width, e.Height) // }).Connect(X, root.Id) // xevent.FocusInFun( // func(X *xgbutil.XUtil, e xevent.FocusInEvent) { // fmt.Printf("(%v, %v)\n", e.Mode, e.Detail) // }).Connect(X, root.Id) // xevent.Main(X) }
func Initialize(x *xgbutil.XUtil, cmdEnv *gribble.Environment, hacks CommandHacks, configDir string) { var err error X = x Startup = true ConfigDir = configDir gribbleEnv = cmdEnv cmdHacks = hacks Root = xwindow.New(X, X.RootWin()) if _, err = Root.Geometry(); err != nil { logger.Error.Fatalf("Could not get ROOT window geometry: %s", err) } if Config, err = loadConfig(); err != nil { logger.Error.Fatalf("Could not load configuration: %s", err) } if Theme, err = loadTheme(); err != nil { logger.Error.Fatalf("Could not load theme: %s", err) } Clients = make(ClientList, 0, 50) Prompts = newPrompts() Heads = heads.NewHeads(X, Config.DefaultLayout) // If _NET_DESKTOP_NAMES is set, let's use workspaces from that instead. if names, _ := ewmh.DesktopNamesGet(X); len(names) > 0 { for _, wrkName := range names { if err := AddWorkspace(wrkName); err != nil { logger.Warning.Printf("Could not add workspace %s: %s", wrkName, err) } } } else { for _, wrkName := range Config.Workspaces { if err := AddWorkspace(wrkName); err != nil { logger.Error.Fatalf("Could not initialize workspaces: %s", err) } } } Heads.Initialize(Clients) keybindings() rootMouseSetup() StickyWrk = Heads.Workspaces.NewSticky() err = shape.Init(X.Conn()) if err != nil { ShapeExt = false logger.Warning.Printf("The X SHAPE extension could not be loaded. " + "Google Chrome might look ugly.") } else { ShapeExt = true } Restart = false ewmhClientList() ewmhNumberOfDesktops() ewmhCurrentDesktop() ewmhVisibleDesktops() ewmhDesktopNames() ewmhDesktopGeometry() }
func (app *RuntimeApp) attachXid(xid xproto.Window) { logger.Debugf("attach 0x%x to %s", xid, app.Id) if _, ok := app.xids[xid]; ok { logger.Debugf("0x%x is already on %s", xid, app.Id) return } xwin := xwindow.New(XU, xid) xwin.Listen(xproto.EventMaskPropertyChange | xproto.EventMaskStructureNotify | xproto.EventMaskVisibilityChange) winfo := &WindowInfo{Xid: xid} xevent.UnmapNotifyFun(func(XU *xgbutil.XUtil, ev xevent.UnmapNotifyEvent) { app.detachXid(xid) }).Connect(XU, xid) xevent.DestroyNotifyFun(func(XU *xgbutil.XUtil, ev xevent.DestroyNotifyEvent) { app.detachXid(xid) }).Connect(XU, xid) xevent.PropertyNotifyFun(func(XU *xgbutil.XUtil, ev xevent.PropertyNotifyEvent) { app.lock.Lock() defer app.lock.Unlock() switch ev.Atom { case ATOM_WINDOW_ICON: app.updateIcon(xid) app.updateAppid(xid) app.notifyChanged() case ATOM_WINDOW_NAME: if app.updateWMNameTimer != nil { app.updateWMNameTimer.Stop() app.updateWMNameTimer = nil } app.updateWMNameTimer = time.AfterFunc(time.Millisecond*20, func() { app.updateWmName(xid) app.updateAppid(xid) app.notifyChanged() app.updateWMNameTimer = nil }) case ATOM_WINDOW_STATE: logger.Debugf("%s(0x%x) WM_STATE is changed", app.Id, xid) if app.CurrentInfo.Xid == xid { logger.Debug("is current window info changed") app.updateState(xid) } app.notifyChanged() if HideModeType(setting.GetHideMode()) != HideModeSmartHide { break } time.AfterFunc(time.Millisecond*20, func() { app.updateOverlap(xid) }) // case ATOM_DEEPIN_WINDOW_VIEWPORTS: // app.updateViewports(xid) case ATOM_WINDOW_TYPE: if !isNormalWindow(ev.Window) { app.detachXid(xid) } case ATOM_DOCK_APP_ID: app.updateAppid(xid) app.notifyChanged() } }).Connect(XU, xid) update := func(xid xproto.Window) { app.lock.Lock() defer app.lock.Unlock() app.updateOverlap(xid) } xevent.ConfigureNotifyFun(func(XU *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { app.lock.Lock() defer app.lock.Unlock() if app.updateConfigureTimer != nil { app.updateConfigureTimer.Stop() app.updateConfigureTimer = nil } app.updateConfigureTimer = time.AfterFunc(time.Millisecond*20, func() { update(ev.Window) app.updateConfigureTimer = nil }) }).Connect(XU, xid) app.xids[xid] = winfo update(xid) app.updateIcon(xid) app.updateWmName(xid) app.updateState(xid) // app.updateViewports(xid) app.notifyChanged() }
// own requests ownership over the role of window manager in the current // X environment. It can fail if it does not successfully get ownership. // // When 'replace' is true, Wingo will attempt to replace an window manager // that is currently running. Otherwise, Wingo will quit if a window manager // is running. func own(X *xgbutil.XUtil, replace bool) error { otherWmRunning := false otherWmName := "" otherWmOwner := xproto.Window(xproto.WindowNone) xTime, err := currentTime(X) if err != nil { return err } selAtom, err := managerAtom(X) if err != nil { return err } // Check to see if we need to replace. If so, determine whether to // continue based on `replace`. reply, err := xproto.GetSelectionOwner(X.Conn(), selAtom).Reply() if err != nil { return err } if reply.Owner != xproto.WindowNone { otherWmRunning = true otherWmOwner = reply.Owner // Look for the window manager's name for a nicer error message. otherWmName, err = ewmh.GetEwmhWM(X) if err != nil || len(otherWmName) == 0 { otherWmName = "Unknown" } // We need to listen for DestroyNotify events on the selection // owner in case we need to replace the WM. owner := xwindow.New(X, reply.Owner) if err = owner.Listen(xproto.EventMaskStructureNotify); err != nil { return err } } if otherWmRunning { if !replace { return fmt.Errorf( "Another window manager (%s) is already running. Please use "+ "the '--replace' option to replace the current window "+ "manager with Wingo.", otherWmName) } else { logger.Message.Printf( "Waiting for %s to shutdown and transfer ownership to us.", otherWmName) } } logger.Message.Printf("Setting selection owner...") err = xproto.SetSelectionOwnerChecked( X.Conn(), X.Dummy(), selAtom, xTime).Check() if err != nil { return err } // Now we've got to make sure that we *actually* got ownership. logger.Message.Printf("Getting selection owner...") reply, err = xproto.GetSelectionOwner(X.Conn(), selAtom).Reply() if err != nil { return err } if reply.Owner != X.Dummy() { return fmt.Errorf( "Could not acquire ownership with SetSelectionOwner. "+ "GetSelectionOwner claims that '%d' is the owner, but '%d' "+ "needs to be.", reply.Owner, X.Dummy()) } // While X now acknowledges us as the selection owner, it's possible // that the window manager is misbehaving. ICCCM 2.8 calls for the previous // manager to destroy the selection owner when it's OK for us to take // over. Otherwise, listening to SubstructureRedirect on the root window // might fail if we move too quickly. timeout := time.After(3 * time.Second) if otherWmRunning { OTHER_WM_SHUTDOWN: for { select { case <-timeout: return fmt.Errorf( "Wingo failed to replace the currently running window "+ "manager (%s). Namely, Wingo was not able to detect "+ "that the current window manager had shut down.", otherWmName) default: logger.Message.Printf("Polling for event...") ev, err := X.Conn().PollForEvent() if err != nil { continue } logger.Message.Printf("Got event, error: %s -- %s", ev, err) if destNotify, ok := ev.(xproto.DestroyNotifyEvent); ok { if destNotify.Window == otherWmOwner { break OTHER_WM_SHUTDOWN } } time.Sleep(100 * time.Millisecond) } } } logger.Message.Println("Wingo has window manager ownership!") announce(X) // Listen for SelectionClear events. When we get one of these, then we // know a window manager is trying to replace us. xevent.SelectionClearFun(disown).Connect(X, X.Dummy()) return nil }
func main() { var err error X, err = xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Println("Error connecting to X, quitting...") return } defer X.Conn().Close() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) wingo = newWingoState() // Create a root window abstraction and load its geometry wingo.root = xwindow.New(X, X.RootWin()) _, err = wingo.root.Geometry() if err != nil { logger.Error.Println("Could not get ROOT window geometry because: %v", err) logger.Error.Println("Cannot continue. Quitting...") return } // Load configuration wingo.conf, err = loadConfig() if err != nil { logger.Error.Println(err) logger.Error.Println("No configuration found. Quitting...") return } // Load theme wingo.theme, err = loadTheme(X) if err != nil { logger.Error.Println(err) logger.Error.Println("No theme configuration found. Quitting...") return } // Initialize prompts wingo.prompts = newPrompts() wingo.initializeHeads() // Attach all global key bindings attachAllKeys() // Attach all root mouse bindings rootMouseConfig() // Setup some cursors we use cursors.Setup(X) // Listen to Root. It is all-important. wingo.root.Listen(xproto.EventMaskPropertyChange | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect) // Update state when the root window changes size // xevent.ConfigureNotifyFun(rootGeometryChange).Connect(X, wingo.root.Id) // Oblige map request events xevent.MapRequestFun( func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) { newClient(X, ev.Window) }).Connect(X, wingo.root.Id) // Oblige configure requests from windows we don't manage. xevent.ConfigureRequestFun( func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) { flags := int(ev.ValueMask) & ^int(xproto.ConfigWindowSibling) & ^int(xproto.ConfigWindowStackMode) xwindow.New(X, ev.Window).Configure(flags, int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height), ev.Sibling, ev.StackMode) }).Connect(X, wingo.root.Id) // Listen to Root client message events. // We satisfy EWMH with these AND it also provides a mechanism // to issue commands using wingo-cmd. xevent.ClientMessageFun(commandHandler).Connect(X, wingo.root.Id) xevent.Main(X) }
// Root emulates focus of the root window. // // N.B. Technically, a special off-screen window maintained by Wingo gets // focus, but you won't be able to tell the difference. (I hope.) func Root() { for _, c := range Clients { c.Unfocused() } xwindow.New(X, X.Dummy()).Focus() }
func (m *ClientManager) listenRootWindow() { var update = func() { list, err := ewmh.ClientListGet(XU) if err != nil { logger.Warning("Can't Get _NET_CLIENT_LIST", err) } isLauncherShown = false for _, xid := range list { if !isDeepinLauncher(xid) { continue } winProps, err := xproto.GetWindowAttributes(XU.Conn(), xid).Reply() if err != nil { break } if winProps.MapState == xproto.MapStateViewable { isLauncherShown = true } break } ENTRY_MANAGER.runtimeAppChanged(list) } xwindow.New(XU, XU.RootWin()).Listen(xproto.EventMaskPropertyChange) xevent.PropertyNotifyFun(func(XU *xgbutil.XUtil, ev xevent.PropertyNotifyEvent) { switch ev.Atom { case _NET_CLIENT_LIST: update() case _NET_ACTIVE_WINDOW: var err error isLauncherShown = false if activeWindow, err = ewmh.ActiveWindowGet(XU); err == nil { appId := find_app_id_by_xid(activeWindow, DisplayModeType(setting.GetDisplayMode())) logger.Debug("current active window:", appId) if rApp, ok := ENTRY_MANAGER.runtimeApps[appId]; ok { logger.Debug("find runtime app") rApp.setLeader(activeWindow) rApp.updateState(activeWindow) } logger.Debug("active window is", appId) if appId != DDELauncher { LAUNCHER, err := launcher.NewLauncher( "com.deepin.dde.launcher", "/com/deepin/dde/launcher", ) if err != nil { logger.Debug(err) } else { LAUNCHER.Hide() launcher.DestroyLauncher(LAUNCHER) } } else { isLauncherShown = true } lastActive = appId dbus.Emit(m, "ActiveWindowChanged", uint32(activeWindow)) } hideMode := HideModeType(setting.GetHideMode()) if hideMode == HideModeSmartHide || hideMode == HideModeKeepHidden { hideModemanager.UpdateState() } case _NET_SHOWING_DESKTOP: dbus.Emit(m, "ShowingDesktopChanged") case DEEPIN_SCREEN_VIEWPORT: updateCurrentViewport() } }).Connect(XU, XU.RootWin()) update() xevent.Main(XU) }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Wrap the root window in a nice Window type. root := xwindow.New(X, X.RootWin()) // Get the geometry of the root window. rgeom, err := root.Geometry() if err != nil { log.Fatal(err) } // Get the rectangles for each of the active physical heads. // These are returned sorted in order from left to right and then top // to bottom. // But first check if Xinerama is enabled. If not, use root geometry. var heads xinerama.Heads if X.ExtInitialized("XINERAMA") { heads, err = xinerama.PhysicalHeads(X) if err != nil { log.Fatal(err) } } else { heads = xinerama.Heads{rgeom} } // Fetch the list of top-level client window ids currently managed // by the running window manager. clients, err := ewmh.ClientListGet(X) if err != nil { log.Fatal(err) } // Output the head geometry before modifying them. fmt.Println("Workarea for each head:") for i, head := range heads { fmt.Printf("\tHead #%d: %s\n", i+1, head) } // For each client, check to see if it has struts, and if so, apply // them to our list of head rectangles. for _, clientid := range clients { strut, err := ewmh.WmStrutPartialGet(X, clientid) if err != nil { // no struts for this client continue } // Apply the struts to our heads. // This modifies 'heads' in place. xrect.ApplyStrut(heads, uint(rgeom.Width()), uint(rgeom.Height()), strut.Left, strut.Right, strut.Top, strut.Bottom, strut.LeftStartY, strut.LeftEndY, strut.RightStartY, strut.RightEndY, strut.TopStartX, strut.TopEndX, strut.BottomStartX, strut.BottomEndX) } // Now output the head geometry again after modification. fmt.Println("Workarea for each head after applying struts:") for i, head := range heads { fmt.Printf("\tHead #%d: %s\n", i+1, head) } }
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 { 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 (self *SessionModule) GetWindow(window_id string) (SessionWindow, error) { window := SessionWindow{} if id, err := self.toX11WindowId(window_id); err == nil { xgbWindow := xwindow.New(self.X, id) geom, _ := xgbWindow.DecorGeometry() process := SessionProcess{} window.ID = uint32(id) window.Title, _ = ewmh.WmNameGet(self.X, id) //window.IconUri = r.Path() + "/" + id windowWorkspace, _ := ewmh.WmDesktopGet(self.X, id) activeWinId, _ := ewmh.ActiveWindowGet(self.X) if windowWorkspace == 0xFFFFFFFF { window.AllWorkspaces = true } else { window.Workspace = windowWorkspace } if id == activeWinId { window.Active = true } // calculate window dimensions from desktop and window frame boundaries window.Dimensions.Width = uint(geom.Width()) window.Dimensions.Height = uint(geom.Height()) window.Dimensions.X = geom.X() window.Dimensions.Y = geom.Y() // fill in process details process.PID, _ = ewmh.WmPidGet(self.X, id) window.Process = process // get window state flags window.Flags = make(map[string]bool) // minimized if self.x11HasWmState(id, `_NET_WM_STATE_HIDDEN`) { window.Flags["minimized"] = true } // shaded if self.x11HasWmState(id, `_NET_WM_STATE_SHADED`) { window.Flags[`shaded`] = true } // maximized if self.x11HasWmState(id, `_NET_WM_STATE_MAXIMIZED_VERT`) && self.x11HasWmState(id, `_NET_WM_STATE_MAXIMIZED_HORZ`) { window.Flags[`maximized`] = true } // above if self.x11HasWmState(id, `_NET_WM_STATE_ABOVE`) { window.Flags[`above`] = true } // below if self.x11HasWmState(id, `_NET_WM_STATE_BELOW`) { window.Flags[`below`] = true } // urgent if self.x11HasWmState(id, `_NET_WM_STATE_DEMANDS_ATTENTION`) { window.Flags[`urgent`] = true } // skip_taskbar if self.x11HasWmState(id, `_NET_WM_STATE_SKIP_TASKBAR`) { window.Flags[`skip_taskbar`] = true } // skip_pager if self.x11HasWmState(id, `_NET_WM_STATE_SKIP_PAGER`) { window.Flags[`skip_pager`] = true } // sticky if self.x11HasWmState(id, `_NET_WM_STATE_STICKY`) { window.Flags[`sticky`] = true } // fullscreen if self.x11HasWmState(id, `_NET_WM_STATE_FULLSCREEN`) { window.Flags[`fullscreen`] = true } // modal if self.x11HasWmState(id, `_NET_WM_STATE_MODAL`) { window.Flags[`modal`] = true } // ICCCM WM_CLASS instance if wmClass, err := icccm.WmClassGet(self.X, id); err == nil { window.ClassInstance = wmClass.Instance window.ClassName = wmClass.Class if entry, ok := self.Applications.Entries[window.ClassInstance]; ok { window.EntryName = entry.Key } } return window, nil } else { return window, err } }