type xatom
type xwin
type xevent =
- Focus of { focused: bool }
+ | Focus of { focused: bool }
| KeyPress of { mods: int; rune: int }
| MouseBtn of {
mods: int;
| Resize of { height: int; width: int }
| Shutdown
| QueueEmpty
+ | Filtered
+(*
+ | PipeClosed
+ | PipeWriteReady
+ | PipeReadReady
+*)
external connect : unit -> unit
= "x11_connect"
external show_window : bool -> unit
= "x11_show_window"
-external has_event : unit -> bool
- = "x11_has_event"
+external event_loop : int -> (xevent -> unit) -> unit
+ = "x11_event_loop"
+
+external num_events : unit -> int
+ = "x11_num_events"
external next_event : unit -> xevent
= "x11_next_event"
= "x11_prop_get"
(* to be implemented
-external sel_set : atom -> string -> unit
- = "x11_sel_set"
-external sel_get : atom -> unit
- = "x11_sel_get"
+external sel_set : xatom -> string -> unit
+ = "x11_sel_set"
+external sel_fetch : xatom -> unit
+ = "x11_sel_get"
*)
(* Automatically connect and disconnect to the display server *)
#include <caml/fail.h>
#include <caml/memory.h>
#include <caml/alloc.h>
-//#include <caml/custom.h>
+#include <caml/callback.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
static void create_window(int height, int width);
static struct {
+ bool running;
Display* display;
Visual* visual;
Colormap colormap;
XIC xic;
XIM xim;
GC gc;
-} X;
+} X = {0};
CAMLprim value x11_connect(void) {
CAMLparam0();
- if (!(X.display = XOpenDisplay(NULL)))
- caml_failwith("could not open display");
- XSetErrorHandler(error_handler);
- X.root = DefaultRootWindow(X.display);
- XWindowAttributes wa;
- XGetWindowAttributes(X.display, X.root, &wa);
- X.visual = wa.visual;
- X.colormap = wa.colormap;
- X.screen = DefaultScreen(X.display);
- X.depth = DefaultDepth(X.display, X.screen);
+ if (!X.display) {
+ if (!(X.display = XOpenDisplay(NULL)))
+ caml_failwith("could not open display");
+ XSetErrorHandler(error_handler);
+ X.root = DefaultRootWindow(X.display);
+ XWindowAttributes wa;
+ XGetWindowAttributes(X.display, X.root, &wa);
+ X.visual = wa.visual;
+ X.colormap = wa.colormap;
+ X.screen = DefaultScreen(X.display);
+ X.depth = DefaultDepth(X.display, X.screen);
+ X.running = true;
+ }
CAMLreturn(Val_unit);
}
CAMLprim value x11_disconnect(void) {
CAMLparam0();
- XCloseDisplay(X.display);
+ if (X.display) {
+ if (X.self) {
+ XUnmapWindow(X.display, X.self);
+ XSync(X.display, True);
+ }
+ XCloseDisplay(X.display);
+ }
CAMLreturn(Val_unit);
}
CAMLprim value x11_show_window(value state) {
CAMLparam1(state);
- if (Bool_val(state)) {
- /* simulate an initial resize and map the window */
- XConfigureEvent ce;
- ce.type = ConfigureNotify;
- ce.width = X.width;
- ce.height = X.height;
- XSendEvent(X.display, X.self, False, StructureNotifyMask, (XEvent *)&ce);
+ if (Bool_val(state))
XMapWindow(X.display, X.self);
- } else {
+ else
XUnmapWindow(X.display, X.self);
+ CAMLreturn(Val_unit);
+}
+
+CAMLprim value x11_event_loop(value ms, value cbfn) {
+ CAMLparam2(ms, cbfn);
+ while (X.running) {
+ XEvent e; XPeekEvent(X.display, &e);
+ bool pending = false; //pollfds(Int_val(ms), cbfn);
+ int nevents = XEventsQueued(X.display, QueuedAfterFlush);
+ if (pending || nevents) {
+ /* pare down irrelevant mouse drag events to just the latest */
+ XTimeCoord* coords = XGetMotionEvents(X.display, X.self, CurrentTime, CurrentTime, &nevents);
+ if (coords) XFree(coords);
+
+ /* now take the events, convert them, and call the callback */
+ for (XEvent e; XPending(X.display);) {
+ XNextEvent(X.display, &e);
+ if (!XFilterEvent(&e, None)) {
+ // Convert the event.
+ caml_callback(cbfn, Val_unit);
+ }
+ }
+
+ if (X.running) {
+ caml_callback(cbfn, Val_unit /* redraw event */);
+ XCopyArea(X.display, X.pixmap, X.self, X.gc, 0, 0, X.width, X.height, 0, 0);
+ }
+ }
+ XFlush(X.display);
}
CAMLreturn(Val_unit);
}
XGetWindowAttributes(X.display, X.root, &wa);
X.self = XCreateSimpleWindow(X.display, X.root,
(wa.width - X.width) / 2,
- (wa.height - X.height) /2,
+ (wa.height - X.height) / 2,
X.width,
X.height,
0, X.depth,
swa.backing_store = WhenMapped;
swa.bit_gravity = NorthWestGravity;
XChangeWindowAttributes(X.display, X.self, CWBackingStore|CWBitGravity, &swa);
- XStoreName(X.display, X.self, "tide");
+ //XStoreName(X.display, X.self, "tide");
XSelectInput(X.display, X.self,
StructureNotifyMask
| ButtonPressMask