burntsushi / xgbutil Goto Github PK
View Code? Open in Web Editor NEWA utility library to make use of the X Go Binding easier. (Implements EWMH and ICCCM specs, key binding support, etc.)
License: Do What The F*ck You Want To Public License
A utility library to make use of the X Go Binding easier. (Implements EWMH and ICCCM specs, key binding support, etc.)
License: Do What The F*ck You Want To Public License
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
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
The xgraphics package assumed the following configuration options of an X server:
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.
I know it's an legacy encoding, but there has some guys still use it.
$ go get -u 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."
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).
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.
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:]))
}
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".
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 )
_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.
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
Need a way to enable full screen.
example window-gradient fails
The example window-graient fails with a large number of xgraphics issues.
../../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.
with the move of code.google.com/p/go-freetype
to github.com/golang/freetype
there has been some API changes, namely the move to golang.org/x/image/math/fixed
to express font sizes.
more info here:
https://groups.google.com/d/topic/golang-nuts/tr-MftD7kbo/discussion
could you please migrate to that new API? it's blocking gonum/plot
: gonum/plot#216
thanks.
The Text helper function seems to be rendering foreign chars incorrectly.
For example (should be śledź
):
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.
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.
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.
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
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.
It seems you have to press several times to get one successful trigger.
I suspect somehow the very first one is always eaten by X window system menu.
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"
This is a simple patch that adds hooks to the xevent main loop, allowing handling of messages that don't conform to the package's routing mechanics
Hooks return true to allow the message to be processed as normal, false to abort processing of the event, presumably to implement it all in the hook's callback.
See title, support for pcf fonts would be very nice, expecially since many terminal like applications make use of them and because it doesn't seem to be possible to draw bitmap fonts using freetype-go.
I've looked around and this seems to be the only pcf library for go: https://github.com/nareix/pcf
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:
-
Now, this isn't to say it's a bad function, but rather that it isn't sufficient as the only function.
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:
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.
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
The callbacks are executed on both the Event
and Window
members. Why?
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
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.
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.
go build
A window that pops up with the contents of the screenshot and a png gets written to disk with the contents of the screenshot.
A window that pops up with the contents of the screenshot and blank png gets written to disk (https://punpun.xyz/hqgz.png)
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.
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).
Can you add the following line to keybind/keysymdef.go
?
"XF86AudioMicMute": 0x1008FFB2,
This key appears on Thinkpads and perhaps other systems. Here's a similar request for KDE: https://bugs.kde.org/show_bug.cgi?id=182672#c42
http://godoc.burntsushi.net/pkg/github.com/BurntSushi/xgbutil/ from README is unavailable
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.
What's the point of grab
option for keybind.*
or mousebin.d*
Connect method, if no binding works when it's not grabbed?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.