// GetFormat searches SetupInfo for a Format matching the depth provided. func GetFormat(X *xgbutil.XUtil, depth byte) *xproto.Format { for _, pixForm := range X.Setup().PixmapFormats { if pixForm.Depth == depth { return &pixForm } } return nil }
// checkCompatibility reads info in the X setup info struct and emits // messages to stderr if they don't correspond to values that xgraphics // supports. // The idea is that in the future, we'll support more values. // The real reason for checkCompatibility is to make debugging easier. Without // it, if the values weren't what we'd expect, we'd see garbled images in the // best case, and probably BadLength errors in the worst case. func checkCompatibility(X *xgbutil.XUtil) { s := X.Setup() scrn := X.Screen() failed := false if s.ImageByteOrder != xproto.ImageOrderLSBFirst { log.Printf("Your X server uses MSB image byte order. Unfortunately, " + "xgraphics currently requires LSB image byte order. You may see " + "weird things. Please report this.") failed = true } if s.BitmapFormatBitOrder != xproto.ImageOrderLSBFirst { log.Printf("Your X server uses MSB bitmap bit order. Unfortunately, " + "xgraphics currently requires LSB bitmap bit order. If you " + "aren't using X bitmaps, you should be able to proceed normally. " + "Please report this.") failed = true } if s.BitmapFormatScanlineUnit != 32 { log.Printf("xgraphics expects that the scanline unit is set to 32, "+ "but your X server has it set to '%d'. "+ "Namely, xgraphics hasn't been tested on other values. Things "+ "may still work. Particularly, if you aren't using X bitmaps, "+ "you should be completely unaffected. Please report this.", s.BitmapFormatScanlineUnit) failed = true } if scrn.RootDepth != 24 { log.Printf("xgraphics expects that the root window has a depth of 24, "+ "but yours has depth '%d'. Its possible things will still work "+ "if your value is 32, but will be unlikely to work with values "+ "less than 24. Please report this.", scrn.RootDepth) failed = true } // Look for the default format for pixmaps and make sure bits per pixel // is 32. format := xgraphics.GetFormat(X, scrn.RootDepth) if format.BitsPerPixel != 32 { log.Printf("xgraphics expects that the bits per pixel for the root "+ "window depth is 32. On your system, the root depth is %d and "+ "the bits per pixel is %d. Things will most certainly not work. "+ "Please report this.", scrn.RootDepth, format.BitsPerPixel) failed = true } // Give instructions on reporting the issue. if failed { log.Printf("Please report the aforementioned error message(s) at " + "https://github.com/BurntSushi/xgbutil. Please also include the " + "entire output of the `xdpyinfo` command in your report. Thanks!") } else { log.Printf("No compatibility issues detected.") } }
// minMaxKeycodeGet a simple accessor to the X setup info to return the // minimum and maximum keycodes. They are typically 8 and 255, respectively. func minMaxKeycodeGet(xu *xgbutil.XUtil) (xproto.Keycode, xproto.Keycode) { return xu.Setup().MinKeycode, xu.Setup().MaxKeycode }
// readDrawableData uses Format information to read data from an X pixmap // into an xgraphics.Image. // readPixmapData does not take into account all information possible to read // X pixmaps and bitmaps. Of particular note is bit order/byte order. func readDrawableData(X *xgbutil.XUtil, ximg *Image, did xproto.Drawable, imgData *xproto.GetImageReply, width, height int) error { format := GetFormat(X, imgData.Depth) if format == nil { return fmt.Errorf("Could not find valid format for pixmap %d "+ "with depth %d", did, imgData.Depth) } switch format.Depth { case 1: // We read bitmaps in as alpha masks. if format.BitsPerPixel != 1 { return fmt.Errorf("The image returned for pixmap id %d with "+ "depth %d has an unsupported value for bits-per-pixel: %d", did, format.Depth, format.BitsPerPixel) } // Calculate the padded width of our image data. pad := int(X.Setup().BitmapFormatScanlinePad) paddedWidth := width if width%pad != 0 { paddedWidth = width + pad - (width % pad) } // Process one scanline at a time. Each 'y' represents a // single scanline. for y := 0; y < height; y++ { // Each scanline has length 'width' padded to // BitmapFormatScanlinePad, which is found in the X setup info. // 'i' is the index to the starting byte of the yth scanline. i := y * paddedWidth / 8 for x := 0; x < width; x++ { b := imgData.Data[i+x/8] >> uint(x%8) if b&1 > 0 { // opaque ximg.Set(x, y, BGRA{0x0, 0x0, 0x0, 0xff}) } else { // transparent ximg.Set(x, y, BGRA{0xff, 0xff, 0xff, 0x0}) } } } case 24: if format.BitsPerPixel != 24 && format.BitsPerPixel != 32 { return fmt.Errorf("The image returned for pixmap id %d has "+ "an unsupported value for bits-per-pixel: %d", did, format.BitsPerPixel) } bytesPer := int(format.BitsPerPixel) / 8 var i int ximg.For(func(x, y int) BGRA { i = y*width*bytesPer + x*bytesPer return BGRA{ B: imgData.Data[i], G: imgData.Data[i+1], R: imgData.Data[i+2], A: 0xff, } }) default: return fmt.Errorf("The image returned for pixmap id %d has an "+ "unsupported value for depth: %d", did, format.Depth) } return nil }