Same as in xmonad patch, so someone have tested it :)
> I didn't touched to FocusOut events as it is apparently not necessary.
>
> Hope I didn't broke something...
Comments about the patch inline.
>
> --
>
>
>
> 0001-gui-agent-Implementation-of-WM_TAKE_FOCUS.patch
>
>
> From 774b76b37bb30994e1b2efdf5f4b9fbe39bbcfbe Mon Sep 17 00:00:00 2001
> From: Olivier Medoc <
o_m...@yahoo.fr>
> Date: Fri, 18 Jan 2013 17:05:27 +0100
> Subject: [PATCH] gui-agent: Implementation of WM_TAKE_FOCUS
>
> Only for FocusIn events : need to retrieve and store the InputHint for each window in order to know if the window want to receive InputFocus events. Send WM_TAKE_FOCUS to all window anyway.
> ---
> gui-agent/vmside.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c
> index f03dd7c..a0839ff 100644
> --- a/gui-agent/vmside.c
> +++ b/gui-agent/vmside.c
> @@ -64,12 +64,14 @@ struct _global_handles {
> Atom wm_state; /* Atom: _NET_WM_STATE */
> Atom wm_state_fullscreen; /* Atom: _NET_WM_STATE_FULLSCREEN */
> Atom wm_state_demands_attention; /* Atom: _NET_WM_STATE_DEMANDS_ATTENTION */
> + Atom wm_take_focus; /* Atom: WM_TAKE_FOCUS */
> int xserver_fd;
> Window stub_win; /* window for clipboard operations and to simulate LeaveNotify events */
> unsigned char *clipboard_data;
> unsigned int clipboard_data_len;
> int log_level;
> int sync_all_modifiers;
> + int input_hint; /* the window should get input focus - False=Never */
This should be per-window data, not global one. Struct _global_handles as name
suggests is common for all windows.
Per-window data can be stored in "struct window_data" attached as "data" to
window_list. Note that currently data field is allocated only on docked
windows (check process_xevent_message function) - now it looks that every
window will need such struct (which isn't bad in any way).
> };
>
> struct window_data {
> @@ -273,6 +275,32 @@ void send_wmname(Ghandles * g, XID window)
> write_message(hdr, msg);
> }
>
> +/* Retrieve the 'real' WMHints.
> + We don't forward the info to dom0 as we only need InputHint and dom0 doesn't care about it
> +*/
> +void send_wmhints2(Ghandles * g, XID window)
If function isn't intended to send anything out, it shouldn't be called
"send_wmhints32", better "retrieve_wmhints32".
> +{
> + XWMHints *wm_hints;
> +
> + if (!(wm_hints = XGetWMHints(g->display, window))) {
> + fprintf(stderr, "error reading WM_HINTS\n");
> + return;
> + }
> +
> + if (wm_hints->flags & InputHint) {
> + g->input_hint = wm_hints->input;
> +
> + if (g->log_level > 1)
> + fprintf(stderr, "Received input hint 0x%x for windows 0x%x\n", g->input_hint, (int)window);
> + } else {
> + // Default value
> + if (g->log_level > 1)
> + fprintf(stderr, "Received WMHints without input hint set for window 0x%x\n", (int)window);
> + g->input_hint = True;
> + }
> + XFree(wm_hints);
> +}
> +
> void send_wmhints(Ghandles * g, XID window)
> {
> struct msghdr hdr;
> @@ -302,6 +330,7 @@ void send_wmhints(Ghandles * g, XID window)
> write_message(hdr, msg);
> }
>
> +
> static inline uint32_t flags_from_atom(Ghandles * g, Atom a) {
> if (a == g->wm_state_fullscreen)
> return WINDOW_FLAG_FULLSCREEN;
> @@ -619,6 +648,9 @@ void process_xevent_property(Ghandles * g, XID window, XPropertyEvent * ev)
> else if (ev->atom ==
> XInternAtom(g->display, "WM_NORMAL_HINTS", False))
> send_wmhints(g, window);
> + else if (ev->atom ==
> + XInternAtom(g->display, "WM_HINTS", False))
> + send_wmhints2(g,window);
> else if (ev->atom == g->xembed_info) {
> struct genlist *l = list_lookup(windows_list, window);
> Atom act_type;
> @@ -912,6 +944,7 @@ void mkghandles(Ghandles * g)
> g->wm_state = XInternAtom(g->display, "_NET_WM_STATE", False);
> g->wm_state_fullscreen = XInternAtom(g->display, "_NET_WM_STATE_FULLSCREEN", False);
> g->wm_state_demands_attention = XInternAtom(g->display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
> + g->wm_take_focus = XInternAtom(g->display, "WM_TAKE_FOCUS", False);
> }
>
> void handle_keypress(Ghandles * g, XID winid)
> @@ -1153,6 +1186,25 @@ void handle_crossing(Ghandles * g, XID winid)
>
> }
>
> +void take_focus(Ghandles * g, XID winid)
> +{
> + // Send
> + XClientMessageEvent ev;
> + memset(&ev, 0, sizeof(ev));
> + ev.type = ClientMessage;
> + ev.display = g->display;
> + ev.window = winid;
> + ev.format = 32;
> + ev.message_type = g->wmProtocols;
> + ev.data.l[0] = g->wm_take_focus;
> + ev.data.l[1] = CurrentTime;
> + XSendEvent(ev.display, ev.window, TRUE, 0, (XEvent *) & ev);
> + if (g->log_level > 0)
> + fprintf(stderr, "wm_TAKE_FOCUS sent for 0x%x\n",
> + (int) winid);
> +
> +}
> +
> void handle_focus(Ghandles * g, XID winid)
> {
> struct msg_focus key;
> @@ -1173,19 +1225,31 @@ void handle_focus(Ghandles * g, XID winid)
> #endif
> if (key.type == FocusIn
> && (key.mode == NotifyNormal || key.mode == NotifyUngrab)) {
> +
> XRaiseWindow(g->display, winid);
> - XSetInputFocus(g->display, winid, RevertToParent,
> +
> + // Give input focus only to window that set the input hint
> + if (g->input_hint)
Same as earlier - g->input_hint is global, not local to the window.
> + XSetInputFocus(g->display, winid, RevertToParent,
> CurrentTime);
> +
> + // TODO: do not send take focus if the window doesn't support it ?
Not sure how about the case when window have no WM_HINTS propery at all.
Anyway support for WM_TAKE_FOCUS should announced by window in WM_PROTOCOLS
property (maybe also should be monitoried in process_xevent_property?). IMO
fallback should be XSetInputFocus.
> + take_focus(g, winid);
> +
> if (g->log_level > 1)
> fprintf(stderr, "0x%x raised\n", (int) winid);
> } else if (key.type == FocusOut
> && (key.mode == NotifyNormal
> || key.mode == NotifyUngrab)) {
> +
> XSetInputFocus(g->display, None, RevertToParent,
> CurrentTime);
> +
> + //take_focus();
Souldn't be needed here, even as comment...
> if (g->log_level > 1)
> fprintf(stderr, "0x%x lost focus\n", (int) winid);
> }
> +
> }
>
> int bitset(unsigned char *keys, int num)
> -- 1.7.11.7