diff --git a/dlibincludes.c b/dlibincludes.c index 8289471..76e64d1 100644 --- a/dlibincludes.c +++ b/dlibincludes.c @@ -1,20 +1,22 @@ //#pragma attribute(push, nogc, nothrow) #ifdef __linux__ -# include -# include +# define XLIB_ILLEGAL_ACCESS +# include # include # include -# include # include # include +# include +# include + # include +# include +# include # include FT_FREETYPE_H # include FT_GLYPH_H #endif -#include - #include "external/stb/stb_image.h" #include "external/stb/stb_image_write.h" diff --git a/platform.d b/platform.d index 46fe08c..44e9847 100644 --- a/platform.d +++ b/platform.d @@ -408,10 +408,10 @@ struct SysThread struct Selection { - bool owned; - u8[] data; - xcb_atom_t target; - xcb_atom_t xmode; + bool owned; + u8[] data; + Atom target; + Atom xmode; } enum Atoms @@ -429,15 +429,15 @@ enum Atoms } const char[][] ATOM_STRS = [ - CastStr!(char)("TARGETS"), - CastStr!(char)("MULTIPLE"), - CastStr!(char)("TIMESTAMP"), - CastStr!(char)("INCR"), - CastStr!(char)("CLIPBOARD"), - CastStr!(char)("UTF8_STRING"), - CastStr!(char)("WM_PROTOCOLS"), - CastStr!(char)("WM_DELETE_WINDOW"), - CastStr!(char)("_NET_WM_STATE_HIDDEN"), + Atoms.Targets: CastStr!(char)("TARGETS"), + Atoms.Multiple: CastStr!(char)("MULTIPLE"), + Atoms.Timestamp: CastStr!(char)("TIMESTAMP"), + Atoms.Incr: CastStr!(char)("INCR"), + Atoms.Clipboard: CastStr!(char)("CLIPBOARD"), + Atoms.Utf8String: CastStr!(char)("UTF8_STRING"), + Atoms.WMProtocols: CastStr!(char)("WM_PROTOCOLS"), + Atoms.DeleteWindow: CastStr!(char)("WM_DELETE_WINDOW"), + Atoms.StateHidden: CastStr!(char)("_NET_WM_STATE_HIDDEN"), ]; alias PThreadProc = extern (C) void* function(void*); @@ -579,13 +579,16 @@ PushMotion(Inputs* inputs, i32 rel_x, i32 rel_y, i32 x, i32 y) struct PlatformWindow { - xcb_atom_t[Atoms.max] atoms; + Atom[Atoms.max] atoms; Display* display; - xcb_connection_t* conn; - xcb_screen_t* screen; - xcb_window_t window; - u16 w; - u16 h; + Window window; + Window root_window; + i32 screen_id; + // xcb_connection_t* conn; + // xcb_screen_t* screen; + // xcb_window_t window; + u32 w; + u32 h; i32 mouse_prev_x; i32 mouse_prev_y; bool locked_cursor; @@ -614,51 +617,144 @@ struct Function void* ptr; }; -pragma(inline) bool -NilErr(PlatformWindow* window, xcb_void_cookie_t* cookie, xcb_generic_error_t* err) +__gshared string WINDOW_ERR_MSG = null; + +string +WindowError() { - bool result = err == null; - pureFree(err); - return result; + return WINDOW_ERR_MSG; } -pragma(inline) void -CheckErr(PlatformWindow *window, xcb_void_cookie_t *cookie, xcb_generic_error_t *err, string msg) +bool +CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisualInfo* visual_info = null) { - assert(err == null, msg); - pureFree(err); -}; - -PlatformWindow -CreateWindow(string name, u16 width, u16 height) -{ - PlatformWindow window = { + PlatformWindow wnd = { w: width, h: height, input_mutex: CreateTicketMut(), - msg_queue: CreateMessageQueue(), - cb_mut: CreateTicketMut(), - cb_msg_mut: CreateMut(), + msg_queue: CreateMessageQueue(), + cb_mut: CreateTicketMut(), + cb_msg_mut: CreateMut(), inputs: [ { arena: CreateArena(MB(1)) }, { arena: CreateArena(MB(1)) }, ], }; - version(linux) - { - window.cb_transfer_size = X11_CB_TRANSFER_SIZE_DEFAULT; - } + *window = wnd; - assert(width > 0 && height > 0, "CreateWindow error: width and height must be above 0"); + window.cb_transfer_size = X11_CB_TRANSFER_SIZE_DEFAULT; window.display = XOpenDisplay(null); - assert(window.display != null, "XOpenDisplay failure"); + if(!window.display) + { + WINDOW_ERR_MSG = "Unable to open X11 display"; + return false; + } + window.root_window = DefaultRootWindow(window.display); + if(window.root_window == None) + { + WINDOW_ERR_MSG = "Unable to retrieve X11 root window"; + return false; + } + + window.screen_id = XDefaultScreen(window.display); + + XSetWindowAttributes attrs = { + background_pixmap: None, + background_pixel: XBlackPixel(window.display, window.screen_id), + }; + + i64 value_mask = CWBackPixmap | CWBackPixel; + + if(visual_info) + { + attrs.colormap = XCreateColormap(window.display, window.root_window, visual_info.visual, AllocNone); + value_mask |= CWColormap; + } + + auto copy = CopyFromParent; + + window.window = XCreateWindow( + window.display, + window.root_window, + 0, + 0, + width, + height, + 0, + (visual_info ? visual_info.depth : cast(i32)copy), + InputOutput, + (visual_info ? visual_info.visual : cast(Visual*)©), + value_mask, + &attrs + ); + + if(window.window == None) + { + WINDOW_ERR_MSG = "Failed to create X11 window"; + return false; + } + + if(visual_info) + { + XFree(visual_info); + } + + i64 event_mask = KeyPressMask | + KeyReleaseMask | + ExposureMask | + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + StructureNotifyMask | + PropertyChangeMask; + + XSelectInput(window.display, window.window, event_mask); + + foreach(atom; Atoms.min .. Atoms.max) + { + window.atoms[atom] = XInternAtom(window.display, ATOM_STRS[atom].ptr, false); + } + + XSetWMProtocols(window.display, window.window, window.atoms.ptr, window.atoms.length); + + XChangeProperty( + window.display, + window.window, + XA_WM_NAME, + XA_STRING, + 8, + PropModeReplace, + cast(const(u8)*)name.ptr, + cast(u32)name.length + ); + XStoreName(window.display, window.window, name.ptr); + + XChangeProperty( + window.display, + window.window, + window.atoms[Atoms.WMProtocols], + XA_ATOM, + 32, + PropModeReplace, + cast(const(u8)*)&window.atoms[Atoms.DeleteWindow], + 1 + ); + + int major, minor; + XFixesQueryVersion(window.display, &major, &minor); + + XMapWindow(window.display, window.window); + + XFlush(window.display); + + /* window.conn = XGetXCBConnection(window.display); assert(window.conn != null, "XGetXCBConnection failure"); - xcb_void_cookie_t cookie; + xcb_void_cookie_t cookie; xcb_generic_error_t *error; xcb_setup_t *setup = xcb_get_setup(window.conn); @@ -753,8 +849,9 @@ CreateWindow(string name, u16 width, u16 height) assert(stream_result > 0, "xcb_flush failure"); xcb_xfixes_query_version(window.conn, 4, 0); + */ - return window; + return true; }; void @@ -773,17 +870,9 @@ LockCursor(PlatformWindow* window) u32 counter = 0; for(;;) { - xcb_generic_error_t *error; - xcb_grab_pointer_cookie_t grab_cookie = xcb_grab_pointer(window.conn, true, window.window, 0, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, window.window, XCB_NONE, XCB_CURRENT_TIME); - xcb_grab_pointer_reply_t* grab_reply = xcb_grab_pointer_reply(window.conn, grab_cookie, &error); + i32 grab_res = XGrabPointer(window.display, window.window, true, 0, GrabModeAsync, GrabModeAsync, window.window, None, CurrentTime); - scope(exit) - { - pureFree(error); - pureFree(grab_reply); - } - - if(grab_reply.status == XCB_GRAB_STATUS_SUCCESS) + if(grab_res == None) { result = true; break; @@ -810,7 +899,7 @@ UnlockCursor(PlatformWindow* window) { if(window.locked_cursor) { - xcb_ungrab_pointer(window.conn, XCB_CURRENT_TIME); + XUngrabPointer(window.display, CurrentTime); ShowCursor(window); window.locked_cursor = false; } @@ -819,71 +908,78 @@ UnlockCursor(PlatformWindow* window) bool HideCursor(PlatformWindow* window) { - xcb_void_cookie_t hide_cursor_cookie = xcb_xfixes_hide_cursor_checked(window.conn, window.window); - xcb_generic_error_t *error = xcb_request_check(window.conn, hide_cursor_cookie); - return NilErr(window, &hide_cursor_cookie, error); + XFixesHideCursor(window.display, window.window); + return true; } bool ShowCursor(PlatformWindow* window) { - xcb_void_cookie_t show_cursor_cookie = xcb_xfixes_show_cursor_checked(window.conn, window.window); - xcb_generic_error_t *error = xcb_request_check(window.conn, show_cursor_cookie); - return NilErr(window, &show_cursor_cookie, error); + XFixesShowCursor(window.display, window.window); + return true; } void -FlushEvents(PlatformWindow* window) +ClearEvents(PlatformWindow* window) { - xcb_generic_event_t* e; - do + for(;;) { - e = xcb_poll_for_event(window.conn); - } while (e); + XEvent ev; + u32 count = XPending(window.display); + for(u32 i = 0; i < count; i += 1) + { + XNextEvent(window.display, &ev); + } + + if(count == 0) + { + break; + } + } } bool -TransmitSelection(PlatformWindow* w, xcb_selection_request_event_t* ev) +TransmitSelection(PlatformWindow* w, XSelectionRequestEvent* ev) { bool result; - if(ev.property == XCB_NONE) + if(ev.property == None) { ev.property = ev.target; } if(ev.target == w.atoms[Atoms.Targets]) { - xcb_atom_t[3] targets = [ + Atom[3] targets = [ w.atoms[Atoms.Timestamp], w.atoms[Atoms.Targets], w.atoms[Atoms.Utf8String] ]; - xcb_change_property( - w.conn, - XCB_PROP_MODE_REPLACE, + XChangeProperty( + w.display, ev.requestor, ev.property, - XCB_ATOM_ATOM, - xcb_atom_t.sizeof * 8, - targets.length, - targets.ptr + XA_ATOM, + Atom.sizeof * 8, + PropModeReplace, + cast(const(u8)*)targets.ptr, + targets.length ); result = true; } else if(ev.target == w.atoms[Atoms.Timestamp]) { - xcb_timestamp_t cur = XCB_CURRENT_TIME; - xcb_change_property( - w.conn, - XCB_PROP_MODE_REPLACE, + Time cur = CurrentTime; + XChangeProperty( + w.display, ev.requestor, ev.property, - XCB_ATOM_INTEGER, + XA_INTEGER, cur.sizeof * 8, - 1, - &cur + PropModeReplace, + cast(const(u8)*)&cur, + 1 ); result = true; @@ -904,15 +1000,15 @@ TransmitSelection(PlatformWindow* w, xcb_selection_request_event_t* ev) if(sel != null && sel.owned && sel.data.length > 0 && sel.target == ev.target) { - xcb_change_property( - w.conn, - XCB_PROP_MODE_REPLACE, + XChangeProperty( + w.display, ev.requestor, ev.property, ev.target, 8, - cast(u32)sel.data.length, - sel.data.ptr + PropModeReplace, + cast(const(u8)*)sel.data.ptr, + cast(u32)sel.data.length ); result = true; @@ -952,10 +1048,9 @@ ClipboardText(PlatformWindow* w, ClipboardMode mode) } else { - auto owner = xcb_get_selection_owner_reply(w.conn, xcb_get_selection_owner(w.conn, sel.xmode), null); - scope(exit) pureFree(owner); + Window owner = XGetSelectionOwner(w.display, sel.xmode); - if(owner != null && owner.owner != 0) + if(owner == None) { Free(sel.data); sel.data = []; @@ -965,8 +1060,8 @@ ClipboardText(PlatformWindow* w, ClipboardMode mode) u64 ticket = w.cb_mut.next_ticket; sel.target = w.atoms[Atoms.Utf8String]; - xcb_convert_selection(w.conn, w.window, sel.xmode, sel.target, sel.xmode, XCB_CURRENT_TIME); - xcb_flush(w.conn); + XConvertSelection(w.display, sel.xmode, sel.target, sel.xmode, w.window, CurrentTime); + XFlush(w.display); while(ticket == w.cb_mut.next_ticket) {} @@ -1009,8 +1104,8 @@ SetClipboard(PlatformWindow* w, u8[] data, ClipboardMode mode) sel.owned = true; sel.target = w.atoms[Atoms.Utf8String]; - xcb_set_selection_owner(w.conn, w.window, sel.xmode, XCB_CURRENT_TIME); - xcb_flush(w.conn); + XSetSelectionOwner(w.display, sel.xmode, w.window, CurrentTime); + XFlush(w.display); } else { @@ -1041,49 +1136,40 @@ GetClipboardSelection(PlatformWindow* w, Selection* sel) } void -RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev) +RetrieveSelection(PlatformWindow* w, XSelectionEvent* ev) { Lock(&w.cb_mut); scope(exit) Unlock(&w.cb_mut); u8[] buf; - u64 buf_size; - u64 bytes_after = 1; - xcb_get_property_reply_t* reply; - xcb_atom_t actual_type; - u8 actual_format; + u64 buf_size; + u64 bytes_after = 1; + Atom actual_type; + i32 actual_format; + u64 nitems; + u8* prop_data; - if(ev.property == XCB_ATOM_PRIMARY || ev.property == XCB_ATOM_SECONDARY || ev.property == w.atoms[Atoms.Clipboard]) + if(ev.property == XA_PRIMARY || ev.property == XA_SECONDARY || ev.property == w.atoms[Atoms.Clipboard]) { while(bytes_after > 0) { - scope(exit) pureFree(reply); + scope(exit) XFree(prop_data); - xcb_get_property_cookie_t cookie = xcb_get_property( - w.conn, - true, + i32 get_res = XGetWindowProperty( + w.display, w.window, ev.property, - XCB_ATOM_ANY, cast(u32)(buf_size/4), - cast(u32)(w.cb_transfer_size/4) + cast(u32)(w.cb_transfer_size/4), + true, + AnyPropertyType, + &actual_type, + &actual_format, + &nitems, + &bytes_after, + &prop_data ); - reply = xcb_get_property_reply(w.conn, cookie, null); - - if(reply == null || (buf_size > 0 && (reply.format != actual_format || reply.type != actual_type)) || reply.format%8 != 0) - { - Errf("RetrieveSelection failure: Invalid return value from xcb_get_property_reply"); - break; - } - - if(buf_size == 0) - { - actual_type = reply.type; - actual_format = reply.format; - } - - int nitems = xcb_get_property_value_length(reply); if(nitems > 0) { if(buf_size%4 != 0) @@ -1092,14 +1178,13 @@ RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev) break; } - u64 unit_size = reply.format/8; - buf = Alloc!(u8)(unit_size * (buf_size + nitems)); + u64 unit_size = actual_format/8; + u64 data_len = unit_size * nitems; + buf = Realloc!(u8)(buf, data_len + buf_size); - MemCpy(buf.ptr + buf_size, xcb_get_property_value(reply), nitems * unit_size); - buf_size += nitems * unit_size; + MemCpy(buf.ptr + buf_size, prop_data, data_len); + buf_size += data_len; } - - bytes_after = reply.bytes_after; } } @@ -1133,9 +1218,9 @@ RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev) } void -ClearSelection(PlatformWindow* w, xcb_selection_clear_event_t* ev) +ClearSelection(PlatformWindow* w, XSelectionClearEvent* ev) { - if(ev.owner == w.window) + if(ev.window == w.window) { foreach(i; CBM.min .. CBM.max) { @@ -1163,7 +1248,7 @@ HandleEvents(void* window_ptr) PlatformWindow* w = cast(PlatformWindow*)window_ptr; DNode!(SysMessage)* sys_msg = g_NIL_MSG; - xcb_generic_event_t* e; + XEvent e; bool ignore_mouse_events = false; @@ -1225,39 +1310,38 @@ HandleEvents(void* window_ptr) } } - e = xcb_poll_for_event(w.conn); - - if(e) + if(XPending(w.display)) { + XNextEvent(w.display, &e); Inputs* inputs = GetInputs(w); - switch (e.response_type & ~0x80) + switch (e.type) { - case XCB_CLIENT_MESSAGE: + case ClientMessage: { - xcb_client_message_event_t* msg = cast(xcb_client_message_event_t*)e; + XClientMessageEvent* msg = &e.xclient; if(msg.window != w.window) { break; } - if(msg.data.data32[0] == w.atoms[Atoms.DeleteWindow]) + if(msg.data.l[0] == w.atoms[Atoms.DeleteWindow]) { w.close = true; } } break; - case XCB_KEY_RELEASE: - case XCB_KEY_PRESS: + case KeyRelease: + case KeyPress: { - xcb_key_press_event_t* keyboard_event = cast(xcb_key_press_event_t*)e; + XKeyEvent* kb_ev = &e.xkey; - bool pressed = e.response_type == XCB_KEY_PRESS; - xcb_keycode_t code = keyboard_event.detail; + bool pressed = e.type == KeyPress; + u32 code = kb_ev.keycode; KeySym key_sym = XkbKeycodeToKeysym(w.display, cast(KeyCode)code, 0, 0); - Input input = ConvertInput(key_sym); + Input input = ConvertInput(key_sym); enum modifier_inputs = [Input.LeftShift, Input.RightShift, Input.LeftCtrl, Input.RightCtrl, Input.LeftAlt, Input.RightAlt]; - enum modifiers = [MD.LeftShift, MD.RightShift, MD.LeftCtrl, MD.RightCtrl, MD.LeftAlt, MD.RightAlt]; + enum modifiers = [MD.LeftShift, MD.RightShift, MD.LeftCtrl, MD.RightCtrl, MD.LeftAlt, MD.RightAlt]; static foreach(i, md; modifier_inputs) { @@ -1269,37 +1353,38 @@ HandleEvents(void* window_ptr) if(input != Input.None) { - Push(inputs, input, keyboard_event.event_x, keyboard_event.event_y, pressed, w.modifier); + Push(inputs, input, kb_ev.x, kb_ev.y, pressed, w.modifier); } } break; - case XCB_BUTTON_PRESS: - case XCB_BUTTON_RELEASE: + case ButtonPress: + case ButtonRelease: { - xcb_button_press_event_t* mouse_event = cast(xcb_button_press_event_t*)e; - bool pressed = e.response_type == XCB_BUTTON_PRESS; - Input input = Input.None; + XButtonEvent* mouse_event = &e.xbutton; - switch (mouse_event.detail) + bool pressed = e.type == ButtonPress; + Input input = Input.None; + + switch (mouse_event.button) { - case XCB_BUTTON_INDEX_1: input = Input.LeftClick; break; - case XCB_BUTTON_INDEX_2: input = Input.MiddleClick; break; - case XCB_BUTTON_INDEX_3: input = Input.RightClick; break; + case Button1: input = Input.LeftClick; break; + case Button2: input = Input.MiddleClick; break; + case Button3: input = Input.RightClick; break; default: break; } if(input != Input.None) { - Push(inputs, input, mouse_event.event_x, mouse_event.event_y, pressed, w.modifier); + Push(inputs, input, mouse_event.x, mouse_event.y, pressed, w.modifier); } } break; - case XCB_MOTION_NOTIFY: + case MotionNotify: { if(ignore_mouse_events) continue; - xcb_motion_notify_event_t* move_event = cast(xcb_motion_notify_event_t*)e; + XMotionEvent* move_event = &e.xmotion; - i16 x = move_event.event_x; - i16 y = move_event.event_y; + i32 x = move_event.x; + i32 y = move_event.y; static bool first = true; if(first) @@ -1320,45 +1405,48 @@ HandleEvents(void* window_ptr) if(w.locked_cursor && (x < WINDOW_EDGE_BUFFER || y < WINDOW_EDGE_BUFFER || x > w.w - WINDOW_EDGE_BUFFER || y > w.h - WINDOW_EDGE_BUFFER)) { - i16 new_x = cast(i16)(w.w / 2); - i16 new_y = cast(i16)(w.h / 2); - xcb_warp_pointer(w.conn, w.window, w.window, 0, 0, cast(i16)w.w, cast(i16)w.h, new_x, new_y); + i32 new_x = cast(i32)(w.w / 2); + i32 new_y = cast(i32)(w.h / 2); + XWarpPointer(w.display, w.window, w.window, 0, 0, cast(i16)w.w, cast(i16)w.h, new_x, new_y); w.mouse_prev_x = new_x; w.mouse_prev_y = new_y; ignore_mouse_events = true; } } break; - case XCB_CONFIGURE_NOTIFY: + case ConfigureNotify: { - xcb_configure_notify_event_t* config_event = cast(xcb_configure_notify_event_t*)e; + XConfigureEvent* config_event = &e.xconfigure; if(w.w != config_event.width || w.h != config_event.height) { w.w = config_event.width; w.h = config_event.height; } } break; - case XCB_SELECTION_CLEAR: + case SelectionClear: { - ClearSelection(w, cast(xcb_selection_clear_event_t*)e); + ClearSelection(w, &e.xselectionclear); } break; - case XCB_SELECTION_NOTIFY: + case SelectionNotify: { - RetrieveSelection(w, cast(xcb_selection_notify_event_t*)e); + RetrieveSelection(w, &e.xselection); } break; - case XCB_SELECTION_REQUEST: + case SelectionRequest: { - auto req = cast(xcb_selection_request_event_t*)e; - xcb_selection_notify_event_t notify = { - response_type: XCB_SELECTION_NOTIFY, - time: XCB_CURRENT_TIME, - requestor: req.requestor, - selection: req.selection, - target: req.target, - property: TransmitSelection(w, req) ? req.property : XCB_NONE, + auto req = &e.xselectionrequest; + XEvent notify = { + xselection: { + type: SelectionNotify, + time: CurrentTime, + display: w.display, + requestor: req.requestor, + selection: req.selection, + target: req.target, + property: TransmitSelection(w, req) ? req.property : None, + }, }; - xcb_send_event(w.conn, false, req.requestor, XCB_EVENT_MASK_PROPERTY_CHANGE, cast(char*)¬ify); - xcb_flush(w.conn); + XSendEvent(w.display, req.requestor, false, PropertyChangeMask, ¬ify); + XFlush(w.display); } break; default: break; } diff --git a/util.d b/util.d index 0a8188c..2cce492 100644 --- a/util.d +++ b/util.d @@ -33,6 +33,15 @@ Pause() } } +void +Assert(T)(T cond, string msg) +{ + if(!cond) + { + assert(false, msg); + } +} + string ConvToStr(T)(T[] arr) {