Index: intern/ghost/intern/GHOST_SystemX11.cpp =================================================================== --- intern/ghost/intern/GHOST_SystemX11.cpp (revision 19921) +++ intern/ghost/intern/GHOST_SystemX11.cpp (working copy) @@ -975,104 +975,300 @@ #undef GXMAP + +/* 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 /* UTF8_STRING failed, need fallback to XA_STRING */ + +/* Retrieves the contents of a selections. Arguments are: + * + * A display that has been opened. + * + * A window + * + * An event to process + * + * The selection to return + * + * The target(UTF8_STRING or XA_STRING) to return + * + * A pointer to a char array to put the selection into. + * + * A pointer to a long to record the length of the char array + * + * A pointer to an int to record the context in which to process the event + * + * Return value is 1 if the retrieval of the selection data is complete, + * otherwise it's 0. + */ +static int +getClipboard_xcout(Display * dpy, + Window win, + XEvent evt, Atom sel, Atom target, unsigned char **txt, unsigned long *len, unsigned int *context) +{ + /* a property for other windows to put their selection into */ + static Atom pty; + static Atom inc; + Atom pty_type; + Atom atomUTF8String; + int pty_format; + + /* buffer for XGetWindowProperty to dump data into */ + unsigned char *buffer; + unsigned long pty_size, pty_items; + + /* local buffer of text to return */ + unsigned char *ltxt = *txt; + + if (!pty) { + pty = XInternAtom(dpy, "XCLIP_OUT", False); + } + + if (!inc) { + inc = XInternAtom(dpy, "INCR", False); + } + + 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; + } + + /* send a selection request */ + XConvertSelection(dpy, sel, target, pty, win, CurrentTime); + *context = XCLIB_XCOUT_SENTCONVSEL; + return (0); + + case XCLIB_XCOUT_SENTCONVSEL: + atomUTF8String = XInternAtom(dpy, "UTF8_STRING", False); + if (evt.type != SelectionNotify) + return (0); + + /* fallback to XA_STRING when UTF8_STRING failed */ + if (target == atomUTF8String && evt.xselection.property == None) { + *context = XCLIB_XCOUT_FALLBACK; + return(0); + } + + /* find the size and format of the data in property */ + XGetWindowProperty(dpy, + win, + pty, + 0, + 0, + False, + AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, &buffer); + XFree(buffer); + + if (pty_type == inc) { + /* start INCR mechanism by deleting property */ + XDeleteProperty(dpy, win, pty); + XFlush(dpy); + *context = XCLIB_XCOUT_INCR; + return (0); + } + + /* 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 (0); + } + + /* not using INCR mechanism, just read the property */ + XGetWindowProperty(dpy, + win, + pty, + 0, + (long) pty_size, + False, + AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, &buffer); + + /* finished with property, delete it */ + XDeleteProperty(dpy, win, pty); + + /* 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 (1); + + 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 (0); + + /* skip unless the property has a new value */ + if (evt.xproperty.state != PropertyNewValue) + return (0); + + /* check size and format of the property */ + XGetWindowProperty(dpy, + win, + pty, + 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(dpy, win, pty); + return (0); + } + + if (pty_size == 0) { + /* no more data, exit from loop */ + XFree(buffer); + XDeleteProperty(dpy, win, pty); + *context = XCLIB_XCOUT_NONE; + + /* this means that an INCR transfer is now + * complete, return 1 + */ + return (1); + } + + XFree(buffer); + + /* if we have come this far, the propery contains + * text, we know the size. + */ + XGetWindowProperty(dpy, + win, + pty, + 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(dpy, win, pty); + XFlush(dpy); + return (0); + } + + return (0); +} + + + + 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; vector & win_vec = m_windowManager->getWindows(); vector::iterator win_it = win_vec.begin(); GHOST_WindowX11 * window = static_cast(*win_it); - m_window = window->getXWindow(); + + Display *dpy= m_display; + Window win = window->getXWindow(); + + /* Options for where to get the selection from */ + Atom sseln = flag ? XInternAtom(m_display, "CLIPBOARD", False) : XA_PRIMARY; /* X selection to work with, (XA_PRIMARY, XA_SECONDARY, XA_CLIPBOARD(dpy), XA_STRING) */ + Atom target = XA_STRING; /* (XA_STRING, XA_UTF8_STRING(dpy)) */ + + + /* 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; - 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); + if (sseln == XA_STRING) + sel_buf = (unsigned char *) XFetchBuffer(dpy, (int *) &sel_len, 0); + else { + while (1) { + /* only get an event if xcout() is doing something */ + if (context != XCLIB_XCOUT_NONE) + XNextEvent(dpy, &evt); - //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; - } - } + /* fetch the selection, or part of it */ + getClipboard_xcout(dpy, win, evt, sseln, target, &sel_buf, &sel_len, &context); - 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); - - //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); - } + /* fallback is needed. set XA_STRING to target and restart the loop. */ + if (context == XCLIB_XCOUT_FALLBACK) + { + context = XCLIB_XCOUT_NONE; + target = XA_STRING; + continue; } - 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); - } + /* 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'; + + if (sseln == XA_STRING) + XFree(sel_buf); + else + free(sel_buf); + + return (GHOST_TUns8*)tmp_data; + } + + return NULL; } void