[Xcb] Finding which screen has focus in multi-head mode

Baron baron at bologrew.net
Thu Nov 5 00:32:22 PST 2015


Greetings all.

I have been trying to fix a focus-stealing bug in the KDE KWin window manager 
which occurs when you have two (or more) independent screens or heads (also 
known as Zaphod mode).
The function that is required is to find which head has focus so I am using 
"xcb_get_input_focus".  The man page is incomplete with the "focus" reply 
value just listed as "TODO: NOT YET DOCUMENTED".  However, I think it has the 
same replies as "XGetInputFocus" in which case it could be the window ID, 
PointerRoot or None.

I am frequently getting "PointerRoot" as the returned value and there is 
disagreement between the KWin maintainer and me as to exactly what that means 
when you have two separate screens.

He says that "the value is simply unspecific" and tells you nothing about 
which screen has the focus.

I, on the other hand, read the man page for "XGetInputFocus" which says "if 
focus is PointerRoot, the focus window is dynamically taken to be the root 
window of whatever screen the pointer is on at each keyboard event".
If that is the case then I can call "xcb_query_pointer" and ask it which 
screen it is on.

Now I don't mind which, if either, of us is right but I really would like to 
know what a focus of "PointerRoot" should or does mean in this context.
Alternatively, if anyone has a different way to find which screen has focus 
then I'd love to hear about it.

My test program is reproduced below.
Thank-you for your time.

Nicholas Redgrave


#include <stdio.h>
#include <xcb/xcb.h>
#include <inttypes.h>
#include <stdlib.h>

int main ()
{
  int i, screenNum;
  xcb_screen_t     *screen;

  xcb_get_input_focus_reply_t *focus_reply;
  xcb_get_geometry_reply_t *geometry_reply;
  xcb_query_pointer_reply_t *pointer_reply;
  xcb_generic_error_t *error;

  xcb_connection_t *connection = xcb_connect (NULL, &screenNum);
  printf("screenNum: %d\n",screenNum);

  /* Get the screen whose number is screenNum */
  const xcb_setup_t *setup = xcb_get_setup (connection);
  xcb_screen_iterator_t iter = xcb_setup_roots_iterator (setup);  

  // we want the screen at index screenNum of the iterator
  for (i = 0; i < screenNum; ++i) {
    xcb_screen_next (&iter);
  }
  screen = iter.data;

/* find which screen has focus */
  focus_reply = xcb_get_input_focus_reply (connection, xcb_get_input_focus(connection), &error);
  if( error != NULL ) {
    printf("Could not get focussed window (X error %d)\n",error->error_code);
    free(error);
  }
  else {
    printf("Focussed window is %d\n",focus_reply->focus);
    if( focus_reply->focus == 0 ) {
      printf("I presume this is None so no window anywhere has focus\n");
    }
    else if( focus_reply->focus == 1 ) {
      printf("I presume this is PointerRoot - what does PointerRoot really mean?\n");
      pointer_reply = xcb_query_pointer_reply (connection, xcb_query_pointer(connection, screen->root), &error);
      if( error != NULL ) {
        printf("Could not get pointer query (X error %d)\n",error->error_code);
        free(error);
      }
      else {
        printf ("Pointer on this screen?: %d\n", pointer_reply->same_screen);
        free(pointer_reply);
      }
    }
    else {
      geometry_reply = xcb_get_geometry_reply (connection, xcb_get_geometry(connection, focus_reply->focus), NULL);
      printf ("Focussed Window root id: %d\n", geometry_reply->root);
      if( screen->root == geometry_reply->root ) {
        printf("Window with focus on this screen\n");
      }
      else {
        printf("Window with focus NOT on this screen\n");
      }
      free(geometry_reply);
    }
    free(focus_reply);
  }
  xcb_disconnect (connection);
  return 0;
}


-- 
Fingerprint for GnuPG ID 0x0189562F
ADCF CC73 0DFB 9613 FA78 553B C98C 086F 0189 562F


More information about the Xcb mailing list