Comportamento Xlib e Firefox
Estou tentando criar um pequeno gerenciador de janelas (apenas por diversão), mas estou tendo problemas ao lidar com janelas criadas pelo Firefox (somente com esse aplicativo, outros aplicativos funcionam bem)
O problema é que, depois que inicio o Firefox e adiciono minha decoração, ele parece funcionar bem, mas se, por exemplo, eu tentar clicar no botão de menu, a janela (sub) não aparecerá.
O que parece acontecer é que, após o clique, um evento ClientMessage é acionado com os seguintes valores:
Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)
Agora, o problema é que não sei como mostrar a janela, qual janela. Eu tentei com:
XRaiseWindowXMapWindowEu tentei pegar a janela transitória e mostrarMas sem sucesso. O que eu não entendo é que, se essa mensagem do cliente for gerada pela sub-janela do menu ou não.
Como devo mostrar uma janela que está em _NET_WM_STATE_HIDDEN?
Outro problema estranho é que, depois de receber o ClientMessage, eu sempre recebo 2 eventos UnMapNotify.
Eu também tenho outra pergunta, se eu quiser mostrar o menu "Arquivo, Editar" (no Firefox, se bem me lembro, aparece quando você pressiona o botão Alt.
Talvez o Firefox crie uma árvore de janelas?
Este é o loop em que eu manejo os eventos:
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;
}
Agora, na mensagem do cliente, na verdade, estou apenas tentando coletar algumas informações para entender o que está acontecendo. E o que posso ver no código acima é que a janela que gerou o evento contém um filho (novamente: esse é o menu? Ou não?)
O código para o evento MapNotify, onde adiciono a decoração, é o seguinte:
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);
}
Agora alguém pode me ajudar com esses problemas? Infelizmente, eu já pesquisei no google várias vezes, mas sem sucesso.
Para resumir, meus problemas são dois: 1. Como mostrar sub-janelas do Firefox 2. Como mostrar o menu Arquivo, Editar.
ATUALIZAR
Notei algo estranho testando o Firefox com o xev para entender quais eventos são disparados para mostrar um aplicativo. Vi que, usando o Firefox em unidade, e usando o Firefox em outra janela, os eventos disparados são completamente diferentes. Na Unity tenho apenas:
ClientMessageUnmapNotifyEm vez de usar o Firefox, por exemplo, com o xfce4, os xevents gerados são mais:
VisiblityNotify (mais de um)Evento de exposição (mais de um)Mas se eu tentar habilitar o VisibilityChangeMask no meu wm, eu recebo os seguintes eventos:
ConfigureNotifyClientMessageMapNotify2 UnMapNotifyATUALIZAÇÃO 2
Tentei ler as propriedades XWMhints na janela ClientMessage (provavelmente a janela menù) e os valores são:
Para os sinalizadores 67 = InputHint, StateHint, WIndowGroupHint
Para o estado inicial NormalState
ATUALIZAÇÃO 3
Tentei ver como outro gerenciador de janelas funciona e estava olhando o código fonte do calmwm. O que eu entendo é que, quando o evento ClientMessage chegar, com uma mensagem _NET_WM_STATE, ele atualiza essas propriedades e, no caso de _NET_WM_STATE_HIDDEN, limpa essa propriedade e o resultado será que a propriedade será excluída. Então, tentei atualizar meu código para excluir essa propriedade, mas ainda não está funcionando. De qualquer forma, o código atualizado relevante em client_message_handler agora se parece com isso:
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]);
}
}
É apenas um teste e tenho certeza de que i = 1 no meu caso é a propriedade _NET_WM_STATE_HIDDEN.
Aqui está um link para o código-fonte calmwm:https://github.com/chneukirchen/cwm/blob/linux/xevents.c
Então, eu ainda estou preso nesse ponto.
ATUALIZAÇÃO 4
Realmente não sei se isso ajuda, mas tentei ler os atributos da janela no evento MapNotify, e a janela map_state é IsViewable (2).
ATUALIZAÇÃO 5
Eu encontrei um problema semelhante aqui no SO, usando xlib com python:Xlib python: não é possível mapear menus do firefox
A solução sugere usar XSetInputFocus, tentei isso no meu manipulador XMapNotify:
XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);
Mas ainda não ajuda, o menu do Firefox ainda não aparece! E eu tenho o mesmo problema com o botão direito.
ATUALIZAÇÃO 6
Jogando com o evento xconfigurenotify e o evento unmap, descobri que a solicitação: Xconfigure possui 2 campos da janela: window e acima, e quando o valor xconfigurerequest.window é o mesmo que o valor xunmap.window.
E também que o xconfigurerequest.above está sempre mudando, mas o xconfigurerequest.window é sempre o mesmo em todos os eventos.
Parece que o xconfigurerequest.above está relacionado ao menu que estou tentando abrir. Por exemplo:
se clicar com o botão direito do mouse em uma página, recebo um ID (sempre o mesmo para cada clique subsequente)se eu clicar com o botão direito em uma guia, o valor acima será outroe o mesmo acontece se eu clicar com o botão esquerdo do mouse no menu principal do FirefoxAinda não sei se isso ajuda.
Realmente não sei Alguém tem alguma idéia?