Example #1
0
// Replace existing window manager
func usurpWM(X *xgb.Conn, screen *xproto.ScreenInfo) {
	wmName := fmt.Sprintf("WM_S%d", X.DefaultScreen)
	managerAtom, err := xproto.InternAtom(X, true, uint16(len(wmName)), wmName).Reply()
	if err != nil {
		log.Fatal(err)
	}

	fakeWindow, _ := xproto.NewWindowId(X)
	xproto.CreateWindow(X, // Connection
		screen.RootDepth, // Depth
		fakeWindow,       // Window Id
		screen.Root,      // Parent Window
		-1000, -1000,     // x, y
		1, 1, // width, height
		0, // border_width
		xproto.WindowClassInputOutput, // class
		screen.RootVisual,             // visual
		xproto.CwEventMask|xproto.CwOverrideRedirect,
		[]uint32{1, xproto.EventMaskPropertyChange}) // masks
	xproto.MapWindow(X, fakeWindow)
	err = xproto.SetSelectionOwnerChecked(X, fakeWindow, managerAtom.Atom, xproto.TimeCurrentTime).Check()
	if err != nil {
		log.Fatal(err)
	}
}
Example #2
0
func (m *TrayManager) tryOwner() bool {
	// Make a check, the tray application MUST be 1.
	reply, err := m.getSelectionOwner()
	if err != nil {
		logger.Error(err)
		return false
	}
	if reply.Owner != 0 {
		logger.Warning("Another System tray application is running")
		return false
	}

	timeStamp, _ := ewmh.WmUserTimeGet(TrayXU, m.owner)
	err = xproto.SetSelectionOwnerChecked(
		TrayXU.Conn(),
		m.owner,
		_NET_SYSTEM_TRAY_S0,
		xproto.Timestamp(timeStamp),
	).Check()
	if err != nil {
		logger.Warning("Set Selection Owner failed: ", err)
		return false
	}

	//owner the _NET_SYSTEM_TRAY_Sn
	logger.Info("Required _NET_SYSTEM_TRAY_S0 successful")

	m.RequireManageTrayIcons()

	xprop.ChangeProp32(
		TrayXU,
		m.owner,
		"_NET_SYSTEM_TRAY_VISUAL",
		"VISUALID",
		uint(TRAYMANAGER.visual),
	)
	xprop.ChangeProp32(
		TrayXU,
		m.owner,
		"_NET_SYSTEM_TRAY_ORIENTAION",
		"CARDINAL",
		0,
	)
	reply, err = m.getSelectionOwner()
	if err != nil {
		logger.Warning(err)
		return false
	}
	return reply.Owner != 0
}
Example #3
0
func initXSettings() {
	a0 := internAtom("_XSETTINGS_S0")
	if err := xp.SetSelectionOwnerChecked(xConn, desktopXWin, a0,
		xp.TimeCurrentTime).Check(); err != nil {
		log.Printf("could not set xsettings: %v", err)
		return
	}
	a1 := internAtom("_XSETTINGS_SETTINGS")
	encoded := makeEncodedXSettings()
	if err := xp.ChangePropertyChecked(xConn, xp.PropModeReplace, desktopXWin, a1, a1,
		8, uint32(len(encoded)), encoded).Check(); err != nil {
		log.Printf("could not set xsettings: %v", err)
		return
	}
}
Example #4
0
func (m *TrayManager) Unmanage() bool {
	reply, err := m.getSelectionOwner()
	if err != nil {
		logger.Warning("get selection owner failed:", err)
		return false
	}
	if reply.Owner != m.owner {
		logger.Warning("not selection owner")
		return false
	}

	m.destroyOwnerWindow()
	trayicons := m.TrayIcons
	for _, icon := range trayicons {
		m.removeTrayIcon(xproto.Window(icon))
	}
	timeStamp, _ := ewmh.WmUserTimeGet(TrayXU, m.owner)
	return xproto.SetSelectionOwnerChecked(
		TrayXU.Conn(),
		0,
		_NET_SYSTEM_TRAY_S0,
		xproto.Timestamp(timeStamp),
	).Check() == nil
}
Example #5
0
// 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
}
Example #6
0
func New(X *xgbutil.XUtil) (*SystemTray, error) {
	tray := &SystemTray{
		X: X,
	}

	var err error

	if sysTrayAtom == 0 {
		sysTrayAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_S0", false)

		if err != nil {
			return nil, err
		}
	}

	if sysTrayMsgAtom == 0 {
		sysTrayMsgAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_OPCODE", false)

		if err != nil {
			return nil, err
		}
	}

	if managerEventAtom == 0 {
		managerEventAtom, err = xprop.Atom(X, "MANAGER", false)

		if err != nil {
			return nil, err
		}
	}

	tray.wid, err = xwindow.Create(X, X.RootWin())

	if err != nil {
		return nil, err
	}

	ts, err := currentTime(X)

	if err != nil {
		return nil, err
	}

	X.TimeSet(ts)

	// tray.wid.Listen(xproto.EventMaskNoEvent | xproto.EventMaskPropertyChange)

	err = xproto.SetSelectionOwnerChecked(tray.X.Conn(), tray.wid.Id, sysTrayAtom, tray.X.TimeGet()).Check()

	if err != nil {
		return nil, err
	}

	reply, err := xproto.GetSelectionOwner(X.Conn(), sysTrayAtom).Reply()
	if err != nil {
		return nil, err
	}

	if reply.Owner != tray.wid.Id {
		return nil, fmt.Errorf("Could not get ownership of the thingy-thing.")
	}

	evt, err := xevent.NewClientMessage(32, X.RootWin(), managerEventAtom,
		int(X.TimeGet()), int(sysTrayAtom), int(tray.wid.Id))

	if err != nil {
		return nil, err
	}

	if err = xevent.SendRootEvent(X, evt, xproto.EventMaskStructureNotify); err != nil {
		return nil, err
	}

	xevent.ClientMessageFun(func(_ *xgbutil.XUtil, ev xevent.ClientMessageEvent) {
		tray.event(ev)
	}).Connect(tray.X, tray.wid.Id)

	return tray, nil
}
Example #7
0
func (tray *SystemTray) Teardown() error {
	// TODO: Tray Icon Tracking?

	currentTime(tray.X)
	return xproto.SetSelectionOwnerChecked(tray.X.Conn(), xproto.WindowNone, sysTrayAtom, tray.X.TimeGet()).Check()
}
Example #8
0
func main() {
	// Open the connection to the X server
	X, err := xgb.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	defer X.Close()

	setup := xproto.Setup(X)
	// Get the first screen
	screen := setup.DefaultScreen(X)

	// Replace existing window manager
	wmName := fmt.Sprintf("WM_S%d", X.DefaultScreen)
	managerAtom, err := xproto.InternAtom(X, true, uint16(len(wmName)), wmName).Reply()
	if err != nil {
		log.Fatal(err)
	}

	fakeWindow, _ := xproto.NewWindowId(X)
	xproto.CreateWindow(X, // Connection
		screen.RootDepth, // Depth
		fakeWindow,       // Window Id
		screen.Root,      // Parent Window
		-1000, -1000,     // x, y
		1, 1, // width, height
		0, // border_width
		xproto.WindowClassInputOutput, // class
		screen.RootVisual,             // visual
		xproto.CwEventMask|xproto.CwOverrideRedirect,
		[]uint32{1, xproto.EventMaskPropertyChange}) // masks
	xproto.MapWindow(X, fakeWindow)
	err = xproto.SetSelectionOwnerChecked(X, fakeWindow, managerAtom.Atom, xproto.TimeCurrentTime).Check()
	if err != nil {
		fmt.Println("foo")
		log.Fatal(err)
	}

	arcs := []xproto.Arc{
		{10, 100, 60, 40, 0, 90 << 6},
		{90, 100, 55, 40, 0, 270 << 6}}

	// Create black (foreground) graphic context
	foreground, _ := xproto.NewGcontextId(X)
	mask := uint32(xproto.GcForeground | xproto.GcGraphicsExposures)
	values := []uint32{screen.BlackPixel, 0}
	xproto.CreateGC(X, foreground, xproto.Drawable(screen.Root), mask, values)

	// Ask for our window's Id
	win, _ := xproto.NewWindowId(X)
	winDrawable := xproto.Drawable(win)

	// Create the window
	mask = uint32(xproto.CwBackPixel | xproto.CwEventMask)
	values = []uint32{screen.WhitePixel, xproto.EventMaskExposure}
	xproto.CreateWindow(X, // Connection
		screen.RootDepth, // Depth
		win,              // Window Id
		screen.Root,      // Parent Window
		0, 0,             // x, y
		150, 150, // width, height
		10, // border_width
		xproto.WindowClassInputOutput, // class
		screen.RootVisual,             // visual
		mask, values)                  // masks

	// Map the window on the screen
	xproto.MapWindow(X, win)

	// Obey the window-delete protocol
	tp := "WM_PROTOCOLS"
	prp := "WM_DELETE_WINDOW"
	typeAtom, _ := xproto.InternAtom(X, true, uint16(len(tp)), tp).Reply()
	propertyAtom, _ := xproto.InternAtom(X, true, uint16(len(prp)), prp).Reply()

	data := make([]byte, 4)
	xgb.Put32(data, uint32(propertyAtom.Atom))
	xproto.ChangeProperty(X, xproto.PropModeReplace, win, typeAtom.Atom, xproto.AtomAtom, 32, 1, data)

	// Main loop
	for {
		evt, err := X.WaitForEvent()
		fmt.Printf("An event of type %T occured.\n", evt)

		if evt == nil && err == nil {
			fmt.Println("Exiting....")
			return
		} else if err != nil {
			log.Fatal(err)
		}

		switch event := evt.(type) {
		case xproto.ExposeEvent:
			/* We draw the arcs */
			xproto.PolyArc(X, winDrawable, foreground, arcs)
		case xproto.ClientMessageEvent:
			if len(event.Data.Data32) > 0 {
				data := xproto.Atom(event.Data.Data32[0])
				if data == propertyAtom.Atom {
					return
				} else {
					atomName, _ := xproto.GetAtomName(X, data).Reply()
					fmt.Println(atomName.Name)
				}
			} else {
				atomName, _ := xproto.GetAtomName(X, event.Type).Reply()
				fmt.Println(atomName.Name)
			}
		default:
			/* Unknown event type, ignore it */
		}
	}
	return
}