aboutsummaryrefslogtreecommitdiffhomepage
path: root/xcb
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-12-17 12:46:36 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-12-17 12:46:36 +0900
commitc2b178e626ed18955aeada3180e9e4cb9bf2694b (patch)
tree84a1bdbcc2d456c82d9dd2508b75e38105f97afe /xcb
parentaeda40fc92f7a569eda58323daf13a86c50574fb (diff)
xcb: refactor and clean up
No clean way to write Go tests for this package. Will rely on NixOS tests for now. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'xcb')
-rw-r--r--xcb/c.go137
-rw-r--r--xcb/export.go61
2 files changed, 124 insertions, 74 deletions
diff --git a/xcb/c.go b/xcb/c.go
index 8fe59d8c..3138c1db 100644
--- a/xcb/c.go
+++ b/xcb/c.go
@@ -1,33 +1,124 @@
package xcb
import (
- "errors"
+ "runtime"
+ "unsafe"
)
-//#include <stdlib.h>
-//#include <xcb/xcb.h>
-//#cgo linux LDFLAGS: -lxcb
+/*
+#cgo linux pkg-config: xcb
+
+#include <stdlib.h>
+#include <xcb/xcb.h>
+
+static int _go_xcb_change_hosts_checked(xcb_connection_t *c, uint8_t mode, uint8_t family, uint16_t address_len, const uint8_t *address) {
+ xcb_void_cookie_t cookie = xcb_change_hosts_checked(c, mode, family, address_len, address);
+ free((void *)address);
+
+ int errno = xcb_connection_has_error(c);
+ if (errno != 0)
+ return errno;
+
+ xcb_generic_error_t *e = xcb_request_check(c, cookie);
+ if (e != NULL) {
+ // don't want to deal with xcb errors
+ free((void *)e);
+ return -1;
+ }
+
+ return 0;
+}
+*/
import "C"
-func xcbHandleConnectionError(c *C.xcb_connection_t) error {
- if errno := C.xcb_connection_has_error(c); errno != 0 {
- switch errno {
- case C.XCB_CONN_ERROR:
- return errors.New("connection error")
- case C.XCB_CONN_CLOSED_EXT_NOTSUPPORTED:
- return errors.New("extension not supported")
- case C.XCB_CONN_CLOSED_MEM_INSUFFICIENT:
- return errors.New("memory not available")
- case C.XCB_CONN_CLOSED_REQ_LEN_EXCEED:
- return errors.New("request length exceeded")
- case C.XCB_CONN_CLOSED_PARSE_ERR:
- return errors.New("invalid display string")
- case C.XCB_CONN_CLOSED_INVALID_SCREEN:
- return errors.New("server has no screen matching display")
- default:
- return errors.New("generic X11 failure")
- }
- } else {
+const (
+ HostModeInsert = C.XCB_HOST_MODE_INSERT
+ HostModeDelete = C.XCB_HOST_MODE_DELETE
+
+ FamilyInternet = C.XCB_FAMILY_INTERNET
+ FamilyDecnet = C.XCB_FAMILY_DECNET
+ FamilyChaos = C.XCB_FAMILY_CHAOS
+ FamilyServerInterpreted = C.XCB_FAMILY_SERVER_INTERPRETED
+ FamilyInternet6 = C.XCB_FAMILY_INTERNET_6
+)
+
+type (
+ HostMode = C.xcb_host_mode_t
+ Family = C.xcb_family_t
+)
+
+func (conn *connection) changeHostsChecked(mode HostMode, family Family, address string) error {
+ errno := C._go_xcb_change_hosts_checked(
+ conn.c,
+ C.uint8_t(mode),
+ C.uint8_t(family),
+ C.uint16_t(len(address)),
+ (*C.uint8_t)(unsafe.Pointer(C.CString(address))),
+ )
+ switch errno {
+ case 0:
+ return nil
+ case -1:
+ return ErrChangeHosts
+ default:
+ return &ConnectionError{errno}
+ }
+}
+
+type connection struct{ c *C.xcb_connection_t }
+
+func connect() (*connection, error) {
+ conn := newConnection(C.xcb_connect(nil, nil))
+ return conn, conn.hasError()
+}
+
+func newConnection(c *C.xcb_connection_t) *connection {
+ conn := &connection{c}
+ runtime.SetFinalizer(conn, (*connection).disconnect)
+ return conn
+}
+
+const (
+ ConnError = C.XCB_CONN_ERROR
+ ConnClosedExtNotSupported = C.XCB_CONN_CLOSED_EXT_NOTSUPPORTED
+ ConnClosedMemInsufficient = C.XCB_CONN_CLOSED_MEM_INSUFFICIENT
+ ConnClosedReqLenExceed = C.XCB_CONN_CLOSED_REQ_LEN_EXCEED
+ ConnClosedParseErr = C.XCB_CONN_CLOSED_PARSE_ERR
+ ConnClosedInvalidScreen = C.XCB_CONN_CLOSED_INVALID_SCREEN
+)
+
+type ConnectionError struct{ errno C.int }
+
+func (ce *ConnectionError) Error() string {
+ switch ce.errno {
+ case ConnError:
+ return "connection error"
+ case ConnClosedExtNotSupported:
+ return "extension not supported"
+ case ConnClosedMemInsufficient:
+ return "memory not available"
+ case ConnClosedReqLenExceed:
+ return "request length exceeded"
+ case ConnClosedParseErr:
+ return "invalid display string"
+ case ConnClosedInvalidScreen:
+ return "server has no screen matching display"
+ default:
+ return "generic X11 failure"
+ }
+}
+
+func (conn *connection) hasError() error {
+ errno := C.xcb_connection_has_error(conn.c)
+ if errno == 0 {
return nil
}
+ return &ConnectionError{errno}
+}
+
+func (conn *connection) disconnect() {
+ C.xcb_disconnect(conn.c)
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(conn, nil)
}
diff --git a/xcb/export.go b/xcb/export.go
index 35af9aa5..1ed9997f 100644
--- a/xcb/export.go
+++ b/xcb/export.go
@@ -1,63 +1,22 @@
// Package xcb implements X11 ChangeHosts via libxcb.
package xcb
-//#include <stdlib.h>
-//#include <xcb/xcb.h>
-//#cgo linux LDFLAGS: -lxcb
-import "C"
import (
"errors"
- "unsafe"
)
-const (
- HostModeInsert = C.XCB_HOST_MODE_INSERT
- HostModeDelete = C.XCB_HOST_MODE_DELETE
+var ErrChangeHosts = errors.New("xcb_change_hosts() failed")
- FamilyInternet = C.XCB_FAMILY_INTERNET
- FamilyDecnet = C.XCB_FAMILY_DECNET
- FamilyChaos = C.XCB_FAMILY_CHAOS
- FamilyServerInterpreted = C.XCB_FAMILY_SERVER_INTERPRETED
- FamilyInternet6 = C.XCB_FAMILY_INTERNET_6
-)
-
-type ConnectionError struct {
- err error
-}
-
-func (e *ConnectionError) Error() string {
- return e.err.Error()
-}
-
-func (e *ConnectionError) Unwrap() error {
- return e.err
-}
-
-var (
- ErrChangeHosts = errors.New("xcb_change_hosts() failed")
-)
-
-func ChangeHosts(mode, family C.uint8_t, address string) error {
- c := C.xcb_connect(nil, nil)
- defer C.xcb_disconnect(c)
-
- if err := xcbHandleConnectionError(c); err != nil {
- return &ConnectionError{err}
- }
-
- addr := C.CString(address)
- cookie := C.xcb_change_hosts_checked(c, mode, family, C.ushort(len(address)), (*C.uchar)(unsafe.Pointer(addr)))
- C.free(unsafe.Pointer(addr))
-
- if err := xcbHandleConnectionError(c); err != nil {
- return &ConnectionError{err}
- }
+func ChangeHosts(mode HostMode, family Family, address string) error {
+ var conn *connection
- e := C.xcb_request_check(c, cookie)
- if e != nil {
- defer C.free(unsafe.Pointer(e))
- return ErrChangeHosts
+ if c, err := connect(); err != nil {
+ c.disconnect()
+ return err
+ } else {
+ defer c.disconnect()
+ conn = c
}
- return nil
+ return conn.changeHostsChecked(mode, family, address)
}