Browse Source

Merge pull request #14 from cameronleger/v0.6-linux-lglw

Implement many `lglw_*` functions and X Events for Linux
pull/1639/head
bsp2 GitHub 6 years ago
parent
commit
ce438cc004
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 631 additions and 75 deletions
  1. +631
    -75
      dep/lglw/lglw_linux.c

+ 631
- 75
dep/lglw/lglw_linux.c View File

@@ -130,6 +130,11 @@ typedef struct lglw_int_s {
lglw_timer_fxn_t cbk;
} timer;

struct {
uint32_t numChars;
char *data;
} clipboard;

struct {
lglw_dropfiles_fxn_t cbk;
} dropfiles;
@@ -145,8 +150,6 @@ typedef struct lglw_int_s {
static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
static void loc_destroy_hidden_window(lglw_int_t *lglw);

static void loc_key_hook(lglw_int_t *lglw);
static void loc_key_unhook(lglw_int_t *lglw);
static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
// static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
// static lglw_bool_t loc_touchkeyboard_is_visible (void);
@@ -167,10 +170,6 @@ static void *loc_getProperty (Display *_display, Window _window, const char *_na
static void loc_setEventProc (Display *display, Window window);


// ---------------------------------------------------------------------------- module vars
static lglw_int_t *khook_lglw = NULL; // currently key-hooked lglw instance (one at a time)


// TODO: remove and/or improve debug logging for a debug build
// ---------------------------------------------------------------------------- lglw_log
static FILE *logfile;
@@ -373,6 +372,8 @@ static void loc_eventProc(void *_xevent) {

if(NULL != lglw)
{
lglw_bool_t bHandled = LGLW_FALSE;

switch(xev->type)
{
default:
@@ -381,23 +382,412 @@ static void loc_eventProc(void *_xevent) {

case Expose:
printf("vstgltest<lglw_linux>: xev Expose\n");
loc_handle_queued_mouse_warp(lglw);
if(NULL != lglw->redraw.cbk)
{
lglw->redraw.cbk(lglw);
}
break;

// TODO: Should FocusIn/Out be treated like WM_CAPTURECHANGED and reset the grab state?

case FocusIn:
printf("vstgltest<lglw_linux>: xev FocusIn\n");
break;

case FocusOut:
printf("vstgltest<lglw_linux>: xev FocusOut\n");
break;

case EnterNotify:
// printf("vstgltest<lglw_linux>: xev XEnterWindowEvent\n");
; // empty statement
XEnterWindowEvent *wenter = (XEnterWindowEvent*)xev;
printf("vstgltest<lglw_linux>: xev EnterNotify: mode:%i, detail:%i, state:%d\n", wenter->mode, wenter->detail, wenter->state);
lglw->mouse.p.x = wenter->x;
lglw->mouse.p.y = wenter->y;
loc_handle_mousemotion(lglw);

// EnterNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
// when buttons are pressed, which would trigger false focus changes
// so, the callback is only sent when a normal entry happens
if (wenter->mode == NotifyNormal)
{
loc_handle_mouseenter(lglw);
}

break;

case LeaveNotify:
// printf("vstgltest<lglw_linux>: xev XLeaveWindowEvent\n");
; // empty statement
XLeaveWindowEvent *wexit = (XLeaveWindowEvent*)xev;
printf("vstgltest<lglw_linux>: xev LeaveNotify: mode:%i, detail:%i, state:%d\n", wexit->mode, wexit->detail, wexit->state);

// LeaveNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
// when buttons are pressed, which would trigger false focus changes
// so, the callback is only sent when a normal entry happens
if (wexit->mode == NotifyNormal)
{
loc_handle_mouseleave(lglw);
}

break;

case MotionNotify:
printf("vstgltest<lglw_linux>: xev MotionNotify\n");
// printf("vstgltest<lglw_linux>: xev MotionNotify\n");
; // empty statement
XMotionEvent *motion = (XMotionEvent*)xev;

if(LGLW_MOUSE_GRAB_WARP == lglw->mouse.grab.mode)
{
lglw->mouse.grab.b_queue_warp = LGLW_TRUE;

lglw->mouse.p.x += (motion->x - lglw->mouse.grab.last_p.x);
lglw->mouse.p.y += (motion->y - lglw->mouse.grab.last_p.y);

lglw->mouse.grab.last_p.x = motion->x;
lglw->mouse.grab.last_p.y = motion->y;
}
else
{
lglw->mouse.p.x = motion->x;
lglw->mouse.p.y = motion->y;
}

loc_handle_mousemotion(lglw);

break;

case KeyPress:
printf("vstgltest<lglw_linux>: xev KeyPress\n");
lglw_redraw(lglw);
XKeyPressedEvent *keyPress = (XKeyPressedEvent*)xev;

KeySym xkp = XLookupKeysym(keyPress, 0);
switch(xkp)
{
default:
printf("vstgltest<lglw_linux>: xev KeyPress: %x or %lu\n", keyPress->keycode, xkp);
if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
{
KeySym xkpl;
KeySym xkpu;
XConvertCase(xkp, &xkpl, &xkpu);
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkpu);
}
else
{
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkp);
}
break;

case NoSymbol:
printf("vstgltest<lglw_linux>: xev UNKNOWN KeyPress: %x\n", keyPress->keycode);
break;

case XK_F1:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F1);
break;

case XK_F2:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F2);
break;

case XK_F3:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F3);
break;

case XK_F4:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F4);
break;

case XK_F5:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F5);
break;

case XK_F6:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F6);
break;

case XK_F7:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F7);
break;

case XK_F8:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F8);
break;

case XK_F9:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F9);
break;

case XK_F10:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F10);
break;

case XK_F11:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F11);
break;

case XK_F12:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F12);
break;

case XK_BackSpace:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_BACKSPACE);
break;

case XK_Tab:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_TAB);
break;

case XK_Return:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RETURN);
break;

case XK_Escape:
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_ESCAPE);
break;

case XK_Shift_L:
lglw->keyboard.kmod_state |= LGLW_KMOD_LSHIFT;
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LSHIFT);
bHandled = LGLW_FALSE;
break;

case XK_Shift_R:
lglw->keyboard.kmod_state |= LGLW_KMOD_RSHIFT;
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RSHIFT);
bHandled = LGLW_FALSE;
break;

case XK_Control_L:
lglw->keyboard.kmod_state |= LGLW_KMOD_LCTRL;
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_LCTRL);
bHandled = LGLW_FALSE;
break;

case XK_Control_R:
lglw->keyboard.kmod_state |= LGLW_KMOD_RCTRL;
bHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_RCTRL);
bHandled = LGLW_FALSE;
break;
}

break;

case KeyRelease:
printf("vstgltest<lglw_linux>: xev KeyRelease\n");
XKeyReleasedEvent *keyRelease = (XKeyReleasedEvent*)xev;

KeySym xkr = XLookupKeysym(keyRelease, 0);
switch(xkr)
{
default:
printf("vstgltest<lglw_linux>: xev KeyRelease: %x or %lu\n", keyRelease->keycode, xkr);
if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
{
KeySym xkrl;
KeySym xkru;
XConvertCase(xkr, &xkrl, &xkru);
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkru);
}
else
{
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkr);
}
break;

case NoSymbol:
printf("vstgltest<lglw_linux>: xev UNKNOWN KeyRelease: %x\n", keyRelease->keycode);
break;

case XK_F1:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F1);
break;

case XK_F2:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F2);
break;

case XK_F3:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F3);
break;

case XK_F4:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F4);
break;

case XK_F5:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F5);
break;

case XK_F6:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F6);
break;

case XK_F7:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F7);
break;

case XK_F8:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F8);
break;

case XK_F9:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F9);
break;

case XK_F10:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F10);
break;

case XK_F11:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F11);
break;

case XK_F12:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F12);
break;

case XK_BackSpace:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_BACKSPACE);
break;

case XK_Tab:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_TAB);
break;

case XK_Return:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RETURN);
break;

case XK_Escape:
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_ESCAPE);
break;

case XK_Shift_L:
lglw->keyboard.kmod_state &= ~LGLW_KMOD_LSHIFT;
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LSHIFT);
bHandled = LGLW_FALSE;
break;

case XK_Shift_R:
lglw->keyboard.kmod_state &= ~LGLW_KMOD_RSHIFT;
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RSHIFT);
bHandled = LGLW_FALSE;
break;

case XK_Control_L:
lglw->keyboard.kmod_state &= ~LGLW_KMOD_LCTRL;
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LCTRL);
bHandled = LGLW_FALSE;
break;

case XK_Control_R:
lglw->keyboard.kmod_state &= ~LGLW_KMOD_RCTRL;
bHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RCTRL);
bHandled = LGLW_FALSE;
break;
}

break;

case ButtonPress:
printf("vstgltest<lglw_linux>: xev ButtonPress\n");
XButtonPressedEvent *btnPress = (XButtonPressedEvent*)xev;
lglw->mouse.p.x = btnPress->x;
lglw->mouse.p.y = btnPress->y;

if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
{
loc_handle_mouseenter(lglw);
}

switch(btnPress->button)
{
default:
printf("vstgltest<lglw_linux>: xev ButtonPress unhandled button: %i\n", btnPress->button);
break;
case Button1:
loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_LBUTTON);
break;
case Button2:
loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
break;
case Button3:
loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
break;
case Button4:
loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELUP);
break;
case Button5:
loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
break;
}
break;

case ButtonRelease:
printf("vstgltest<lglw_linux>: xev ButtonRelease\n");
XButtonReleasedEvent *btnRelease = (XButtonReleasedEvent*)xev;
lglw->mouse.p.x = btnRelease->x;
lglw->mouse.p.y = btnRelease->y;
switch(btnRelease->button)
{
default:
printf("vstgltest<lglw_linux>: xev ButtonRelease unhandled button: %i\n", btnRelease->button);
break;
case Button1:
loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
break;
case Button2:
loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
break;
case Button3:
loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
break;
case Button4:
loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELUP);
break;
case Button5:
loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
break;
}
break;

case SelectionClear:
printf("vstgltest<lglw_linux>: xev SelectionClear\n");
lglw->clipboard.numChars = 0;
free(lglw->clipboard.data);
break;

case SelectionRequest:
printf("vstgltest<lglw_linux>: xev SelectionRequest\n");
XSelectionRequestEvent *cbReq = (XSelectionRequestEvent*)xev;
XSelectionEvent cbRes;

Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);

cbRes.type = SelectionNotify;
cbRes.requestor = cbReq->requestor;
cbRes.selection = cbReq->selection;
cbRes.target = cbReq->target;
cbRes.time = cbReq->time;

if(cbReq->target == utf8)
{
XChangeProperty(lglw->xdsp, cbReq->requestor, cbReq->property, utf8, 8/*format*/, PropModeReplace,
(unsigned char *)lglw->clipboard.data, lglw->clipboard.numChars);

cbRes.property = cbReq->property;
}
else
{
cbRes.property = None;
}

XSendEvent(lglw->xdsp, cbReq->requestor, True, NoEventMask, (XEvent *)&cbRes);

break;
}
}
@@ -658,6 +1048,18 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x,
NULL/*XSizeHints*/
);

// Setup the event proc now, on the parent window as well just for the debug host
// It was simpler to do this than check in the debug host for the reparent event
lglw_log("lglw:lglw_window_open: 7\n");
loc_setEventProc(lglw->xdsp, lglw->win.xwnd);
loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer

if(0 != _parentHWNDOrNull)
{
loc_setEventProc(lglw->xdsp, lglw->parent_xwnd);
loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer
}

// Some hosts only check and store the callback when the Window is reparented
// Since creating the Window with a Parent may or may not do that, but the callback is not set,
// ... it's created as a root window, the callback is set, and then it's reparented
@@ -665,7 +1067,7 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x,
// (note) [cameronleger] In Ardour's code-base, the only time it looks for the _XEventProc is during a ReparentNotify event
if (0 != _parentHWNDOrNull)
{
lglw_log("lglw:lglw_window_open: 7\n");
lglw_log("lglw:lglw_window_open: 8\n");
XReparentWindow(lglw->xdsp, lglw->win.xwnd, lglw->parent_xwnd, 0, 0);
}
#endif
@@ -675,18 +1077,6 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x,
lglw->win.b_owner = LGLW_FALSE;
#endif

// Setup the event proc now, on the parent window as well just for the debug host
// It was simpler to do this than check in the debug host for the reparent event
lglw_log("lglw:lglw_window_open: 8\n");
loc_setEventProc(lglw->xdsp, lglw->win.xwnd);

if(NULL != _parentHWNDOrNull)
{
loc_setEventProc(lglw->xdsp, lglw->parent_xwnd);
loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer
}
loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer

lglw_log("lglw:lglw_window_open: 9\n");
if(lglw->win.b_owner)
{
@@ -805,12 +1195,9 @@ void lglw_window_close (lglw_t _lglw) {
lglw_timer_stop(_lglw);

lglw_log("lglw:lglw_window_close: 2\n");
loc_key_unhook(lglw);

lglw_log("lglw:lglw_window_close: 3\n");
glXMakeCurrent(lglw->xdsp, None, NULL);

lglw_log("lglw:lglw_window_close: 4\n");
lglw_log("lglw:lglw_window_close: 3\n");
if(lglw->win.b_owner)
{
XDestroyWindow(lglw->xdsp, lglw->win.xwnd);
@@ -904,7 +1291,6 @@ void lglw_redraw(lglw_t _lglw) {
{
// TODO Event Loop
lglw_log("lglw:lglw_redraw: 1\n");
// XClearArea(lglw->xdsp, lglw->win.xwnd, 0, 0, 1, 1, True); // clear tiny area for exposing
XEvent xev;
xev.xany.type = Expose;
xev.xany.serial = 0;
@@ -1022,29 +1408,8 @@ int32_t lglw_swap_interval_get(lglw_t _lglw) {
}


// ---------------------------------------------------------------------------- loc_key_hook
static void loc_key_hook(lglw_int_t *lglw) {
loc_key_unhook(lglw);

// (todo) implement me

khook_lglw = lglw;
}


// ---------------------------------------------------------------------------- loc_key_unhook
static void loc_key_unhook(lglw_int_t *lglw) {

// (todo) implement me
if(khook_lglw == lglw)
khook_lglw = NULL;
}


// ---------------------------------------------------------------------------- loc_handle_mouseleave
static void loc_handle_mouseleave(lglw_int_t *lglw) {
loc_key_unhook(lglw);

lglw->focus.state &= ~LGLW_FOCUS_MOUSE;

if(NULL != lglw->focus.cbk)
@@ -1058,8 +1423,6 @@ static void loc_handle_mouseleave(lglw_int_t *lglw) {

// ---------------------------------------------------------------------------- loc_handle_mouseenter
static void loc_handle_mouseenter(lglw_int_t *lglw) {
loc_key_hook(lglw);

lglw->focus.state |= LGLW_FOCUS_MOUSE;

@@ -1188,8 +1551,7 @@ void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {

if(NULL != lglw)
{
// (todo) implement me
// if(NULL != lglw->win.hwnd)
if(0 != lglw->win.xwnd)
{
if(!lglw->mouse.touch.b_enable)
{
@@ -1198,6 +1560,8 @@ void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
lglw_mouse_ungrab(_lglw);
}

int result;

switch(_grabMode)
{
default:
@@ -1205,18 +1569,44 @@ void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
break;

case LGLW_MOUSE_GRAB_CAPTURE:
// (todo) implement me
// (void)SetCapture(lglw->win.hwnd);
lglw->mouse.grab.mode = _grabMode;
result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
True/*owner_events*/,
ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
GrabModeAsync/*pointer_mode*/,
GrabModeAsync/*keyboard_mode*/,
lglw->win.xwnd/*confine_to*/,
None/*cursor*/,
CurrentTime/*time*/);
if(GrabSuccess != result)
{
printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
}
else
{
lglw->mouse.grab.mode = _grabMode;
}
break;

case LGLW_MOUSE_GRAB_WARP:
// (todo) implement me
// (void)SetCapture(lglw->win.hwnd);
lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
lglw->mouse.grab.p = lglw->mouse.p;
lglw->mouse.grab.last_p = lglw->mouse.p;
lglw->mouse.grab.mode = _grabMode;
result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
True/*owner_events*/,
ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
GrabModeAsync/*pointer_mode*/,
GrabModeAsync/*keyboard_mode*/,
lglw->win.xwnd/*confine_to*/,
None/*cursor*/,
CurrentTime/*time*/);
if(GrabSuccess != result)
{
printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
}
else
{
lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
lglw->mouse.grab.p = lglw->mouse.p;
lglw->mouse.grab.last_p = lglw->mouse.p;
lglw->mouse.grab.mode = _grabMode;
}
break;
}
}
@@ -1231,8 +1621,7 @@ void lglw_mouse_ungrab(lglw_t _lglw) {

if(NULL != lglw)
{
// (todo) implement me
// if(NULL != lglw->win.hwnd)
if(0 != lglw->win.xwnd)
{
if(!lglw->mouse.touch.b_enable)
{
@@ -1243,14 +1632,12 @@ void lglw_mouse_ungrab(lglw_t _lglw) {
break;

case LGLW_MOUSE_GRAB_CAPTURE:
// (todo) implement me
// (void)ReleaseCapture();
XUngrabPointer(lglw->xdsp, CurrentTime);
lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
break;

case LGLW_MOUSE_GRAB_WARP:
// (todo) implement me
// (void)ReleaseCapture();
XUngrabPointer(lglw->xdsp, CurrentTime);
lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
@@ -1266,10 +1653,20 @@ void lglw_mouse_ungrab(lglw_t _lglw) {
void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
LGLW(_lglw);

// (todo) implement me

if(NULL != lglw)
{
if(0 != lglw->win.xwnd)
{
XWarpPointer(lglw->xdsp,
None/*src_w*/,
lglw->win.xwnd/*dest_w*/,
0/*src_x*/,
0/*src_y*/,
0/*src_width*/,
0/*src_height*/,
_x/*dest_x*/,
_y/*dest_y*/);
}
}
}

@@ -1289,10 +1686,30 @@ static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
LGLW(_lglw);

// (todo) implement me

if(NULL != lglw)
{
if(LGLW_FALSE == _bShow)
{
Pixmap noPxm;
Cursor noCursor;
XColor black, dummy;
static char pxmNoData[] = {0, 0, 0, 0, 0, 0, 0, 0};

XAllocNamedColor(lglw->xdsp, lglw->cmap, "black", &black, &dummy);
noPxm = XCreateBitmapFromData(lglw->xdsp, lglw->win.xwnd, pxmNoData, 8, 8);
noCursor = XCreatePixmapCursor(lglw->xdsp, noPxm, noPxm, &black, &black, 0, 0);

XDefineCursor(lglw->xdsp, lglw->win.xwnd, noCursor);
XFreeCursor(lglw->xdsp, noCursor);
if(noPxm != None)
{
XFreePixmap(lglw->xdsp, noPxm);
}
}
else
{
XUndefineCursor(lglw->xdsp, lglw->win.xwnd);
}
}
}

@@ -1390,15 +1807,44 @@ void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char
LGLW(_lglw);
(void)_numChars;

// (todo) implement me

if(NULL != _text)
{
(void)lglw;
if(NULL != _lglw)
{
if(0 != lglw->win.xwnd)
{
uint32_t numChars = (0u == _numChars) ? ((uint32_t)strlen(_text)+1u) : _numChars;

if(numChars > 0u)
{
lglw->clipboard.numChars = numChars;
lglw->clipboard.data = malloc(numChars+1);

uint32_t i;
for(i = 0u; i < numChars; i++)
{
lglw->clipboard.data[i] = _text[i];
}
lglw->clipboard.data[numChars - 1] = 0;

printf("xxx lglw_clipboard_text_set(%i): %s\n", lglw->clipboard.numChars, lglw->clipboard.data);

Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
XSetSelectionOwner(lglw->xdsp, clipboard, lglw->win.xwnd, CurrentTime);
XSync(lglw->xdsp, False);
}
}
}
}
}


// ---------------------------------------------------------------------------- loc_is_clipboard_event
static Bool loc_is_clipboard_event(Display *_display, XEvent *_xevent, XPointer _xarg) {
return _xevent->type == SelectionNotify;
}


// ---------------------------------------------------------------------------- lglw_clipboard_text_get
void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
LGLW(_lglw);
@@ -1413,8 +1859,118 @@ void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNum
{
if(NULL != _lglw)
{
// (todo) implement me
(void)lglw;
if(0 != lglw->win.xwnd)
{
Window owner;
XEvent xev;
XSelectionEvent *cbReq;
Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);
Atom target = XInternAtom(lglw->xdsp, "_clipboard_result", False);

owner = XGetSelectionOwner(lglw->xdsp, clipboard);
if(owner == None)
{
printf("xxx lglw_clipboard_text_get: No Window can provide a clipboard result\n");
return;
}

if(owner == lglw->win.xwnd)
{
printf("xxx lglw_clipboard_text_get: We are the owner of the clipboard, skip X interactions\n");

uint32_t i = 0u;
for(; i < _maxChars; i++)
{
_retText[i] = lglw->clipboard.data[i];
if(0 == _retText[i])
break;
}
_retText[_maxChars - 1u] = 0;

if(NULL != _retNumChars)
*_retNumChars = i;

printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
return;
}

XConvertSelection(lglw->xdsp, clipboard, utf8, target, lglw->win.xwnd, CurrentTime);
XIfEvent(lglw->xdsp, &xev, &loc_is_clipboard_event, None);

cbReq = (XSelectionEvent*)&xev;
if(None == cbReq->property)
{
printf("xxx lglw_clipboard_text_get: Clipboard was not converted to UTF-8 string\n");
return;
}

Atom returnType;
int returnFormat;
unsigned long size, returnSize, bytesLeft;
unsigned char *propertyValue = NULL;

XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
0/*offset*/,
0/*length*/,
False/*delete*/,
AnyPropertyType/*req_type*/,
&returnType/*actual_type_return*/,
&returnFormat/*actual_format_return*/,
&returnSize/*nitems_return*/,
&size/*bytes_after_return*/,
&propertyValue/*prop_return*/);
XFree(propertyValue);

if(utf8 != returnType)
{
printf("xxx lglw_clipboard_text_get: Clipboard result is not a UTF-8 string\n");
return;
}

if(8u != returnFormat)
{
printf("xxx lglw_clipboard_text_get: Clipboard format is not a char array\n");
return;
}

if(_maxChars < size)
size = _maxChars;
size = 1 + ((size - 1) / 4);

// TODO: Even with the largest current use-case, multiple calls aren't necessary. do it anyway just in case
XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
0/*offset*/,
size/*length*/,
True/*delete*/,
AnyPropertyType/*req_type*/,
&returnType/*actual_type_return*/,
&returnFormat/*actual_format_return*/,
&returnSize/*nitems_return*/,
&bytesLeft/*bytes_after_return*/,
&propertyValue/*prop_return*/);

if(returnSize == 0)
{
printf("xxx lglw_clipboard_text_get: No Clipboard result after final request\n");
return;
}

uint32_t i = 0u;
for(; i < _maxChars; i++)
{
_retText[i] = propertyValue[i];
if(0 == _retText[i])
break;
}
_retText[_maxChars - 1u] = 0;

if(NULL != _retNumChars)
*_retNumChars = i;

printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
XFree(propertyValue);
}
}
}
}

Loading…
Cancel
Save