tags:

views:

505

answers:

3

I have multiple "desktops" that I switch between for different tasks in my KDE Linux environment. How can I automagically determine which desktop my Konsole ( kde console) window is being displayed in?

EDIT: I'm using KDE 3.4 in a corporate environment

This is programming related. I need to programatically (a.k.a. automagically ) determine which desktop a user is on and then interact with X windows in that desktop from a python script.

Should I go around and nuke all Microsoft IDE questions as not programming related? How about Win32 "programming" questions? Should I try to close those too?

+3  A: 

The KDE window manager, as well as GNOME and all WMs that follow the freedesktop standards support the Extended Window Manager Hints (EWMH).

These hints allow developers to access programmatically several window manager functions like maximize, minimize, set window title, virtual desktop e.t.c

I have never worked with KDE but Gnome provides such functionality so I assume that KDE has it too.

It is also possible to access a subset of these hints with pure Xlib functions. This subset are ICCCM hints. If memory serves me correct virtual desktop access is only in EWMH.

Update: Found it! (_NET_CURRENT_DESKTOP)

kazanaki
+4  A: 

Actually EWMH _NET_CURRENT_DESKTOP gives you which is the current desktop for X, not relative to the application. Here's a C snippet to get the _WM_DESKTOP of an application. If run from the KDE Konsole in question it will give you what desktop it is on, even it is not the active desktop or not in focus.

#include <X11/Xlib.h>
#include <X11/Shell.h>
...

Atom net_wm_desktop = 0;
long desktop;
Status ret;

/* see if we've got a desktop atom */
Atom net_wm_desktop = XInternAtom( display, "_NET_WM_DESKTOP", False);
if( net_wm_desktop == None ) {
 return;
}

/* find out what desktop we're currently on */
if ( XGetWindowProperty(display, window, net_wm_desktop, 0, 1, 
   False, XA_CARDINAL, (Atom *) &type_ret, &fmt_ret, 
   &nitems_ret, &bytes_after_ret, 
   (unsigned char**)&data) != Success || data == NULL
) {
fprintf(stderr, "XGetWindowProperty() failed");
 if ( data == NULL ) {
  fprintf(stderr, "No data returned from XGetWindowProperty()" );
 }
 return;
}
desktop = *data;
XFree(data);

and desktop should be the index of the virtual desktop the Konsole is currently in. That is not the same which head of a multi-headed display. If you want to determine which head, you need to use XineramaQueryScreens (Xinerama extension, not sure if there is a XRandR equivalent or not. Does not work for nVidia's TwinView.

Here's an excerpt from some code I wrote, that given a x and y, calculate the screen boundaries (sx, sy, and sw with screen width and sh for screen height). You can easily adapt it to simply return which "screen" or head x and y are on. (Screen has a special meaning in X11).

#include <X11/X.h>
#include <X11/extensions/Xinerama.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

Bool xy2bounds(Display* d,int x, int y, int* sx, int* sy, int* sw, int* sh) {
   *sx = *sy = *sw = *sh = -1;   /* Set to invalid, for error condition */
   XineramaScreenInfo *XinInfo;
   int xin_screens = -1;
    int i;
   int x_origin, y_origin, width, height;
   Bool found = False;

   if ( d == NULL )
      return False;
   if ( (x < 0) || (y < 0) )
      return False;

   if ( True == XineramaIsActive(d) ) {
      XinInfo = XineramaQueryScreens( d, &xin_screens );
      if ( (NULL == XinInfo) || (0 == xin_screens) ) {
         return False;
      }
   } else {
      /* Xinerama is not active, so return usual width/height values */
      *sx = 0;
      *sy = 0;
      *sw = DisplayWidth( d, XDefaultScreen(d) );
      *sh = DisplayHeight( d, XDefaultScreen(d) );
      return True;
   }

   for ( i = 0; i < xin_screens; i++ ) {
      x_origin = XinInfo[i].x_org;
      y_origin = XinInfo[i].y_org;
      width = XinInfo[i].width;
      height = XinInfo[i].height;
      printf("Screens: (%d) %dx%d - %dx%d\n", i,
            x_origin, y_origin, width, height );

      if ( (x >= x_origin) && (y >= y_origin) ) {
         if ( (x <= x_origin+width) && (y <= y_origin+height) ) {
            printf("Found Screen[%d] %dx%d - %dx%d\n",
               i, x_origin, y_origin, width, height );

            *sx = x_origin;
            *sy = y_origin;
            *sw = width;
            *sh = height;
            found = True;
            break;
         }
      }
   }

   assert( found == True );

   return found;
}
mctylr
Wow! Thank you *very* much.
Ross Rogers
I'm working my way through your example code, but I can't figure out how to get a "Window" handle to the Konsole window?
Ross Rogers
I had forgotten that detail, but it should be possible with `xwininfo` or `xprop`.
mctylr
+1  A: 

With dcop, the kde Desktop COmmunication Protocol, you could easily get current desktop executing

  dcop kwin KWinInterface currentDesktop

command. If you are working with new kde 4.x dcop is no more used, and you can translate the command to a DBUS call. It should be quite simple to send/get dbous messages with python apis.

Sorry for my bad english, Emilio

Emilio