Giter Club home page Giter Club logo

xgbutil's Introduction

xgbutil is a utility library designed to work with the X Go Binding. This
project's main goal is to make various X related tasks easier. For example,
binding keys, using the EWMH or ICCCM specs with the window manager,
moving/resizing windows, assigning function callbacks to particular events,
drawing images to a window, etc.

xgbutil attempts to be thread safe, but it has not been completely tested in
this regard. In general, the X event loop implemented in the xevent package is
sequential. The idea is to be sequential by default, and let the user spawn
concurrent code at their discretion. (i.e., the complexity of making the main
event loop generally concurrent is vast.)

You may sleep safely at night by assuming that XGB is thread safe, though.

To start using xgbutil, you should have at least a passing familiarity with X.
Your first stop should be the examples directory.

Installation
============
go get github.com/BurntSushi/xgbutil

Dependencies
============
XGB is the main dependency. Use of the xgraphics packages requires graphics-go
and freetype-go.

XGB project URL: https://github.com/BurntSushi/xgb

Quick Example
=============
go get github.com/BurntSushi/xgbutil/_examples/window-name-sizes
"$GOPATH"/bin/window-name-sizes

The output will be a list of names of all top-level windows and their geometry
including window manager decorations. (Assuming your window manager supports
some basic EWMH properties.)

Documentation
=============
https://godoc.org/github.com/BurntSushi/xgbutil

Examples
========
There are several examples in the examples directory covering common use cases.
They are heavily documented and should run out of the box.

Python
======
An older project of mine, xpybutil, served as inspiration for xgbutil. If you
want to use Python, xpybutil should help quite a bit. Please note though, that
at this point, xgbutil provides a lot more functionality and is much better
documented.

xpybutil project URL: https://github.com/BurntSushi/xpybutil

xgbutil's People

Contributors

aarzilli avatar baskerville avatar burntsushi avatar dominikh avatar droundy avatar harryfei avatar knivey avatar snyh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xgbutil's Issues

WmClassGet failed

well, i used WmClassGet to get the instance name and class name of yozo office, however, i get an error:
WmClass: Two string make up WM_CLASS, but xgbutil found 1...

I first thought this might be the bug of xcb, so I try to get WmClass with xcb.

xcb_connection_t *c = xcb_connect (NULL, NULL);
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_class(c, xid);
xcb_get_property_reply_t* rep = xcb_get_property_reply(c, cookie, NULL);

xcb_icccm_get_wm_class_reply_t prop;
xcb_icccm_get_wm_class_from_reply(&prop, rep);
printf("%s %s\n", prop.instance_name, prop.class_name);

the output is:
sun-awt-X11-XFramePeer yozo-writer

that's right.

then, i walk through the go codes and find the reason.

xprop.PropValStrs on https://github.com/BurntSushi/xgbutil/blob/master/xprop/xprop.go#L249 parses the result wrong.

the reply.Value of yozo office does not end with 0 which leads to the string is appended once, so the wrong return value is gotten. I have no ideal why the reply.Value doesn't end with 0, I event don't know whether the reply.Value is right, but here is a hack for xprop.PropValStrs to get the right result:

if rep.Value[len(rep.Value)-1] != 0 {
    strs = append(strs, string(rep.Value[sstart:]))
}

keysym bug

Reference.

WINGO MESSAGE: ownership.go:129: Wingo has window manager ownership!
WINGO WARNING: config_theme_setters.go:167: Could not load './data/minimize.png' as a png image because: open ./data/minimize.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/minimize.png' as a png image because: open ./data/minimize.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/close.png' as a png image because: open ./data/close.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/close.png' as a png image because: open ./data/close.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/maximize.png' as a png image because: open ./data/maximize.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/maximize.png' as a png image because: open ./data/maximize.png: no such file or directory
WINGO WARNING: config_theme_setters.go:167: Could not load './data/wingo.png' as a png image because: open ./data/wingo.png: no such file or directory
panic: runtime error: index out of range

goroutine 11 [running]:
github.com/BurntSushi/xgbutil/keybind.KeysymGetWithMap(0x18c85780, 0x19f29b38, 0x19f207ff, 0x8, 0x19f29b38, ...)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/keybind/keybind.go:279 +0x65
github.com/BurntSushi/xgbutil/keybind.KeysymGet(0x18c85780, 0x7ff, 0x708, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/keybind/keybind.go:268 +0x56
github.com/BurntSushi/xgbutil/keybind.updateMaps(0x18c85780, 0x19945098, 0x19945098)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/keybind/keybind.go:68 +0x166
github.com/BurntSushi/xgbutil/xevent.MappingNotifyFun.Run(0x812877f, 0x18c85780, 0x83289f0, 0x19945098)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/callback.go:377 +0x4d
github.com/BurntSushi/xgbutil/xevent.runCallbacks(0x18c85780, 0x83289f0, 0x19945098, 0x22, 0x0, ...)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/xevent.go:182 +0xf3
github.com/BurntSushi/xgbutil/xevent.processEventQueue(0x18c85780, 0x19f80960, 0x19f80990, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/eventloop.go:268 +0x2656
github.com/BurntSushi/xgbutil/xevent.mainEventLoop(0x18c85780, 0x19f80960, 0x19f80990, 0x19f809c0, 0x805a26d, ...)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/eventloop.go:109 +0x9b
github.com/BurntSushi/xgbutil/xevent._func_001(0x19fb19c8, 0x19fb19d0, 0x19fb19d8, 0x19fb19e0, 0x0, ...)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/eventloop.go:88 +0x49
created by github.com/BurntSushi/xgbutil/xevent.MainPing
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgbutil/xevent/eventloop.go:89 +0x112

goroutine 1 [chan receive]:
main.main()
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/wingo/main.go:212 +0x872

goroutine 2 [syscall]:
created by runtime.main
        /usr/lib/go/src/pkg/runtime/proc.c:221

goroutine 3 [syscall]:
syscall.Syscall6()
        /usr/lib/go/src/pkg/syscall/asm_linux_386.s:46 +0x27
syscall.EpollWait(0x6, 0x19f22008, 0xa, 0xa, 0xffffffff, ...)
        /usr/lib/go/src/pkg/syscall/zerrors_linux_386.go:1845 +0x7d
net.(*pollster).WaitFD(0x19f22000, 0x19f2c600, 0x0, 0x0, 0x0, ...)
        /usr/lib/go/src/pkg/net/fd_linux.go:146 +0x12b
net.(*pollServer).Run(0x19f2c600, 0x0)
        /usr/lib/go/src/pkg/net/fd.go:236 +0xdf
created by net.newPollServer
        /usr/lib/go/src/pkg/net/newpollserver.go:35 +0x308

goroutine 4 [chan send]:
github.com/BurntSushi/xgb.(*Conn).generateXIds(0x19f2b910, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:229 +0x18a
created by github.com/BurntSushi/xgb.NewConnDisplay
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:103 +0x194

goroutine 5 [chan send]:
github.com/BurntSushi/xgb.(*Conn).generateSeqIds(0x19f2b910, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:251 +0x64
created by github.com/BurntSushi/xgb.NewConnDisplay
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:104 +0x1a9

goroutine 6 [chan receive]:
github.com/BurntSushi/xgb.(*Conn).sendRequests(0x19f2b910, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:297 +0x86
created by github.com/BurntSushi/xgb.NewConnDisplay
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:105 +0x1be

goroutine 7 [runnable]:
syscall.Syscall()
        /usr/lib/go/src/pkg/syscall/asm_linux_386.s:27 +0x41
syscall.Read(0x3, 0x199471c0, 0x20, 0x20, 0xb, ...)
        /usr/lib/go/src/pkg/syscall/zerrors_linux_386.go:2261 +0x61
net.(*netFD).Read(0x18c94a10, 0x199471c0, 0x20, 0x20, 0x0, ...)
        /usr/lib/go/src/pkg/net/fd.go:424 +0xde
net.(*UnixConn).Read(0x19f29a30, 0x199471c0, 0x20, 0x20, 0xb757bbc0, ...)
        /usr/lib/go/src/pkg/net/unixsock_posix.go:128 +0xb1
io.ReadAtLeast(0x19f27f60, 0x19f29a30, 0x199471c0, 0x20, 0x20, ...)
        /usr/lib/go/src/pkg/io/io.go:266 +0xb0
io.ReadFull(0x19f27f60, 0x19f29a30, 0x199471c0, 0x20, 0x20, ...)
        /usr/lib/go/src/pkg/io/io.go:285 +0x4a
github.com/BurntSushi/xgb.(*Conn).readResponses(0x19f2b910, 0x0)
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:347 +0x12c
created by github.com/BurntSushi/xgb.NewConnDisplay
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/xgb/xgb.go:106 +0x1d3

goroutine 8 [timer goroutine (idle)]:
created by addtimer
        /usr/lib/go/src/pkg/runtime/ztime_386.c:72

goroutine 9 [finalizer wait]:
created by runtime.gc
        /usr/lib/go/src/pkg/runtime/mgc0.c:882

goroutine 10 [chan receive]:
net.(*pollServer).WaitRead(0x19f2c600, 0x1a1ed2a0, 0x18c7c560, 0xb)
        /usr/lib/go/src/pkg/net/fd.go:268 +0x75
net.(*netFD).accept(0x1a1ed2a0, 0x80ae3de, 0x0, 0x18c7c540, 0x18c00110, ...)
        /usr/lib/go/src/pkg/net/fd.go:622 +0x199
net.(*UnixListener).AcceptUnix(0x19e107b0, 0xc, 0x0)
        /usr/lib/go/src/pkg/net/unixsock_posix.go:350 +0x46
net.(*UnixListener).Accept(0x19e107b0, 0x0, 0x0, 0x0, 0x0, ...)
        /usr/lib/go/src/pkg/net/unixsock_posix.go:361 +0x39
main.ipc()
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/wingo/ipc.go:35 +0x1b9
created by main.main
        /home/hitori/aur/wingo-git/src/src/github.com/BurntSushi/wingo/main.go:172 +0x594

ewmh.SupportingWmCheckSet should set property on both root and window

_NET_SUPPORTING_WM_CHECK needs to be set to the ID of the dummy window for both the root and the dummy window itself. Currently, it's only being set for the root window.

The Window Manager MUST set this property on the root window to be the ID of a child window created by himself, to indicate that a compliant window manager is active. The child window MUST also have the _NET_SUPPORTING_WM_CHECK property set to the ID of the child window

One could argue that the user should simply do two calls to the function; alternatively one could argue that the only use of that function is to set it for both windows.

xgraphics: package depends on code.google.com/p/jamslam-freetype-go/freetype

The package "code.google.com/p/jamslam-freetype-go/freetype" is going to disappear in January (last I heard). At that point the xgraphics package will not build.

It seems that the package requires the Context.MeasureString method which iirc was not available in "code.google.com/p/freetype-go/freetype".Context. I assume this was the original reason the "jamslam-" variant was used.

I have had similar requirements in the past. And I have used "jamslam" to meet them. Most recently when dealing with and trying to avoid code.google.com I found that I could achieve the MeasureString functionality by combining "github.com/golang/freetype" and "golang.org/x/image/font". You can look at my code. There is some weird rendering stuff going on in that program. But if you just trace back the types from the call site it should be fairly straightforward.

I think what it would boil down to in xgraphics/text.go would be something like the following (with some additional logic to create a font.Drawer):

w := f.MeasureString(text)
h := int(c.PointToFixed(fontSize) >> 6)

The height calculation is basically the same thing that "jamslam" is doing.

xgraphics.Image.Subimage return type should be image.Image

I'd love to treat xgraphics.Image as just another drawing destination, but it doesn't quite match what stdlib does:

stdlib:

func (p *Alpha) SubImage(r Rectangle) Image
func (p *Alpha16) SubImage(r Rectangle) Image
func (p *Gray) SubImage(r Rectangle) Image
func (p *Gray16) SubImage(r Rectangle) Image
func (p *NRGBA) SubImage(r Rectangle) Image
func (p *NRGBA64) SubImage(r Rectangle) Image
func (p *Paletted) SubImage(r Rectangle) Image
func (p *RGBA) SubImage(r Rectangle) Image
func (p *RGBA64) SubImage(r Rectangle) Image
func (p *YCbCr) SubImage(r Rectangle) Image

xgraphics:

func (im *Image) SubImage(r image.Rectangle) *Image

Wingo runs on the Raspberry Pi, but throws xgbutil errors

running wingo --replace:

[xgbutil] new.go:: xgraphics expects that root window has a dept of 24, but yours has depth '16'...
...
WINGO WARNING: heads.go:270: Cound not find any physical heads with the Xinerama extension
WINGO WARNING: heads.go:276: Assuming one head with size equivalent to the root window

xevent callbacks --- which window?

Find some place to document which window is used to fire callbacks.

i.e., the CreateNotify event has both a Parent and Window member. The callback should be run on Parent, since it is impossible to assign a callback to Window.

Other events are less straight-forward.

More functions for working with modifiers

Currently, if you don't want to do any masking yourself, there's only one function that you can use (that I know of), and that's keybind.ModifierString. This functions does several things you might not want:

  • It returns the modifiers connected with -
  • It returns the modifiers as strings, which isn't very efficient

Now, this isn't to say it's a bad function, but rather that it isn't sufficient as the only function.

example window-gradient fails

example window-gradient fails

The example window-graient fails with a large number of xgraphics issues.

Errors

../../xgraphics/image.go:32: imported and not used: "code.google.com/p/graphics-go/graphics"
../../xgraphics/text.go:10: emptyarchive redeclared as imported package name
previous declaration at ../../xgraphics/text.go:9
../../xgraphics/text.go:10: imported and not used: "code.google.com/p/freetype-go/freetype/truetype"
../../xgraphics/text.go:24: undefined: truetype
../../xgraphics/text.go:54: undefined: truetype
../../xgraphics/text.go:63: undefined: freetype
../../xgraphics/text.go:63: undefined: truetype
../../xgraphics/text.go:73: undefined: truetype
../../xgraphics/text.go:88: undefined: truetype
../../xgraphics/util.go:10: imported and not used: "code.google.com/p/graphics-go/graphics"
../../xgraphics/text.go:88: too many errors

These same errors appear any time you attempt to load xgraphics.

needs fix to work with current freetype

$ go get -u github.com/BurntSushi/xgbutil/xgraphics

github.com/BurntSushi/xgbutil/xgraphics

../../../../BurntSushi/xgbutil/xgraphics/text.go:36: c.FUnitToPixelRU undefined (type *freetype.Context has no field or method FUnitToPixelRU)
../../../../BurntSushi/xgbutil/xgraphics/text.go:36: font.UnitsPerEm undefined (type *truetype.Font has no field or method UnitsPerEm)
../../../../BurntSushi/xgbutil/xgraphics/text.go:60: c.FUnitToPixelRU undefined (type *freetype.Context has no field or method FUnitToPixelRU)
../../../../BurntSushi/xgbutil/xgraphics/text.go:60: font.UnitsPerEm undefined (type *truetype.Font has no field or method UnitsPerEm)

A quick google search indicates that this breakage results from the change "freetype: move the scaling from FUnits to pixels from package freetype to package truetype."

http://code.google.com/p/freetype-go/source/detail?spec=svn15b6d4e041517055da50fd23f5f4b4cc2c66ee94&r=15b6d4e041517055da50fd23f5f4b4cc2c66ee94

I would submit a fix, but am a bit intimidated, since I've never used any of these packages myself (and was just trying to compile go.uik working).

Image.Text and non-English chars.

The Text helper function seems to be rendering foreign chars incorrectly.
For example (should be śledź):
sledz

It's using a slightly modified _examples/draw-text code (changed the text to be rendered, of course). Tried with different fonts, all the same.

By the looking of this, I think it might be calculating the extents wrong. Which will make it a freetype-go bug, I guess. In such case, feel free to close this one.

ShowingDesktopReq failed

the ShowingDesktopReq will fail, because you pass the argument with uint type and NewClientMessage uses data[i].(int). You'd better make much more check on NewClientMessage(xevent/types_manual:24).

[question] mousebind -- button chords

Thank you for this library, it's real nice, made things so much easier

Mousebind docs say mouse buttons can be modifiers, so mouse chords should work.

But running this code:

package main

import (
	"log"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/mousebind"
	"github.com/BurntSushi/xgbutil/xevent"
)

func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	mousebind.Initialize(X)


	cb1 := mousebind.ButtonPressFun(
		func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) {
			log.Println("Button press!")
		})

	err = cb1.Connect(X, X.RootWin(), "button3-1", false, true)
	if err != nil {
		log.Println(err)
	}

	xevent.Main(X)
}

Produces this error:

Could not bind 'button3-1' because: 
BadValue {NiceName: Value, Sequence: 5, BadValue: 1024, MinorOpcode: 0, MajorOpcode: 28}

Any kind of help for solving this would be much appreciated.
Thank you again for all your great work

[question] Fall back fonts.

How would I go about loading fallback fonts, for example I'm using a ttf font that doesn't have Japanese characters, so I want a different to be used whenever there is a Japanese character.

LookupString segfault on linux

output:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x5911be]

goroutine 19 [running]:
testing.tRunner.func1.1(0x5b4dc0, 0x733ee0)
        /usr/lib/go-1.15/src/testing/testing.go:1057 +0x30d
testing.tRunner.func1(0xc000082900)
        /usr/lib/go-1.15/src/testing/testing.go:1060 +0x41a
panic(0x5b4dc0, 0x733ee0)
        /usr/lib/go-1.15/src/runtime/panic.go:969 +0x175
github.com/BurntSushi/xgbutil/keybind.KeysymGetWithMap(...)
        /home/binarycat/go/src/github.com/BurntSushi/xgbutil/keybind/keybind.go:260
github.com/BurntSushi/xgbutil/keybind.KeysymGet(...)
        /home/binarycat/go/src/github.com/BurntSushi/xgbutil/keybind/keybind.go:251
github.com/BurntSushi/xgbutil/keybind.interpretSymList(0xc0000fa140, 0x5ab836, 0x620101, 0xc000129e98, 0x59200d, 0x9, 0xc000129e80, 0x7208c0, 0x5ebcfd, 0x4)
        /home/binarycat/go/src/github.com/BurntSushi/xgbutil/keybind/encoding.go:87 +0x3e
github.com/BurntSushi/xgbutil/keybind.LookupString(0xc0000fa140, 0x360010, 0x4, 0x6c68b0)
        /home/binarycat/go/src/github.com/BurntSushi/xgbutil/keybind/encoding.go:34 +0x3e
github.com/lolbinarycat/dprefix.GetString(0x5f525ef0, 0xc000030770)
        /home/binarycat/go/src/github.com/lolbinarycat/dprefix/main.go:30 +0x8c
github.com/lolbinarycat/dprefix.TestGetString(0xc000082900)
        /home/binarycat/go/src/github.com/lolbinarycat/dprefix/main_test.go:27 +0x26
testing.tRunner(0xc000082900, 0x5fd808)
        /usr/lib/go-1.15/src/testing/testing.go:1108 +0xef
created by testing.(*T).Run
        /usr/lib/go-1.15/src/testing/testing.go:1159 +0x386

uname -a:

Linux binarycat 4.19.0-10-amd64 #1 SMP Debian 4.19.132-1 (2020-07-24) x86_64 GNU/Linux

go env:

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/binarycat/.cache/go-build"
GOENV="/home/binarycat/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/binarycat/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/binarycat/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go-1.15"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.15/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build338105219=/tmp/go-build -gno-record-gcc-switches"

unsafe quitting mechanism

From Nigel Tao:

I just wanted to note, though, that:

Goroutine A:
xu.Quit = true

Goroutine B:
for {
if xu.Quit {
return
}
// etc.
}

isn't guaranteed to work. See http://golang.org/ref/mem, especially
the part that says "another incorrect idiom is busy waiting for a
value".

png files (gopher subpackage) double-gzip'd

The png format already uses zlib internally for compression -- compressing it again is very unlikely to provide additional compression, and requires additional processing (once for your decompression, another time for the image library to decompress the png's pixels).

Large byte slices may also cause pathological behavior in the gc compiler (memory use ballooning). https://github.com/jteeuwen/go-bindata specializes in making sure the given binary file is compiled into a readonly memory segment without the major adverse effects -- though again, gzipping png files is best avoided.

[Newbie] Strange behavior on events

i've got this code :

x, err := xgbutil.NewConnDisplay(os.Getenv(displayEnv))
	if err != nil {
		return nil, err
	}

	wm := &WindowManager{
		X:                x,
		WorkspaceManager: newWorkspaceManager(len(conf.Workspaces)),
	}
	wm.WorkspaceManager.Add(x, conf)
	wm.WorkspaceManager.Activate(0)

	panel, err := newPanel(x, wm)
	if err != nil {
		return nil, err
	}
	panel.Run()

	root := xwindow.New(x, x.RootWin())
	evMasks := xproto.EventMaskPropertyChange |
		xproto.EventMaskFocusChange |
		xproto.EventMaskButtonPress |
		xproto.EventMaskButtonRelease |
		xproto.EventMaskStructureNotify |
		xproto.EventMaskSubstructureRedirect |
		xproto.EventMaskSubstructureRedirect

	if err := root.Listen(evMasks); err != nil {
		return nil, err
	}

	keybind.Initialize(x)

	xevent.MapRequestFun(wm.handleMapRequest).Connect(x, x.RootWin())
	xevent.ConfigureRequestFun(wm.handleConfigureRequest).Connect(x, x.RootWin())
	xevent.ConfigureNotifyFun(wm.handleConfigureNotify).Connect(x, x.RootWin())
	if err := keybind.KeyPressFun(wm.handleActivateNextWorkspace).Connect(x, x.RootWin(), conf.Keybindings.NextWorkspace, true); err != nil {
		return nil, err
	}
	if err := keybind.KeyPressFun(wm.handleActivatePreviousWorkspace).Connect(x, x.RootWin(), conf.Keybindings.PreviousWorkspace, true); err != nil {
		return nil, err
	}


	return wm, nil
}

func (wm *WindowManager) handleMapRequest(x *xgbutil.XUtil, ev xevent.MapRequestEvent) {
	glog.V(2).Infof("Event: map request: %s", ev)
	x.Grab()
	defer x.Ungrab()

	w, err := newWindow(x, wm.activeWorkspace().WindowId(), ev.Window)
	if err != nil {
		glog.Errorf("Can't create windows: %s", err)
		return
	}
	w.Draw()
}

func (wm *WindowManager) handleConfigureRequest(x *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) {
	glog.V(2).Infof("Event: configure request: %s", ev)
	xwindow.New(x, ev.Window).Configure(int(ev.ValueMask), int(ev.X), int(ev.Y), int(ev.Width)*2, int(ev.Height)*2, ev.Sibling, ev.StackMode)
}

func (wm *WindowManager) handleConfigureNotify(x *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) {
	glog.V(2).Infof("Event: configure notify: %s", ev)
}

When i add a termite application, i've got this log :

I0616 16:57:28.694279   28127 wm.go:137] Event: configure notify: ConfigureNotify {Sequence: 106, Event: 621, Window: 621, AboveSibling: 0, X: 0, Y: 0, Width: 1024, Height: 748, BorderWidth: 0, OverrideRedirect: false}
I0616 16:57:28.815842   28127 wm.go:132] Event: configure request: ConfigureRequest {Sequence: 106, StackMode: 0, Parent: 621, Window: 4194307, Sibling: 0, X: 0, Y: 0, Width: 722, Height: 434, BorderWidth: 0, ValueMask: 64}
I0616 16:57:28.815913   28127 wm.go:119] Event: map request: MapRequest {Sequence: 106, Parent: 621, Window: 4194307}

Do you know why i've got different width and height on configureNotify and configureRequest events ?
Thanks

xwindow.Create failed when the parent is a 32 depth window

I repeatedly read the man XWindowCreate, there hasn't a visual badmatch restrict.

*For class InputOutput, the visual type and depth must be a combination supported for the screen, or a BadMatch error results. *
the code of xwindow.Create use RootDeapth and RootVisual, so it must be a combination supported for the screen.

below is the test code.

package main

import (
    "fmt"
    "github.com/BurntSushi/xgb/xproto"
    "github.com/BurntSushi/xgbutil"
    "github.com/BurntSushi/xgbutil/xwindow"
)

var XU, _ = xgbutil.NewConn()

func main() {
    visual := func() xproto.Visualid {
        for _, dinfo := range XU.Screen().AllowedDepths {
            for _, vinfo := range dinfo.Visuals {
                if dinfo.Depth == 32 {
                    return vinfo.VisualId
                }
            }
        }
        panic("can't found a Visual which support RGBA")
    }()
    rgbaWindow, _ := xwindow.Generate(XU)
    if err := xproto.CreateWindowChecked(XU.Conn(), 0, rgbaWindow.Id, XU.RootWin(), 0, 0, 1, 1, 0, xproto.WindowClassInputOnly, visual, 0, nil).Check(); err != nil {
        panic("Can't create an RGBA window by manual")
    }

    //this should be failed
    if _, err := xwindow.Create(XU, rgbaWindow.Id); err != nil {
        fmt.Println("Create Failed by xwindow.Create:", err)
    }

    //this should be ok
    child, _ := xwindow.Generate(XU)
    if err := xproto.CreateWindowChecked(XU.Conn(), 0, child.Id, rgbaWindow.Id, 0, 0, 1, 1, 0, xproto.WindowClassInputOnly, visual, 0, nil).Check(); err == nil {
        fmt.Println("Create OK by manual")

}

We can solve this by use parent's visualID (but it cost a xproto.GetWindowAttributes request) and 0 (CopyFromParent) for the depth. I don't know whether I understand all of the man XCreateWindow meanings, so I created this issue to hope you find out the way.

By the way, you use xproto.WindowClassCopyFromParent in the xwindow.Window.Create, same value but different semantic. (xcb use XCB_COPY_FROM_PARENT, may be you can manually define this variable in xgb )

Calculating extents using freetype-go

The freetype-go package API doesn't yet support computing text extents without actually rendering the text to the image. Currently, the workaround is to calculate a "maximum" bounding box using the number of pixels in a single em unit. While this prevents text from ever being cut off, it tends to dramatically overestimate when fonts aren't monospace (since many characters have a width or height less than one em unit). Thus, the image is then cropped using the (x, y) offset returned from (*Context).DrawString.

Ideally, we should be able to calculate extents before rendering, therefore saving wasteful allocation. (For my use cases, the wasted allocation isn't too big of a deal.)

For more details, see Issue 5 on the freetype-go issue tracker.

Resize issues and Geometry values

Hi !

I am trying to resize and move window using xgbutil and facing some issues about it.
I am running i3wm and use pkg.go.dev/go.i3wm.org/i3/ to obtain the focused window ID.
Then I resize the window using one of the several methods provided by xgbutil.

My issue is :
I have a window of random size, I want to move it and set it to a specific size, let's say 640x360. When I run one time my program, the window is moved in the correct place however the size is not correct. Geometry functions report a bogus size.
If I run a second time the program immediately after, I can see the window changing a liittle bit its size again to finally get the correct size.
Geometry functions returns the same value as before but this time it is correct.
Subsquent run does not change the size anymore.

I have printed the geometry of the window before and after the call to the resize function and can see the second time that the size was incorrect (geometry reports the incorrect size). I don't understand why the geometry after the call in the first run is incorrect though.

Let's wrap-up:
I create two sets of objects to be sure I am not reusing bufferized values.
My code is

xgbUtil, _ := xgbutil.NewConn()
xWin := xwindow.New(xgbUtil, windID)
geom, _ := xWin.Geometry()
fmt.Println("Before ", uint(geom.Width()))
ewmh.MoveresizeWindow(xgbUtil, windID, 0, 0, 640,360)
xgbUtil2, _ := xgbutil.NewConn()
xWin2 := xwindow.New(xgbUtil2, windID)
geom2, _ := xWin2.Geometry()
fmt.Println("After  ", uint(geom2.Width()))

First run I got:

Before 789 <= Random initial width of the window
After 640 <= This is incorrect, the window is smaller

I do not touch anything and a rerun the program, I got:

Before 637 <= This shall have been in the "After" value on the first run
After 640 <= Now this is correct !

I am a little bit confused in front of the multiple function to resize a window.
I found:
ewmh.MoveresizeWindow
ewmh.MoveresizeWindowExtra
ewmh.WmMoveresizeWindow
ewmh.WmMoveresizeWindowExtra
ewmh.ResizeWindow
xwindow.Resize
xwindow.MoveResize
xwindow.WMResize
xwindow.WMMoveResize

I understand some of the differences (such as between Move and MoveResize) but I do not understand the difference between Resize and WMResize for example.

Transparent Child Window

How do I create a transparent child window ?

This is how I create a child window under a root window

win, err := xwindow.Generate(xu)
win.Create(parent, X,Y, Width,Height, xproto.CwBackPixel, 0xfffff)

Is it something to do with the valuemasks xproto.CwBackPixel ?

Any pointer will be very helpful. Thanks.

Panic during ActiveWindowGet call when app runs with sudo

I use ActiveWindowGet command to get currently active process. It runs perfectly. But if user starts the app with sudo, following part makes Panic and it crashes my entire app.

XGB: conn.go:47: Could not get authority info: open /root/.Xauthority: no such file or directory
XGB: conn.go:48: Trying connection without authority info...
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0xb48834]

goroutine 101 [running]:
github.com/BurntSushi/xgbutil/ewmh.ActiveWindowGet(0x7f4ce5424a68?)
        /github.com/BurntSushi/xgbutil/ewmh/ewmh.go:33 +0x14

So my questions would be:

  1. Can we handle panic here and return an error to user
  2. Is it possible to use ActiveWindowGet with sudo?

Thanks!

Edit: Oh, I'm sorry, totally my mistake. NewConn was giving an error but I didn't check that.
Closing the issue, sorry for the mistake.

[Question] Support for simulating keypresses?

Hello! Thanks for this library and for taking the time to write out the examples as they have been very helpful. Currently I'm trying to make a bare bones a simple text expander. The first part was easy to do modifying the example the keypress-english examples so I could listen for the text. I didn't any examples for simulating a keypress and was wondering if this library supports that and if not where to start looking for something like that? I have some very simple working C code:

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>

#define XK_c                             0x0063
#define XK_d                             0x0064
#define XK_h                             0x0068
#define XK_o                             0x006f
#define XK_y                             0x0079 
#define XK_at                            0x0040
#define XK_Shift_L                       0xffe1

int main() {
  Display *dpy;
  dpy = XOpenDisplay(NULL);
  sleep(2);

  KeyCode code = XKeysymToKeycode(dpy, XK_c);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
  code = XKeysymToKeycode(dpy, XK_o);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
  code = XKeysymToKeycode(dpy, XK_d);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
  code = XKeysymToKeycode(dpy, XK_y);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);

  // Make sure to send shift
  code = XKeysymToKeycode(dpy, XK_Shift_L);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  code = XKeysymToKeycode(dpy, XK_at);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
  code = XKeysymToKeycode(dpy, XK_Shift_L);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
  // No more shift
  //
  code = XKeysymToKeycode(dpy, XK_h);
  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
  XTestFakeKeyEvent(dpy, code, False, CurrentTime);

  XFlush( dpy );
  XCloseDisplay( dpy );

  return 0;
}

After that I updated this code to use something a bit more robust so I could call the C code from go with the following:

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>


int x11_key(char *zh){
  Display *dpy;
  dpy = XOpenDisplay(NULL);

  KeySym sym = XStringToKeysym(zh);
  int min, max, numcodes;
  XDisplayKeycodes(dpy,&min,&max);
  KeySym *keysym;
  keysym = XGetKeyboardMapping(dpy,min,max-min+1,&numcodes);
  keysym[(max-min-1)*numcodes]=sym;
  XChangeKeyboardMapping(dpy,min,numcodes,keysym,(max-min));
  XFree(keysym);
  XFlush( dpy );
  KeyCode code = XKeysymToKeycode(dpy,sym);
  XTestFakeKeyEvent(dpy, code, True, 1);
  XTestFakeKeyEvent(dpy, code, False, 1);

  XFlush( dpy );
  XCloseDisplay( dpy );

  return 0;
}

Which worked pretty well but when I would send a string like [email protected] the @ symbol would get messed up in programs other that the terminal I was running the code in. I searched around and saw the comment posted on https://stackoverflow.com/questions/26446184/control-the-mouse-and-keyboard-golang that said For X11 at least, there's no reason to use a C library. XGB is a native implementation of the X client protocol. which lead me here but I couldn't find and examples that simulated keypresses.

xgraphics should support more X server configurations (i.e., Raspberry Pi support)

The xgraphics package assumed the following configuration options of an X server:

  • Byte order: least significant byte first
  • Depth: 24
  • Bits per pixel: 32

Some or all of these configuration options aren't available (or aren't well supported) on the Raspberry Pi. More generally, the xgraphics package should be able to support some reasonable subset of these configuration options.

ximg doesn't get saved with SavePng.

Reproduce

Expected result

A window that pops up with the contents of the screenshot and a png gets written to disk with the contents of the screenshot.

Actual result

A window that pops up with the contents of the screenshot and blank png gets written to disk (https://punpun.xyz/hqgz.png)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.