LINUX.ORG.RU

Xlib event'ы из всех окон.

 


0

1

Как получить позицию курсора в независимости от окна под курсором? На данный момент этот код работает только вне любого окна или xterm(?).

#include <stdio.h>
#include <X11/Xlib.h>

int main(int argc, char **argv)
{
    Display *display;
    Window root_window;
    XEvent event;

    display = XOpenDisplay(0);
    root_window = XRootWindow(display, 0); 
    XSelectInput(display, root_window, SubstructureNotifyMask | PointerMotionMask);

    while (1) {
        XNextEvent(display, &event);
        switch(event.type) { 
            
            case MotionNotify:
                printf("x: %d y: %d\n", event.xmotion.x, event.xmotion.y);
                break;
        }
    }   
    return 0;
}

★★★★

Есть ли тут гуру по иксам или все уже на вяленом пилят?

AUX ★★★★
() автор топика

Ну как бы так все и должно быть, как ты пишешь. Тебе вообще зачем? Два варината приходят на ум:

1. Метод xeyes через поллинг по таймеру и вызов XQueryPointer для определения координат. Посмотри это приложение, где глаза за курсором следят.

2. Опрос курсора может быть не айс. Есть механизм получения событий устройств ввода через расширение Xinput2. Вот тебе направление - копай.

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

Тебе вообще зачем?

Ковыряю код WindowMaker

XQueryPointer

Наверное накладно на CPU?

Xinput2

Думаю мейнтейнеры не одобрят :)

AUX ★★★★
() автор топика

Как получить позицию курсора в независимости от окна под курсором?

PointerMotionMask

Тебе надо позицию получить или регистрировать движение?

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

Думаю мейнтейнеры не одобрят :)

Почему? Ну тогда есть еще черезжопный вариант. Можно отслеживать все события создания окон и их дочерних окон и заказывать рекурсивно события поинтера к себе. Но это вообще какой-то ад.

Вот, кстати, патч к xeyes c Xinput2:

https://gitlab.freedesktop.org/xorg/app/xeyes/-/commit/420c2d8517246c9e422739...

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

Почему?

Потому-что от XI будет бомбёжка ортодоксальных жоп.

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

А если из соображений безопасности заднепроходные инпуты запрещены и ввод работает только из окна, в котором мышь? То есть как это изначально и задумывалось? Вот в вейланд это решили переизобрести, там как будут посторонний ввод прикручивать?

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

Зачем тогда подписываешься на сообщения изменения позиции курсора?

Получай позицию там где надо.

Если хочется подписаться на изменения, то придется подписаться на события создания окна (начиная от корневого окна), и при создании окна подписаться на движения курсора для созданного окна, и кучу сопутствующих подписок на изменение (структуры) окна, чтобы подписаться/отписаться, добавить/удалить лишнее и тд. Но вопрос «зачем?» остается

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

Например нужно чтобы панель появлялась при наведении к краю,а если окно (которое перекрывает панель) уходит частично за границы экрана, то координаты невозможно получить.

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

Например нужно чтобы панель появлялась при наведении к краю,а если окно (которое перекрывает панель) уходит частично за границы экрана, то координаты невозможно получить.

Ага, как раз такую багу у себя надо решать, но лень.

Метод подписки на события от всех окон решает проблему. Не вижу, почему это считается костылём.

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

Вот такой код работает, но теперь вопрос как это теперь подружить с реализацией WindowMaker которая в топик посте. Не городить же отдельный поток?

#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>

    
XIRawEvent      *re;
Window          root_ret, child_ret;
int         root_x, root_y;
int         win_x, win_y;
unsigned int        mask;

/* Return 1 if XI2 is available, 0 otherwise */
static int has_xi2(Display *dpy)
{
    int major, minor;
    int rc;

    /* We support XI 2.2 */
    major = 2;
    minor = 2;

    rc = XIQueryVersion(dpy, &major, &minor);
    if (rc == BadRequest) {
    printf("No XI2 support. Server supports version %d.%d only.\n", major, minor);
    return 0;
    } else if (rc != Success) {
    fprintf(stderr, "Internal Error! This is a bug in Xlib.\n");
    }

    printf("XI2 supported. Server provides version %d.%d.\n", major, minor);

    return 1;
}

static void select_events(Display *dpy, Window win)
{
    XIEventMask evmasks[1];
    unsigned char mask1[(XI_LASTEVENT + 7)/8];

    memset(mask1, 0, sizeof(mask1));

    /* select for button and key events from all master devices */
    XISetMask(mask1, XI_RawMotion);

    evmasks[0].deviceid = XIAllMasterDevices;
    evmasks[0].mask_len = sizeof(mask1);
    evmasks[0].mask = mask1;

    XISelectEvents(dpy, win, evmasks, 1);
    XFlush(dpy);
}

int main (int argc, char **argv)
{
    Display *dpy;
    int xi_opcode, event, error;
    XEvent ev;

    dpy = XOpenDisplay(NULL);

    if (!dpy) {
    fprintf(stderr, "Failed to open display.\n");
    return -1;
    }

    if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) {
       printf("X Input extension not available.\n");
          return -1;
    }

    if (!has_xi2(dpy))
    return -1;

    /* select for XI2 events */
    select_events(dpy, DefaultRootWindow(dpy));

    while(1) {

    XGenericEventCookie *cookie = &ev.xcookie;
    XNextEvent(dpy, &ev);

    if (cookie->type != GenericEvent ||
        cookie->extension != xi_opcode ||
        !XGetEventData(dpy, cookie))
        continue;

    switch (cookie->evtype) {
    case XI_RawMotion:
        re = (XIRawEvent *) cookie->data;
        XQueryPointer(dpy, DefaultRootWindow(dpy),
                  &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask);
        printf ("raw %g,%g root %d,%d\n",
            re->raw_values[0], re->raw_values[1],
            root_x, root_y);
        break;
    }
    XFreeEventData(dpy, cookie);
    }

    return 0;
}

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

Делаешь два окна - «рабочее пространство» и окно панели. Все дочерние окна в рабочем пространстве обрезаются и не лезут в окно панели. Окно панели рисуешь (или не рисуешь) как тонкую полоску, при попадании курсора в эту полоску увеличивешь свою панель и уменьшаешь «рабочее пространство».

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

Думаю в рамках WindowMaker это будет глобальная переделка всего и всея. Может как-то можно подписаться на события всех окон, например на MotionNotify?

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

в рамках WindowMaker

Тогда надо узнать как в нем сделать окно, которое будет поверх всех. И добавить прозрачую полоску поверх всех окон.

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

Например нужно чтобы панель появлялась при наведении к краю,

Для этой задачи EnterNotify должно хватить, наверное. Сделать невидимое окно у границы UPD (UPD: окно со атрибутами InputOnly, OverrideRedirect) и просить EnterNotify/LeaveNotify. кажется так Taskbar в IceWM сделан. Подносишь к краю курсор - панель появляется. Отводишь курсор с панели - она исчезает. Ортодоксы будут довольны. :) Я смогу позже глянуть, как там точно сделано. ,

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

Вот такой код работает, но теперь вопрос как это теперь подружить с реализацией WindowMaker которая в топик посте. Не городить же отдельный поток?

Задача как бы все решает. Потому что тебе нужно по сути засечь касание. Среди нововведений (относительно новых, конечно. Если быть более точным, то им семь-восемь лет) есть pointer barriers. Тоже придется задействовать XI, но все же все время принимать события мыши не потребуется. Создается pointer barrier (это линия, которая может быть даже наклонной). Когда ты ее касаешься, то к тебе приходит событие. Отходишь от нее - приходит другое. Это вроде и было создано. чтобы активные области были как бы.

http://who-t.blogspot.com/2012/12/whats-new-in-xi-23-pointer-barrier.html

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

Спасибо, будь добр если будет время кинь пример кода

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

Вот нашёл пример, но в WindowMaker чёрный фон вместо прозрачного :( Походу проблема с композитором?

#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main(int argc, char* argv[])
{
    Display* display = XOpenDisplay(NULL);


    XVisualInfo vinfo;
    XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);

    XSetWindowAttributes attr;
    attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
    attr.border_pixel = 0;
    attr.background_pixel = 0;
    attr.override_redirect = 1;

    Window win = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 100, 500, 0, vinfo.depth, InputOutput, vinfo.visual, CWOverrideRedirect | CWColormap | CWBorderPixel | CWBackPixel, &attr);
    XSelectInput(display, win, StructureNotifyMask);
    GC gc = XCreateGC(display, win, 0, 0);

    Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
    XSetWMProtocols(display, win, &wm_delete_window, 1);

    XMapWindow(display, win);

    int keep_running = 1;
    XEvent event;

    while (keep_running) {
        XNextEvent(display, &event);

        switch(event.type) {
            case ClientMessage:
                if (event.xclient.message_type == XInternAtom(display, "WM_PROTOCOLS", 1) && (Atom)event.xclient.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", 1))
                    keep_running = 0;

                break;

            default:
                break;
        }
    }

    XDestroyWindow(display, win);
    XCloseDisplay(display);
    return 0;
}

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

посмотри на барьеры. грубо говоря ты можешь настроить барьер при подходе к которому тебе будет приходить событие. но для этого нужен XInput2.

вообще если у тебя какие-то проблемы с «ортодоксальными жопами», то походу ты вообще не на тот район зашёл. как насчёт соснуть вейлдендца и не кукарекать?

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

InputOutput

Только InputOnly

Размер в один пиксель по высоте надо сделать и расположить у нижней границы. Будет только одна проблема с этим решением - возникнет зона нечуствительности в один пиксель внизу. Окно приложения под этим невидимым тонким окном активной границы в этом месте не будет получать события мыши. В IceWM, если используется функция autohide для панели (я не использую ее, если что), именно так и происходит, но если на это не обратить специально внимания, то можно ничего вообще не заметить. Неизбежная издержка, увы. Когда панель окажется наверху, то лучше это окно убирать. По-моему, так и сделано в IceWM.

будь добр если будет время кинь пример кода

Исходный код этого места вот тут: https://github.com/ice-wm/icewm/blob/master/src/wmtaskbar.cc

и wmtaskbar.h

Чтобы быстрее понять: Класс EdgeTrigger - это как раз класс того самого окна границы. TaskBar - это окно панели. Тут еще есть таймер, так как панель поднимается не сразу при касании, а по таймеру, который задается в настройках. Отслеживаются события EnterNotify и LeaveNotify. Класс YWindow - это просто класс иксового окна в IceWM (IceWM не использует тулкиты, а иксы напрямую).

fEdgeTrigger - собственно экземпляр окна. Размер 1 пиксель высотой, а шириной во всю панель.

    fEdgeTrigger->setGeometry(YRect(x, by, w, 1));

Когда панели нет, то окно fEdgeTrigger не видно, оно прозрачное, но его можно обнаружить по неработающим нажатиям кнопок мыши на нижнем пикселе экрана. Но после короткого таймаута появляется панель.

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

Я же говорю, что ортодоксальная секта у нас.

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

Спасибо, буду курить.

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

В чем костыли?

Расположение окон - это дело оконного менеджера. Эти хинты - это протокол, которого можно (и лучше) придерживаться тем, кто говорит, что поддерживает этот протокол. Точно так же вейланд - это всего лишь протокол, по твоим словам такой же костыль, только в профиль.

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

это дурачок какой-то, зачем он связался с иксами вообще непонятно. ему же сразу предложили лососнуть вяленца.

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

Сам, мудо. Я же писал что это для windowmaker.

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

В чем костыли?

XInput2, xlib, xcb.

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