Событие X11 DestroyNotify возвращает неверный параметр окна

c #x11 #xcb

#c #x11 #xcb

Вопрос:

В настоящее время я работаю над написанием диспетчера окон для восстановления с использованием C и библиотеки XCB. Я отключаю управление окнами, когда получаю событие UnmapNotify; в этом случае код очень прост:

   if (unmap_ignore > 0) {
    unmap_ignore--;
    return;
  }
  client *cl = nullptr;
  size_t idx = 0;
  for (client amp;c : clients) {
    if (c.window == ev->window) {
      cl = amp;c;
      break;
    }
    idx  ;
  }
  if (!cl)
    return;
  xcb_unmap_window(conn, cl->frame);
  clients.erase(clients.begin()   idx);
 

Однако это не работает для некоторых клиентов, которые не беспокоятся о том, чтобы отменить отображение окна (обычно это происходит, когда вы принудительно завершаете процесс). Затем вместо этого отправляется DestroyNotify. Однако ev->window поле там (typeof ev = xcb_destroy_notify_event_t) представляет собой некоторое значение, которое мне не нужно… вот несколько примеров журналов (также обратите внимание, что каждая строка представляет собой новое событие DestroyNotify, по какой-то причине я получаю его дважды, и каждый раз поле #window отличается, но неверно):

 Found a client window: 4194307 but this was destroyed: 4194305
Found a client window: 4194307 but this was destroyed: 4194313
 

Я помню, прежде чем я попытался написать оконный менеджер в Xlib, и у меня была точно такая же проблема. Должно быть, я упускаю что-то очевидное, но если я посмотрю на код других перепрофилирующих оконных менеджеров, таких как Awesome или Herbsluftwm, они просто используют поле window и не имеют проблем. Что я делаю не так?

(мой полный код здесь: http://ix.io/3yDj )

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

Я также сначала подумал, что он может сообщать о DestroyNotify в родительском окне вместо перепрофилированного клиентом, поэтому я попытался проверить фрейм, но безрезультатно:

 Found a client window: 2097152 but this was destroyed: 4194305
Found a client window: 2097152 but this was destroyed: 4194313
 

Я действительно был в тупике, поэтому любая помощь приветствуется, спасибо!

Например, Awesome делает то же самое, что я пробовал с ev-> window:

 static void
event_handle_destroynotify(xcb_destroy_notify_event_t *ev)
{
    client_t *c;

    if((c = client_getbywin(ev->window)))
        client_unmanage(c, CLIENT_UNMANAGE_DESTROYED);
    else
        for(int i = 0; i < globalconf.embedded.len; i  )
            if(globalconf.embedded.tab[i].win == ev->window)
            {
                xembed_window_array_take(amp;globalconf.embedded, i);
                luaA_systray_invalidate();
            }
}
 

Комментарии:

1. Устанавливаете ли вы StructureNotifyMask или SubstructureNotifyMask или оба, и в каком окне?

2. Я установил SubstructureNotifyMask и SubstructureRedirect mask ( XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT ) в корневом окне.

3. SubstructureNotifyMask должен заставить корневое окно получать события DestroyNotify для своих дочерних элементов. Какова ваша структура восстановления? У вас каждое окно перенаправлено на своего собственного родителя или на корень?

4. Я получаю события destroynotify; просто поле window из них не является фактическим уничтоженным окном. У меня каждое окно повторно отображается в созданном мной фреймовом окне, вы можете увидеть это window_manager::handle_map_request в моем коде.

5. Возможно, обходным путем может быть попытка получить родительское окно из тех, для которых сообщается о DestroyNotify, если они на самом деле являются дочерними окнами. Но я не уверен, что это возможно даже с уже уничтоженным окном…