linux copy/paste
parent
61ddb8a9d1
commit
1f078aa96c
|
@ -158,6 +158,7 @@ struct Linux_Vars {
|
|||
int step_timer_fd;
|
||||
u64 last_step_time;
|
||||
|
||||
XCursor xcursors[APP_MOUSE_CURSOR_COUNT];
|
||||
Application_Mouse_Cursor cursor;
|
||||
XCursor hidden_cursor;
|
||||
i32 cursor_show;
|
||||
|
@ -168,7 +169,9 @@ struct Linux_Vars {
|
|||
|
||||
System_Mutex global_frame_mutex;
|
||||
|
||||
Arena clipboard_out_arena;
|
||||
Arena* clipboard_out_arena;
|
||||
Arena* clipboard_arena;
|
||||
String_Const_u8 clipboard_out_contents;
|
||||
String_Const_u8 clipboard_contents;
|
||||
b32 received_new_clipboard;
|
||||
|
||||
|
@ -892,6 +895,11 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
|
|||
int xfixes_version_unused, xfixes_err_unused;
|
||||
Bool has_xfixes = XQueryExtension(linuxvars.dpy, "XFIXES", &xfixes_version_unused, &linuxvars.xfixes_selection_event, &xfixes_err_unused);
|
||||
linuxvars.has_xfixes = (has_xfixes == True);
|
||||
|
||||
// request notifications for CLIPBOARD updates.
|
||||
if(has_xfixes) {
|
||||
XFixesSelectSelectionInput(linuxvars.dpy, linuxvars.win, linuxvars.atom_CLIPBOARD, XFixesSetSelectionOwnerNotifyMask);
|
||||
}
|
||||
}
|
||||
|
||||
// Input handling init
|
||||
|
@ -967,6 +975,26 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
|
|||
| xim_event_mask;
|
||||
|
||||
XSelectInput(linuxvars.dpy, linuxvars.win, event_mask);
|
||||
|
||||
XCursor cursors[APP_MOUSE_CURSOR_COUNT] = {
|
||||
None,
|
||||
None,
|
||||
XCreateFontCursor(linuxvars.dpy, XC_xterm),
|
||||
XCreateFontCursor(linuxvars.dpy, XC_sb_h_double_arrow),
|
||||
XCreateFontCursor(linuxvars.dpy, XC_sb_v_double_arrow)
|
||||
};
|
||||
block_copy(linuxvars.xcursors, cursors, sizeof(cursors));
|
||||
|
||||
// sneaky invisible cursor
|
||||
{
|
||||
char data = 0;
|
||||
XColor c = {};
|
||||
Pixmap p = XCreateBitmapFromData(linuxvars.dpy, linuxvars.win, &data, 1, 1);
|
||||
|
||||
linuxvars.hidden_cursor = XCreatePixmapCursor(linuxvars.dpy, p, p, &c, &c, 0, 0);
|
||||
|
||||
XFreePixmap(linuxvars.dpy, p);
|
||||
}
|
||||
}
|
||||
|
||||
global Key_Code keycode_lookup_table[255];
|
||||
|
@ -1059,10 +1087,130 @@ linux_keycode_init(Display* dpy){
|
|||
XFree(syms);
|
||||
}
|
||||
|
||||
internal void
|
||||
linux_epoll_init(void) {
|
||||
struct epoll_event e = {};
|
||||
e.events = EPOLLIN | EPOLLET;
|
||||
|
||||
//linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK);
|
||||
linuxvars.step_event_fd = eventfd(0, EFD_NONBLOCK);
|
||||
linuxvars.step_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||
linuxvars.epoll = epoll_create(16);
|
||||
|
||||
e.data.ptr = &epoll_tag_x11;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, ConnectionNumber(linuxvars.dpy), &e);
|
||||
|
||||
e.data.ptr = &epoll_tag_step_event;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e);
|
||||
|
||||
e.data.ptr = &epoll_tag_step_timer;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e);
|
||||
}
|
||||
|
||||
internal void
|
||||
linux_clipboard_send(XSelectionRequestEvent* req) {
|
||||
|
||||
XSelectionEvent rsp = {};
|
||||
rsp.type = SelectionNotify;
|
||||
rsp.requestor = req->requestor;
|
||||
rsp.selection = req->selection;
|
||||
rsp.target = req->target;
|
||||
rsp.time = req->time;
|
||||
rsp.property = None;
|
||||
|
||||
Atom formats[] = {
|
||||
linuxvars.atom_UTF8_STRING,
|
||||
XA_STRING,
|
||||
};
|
||||
|
||||
if(linuxvars.clipboard_out_contents.size == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(req->selection != linuxvars.atom_CLIPBOARD || req->property == None) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (req->target == linuxvars.atom_TARGETS){
|
||||
|
||||
XChangeProperty(
|
||||
req->display,
|
||||
req->requestor,
|
||||
req->property,
|
||||
XA_ATOM,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(u8*)formats,
|
||||
ArrayCount(formats));
|
||||
|
||||
rsp.property = req->property;
|
||||
|
||||
} else {
|
||||
|
||||
int i;
|
||||
for(i = 0; i < ArrayCount(formats); ++i){
|
||||
if (req->target == formats[i]){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != ArrayCount(formats)){
|
||||
XChangeProperty(
|
||||
req->display,
|
||||
req->requestor,
|
||||
req->property,
|
||||
req->target,
|
||||
8,
|
||||
PropModeReplace,
|
||||
linuxvars.clipboard_out_contents.str,
|
||||
linuxvars.clipboard_out_contents.size
|
||||
);
|
||||
|
||||
rsp.property = req->property;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
XSendEvent(req->display, req->requestor, True, 0, (XEvent*)&rsp);
|
||||
}
|
||||
|
||||
internal void
|
||||
linux_clipboard_recv(XSelectionEvent* ev) {
|
||||
|
||||
if(ev->selection != linuxvars.atom_CLIPBOARD ||
|
||||
ev->target != linuxvars.atom_UTF8_STRING ||
|
||||
ev->property == None) {
|
||||
return;
|
||||
}
|
||||
|
||||
Atom type;
|
||||
int fmt;
|
||||
unsigned long nitems;
|
||||
unsigned long bytes_left;
|
||||
u8 *data;
|
||||
|
||||
int result = XGetWindowProperty(
|
||||
linuxvars.dpy,
|
||||
linuxvars.win,
|
||||
linuxvars.atom_CLIPBOARD,
|
||||
0L, 0x20000000L, False,
|
||||
linuxvars.atom_UTF8_STRING,
|
||||
&type, &fmt, &nitems,
|
||||
&bytes_left, &data);
|
||||
|
||||
if(result == Success && fmt == 8){
|
||||
linalloc_clear(linuxvars.clipboard_arena);
|
||||
linuxvars.clipboard_contents = push_u8_stringf(linuxvars.clipboard_arena, "%.*s", nitems, data);
|
||||
linuxvars.received_new_clipboard = true;
|
||||
XFree(data);
|
||||
XDeleteProperty(linuxvars.dpy, linuxvars.win, linuxvars.atom_CLIPBOARD);
|
||||
linux_schedule_step();
|
||||
}
|
||||
}
|
||||
|
||||
internal String_Const_u8
|
||||
linux_filter_text(Arena* arena, u8* buf, int len) {
|
||||
u8* const result = push_array(arena, u8, len);
|
||||
u8* const endp = buf + len;
|
||||
u8* outp = result;
|
||||
|
||||
for(int i = 0; i < len; ++i) {
|
||||
|
@ -1204,6 +1352,14 @@ linux_handle_x11_events() {
|
|||
}
|
||||
} break;
|
||||
|
||||
case FocusIn: {
|
||||
XSetICFocus(linuxvars.xic);
|
||||
} break;
|
||||
|
||||
case FocusOut: {
|
||||
XUnsetICFocus(linuxvars.xic);
|
||||
} break;
|
||||
|
||||
case ConfigureNotify: {
|
||||
i32 w = event.xconfigure.width;
|
||||
i32 h = event.xconfigure.height;
|
||||
|
@ -1235,6 +1391,43 @@ linux_handle_x11_events() {
|
|||
&event);
|
||||
}
|
||||
} break;
|
||||
|
||||
case SelectionRequest: {
|
||||
linux_clipboard_send((XSelectionRequestEvent*)&event);
|
||||
} break;
|
||||
|
||||
case SelectionNotify: {
|
||||
linux_clipboard_recv((XSelectionEvent*)&event);
|
||||
} break;
|
||||
|
||||
case SelectionClear: {
|
||||
if(event.xselectionclear.selection == linuxvars.atom_CLIPBOARD) {
|
||||
linalloc_clear(linuxvars.clipboard_out_arena);
|
||||
block_zero_struct(&linuxvars.clipboard_out_contents);
|
||||
}
|
||||
} break;
|
||||
|
||||
case Expose:
|
||||
case VisibilityNotify: {
|
||||
should_step = true;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// clipboard update notification - ask for the new content
|
||||
if (event.type == linuxvars.xfixes_selection_event) {
|
||||
XFixesSelectionNotifyEvent* sne = (XFixesSelectionNotifyEvent*)&event;
|
||||
if (sne->subtype == XFixesSelectionNotify && sne->owner != linuxvars.win){
|
||||
XConvertSelection(
|
||||
linuxvars.dpy,
|
||||
linuxvars.atom_CLIPBOARD,
|
||||
linuxvars.atom_UTF8_STRING,
|
||||
linuxvars.atom_CLIPBOARD,
|
||||
linuxvars.win,
|
||||
CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1314,7 +1507,8 @@ main(int argc, char **argv){
|
|||
|
||||
// NOTE(allen): memory
|
||||
linuxvars.frame_arena = reserve_arena(&linuxvars.tctx);
|
||||
// TODO(allen): *arena;
|
||||
linuxvars.clipboard_arena = reserve_arena(&linuxvars.tctx);
|
||||
linuxvars.clipboard_out_arena = reserve_arena(&linuxvars.tctx);
|
||||
render_target.arena = make_arena_system(KB(256));
|
||||
|
||||
linuxvars.fontconfig = FcInitLoadConfigAndFonts();
|
||||
|
@ -1440,46 +1634,7 @@ main(int argc, char **argv){
|
|||
|
||||
linux_x11_init(argc, argv, &plat_settings);
|
||||
linux_keycode_init(linuxvars.dpy);
|
||||
|
||||
// TODO(inso): move to x11 init?
|
||||
XCursor xcursors[APP_MOUSE_CURSOR_COUNT] = {
|
||||
None,
|
||||
None,
|
||||
XCreateFontCursor(linuxvars.dpy, XC_xterm),
|
||||
XCreateFontCursor(linuxvars.dpy, XC_sb_h_double_arrow),
|
||||
XCreateFontCursor(linuxvars.dpy, XC_sb_v_double_arrow)
|
||||
};
|
||||
|
||||
// sneaky invisible cursor
|
||||
{
|
||||
char data = 0;
|
||||
XColor c = {};
|
||||
Pixmap p = XCreateBitmapFromData(linuxvars.dpy, linuxvars.win, &data, 1, 1);
|
||||
|
||||
linuxvars.hidden_cursor = XCreatePixmapCursor(linuxvars.dpy, p, p, &c, &c, 0, 0);
|
||||
|
||||
XFreePixmap(linuxvars.dpy, p);
|
||||
}
|
||||
|
||||
// epoll init
|
||||
{
|
||||
struct epoll_event e = {};
|
||||
e.events = EPOLLIN | EPOLLET;
|
||||
|
||||
//linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK);
|
||||
linuxvars.step_event_fd = eventfd(0, EFD_NONBLOCK);
|
||||
linuxvars.step_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||
linuxvars.epoll = epoll_create(16);
|
||||
|
||||
e.data.ptr = &epoll_tag_x11;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, ConnectionNumber(linuxvars.dpy), &e);
|
||||
|
||||
e.data.ptr = &epoll_tag_step_event;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e);
|
||||
|
||||
e.data.ptr = &epoll_tag_step_timer;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e);
|
||||
}
|
||||
linux_epoll_init();
|
||||
|
||||
// app init
|
||||
{
|
||||
|
@ -1533,6 +1688,7 @@ main(int argc, char **argv){
|
|||
|
||||
if (linuxvars.received_new_clipboard){
|
||||
input.clipboard = linuxvars.clipboard_contents;
|
||||
input.clipboard_changed = true;
|
||||
linuxvars.received_new_clipboard = false;
|
||||
}
|
||||
|
||||
|
@ -1569,7 +1725,7 @@ main(int argc, char **argv){
|
|||
|
||||
// NOTE(allen): Switch to New Cursor
|
||||
if (result.mouse_cursor_type != linuxvars.cursor && !linuxvars.input.pers.mouse_l){
|
||||
XCursor c = xcursors[result.mouse_cursor_type];
|
||||
XCursor c = linuxvars.xcursors[result.mouse_cursor_type];
|
||||
if (linuxvars.cursor_show){
|
||||
XDefineCursor(linuxvars.dpy, linuxvars.win, c);
|
||||
}
|
||||
|
|
|
@ -326,10 +326,8 @@ system_sleep(u64 microseconds){
|
|||
internal void
|
||||
system_post_clipboard(String_Const_u8 str){
|
||||
LINUX_FN_DEBUG("%.*s", (int)str.size, str.str);
|
||||
linalloc_clear(&linuxvars.clipboard_out_arena);
|
||||
char* p = push_array(&linuxvars.clipboard_out_arena, char, str.size + 1);
|
||||
block_copy(p, str.data, str.size);
|
||||
p[str.size] = '\0';
|
||||
linalloc_clear(linuxvars.clipboard_out_arena);
|
||||
linuxvars.clipboard_out_contents = push_u8_stringf(linuxvars.clipboard_out_arena, "%.*s", str.size, str.str);
|
||||
XSetSelectionOwner(linuxvars.dpy, linuxvars.atom_CLIPBOARD, linuxvars.win, CurrentTime);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue