在 X11 上激活窗口,为什么标题栏消失了?
使用以下代码,我在 X11 上激活一个窗口。
我使用 FindWindow 来获取窗口句柄,效果很好。 然后我想将指定的窗口置于前台。 为此,我使用 XRaiseWindow。
XRaiseWindow(display, wdThisWindow);
但是,XRaiseWindow 不适用于某些窗口(相当多,但不是全部)。 我认为这是因为他们的 override_redirect WindowAttribute 未设置为 true。 所以我使用 XChangeWindowAttributes 将此属性设置为 true。 现在,XRaiseWindow 将所有窗口置于顶部。 问题是,EyeOfGnome(图片查看器)和所有其他应用程序都失去了顶部标题栏......(你知道,右侧有关闭控件的那个......)。 更糟糕的是,窗口不再转到后台......
我想如果我在升起窗口后设置 override_redirect 属性,问题就会消失。 但... 现在,该问题已从所有应用程序(例如 gnome-terminal)中消失 - 除了 EyeOfGnome(图片查看器)之外的所有应用程序...
我是否遗漏了某些内容,或者这是 EyeOfGnome 问题,还是一般 GTK 问题?
这是代码中引起问题的部分:
XSetWindowAttributes xswa;
xswa.override_redirect = True;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XRaiseWindow(display, wdThisWindow);
xswa.override_redirect = False;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XSetInputFocus(display, wdThisWindow, RevertToNone, CurrentTime);
这是完整的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
// Info: xwininfo
// I am compiling using
// gcc -o activate activate.c -L/usr/X11R6/lib -lX11
// ERROR HANDLER, GENERIC
static int ErrorHandler (Display *display, XErrorEvent *error)
{
//printf ("\r\n error! \r\n");// gcc -o xwinspy lol.c -L/usr/X11R6/lib -lX11
return 0;
}
// END ERROR HANDLER
// Recursively search through all windows on display
Window SearchWindow(char* szWindowToFind, int level, Display *display, Window rootWindow, int iMatchMode, int showErrors)
{
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
int i;
Window wSearchedWindow = 0;
char* win_name;
if (XFetchName(display, rootWindow, &win_name))
{
//printf("WinName (Level %d): %s\n", level, win_name);
if(iMatchMode == 0)
{
if( strstr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 1)
{
if( !strcmp(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 2)
{
if( strcasestr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 3)
{
if( !strcasecmp(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else
{
if( strstr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
} // End if XFetchName
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
if (showErrors)
printf ("ERROR - Could not query the window tree. Aborting.\r\n");
return;
}
if (noOfChildren > 0)
{
for (i=0; i < noOfChildren; i++)
{
wSearchedWindow = SearchWindow(szWindowToFind, level+1, display, children[i], iMatchMode, showErrors);
if(wSearchedWindow)
{
break;
}
}
}
XFree ((char*) children);
return wSearchedWindow;
} // End Sub EnumerateWindows
Window FindWindow(char* szWindowToFind)
{
Display *display = XOpenDisplay (NULL);
int screen = DefaultScreen (display);
XSetErrorHandler(ErrorHandler);
Window rootWindow = RootWindow (display, screen);
Window wSearchedWindow = SearchWindow(szWindowToFind, 0, display, rootWindow, 0, 0);
char* win_name;
if (XFetchName(display, wSearchedWindow, &win_name))
{
printf("Found: %s\n", win_name);
}
XCloseDisplay (display);
return wSearchedWindow;
}
void ActivateWindow(char* szWindow)
{
Window wdThisWindow = FindWindow(szWindow);
Display *display = XOpenDisplay (NULL);
char* win_name;
if (XFetchName(display, wdThisWindow, &win_name))
{
printf("Activating: %s\n", win_name);
}
XSetErrorHandler(ErrorHandler);
XSetWindowAttributes xswa;
xswa.override_redirect = True;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XRaiseWindow(display, wdThisWindow);
xswa.override_redirect = False;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XSetInputFocus(display, wdThisWindow, RevertToNone, CurrentTime);
XCloseDisplay (display);
}
// ENUMARATE THROUGH WINDOWS AND DISPLAY THEIR TITLES
void EnumerateWindows(int level, Display *display, Window rootWindow, int showErrors)
{
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
int i;
char* win_name;
if (XFetchName(display, rootWindow, &win_name))
{
printf("Window-Name (Level %d): %s\n", level, win_name);
}
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
if (showErrors)
printf ("ERROR - Could not query the window tree. Aborting.\r\n");
return;
}
if (noOfChildren > 0)
{
for (i=0; i < noOfChildren; i++)
{
EnumerateWindows(level+1, display, children[i], showErrors);
}
}
XFree ((char*) children);
} // End Sub EnumerateWindows
void ListAllWindowsOnScreen()
{
Display *display = XOpenDisplay (NULL);
int screen = DefaultScreen (display);
XSetErrorHandler(ErrorHandler);
Window rootWindow = RootWindow (display, screen);
EnumerateWindows(0, display, rootWindow, 0);
XCloseDisplay (display);
}
int main(int argc, char *argv[])
{
ListAllWindowsOnScreen();
//ActivateWindow("000727");
return EXIT_SUCCESS;
}
Using the bellow code, I am activating a window on X11.
I'm using FindWindow to get the window handle, which works just fine.
Then I want to bring the specified window in the foreground.
To do this, I use XRaiseWindow.
XRaiseWindow(display, wdThisWindow);
However, XRaiseWindow doesn't work on some windows (quite many, but not all).
I figured this is because their override_redirect WindowAttribute is not set to true.
So I used XChangeWindowAttributes to set this property to true.
Now, XRaiseWindow brings all windows to the top.
The problem is, EyeOfGnome (picture viewer) and all other applications looses the top title bar... (you know, the one with the close control on the right...).
And what's even worse, the window doesn't go to the background anymore...
I figured if I set back the override_redirect property after I raised the window, the problem would be gone.
But...
The problem is now gone from all applications (such as gnome-terminal) - all except EyeOfGnome (Picture Viewer)...
Am I missing something, or is this an EyeOfGnome issue, or is it a general GTK issue ?
Here's the problem-causing part of the code:
XSetWindowAttributes xswa;
xswa.override_redirect = True;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XRaiseWindow(display, wdThisWindow);
xswa.override_redirect = False;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XSetInputFocus(display, wdThisWindow, RevertToNone, CurrentTime);
And this is the complete code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
// Info: xwininfo
// I am compiling using
// gcc -o activate activate.c -L/usr/X11R6/lib -lX11
// ERROR HANDLER, GENERIC
static int ErrorHandler (Display *display, XErrorEvent *error)
{
//printf ("\r\n error! \r\n");// gcc -o xwinspy lol.c -L/usr/X11R6/lib -lX11
return 0;
}
// END ERROR HANDLER
// Recursively search through all windows on display
Window SearchWindow(char* szWindowToFind, int level, Display *display, Window rootWindow, int iMatchMode, int showErrors)
{
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
int i;
Window wSearchedWindow = 0;
char* win_name;
if (XFetchName(display, rootWindow, &win_name))
{
//printf("WinName (Level %d): %s\n", level, win_name);
if(iMatchMode == 0)
{
if( strstr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 1)
{
if( !strcmp(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 2)
{
if( strcasestr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else if(iMatchMode == 3)
{
if( !strcasecmp(win_name, szWindowToFind) )
{
return rootWindow;
}
}
else
{
if( strstr(win_name, szWindowToFind) )
{
return rootWindow;
}
}
} // End if XFetchName
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
if (showErrors)
printf ("ERROR - Could not query the window tree. Aborting.\r\n");
return;
}
if (noOfChildren > 0)
{
for (i=0; i < noOfChildren; i++)
{
wSearchedWindow = SearchWindow(szWindowToFind, level+1, display, children[i], iMatchMode, showErrors);
if(wSearchedWindow)
{
break;
}
}
}
XFree ((char*) children);
return wSearchedWindow;
} // End Sub EnumerateWindows
Window FindWindow(char* szWindowToFind)
{
Display *display = XOpenDisplay (NULL);
int screen = DefaultScreen (display);
XSetErrorHandler(ErrorHandler);
Window rootWindow = RootWindow (display, screen);
Window wSearchedWindow = SearchWindow(szWindowToFind, 0, display, rootWindow, 0, 0);
char* win_name;
if (XFetchName(display, wSearchedWindow, &win_name))
{
printf("Found: %s\n", win_name);
}
XCloseDisplay (display);
return wSearchedWindow;
}
void ActivateWindow(char* szWindow)
{
Window wdThisWindow = FindWindow(szWindow);
Display *display = XOpenDisplay (NULL);
char* win_name;
if (XFetchName(display, wdThisWindow, &win_name))
{
printf("Activating: %s\n", win_name);
}
XSetErrorHandler(ErrorHandler);
XSetWindowAttributes xswa;
xswa.override_redirect = True;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XRaiseWindow(display, wdThisWindow);
xswa.override_redirect = False;
XChangeWindowAttributes(display, wdThisWindow, CWOverrideRedirect, &xswa);
XSetInputFocus(display, wdThisWindow, RevertToNone, CurrentTime);
XCloseDisplay (display);
}
// ENUMARATE THROUGH WINDOWS AND DISPLAY THEIR TITLES
void EnumerateWindows(int level, Display *display, Window rootWindow, int showErrors)
{
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
int i;
char* win_name;
if (XFetchName(display, rootWindow, &win_name))
{
printf("Window-Name (Level %d): %s\n", level, win_name);
}
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
if (showErrors)
printf ("ERROR - Could not query the window tree. Aborting.\r\n");
return;
}
if (noOfChildren > 0)
{
for (i=0; i < noOfChildren; i++)
{
EnumerateWindows(level+1, display, children[i], showErrors);
}
}
XFree ((char*) children);
} // End Sub EnumerateWindows
void ListAllWindowsOnScreen()
{
Display *display = XOpenDisplay (NULL);
int screen = DefaultScreen (display);
XSetErrorHandler(ErrorHandler);
Window rootWindow = RootWindow (display, screen);
EnumerateWindows(0, display, rootWindow, 0);
XCloseDisplay (display);
}
int main(int argc, char *argv[])
{
ListAllWindowsOnScreen();
//ActivateWindow("000727");
return EXIT_SUCCESS;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如 ninjalj 提到的,您要做的是使用 EWMH 规范中的协议,而不是发出这些原始 X 协议请求。你在这里所做的事情会让 GTK+ 和窗口管理器都感到困惑。
具体来说,您在这里要做的是发送一条 _NET_ACTIVE_WINDOW 客户端消息,其中包含
源指示(http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html#sourceinspiration)可能设置为说您是寻呼机。
顺便说一句,有一个名为 libwnck 的库(我最初编写的,但现在由其他人维护),它可以为您完成所有这些工作。即使您不使用它,您也可以查看它的源代码来了解如何做一些事情。
What you have to do, as ninjalj mentions, is use the protocols in the EWMH specification rather than making these raw X protocol requests. What you're doing here will confuse the heck out of both GTK+ and the window manager.
Specifically, what you want to do here is send a _NET_ACTIVE_WINDOW client message, with the
source indication (http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html#sourceindication) probably set to say you're a pager.
Incidentally there's a library called libwnck (which I wrote originally but other people now maintain) which will do all this for you. Even if you don't use it, you can look at its source code to learn how to do stuff.
OverrideRedirect
适用于绕过窗口管理器的窗口。请求堆叠顺序更改的协议在 ICCCM 第 4.1.5 节中描述。 EWMH 规范 包括对此协议的一些扩展,例如分层堆叠顺序和窗口激活(给予焦点并可能提升窗口)。OverrideRedirect
is for windows that bypass the window manager. The protocol for requesting stacking order changes is described in the ICCCM, section 4.1.5. The EWMH spec includes some extensions to this protocol, like layered stacking order and window activation (giving focus and possibly raising the window).