永井 忠一 2025.11.24
レガシーライブラリの利用。例
| C/C++ |
|---|
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(int argc, char *argv[])
{
Display *display = XOpenDisplay(nullptr);
if (display == nullptr) {
exit(1);
}
Window window = XCreateSimpleWindow(display,
RootWindow(display, 0),
100, 100, 320, 200, 2,
BlackPixel(display, 0), WhitePixel(display, 0));
GC context = XCreateGC(display, window, 0, nullptr);
XSelectInput(display, window, (ExposureMask
|((ButtonPressMask|ButtonReleaseMask)|PointerMotionMask)
|(KeyPressMask|KeyReleaseMask)
|StructureNotifyMask));
XStoreName(display, window, "test");
XMapWindow(display, window);
XEvent event;
while (true) {
memset(&event, 0x00, sizeof(event));
XNextEvent(display, &event);
assert(event.type < LASTEvent);
if (event.type == Expose) {
XDrawLine(display, window, context, 10, 10, 100, 100);
XDrawLine(display, window, context, 10, 100, 100, 10);
XPoint points[] = {
{10, 10},
{10, 100},
{100, 100},
{100, 10},
{10, 10}
};
XDrawLines(display, window, context, points, sizeof(points)/sizeof(points[0]), CoordModeOrigin);
XDrawArc(display, window, context, 110, 10, 90, 90, 90*64/* 1/64 deg */, 180*64/* 1/64 deg */);
XDrawString(display, window, context, 160, 120, "hello, X", 8);
XFlush(display);
}
else if (event.type == ButtonPress || event.type == ButtonRelease) {
printf("button(%s) = %u\n", (event.type == ButtonPress ? "press" : "release"), event.xbutton.button);
printf("x, y = %d, %d\n", event.xbutton.x, event.xbutton.y);
}
else if (event.type == MotionNotify) {
printf("x, y = %d, %d\n", event.xmotion.x, event.xmotion.y);
}
else if (event.type == KeyPress || event.type == KeyRelease) {
printf("keycode(%s) = %u\n", (event.type == KeyPress ? "press" : "release"), event.xkey.keycode);
if (event.type == KeyPress) {
const KeySym key = XLookupKeysym(&(event.xkey), 0);
if (key == XK_q) {
break;
}
else if (key == XK_d) {
XClearWindow(display, window);
}
}
}
else if (event.type == ConfigureNotify) {
printf("width, height = %d, %d\n", event.xconfigure.width, event.xconfigure.height);
}
}
XCloseDisplay(display), display = nullptr;
}
|
ほかの言語からは、C のマクロを使うことができないため、ラッパーを用意
| C |
|---|
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#undef RootWindow /* override */
Window RootWindow(const Display *dpy, int scr)
{
return ScreenOfDisplay(dpy, scr)->root;
}
#undef BlackPixel /* override */
unsigned long BlackPixel(const Display *dpy, int scr)
{
return ScreenOfDisplay(dpy, scr)->black_pixel;
}
#undef WhitePixel /* override */
unsigned long WhitePixel(const Display *dpy, int scr)
{
return ScreenOfDisplay(dpy, scr)->white_pixel;
}
|
D言語は、直接 C/C++ の関数とやりとりできる(ただし、テンプレート関数は使えない。また、vtableフォーマットも、C++ との互換性はない)
Go言語の、C の関数とのインタフェースは cgo
Rustでは、FFI(外部関数インタフェース)
(D と Go の GC は、ともに、コンパクションをしない。Go には、goroutineスケジューラによる挙動がある)
| D | Go | Rust |
|---|---|---|
extern(C) {
struct Display; // incomplete type, opaque data type
Display *XOpenDisplay(const char *display_name);
alias XID = ulong;
alias Window = XID;
Window XCreateSimpleWindow(Display *display,
Window parent,
int x,
int y,
uint width,
uint height,
uint border_width,
ulong border,
ulong background);
struct _XGC; // incomplete type
alias GC = _XGC*; // opaque data type
alias Drawable = XID;
struct XGCValues; // unused
GC XCreateGC(Display *display,
Drawable d,
ulong valuemask,
XGCValues *values);
int XSelectInput(Display *display,
Window w,
long event_mask);
int XStoreName(Display *display,
Window w,
const char *window_name);
int XStoreName(Display *display,
Window w,
const char *window_name);
int XMapWindow(Display *display,
Window w);
struct XKeyEvent {
ubyte[84] pad_to_keycode; // adhoc
uint keycode;
ubyte[4] pad; // adhoc
}
struct XButtonEvent {
ubyte[64] pad_to_x; // adhoc
int x;
int y;
ubyte[84 - 4 - 4 - 64] pad_to_button; // adhoc
uint button;
// omitted
}
struct XMotionEvent {
ubyte[64] pad_to_x; // adhoc
int x;
int y;
// omitted
}
struct XConfigureEvent {
ubyte[56] pad_to_x; // adhoc
int width;
int height;
// omitted
}
union XEvent {
int type;
// omitted
XKeyEvent xkey;
XButtonEvent xbutton;
XMotionEvent xmotion;
// omitted
XConfigureEvent xconfigure;
// omitted
long[24] pad;
}
int XNextEvent(Display *display,
XEvent *event_return);
int XDrawLine(Display *display,
Drawable d,
GC gc,
int x1,
int y1,
int x2,
int y2);
struct XPoint {
short x;
short y;
}
int XDrawLines(Display *display,
Drawable d,
GC gc,
XPoint *points,
int npoints,
int mode);
int XDrawArc(Display *display,
Drawable d,
GC gc,
int x,
int y,
uint width,
uint height,
int angle1,
int angle2);
int XDrawString(Display *display,
Drawable d,
GC gc,
int x,
int y,
const char *string,
int length);
int XFlush(Display *display);
alias KeySym = XID;
KeySym XLookupKeysym(XKeyEvent *key_event,
int index);
int XClearWindow(Display *display,
Window w);
int XCloseDisplay(Display *display);
}
enum {
KeyPressMask = 1L<<0,
KeyReleaseMask = 1L<<1,
ButtonPressMask = 1L<<2,
ButtonReleaseMask = 1L<<3,
// omitted
PointerMotionMask = 1L<<6,
// omitted
ExposureMask = 1L<<15,
// omitted
StructureNotifyMask = 1L<<17
// omitted
}
enum {
KeyPress = 2,
KeyRelease = 3,
ButtonPress = 4,
ButtonRelease = 5,
MotionNotify = 6,
// omitted
Expose = 12,
// omitted
ConfigureNotify = 22,
// omitted
LASTEvent = 36
}
enum {
CoordModeOrigin = 0
// omitted
}
enum : uint {
XK_d = 0x0064,
// omitted
XK_q = 0x0071
}
extern(C) { // for macro
Window RootWindow(Display *dpy, int scr);
ulong BlackPixel(Display *dpy, int scr);
ulong WhitePixel(Display *dpy, int scr);
}
import std.stdio;
import core.stdc.stdlib;
import core.stdc.string;
void main() {
Display *display = XOpenDisplay(null);
if (display is null) {
exit(1);
}
Window window = XCreateSimpleWindow(display,
RootWindow(display, 0),
100, 100, 320, 200, 2,
BlackPixel(display, 0), WhitePixel(display, 0));
GC context = XCreateGC(display, window, 0, null);
XSelectInput(display, window, (ExposureMask
|((ButtonPressMask|ButtonReleaseMask)|PointerMotionMask)
|(KeyPressMask|KeyReleaseMask)
|StructureNotifyMask));
XStoreName(display, window, "test");
XMapWindow(display, window);
XEvent event;
while (true) {
memset(&event, 0x00, event.sizeof); static assert(event.sizeof == XEvent.sizeof);
XNextEvent(display, &event);
if (event.type == Expose) {
XDrawLine(display, window, context, 10, 10, 100, 100);
XDrawLine(display, window, context, 10, 100, 100, 10);
XPoint[] points = [XPoint(10, 10),
XPoint(10, 100),
XPoint(100, 100),
XPoint(100, 10),
XPoint(10, 10)];
XDrawLines(display, window, context, points.ptr, cast(int)(points.length), CoordModeOrigin);
XDrawArc(display, window, context, 110, 10, 90, 90, 90*64/* 1/64 deg */, 180*64/* 1/64 deg */);
XDrawString(display, window, context, 160, 120, "hello, X", 8);
XFlush(display);
}
else if (event.type == ButtonPress || event.type == ButtonRelease) {
writeln("button(", (event.type == ButtonPress ? "press" : "release"), ") = ", event.xbutton.button);
writeln("x, y = ", event.xbutton.x, ", ", event.xbutton.y);
}
else if (event.type == MotionNotify) {
writeln("x, y = ", event.xmotion.x, ", ", event.xmotion.y);
}
else if (event.type == KeyPress || event.type == KeyRelease) {
writeln("keycode(", (event.type == KeyPress ? "press" : "release"), ") = ", event.xkey.keycode);
if (event.type == KeyPress) {
const KeySym key = XLookupKeysym(&(event.xkey), 0);
if (key == XK_q) {
break;
}
else if (key == XK_d) {
XClearWindow(display, window);
}
}
}
else if (event.type == ConfigureNotify) {
writeln("width, height = ", event.xconfigure.width, ", ", event.xconfigure.height);
}
}
XCloseDisplay(display); display = null;
}
|
package main
/*
#cgo LDFLAGS: ./wrapper.o -lX11
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef RootWindow
#undef RootWindow
#endif
Window RootWindow(const Display *dpy, int scr);
#ifdef BlackPixel
#undef BlackPixel
#endif
unsigned long BlackPixel(const Display *dpy, int scr);
#ifdef WhitePixel
#undef WhitePixel
#endif
unsigned long WhitePixel(const Display *dpy, int scr);
int get_type(const XEvent *event) {
return event ? event->type : 0;
}
*/
import "C"
import (
"fmt"
"sync"
"runtime"
"os"
"unsafe"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var display *C.Display = C.XOpenDisplay(nil)
if display == nil {
os.Exit(1)
}
var window C.Window = C.XCreateSimpleWindow(display,
C.RootWindow(display, 0),
100, 100, 320, 200, 2,
C.BlackPixel(display, 0), C.WhitePixel(display, 0))
var context C.GC = C.XCreateGC(display, window, 0, nil)
C.XSelectInput(display, window, (C.ExposureMask|
((C.ButtonPressMask|C.ButtonReleaseMask)|C.PointerMotionMask)|
(C.KeyPressMask|C.KeyReleaseMask)|
C.StructureNotifyMask))
{
name := C.CString("test")
C.XStoreName(display, window, name)
C.free(unsafe.Pointer(name))
}
C.XMapWindow(display, window)
var event C.XEvent
for {
C.memset(unsafe.Pointer(&event), 0x00, C.sizeof_XEvent)
C.XNextEvent(display, &event)
// assert(event.type < LASTEvent);
if event_type := C.get_type(&event); event_type == C.Expose {
C.XDrawLine(display, window, context, 10, 10, 100, 100)
C.XDrawLine(display, window, context, 10, 100, 100, 10)
points := []C.XPoint{
{x: 10, y: 10},
{x: 10, y: 100},
{x: 100, y: 100},
{x: 100, y: 10},
{x: 10, y: 10},
}
C.XDrawLines(display, window, context, &(points[0]), C.int(len(points)), C.CoordModeOrigin)
C.XDrawArc(display, window, context, 110, 10, 90, 90, 90*64/* 1/64 deg */, 180*64/* 1/64 deg */)
{
string := C.CString("hello, X")
C.XDrawString(display, window, context, 160, 120, string, 8)
C.free(unsafe.Pointer(string))
}
C.XFlush(display)
} else if event_type == C.ButtonPress || event_type == C.ButtonRelease {
xbutton := (*C.XButtonEvent)(unsafe.Pointer(&event))
if event_type == C.ButtonPress {
fmt.Printf("button(press) = %d\n", xbutton.button)
} else {
fmt.Printf("button(release) = %d\n", xbutton.button)
}
fmt.Printf("x, y = %d, %d\n", xbutton.x, xbutton.y)
} else if event_type == C.MotionNotify {
xmotion := (*C.XMotionEvent)(unsafe.Pointer(&event))
fmt.Printf("x, y = %d, %d\n", xmotion.x, xmotion.y)
} else if event_type == C.KeyPress || event_type == C.KeyRelease {
xkey := (*C.XKeyEvent)(unsafe.Pointer(&event))
if event_type == C.KeyPress {
fmt.Printf("keycode(press) = %d\n", xkey.keycode)
} else {
fmt.Printf("keycode(release) = %d\n", xkey.keycode)
}
if event_type == C.KeyPress {
var key C.KeySym = C.XLookupKeysym(xkey, 0)
if key == C.XK_q {
break
} else if key == C.XK_d {
C.XClearWindow(display, window)
}
}
} else if event_type == C.ConfigureNotify {
xconfigure := (*C.XConfigureEvent)(unsafe.Pointer(&event))
fmt.Printf("width, height = %d, %d\n", xconfigure.width, xconfigure.height)
}
}
C.XCloseDisplay(display); display = nil
}()
wg.Wait()
}
|
use std::os::raw::{c_short, c_int, c_long, c_char, c_uint, c_ulong};
type CARD32 = u32;
type XID = CARD32;
type Window = XID;
type Drawable = XID;
// omitted
type KeySym = XID;
#[repr(C)]
struct _XDisplay {
_private: [u8; 0] // incomplete type
}
type Display = _XDisplay; // opaque data type
#[repr(C)]
struct _XGC {
_private: [u8; 0] // incomplete type
}
type GC = *mut _XGC; // opaque data type
#[repr(C)]
struct XGCValues {
pad: [u8; 128] // unused
}
#[repr(C)]
#[derive(Copy, Clone)]
struct XKeyEvent {
pad_to_keycode: [u8; 84], // adhoc
pub keycode: c_uint,
pad: [u8; 4] // adhoc
}
#[repr(C)]
#[derive(Copy, Clone)]
struct XButtonEvent {
pad_to_x: [u8; 64], // adhoc
pub x: c_int,
pub y: c_int,
pad_to_button: [u8; 84 - 4 - 4 - 64], // adhoc
pub button: c_uint
// omitted
}
#[repr(C)]
#[derive(Copy, Clone)]
struct XMotionEvent {
pad_to_x: [u8; 64], // adhoc
pub x: c_int,
pub y: c_int
// omitted
}
#[repr(C)]
#[derive(Copy, Clone)]
struct XConfigureEvent {
pad_to_x: [u8; 56], // adhoc
pub width: c_int,
pub height: c_int
// omitted
}
#[repr(C)]
union XEvent {
pub type_: c_int,
// omitted
pub xkey: XKeyEvent,
pub xbutton: XButtonEvent,
pub xmotion: XMotionEvent,
// omitted
pub xconfigure: XConfigureEvent,
// omitted
pad: [c_long; 24]
}
#[repr(C)]
struct XPoint {
x: c_short,
y: c_short
}
#[allow(non_upper_case_globals)] const KeyPressMask: c_long = 1<<0;
#[allow(non_upper_case_globals)] const KeyReleaseMask: c_long = 1<<1;
#[allow(non_upper_case_globals)] const ButtonPressMask: c_long = 1<<2;
#[allow(non_upper_case_globals)] const ButtonReleaseMask: c_long = 1<<3;
// omitted
#[allow(non_upper_case_globals)] const PointerMotionMask: c_long = 1<<6;
// omitted
#[allow(non_upper_case_globals)] const ExposureMask: c_long = 1<<15;
// omitted
#[allow(non_upper_case_globals)] const StructureNotifyMask: c_long = 1<<17;
// omitted
#[allow(non_upper_case_globals)] const KeyPress: c_int = 2;
#[allow(non_upper_case_globals)] const KeyRelease: c_int = 3;
#[allow(non_upper_case_globals)] const ButtonPress: c_int = 4;
#[allow(non_upper_case_globals)] const ButtonRelease: c_int = 5;
#[allow(non_upper_case_globals)] const MotionNotify: c_int = 6;
// omitted
#[allow(non_upper_case_globals)] const Expose: c_int = 12;
// omitted
#[allow(non_upper_case_globals)] const ConfigureNotify: c_int = 22;
// omitted
#[allow(non_upper_case_globals)] const LASTEvent: c_int = 36;
#[allow(non_upper_case_globals)] const CoordModeOrigin: c_int = 0;
// omitted
#[allow(non_upper_case_globals)] const XK_d: u32 = 0x0064;
// omitted
#[allow(non_upper_case_globals)] const XK_q: u32 = 0x0071;
extern "C" {
fn XOpenDisplay(display_name: *const c_char) -> *mut Display;
fn XCreateSimpleWindow(display: *mut Display,
parent: Window,
x: c_int,
y: c_int,
width: c_uint,
height: c_uint,
border_width: c_uint,
border: c_ulong,
background: c_ulong) -> Window;
fn XCreateGC(display: *mut Display,
d: Drawable,
valuemask: c_ulong,
values: *mut XGCValues) -> GC;
fn XSelectInput(display: *mut Display,
w: Window,
event_mask: c_long) -> c_int;
fn XStoreName(display: *mut Display,
w: Window,
window_name: *const c_char) -> c_int;
fn XMapWindow(display: *mut Display,
w: Window) -> c_int;
fn XNextEvent(display: *mut Display,
event_return: *mut XEvent) -> c_int;
fn XDrawLine(display: *mut Display,
d: Drawable,
gc: GC,
x1: c_int,
y1: c_int,
x2: c_int,
y2: c_int) -> c_int;
fn XDrawLines(display: *mut Display,
d: Drawable,
gc: GC,
points: *mut XPoint,
npoints: c_int,
mode: c_int) -> c_int;
fn XDrawArc(display: *mut Display,
d: Drawable,
gc: GC,
x: c_int,
y: c_int,
width: c_uint,
height: c_uint,
angle1: c_int,
angle2: c_int) -> c_int;
fn XDrawString(display: *mut Display,
d: Drawable,
gc: GC,
x: c_int,
y: c_int,
string: *const c_char,
length: c_int) -> c_int;
fn XFlush(display: *mut Display) -> c_int;
fn XLookupKeysym(key_event: *mut XKeyEvent,
index: c_int) -> KeySym;
fn XClearWindow(display: *mut Display,
w: Window) -> c_int;
fn XCloseDisplay(display: *mut Display) -> c_int;
}
extern "C" { // for macro
fn RootWindow(dpy: *mut Display, scr: c_int) -> Window;
fn BlackPixel(dpy: *mut Display, scr: c_int) -> c_ulong;
fn WhitePixel(dpy: *mut Display, scr: c_int) -> c_ulong;
}
use std::ptr;
use std::process;
use std::ffi::CString;
use std::mem;
fn main() {
unsafe { // adhoc
let display: *mut Display = XOpenDisplay(ptr::null());
if display.is_null() {
process::exit(1);
}
let window: Window = XCreateSimpleWindow(display,
RootWindow(display, 0),
100, 100, 320, 200, 2,
BlackPixel(display, 0), WhitePixel(display, 0));
let context: GC = XCreateGC(display, window, 0, ptr::null_mut());
XSelectInput(display, window,
ExposureMask
|ButtonPressMask|ButtonReleaseMask|PointerMotionMask
|KeyPressMask|KeyReleaseMask
|StructureNotifyMask);
{
let name = CString::new("test").unwrap();
XStoreName(display, window, name.as_ptr());
}
XMapWindow(display, window);
let mut event: XEvent = mem::zeroed();
loop {
ptr::write_bytes(&mut event as *mut XEvent as *mut u8, 0x00, mem::size_of::<XEvent>());
XNextEvent(display, &mut event);
assert!(event.type_ < LASTEvent);
if event.type_ == Expose {
XDrawLine(display, window, context, 10, 10, 100, 100);
XDrawLine(display, window, context, 10, 100, 100, 10);
let mut points = [
XPoint { x: 10, y: 10 },
XPoint { x: 10, y: 100 },
XPoint { x: 100, y: 100 },
XPoint { x: 100, y: 10 },
XPoint { x: 10, y: 10 }
];
XDrawLines(display, window, context, points.as_mut_ptr(), points.len() as c_int, CoordModeOrigin);
XDrawArc(display, window, context, 110, 10, 90, 90, 90*64/* 1/64 deg */, 180*64/* 1/64 deg */);
{
let string = CString::new("hello, X").unwrap();
XDrawString(display, window, context, 160, 120, string.as_ptr(), 8);
}
XFlush(display);
}
else if event.type_ == ButtonPress || event.type_ == ButtonRelease {
println!("button({}) = {}", if event.type_ == ButtonPress { "press" } else { "release" }, event.xbutton.button);
println!("x, y = {}, {}", event.xbutton.x, event.xbutton.y);
}
else if event.type_ == MotionNotify {
println!("x, y = {}, {}", event.xmotion.x, event.xmotion.y);
}
else if event.type_ == KeyPress || event.type_ == KeyRelease {
println!("keycode({}) = {}", if event.type_ == KeyPress { "press" } else { "release" }, event.xkey.keycode);
let key: KeySym = XLookupKeysym(&mut(event.xkey), 0);
if key == XK_q {
break;
}
else if key == XK_d {
XClearWindow(display, window);
}
}
else if event.type_ == ConfigureNotify {
println!("width, height = {}, {}", event.xconfigure.width, event.xconfigure.height);
}
}
XCloseDisplay(display);
}
}
|

インストール
| Linux apt |
|---|
|
(シンタックスハイライトは、pygmentize)
© 2025 Tadakazu Nagai