diff options
author | Diego Borghetti <bdiego@gmail.com> | 2009-05-04 22:46:34 +0400 |
---|---|---|
committer | Diego Borghetti <bdiego@gmail.com> | 2009-05-04 22:46:34 +0400 |
commit | 4ecff51bfeda54d93f06c2f0c6964e9398841453 (patch) | |
tree | ed46387cba231bcadb004d2068aa16b77451cf7e /intern | |
parent | 40fa6b0f37ce022175d1b17a5c8e987119d14218 (diff) |
BugFix [#18597] Blender's text editor cant paste from SciTE in linux
Commit patch [#18597] Blender's text editor cant paste from SciTE in linux
Submitted by Campbell.
I made some changes to cleanup a little the code, atoms are now in the
System class. The getClipboard_xcout try to convert/request:
1) Request for UTF8, if fail
2) Request for COMPOUND_TEXT, if fail
3) Request for TEXT, if fail
4) Request for STRING
Test here with SciTE Version 1.77, firefox, xterm and text editor working
with both library's gtk/qt and all work fine.
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/intern/GHOST_SystemX11.cpp | 379 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemX11.h | 21 |
2 files changed, 280 insertions, 120 deletions
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index bfa5f35d312..0fb4b735f97 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -107,6 +107,15 @@ GHOST_SystemX11( m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False); m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False); + m_targets= XInternAtom(m_display, "TARGETS", False); + m_string= XInternAtom(m_display, "STRING", False); + m_compound_text= XInternAtom(m_display, "COMPOUND_TEXT", False); + m_text= XInternAtom(m_display, "TEXT", False); + m_clipboard= XInternAtom(m_display, "CLIPBOARD", False); + m_primary= XInternAtom(m_display, "PRIMARY", False); + m_xclip_out= XInternAtom(m_display, "XCLIP_OUT", False); + m_incr= XInternAtom(m_display, "INCR", False); + m_utf8_string= XInternAtom(m_display, "UTF8_STRING", False); // compute the initial time timeval tv; @@ -992,144 +1001,280 @@ convertXKey( #undef GXMAP - GHOST_TUns8* -GHOST_SystemX11:: -getClipboard(int flag -) const { - //Flag - //0 = Regular clipboard 1 = selection - static Atom Primary_atom, clip_String, compound_text, a_text, a_string; - Atom rtype; - Window m_window, owner; - unsigned char *data, *tmp_data; - int bits, count; - unsigned long len, bytes; - XEvent xevent; - + +/* from xclip.c xcout() v0.11 */ + +#define XCLIB_XCOUT_NONE 0 /* no context */ +#define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */ +#define XCLIB_XCOUT_INCR 2 /* in an incr loop */ +#define XCLIB_XCOUT_FALLBACK 3 /* STRING failed, need fallback to UTF8 */ +#define XCLIB_XCOUT_FALLBACK_UTF8 4 /* UTF8 failed, move to compouned */ +#define XCLIB_XCOUT_FALLBACK_COMP 5 /* compouned failed, move to text. */ +#define XCLIB_XCOUT_FALLBACK_TEXT 6 + +// Retrieves the contents of a selections. +void GHOST_SystemX11::getClipboard_xcout(XEvent evt, + Atom sel, Atom target, unsigned char **txt, + unsigned long *len, unsigned int *context) const +{ + Atom pty_type; + int pty_format; + unsigned char *buffer; + unsigned long pty_size, pty_items; + unsigned char *ltxt= *txt; + vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it); - m_window = window->getXWindow(); + Window win = window->getXWindow(); + + switch (*context) { + // There is no context, do an XConvertSelection() + case XCLIB_XCOUT_NONE: + // Initialise return length to 0 + if (*len > 0) { + free(*txt); + *len = 0; + } - clip_String = XInternAtom(m_display, "_BLENDER_STRING", False); - compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False); - a_text= XInternAtom(m_display, "TEXT", False); - a_string= XInternAtom(m_display, "STRING", False); - - //lets check the owner and if it is us then return the static buffer - if(flag == 0) { - Primary_atom = XInternAtom(m_display, "CLIPBOARD", False); - owner = XGetSelectionOwner(m_display, Primary_atom); - if (owner == m_window) { - data = (unsigned char*) malloc(strlen(txt_cut_buffer)+1); - strcpy((char*)data, txt_cut_buffer); - return (GHOST_TUns8*)data; - } else if (owner == None) { - return NULL; - } - } else { - Primary_atom = XInternAtom(m_display, "PRIMARY", False); - owner = XGetSelectionOwner(m_display, Primary_atom); - if (owner == m_window) { - data = (unsigned char*) malloc(strlen(txt_select_buffer)+1); - strcpy((char*)data, txt_select_buffer); - return (GHOST_TUns8*)data; - } else if (owner == None) { - return NULL; - } - } + // Send a selection request + XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime); + *context = XCLIB_XCOUT_SENTCONVSEL; + return; - if(!Primary_atom) { - return NULL; - } - - XDeleteProperty(m_display, m_window, Primary_atom); - XConvertSelection(m_display, Primary_atom, compound_text, clip_String, m_window, CurrentTime); //XA_STRING - XFlush(m_display); + case XCLIB_XCOUT_SENTCONVSEL: + if (evt.type != SelectionNotify) + return; - //This needs to change so we do not wait for ever or check owner first - count= 1; - while(1) { - XNextEvent(m_display, &xevent); - if(xevent.type == SelectionNotify) { - if (xevent.xselection.property == None) { - /* Ok, the client can't convert the property - * to some that we can handle, try other types.. - */ - if (count == 1) { - XConvertSelection(m_display, Primary_atom, a_text, clip_String, m_window, CurrentTime); - count++; - } - else if (count == 2) { - XConvertSelection(m_display, Primary_atom, a_string, clip_String, m_window, CurrentTime); - count++; - } - else { - /* Ok, the owner of the selection can't - * convert the data to something that we can - * handle. - */ - return(NULL); - } + if (target == m_utf8_string && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_UTF8; + return; + } + else if (target == m_compound_text && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_COMP; + return; + } + else if (target == m_text && evt.xselection.property == None) { + *context= XCLIB_XCOUT_FALLBACK_TEXT; + return; } - else { - if(XGetWindowProperty(m_display, m_window, xevent.xselection.property , 0L, 4096L, False, AnyPropertyType, &rtype, &bits, &len, &bytes, &data) == Success) { - if (data) { - if (bits == 8 && (rtype == compound_text || rtype == a_text || rtype == a_string)) { - tmp_data = (unsigned char*) malloc(strlen((char*)data)+1); - strcpy((char*)tmp_data, (char*)data); - } - else - tmp_data= NULL; - XFree(data); - return (GHOST_TUns8*)tmp_data; - } - } - return(NULL); + // find the size and format of the data in property + XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False, + AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, &buffer); + XFree(buffer); + + if (pty_type == m_incr) { + // start INCR mechanism by deleting property + XDeleteProperty(m_display, win, m_xclip_out); + XFlush(m_display); + *context = XCLIB_XCOUT_INCR; + return; } - } + + // if it's not incr, and not format == 8, then there's + // nothing in the selection (that xclip understands, anyway) + + if (pty_format != 8) { + *context = XCLIB_XCOUT_NONE; + return; + } + + // not using INCR mechanism, just read the property + XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size, + False, AnyPropertyType, &pty_type, + &pty_format, &pty_items, &pty_size, &buffer); + + // finished with property, delete it + XDeleteProperty(m_display, win, m_xclip_out); + + // copy the buffer to the pointer for returned data + ltxt = (unsigned char *) malloc(pty_items); + memcpy(ltxt, buffer, pty_items); + + // set the length of the returned data + *len = pty_items; + *txt = ltxt; + + // free the buffer + XFree(buffer); + + *context = XCLIB_XCOUT_NONE; + + // complete contents of selection fetched, return 1 + return; + + case XCLIB_XCOUT_INCR: + // To use the INCR method, we basically delete the + // property with the selection in it, wait for an + // event indicating that the property has been created, + // then read it, delete it, etc. + + // make sure that the event is relevant + if (evt.type != PropertyNotify) + return; + + // skip unless the property has a new value + if (evt.xproperty.state != PropertyNewValue) + return; + + // check size and format of the property + XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False, + AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, (unsigned char **) &buffer); + + if (pty_format != 8) { + // property does not contain text, delete it + // to tell the other X client that we have read + // it and to send the next property + XFree(buffer); + XDeleteProperty(m_display, win, m_xclip_out); + return; + } + + if (pty_size == 0) { + // no more data, exit from loop + XFree(buffer); + XDeleteProperty(m_display, win, m_xclip_out); + *context = XCLIB_XCOUT_NONE; + + // this means that an INCR transfer is now + // complete, return 1 + return; + } + + XFree(buffer); + + // if we have come this far, the propery contains + // text, we know the size. + XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size, + False, AnyPropertyType, &pty_type, &pty_format, + &pty_items, &pty_size, (unsigned char **) &buffer); + + // allocate memory to accommodate data in *txt + if (*len == 0) { + *len = pty_items; + ltxt = (unsigned char *) malloc(*len); + } + else { + *len += pty_items; + ltxt = (unsigned char *) realloc(ltxt, *len); + } + + // add data to ltxt + memcpy(<xt[*len - pty_items], buffer, pty_items); + + *txt = ltxt; + XFree(buffer); + + // delete property to get the next item + XDeleteProperty(m_display, win, m_xclip_out); + XFlush(m_display); + return; } + return; } - void -GHOST_SystemX11:: -putClipboard( -GHOST_TInt8 *buffer, int flag) const +GHOST_TUns8 *GHOST_SystemX11::getClipboard(int flag) const { - static Atom Primary_atom; - Window m_window, owner; - - if(!buffer) {return;} + //Flag + //0 = Regular clipboard 1 = selection - if(flag == 0) { - Primary_atom = XInternAtom(m_display, "CLIPBOARD", False); - if(txt_cut_buffer) { free((void*)txt_cut_buffer); } + // Options for where to get the selection from + Atom sseln= flag ? m_clipboard : m_primary; + Atom target= m_string; + + // from xclip.c doOut() v0.11 + unsigned char *sel_buf; /* buffer for selection data */ + unsigned long sel_len= 0; /* length of sel_buf */ + XEvent evt; /* X Event Structures */ + unsigned int context= XCLIB_XCOUT_NONE; + + if (sseln == m_string) + sel_buf= (unsigned char *)XFetchBuffer(m_display, (int *)&sel_len, 0); + else { + while (1) { + /* only get an event if xcout() is doing something */ + if (context != XCLIB_XCOUT_NONE) + XNextEvent(m_display, &evt); + + /* fetch the selection, or part of it */ + getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context); + + /* fallback is needed. set XA_STRING to target and restart the loop. */ + if (context == XCLIB_XCOUT_FALLBACK) { + context= XCLIB_XCOUT_NONE; + target= m_string; + continue; + } + else if (context == XCLIB_XCOUT_FALLBACK_UTF8) { + /* utf8 fail, move to compouned text. */ + context= XCLIB_XCOUT_NONE; + target= m_compound_text; + continue; + } + else if (context == XCLIB_XCOUT_FALLBACK_COMP) { + /* compouned text faile, move to text. */ + context= XCLIB_XCOUT_NONE; + target= m_text; + continue; + } + + /* only continue if xcout() is doing something */ + if (context == XCLIB_XCOUT_NONE) + break; + } + } + + if (sel_len) { + /* only print the buffer out, and free it, if it's not + * empty + */ + unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1); + memcpy((char*)tmp_data, (char*)sel_buf, sel_len); + tmp_data[sel_len] = '\0'; - txt_cut_buffer = (char*) malloc(strlen(buffer)+1); - strcpy(txt_cut_buffer, buffer); - } else { - Primary_atom = XInternAtom(m_display, "PRIMARY", False); - if(txt_select_buffer) { free((void*)txt_select_buffer); } + if (sseln == m_string) + XFree(sel_buf); + else + free(sel_buf); - txt_select_buffer = (char*) malloc(strlen(buffer)+1); - strcpy(txt_select_buffer, buffer); + return (GHOST_TUns8*)tmp_data; } - - vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); + return(NULL); +} + +void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, int flag) const +{ + Window m_window, owner; + + vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it); m_window = window->getXWindow(); - if(!Primary_atom) { - return; - } - - XSetSelectionOwner(m_display, Primary_atom, m_window, CurrentTime); - owner = XGetSelectionOwner(m_display, Primary_atom); - if (owner != m_window) - fprintf(stderr, "failed to own primary\n"); + if (buffer) { + if (flag == 0) { + XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime); + owner= XGetSelectionOwner(m_display, m_clipboard); + if (txt_cut_buffer) + free((void*)txt_cut_buffer); + + txt_cut_buffer = (char*) malloc(strlen(buffer)+1); + strcpy(txt_cut_buffer, buffer); + } else { + XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime); + owner= XGetSelectionOwner(m_display, m_primary); + if (txt_select_buffer) + free((void*)txt_select_buffer); + + txt_select_buffer = (char*) malloc(strlen(buffer)+1); + strcpy(txt_select_buffer, buffer); + } - return; + if (owner != m_window) + fprintf(stderr, "failed to own primary\n"); + } } diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 576577917ba..6a2c81c09a7 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -199,14 +199,18 @@ public: prepareNdofInfo( volatile GHOST_TEventNDOFData *current_values ); - + + /* Helped function for get data from the clipboard. */ + void getClipboard_xcout(XEvent evt, Atom sel, Atom target, + unsigned char **txt, unsigned long *len, + unsigned int *context) const; + /** * Returns unsinged char from CUT_BUFFER0 * @param flag Flag indicates which buffer to return 0 for clipboard 1 for selection * @return Returns the Clipboard indicated by Flag */ - GHOST_TUns8* - getClipboard(int flag) const; + GHOST_TUns8 *getClipboard(int flag) const; /** * Puts buffer to system clipboard @@ -220,6 +224,17 @@ public: Atom m_wm_protocols; Atom m_delete_window_atom; + /* Atoms for Selection, copy & paste. */ + Atom m_targets; + Atom m_string; + Atom m_compound_text; + Atom m_text; + Atom m_clipboard; + Atom m_primary; + Atom m_xclip_out; + Atom m_incr; + Atom m_utf8_string; + private : Display * m_display; |