Поведение Xlib и Firefox
Я пытаюсь создать небольшой оконный менеджер (просто для удовольствия), но у меня проблемы с обработкой окон, созданных Firefox (только с этим приложением, другие приложения работают нормально)
Проблема в том, что после того, как я запустил Firefox и добавил свое украшение, он, кажется, работает нормально, но если, например, я пытаюсь нажать на кнопку меню, окно (под) не появляется.
Похоже, что после нажатия происходит событие ClientMessage со следующими значениями:
Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)
Теперь проблема в том, что я не знаю, как показать окно, какое окно. Я пробовал с:
XRaiseWindowXMapWindowЯ пытался получить переходное окно и показать егоНо без успеха. Что я не понимаю, так это то, что это клиентское сообщение генерируется подокном меню или нет.
Как мне показать окно в _NET_WM_STATE_HIDDEN?
Другая странная проблема заключается в том, что после получения ClientMessage я всегда получаю 2 события UnMapNotify.
У меня также есть другой вопрос, если я хочу показать меню «Файл, Редактировать» (в Firefox он появляется, если я правильно помню, когда вы нажимаете кнопку Alt.
Может быть, Firefox создает дерево окон?
Это цикл, в котором я обрабатываю события:
while(1){
XNextEvent(display, &local_event);
switch(local_event.type){
case ConfigureNotify:
configure_notify_handler(local_event, display);
break;
case MotionNotify:
motion_handler(local_event, display);
break;
case CreateNotify:
cur_win = local_event.xcreatewindow.window;
char *window_name;
XFetchName(display, cur_win, &window_name);
printf("Window name: %s\n", window_name);
if(window_name!=NULL){
if(!strcmp(window_name, "Parent")){
printf("Adding borders\n");
XSetWindowBorderWidth(display, cur_win, BORDER_WIDTH);
}
XFree(window_name);
}
break;
case MapNotify:
map_notify_handler(local_event,display, infos);
break;
case UnmapNotify:
printf("UnMapNotify\n");
break;
case DestroyNotify:
printf("Destroy Event\n");
destroy_notify_handler(local_event,display);
break;
case ButtonPress:
printf("Event button pressed\n");
button_handler(local_event, display, infos);
break;
case KeyPress:
printf("Keyboard key pressed\n");
keyboard_handler(local_event, display);
break;
case ClientMessage:
printf("------------ClientMessage\n");
printf("\tMessage: %s\n", XGetAtomName(display,local_event.xclient.message_type));
printf("\tFormat: %d\n", local_event.xclient.format);
Atom *atoms = (Atom *)local_event.xclient.data.l;
int i =0;
for(i=0; i<=5; i++){
printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i]));
}
int nchild;
Window *child_windows;
Window parent_window;
Window root_window;
XQueryTree(display, local_event.xclient.window, &root_window, &parent_window, &child_windows, &nchild);
printf("\tNumber of childs: %d\n", nchild);
break;
}
Сейчас в клиентском сообщении на самом деле я просто пытаюсь увидеть, как собирать некоторую информацию, чтобы понять, что происходит. И что я могу видеть из кода выше, это то, что окно, которое вызвало событие, содержит одного дочернего элемента (опять же: это меню? Или нет?)
Код для события MapNotify, куда я добавляю украшение, следующий:
void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){
printf("----------Map Notify\n");
XWindowAttributes win_attr;
char *child_name;
XGetWindowAttributes(display, local_event.xmap.window, &win_attr);
XFetchName(display, local_event.xmap.window, &child_name);
printf("\tAttributes: W: %d - H: %d - Name: %s - ID %lu\n", win_attr.width, win_attr.height, child_name, local_event.xmap.window);
Window trans = None;
XGetTransientForHint(display, local_event.xmap.window, &trans);
printf("\tIs transient: %ld\n", trans);
if(child_name!=NULL){
if(strcmp(child_name, "Parent") && local_event.xmap.override_redirect == False){
Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num,
win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0,
BlackPixel(display, infos.screen_num));
XMapWindow(display, new_win);
XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT);
set_window_item(local_event.xmap.window, new_win);
XSelectInput(display, local_event.xmap.window, StructureNotifyMask);
printf("\tParent window id: %lu\n", new_win);
put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num));
}
}
XFree(child_name);
}
Теперь кто-нибудь может мне помочь с этими проблемами? К сожалению, я уже много раз гуглил, но безуспешно.
Подводя итог, у меня две проблемы: 1. Как показать подокна из Firefox 2. Как показать меню Файл, Правка.
ОБНОВИТЬ
Я заметил кое-что странное тестирование Firefox с xev, чтобы понять, какие события запускаются, чтобы показать приложение. Я видел, что при использовании Firefox в единстве и при использовании Firefox в другом менеджере окон события запускаются совершенно по-другому. В Unity у меня есть только:
ClientMessageUnmapNotifyВместо этого, используя Firefox, например, с xfce4, генерируются xevents:
VisiblityNotify (более одного)Выставить событие (более одного)Но если я пытаюсь включить VisibilityChangeMask в моем wm, я получаю следующие события:
ConfigureNotifyClientMessageMapNotify2 UnMapNotifyОБНОВЛЕНИЕ 2
Я попытался прочитать свойства XWMhints в окне ClientMessage (возможно, в окне меню) и значения:
Для флагов 67 = InputHint, StateHint, WIndowGroupHint
Для начального состояния NormalState
ОБНОВЛЕНИЕ 3
Я пытался посмотреть, как работает другой оконный менеджер, и я искал исходный код спокойного. Насколько я понимаю, при получении события ClientMessage с сообщением _NET_WM_STATE они обновляют эти свойства, а в случае _NET_WM_STATE_HIDDEN очищают это свойство, и в результате это свойство будет удалено. Поэтому я попытался обновить свой код, чтобы удалить это свойство, но оно все еще не работает. В любом случае соответствующий обновленный код в client_message_handler теперь выглядит так:
Atom *atoms = (Atom *)local_event.xclient.data.l;
int i =0;
for(i=0; i<=5; i++){
printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i]));
if(i==1){
printf("\t Deleting Property: _NET_WM_STATE_HIDDEN \n");
XDeleteProperty(display, cur_window, atoms[i]);
}
}
Это всего лишь тест, и я уверен, что в моем случае i = 1 - это свойство _NET_WM_STATE_HIDDEN.
Вот ссылка на исходный код quietwm:https://github.com/chneukirchen/cwm/blob/linux/xevents.c
Так что я все еще застрял в этой точке.
ОБНОВЛЕНИЕ 4
На самом деле я не знаю, помогает ли это, но я попытался прочитать атрибуты окна в событии MapNotify, и окно map_state имеет вид IsViewable (2).
ОБНОВЛЕНИЕ 5
Я нашел похожую проблему здесь, в SO, используя xlib с python:Xlib Python: не может отобразить меню Firefox
Решение предлагает использовать XSetInputFocus, я попробовал это на моем обработчике XMapNotify:
XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);
Но это все равно не помогает, меню Firefox все еще не появляется !! И у меня та же проблема с правой кнопкой мыши.
ОБНОВЛЕНИЕ 6
Играя с событиями xconfigurenotify и unmap, я обнаружил, что запрос: Xconfigure имеет 2 поля окна: window и выше, и когда значение xconfigurerequest.window совпадает со значением xunmap.window.
А также, что xconfigurerequest.above всегда меняется, но xconfigurerequest.window всегда одинаков во всех событиях.
Кажется, что xconfigurerequest.above связан с тем, какое меню я пытаюсь открыть. Например:
если щелкнуть правой кнопкой мыши на странице, я получаю идентификатор (всегда один и тот же для каждого последующего клика)если я щелкну правой кнопкой мыши на вкладке, вышеуказанное значение является еще одними то же самое произойдет, если я щелкну левой кнопкой мыши главное меню FirefoxВсе еще не знаю, помогает ли это.
На самом деле не знаю, кто-нибудь есть идеи?