Определить ориентацию системного лотка\панели задач (X11)

StackOverflow https://stackoverflow.com//questions/10658463

  •  11-12-2019
  •  | 
  •  

Вопрос

Я создал TrayPopupWidget, который должен появиться рядом с лотком.Затем я понял, что если пользователь изменит ориентацию или высоту панели задач, она появится не в том месте.Итак, я создал класс TaskbarDetector.

Я пытался получить геометрию окна трея|панели задач, но получаю только неправильное свойство окна...Я пробовал KDE, LXDE -> такое же плохое поведение...

Код:http://bzfriendsplasm.svn.sourceforge.net/viewvc/bzfriendsplasm/BZFriends/taskbardetector.cpp?revision=156&view=markup

   //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 ();
Это было полезно?

Решение

Наконец, я нашел способ обнаружить его!

  1. Я ищу окно, у которого есть свойство дока и видимым, а потом я звоню xgetwindoWattributes (...) на нем.
  2. Если я установлю метод фильтра к 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% надежно, поскольку трей никоим образом не обязан отображать все значки, которые вы можете на него кинуть.Кроме того, это некрасиво из-за мерцания значков.Но это лучше, чем ничего.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top