BugFix [#18597] Blender's text editor cant paste from SciTE in linux
authorDiego Borghetti <bdiego@gmail.com>
Mon, 4 May 2009 18:46:34 +0000 (18:46 +0000)
committerDiego Borghetti <bdiego@gmail.com>
Mon, 4 May 2009 18:46:34 +0000 (18:46 +0000)
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.

intern/ghost/intern/GHOST_SystemX11.cpp
intern/ghost/intern/GHOST_SystemX11.h

index bfa5f35d31211042a682f0f3480ed03f073a8076..0fb4b735f97321f29482f946d87616b8b72c8e42 100644 (file)
@@ -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(&ltxt[*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");
+       }
 }
 
index 576577917ba67c0b2c6e172367733340afc9cf87..6a2c81c09a78dac1ce15d34a13db3ea877f02fcb 100644 (file)
@@ -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;