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.
This commit is contained in:
Diego Borghetti 2009-05-04 18:46:34 +00:00
parent 40fa6b0f37
commit 4ecff51bfe
2 changed files with 288 additions and 128 deletions

@ -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();
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);
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;
}
//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;
}
// 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 {
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);
*len += pty_items;
ltxt = (unsigned char *) realloc(ltxt, *len);
}
}
}
}
void
GHOST_SystemX11::
putClipboard(
GHOST_TInt8 *buffer, int flag) const
{
static Atom Primary_atom;
Window m_window, owner;
if(!buffer) {return;}
if(flag == 0) {
Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
if(txt_cut_buffer) { free((void*)txt_cut_buffer); }
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); }
txt_select_buffer = (char*) malloc(strlen(buffer)+1);
strcpy(txt_select_buffer, buffer);
}
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();
// add data to ltxt
memcpy(&ltxt[*len - pty_items], buffer, pty_items);
if(!Primary_atom) {
return;
*txt = ltxt;
XFree(buffer);
// delete property to get the next item
XDeleteProperty(m_display, win, m_xclip_out);
XFlush(m_display);
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");
return;
}
GHOST_TUns8 *GHOST_SystemX11::getClipboard(int flag) const
{
//Flag
//0 = Regular clipboard 1 = selection
// 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';
if (sseln == m_string)
XFree(sel_buf);
else
free(sel_buf);
return (GHOST_TUns8*)tmp_data;
}
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 (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);
}
if (owner != m_window)
fprintf(stderr, "failed to own primary\n");
}
}

@ -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;