func RootGeomChangeFun() xevent.ConfigureNotifyFun { f := func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { // Before trying to reload, make sure we have enough workspaces... // We don't want to die here like we might on start up. for i := len(Heads.Workspaces.Wrks); i < Heads.NumConnected(); i++ { AddWorkspace(uniqueWorkspaceName()) } Heads.Reload(Clients) FocusFallback() ewmhVisibleDesktops() ewmhDesktopGeometry() } return xevent.ConfigureNotifyFun(f) }
// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. func (w *Window) setupEventHandlers(chans chans) { w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). if _, err := w.Geometry(); err != nil { errLg.Fatal(err) } // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { chans.ctl <- []string{"pan", "origin"} }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { chans.panStepChan <- image.Point{ex, ey} }, // We do nothing on mouse release func(X *xgbutil.XUtil, rx, ry, ex, ey int) { return }) for _, kb := range keybinds { k := kb // Needed because the callback closure will capture kb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { chans.ctl <- k.command }).Connect(w.X, w.Id, k.key, false) if err != nil { errLg.Println(err) } } }
func newGradientWindow(width, height int) { win := createWindow() xproto.ConfigureWindow( X.Conn(), win, xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, []uint32{uint32(width), uint32(height)}) xwindow.Listen(X, win, xproto.EventMaskStructureNotify) xproto.MapWindow(X.Conn(), win) xgraphics.PaintImg(X, win, gradient(width, height)) xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { img := gradient(int(ev.Width), int(ev.Height)) log.Printf("Painting new image (%d, %d)", ev.Width, ev.Height) xgraphics.PaintImg(X, win, img) }).Connect(X, win) }
func newWindow(X *xgbutil.XUtil, width, height int) *xwindow.Window { var ( err error win *xwindow.Window ) win, err = xwindow.Generate(X) if err != nil { log.Fatal(err) } win.Create(X.RootWin(), 0, 0, width, height, xproto.CwBackPixel|xproto.CwEventMask, 0, xproto.EventMaskButtonRelease) win.WMGracefulClose( func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) // w.Destroy() xevent.Quit(X) application.Exit() }) // In order to get ConfigureNotify events, we must listen to the window // using the 'StructureNotify' mask. win.Listen(xproto.EventMaskStructureNotify) win.Map() xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { reshape(int(ev.Width), int(ev.Height)) }).Connect(X, win.Id) // err = mousebind.ButtonReleaseFun( // func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) { // newWindow(X) // }).Connect(X, win.Id, "1", false, false) if err != nil { log.Fatal(err) } return win }
// newGradientWindow creates a new X window, paints the initial gradient // image, and listens for ConfigureNotify events. (A new gradient image must // be painted in response to each ConfigureNotify event, since a // ConfigureNotify event corresponds to a change in the window's geometry.) func newGradientWindow(X *xgbutil.XUtil, width, height int, start, end color.RGBA) { // Generate a new window id. win, err := xwindow.Generate(X) if err != nil { log.Fatal(err) } // Create the window and die if it fails. err = win.CreateChecked(X.RootWin(), 0, 0, width, height, 0) if err != nil { log.Fatal(err) } // In order to get ConfigureNotify events, we must listen to the window // using the 'StructureNotify' mask. win.Listen(xproto.EventMaskStructureNotify) // Paint the initial gradient to the window and then map the window. paintGradient(X, win.Id, width, height, start, end) win.Map() xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { // If the width and height have not changed, skip this one. if int(ev.Width) == width && int(ev.Height) == height { return } // Compress ConfigureNotify events so that we don't lag when // drawing gradients in response. ev = compressConfigureNotify(X, ev) // Update the width and height and paint the gradient image. width, height = int(ev.Width), int(ev.Height) paintGradient(X, win.Id, width, height, start, end) }).Connect(X, win.Id) }
// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. Should // these be configurable? Meh. func (w *window) setupEventHandlers(chans chans) { w.chans = chans w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). _, err := w.Geometry() if err != nil { errLg.Fatal(err) } // And ask the canvas to draw the first image when it gets around to it. go func() { w.chans.drawChan <- func(origin image.Point) image.Point { return image.Point{} } }() // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { w.chans.drawChan <- func(origin image.Point) image.Point { return origin } }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { w.chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panStepChan <- image.Point{ex, ey} }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panEndChan <- image.Point{ex, ey} }) // Set up a map of keybindings to avoid a lot of boiler plate. // for keystring, fun := range kbs { for _, keyb := range keybinds { keyb := keyb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { keyb.action(w) }).Connect(w.X, w.Id, keyb.key, false) if err != nil { errLg.Println(err) } } }
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() }