LINUX.ORG.RU

XGetInputFocus возвращает неверное значение


1

1

Всем привет. У меня есть вот такой кусок кода:

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main ()
{
	char **name;
	Display *dsp = XOpenDisplay(NULL);
	Window wnd;
	XTextProperty text;
	int param;
	XGetInputFocus(dsp,&wnd,&param);
	XGetWMName(dsp,wnd-1,&text);
	Xutf8TextPropertyToTextList(dsp,&text,&name,&param);
	printf("%s\n",*name);
	return 0;
}

И он работает верно, но! Но почему-то XGetInputFocus всегда возвращает ID активного окна, но на 1 больше, чем реальный ID. Поэтому потом приходится делать в XGetWMName wnd-1. Попахивает плохим кодом.

p.s. Можно ли использовать XGetInputFocus для поиска активного окна? Некоторые делают через атомы, но это сильно увеличивает код. В чем минусы данного решения?


Ничего странного. Ты, я так понимаю, хочешь получить id у toplevel window приложения, а XGetInputFocus наверняка тебе возвращает id subwindow этого toplevel, который этот фокус имеет. Я вплотную с фокусом не знаком (то есть программ на эту тему не писал), но кое-что припоминаю — в цикле получать parent и смотреть, когда он станет == root. Как только стал, то предпоследнее окно и было top level window.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Честно говоря, не понял, где у меня subwindow в том же xfce-терминале. Например, ID моего окна с терминалом 0x1a00004, а XGetInputFocus возвращает мне 0x1a00005, но такого окна нет даже в _NET_CLIENT_LIST. xprop -id возвращает мне примерно вот такое:

TOM fork # xprop -id 0x1a00005
_NET_WM_USER_TIME(CARDINAL) = 17660215

Если можно без цикла(вроде этот код работает нормально), то смысл мне цикл делать?

fillo
() автор топика
Ответ на: комментарий от fillo

В xfce-терминале subwindow может быть само изображение терминала. Короче, делай XQueryTree после своего XGetInputFocus, получишь родителя и детей. Полагаю, что родителем и будет искомое тобой окно. В твой код это добавить очень быстро можно, чтобы посмотреть.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Интересно то, что окно с ID на один выше, содержат все окна. Открывал и плееры, и браузеры, и всякие виджеты. Причем имеет оно только один атом - время пребывания в этом окне.

В общем, ушел ставить еще какой-нибудь DE/WM, чтоб там посмотреть. Я уже видел пример с ним здесь же на ЛОРе, человек делал так:

assert (XQueryTree (dpy, root, &rw, &pw, &cw, &nchildren));
  for (i = 0; i < nchildren; i++)
  {
    assert (XGetWindowAttributes (dpy, cw[i], &wa));
    if (wa.map_state == IsViewable)
    {
      /* сохраню номер видимого окна в общем списке окон */
      w_indexes[nwindows++] = i;
    }
  }

И это у меня работает.

Полагаю, что мне нужно будет делать как-то так. Есть подобный вариант с XInternAtom, но суть та же. И он тоже у меня работает. Но с GetInputFocus самый короткий вариант, это привлекает.

fillo
() автор топика
Ответ на: комментарий от fillo

>И это у меня работает.

А это путь, как ты понимаешь, с другой стороны. Попросили у root всех его детей, пробегают по ним.

По теме рассказывает вкратце Owen Taylor. Он-то знает, что к чему. И говорит то, о чем я тебе выше написал.

http://mail.gnome.org/archives/gtk-list/2004-July/msg00290.html

Zubok ★★★★★
()
Ответ на: комментарий от fillo

Да, я думаю, что и поднимание наверх до root тоже может промашечку дать. Он может дать id декорации, наверное. Для того, чтобы знать наверняка, надо иметь опыт написания оконных менеджеров. Увы, у меня его нет (пока что). Но если действительно так будет, то придется еще эвристику применять, то есть искать окно, у которого есть WM_NAME, WM_CLASS и т. д. Как-то так.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Насколько я понял из ссылки, это фишка GTK. Оно отдает ID непосредственного потомка у toplevel-окна. Проверил с QT-приложением - там нормально.

По поводу XQueryTree: я не понимаю вашего метода, делать XQueryTree после XGetInputFocus.

fillo
() автор топика
Ответ на: комментарий от fillo

>По поводу XQueryTree: я не понимаю вашего метода, делать XQueryTree после XGetInputFocus.

А что непонятного? После XQueryTree ты получаешь родителя окна, которое тебе вернуло XGetInputFocus. У тебя фокус возвращает не toplevel, а его потомок. Смотри, и Растерман тебе пишет, и Owen Taylor пишет. Ну почитай же.

Zubok ★★★★★
()
Ответ на: комментарий от fillo

>Насколько я понял из ссылки, это фишка GTK. Оно отдает ID непосредственного потомка у toplevel-окна. Проверил с QT-приложением - там нормально.

Значит твоя процедура поиска toplevel сразу же завершится. Еще раз. Ситуация, когда XGetInputFocus возвращает не toplevel окно — штатная. Она может возратить его, а может не возвратить.

Zubok ★★★★★
()
Ответ на: комментарий от fillo

>По поводу XQueryTree: я не понимаю вашего метода, делать XQueryTree после XGetInputFocus.

Вотпоискал и нашел тут иллюстрацию в функции get_top_window

http://www.cs.cmu.edu/afs/cs/project/lri/members/lalit/Phd/software/simkit/gr...

Но я выше написал. что метод может быть несколько наивным. Вполне возможно, что тебе придется этим же методом, но только искать окно по наличию WM_* и других признаков toplevel окон.

Zubok ★★★★★
()
Ответ на: комментарий от fillo

>А что с _NET_ACTIVE_WINDOW

Все просто. Есть спецификация NETWM (она же EWMH), которую WM может реализовывать полностью, а может не полностью. http://en.wikipedia.org/wiki/Extended_Window_Manager_Hints. Список может быть неполным и ошибочным. Например, IceWM поддерживает NETWM, но я обнаружил, что некоторые вещи не реализованы. Тоже самое может быть с DWM (не пользуюсь, не знаю). Wikipedia пишет такое: echinus extends dwm with FreeType support, EWMH, click-to-focus, reconfigurability, and more layout types. Тут http://en.wikipedia.org/wiki/Dwm. То есть можно предположить, что этот DWM поддерживает EWMH как минимум не полностью.

Zubok ★★★★★
()
Ответ на: комментарий от fillo

>Аннет, ошибся. Не все приложения его возвращают. Похоже, вы правы. Спасибо. :)

Я бы так сделал. Я бы получил окно с фокусом и начал бы поиск вверх, проверяя WM_STATE (это будет признаком, что окно управляется оконным менеджером), а также в качестве запасного варианта также WM_NAME, WM_CLASS и т .д. Ищем самое последнее окно, которое имеет хотя бы один из этих признаков. Если такое не найдено (что весьма редкий случай), то возвратить окно-родитель, которое имеет родителя RootWindow.

Zubok ★★★★★
()
Ответ на: комментарий от fillo

>А что с _NET_ACTIVE_WINDOW? Слышал, что не работает это в DWM.

Это можно проверять для начала. Но если значения нет (то есть, предположим, WM не поддерживает), то фоллбэк на запасные варианты выше. Я думаю, что как-то так.

Zubok ★★★★★
()

Подведу итог всему вышесказанному. Вот такой код получился. На WM_NAME/WM_CLASS решил не проверять, т.к. в моем случае программа всегда будет запускаться в каком-либо WM.

char *
GetActiveWindowName ()
{
    Display *display	= XOpenDisplay(NULL);
    Window root 	= DefaultRootWindow(display);
    Atom active 	= XInternAtom(display, "_NET_ACTIVE_WINDOW", False);

    XTextProperty text;
    char **name = NULL;
    int param;

    Atom type_ret;
    int format_ret;
    unsigned long items_ret;
    unsigned long after_ret;
    unsigned char *prop_data = 0;

    if(XGetWindowProperty(display, root, active, 0, 0x7fffffff, False, XA_WINDOW,
	&type_ret, &format_ret, &items_ret, &after_ret, &prop_data) == Success)
    {
	Window *active_window = (void*)prop_data;
	if(XGetWMName(display, *active_window, &text) != 0) {
	    Xutf8TextPropertyToTextList(display, &text, &name, &param);
	    return *name;
	} else {
	    return NULL;
	}
    } else {
	Window wnd, parent, *children;
	Atom wm_state = XInternAtom(display, "WM_STATE", False);

	int nchildren;

	XGetInputFocus(display, &wnd, &param);

	for(;;) {
	    XQueryTree(display, wnd, &root, &parent, &children, &nchildren);
	    XFree(children);
	    XGetTextProperty(display, parent, &text, wm_state);
	    if(text.value == NULL) {
		break;
	    }
	    wnd = parent;
	}

	if(XGetWMName(display, wnd, &text) != 0) {
	    Xutf8TextPropertyToTextList(display, &text, &name, &param);
	    return *name;
	} else {
	    return NULL;
	}
    }
}
fillo
() автор топика
Ответ на: комментарий от fillo

Упс, эти return NULL'ы лучше убрать. Под утро совсем ничего не соображается.

fillo
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.