本文介绍了C,Xlib中的freedesktop XEmbed systray客户端代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用C和Xlib来实现systray图标,以及freedesktop规范[0].我似乎无法将Window嵌入到桌面管理器的systray [1]中,而其他应用程序似乎可以做到这一点.我不确定如何进行调试,但是下面提供了最少的示例代码.

I've been trying to implement a systray icon using straight C and Xlib, going along with the freedesktop specification [0]. I can't seem to get my Window to embed into my desktop manager's systray[1], while other apps seem to be able to do it. I am not sure how to go forward debugging this, but I've provided minimal sample code below.

我无法使用直接的Xlib和C查找任何示例代码,而我所看到的所有建议都是关于某些框架(例如Gtk/Qt/Mono/任何东西)的,但是我想了解什么应该按照规范在这里发生,而我做错了.

I haven't been able to find any sample code using straight Xlib and C, and all the suggestions I've seen have been with regard to some framework like Gtk/Qt/Mono/whatever, but I want to understand what is supposed to be happening here as per the spec, and what I'm doing wrong.

#include <X11/Xutil.h>
#include <string.h>

#define MIN(A, B)               ((A) < (B) ? (A) : (B))

/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK   0
#define SYSTEM_TRAY_BEGIN_MESSAGE   1
#define SYSTEM_TRAY_CANCEL_MESSAGE  2

static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);

static int
error_handler(Display     *display, XErrorEvent *error) {
    trapped_error_code = error->error_code;
    return 0;
}

void
trap_errors(void) {
    trapped_error_code = 0;
    old_error_handler = XSetErrorHandler(error_handler);
}

int
untrap_errors(void) {
    XSetErrorHandler(old_error_handler);
    return trapped_error_code;
}

void
send_systray_message(Display* dpy, Window w, long message, long data1, long data2, long data3) {
    XEvent ev;

    memset(&ev, 0, sizeof(ev));
    ev.xclient.type = ClientMessage;
    ev.xclient.window = w;
    ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
    ev.xclient.format = 32;
    ev.xclient.data.l[0] = CurrentTime;
    ev.xclient.data.l[1] = message;
    ev.xclient.data.l[2] = data1;
    ev.xclient.data.l[3] = data2;
    ev.xclient.data.l[4] = data3;

    trap_errors();
    XSendEvent(dpy, w, False, NoEventMask, &ev);
    XSync(dpy, False);
    if (untrap_errors()) {
        /* Handle errors */
    }
}

/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
    int width, height;
    XWindowAttributes wa;
    XEvent ev;
    Display *dpy;
    int screen;
    Window root, win;

    /* init */
    if (!(dpy=XOpenDisplay(NULL)))
        return 1;
    screen = DefaultScreen(dpy);
    root = RootWindow(dpy, screen);
    if(!XGetWindowAttributes(dpy, root, &wa))
        return 1;
    width = height = MIN(wa.width, wa.height);

    /* create window */
    win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0xFFFF9900);

    send_systray_message(dpy, win, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0);
    XMapWindow(dpy, win);

    XSync(dpy, False);

    /* run */
    while(1) {
        while(XPending(dpy)) {
            XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
        }
    }
}

任何帮助将不胜感激.我认为这个问题与语言无关,与我对协议的误解更多有关,因此可以接受任何语言的答案,只要它们可以帮助我解决XEvent问题.

Any help would be greatly appreciated. I think this problem is language-agnostic, and more to do with me misunderstanding the protocols, so answers in any language are acceptable, as long as they help me iron out this XEvent stuff.

[0] https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html

[1]我正在将dwm与systray修补程序配合使用 http://dwm.suckless.org/patches/systray

[1] I'm using dwm with the systray patch http://dwm.suckless.org/patches/systray

推荐答案

您正在将消息发送到错误的窗口.该文档并没有真正帮助,将托盘嵌入消息发送到您自己的窗口毫无意义!您需要将其发送到任务栏窗口.

You are sending the message to a wrong window. The documentation isn't really helpful, it makes no sense whatsoever to send a tray embed message to your own window!. You need to send it to the tray window.

这是固定的send_systray_message

void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
    XEvent ev;

    Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
    Window tray = XGetSelectionOwner (dpy,selection_atom);

    if ( tray != None)
        XSelectInput (dpy,tray,StructureNotifyMask);

    memset(&ev, 0, sizeof(ev));
    ev.xclient.type = ClientMessage;
    ev.xclient.window = tray;
    ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
    ev.xclient.format = 32;
    ev.xclient.data.l[0] = CurrentTime;
    ev.xclient.data.l[1] = message;
    ev.xclient.data.l[2] = data1; // <--- your window is only here
    ev.xclient.data.l[3] = data2;
    ev.xclient.data.l[4] = data3;

    trap_errors();
    XSendEvent(dpy, tray, False, NoEventMask, &ev);
    XSync(dpy, False);
    usleep(10000);
    if (untrap_errors()) {
        /* Handle errors */
    }
}

并对其进行呼叫

send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once

信用: http ://distro.ibiblio.org/vectorlinux/Uelsk8s/GAMBAS/gambas-svn/gambas2/gb.gtk/src/gtrayicon.cpp

这篇关于C,Xlib中的freedesktop XEmbed systray客户端代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 12:17