Source

Mirror / src / window.cpp

#include "window.h"

Window::Window(Setup *setup, xcb_window_t id):
    id(id),
    exempt(false),
    fullscreen(false),
    ignore(false),
    setup(setup)
{
    inputHint = false;
    handleHints();
    handleGeometry();
    handleTransient();
    handleName();
    handleClass();

    uint32_t event_mask[] = {XCB_EVENT_MASK_ENTER_WINDOW};
    xcb_change_window_attributes(setup->conn, id, XCB_CW_EVENT_MASK, event_mask);
    xcb_flush(setup->conn);
}

Window::Window():
    id(XCB_NONE)
{
}

Window::~Window()
{
}

void Window::handleHints()
{
    xcb_icccm_wm_hints_t hints;
    if(xcb_icccm_get_wm_hints_reply(setup->conn, 
        xcb_icccm_get_wm_hints(setup->conn, id), &hints, nullptr))
    {
        if (hints.flags & XCB_ICCCM_WM_HINT_INPUT)
            inputHint = true;
    }
}

void Window::handleGeometry()
{
    xcb_get_geometry_reply_t *geomReply;
    if ((geomReply = xcb_get_geometry_reply(setup->conn, xcb_get_geometry_unchecked(setup->conn, id), nullptr)))
    {
        geometry.x = geomReply->x;
        geometry.y = geomReply->y;
        geometry.width = geomReply->width;
        geometry.height = geomReply->height;
    }
}

void Window::handleTransient()
{
    xcb_window_t transientFor = XCB_NONE;
    if (xcb_icccm_get_wm_transient_for_reply(setup->conn, 
        xcb_icccm_get_wm_transient_for_unchecked(setup->conn, id), &transientFor, nullptr)
        and transientFor != XCB_NONE)
    {
        transient = true;
    }
    else
        transient = false;
}

void Window::handleName()
{
    xcb_icccm_get_text_property_reply_t namePropReply;
    if ( not xcb_icccm_get_wm_name_reply(setup->conn, 
        xcb_icccm_get_wm_name_unchecked(setup->conn, id),&namePropReply, nullptr)
        or namePropReply.name_len < 1)
    {
        return;
    }
    name.assign(namePropReply.name, namePropReply.name_len);
    xcb_icccm_get_text_property_reply_wipe(&namePropReply);
}

void Window::handleClass()
{
    xcb_icccm_get_wm_class_reply_t prop;
    if(xcb_icccm_get_wm_class_reply(setup->conn, xcb_icccm_get_wm_class_unchecked(setup->conn, id), 
        &prop, nullptr))
    {
        wmClass.first = prop.class_name;
        wmClass.second = prop.instance_name;
        return;
    }
    wmClass = std::make_pair("unknown", "unknown");
}

void Window::focus()
{
   if (takeFocus)   
   {
       sendTakeFocus();
   }

   xcb_set_input_focus(setup->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
                       id, XCB_CURRENT_TIME);
}

void Window::close()
{
    xcb_atom_t WM_DELETE_WINDOW;
    std::string wmDelString = "WM_DELETE_WINDOW";
    xcb_client_message_event_t clientMessage;
    xcb_intern_atom_reply_t *reply;
    
    if ((reply = xcb_intern_atom_reply(setup->conn, 
        xcb_intern_atom_unchecked(setup->conn, false, wmDelString.length(), wmDelString.c_str()),
        nullptr)))
    {
        WM_DELETE_WINDOW = reply->atom;
        free(reply);
    }
    else
        return;
    xcb_icccm_get_wm_protocols_reply_t protoReply;
    xcb_icccm_get_wm_protocols_reply(setup->conn, 
    xcb_icccm_get_wm_protocols_unchecked(setup->conn, id, setup->ewmh->WM_PROTOCOLS),
    &protoReply, nullptr);
    if (protoReply.atoms_len>0)
    {
        for (int i = 0; i < protoReply.atoms_len; i++)
            if (protoReply.atoms[i] == WM_DELETE_WINDOW)
            {
                clientMessage.response_type = XCB_CLIENT_MESSAGE;
                clientMessage.window = id;
                clientMessage.format = 32;
                clientMessage.type = setup->ewmh->WM_PROTOCOLS;
                clientMessage.data.data32[0] = WM_DELETE_WINDOW;
                clientMessage.data.data32[1] = XCB_CURRENT_TIME;
                
                xcb_send_event(setup->conn, false, id, XCB_EVENT_MASK_NO_EVENT, (char *) &clientMessage);
                return;
            }
    }

    xcb_kill_client(setup->conn, id);

}

void Window::setGeometry(xcb_rectangle_t rect)
{
    uint32_t values[] = { rect.x, rect.y, rect.width, rect.height, 1};

    if (rect.width == 0 or rect.height == 0)
    {
        sendConfigureNotify();
        return;
    }

    if (geometry.x != rect.x
        or geometry.y != rect.y
        or geometry.width != rect.width
        or geometry.height != rect.height)
    {
        xcb_configure_window(setup->conn, id, 
        XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH,
        values);
        xcb_flush(setup->conn);

        if (geometry.width == rect.width and geometry.height == rect.height)
        {
            sendConfigureNotify();
        }
    }
    
    geometry = rect;    
}

xcb_rectangle_t Window::getGeometry()
{
    return geometry;
}

void Window::map()
{
    xcb_map_window(setup->conn, id);
}

void Window::unmap()
{
    xcb_unmap_window(setup->conn, id);
}

void Window::sendTakeFocus()
{
    xcb_atom_t WM_TAKE_FOCUS;
    std::string wmTakeString = "WM_TAKE_FOCUS";
    xcb_client_message_event_t clientMessage;
    xcb_intern_atom_reply_t *reply;

    if ((reply = xcb_intern_atom_reply(setup->conn, 
        xcb_intern_atom_unchecked(setup->conn, false, wmTakeString.length(), wmTakeString.c_str()),
        nullptr)))
    {
        WM_TAKE_FOCUS = reply->atom;
        free(reply);
    }
    else
        return;

    clientMessage.response_type = XCB_CLIENT_MESSAGE;
    clientMessage.window = id;
    clientMessage.format = 32;
    clientMessage.data.data32[1] = XCB_CURRENT_TIME;
    clientMessage.type = setup->ewmh->WM_PROTOCOLS;
    clientMessage.data.data32[0] = WM_TAKE_FOCUS;
        
    xcb_send_event(setup->conn, false, id,
                    XCB_EVENT_MASK_NO_EVENT, (char *) &clientMessage);
}

void Window::sendConfigureNotify()
{
    xcb_configure_notify_event_t ce;

    ce.response_type = XCB_CONFIGURE_NOTIFY;
    ce.event = id;
    ce.window = id;
    ce.x = geometry.x;
    ce.y = geometry.y;
    ce.width = geometry.width;
    ce.height = geometry.height;
    ce.border_width = 0;
    ce.above_sibling = XCB_NONE;
    ce.override_redirect = false;
    xcb_send_event(setup->conn, false, id, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *) &ce);
    xcb_flush(setup->conn);
}

void Window::stackAbove()
{
    uint32_t values[] = { XCB_STACK_MODE_ABOVE  };
    xcb_configure_window(setup->conn, id, XCB_CONFIG_WINDOW_STACK_MODE, values);
    xcb_flush(setup->conn);
}

void Window::stackBelow()
{
    uint32_t values[] = { XCB_STACK_MODE_BELOW  };
    xcb_configure_window(setup->conn, id, XCB_CONFIG_WINDOW_STACK_MODE, values);
    xcb_flush(setup->conn);
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.