Comportamiento de Xlib y Firefox
Estoy tratando de crear un pequeño administrador de ventanas (solo por diversión), pero tengo problemas para manejar las ventanas creadas por Firefox (solo con esa aplicación, otras aplicaciones funcionan bien)
El problema es que después de iniciar Firefox y agregar mi decoración, parece funcionar bien, pero si, por ejemplo, trato de hacer clic en el botón de menú, no aparece la (sub) ventana.
Lo que parece suceder es que después del clic, se desencadena un evento ClientMessage con los siguientes valores:
Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)
Ahora el problema es que no sé cómo mostrar la ventana, qué ventana. Lo intenté con:
XRaiseWindowXMapWindowTraté de obtener la ventana transitoria y mostrarlaPero sin éxito. Lo que no entiendo es que si este mensaje de cliente es generado por la subventana del menú o no.
¿Cómo debo mostrar una ventana que está en _NET_WM_STATE_HIDDEN?
Otro problema extraño es que después de recibir ClientMessage, siempre recibo 2 eventos UnMapNotify.
También tengo otra pregunta, si quiero mostrar el menú "Archivo, Editar" (en Firefox aparece, si no recuerdo mal, cuando presionas el botón Alt.
¿Quizás Firefox crea un árbol de ventanas?
Este es el ciclo donde manejo los 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;
}
Ahora, en el mensaje del cliente, en realidad solo estoy tratando de recopilar información para comprender lo que está sucediendo. Y lo que puedo ver en el código anterior es que la ventana que generó el evento contiene un elemento secundario (de nuevo: ¿es ese el menú o no?)
El código para el evento MapNotify, donde agrego la decoración es el siguiente:
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);
}
Ahora, ¿alguien puede ayudarme con estos problemas? Lamentablemente ya busqué en Google muchas veces, pero sin éxito.
En resumen, mis problemas son dos: 1. Cómo mostrar subventanas de Firefox 2. Cómo mostrar el menú Archivo, Editar.
ACTUALIZAR
Noté algo extraño probando Firefox con xev para comprender qué eventos se activan para mostrar una aplicación. Vi que usando Firefox en la unidad, y usando Firefox en otro administrador de ventanas, los eventos disparados son completamente diferentes. En Unity solo tengo:
ClientMessageUnmapNotifyEn lugar de usar Firefox, por ejemplo con xfce4, los eventos x generados son más:
VisiblityNotify (más de uno)Exponer evento (más de uno)Pero si trato de habilitar VisibilityChangeMask en mi wm, recibo los siguientes eventos:
ConfigureNotifyClientMessageMapNotify2 UnMapNotifyACTUALIZACIÓN 2
Intenté leer las propiedades de XWMhints en la ventana ClientMessage (probablemente la ventana de menú) y los valores son:
Para las banderas 67 = InputHint, StateHint, WIndowGroupHint
Para el estado inicial NormalState
ACTUALIZACIÓN 3
Traté de ver cómo funciona otro administrador de ventanas, y estaba mirando el código fuente de calmwm. Entiendo que, cuando llega el evento ClientMessage, con un mensaje _NET_WM_STATE, actualiza estas propiedades y, en el caso de _NET_WM_STATE_HIDDEN, borra esta propiedad y el resultado será que la propiedad se eliminará. Así que intenté actualizar mi código para eliminar esa propiedad, pero todavía no funciona. De todos modos, el código actualizado relevante en client_message_handler ahora se ve así:
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]);
}
}
Es solo una prueba, y estoy seguro de que i = 1 en mi caso es la propiedad _NET_WM_STATE_HIDDEN.
Aquí un enlace al código fuente de calmwm:https://github.com/chneukirchen/cwm/blob/linux/xevents.c
Entonces todavía estoy atrapado en ese punto.
ACTUALIZACIÓN 4
Realmente no sé si ayuda, pero intenté leer los atributos de la ventana en el evento MapNotify, y la ventana map_state es IsViewable (2).
ACTUALIZACIÓN 5
Encontré un problema similar aquí en SO, usando xlib con python:Python Xlib: no se pueden asignar menús de Firefox
La solución sugiere usar XSetInputFocus, lo intenté en mi controlador XMapNotify:
XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);
¡Pero todavía no ayuda, el menú de Firefox todavía no aparece! Y tengo el mismo problema con el clic derecho.
ACTUALIZACIÓN 6
Jugando con el evento xconfigurenotify y el evento unmap descubrí que: la solicitud Xconfigure tiene 2 campos de ventana: ventana y superior, y cuando el valor xconfigurerequest.window es el mismo que el valor xunmap.window.
Y también que xconfigurerequest.above siempre está cambiando, pero xconfigurerequest.window es siempre el mismo en todos los eventos.
Parece que xconfigurerequest.above está relacionado con el menú que intento abrir. Por ejemplo:
si hago clic derecho en una página, obtengo una identificación (siempre la misma para cada clic posterior)si hago clic derecho en una pestaña, el valor anterior es otroy lo mismo sucede si hago clic izquierdo en el menú principal de FirefoxTodavía no sé si eso ayuda.
Realmente no sé ¿Alguien tiene alguna idea?