Esempio n. 1
0
def setup():
    """Setup the system tray.

    Initializes tray support by requesting the appropriate _NET_SYSTEM_TRAY
    atom for the X11 display we are running on, then acquiring the selection
    for this atom. Afterwards, tray clients will send ClientMessages to our
    window.
    """

    # We need a window to own the selection
    global selection_window
    selection_window = pwm.windows.create(
        -1, -1, 1, 1, xcb.mask((xcb.CW_OVERRIDE_REDIRECT, 1)))
    xcb.core.map_window(selection_window)

    # Get the selection
    global tray_atom
    tray_atom = pwm.atom.get("_NET_SYSTEM_TRAY_S{}".format(
        xcb.screen_number))
    xcb.core.set_selection_owner(selection_window, tray_atom, xcb.CURRENT_TIME)

    # Inform clients waiting for a new _NET_SYSTEM_TRAY that we took the
    # selection.
    event = pwm.windows.create_client_message(
        xcb.screen.root,
        pwm.atom.get("MANAGER"),
        xcb.CURRENT_TIME,
        tray_atom,
        selection_window)

    xcb.core.send_event(False, xcb.screen.root, 0xffffff, event)
Esempio n. 2
0
File: bar.py Progetto: linuscl/pwm
    def create_window(self):
        mask = [(xcb.CW_OVERRIDE_REDIRECT, 1),
                (xcb.CW_BACK_PIXEL, color.get_pixel(config.bar.background)),
                (xcb.CW_EVENT_MASK, xcb.EVENT_MASK_EXPOSURE)]

        return pwm.windows.create(self.x, self.y, self.width, self.height,
                                  xcb.mask(mask))
Esempio n. 3
0
def setup():
    """Setup the system tray.

    Initializes tray support by requesting the appropriate _NET_SYSTEM_TRAY
    atom for the X11 display we are running on, then acquiring the selection
    for this atom. Afterwards, tray clients will send ClientMessages to our
    window.
    """

    # We need a window to own the selection
    global selection_window
    selection_window = pwm.windows.create(
        -1, -1, 1, 1, xcb.mask((xcb.CW_OVERRIDE_REDIRECT, 1)))
    xcb.core.map_window(selection_window)

    # Get the selection
    global tray_atom
    tray_atom = pwm.atom.get("_NET_SYSTEM_TRAY_S{}".format(xcb.screen_number))
    xcb.core.set_selection_owner(selection_window, tray_atom, xcb.CURRENT_TIME)

    # Inform clients waiting for a new _NET_SYSTEM_TRAY that we took the
    # selection.
    event = pwm.windows.create_client_message(xcb.screen.root,
                                              pwm.atom.get("MANAGER"),
                                              xcb.CURRENT_TIME, tray_atom,
                                              selection_window)

    xcb.core.send_event(False, xcb.screen.root, 0xffffff, event)
Esempio n. 4
0
def setup():
    global _width
    _width = xcb.screen.width_in_pixels

    global _height
    _height = pwm.bar.calculate_height()

    global _window
    mask = [(xcb.CW_OVERRIDE_REDIRECT, 1),
            (xcb.CW_BACK_PIXEL, pwm.color.get_pixel(config.bar.background)),
            (xcb.CW_EVENT_MASK, xcb.EVENT_MASK_EXPOSURE)]
    _window = pwm.windows.create(pwm.bar.primary.x, pwm.bar.primary.y,
                                 _width, _height, xcb.mask(mask))

    global _pixmap
    _pixmap = xcb.core.generate_id()
    xcb.core.create_pixmap(
        xcb.screen.root_depth,
        _pixmap,
        _window,
        _width,
        _height)

    global _gc
    _gc = xcb.core.generate_id()
    xcb.core.create_gc(_gc, xcb.screen.root,
                       *xcb.mask([(xcb.GC_FOREGROUND, xcb.screen.white_pixel),
                                  (xcb.GC_BACKGROUND, xcb.screen.black_pixel),
                                  (xcb.GC_GRAPHICS_EXPOSURES, 0)]))

    global _surface
    _surface = cairo.xcb_surface_create(
        xcb.conn,
        _pixmap,
        xcb.aux_find_visual_by_id(xcb.screen, xcb.screen.root_visual),
        _width,
        _height)

    global _ctx
    _ctx = cairo.create(_surface)

    _ctx.select_font_face(config.bar.font.face,
                          cairo.FONT_SLANT_NORMAL,
                          cairo.FONT_WEIGHT_NORMAL)
    _ctx.set_font_size(config.bar.font.size)
Esempio n. 5
0
File: menu.py Progetto: linuscl/pwm
def setup():
    global _width
    _width = xcb.screen.width_in_pixels

    global _height
    _height = pwm.bar.calculate_height()

    global _window
    mask = [(xcb.CW_OVERRIDE_REDIRECT, 1),
            (xcb.CW_BACK_PIXEL, pwm.color.get_pixel(config.bar.background)),
            (xcb.CW_EVENT_MASK, xcb.EVENT_MASK_EXPOSURE)]
    _window = pwm.windows.create(pwm.bar.primary.x, pwm.bar.primary.y,
                                 _width, _height, xcb.mask(mask))

    global _pixmap
    _pixmap = xcb.core.generate_id()
    xcb.core.create_pixmap(
        xcb.screen.root_depth,
        _pixmap,
        _window,
        _width,
        _height)

    global _gc
    _gc = xcb.core.generate_id()
    xcb.core.create_gc(_gc, xcb.screen.root,
                       *xcb.mask([(xcb.GC_FOREGROUND, xcb.screen.white_pixel),
                                  (xcb.GC_BACKGROUND, xcb.screen.black_pixel),
                                  (xcb.GC_GRAPHICS_EXPOSURES, 0)]))

    global _surface
    _surface = cairo.xcb_surface_create(
        xcb.conn,
        _pixmap,
        xcb.aux_find_visual_by_id(xcb.screen, xcb.screen.root_visual),
        _width,
        _height)

    global _ctx
    _ctx = cairo.create(_surface)

    _ctx.select_font_face(config.bar.font.face,
                          cairo.FONT_SLANT_NORMAL,
                          cairo.FONT_WEIGHT_NORMAL)
    _ctx.set_font_size(config.bar.font.size)
Esempio n. 6
0
File: bar.py Progetto: linuscl/pwm
    def create_gc(self):
        gc = xcb.core.generate_id()

        xcb.core.create_gc(
            gc, xcb.screen.root,
            *xcb.mask([(xcb.GC_FOREGROUND, xcb.screen.white_pixel),
                       (xcb.GC_BACKGROUND, xcb.screen.black_pixel),
                       (xcb.GC_GRAPHICS_EXPOSURES, 0)]))

        return gc
Esempio n. 7
0
File: root.py Progetto: linuscl/pwm
def set_cursor(cursor):
    fid = xcb.core.generate_id()
    xcb.core.open_font(fid, len("cursor"), "cursor".encode("UTF-8"))

    cid = xcb.core.generate_id()
    xcb.core.create_glyph_cursor(cid, fid, fid, cursor, cursor + 1, 0, 0, 0,
                                 65535, 65535, 65535)
    xcb.core.change_window_attributes(xcb.screen.root,
                                      *xcb.mask((xcb.CW_CURSOR, cid)))

    xcb.core.free_cursor(cid)
    xcb.core.close_font(fid)
Esempio n. 8
0
def configure_clients():
    offset = 0
    for client, mapped in clients.items():
        if not mapped:
            continue

        # Client windows are squares, width=height
        offset += pwm.bar.primary.height+2
        xcb.core.configure_window(
            client,
            *xcb.mask((xcb.CONFIG_WINDOW_X, pwm.bar.primary.width-offset)))

    pwm.bar.primary.update_systray(offset)
Esempio n. 9
0
def configure_clients():
    offset = 0
    for client, mapped in clients.items():
        if not mapped:
            continue

        # Client windows are squares, width=height
        offset += pwm.bar.primary.height + 2
        xcb.core.configure_window(
            client,
            *xcb.mask((xcb.CONFIG_WINDOW_X, pwm.bar.primary.width - offset)))

    pwm.bar.primary.update_systray(offset)
Esempio n. 10
0
def configure(wid, **kwargs):
    """Configure the window and set the given variables in relation to the
    workspace.

    Arguments can be: x, y, width, height, stackmode
    If absolute=True then the window will be configured in absolute coordinates
    and not in relation to the workspace.
    """

    workspace = pwm.workspaces.current()
    values = []
    abs_ = 0 if kwargs.get("absolute", False) else 1

    border = (kwargs["borderwidth"] if "borderwidth" in kwargs
              else config.window.border)
    values.append((xcb.CONFIG_WINDOW_BORDER_WIDTH, border))

    # We need to cast x and y in order to have correct handling for negative
    # values.
    if "x" in kwargs:
        values.append(
            (xcb.CONFIG_WINDOW_X,
             xcb.ffi.cast("uint32_t", int(workspace.x*abs_ + kwargs["x"]))))
    if "y" in kwargs:
        values.append(
            (xcb.CONFIG_WINDOW_Y,
             xcb.ffi.cast("uint32_t", int(workspace.y*abs_ + kwargs["y"]))))

    if "width" in kwargs:
        values.append((xcb.CONFIG_WINDOW_WIDTH,
                       max(0, int(kwargs["width"] - 2*border))))
    if "height" in kwargs:
        values.append((xcb.CONFIG_WINDOW_HEIGHT,
                       max(0, int(kwargs["height"] - 2*border))))

    if "stackmode" in kwargs:
        values.append((xcb.CONFIG_WINDOW_STACK_MODE, kwargs["stackmode"]))

    if "sibling" in kwargs:
        values.append((xcb.CONFIG_WINDOW_SIBLING, kwargs["sibling"]))

    xcb.core.configure_window(wid, *xcb.mask(values))

    if wid in managed and "noupdate" not in kwargs:
        if ("x" in kwargs or "y" in kwargs or
                "width" in kwargs or "height" in kwargs):
            update_geometry(wid)
Esempio n. 11
0
File: root.py Progetto: linuscl/pwm
def setup():
    """Setup the root window."""

    cookie = xcb.core.change_window_attributes_checked(
        xcb.screen.root, *xcb.mask([(xcb.CW_EVENT_MASK, EVENT_MASK)]))

    cookie.check()

    try:
        # We have to set the cursor now, otherwise it will not show up until
        # the first client is launched.
        set_cursor(Cursor.left_ptr)
    except:
        logging.exception("Root cursor error")

    try:
        _set_properties()
    except:
        logging.exception("Root properties error")
Esempio n. 12
0
def create(x, y, width, height, mask=None):
    """Create a new window and return its id."""

    wid = xcb.core.generate_id()

    if not mask:
        mask = xcb.mask([(xcb.CW_BACK_PIXEL, xcb.screen.black_pixel),
                         (xcb.CW_EVENT_MASK, xcb.EVENT_MASK_EXPOSURE)])

    xcb.core.create_window(
        xcb.screen.root_depth,
        wid,
        xcb.screen.root,
        x, y,
        width,
        height,
        0,  # border
        xcb.WINDOW_CLASS_INPUT_OUTPUT,
        xcb.screen.root_visual,
        *mask)

    return wid
Esempio n. 13
0
def handle_client_message(event):
    """Handle client messages directed at the systray."""

    # System Tray Specification
    # http://standards.freedesktop.org/systemtray-spec/latest
    #
    # The first data field in the message is a timestamp (the stamp of the
    # current event, if available, otherwise CurrentTime). The second data
    # field is an integer indicating the op code of the message.
    # The content remaining three data fields depends on the type of message
    # being sent.

    # To begin the docking process, the tray icon application sends a
    # client message event to the manager selection owner window, [...].
    # This event should contain the SYSTEM_TRAY_REQUEST_DOCK opcode,
    # xclient.data.l[2] should contain the X window ID of the tray icon to be
    # docked.

    # At this point the "embedding life cycle" explained in the XEMBED
    # specification begins. The XEMBED specification explains how the
    # embedding application will interact with the embedded tray icon, and how
    # the embedder/embedded relationship may be ended.

    if event.data.data32[1] == SYSTEM_TRAY_REQUEST_DOCK:
        client = event.data.data32[2]
        logging.debug("client {} requested docking".format(client))

        # Listen for PropertyNotify events to get the most recent value of
        # the XEMBED_MAPPED atom, also listen for UnmapNotify events
        pwm.windows.change_attributes(
            client, (xcb.CW_EVENT_MASK,
                     xcb.EVENT_MASK_PROPERTY_CHANGE |
                     xcb.EVENT_MASK_STRUCTURE_NOTIFY))

        # Request the _XEMBED_INFO property. The XEMBED specification
        # says this *has* to be set, but VLC does not set it...
        xe_version = 1
        map_it = True
        info = pwm.windows.get_property(client, "_XEMBED_INFO")

        if info:
            xe_version = info[0]
            map_it = ((info[1] & XEMBED_MAPPED) == XEMBED_MAPPED)
            logging.debug("xembed version: {}".format(info[0]))
            logging.debug("xembed flags: {}".format(info[1]))
        else:
            logging.debug("client {} violates the XEMBED protocol, "
                          "_XEMBED_INFO not set.".format(client))

        # Put the client inside the save set. Upon termination (whether killed
        # or normal exit does not matter), these clients will be correctly
        # reparented to their most closest living ancestor. Without this, tray
        # icons might die when we exit/crash.
        xcb.core.change_save_set(xcb.SET_MODE_INSERT, client)

        xcb.core.reparent_window(client, pwm.bar.primary.wid, 0, 0)

        # We reconfigure the window to use a reasonable size. The systray
        # specification explicitly says:
        #   Tray icons may be assigned any size by the system tray, and
        #   should do their best to cope with any size effectively
        size = pwm.bar.primary.height
        xcb.core.configure_window(
            client, *xcb.mask([(xcb.CONFIG_WINDOW_WIDTH, size),
                               (xcb.CONFIG_WINDOW_HEIGHT, size)]))

        # Send the XEMBED_EMBEDDED_NOTIFY message.
        # http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
        # An XEmbed message is an X11 client message with message type
        # "_XEMBED". The format is 32, the first three data longs carry the
        # toolkit's X time (l[0]), the message's major opcode (l[1]) and the
        # message's detail code (l[2]). If no detail is required, the value
        # passed has to be 0. The remaining two data longs (l[3] and l[4]) are
        # reserved for data1 and data2. Unused bytes of the client message are
        # set to 0. The event is sent to the target window with no event mask
        # and propagation turned off.
        event = pwm.windows.create_client_message(
            client,
            pwm.atom.get("_XEMBED"),
            xcb.CURRENT_TIME,
            XEMBED_EMBEDDED_NOTIFY,
            0,
            pwm.bar.primary.wid,
            xe_version)

        xcb.core.send_event(False, client, xcb.EVENT_MASK_NO_EVENT, event)

        if map_it:
            xcb.core.map_window(client)

        clients[client] = map_it

        configure_clients()
Esempio n. 14
0
def change_attributes(wid, masks):
    """Set attributes for the given window."""
    xcb.core.change_window_attributes(wid, *xcb.mask(masks))
Esempio n. 15
0
def handle_client_message(event):
    """Handle client messages directed at the systray."""

    # System Tray Specification
    # http://standards.freedesktop.org/systemtray-spec/latest
    #
    # The first data field in the message is a timestamp (the stamp of the
    # current event, if available, otherwise CurrentTime). The second data
    # field is an integer indicating the op code of the message.
    # The content remaining three data fields depends on the type of message
    # being sent.

    # To begin the docking process, the tray icon application sends a
    # client message event to the manager selection owner window, [...].
    # This event should contain the SYSTEM_TRAY_REQUEST_DOCK opcode,
    # xclient.data.l[2] should contain the X window ID of the tray icon to be
    # docked.

    # At this point the "embedding life cycle" explained in the XEMBED
    # specification begins. The XEMBED specification explains how the
    # embedding application will interact with the embedded tray icon, and how
    # the embedder/embedded relationship may be ended.

    if event.data.data32[1] == SYSTEM_TRAY_REQUEST_DOCK:
        client = event.data.data32[2]
        logging.debug("client {} requested docking".format(client))

        # Listen for PropertyNotify events to get the most recent value of
        # the XEMBED_MAPPED atom, also listen for UnmapNotify events
        pwm.windows.change_attributes(
            client,
            (xcb.CW_EVENT_MASK,
             xcb.EVENT_MASK_PROPERTY_CHANGE | xcb.EVENT_MASK_STRUCTURE_NOTIFY))

        # Request the _XEMBED_INFO property. The XEMBED specification
        # says this *has* to be set, but VLC does not set it...
        xe_version = 1
        map_it = True
        info = pwm.windows.get_property(client, "_XEMBED_INFO")

        if info:
            xe_version = info[0]
            map_it = ((info[1] & XEMBED_MAPPED) == XEMBED_MAPPED)
            logging.debug("xembed version: {}".format(info[0]))
            logging.debug("xembed flags: {}".format(info[1]))
        else:
            logging.debug("client {} violates the XEMBED protocol, "
                          "_XEMBED_INFO not set.".format(client))

        # Put the client inside the save set. Upon termination (whether killed
        # or normal exit does not matter), these clients will be correctly
        # reparented to their most closest living ancestor. Without this, tray
        # icons might die when we exit/crash.
        xcb.core.change_save_set(xcb.SET_MODE_INSERT, client)

        xcb.core.reparent_window(client, pwm.bar.primary.wid, 0, 0)

        # We reconfigure the window to use a reasonable size. The systray
        # specification explicitly says:
        #   Tray icons may be assigned any size by the system tray, and
        #   should do their best to cope with any size effectively
        size = pwm.bar.primary.height
        xcb.core.configure_window(
            client,
            *xcb.mask([(xcb.CONFIG_WINDOW_WIDTH, size),
                       (xcb.CONFIG_WINDOW_HEIGHT, size)]))

        # Send the XEMBED_EMBEDDED_NOTIFY message.
        # http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
        # An XEmbed message is an X11 client message with message type
        # "_XEMBED". The format is 32, the first three data longs carry the
        # toolkit's X time (l[0]), the message's major opcode (l[1]) and the
        # message's detail code (l[2]). If no detail is required, the value
        # passed has to be 0. The remaining two data longs (l[3] and l[4]) are
        # reserved for data1 and data2. Unused bytes of the client message are
        # set to 0. The event is sent to the target window with no event mask
        # and propagation turned off.
        event = pwm.windows.create_client_message(client,
                                                  pwm.atom.get("_XEMBED"),
                                                  xcb.CURRENT_TIME,
                                                  XEMBED_EMBEDDED_NOTIFY, 0,
                                                  pwm.bar.primary.wid,
                                                  xe_version)

        xcb.core.send_event(False, client, xcb.EVENT_MASK_NO_EVENT, event)

        if map_it:
            xcb.core.map_window(client)

        clients[client] = map_it

        configure_clients()