Exemple #1
0
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)
}
Exemple #2
0
// 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)
}
Exemple #4
0
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)
}
Exemple #6
0
// 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()
}