LINUX.ORG.RU

[x window system] не двигается окно


0

1

Добрый день!

Столкнулся со следующей проблемой. Есть многопоточное приложение, которое работает с api x window system. Основной поток этого приложения создает окно и содержит главный цикл обработки некоторых оконных сообщений. Существует до конца работы программы. Второй поток занимается рисованием битмапов на этом окне. Другие потоки не имеют отношения к оконной части программы.

В какой-то момент пропала возможность перемещения окна по рабочему столу (изначально все работало, а сам момент я не уловил). Т.е. я щелкаю мышкой по заголовку, пытаюсь передвинуть окно, а оно не меняет свою позицию. Чаще всего курсор не меняет свою форму, но иногда становится «рукой» на долю секунды. Также сочетание альт + кнопка мыши не работает.

Когда я пробую переместить окно, то никаких событий мне не прилетает. По идее этим должен заниматься оконный менеджер.

В чем тут может быть дело?

Спасибо.

> Когда я пробую переместить окно, то никаких событий мне не прилетает.

Прилетают, просто (весьма вероятно) у вас в программе косяк (кривая или отсутствующая синхронизация) и вы про№;%ваете приходящие сообщения

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

Вы можете как-то раскрыть свою мысль на счет синхронизации?

Все сообщения достаются из очереди сообщений. Крутится цикл, в котором выполняется такой код:

...

if (XPending(display) > 0)
{
    /* get next event or wait */
    XNextEvent(display, &xevent);
    isEvent = true;
}

если есть ивент, то обработать его
...

При перемещении окна должен прилетать XConfigureEvent, на сколько я знаю. Но уже после перемещения окна на новую позицию, так?

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

Alexander8 ()

Рисовать надо в одном оконном потоке, как в виндовс. Отправил сообщение из второго - нарисовал в главном потоке окна при его получении. По свему опыту знаю, что рисовать из разных потоков много гемора, в одном как-то оно проще получается.

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

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

Да, кстати, xprop по моему окну выдает _NET_WM_ALLOWED_ACTIONS(ATOM) = _NET_WM_ACTION_MOVE, _NET_WM_ACTION_MINIMIZE, _NET_WM_ACTION_SHADE, _NET_WM_ACTION_CHANGE_DESKTOP, _NET_WM_ACTION_CLOSE, _NET_WM_ACTION_ABOVE, _NET_WM_ACTION_BELOW

Т.е. перемещение моего окна разрешено для оконного менеджера.

Немного растерян, в гугле тоже информации нет.

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

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

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

Это я делал. Окно перемещается, более того, как бы я не пытался запретить перемещение — не смог. :-)

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

Может будут еще какие-то идеи?

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

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

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

Спасибо, друзья, все получилось!

Проблема действительно была в обработке сообщений.

У меня было так:

    long input_mask = KeyPressMask | KeyReleaseMask | FocusChangeMask | 
                                    ExposureMask | ButtonPressMask | ButtonReleaseMask |
                                    PointerMotionMask | ButtonMotionMask;
    long ic_input_mask = 0;

    if (im != NULL)
    {
        ic = XCreateIC(im, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
                         XNClientWindow, window, XNFocusWindow, window, NULL);

        if ((ic != NULL)
            && (XGetICValues(ic, XNFilterEvents, &ic_input_mask, NULL) == NULL))
                input_mask |= ic_input_mask;
        else
            pWorkView->pViClient->Log("XCreateIC or XGetICValues failed");
    }

    XSelectInput(display, window, input_mask);

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

Не смотря на то, что я указывал для pointer GrabModeAsync, функция вела себя как GrabModeSync.

«If pointer_mode is GrabModeSync , the state of the pointer (as seen by client applications) appears to freeze, and the X server generates no further pointer events ...»

А должна была так: «If pointer_mode is GrabModeAsync , pointer event processing is unaffected by activation of the grab.»

Вообщем, я поступил так: подписался еще на события LeaveNotify и EnterNotify и сделал следующим образом.

...

          case FocusIn:
                if (xevent.xfocus.mode == NotifyGrab)
                    break;

                focused = true;

                pKeyboard->ResetModifierKeys();

                if (mouse_in_window)
                {
                    status = XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
                    pWorkView->pViClient->Log("XGrabKeyboard returned %d", status);
                }

                break;

            case FocusOut:
                if (xevent.xfocus.mode == NotifyUngrab)
                    break;

                focused = false;

                if (xevent.xfocus.mode == NotifyWhileGrabbed)
                {
                    status = XUngrabKeyboard(display, CurrentTime);
                    pWorkView->pViClient->Log("XUngrabKeyboard returned %d", status);
                }

                break;

            case EnterNotify:
                mouse_in_window = true;

                if (fullscreen)
                {
                    XSetInputFocus(display, window, RevertToPointerRoot, CurrentTime);
                    break;
                }

                if (focused)
                {
                    status = XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
                    pWorkView->pViClient->Log("XGrabKeyboard returned %d", status);
                }

                break;

            case LeaveNotify:
                mouse_in_window = false;
                status = XUngrabKeyboard(display, CurrentTime);
                pWorkView->pViClient->Log("XUngrabKeyboard returned %d", status);
                break;

...

Теперь захваты происходят только, когда окно в фокусе и мышь в клиентской области. Окно перемещается и все работает отлично. Спасибо еще раз за помощь.

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