LINUX.ORG.RU

XLib - не могу отправить клиенту список selection TARGETS

 , , ,


1

2

Всех с Новым Годом!

У меня тут возникли некоторые трудности с использованием библиотеки XLib в Linux:
Есть С++ программа, содержащая строку с UTF8 текстом. Я хочу посредством XLib объявить эту программу как selection owner, чтобы все selection реквесты от клиентов поступали в программу. Программа должна предоставить клиентам текст из строки в ответ на selection request. Некоторые клиенты, отправляя selection request, сначала запрашивают у владельца лист атомов, описывающих типы данных, которые владелец может предоставить(selection TARGETS), и, если находят в этом списке интересующий их тип данных(строка, картинка…), запрашивают у владельца данные этого типа. Программа должна при запросе клиента предоставить ему список торгетов, состоящий из единственного атома «UTF8_STRING», и, если клиент пожелает запросить данные типа «UTF8_STRING», нужно ему эти данные любезно предоставить. Если вкратце, то что-то типа этого:

#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
 
int selectionRequested(Display*, XEvent* event, XPointer arg)
{
    return event->type == SelectionRequest;
}
 
int main()
{
    // ...
    Display* display = XOpenDisplay(NULL);
    int screen = XDefaultScreen(display);
    Window rootWindow = XRootWindow(display, screen);
    Atom selection = XInternAtom(display, "CLIPBOARD", false);
    Atom selectionType = XInternAtom(display, "UTF8_STRING", false);
    Atom targets = XInternAtom(display, "TARGETS", false);
    Window owner = XCreateSimpleWindow(display, rootWindow,
            -10, -10, 1, 1, 0, 0, 0);
    XSetSelectionOwner(display, selection, owner, CurrentTime);
    XEvent event;
    while (true)
    {
        XIfEvent(display, &event, selectionRequested, NULL);
        XEvent selectionResponse;
        selectionResponse.type = SelectionNotify;
        selectionResponse.xselection.send_event = true;
        selectionResponse.xselection.requestor =
            event.xselectionrequest.requestor;
        selectionResponse.xselection.property =
            event.xselectionrequest.property;
        selectionResponse.xselection.display =
            event.xselectionrequest.display;
        selectionResponse.xselection.selection =
            event.xselectionrequest.selection;
        selectionResponse.xselection.target =
            event.xselectionrequest.target;
        selectionResponse.xselection.time =
            event.xselectionrequest.time;
        Atom targetRequsted = event.xselectionrequest.target;
        std::cout << "REQUESTED TARGET \"" <<
            XGetAtomName(display, targetRequsted) << "\"" << '\n';
        if (targetRequsted == targets)
        {
            XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    XA_ATOM, 32, PropModeReplace,
                    reinterpret_cast<unsigned char*>(&selectionType), 1);
            XSendEvent(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor, 0,
                    0, &selectionResponse);
        }
        else if (targetRequsted == selectionType)
        {
            // Code for sending data to the requestor...
        }
        else
        {
            // ...
        }
    }
    return 0;
}

Здесь я, судя по всему, как-то некорректно использую XChangeProperty() в условном блоке if (targetRequested == targets), поскольку при попытке вставить строку в окно клиента, клиент продолжает многократно запрашивать selection targets после того, как я ему отвечаю, и, не добившись ответа, запрашивает типы, которые я не объявлял. Например, вот что я вижу, когда пытаюсь вставить текст в Firefox:

REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "text/plain;charset=utf-8"
REQUESTED TARGET "text/plain;charset=utf-8"
REQUESTED TARGET "text/x-moz-text-internal"

Клиенты по какой-то причине не воспринимают атом, который я им отправляю в ответ на запрос торгетов, и, соответственно, не видят тип «UTF8_STRING», который я им предоставляю. Если же клиент не запрашивает сначала тип «TARGETS», а сразу запрашивает тип «UTF8_STRING», то дальнейший код(я его здесь опустил) работает прекрасно, и строка из программы успешно вставляется в окно клиента.

Я, если честно, только начал разбираться с XLib. Читал вот это - там всё, вроде бы, и расписано, но совсем нет даже элементарных примеров использования, одна сухая теория.

Может кто опытный подсказать, что я делаю не так?

Я деталей процесса не помню, но пока такое:

selectionType = XInternAtom(display, «UTF8_STRING», false);

На первый TARGETS ответь массивом поддерживаемых атомов. Например, TARGETS, XA_STRING, XA_TEXT, UTF8_STRING. Второй запрос придет за конкретным типом и на него ты ответишь уже текстом.

Вот здесь вместо XA_ATOM укажи selectionResponse.xselection.target:

XChangeProperty(selectionResponse.xselection.display,
                selectionResponse.xselection.requestor,
                selectionResponse.xselection.property,
                selectionResponse.xselection.target, 32, PropModeReplace,
                reinterpret_cast<unsigned char*>(&selectionType), 1);
Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Спасибо, милый человек, но я и так тоже пробовал - не прокатывает:

//...
Atom targets = XInternAtom(display, "TARGETS", false);
Atom utf = XInternAtom(display, "UTF8_STRING", false);
Atom availableTargets[] = { targets, utf };
//...
            XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    selectionResponse.xselection.target, 32, PropModeReplace,
                    reinterpret_cast<unsigned char*>(availableTargets),
                    sizeof(availableTargets) / sizeof(availableTargets[0]));
            XSendEvent(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor, 0,
                    0, &selectionResponse);
//...

Всё равно клиенты игнорируют такой ответ и продолжают запрашивать всякую чушь. Если закомментировать функцию XChangeProperty(), то вообще ничего не меняется, из чего можно сделать вывод, что проблема именно в ней. Но, чёрт возьми, я просматривал исходники всяхих xclip и xsel на гитхабе - там именно так и делают, то есть создают массив из двух атомов(TARGETS и UTF8_STRING), и вызывают XChangeProperty() в ответ на запрос торгетов. И это работает:

echo -n "blablabla" | xclip -sel c

xclip -sel c -t TARGETS -o                                                                                                 
TARGETS
UTF8_STRING

И текст успешно вставляется в Firefox и другие окна.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Может, я чего-то недопонимаю, но я себе это представляю следующим образом:
Клиент запрашивает у владельца список торгетов. Владелец отвечает: «У меня есть UTF8_STRING. Надо?» Клиент получает ответ и решает, надо ли ему UTF8_STRING. Если надо, клиент отправляет следующий запрос, в котором запрашивает UTF8_STRING.
В моём случае клиент не получает ответ, либо получает его в какой-то некорректной форме, но почему - непонятно.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Если закомментировать функцию XChangeProperty(), то вообще ничего не меняется, из чего можно сделать вывод, что проблема именно в ней.

Не думаю. Мне кажется, что дело в XSendEvent, то есть сообщение клиенту, что данные готовы. Пробовал указать True вместо propagate = False?

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Пробовал указать True вместо propagate = False?

Ага, пробовал - вообще ничего не происходит.

Мне кажется, что дело в XSendEvent…

Если закомментировать XSendEvent(), то сразу появляется длительная пауза между запросами торгетов, значит клиенты получают SelectionNotify, но почему-то не могут корректно прочитать содержимое Property.\

Кстати, я понял, почему это работает в xclip - там нет последующей проверки на запрашиваемый тип данных, то есть либо запрашиваются targets, либо что-то другое, но что - не проверяется и возвращается поток байт. В моём коде подобного поведения можно достичь, изменив else if (targetRequsted == selectionType) на просто else, но это приводит к тому, что клиенты могут попытаться вставить какую-нибудь картинку в поле для ввода текста, и с xclip именно так и происходит - можно всавить HD обоину в поисковую строку гугла, получив хаотичные кракозябры, можно даже попытаться вставить эту обоину в адресную строку мозилы и повесить браузер.

Alexey104
() автор топика
Ответ на: комментарий от anonymous

Спасибо, но это я тоже пробовал - безрезультатно.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Если закомментировать XSendEvent(), то сразу появляется длительная пауза между запросами торгетов, значит клиенты получают SelectionNotify,

Они могут принять, но могут не отреагировать. Еще, что касается XSendEvent, то закомментируй selectionResponse.xselection.send_event = true;

Zubok ★★★★★
()
Ответ на: комментарий от Alexey104

...то закомментируй selectionResponse.xselection.send_event = true;

Тоже пробовал.

В любом случае, это поле трогать не надо.

Zubok ★★★★★
()

«UTF8_STRING»

Если вообще не запрашивают (не ожидают) такой тип, запрашивают (ожидают) просто строку XA_STRING или конкретный mime, как «text/plain;charset=utf-8»?

anonymous
()
Ответ на: комментарий от anonymous

Да, я об этом думал, но здесь дело вот в чём:

Я точно знаю, что, например, Firefox поддерживает тип UTF8_STRING. Если скопировать текст из мозилы и запросить у неё список торгетов, в списке имеется UTF8_STRING. Значит, если сказать браузеру, что я ему этот тип данных могу предоставить, и это единственный тип, который у меня есть, он должен запросить у меня именно этот тип. Но он продолжает ещё раз десять подряд запрашивать у меня список торгетов, и, отчаявшись добиться ответа, начинает запрашивать всё подряд. Значит, моё сообщение до него не доходит, либо доходит в непонятной для него форме. А причина этого не ясна. Если заменить блок else if (targetRequsted == selectionType) на просто else, то есть позволить программе отвечать на любой запрос строкой, то текст вставляется:

//...
else
{
// selectionData - строка с текстом

            XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    selectionType, 8, PropModeReplace,
                    reinterpret_cast<const unsigned char*>
                    (&selectionData[0]), selectionData.size());
            XSendEvent(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    true, NoEventMask, &selectionResponse);
}
//..

То есть в данном коде не работает именно блок, ответственный за отправку клиенту торгетов, а сами данные прекрасно отправляются и принимаются клиентом.

Alexey104
() автор топика

Почему я так зациклился на торгетах?

Да просто я в первом посте несколько упростил задачу и код выложил урезаный и примерный. На самом деле моя программа может содержать не только текст, но и картинки и любые другие форматы данных. Поэтому мне нужно чётко обозначить клиентам, какие данные они могут запрашивать, чтобы клиенты не пытались вставить картинку в поле для ввода текста и наоборот.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Если скопировать текст из мозилы и запросить у неё список торгетов, в списке имеется UTF8_STRING.

Но только вопрос, какого списка она ждет от тебя. Может, ей UTF8_STRING мало. Если мозилле ответить, что ты можешь TEXT, MULTIPLE, UTF8_STRING, DELETE, TARGET, TIMESTAMP? Вдруг она проверяет не только наличие UTF8_STRING?

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Вдруг она проверяет не только наличие UTF8_STRING?

Ну да, но я же ей предоставляю список имеющихся у меня типов, и список этот состоит из одного единственного типа. Значит, она должна понимать, что не нужно запрашивать у меня другие типы - либо UTF8_STRING(например), либо вообще ничего. Может, я чего-то не догоняю, но жду именно такого поведения.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

https://tronche.com/gui/x/icccm/sec-2.html#s-2.6.2

 Selection owners are required to support the following targets. All other targets are optional.

    * TARGETS - The owner should return a list of atoms that represent the targets for which an attempt to convert the current selection will succeed (barring unforseeable problems such as Alloc errors). This list should include all the required atoms.
    * MULTIPLE - The MULTIPLE target atom is valid only when a property is specified on the ConvertSelection request. If the property argument in the SelectionRequest event is None and the target is MULTIPLE, it should be refused.

    When a selection owner receives a SelectionRequest (target==MULTIPLE) request, the contents of the property named in the request will be a list of atom pairs: the first atom naming a target and the second naming a property ( None is not valid here). The effect should be as if the owner had received a sequence of SelectionRequest events (one for each atom pair) except that:
        The owner should reply with a SelectionNotify only when all the requested conversions have been performed.
        If the owner fails to convert the target named by an atom in the MULTIPLE property, it should replace that atom in the property with None . 

Convention

    The entries in a MULTIPLE property must be processed in the order they appear in the property. For further information, see section 2.6.3. 

The requestor should delete each individual property when it has copied the data from that conversion, and the property specified in the MULTIPLE request when it has copied all the data.

The requests are otherwise to be processed independently, and they should succeed or fail independently. The MULTIPLE target is an optimization that reduces the amount of protocol traffic between the owner and the requestor; it is not a transaction mechanism. For example, a client may issue a MULTIPLE request with two targets: a data target and the DELETE target. The DELETE target will still be processed even if the conversion of the data target fails.

    * TIMESTAMP - To avoid some race conditions, it is important that requestors be able to discover the timestamp the owner used to acquire ownership. Until and unless the protocol is changed so that a GetSelectionOwner request returns the timestamp used to acquire ownership, selection owners must support conversion to TIMESTAMP, returning the timestamp they used to obtain the selection. 

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 2)
Ответ на: комментарий от Zubok

Милый человек, большое тебе спасибо за то, что потратил на меня своё драгоценное время и заставил меня перечитать эту долбаную документацию. Я почитал ещё раз и понял, что делал не так. Ты оказался прав насчёт того, что дело в XSendEvent(). Там же чёрным по белому написано:

If the selection cannot be converted into a form based on the target (and parameters, if any), the owner should refuse the SelectionRequest as previously described. 

Когда клиент запрашивает невалидный тип данных, ему нужно просто явно отказать, отправив XSendEvent() с property = None, тогда клиент понимает, что ему отказали с запросом, и запрашивает следующий тип до тех пор, пока не запросит то, что мы ему можем предоставить. То есть правильно было так:

if (targetRequsted == targets)
{
      XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    XA_ATOM, 32, PropModeReplace,
                    reinterpret_cast<unsigned char*>
                    (&selectionType), 1);
      XSendEvent(selectionResponse.xselection.display,
                 selectionResponse.xselection.requestor, 0,
                 0, &selectionResponse);
}
else if (targetRequsted == selectionType)
{
            // Code for sending data to the requestor...
}
else
{
            // Вот, чего не хватало:

        std::cout << "REFUSE WITH REQUEST << '\n';
        selectionResponse.xselection.property = None;
        XSendEvent(selectionResponse.xselection.display,
                selectionResponse.xselection.requestor,
                true, NoEventMask, &selectionResponse);

}       
Alexey104
() автор топика
Ответ на: комментарий от Alexey104

А почему тогда он столько раз слал TARGETS?

REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "text/plain;charset=utf-8"
REQUESTED TARGET "text/plain;charset=utf-8"
REQUESTED TARGET "text/x-moz-text-internal"

Ведь ты же ему уже ответил в первый раз, а он продолжает долбить. Я вот что имею в виду. Может, он проверяет список и понимает, что ему не хватает чего-то, просит еще раз какое-то запрограммированное число раз. Или что показывает этот лог? Это одна попытка скопировать строчку или просто много попыток? В посте не объяснено.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

А почему тогда он столько раз слал TARGETS?

Понятия не имею, я изначально это и пытался выяснить. Я тут обрадовался, что, вроде бы, всё заработало, но по факту-то проблема с отправкой торгетов не решилась.

Это одна попытка скопировать строчку или просто много попыток?

Да, это одна попытка скопировать строчку. И я всё ещё вижу эту череду запросов:

REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "text/plain;charset=utf-8"
REFUSE WITH REQUEST
Requested target "UTF8_STRING"
Sending data to the requestor...

Программа больше не виснет на запросах ненужных типов, и нужный тип в итоге запрашивается, но запрашивается он методом перебора, а не методом чтения торгетов. В общем, всё ещё ни хрена не понятно, на самом деле.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Ну вот для начала надо сделать вот это XLib - не могу отправить клиенту список selection TARGETS (комментарий) . то есть ответить что ты поддерживаешь не только UTF8_STRING, но и TARGETS, MULTIPLE и TIMESTAMP. Может быть, расширить этот список еще DELETE и др. Я ожидаю, что он один раз должен попросить TARGETS.

Второе предположение в том, что надо Mozilla может хотеть работать инкрементально. Тогда на любой запрос надо указывать не XA_ATOM, а слать INCR в XChangeProperty. И тогда придется реализовывать в своей программе инкрементальные апдейты. Это все тоже в доках есть. https://tronche.com/gui/x/icccm/sec-2.html#s-2.7.2

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Насчёт инкремента - у меня это уже реализовано, просто я это здесь не показываю, поскольку там много строк, не относящихся к вопросу. Клиент сам не запрашивает тип «INCR» - selection owner сообщает ему о том, что будет передавать данные кусками. Я это использую для объёмных трансферов, когда надо мегабайт 10-20 передать, и это работает - проверено.

Насчёт всего остального - я пошёл спать, если продвинусь куда-нибудь, позже отпишусь.

Я ожидаю, что он один раз должен попросить TARGETS.

Мне тоже так кажется.

Alexey104
() автор топика

Я тут немного занят был, но темой по-прежнему интересуюсь.
В общем, объявил я торгеты, указанные в доках как обязательные(TIMESTAMP, TARGETS, MULTIPLE), но это ничего не изменило. Я, конечно, не реализовывал ответы на запросы этих торгетов, но они в любом случае даже не запрашиваются. Более того, я попробовал сделать следующее:
Выделяем какой-нибудь текст в браузере, через программу запрашиваем у браузера полный список имеющихся у него торгетов и копируем этот список куда-нибудь в вектор. Запрашиваем селекшн из браузера, объявляем себя владельцем селекшна и слушаем селекшн реквесты:

#include <iostream>
#include <vector>
#include <X11/Xlib.h>
#include <X11/Xatom.h>

Display* display = XOpenDisplay(NULL);
int screen = XDefaultScreen(display);
Window rootWindow = XRootWindow(display, screen);
Atom selection = XInternAtom(display, "CLIPBOARD", false);
Atom selectionType = XInternAtom(display, "UTF8_STRING", false);
Atom targets = XInternAtom(display, "TARGETS", false);
Atom property = XInternAtom(display, "PROP", false);
Window owner = XCreateSimpleWindow(display, rootWindow,
        -10, -10, 1, 1, 0, 0, 0);

int selectionRequested(Display*, XEvent* event, XPointer)
{
    return event->type == SelectionRequest;
}

int selectionNotifyArrived(Display*, XEvent* event, XPointer requestorProperty)
{
    return event->type == SelectionNotify &&
        event->xselection.selection == selection &&
        event->xselection.property ==
        *(reinterpret_cast<Atom*>(requestorProperty));
}

int main()
{
    // ...
    XConvertSelection(display, selection, targets, property, owner,
            CurrentTime);
    XEvent event;
    XIfEvent(display, &event, selectionNotifyArrived,
            reinterpret_cast<XPointer>(&property));
    Atom typeReturned;
    int formatReturned;
    unsigned char* targetsReturned = NULL;
    unsigned long nItemsReturned;
    unsigned long nBytesRemaining;
    XGetWindowProperty(const_cast<Display*>(display), owner,
            property, 0, 0, false, XA_ATOM,
            &typeReturned, &formatReturned, &nItemsReturned,
            &nBytesRemaining, &targetsReturned);
    XGetWindowProperty(const_cast<Display*>(display), owner,
            property, 0, nBytesRemaining,
            true, XA_ATOM, &typeReturned, &formatReturned,
            &nItemsReturned, &nBytesRemaining, &targetsReturned);
    std::vector<Atom> targetList;
    for (long unsigned int i = 0; i < sizeof(targetsReturned); ++i)
    {
        targetList.push_back(reinterpret_cast<Atom*>(targetsReturned)[i]);
    }
    XFree(targetsReturned);
    std::cout << "TARGETS RECIEVED:" << '\n';
    for (long unsigned int i = 0; i < targetList.size(); ++i)
    {
        std::cout << "\"" <<
            XGetAtomName(display, targetList[i]) << "\"" << '\n';
    }
    std::cout << "\n\n";
    XSetSelectionOwner(display, selection, owner, CurrentTime);
    while (true)
    {
        XEvent event;
        XIfEvent(display, &event, selectionRequested, NULL);
        XEvent selectionResponse;
        selectionResponse.type = SelectionNotify;
        selectionResponse.xselection.requestor =
            event.xselectionrequest.requestor;
        selectionResponse.xselection.property =
            event.xselectionrequest.property;
        selectionResponse.xselection.display =
            event.xselectionrequest.display;
        selectionResponse.xselection.selection =
            event.xselectionrequest.selection;
        selectionResponse.xselection.target =
            event.xselectionrequest.target;
        selectionResponse.xselection.time =
            event.xselectionrequest.time;
        Atom targetRequsted = event.xselectionrequest.target;
        std::cout << "REQUESTED TARGET \"" <<
            XGetAtomName(display, targetRequsted) << "\"" << '\n';
        if (targetRequsted == targets)
        {
            XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    XA_ATOM, 32, PropModeReplace,
                    reinterpret_cast<unsigned char*>(&targetList),
                    targetList.size());
            XSendEvent(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor, true,
                    NoEventMask, &selectionResponse);
        }
        else if (targetRequsted == selectionType)
        {
            // Code for sending data to the requestor...
        }
        else
        {
            std::cout << "IGNORING REQUEST" << '\n';
            selectionResponse.xselection.property = None;
            XSendEvent(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    true, NoEventMask, &selectionResponse);
        }
    }
    return 0;
}

Теперь пытаемся вставить текст, скопированный из браузера, обратно в браузер, а на запрос торгетов отвечаем списком торгетов, скопированных, опять же, из самого браузера, то есть отвечаем браузеру торгетами, которые он нам сам предоставил для данного селекшна:

TARGETS RECIEVED:
"TIMESTAMP"
"TARGETS"
"MULTIPLE"
"SAVE_TARGETS"
"text/html"
"text/_moz_htmlcontext"
"text/_moz_htmlinfo"
"UTF8_STRING"


REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "TARGETS"
REQUESTED TARGET "text/plain;charset=utf-8"
IGNORING REQUEST
REQUESTED TARGET "UTF8_STRING"
SENDING DATA TO THE REQUESTOR...

Вообще ничего не изменилось. Можно, конечно, вообще забить на торгеты и отвечать лишь на запросы нужного типа, игнорируя все остальные запросы, и это работает, но, сдаётся мне, это больше похоже на корявый костыль, нежели решение, и должно это работать совсем не так.

Alexey104
() автор топика

const_cast<Display*>(display) - это случайно попало в код выше, там должно быть просто display, но это ни на что не влияет.

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

И ещё в XChangeProperty() нужно передавать &targetList[0] вместо &targetList, но это тоже ничего не меняет:

            XChangeProperty(selectionResponse.xselection.display,
                    selectionResponse.xselection.requestor,
                    selectionResponse.xselection.property,
                    XA_ATOM, 32, PropModeReplace,
                    reinterpret_cast<unsigned char*>(&targetList[0]),
                    targetList.size());
Alexey104
() автор топика

Мне кажется, дополнительно стоит написать в список рассылки X.org.

Возможно, там ещё осталось несколько отцов-аксакалов.

Bass ★★★★★
()
Ответ на: комментарий от Bass

Ага, возможно, как-нибудь напишу, если ничего не придумается.
Вообще, тема довольно специфическая, поскольку все вокруг хейтят доисторическую XLib, никто ей не пользуется, предлагают не ипать мозги и использовать взамен GTK или QT тулкиты. Но я не хочу привязываться к конкретным сторонним библиотекам и тянуть их в качестве зависимостей, которые будут весить в сотни раз больше самой программы и которые в конечном итоге на той же XLib и основаны, насколько я понимаю. Официальная документация, с одной стороны, все эти процессы описывает, но в ней нет ни одного примера кода, что значительно усложняет понимание того, как это всё использовать. Как говорится, «ни хера не понятно, но очень интересно».

Alexey104
() автор топика
Ответ на: комментарий от Alexey104

Там просто сама документация ещё очень объёмная. Xlib + Xt — это, как минимум, 900 страниц текста.

Ещё могу порекомендовать посмотреть код старинных программ, лежащих на ftp.x.org и многочисленных зеркалах (ibiblio.org, например).

Bass ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.