C++ 检测系统托盘\任务栏方向(X11)
我创建了一个TrayPopupWidget,应该会在托盘附近弹出。 然后我意识到,如果用户更改任务栏的方向或高度,它将在错误的位置弹出。所以我创建了TaskbarDetector类 我试图获得任务栏的窗口几何图形,但我只得到了错误的窗口属性。。。 我试过KDE,LXDE->同样的坏行为 守则:C++ 检测系统托盘\任务栏方向(X11),c++,qt,x11,taskbar,tray,C++,Qt,X11,Taskbar,Tray,我创建了一个TrayPopupWidget,应该会在托盘附近弹出。 然后我意识到,如果用户更改任务栏的方向或高度,它将在错误的位置弹出。所以我创建了TaskbarDetector类 我试图获得任务栏的窗口几何图形,但我只得到了错误的窗口属性。。。 我试过KDE,LXDE->同样的坏行为 守则: //获取屏幕分辨率 整数大小; 旋转-原始旋转; Display*Display=XOpenDisplay(空); 窗口根=根窗口(显示,0); XRRScreenSize*xrrs=XRRSizes(
//获取屏幕分辨率
整数大小;
旋转-原始旋转;
Display*Display=XOpenDisplay(空);
窗口根=根窗口(显示,0);
XRRScreenSize*xrrs=XRRSizes(显示、0和数量大小);
XRRScreenConfiguration*conf=XRRGetScreenInfo(显示,根目录);
XRRConfigCurrentRate(配置);
SizeID原始大小id=XRRConfigCurrentConfiguration(配置和原始旋转);
p_screenWidth=xrrs[原始大小\u id]。宽度;
p_screenHeight=xrrs[原始尺寸\u id]。高度;
//获取托盘位置
无符号长系统选择=0;
Screen*Screen=xDefaultScreen显示(显示);
//修正我!!!
QString*net\u系统托盘=新的QString(“\u net\u系统托盘%i”);
(*净系统托盘)=净系统托盘->替换(“%i”,QString::number(XScreenNumber of screen(screen));
sysTraySelection=XInternAtom(显示,网络系统托盘->本地8bit(),False);
如果(sysTraySelection==无)
返回未知;
trayWindow=XGetSelectionOwner(显示、系统选择);
XWindowAttributes w_attr;
unsigned long status=XGetWindowAttributes(显示、trayWindow和w_属性);
如果(状态==0)
返回未知;
p_taskBarLeft=w_attr.y;
p_taskBarTop=w_attr.x;
p_taskBarBottom=w_attr.x+w_attr.height;
p_taskBarRight=w_属性y+w_属性宽度;
qDebug()系统托盘本身不一定是一个窗口。在KDE中,这只是任务栏中的一个区域(它与\u NET\u SYSTEM\u TRAY\u S%i
选择所有者无关)
您可能希望尝试嵌入一个托盘图标并获取其几何图形,然后显示您的小部件“near”所述图标(对于一些合理的“near”值)。一旦知道图标的几何图形,就可以删除它(但是如果用户移动托盘,就不会知道它的新坐标)
这不是100%可靠的,因为托盘没有义务显示您可以扔给它的所有图标。此外,由于图标闪烁,视觉效果不佳。但总比什么都没有好。最后,我找到了一种检测它的方法
我正在搜索一个具有dock属性且可见的窗口,然后对其调用XGetWindowAttributes(…)李>
如果我将筛选方法设置为QApplication::setEventFilter(),我可以获取每个XEvent、\u NET\u WORKAREA事件(此事件发生在调整任务栏大小或移动任务栏时),然后我重新调用任务栏/任务栏检测方法
然而,这在KDE4、GNOME和LXDE上有效,我计划允许用户自己设置弹出位置
bool TaskBarDetector::lookUpDockWindow ( unsigned long &rootWindow, bool check)
{
Display *display = QX11Info::display ();
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
if ( check && checkDockProperty(rootWindow) )
{
trayWindow = rootWindow;
return true;
}
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
qDebug() << "ERROR - Could not query the window tree. Aborting.";
trayWindow = 0;
return false;
}
if (noOfChildren == 0)
{
trayWindow = 0;
return false;
}
for (unsigned int ind = 0 ; ind < noOfChildren; ++ind )
{
if ( lookUpDockWindow ( children[ind] ,true) )
return true;
}
XFree ((char*) children);
trayWindow = 0;
return false;
}
bool TaskBarDetector::checkDockProperty(unsigned long window)
{
Display *x11display = QX11Info::display ();
Atom *atoms;
int numberAtoms = 0;
char *atomName;
XTextProperty prop;
XWindowAttributes windowattr;
atoms = XListProperties (x11display, window, &numberAtoms);
for (int ind = 0; ind < numberAtoms; ++ind )
{
atomName = XGetAtomName(x11display, atoms[ind]);
if (QString(atomName).compare ("_NET_WM_WINDOW_TYPE" ) != 0 )
continue;
unsigned long status = XGetTextProperty (x11display,window,&prop,atoms[ind]);
if ( status == 0 )
continue;
int value = (int) (*prop.value);
if (value != 151 )
continue;
if (XGetWindowAttributes(x11display,window,&windowattr) == 0)
continue;
return windowattr.map_state == 2;
}
return false;
}
void TaskBarDetector::saveWindowAttr(unsigned long root)
{
XWindowAttributes windowattr;
Display *x11display =QX11Info::display ();
if (XGetWindowAttributes(x11display,trayWindow,&windowattr) == 0)
{
trayWindow = 0;
return;
}
int x = 0;
int y = 0;
Window *w = &trayWindow;
if( XTranslateCoordinates(x11display,trayWindow,root,windowattr.x,windowattr.y,&x,&y,w) == True)
{
p_taskBarTop = y;
p_taskBarLeft = x;
p_taskBarRight = p_taskBarLeft + windowattr.width;
p_taskBarBottom = p_taskBarTop + windowattr.height;
p_taskBarHeight = windowattr.height;
p_taskBarWidth = windowattr.width;
} else
{
p_orientation = Unknown;
p_taskBarTop = 0;
p_taskBarLeft = 0;
p_taskBarRight = 0;
p_taskBarBottom = 0;
p_taskBarHeight = 0;
p_taskBarWidth = 0;
}
bool TaskBarDetector::appEventFilter(void *msg, long *result)
{
Q_UNUSED(result);
if ( !TaskBarDetector::hasInstance() )
return false;
TaskBarDetector *detector = TaskBarDetector::getInstance();
#ifdef Q_WS_WIN
MSG *seged = static_cast<MSG*>(msg);
if ( seged->message == WM_SETTINGCHANGE && seged->wParam == SPI_SETWORKAREA )
{
detector->processDetectEvent();
return false;
}
return false;
#endif
#ifdef Q_WS_X11
XEvent *xevent = static_cast<XEvent*> (msg);
if ( xevent->type == PropertyNotify )
{
XPropertyEvent xpe = xevent->xproperty;
char * ch_atom_name = XGetAtomName(QX11Info::display(),xpe.atom);
QString atom_name = QString(ch_atom_name).trimmed ();
if ( atom_name == "_NET_WORKAREA" )
{
detector->processDetectEvent ();
return false;
}
}
return false;
#endif
}
bool TaskBarDetector::lookUpDockWindow(无符号长和根窗口,bool检查)
{
Display*Display=QX11Info::Display();
窗口父对象;
窗口*儿童;
未签名的非整数儿童;
智力状态;
if(检查和检查dockProperty(rootWindow))
{
trayWindow=根窗口;
返回true;
}
状态=XQueryTree(显示、根窗口、根窗口、父级、子级和noOfChildren);
如果(状态==0)
{
qDebug()消息==WM\u设置更改和分段->wParam==SPI\u设置工作区)
{
检测器->过程检测事件();
返回false;
}
返回false;
#恩迪夫
#ifdef Q_WS_X11
XEvent*XEvent=static_cast(msg);
如果(xevent->type==PropertyNotify)
{
XPropertyEvent xpe=xevent->xproperty;
char*ch_atom_name=XGetAtomName(QX11Info::display(),xpe.atom);
QString atom_name=QString(ch_atom_name).trimmed();
if(原子名称=“\u网络\u工作区”)
{
检测器->处理检测器事件();
返回false;
}
}
返回false;
#恩迪夫
}
}1。使用xwininfo-tree-all命令,我可以得到我想要的东西,因此它必须是一个窗口。
2.我可以通过捕获x11属性更改事件来检测更改,并通过窗口识别它(但这部分代码没有发布在此处(链接),我有KDE,xwininfo-tree-all
完全没有提到系统托盘。
bool TaskBarDetector::lookUpDockWindow ( unsigned long &rootWindow, bool check)
{
Display *display = QX11Info::display ();
Window parent;
Window *children;
unsigned int noOfChildren;
int status;
if ( check && checkDockProperty(rootWindow) )
{
trayWindow = rootWindow;
return true;
}
status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
if (status == 0)
{
qDebug() << "ERROR - Could not query the window tree. Aborting.";
trayWindow = 0;
return false;
}
if (noOfChildren == 0)
{
trayWindow = 0;
return false;
}
for (unsigned int ind = 0 ; ind < noOfChildren; ++ind )
{
if ( lookUpDockWindow ( children[ind] ,true) )
return true;
}
XFree ((char*) children);
trayWindow = 0;
return false;
}
bool TaskBarDetector::checkDockProperty(unsigned long window)
{
Display *x11display = QX11Info::display ();
Atom *atoms;
int numberAtoms = 0;
char *atomName;
XTextProperty prop;
XWindowAttributes windowattr;
atoms = XListProperties (x11display, window, &numberAtoms);
for (int ind = 0; ind < numberAtoms; ++ind )
{
atomName = XGetAtomName(x11display, atoms[ind]);
if (QString(atomName).compare ("_NET_WM_WINDOW_TYPE" ) != 0 )
continue;
unsigned long status = XGetTextProperty (x11display,window,&prop,atoms[ind]);
if ( status == 0 )
continue;
int value = (int) (*prop.value);
if (value != 151 )
continue;
if (XGetWindowAttributes(x11display,window,&windowattr) == 0)
continue;
return windowattr.map_state == 2;
}
return false;
}
void TaskBarDetector::saveWindowAttr(unsigned long root)
{
XWindowAttributes windowattr;
Display *x11display =QX11Info::display ();
if (XGetWindowAttributes(x11display,trayWindow,&windowattr) == 0)
{
trayWindow = 0;
return;
}
int x = 0;
int y = 0;
Window *w = &trayWindow;
if( XTranslateCoordinates(x11display,trayWindow,root,windowattr.x,windowattr.y,&x,&y,w) == True)
{
p_taskBarTop = y;
p_taskBarLeft = x;
p_taskBarRight = p_taskBarLeft + windowattr.width;
p_taskBarBottom = p_taskBarTop + windowattr.height;
p_taskBarHeight = windowattr.height;
p_taskBarWidth = windowattr.width;
} else
{
p_orientation = Unknown;
p_taskBarTop = 0;
p_taskBarLeft = 0;
p_taskBarRight = 0;
p_taskBarBottom = 0;
p_taskBarHeight = 0;
p_taskBarWidth = 0;
}
bool TaskBarDetector::appEventFilter(void *msg, long *result)
{
Q_UNUSED(result);
if ( !TaskBarDetector::hasInstance() )
return false;
TaskBarDetector *detector = TaskBarDetector::getInstance();
#ifdef Q_WS_WIN
MSG *seged = static_cast<MSG*>(msg);
if ( seged->message == WM_SETTINGCHANGE && seged->wParam == SPI_SETWORKAREA )
{
detector->processDetectEvent();
return false;
}
return false;
#endif
#ifdef Q_WS_X11
XEvent *xevent = static_cast<XEvent*> (msg);
if ( xevent->type == PropertyNotify )
{
XPropertyEvent xpe = xevent->xproperty;
char * ch_atom_name = XGetAtomName(QX11Info::display(),xpe.atom);
QString atom_name = QString(ch_atom_name).trimmed ();
if ( atom_name == "_NET_WORKAREA" )
{
detector->processDetectEvent ();
return false;
}
}
return false;
#endif
}