Уважаемые обитатели форума!
Пытаюсь сделать поле текстового ввода для своей небольшой программы. Дошел до copy/paste. На основе ряда примеров, в том числе с вашего сайта, добавил «импорт» текста из CLIPBOARD. Но на этом мой оптимизм закончился: вторую неделю пытаюсь отправить тестовую строку «Hello World!» другим приложениям. Перевернул всю документацию и те немногие доступные примеры, которые есть в интернете. Мне кажется, я что-то фундаментально недопонял/пропустил в работе XChangeProperty, вызываемой перед XSendEvent для отправки SelectionNotify. Событие отправляется, но, например, в Plume я не могу вставить отправленный текст. Ниже привожу код (работающий «импорт» и неработающий «экспорт»).
void MkProgWin(Prog *prog)
{
//...
prog->clip.atom.utf8 =
XInternAtom (prog->dpy, "UTF8_STRING", True);
prog->clip.atom.clipboard =
XInternAtom (prog->dpy, "CLIPBOARD", False); //==XA_CLIPBOARD(prog->dpy)
prog->clip.atom.target =
XInternAtom (prog->dpy, "TARGETS", False);
//...
}
//-----------------------------------------------------------------------------
void WidgetClipboardSetOwner (Widget *widget)
{
if(widget->prog->event.type == ButtonPress)
if(widget->prog->event.xbutton.button == 3)
if(widget->prog->event.xbutton.window == widget->win)
if(widget->prog->cursor.win_id == widget->id)
if(widget->cursor.symbol != NULL)
{
XSetSelectionOwner(
widget->prog->dpy,
widget->prog->clip.atom.clipboard,
widget->win, CurrentTime);
XFlush(widget->prog->dpy);
}
}
//-----------------------------------------------------------------------------
void WidgetClipboardSendData (Widget *widget)
{
if(widget->prog->event.type == SelectionRequest)
if(widget->prog->event.xselectionrequest.owner == widget->win)
if(widget->prog->event.xselectionrequest.selection ==
widget->prog->clip.atom.clipboard)
{
XSelectionRequestEvent *req = &(widget->prog->event.xselectionrequest);
if(req->target == widget->prog->clip.atom.target)
{
char text[] = "Hello World";
size_t sizze = strlen(text); // +1?
XChangeProperty(
widget->prog->dpy,
req->requestor,
req->property, /* widget->prog->clip.atom.clipboard */
req->target, /* XA_TARGETS(widget->prog->dpy) XA_UTF8_STRING(widget->prog->dpy) XA_STRING */
8,
PropModeReplace,
(unsigned char *) text,
sizze);
XEvent respond;
respond.xselection.display = widget->prog->dpy;
respond.xselection.type = SelectionNotify;
respond.xselection.send_event = True;
respond.xselection.time = req->time;
respond.xselection.requestor = req->requestor;
respond.xselection.selection = req->selection;
respond.xselection.target = req->target, // widget->prog->clip.atom.utf8
respond.xselection.property = req->property;
int status = XSendEvent(
widget->prog->dpy,
req->requestor,
False, //True
NoEventMask, // NULL 0L
&respond);
XFlush(widget->prog->dpy);
printf("status == %d\n", status);
}
char *an;
if(XFetchName(
widget->prog->dpy,
widget->prog->event.xselectionrequest.requestor,
&an) != 0) {
printf("Requestor: %s\n", an);
XFree(an);
}
an = XGetAtomName(
widget->prog->dpy,
widget->prog->event.xselectionrequest.selection);
if(an != NULL) {
printf("Selection: %s\n", an);
XFree(an);
}
an = XGetAtomName(
widget->prog->dpy,
widget->prog->event.xselectionrequest.target);
if(an != NULL) {
printf("Target: %s\n", an);
XFree(an);
}
an = XGetAtomName(
widget->prog->dpy,
widget->prog->event.xselectionrequest.property);
if(an != NULL) {
printf("Property: %s\n", an);
XFree(an);
}
printf("--------------------\n");
}
}
Вот что печает терминал:
status == 1
Requestor: Pluma
Selection: CLIPBOARD
Target: TARGETS
Property: GDK_SELECTION
--------------------
status == 1
Requestor: Caja
Selection: CLIPBOARD
Target: TARGETS
Property: GDK_SELECTION
--------------------
status == 1
Requestor: Caja
Selection: CLIPBOARD
Target: TARGETS
Property: GDK_SELECTION
--------------------
// Работающий код, но в программе он полностью закомментирован
// поскольку тоже реагирует на Button3Press
void WidgetClipboardGetData (Widget *widget) // Работает
{
if(widget->prog->event.type == ButtonPress)
if(widget->prog->event.xbutton.button == 3)
if(widget->prog->cursor.win_id == widget->id)
{
Window win = XGetSelectionOwner(
widget->prog->dpy,
widget->prog->clip.atom.clipboard);
if(win != None)
{
XConvertSelection ( widget->prog->dpy,
widget->prog->clip.atom.clipboard,
widget->prog->clip.atom.utf8,
widget->prog->clip.atom.target,
widget->win, CurrentTime );
XFlush(widget->prog->dpy);
usleep(5000);
XEvent e;
if(XCheckTypedEvent(widget->prog->dpy, SelectionNotify, &e))
if(e.xselection.property != None)
{
u_char* data = NULL;
Atom type = None;
int format = 0;
u_long nitems = 0;
u_long bytes_left = 0;
if(Success ==
XGetWindowProperty( widget->prog->dpy,
e.xselection.requestor,
e.xselection.property,
0L,
0L,
False,
widget->prog->clip.atom.utf8,
&type,
&format,
&nitems,
&bytes_left,
&data))
{
if(bytes_left > 0)
{
size_t bytes = (size_t)bytes_left;
char *text = (char*)malloc(bytes);
if(text != NULL)
{
if(Success == XGetWindowProperty(
widget->prog->dpy,
e.xselection.requestor,
e.xselection.property,
0L,
bytes_left,
False,
widget->prog->clip.atom.utf8,
&type,
&format,
&nitems,
&bytes_left,
&data))
{
strncpy(text, (char*)data, bytes);
printf("%s\n", text);
free(text);
XFree(data);
}
}
}
}
}
}
}
}
ОГРОМНОЕ СПАСИБО ЗА ПОМОЩЬ!!! ВОТ РЕШЕНИЕ:
void MkProgWin(Prog *prog)
{
//...
prog->clip.atom.clipboard =
XInternAtom (prog->dpy, "CLIPBOARD", False);
prog->clip.atom.target =
XInternAtom (prog->dpy, "TARGETS", False);
prog->clip.atom.utf8 =
XInternAtom (prog->dpy, "UTF8_STRING", False);
prog->clip.atom.xa_string =
XInternAtom (prog->dpy, "XA_STRING", False);
prog->clip.atom.xa_text =
XInternAtom (prog->dpy, "XA_TEXT", False);
//...
}
//-----------------------------------------------------------------------------
void WidgetClipboardSetOwner (Widget *widget)
{
if(widget->prog->event.type == ButtonPress)
if(widget->prog->event.xbutton.button == 3)
if(widget->prog->event.xbutton.window == widget->win)
if(widget->prog->cursor.win_id == widget->id)
if(widget->cursor.symbol != NULL)
{
XSetSelectionOwner(
widget->prog->dpy,
widget->prog->clip.atom.clipboard,
widget->win, CurrentTime);
XFlush(widget->prog->dpy);
}
}
//-----------------------------------------------------------------------------
void WidgetClipboardSendData (Widget *widget)
{
if(widget->prog->event.type == SelectionRequest)
if(widget->prog->event.xselectionrequest.owner == widget->win)
if(widget->prog->event.xselectionrequest.selection ==
widget->prog->clip.atom.clipboard)
{
XSelectionRequestEvent *req = &(widget->prog->event.xselectionrequest);
XEvent respond;
respond.xselection.display = widget->prog->dpy;
respond.xselection.type = SelectionNotify;
respond.xselection.send_event = True;
respond.xselection.time = req->time;
respond.xselection.requestor = req->requestor;
respond.xselection.selection = req->selection;
respond.xselection.target = req->target;
respond.xselection.property = req->property;
if(req->target == widget->prog->clip.atom.target)
{
Atom supported[] = {
widget->prog->clip.atom.target,
widget->prog->clip.atom.utf8,
widget->prog->clip.atom.xa_string,
widget->prog->clip.atom.xa_text
};
XChangeProperty(
widget->prog->dpy,
req->requestor,
req->property,
req->target,
32,
PropModeReplace,
(unsigned char *) (&supported),
sizeof(supported) / sizeof(supported[0]));
}
else
if((req->target == widget->prog->clip.atom.utf8)
|| (req->target == widget->prog->clip.atom.xa_string)
|| (req->target == widget->prog->clip.atom.xa_text)) // то, что требовал GTK
{
char text[] = "HELLO WORLD! ___(UTF8)___!!!____";
XChangeProperty(
widget->prog->dpy,
req->requestor,
req->property,
req->target,
8,
PropModeReplace,
(unsigned char *) text,
strlen(text));
}
else reply.xselection.property = None;
XSendEvent(
widget->prog->dpy,
req->requestor,
False,
NoEventMask,
&respond);
XFlush(widget->prog->dpy);
}
}