type atom
-type window
+type winid
external connect : unit -> unit
= "x11_connect"
external disconnect : unit -> unit
= "x11_disconnect"
+external make_window : int -> int -> unit
+ = "x11_make_window"
+
+external make_dialog : int -> int -> unit
+ = "x11_make_dialog"
+
+external show_window : bool -> unit
+ = "x11_show_window"
+
external errno : unit -> int
= "x11_errno"
external intern : string -> atom
= "x11_intern"
-external prop_set : window -> atom -> string -> unit
+external prop_set : winid -> atom -> string -> unit
= "x11_prop_set"
-external prop_get : window -> atom -> string
+external prop_get : winid -> atom -> string
= "x11_prop_get"
(* to be implemented
-external mkwindow : int -> int -> window
- = "x11_mkwindow"
-external mkdialog : int -> int -> window
- = "x11_mkdialog"
external sel_set : atom -> string -> unit
= "x11_sel_set"
external sel_get : atom -> unit
= "x11_sel_get"
*)
+
+(* Automatically connect and disconnect to the display server *)
+let () =
+ connect ();
+ at_exit disconnect
+
#include <caml/memory.h>
#include <caml/alloc.h>
//#include <caml/custom.h>
-//#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
+#include <X11/Xft/Xft.h>
static int error_handler(Display* disp, XErrorEvent* ev);
static char* readprop(Window win, Atom prop);
+static void create_window(int height, int width);
static struct {
Display* display;
int screen;
Window root;
int errno;
+ /* assume one window per process for now */
+ Window self;
+ XftDraw* xft;
+ Pixmap pixmap;
+ int width;
+ int height;
+ XIC xic;
+ XIM xim;
+ GC gc;
} X;
CAMLprim value x11_connect(void) {
CAMLreturn(Val_unit);
}
+CAMLprim value x11_make_window(value height, value width) {
+ CAMLparam2(height, width);
+ create_window(Int_val(height), Int_val(width));
+ CAMLreturn(Val_unit);
+}
+
+CAMLprim value x11_make_dialog(value height, value width) {
+ CAMLparam2(height, width);
+ create_window(Int_val(height), Int_val(width));
+ Atom WindowType = XInternAtom(X.display, "_NET_WM_WINDOW_TYPE", False);
+ Atom DialogType = XInternAtom(X.display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ XChangeProperty(X.display, X.self, WindowType, XA_ATOM, 32, PropModeReplace, (unsigned char*)&DialogType, 1);
+ 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);
+ XMapWindow(X.display, X.self);
+ } else {
+ XUnmapWindow(X.display, X.self);
+ }
+ CAMLreturn(Val_unit);
+}
+
CAMLprim value x11_errno(void) {
CAMLparam0();
CAMLreturn(Val_int(X.errno));
X.errno = ev->error_code;
return 0;
}
+
+static void create_window(int height, int width) {
+ /* create the main window */
+ X.width = width ;
+ X.height = height;
+ XWindowAttributes wa;
+ XGetWindowAttributes(X.display, X.root, &wa);
+ X.self = XCreateSimpleWindow(X.display, X.root,
+ (wa.width - X.width) / 2,
+ (wa.height - X.height) /2,
+ X.width,
+ X.height,
+ 0, X.depth,
+ 0xffffffff // config_get_int(Color00)
+ );
+
+ /* register interest in the delete window message */
+ Atom wmDeleteMessage = XInternAtom(X.display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(X.display, X.self, &wmDeleteMessage, 1);
+
+ /* setup window attributes and events */
+ XSetWindowAttributes swa;
+ swa.backing_store = WhenMapped;
+ swa.bit_gravity = NorthWestGravity;
+ XChangeWindowAttributes(X.display, X.self, CWBackingStore|CWBitGravity, &swa);
+ XStoreName(X.display, X.self, "tide");
+ XSelectInput(X.display, X.self,
+ StructureNotifyMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | ButtonMotionMask
+ | KeyPressMask
+ | FocusChangeMask
+ | PropertyChangeMask
+ );
+
+ /* set input methods */
+ if ((X.xim = XOpenIM(X.display, 0, 0, 0)))
+ X.xic = XCreateIC(X.xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing,
+ XNClientWindow, X.self, XNFocusWindow, X.self, NULL);
+
+ /* initialize pixmap and drawing context */
+ X.pixmap = XCreatePixmap(X.display, X.self, width, height, X.depth);
+ X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap);
+
+ /* initialize the graphics context */
+ XGCValues gcv;
+ gcv.foreground = WhitePixel(X.display, X.screen);
+ gcv.graphics_exposures = False;
+ X.gc = XCreateGC(X.display, X.self, GCForeground|GCGraphicsExposures, &gcv);
+}