Я пытаюсь создать небольшой оконный менеджер (просто для удовольствия), но у меня возникают проблемы с обработкой окон, созданных Firefox (только с этим приложением, другие приложения прекрасно работают)
Проблема заключается в том, что после запуска Firefox и добавления своего оформления кажется, что он работает нормально, но если, например, я пытаюсь нажать кнопку меню, окно (sub) не появится.
Похоже, что после клика событие ClientMessage запускается со следующими значениями:
Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)
Теперь проблема в том, что я не знаю, как показать окно, какое окно. Я пробовал:
- XRaiseWindow
- XMapWindow
- Я попытался получить временное окно и показать его
Но без успеха. Я не понимаю, что если это сообщение клиента генерируется подположением меню или нет.
Как показать окно, которое находится в _NET_WM_STATE_HIDDEN?
Еще одна странная проблема заключается в том, что после получения ClientMessage я всегда получаю 2 события UnMapNotify.
У меня также есть другой вопрос, если я хочу показать "File, Edit" menù (в 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;
}
Теперь в clientmessage на самом деле я просто пытаюсь собрать информацию, чтобы понять, что происходит. И то, что я вижу из приведенного выше кода, заключается в том, что окно, в котором было создано событие, содержит один дочерний элемент (опять же: это меню? Или нет?)
Код события 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);
}
Теперь кто-нибудь может мне помочь с этими проблемами? К сожалению, я уже много раз искал Google, но безуспешно.
Подводя итог, мои проблемы - два: 1. Как показать подкачки из Firefox 2. Как показать меню File, Edit.
UPDATE
Я заметил что-то странное, проверяя Firefox с помощью xev, чтобы понять, какие события увольняются, чтобы показать приложение. Я видел, что использование Firefox в единстве и использование Firefox в другом ящике окна, уволенные события совершенно разные. В Unity у меня есть только:
- ClientMessage
- UnmapNotify
Вместо использования Firefox, например с xfce4, генерируемые xevents:
- VisiblityNotify (более одного)
- Событие Expose (более одного)
Но если я попытаюсь включить VisibilityChangeMask в моем wm, я получаю следующие события:
- ConfigureNotify
- ClientMessage
- MapNotify
- 2 UnMapNotify
ОБНОВЛЕНИЕ 2
Я попытался прочитать свойства XWMhints в окне ClientMessage (возможно, в мужском окне) и значения:
-
Для флагов 67 = InputHint, StateHint, WIndowGroupHint
-
Для исходного состояния NormalState
ОБНОВЛЕНИЕ 3
Я попытался посмотреть, как работает другой оконный менеджер, и я смотрел исходный код quietwm. Насколько я понимаю, когда событие 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]);
}
}
Это только тест, и я уверен, что я = 1 в моем случае является свойством _NET_WM_STATE_HIDDEN.
Здесь ссылка на исходный код quietwm: https://github.com/chneukirchen/cwm/blob/linux/xevents.c
Итак, я все еще застрял в этом.
ОБНОВЛЕНИЕ 4
На самом деле я не знаю, помогает ли это, но я попытался прочитать атрибуты окна в событии MapNotify, а window 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 поля окна: окно и выше, и когда значение xconfigurerequest.window совпадает с значением xunmap.window.
А также, что xconfigurerequest.above всегда меняется, но xconfigurerequest.window всегда одинаково во всех событиях.
Кажется, что xconfigurerequest.выше связано с тем, какое меню я пытаюсь открыть. Например:
- если щелкнуть правой кнопкой мыши на странице, я получу идентификатор (всегда один и тот же для каждого последующего щелчка)
- Если я right-clik на вкладке, указанное выше значение - это еще один
- и то же самое произойдет, если я щелкнул левой кнопкой мыши по главному меню firefox
Не знаю, поможет ли это.
На самом деле не знаю Кто-нибудь понял?