| @@ -130,6 +130,11 @@ typedef struct lglw_int_s { | |||||
| lglw_timer_fxn_t cbk; | lglw_timer_fxn_t cbk; | ||||
| } timer; | } timer; | ||||
| struct { | |||||
| uint32_t numChars; | |||||
| char *data; | |||||
| } clipboard; | |||||
| struct { | struct { | ||||
| lglw_dropfiles_fxn_t cbk; | lglw_dropfiles_fxn_t cbk; | ||||
| } dropfiles; | } dropfiles; | ||||
| @@ -525,6 +530,41 @@ static void loc_eventProc(void *_xevent) { | |||||
| break; | break; | ||||
| } | } | ||||
| 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; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1569,15 +1609,44 @@ void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char | |||||
| LGLW(_lglw); | LGLW(_lglw); | ||||
| (void)_numChars; | (void)_numChars; | ||||
| // (todo) implement me | |||||
| if(NULL != _text) | 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 | // ---------------------------------------------------------------------------- lglw_clipboard_text_get | ||||
| void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) { | void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) { | ||||
| LGLW(_lglw); | LGLW(_lglw); | ||||
| @@ -1592,8 +1661,118 @@ void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNum | |||||
| { | { | ||||
| if(NULL != _lglw) | 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); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||