Определить ориентацию системного лотка\панели задач (X11)
Вопрос
Я создал TrayPopupWidget, который должен появиться рядом с лотком.Затем я понял, что если пользователь изменит ориентацию или высоту панели задач, она появится не в том месте.Итак, я создал класс TaskbarDetector.
Я пытался получить геометрию окна трея|панели задач, но получаю только неправильное свойство окна...Я пробовал KDE, LXDE -> такое же плохое поведение...
//Getting screen resolutoin
int num_sizes;
Rotation original_rotation;
Display *display = XOpenDisplay(NULL);
Window root = RootWindow(display, 0);
XRRScreenSize *xrrs = XRRSizes(display, 0, &num_sizes);
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, root);
XRRConfigCurrentRate(conf);
SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation);
p_screenWidth = xrrs[original_size_id].width;
p_screenHeight = xrrs[original_size_id].height;
//Getting tray position
unsigned long sysTraySelection = 0;
Screen *screen = XDefaultScreenOfDisplay(display);
//FIXME !!!
QString *net_sys_tray = new QString("_NET_SYSTEM_TRAY_S%i");
(*net_sys_tray) = net_sys_tray->replace ("%i",QString::number (XScreenNumberOfScreen(screen)));
sysTraySelection = XInternAtom(display, net_sys_tray->toLocal8Bit (), False);
if ( sysTraySelection == None)
return Unknown;
trayWindow = XGetSelectionOwner(display, sysTraySelection);
XWindowAttributes w_attr;
unsigned long status = XGetWindowAttributes (display,trayWindow,&w_attr);
if ( status == 0)
return Unknown;
p_taskBarLeft = w_attr.y;
p_taskBarTop = w_attr.x;
p_taskBarBottom = w_attr.x + w_attr.height;
p_taskBarRight = w_attr.y + w_attr.width;
qDebug () << QString("Window id: " ) + QString::number (trayWindow);
qDebug() << QString("SysTraySelection: ") + QString::number (sysTraySelection );
qDebug() << QString("Top ") + QString::number (p_taskBarTop);
qDebug() << QString("Left ") + QString::number (p_taskBarLeft);
qDebug() << QString("Bottom ") + QString::number (p_taskBarBottom);
qDebug() << QString("Right " ) + QString::number (p_taskBarRight);
XCloseDisplay(display);
delete net_sys_tray;
return decideOrientation ();
Решение
Наконец, я нашел способ обнаружить его!
- Я ищу окно, у которого есть свойство дока и видимым, а потом я звоню xgetwindoWattributes (...) на нем.
- Если я установлю метод фильтра к qapplication :: seteventfilter (), я могу получить каждое событие Xevent, _net_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 }
}
Другие советы
Панель задач не обязательно является окном сама по себе.В KDE это просто область на панели задач (и она не связана с _NET_SYSTEM_TRAY_S%i
владелец выбора).
Вы можете попробовать встроить значок в трее и получить его геометрию, а затем отобразить виджет «рядом» с указанным значком (при некотором разумном значении «рядом»).Вы можете удалить значок, как только узнаете его геометрию (но тогда, если пользователь переместит лоток, вы не узнаете его новые координаты).
Это не на 100% надежно, поскольку трей никоим образом не обязан отображать все значки, которые вы можете на него кинуть.Кроме того, это некрасиво из-за мерцания значков.Но это лучше, чем ничего.