В KDE, как я могу автоматически определить, на каком "рабочем столе" находится терминал Konsole?

У меня есть несколько "рабочих столов", между которыми я переключаюсь для разных задач в моей среде KDE Linux. Как я могу автоматически определить, на каком рабочем столе отображается мое окно Konsole (консоли KDE)?

РЕДАКТИРОВАТЬ: я использую KDE 3.4 в корпоративной среде

Это связано с программированием. Мне нужно программно (то есть автоматически) определить, на каком рабочем столе находится пользователь, а затем взаимодействовать с X windows на этом рабочем столе из скрипта Python.

Должен ли я обойти все вопросы по Microsoft IDE как не связанные с программированием? Как насчет Win32 вопросов "программирования"? Должен ли я попытаться закрыть их тоже?

5 ответов

Решение

С dcop, протоколом связи kde для рабочего стола, вы можете легко получить текущую версию рабочего стола

  dcop kwin KWinInterface currentDesktop

команда. Если вы работаете с новым kde 4.x, dcop больше не используется, и вы можете перевести команду в вызов DBUS. Должно быть довольно просто отправлять / получать сообщения dbous с помощью python apis.

Извините за мой плохой английский, Эмилио

На самом деле EWMH _NET_CURRENT_DESKTOP дает вам текущий рабочий стол для X, не относящийся к приложению. Вот фрагмент кода C, чтобы получить _WM_DESKTOP приложения. Если запустить из рассматриваемой KDE Konsole, он покажет, на каком рабочем столе он находится, даже если он не является активным или не находится в фокусе.

#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);

а также desktop должен быть индексом виртуального рабочего стола, в котором в данный момент находится Konsole. Это не то же самое, что заголовок многоголового дисплея. Если вы хотите определить, какую голову вам нужно использовать XineramaQueryScreens (Расширение Xinerama, не уверен, есть ли эквивалент XRandR или нет. Не работает для TwinView nVidia.

Вот выдержка из некоторого кода, который я написал, для которого заданы ax и y, вычисляются границы экрана (sx, sy и sw с шириной экрана и sh для высоты экрана). Вы можете легко адаптировать его, чтобы просто возвращать, какой "экран" или заголовок x и y включены. (Экран имеет особое значение в 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;
}

Ссылаясь на принятый ответ.... dcop сейчас устарел; вместо dcop вы можете использовать dbus (qdbus - инструмент командной строки для dbus).

qdbus org.kde.kwin /KWin currentDesktop

Диспетчер окон KDE, а также GNOME и все WM, соответствующие стандартам freedesktop, поддерживают советы по расширенному диспетчеру окон (EWMH).

Эти советы позволяют разработчикам программно получить доступ к нескольким функциям оконного менеджера, таким как максимизация, свертывание, установка заголовка окна, виртуального рабочего стола и т. Д.

Я никогда не работал с KDE, но Gnome предоставляет такую ​​функциональность, поэтому я предполагаю, что и в KDE она есть.

Также возможно получить доступ к подмножеству этих подсказок с помощью чисто Xlib- функций. Это подмножество - подсказки ICCCM. Если мне не изменяет память, правильный доступ к виртуальному рабочему столу есть только в EWMH.

Обновление: нашел! (_NET_CURRENT_DESKTOP)

Новый ответ, потому что большинство ответов здесь получают текущий рабочий стол, а не тот, на котором находится терминал (сломается, если пользователь изменит рабочий стол во время выполнения скрипта).

xprop -id $WINDOWID | sed -rn -e 's/_NET_WM_DESKTOP\(CARDINAL\) = ([^)]+)/\1/pg'

Я проверял это в цикле при смене рабочих столов, все работает нормально (тестовый скрипт ниже, вы должны проверить вывод вручную после запуска).

while true
do
  xprop -id $WINDOWID | sed -rn -e  's/_NET_WM_DESKTOP\(CARDINAL\) = ([^)]+)/\1/pg'
  sleep 1
done

Спасибо за другие ответы и комментарии, за то, что помог мне.

Я искал то же самое, но с еще одним ограничением, я не хочу запускать команду оболочки для достижения результата. Начиная с ответа Кимбалла Робинсона, это то, что я получил.

Протестировано в Python3.7, Debian 10.3, KDE Plasma 5.14.5.

import dbus 

bus = dbus.SessionBus()
proxy = bus.get_object("org.kde.KWin", "/KWin")
int( proxy.currentDesktop(dbus_interface="org.kde.KWin") )
Другие вопросы по тегам