I'm trying to create a small window manager (just for fun), but I'm having problems in handling windows created by Firefox (only with that application, other apps works fine)
The problem is, after I launch Firefox, and add my decoration, it seems to work fine, but if for example I try to click on the menu button, the (sub)window doesn't appear.
What seems to happen is that after the click, a ClientMessage event is fired with the following values:
Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)
Now the problem is that I don't know how to show the window, which window. I tried with:
- XRaiseWindow
- XMapWindow
- I tried to get the transient window and show it
But without success. What I don't understand is that if this client message is generated by the menu subwindow or not.
How should I show a window that is in _NET_WM_STATE_HIDDEN?
Another strange problem is that after receiving the ClientMessage, I always receive 2 UnMapNotify Events.
I also have another question, if I want to show the "File, Edit" menù (in Firefox it appears, if I remember correctly, when you press the Alt button.
Maybe Firefox creates a tree of windows?
This is the loop where I handle the events:
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;
}
Now in the clientmessage actually I'm just trying to see collect some information to understand what is happening. And what I can see from the code above, is that the window that raised the event contains one child (again: is that the menu? or not?)
The code for the MapNotify event, where I add the decoration is the following:
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);
}
Now can someone help me with these problems? Unfortunately I already googled many times, but without success.
To sum up, my issues are two: 1. How to show subwindows from Firefox 2. How to show the File, Edit menu.
UPDATE
I noticed something strange testing Firefox with xev to understand what events are fired in order to show an application. I saw that using Firefox in unity, and using Firefox in another window manger, the events fired are completely different. In Unity I have only:
- ClientMessage
- UnmapNotify
Instead using Firefox, for example with xfce4, the xevents generated are more:
- VisiblityNotify (more than one)
- Expose event (more than one)
But if I try to enable VisibilityChangeMask in my wm, I receive the following events:
- ConfigureNotify
- ClientMessage
- MapNotify
- 2 UnMapNotify
UPDATE 2
I tried to read the XWMhints properties in the ClientMessage window (probably the menù window) and the values are:
For the flags 67 = InputHint, StateHint, WIndowGroupHint
For the initial state NormalState
UPDATE 3
I tried to look how another window manager works, and I was looking at the source code of calmwm. What is my understanding is that, when the ClientMessage event arrives, with a _NET_WM_STATE message, it updates these properties, and in the case of _NET_WM_STATE_HIDDEN it clears this property, and the result will be that the property will be deleted. So I tried to update my code to delete that property, but it's still not working. Anyway the relevant updated code in client_message_handler now looks like this:
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]);
}
}
It is only a test, and I'm sure that i=1 in my case is the _NET_WM_STATE_HIDDEN property.
Here a link to calmwm source code: https://github.com/chneukirchen/cwm/blob/linux/xevents.c
So I'm still stuck at that point.
UPDATE 4
Really I don't know if it helps, but I tried to read the window attributes in the MapNotify Event, and the window map_state is IsViewable (2).
UPDATE 5
I found a similar problem here in SO, using xlib with python: Xlib python: cannot map firefox menus
The solution suggests to use XSetInputFocus, i tried that on my XMapNotify handler:
XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);
But it still doesn't help, the firefox menu still doesn't appear!! And i have the same problem with right-click.
UPDATE 6
Playing with xconfigurenotify event and unmap event i found that the: Xconfigure request has 2 window fields: window and above, and when the the xconfigurerequest.window value is the same of xunmap.window value.
And also that the xconfigurerequest.above is always changing, but xconfigurerequest.window is always the same in all events.
It seems that the xconfigurerequest.above is related to what menu i'm trying to open. For example:
- if right-click on a page i get an id (always the same for every subsequent click)
- if i right-clik on a tab, the above value is another one
- and the same happen if i left-click the firefox main menu
Still don't know if that helps.
Really don't know Anyone got any idea?
_NET_ACTIVE_WINDOW
hint and alsoXMapRaised
: gist.github.com/Noitidart/… ill look more at your issue and also let my friend know – Knut_NET_WM_STATE_TOGGLE
as seen here: github.com/Noitidart/NativeShot/blob/… theXFlush
is crucial for action to take, ifXFlush
is not done, it will not come forward, at least in our experince, so usingXFlush
might be your solution let me know how it goes plz. – Knut