port from xcb to x11
This commit is contained in:
parent
2ba1ae480c
commit
a221c1d5ce
@ -1,20 +1,22 @@
|
|||||||
//#pragma attribute(push, nogc, nothrow)
|
//#pragma attribute(push, nogc, nothrow)
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include <xcb/xcb.h>
|
# define XLIB_ILLEGAL_ACCESS
|
||||||
# include <xcb/xfixes.h>
|
# include <X11/Xlib.h>
|
||||||
# include <X11/XKBlib.h>
|
# include <X11/XKBlib.h>
|
||||||
# include <X11/Xlib-xcb.h>
|
# include <X11/Xlib-xcb.h>
|
||||||
# include <X11/Xlib.h>
|
|
||||||
# include <X11/keysym.h>
|
# include <X11/keysym.h>
|
||||||
# include <X11/extensions/Xfixes.h>
|
# include <X11/extensions/Xfixes.h>
|
||||||
|
# include <X11/Xatom.h>
|
||||||
|
# include <X11/Xutil.h>
|
||||||
|
|
||||||
# include <ft2build.h>
|
# include <ft2build.h>
|
||||||
|
# include <GL/glx.h>
|
||||||
|
# include <GL/glxext.h>
|
||||||
# include FT_FREETYPE_H
|
# include FT_FREETYPE_H
|
||||||
# include FT_GLYPH_H
|
# include FT_GLYPH_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
|
|
||||||
#include "external/stb/stb_image.h"
|
#include "external/stb/stb_image.h"
|
||||||
|
|
||||||
#include "external/stb/stb_image_write.h"
|
#include "external/stb/stb_image_write.h"
|
||||||
|
|||||||
452
platform.d
452
platform.d
@ -408,10 +408,10 @@ struct SysThread
|
|||||||
|
|
||||||
struct Selection
|
struct Selection
|
||||||
{
|
{
|
||||||
bool owned;
|
bool owned;
|
||||||
u8[] data;
|
u8[] data;
|
||||||
xcb_atom_t target;
|
Atom target;
|
||||||
xcb_atom_t xmode;
|
Atom xmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Atoms
|
enum Atoms
|
||||||
@ -429,15 +429,15 @@ enum Atoms
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char[][] ATOM_STRS = [
|
const char[][] ATOM_STRS = [
|
||||||
CastStr!(char)("TARGETS"),
|
Atoms.Targets: CastStr!(char)("TARGETS"),
|
||||||
CastStr!(char)("MULTIPLE"),
|
Atoms.Multiple: CastStr!(char)("MULTIPLE"),
|
||||||
CastStr!(char)("TIMESTAMP"),
|
Atoms.Timestamp: CastStr!(char)("TIMESTAMP"),
|
||||||
CastStr!(char)("INCR"),
|
Atoms.Incr: CastStr!(char)("INCR"),
|
||||||
CastStr!(char)("CLIPBOARD"),
|
Atoms.Clipboard: CastStr!(char)("CLIPBOARD"),
|
||||||
CastStr!(char)("UTF8_STRING"),
|
Atoms.Utf8String: CastStr!(char)("UTF8_STRING"),
|
||||||
CastStr!(char)("WM_PROTOCOLS"),
|
Atoms.WMProtocols: CastStr!(char)("WM_PROTOCOLS"),
|
||||||
CastStr!(char)("WM_DELETE_WINDOW"),
|
Atoms.DeleteWindow: CastStr!(char)("WM_DELETE_WINDOW"),
|
||||||
CastStr!(char)("_NET_WM_STATE_HIDDEN"),
|
Atoms.StateHidden: CastStr!(char)("_NET_WM_STATE_HIDDEN"),
|
||||||
];
|
];
|
||||||
|
|
||||||
alias PThreadProc = extern (C) void* function(void*);
|
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
|
struct PlatformWindow
|
||||||
{
|
{
|
||||||
xcb_atom_t[Atoms.max] atoms;
|
Atom[Atoms.max] atoms;
|
||||||
Display* display;
|
Display* display;
|
||||||
xcb_connection_t* conn;
|
Window window;
|
||||||
xcb_screen_t* screen;
|
Window root_window;
|
||||||
xcb_window_t window;
|
i32 screen_id;
|
||||||
u16 w;
|
// xcb_connection_t* conn;
|
||||||
u16 h;
|
// xcb_screen_t* screen;
|
||||||
|
// xcb_window_t window;
|
||||||
|
u32 w;
|
||||||
|
u32 h;
|
||||||
i32 mouse_prev_x;
|
i32 mouse_prev_x;
|
||||||
i32 mouse_prev_y;
|
i32 mouse_prev_y;
|
||||||
bool locked_cursor;
|
bool locked_cursor;
|
||||||
@ -614,51 +617,144 @@ struct Function
|
|||||||
void* ptr;
|
void* ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
pragma(inline) bool
|
__gshared string WINDOW_ERR_MSG = null;
|
||||||
NilErr(PlatformWindow* window, xcb_void_cookie_t* cookie, xcb_generic_error_t* err)
|
|
||||||
|
string
|
||||||
|
WindowError()
|
||||||
{
|
{
|
||||||
bool result = err == null;
|
return WINDOW_ERR_MSG;
|
||||||
pureFree(err);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) void
|
bool
|
||||||
CheckErr(PlatformWindow *window, xcb_void_cookie_t *cookie, xcb_generic_error_t *err, string msg)
|
CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisualInfo* visual_info = null)
|
||||||
{
|
{
|
||||||
assert(err == null, msg);
|
PlatformWindow wnd = {
|
||||||
pureFree(err);
|
|
||||||
};
|
|
||||||
|
|
||||||
PlatformWindow
|
|
||||||
CreateWindow(string name, u16 width, u16 height)
|
|
||||||
{
|
|
||||||
PlatformWindow window = {
|
|
||||||
w: width,
|
w: width,
|
||||||
h: height,
|
h: height,
|
||||||
input_mutex: CreateTicketMut(),
|
input_mutex: CreateTicketMut(),
|
||||||
msg_queue: CreateMessageQueue(),
|
msg_queue: CreateMessageQueue(),
|
||||||
cb_mut: CreateTicketMut(),
|
cb_mut: CreateTicketMut(),
|
||||||
cb_msg_mut: CreateMut(),
|
cb_msg_mut: CreateMut(),
|
||||||
inputs: [
|
inputs: [
|
||||||
{ arena: CreateArena(MB(1)) },
|
{ arena: CreateArena(MB(1)) },
|
||||||
{ arena: CreateArena(MB(1)) },
|
{ arena: CreateArena(MB(1)) },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
version(linux)
|
*window = wnd;
|
||||||
{
|
|
||||||
window.cb_transfer_size = X11_CB_TRANSFER_SIZE_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
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);
|
window.conn = XGetXCBConnection(window.display);
|
||||||
assert(window.conn != null, "XGetXCBConnection failure");
|
assert(window.conn != null, "XGetXCBConnection failure");
|
||||||
|
|
||||||
xcb_void_cookie_t cookie;
|
xcb_void_cookie_t cookie;
|
||||||
xcb_generic_error_t *error;
|
xcb_generic_error_t *error;
|
||||||
|
|
||||||
xcb_setup_t *setup = xcb_get_setup(window.conn);
|
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");
|
assert(stream_result > 0, "xcb_flush failure");
|
||||||
|
|
||||||
xcb_xfixes_query_version(window.conn, 4, 0);
|
xcb_xfixes_query_version(window.conn, 4, 0);
|
||||||
|
*/
|
||||||
|
|
||||||
return window;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -773,17 +870,9 @@ LockCursor(PlatformWindow* window)
|
|||||||
u32 counter = 0;
|
u32 counter = 0;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
xcb_generic_error_t *error;
|
i32 grab_res = XGrabPointer(window.display, window.window, true, 0, GrabModeAsync, GrabModeAsync, window.window, None, CurrentTime);
|
||||||
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);
|
|
||||||
|
|
||||||
scope(exit)
|
if(grab_res == None)
|
||||||
{
|
|
||||||
pureFree(error);
|
|
||||||
pureFree(grab_reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(grab_reply.status == XCB_GRAB_STATUS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
@ -810,7 +899,7 @@ UnlockCursor(PlatformWindow* window)
|
|||||||
{
|
{
|
||||||
if(window.locked_cursor)
|
if(window.locked_cursor)
|
||||||
{
|
{
|
||||||
xcb_ungrab_pointer(window.conn, XCB_CURRENT_TIME);
|
XUngrabPointer(window.display, CurrentTime);
|
||||||
ShowCursor(window);
|
ShowCursor(window);
|
||||||
window.locked_cursor = false;
|
window.locked_cursor = false;
|
||||||
}
|
}
|
||||||
@ -819,71 +908,78 @@ UnlockCursor(PlatformWindow* window)
|
|||||||
bool
|
bool
|
||||||
HideCursor(PlatformWindow* window)
|
HideCursor(PlatformWindow* window)
|
||||||
{
|
{
|
||||||
xcb_void_cookie_t hide_cursor_cookie = xcb_xfixes_hide_cursor_checked(window.conn, window.window);
|
XFixesHideCursor(window.display, window.window);
|
||||||
xcb_generic_error_t *error = xcb_request_check(window.conn, hide_cursor_cookie);
|
return true;
|
||||||
return NilErr(window, &hide_cursor_cookie, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ShowCursor(PlatformWindow* window)
|
ShowCursor(PlatformWindow* window)
|
||||||
{
|
{
|
||||||
xcb_void_cookie_t show_cursor_cookie = xcb_xfixes_show_cursor_checked(window.conn, window.window);
|
XFixesShowCursor(window.display, window.window);
|
||||||
xcb_generic_error_t *error = xcb_request_check(window.conn, show_cursor_cookie);
|
return true;
|
||||||
return NilErr(window, &show_cursor_cookie, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlushEvents(PlatformWindow* window)
|
ClearEvents(PlatformWindow* window)
|
||||||
{
|
{
|
||||||
xcb_generic_event_t* e;
|
for(;;)
|
||||||
do
|
|
||||||
{
|
{
|
||||||
e = xcb_poll_for_event(window.conn);
|
XEvent ev;
|
||||||
} while (e);
|
u32 count = XPending(window.display);
|
||||||
|
for(u32 i = 0; i < count; i += 1)
|
||||||
|
{
|
||||||
|
XNextEvent(window.display, &ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TransmitSelection(PlatformWindow* w, xcb_selection_request_event_t* ev)
|
TransmitSelection(PlatformWindow* w, XSelectionRequestEvent* ev)
|
||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
if(ev.property == XCB_NONE)
|
if(ev.property == None)
|
||||||
{
|
{
|
||||||
ev.property = ev.target;
|
ev.property = ev.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ev.target == w.atoms[Atoms.Targets])
|
if(ev.target == w.atoms[Atoms.Targets])
|
||||||
{
|
{
|
||||||
xcb_atom_t[3] targets = [
|
Atom[3] targets = [
|
||||||
w.atoms[Atoms.Timestamp],
|
w.atoms[Atoms.Timestamp],
|
||||||
w.atoms[Atoms.Targets],
|
w.atoms[Atoms.Targets],
|
||||||
w.atoms[Atoms.Utf8String]
|
w.atoms[Atoms.Utf8String]
|
||||||
];
|
];
|
||||||
|
|
||||||
xcb_change_property(
|
XChangeProperty(
|
||||||
w.conn,
|
w.display,
|
||||||
XCB_PROP_MODE_REPLACE,
|
|
||||||
ev.requestor,
|
ev.requestor,
|
||||||
ev.property,
|
ev.property,
|
||||||
XCB_ATOM_ATOM,
|
XA_ATOM,
|
||||||
xcb_atom_t.sizeof * 8,
|
Atom.sizeof * 8,
|
||||||
targets.length,
|
PropModeReplace,
|
||||||
targets.ptr
|
cast(const(u8)*)targets.ptr,
|
||||||
|
targets.length
|
||||||
);
|
);
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else if(ev.target == w.atoms[Atoms.Timestamp])
|
else if(ev.target == w.atoms[Atoms.Timestamp])
|
||||||
{
|
{
|
||||||
xcb_timestamp_t cur = XCB_CURRENT_TIME;
|
Time cur = CurrentTime;
|
||||||
xcb_change_property(
|
XChangeProperty(
|
||||||
w.conn,
|
w.display,
|
||||||
XCB_PROP_MODE_REPLACE,
|
|
||||||
ev.requestor,
|
ev.requestor,
|
||||||
ev.property,
|
ev.property,
|
||||||
XCB_ATOM_INTEGER,
|
XA_INTEGER,
|
||||||
cur.sizeof * 8,
|
cur.sizeof * 8,
|
||||||
1,
|
PropModeReplace,
|
||||||
&cur
|
cast(const(u8)*)&cur,
|
||||||
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
result = true;
|
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)
|
if(sel != null && sel.owned && sel.data.length > 0 && sel.target == ev.target)
|
||||||
{
|
{
|
||||||
xcb_change_property(
|
XChangeProperty(
|
||||||
w.conn,
|
w.display,
|
||||||
XCB_PROP_MODE_REPLACE,
|
|
||||||
ev.requestor,
|
ev.requestor,
|
||||||
ev.property,
|
ev.property,
|
||||||
ev.target,
|
ev.target,
|
||||||
8,
|
8,
|
||||||
cast(u32)sel.data.length,
|
PropModeReplace,
|
||||||
sel.data.ptr
|
cast(const(u8)*)sel.data.ptr,
|
||||||
|
cast(u32)sel.data.length
|
||||||
);
|
);
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
@ -952,10 +1048,9 @@ ClipboardText(PlatformWindow* w, ClipboardMode mode)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto owner = xcb_get_selection_owner_reply(w.conn, xcb_get_selection_owner(w.conn, sel.xmode), null);
|
Window owner = XGetSelectionOwner(w.display, sel.xmode);
|
||||||
scope(exit) pureFree(owner);
|
|
||||||
|
|
||||||
if(owner != null && owner.owner != 0)
|
if(owner == None)
|
||||||
{
|
{
|
||||||
Free(sel.data);
|
Free(sel.data);
|
||||||
sel.data = [];
|
sel.data = [];
|
||||||
@ -965,8 +1060,8 @@ ClipboardText(PlatformWindow* w, ClipboardMode mode)
|
|||||||
u64 ticket = w.cb_mut.next_ticket;
|
u64 ticket = w.cb_mut.next_ticket;
|
||||||
|
|
||||||
sel.target = w.atoms[Atoms.Utf8String];
|
sel.target = w.atoms[Atoms.Utf8String];
|
||||||
xcb_convert_selection(w.conn, w.window, sel.xmode, sel.target, sel.xmode, XCB_CURRENT_TIME);
|
XConvertSelection(w.display, sel.xmode, sel.target, sel.xmode, w.window, CurrentTime);
|
||||||
xcb_flush(w.conn);
|
XFlush(w.display);
|
||||||
|
|
||||||
while(ticket == w.cb_mut.next_ticket) {}
|
while(ticket == w.cb_mut.next_ticket) {}
|
||||||
|
|
||||||
@ -1009,8 +1104,8 @@ SetClipboard(PlatformWindow* w, u8[] data, ClipboardMode mode)
|
|||||||
sel.owned = true;
|
sel.owned = true;
|
||||||
sel.target = w.atoms[Atoms.Utf8String];
|
sel.target = w.atoms[Atoms.Utf8String];
|
||||||
|
|
||||||
xcb_set_selection_owner(w.conn, w.window, sel.xmode, XCB_CURRENT_TIME);
|
XSetSelectionOwner(w.display, sel.xmode, w.window, CurrentTime);
|
||||||
xcb_flush(w.conn);
|
XFlush(w.display);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1041,49 +1136,40 @@ GetClipboardSelection(PlatformWindow* w, Selection* sel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev)
|
RetrieveSelection(PlatformWindow* w, XSelectionEvent* ev)
|
||||||
{
|
{
|
||||||
Lock(&w.cb_mut);
|
Lock(&w.cb_mut);
|
||||||
scope(exit) Unlock(&w.cb_mut);
|
scope(exit) Unlock(&w.cb_mut);
|
||||||
|
|
||||||
u8[] buf;
|
u8[] buf;
|
||||||
u64 buf_size;
|
u64 buf_size;
|
||||||
u64 bytes_after = 1;
|
u64 bytes_after = 1;
|
||||||
xcb_get_property_reply_t* reply;
|
Atom actual_type;
|
||||||
xcb_atom_t actual_type;
|
i32 actual_format;
|
||||||
u8 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)
|
while(bytes_after > 0)
|
||||||
{
|
{
|
||||||
scope(exit) pureFree(reply);
|
scope(exit) XFree(prop_data);
|
||||||
|
|
||||||
xcb_get_property_cookie_t cookie = xcb_get_property(
|
i32 get_res = XGetWindowProperty(
|
||||||
w.conn,
|
w.display,
|
||||||
true,
|
|
||||||
w.window,
|
w.window,
|
||||||
ev.property,
|
ev.property,
|
||||||
XCB_ATOM_ANY,
|
|
||||||
cast(u32)(buf_size/4),
|
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(nitems > 0)
|
||||||
{
|
{
|
||||||
if(buf_size%4 != 0)
|
if(buf_size%4 != 0)
|
||||||
@ -1092,14 +1178,13 @@ RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 unit_size = reply.format/8;
|
u64 unit_size = actual_format/8;
|
||||||
buf = Alloc!(u8)(unit_size * (buf_size + nitems));
|
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);
|
MemCpy(buf.ptr + buf_size, prop_data, data_len);
|
||||||
buf_size += nitems * unit_size;
|
buf_size += data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes_after = reply.bytes_after;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,9 +1218,9 @@ RetrieveSelection(PlatformWindow* w, xcb_selection_notify_event_t* ev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)
|
foreach(i; CBM.min .. CBM.max)
|
||||||
{
|
{
|
||||||
@ -1163,7 +1248,7 @@ HandleEvents(void* window_ptr)
|
|||||||
PlatformWindow* w = cast(PlatformWindow*)window_ptr;
|
PlatformWindow* w = cast(PlatformWindow*)window_ptr;
|
||||||
|
|
||||||
DNode!(SysMessage)* sys_msg = g_NIL_MSG;
|
DNode!(SysMessage)* sys_msg = g_NIL_MSG;
|
||||||
xcb_generic_event_t* e;
|
XEvent e;
|
||||||
|
|
||||||
bool ignore_mouse_events = false;
|
bool ignore_mouse_events = false;
|
||||||
|
|
||||||
@ -1225,39 +1310,38 @@ HandleEvents(void* window_ptr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e = xcb_poll_for_event(w.conn);
|
if(XPending(w.display))
|
||||||
|
|
||||||
if(e)
|
|
||||||
{
|
{
|
||||||
|
XNextEvent(w.display, &e);
|
||||||
Inputs* inputs = GetInputs(w);
|
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)
|
if(msg.window != w.window)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(msg.data.data32[0] == w.atoms[Atoms.DeleteWindow])
|
if(msg.data.l[0] == w.atoms[Atoms.DeleteWindow])
|
||||||
{
|
{
|
||||||
w.close = true;
|
w.close = true;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case XCB_KEY_RELEASE:
|
case KeyRelease:
|
||||||
case XCB_KEY_PRESS:
|
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;
|
bool pressed = e.type == KeyPress;
|
||||||
xcb_keycode_t code = keyboard_event.detail;
|
u32 code = kb_ev.keycode;
|
||||||
KeySym key_sym = XkbKeycodeToKeysym(w.display, cast(KeyCode)code, 0, 0);
|
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 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)
|
static foreach(i, md; modifier_inputs)
|
||||||
{
|
{
|
||||||
@ -1269,37 +1353,38 @@ HandleEvents(void* window_ptr)
|
|||||||
|
|
||||||
if(input != Input.None)
|
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;
|
} break;
|
||||||
case XCB_BUTTON_PRESS:
|
case ButtonPress:
|
||||||
case XCB_BUTTON_RELEASE:
|
case ButtonRelease:
|
||||||
{
|
{
|
||||||
xcb_button_press_event_t* mouse_event = cast(xcb_button_press_event_t*)e;
|
XButtonEvent* mouse_event = &e.xbutton;
|
||||||
bool pressed = e.response_type == XCB_BUTTON_PRESS;
|
|
||||||
Input input = Input.None;
|
|
||||||
|
|
||||||
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 Button1: input = Input.LeftClick; break;
|
||||||
case XCB_BUTTON_INDEX_2: input = Input.MiddleClick; break;
|
case Button2: input = Input.MiddleClick; break;
|
||||||
case XCB_BUTTON_INDEX_3: input = Input.RightClick; break;
|
case Button3: input = Input.RightClick; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(input != Input.None)
|
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;
|
} break;
|
||||||
case XCB_MOTION_NOTIFY:
|
case MotionNotify:
|
||||||
{
|
{
|
||||||
if(ignore_mouse_events) continue;
|
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;
|
i32 x = move_event.x;
|
||||||
i16 y = move_event.event_y;
|
i32 y = move_event.y;
|
||||||
|
|
||||||
static bool first = true;
|
static bool first = true;
|
||||||
if(first)
|
if(first)
|
||||||
@ -1320,45 +1405,48 @@ HandleEvents(void* window_ptr)
|
|||||||
if(w.locked_cursor &&
|
if(w.locked_cursor &&
|
||||||
(x < WINDOW_EDGE_BUFFER || y < WINDOW_EDGE_BUFFER || x > w.w - WINDOW_EDGE_BUFFER || y > w.h - WINDOW_EDGE_BUFFER))
|
(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);
|
i32 new_x = cast(i32)(w.w / 2);
|
||||||
i16 new_y = cast(i16)(w.h / 2);
|
i32 new_y = cast(i32)(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);
|
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_x = new_x;
|
||||||
w.mouse_prev_y = new_y;
|
w.mouse_prev_y = new_y;
|
||||||
ignore_mouse_events = true;
|
ignore_mouse_events = true;
|
||||||
}
|
}
|
||||||
} break;
|
} 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)
|
if(w.w != config_event.width || w.h != config_event.height)
|
||||||
{
|
{
|
||||||
w.w = config_event.width;
|
w.w = config_event.width;
|
||||||
w.h = config_event.height;
|
w.h = config_event.height;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case XCB_SELECTION_CLEAR:
|
case SelectionClear:
|
||||||
{
|
{
|
||||||
ClearSelection(w, cast(xcb_selection_clear_event_t*)e);
|
ClearSelection(w, &e.xselectionclear);
|
||||||
} break;
|
} break;
|
||||||
case XCB_SELECTION_NOTIFY:
|
case SelectionNotify:
|
||||||
{
|
{
|
||||||
RetrieveSelection(w, cast(xcb_selection_notify_event_t*)e);
|
RetrieveSelection(w, &e.xselection);
|
||||||
} break;
|
} break;
|
||||||
case XCB_SELECTION_REQUEST:
|
case SelectionRequest:
|
||||||
{
|
{
|
||||||
auto req = cast(xcb_selection_request_event_t*)e;
|
auto req = &e.xselectionrequest;
|
||||||
xcb_selection_notify_event_t notify = {
|
XEvent notify = {
|
||||||
response_type: XCB_SELECTION_NOTIFY,
|
xselection: {
|
||||||
time: XCB_CURRENT_TIME,
|
type: SelectionNotify,
|
||||||
requestor: req.requestor,
|
time: CurrentTime,
|
||||||
selection: req.selection,
|
display: w.display,
|
||||||
target: req.target,
|
requestor: req.requestor,
|
||||||
property: TransmitSelection(w, req) ? req.property : XCB_NONE,
|
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);
|
XSendEvent(w.display, req.requestor, false, PropertyChangeMask, ¬ify);
|
||||||
xcb_flush(w.conn);
|
XFlush(w.display);
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user