From 0f7fcca7cea7682f0d1db65a277c43be2ab9dcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sun, 19 Aug 2018 18:05:53 +0200 Subject: [PATCH] xgb-xrender: add a basic demo for XRender So far just a conversion of xgb-window.go. --- prototypes/xgb-xrender.go | 176 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 prototypes/xgb-xrender.go diff --git a/prototypes/xgb-xrender.go b/prototypes/xgb-xrender.go new file mode 100644 index 0000000..73b5fed --- /dev/null +++ b/prototypes/xgb-xrender.go @@ -0,0 +1,176 @@ +package main + +import ( + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/render" + "github.com/BurntSushi/xgb/xproto" + "log" + "math/rand" +) + +func F64ToFixed(f float64) render.Fixed { return render.Fixed(f * 65536) } +func FixedToF64(f render.Fixed) float64 { return float64(f) / 65536 } + +func main() { + X, err := xgb.NewConn() + if err != nil { + log.Fatalln(err) + } + + if err := render.Init(X); err != nil { + log.Fatalln(err) + } + + setup := xproto.Setup(X) + screen := setup.DefaultScreen(X) + + var visual xproto.Visualid + var depth byte + for _, i := range screen.AllowedDepths { + if i.Depth == 32 { + // TODO: Could/should check other parameters. + for _, v := range i.Visuals { + if v.Class == xproto.VisualClassTrueColor { + visual = v.VisualId + depth = i.Depth + break + } + } + } + } + if visual == 0 { + log.Fatalln("cannot find an RGBA TrueColor visual") + } + + mid, err := xproto.NewColormapId(X) + if err != nil { + log.Fatalln(err) + } + + _ = xproto.CreateColormap( + X, xproto.ColormapAllocNone, mid, screen.Root, visual) + + wid, err := xproto.NewWindowId(X) + if err != nil { + log.Fatalln(err) + } + + // Border pixel and colormap are required when depth differs from parent. + _ = xproto.CreateWindow(X, depth, wid, screen.Root, + 0, 0, 500, 500, 0, xproto.WindowClassInputOutput, + visual, xproto.CwBorderPixel|xproto.CwColormap, + []uint32{0, uint32(mid)}) + + // This could be included in CreateWindow parameters. + _ = xproto.ChangeWindowAttributes(X, wid, + xproto.CwBackPixel|xproto.CwEventMask, []uint32{0x80808080, + xproto.EventMaskStructureNotify | xproto.EventMaskKeyPress | + xproto.EventMaskExposure}) + + title := []byte("Gradient") + _ = xproto.ChangeProperty(X, xproto.PropModeReplace, wid, xproto.AtomWmName, + xproto.AtomString, 8, uint32(len(title)), title) + + _ = xproto.MapWindow(X, wid) + + pformats, err := render.QueryPictFormats(X).Reply() + if err != nil { + log.Fatalln(err) + } + + // Similar to XRenderFindVisualFormat. + // The DefaultScreen is almost certain to be zero. + var pformat render.Pictformat + for _, pd := range pformats.Screens[X.DefaultScreen].Depths { + // This check seems to be slightly extraneous. + if pd.Depth != depth { + continue + } + for _, pv := range pd.Visuals { + if pv.Visual == visual { + pformat = pv.Format + } + } + } + + // ...or just scan through pformats.Formats and look for matches, which is + // what XRenderFindStandardFormat in Xlib does as well as exp/shiny. + + pid, err := render.NewPictureId(X) + if err != nil { + log.Fatalln(err) + } + render.CreatePicture(X, pid, xproto.Drawable(wid), pformat, 0, []uint32{}) + + // Reserve an ID for the gradient. + gid, err := render.NewPictureId(X) + if err != nil { + log.Fatalln(err) + } + + var from, to render.Color + recolor := func() { + start := rand.Uint32() & 0xffffff + from = render.Color{ + Red: 0x101 * uint16((start>>16)&0xff), + Green: 0x101 * uint16((start>>8)&0xff), + Blue: 0x101 * uint16(start&0xff), + Alpha: 0xffff, + } + + end := rand.Uint32() & 0xffffff + to = render.Color{ + Red: 0x101 * uint16((end>>16)&0xff), + Green: 0x101 * uint16((end>>8)&0xff), + Blue: 0x101 * uint16(end&0xff), + Alpha: 0xffff, + } + } + + var w, h uint16 + gradient := func() { + if w < 100 || h < 100 { + return + } + + _ = render.CreateLinearGradient(X, gid, + render.Pointfix{F64ToFixed(0), F64ToFixed(0)}, + render.Pointfix{F64ToFixed(0), F64ToFixed(float64(h) - 100)}, + 2, []render.Fixed{F64ToFixed(0), F64ToFixed(1)}, + []render.Color{from, to}) + + _ = render.Composite(X, render.PictOpSrc, gid, render.PictureNone, pid, + 0, 0, 0, 0, 50, 50, w-100, h-100) + + _ = render.FreePicture(X, gid) + } + + for { + ev, xerr := X.WaitForEvent() + if xerr != nil { + log.Printf("Error: %s\n", xerr) + return + } + if ev == nil { + return + } + + log.Printf("Event: %s\n", ev) + switch e := ev.(type) { + case xproto.UnmapNotifyEvent: + return + + case xproto.ConfigureNotifyEvent: + w, h = e.Width, e.Height + recolor() + + case xproto.KeyPressEvent: + recolor() + gradient() + + case xproto.ExposeEvent: + gradient() + } + } + +}