首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Ubuntu/GNOME上使用PyQt在桌面图标后面放置一个窗口

在Ubuntu/GNOME上使用PyQt在桌面图标后面放置一个窗口
EN

Stack Overflow用户
提问于 2022-02-23 17:15:00
回答 1查看 418关注 0票数 2

我正在尝试开发一个简单的跨平台壁纸管理器,但我无法找到任何方法将我的PyQt窗口放在当前的壁纸和桌面图标之间,使用XLib (在windows和macOS上--它更简单、工作更完美)。

这对肉桂有效(只需模拟一下点击),而不适用于GNOME。有人能帮我或者给我点线索吗?(我提供所有这些代码只是为了提供一个最小的可执行部分,但关键部分,我想,就在'if‘GNOME’之后.‘(判刑)

代码语言:javascript
复制
import os
import time

import Xlib
import ewmh
import pywinctl
from pynput import mouse

DISP = Xlib.display.Display()
SCREEN = DISP.screen()
ROOT = DISP.screen().root
EWMH = ewmh.EWMH(_display=DISP, root=ROOT)


def sendBehind(hWnd):

        w = DISP.create_resource_object('window', hWnd)
        w.change_property(DISP.intern_atom('_NET_WM_STATE', False), Xlib.Xatom.ATOM, 32, [DISP.intern_atom('_NET_WM_STATE_BELOW', False), ], Xlib.X.PropModeReplace)
        w.change_property(DISP.intern_atom('_NET_WM_STATE', False), Xlib.Xatom.ATOM, 32, [DISP.intern_atom('_NET_WM_STATE_SKIP_TASKBAR', False), ], Xlib.X.PropModeAppend)
        w.change_property(DISP.intern_atom('_NET_WM_STATE', False), Xlib.Xatom.ATOM, 32, [DISP.intern_atom('_NET_WM_STATE_SKIP_PAGER', False), ], Xlib.X.PropModeAppend)
        DISP.flush()

        # This sends window below all others, but not behind the desktop icons
        w.change_property(DISP.intern_atom('_NET_WM_WINDOW_TYPE', False), Xlib.Xatom.ATOM, 32, [DISP.intern_atom('_NET_WM_WINDOW_TYPE_DESKTOP', False), ],Xlib.X.PropModeReplace)
        DISP.flush()

        if "GNOME" in os.environ.get('XDG_CURRENT_DESKTOP', ""):
            # This sends the window "too far behind" (below all others, including Wallpaper, like unmapped)
            # Trying to figure out how to raise it on top of wallpaper but behind desktop icons
            desktop = _xlibGetAllWindows(title="gnome-shell")
            if desktop:
                w.reparent(desktop[-1], 0, 0)
                DISP.flush()
        else:
            # Mint/Cinnamon: just clicking on the desktop, it raises, sending the window/wallpaper to the bottom!
            m = mouse.Controller()
            m.move(SCREEN.width_in_pixels - 1, 100)
            m.click(mouse.Button.left, 1)

        return '_NET_WM_WINDOW_TYPE_DESKTOP' in EWMH.getWmWindowType(hWnd, str=True)


def bringBack(hWnd, parent):
    w = DISP.create_resource_object('window', hWnd)

    if parent:
        w.reparent(parent, 0, 0)
        DISP.flush()

    w.unmap()
    w.change_property(DISP.intern_atom('_NET_WM_WINDOW_TYPE', False), Xlib.Xatom.ATOM,
                      32, [DISP.intern_atom('_NET_WM_WINDOW_TYPE_NORMAL', False), ],
                      Xlib.X.PropModeReplace)
    DISP.flush()
    w.change_property(DISP.intern_atom('_NET_WM_STATE', False), Xlib.Xatom.ATOM,
                      32, [DISP.intern_atom('_NET_WM_STATE_FOCUSED', False), ],
                      Xlib.X.PropModeReplace)
    DISP.flush()
    w.map()
    EWMH.setActiveWindow(hWnd)
    EWMH.display.flush()
    return '_NET_WM_WINDOW_TYPE_NORMAL' in EWMH.getWmWindowType(hWnd, str=True)


def _xlibGetAllWindows(parent: int = None, title: str = ""):

    if not parent:
        parent = ROOT
    allWindows = [parent]

    def findit(hwnd):
        query = hwnd.query_tree()
        for child in query.children:
            allWindows.append(child)
            findit(child)

    findit(parent)
    if not title:
        matches = allWindows
    else:
        matches = []
        for w in allWindows:
            if w.get_wm_name() == title:
                matches.append(w)
    return matches


hWnd = pywinctl.getActiveWindow()
parent = hWnd._hWnd.query_tree().parent
sendBehind(hWnd._hWnd)
time.sleep(3)
bringBack(hWnd._hWnd, parent)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-12-02 22:27:47

尤里卡!上一个Ubuntu版本(22.04)似乎是自己带来了解决方案。它现在有一个“层”的桌面图标,你可以与之互动。这也给了我一条线索,可以在薄荷/肉桂上找到更聪明的解决方案(其他操作系统上的测试仍在等待中)。对于那些有同样问题的人来说,这段代码似乎是正常的:

代码语言:javascript
复制
import time

import Xlib.display
import ewmh
import pywinctl

DISP = Xlib.display.Display()
SCREEN = DISP.screen()
ROOT = DISP.screen().root
EWMH = ewmh.EWMH(_display=DISP, root=ROOT)


def sendBehind(hWnd):
    w = DISP.create_resource_object('window', hWnd.id)
    w.unmap()
    w.change_property(DISP.intern_atom('_NET_WM_WINDOW_TYPE', False), Xlib.Xatom.ATOM,
                      32, [DISP.intern_atom('_NET_WM_WINDOW_TYPE_DESKTOP', False), ],
                      Xlib.X.PropModeReplace)
    DISP.flush()
    w.map()

    # This will try to raise the desktop icons layer on top of the window
    # Ubuntu: "@!0,0;BDHF" is the new desktop icons NG extension
    # Mint: "Desktop" name is language-dependent. Using its class (nemo-desktop)
    desktop = _xlibGetAllWindows(title="@!0,0;BDHF", klass=('nemo-desktop', 'Nemo-desktop'))
    for d in desktop:
        w = DISP.create_resource_object('window', d)
        w.raise_window()

    return '_NET_WM_WINDOW_TYPE_DESKTOP' in EWMH.getWmWindowType(hWnd, str=True)


def bringBack(hWnd):

    w = DISP.create_resource_object('window', hWnd.id)

    w.unmap()
    w.change_property(DISP.intern_atom('_NET_WM_WINDOW_TYPE', False), Xlib.Xatom.ATOM,
                      32, [DISP.intern_atom('_NET_WM_WINDOW_TYPE_NORMAL', False), ],
                      Xlib.X.PropModeReplace)
    DISP.flush()
    w.change_property(DISP.intern_atom('_NET_WM_STATE', False), Xlib.Xatom.ATOM,
                      32, [DISP.intern_atom('_NET_WM_STATE_FOCUSED', False), ],
                      Xlib.X.PropModeReplace)
    DISP.flush()
    w.map()
    EWMH.setActiveWindow(hWnd)
    EWMH.display.flush()
    return '_NET_WM_WINDOW_TYPE_NORMAL' in EWMH.getWmWindowType(hWnd, str=True)


def _xlibGetAllWindows(parent=None, title: str = "", klass=None):

    parent = parent or ROOT
    allWindows = [parent]

    def findit(hwnd):
        query = hwnd.query_tree()
        for child in query.children:
            allWindows.append(child)
            findit(child)

    findit(parent)
    if not title and not klass:
        return allWindows
    else:
        return [window for window in allWindows if ((title and window.get_wm_name() == title) or
                                                    (klass and window.get_wm_class() == klass))]


hWnd = pywinctl.getActiveWindow()
sendBehind(hWnd._hWnd)
time.sleep(3)
bringBack(hWnd._hWnd)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71241339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档