Mirror / src / setup.cpp

#include "setup.h"
#include "monitor.h"
#include "statusBar.h"
#include "window.h"

Setup::Setup(std::vector<std::string> tags, std::vector<Rule> windowRules):
    tags(tags),
    windowRules(windowRules)
{
    conn = xcb_connect(nullptr, nullptr);
    screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
    root = screen->root;

    ewmh = ewmhInit(conn);
    
    uint32_t event_mask[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
                                XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
                                XCB_EVENT_MASK_PROPERTY_CHANGE};
    xcb_void_cookie_t checkCookie = xcb_change_window_attributes_checked(conn, root, XCB_CW_EVENT_MASK, event_mask);
    if (xcb_request_check(conn, checkCookie))
	{
        throw OtherWindowManager();                                                                                       
    }
    getMonitors();
    for (auto& monitor : monitors)
    {
        monitor.statusBar = new StatusBar(this, monitor);
    }
}

Setup::~Setup()
{
    xcb_disconnect(conn);
}

void Setup::getMonitors()
{
    if (!getXrandrMonitors())
    {
        xcb_rectangle_t screenArea;
        screenArea.x = 0;
        screenArea.y = statusBarHeight;
        screenArea.width = screen->width_in_pixels;
        screenArea.height = screen->height_in_pixels - statusBarHeight+1;
        Monitor newMonitor(screenArea);
        for (auto &tagName : tags)
		{
			newMonitor.tagList.push_back(Tag(tagName));
		}
        monitors.push_back(newMonitor);

    }
}

bool Setup::getXrandrMonitors()
{
    if (xcb_get_extension_data(conn, &xcb_randr_id)->present)
    {
        auto *versionReply = xcb_randr_query_version_reply(conn, xcb_randr_query_version(conn, 1, 1), 0);

        if (versionReply)
        {
            free(versionReply);

            auto screenResCookie = xcb_randr_get_screen_resources(conn, root);
            auto *screenResReply = xcb_randr_get_screen_resources_reply(conn, screenResCookie, nullptr);
            if (screenResReply->num_crtcs <= 1)                
            {
                    free(screenResReply);                            
                    return false;                                                
            }
                
            xcb_randr_crtc_t *randrCRTCs = xcb_randr_get_screen_resources_crtcs(screenResReply);
            for (int i = 0; i < screenResReply->num_crtcs; i++)
            {
                auto crtcInfoCookie = xcb_randr_get_crtc_info(conn, randrCRTCs[i], XCB_CURRENT_TIME);
                auto *crtcInfoReply = xcb_randr_get_crtc_info_reply(conn, crtcInfoCookie, nullptr);
                if(!xcb_randr_get_crtc_info_outputs_length(crtcInfoReply))
                    continue;

                xcb_rectangle_t screenArea;
                screenArea.x = crtcInfoReply->x;
                screenArea.y = crtcInfoReply->y+statusBarHeight;
                screenArea.width = crtcInfoReply->width;
                screenArea.height = crtcInfoReply->height-statusBarHeight;
                Monitor newMonitor(screenArea);
                for (auto &tagName : tags)
				{
					newMonitor.tagList.push_back(Tag(tagName));
				}
                monitors.push_back(newMonitor);
                free(crtcInfoReply);
            }

            free(screenResReply);
            return true;
        }
    }
    return false;
}

Window& Setup::findWindow(xcb_window_t window)
{
    for(auto& monitor : monitors)
        for (auto& tag : monitor.tagList)
        {
            auto& win = tag.windowContainer.findWindow(window);
            if (win)
                return win;
        }
    return monitors.at(0).tagList.at(0).windowContainer.invalidWin;
}

void Setup::addWindow(xcb_window_t window)
{
    if(findWindow(window))
        return;
	
    auto& monitor = getCurrentMonitor();
    Window win(this, window);
    for (auto &rule : windowRules)
    {
        if ((std::get<0>(rule) == win.name or std::get<0>(rule) == "*" )
            and (std::get<1>(rule) == win.wmClass.first 
            or std::get<1>(rule) == win.wmClass.second or std::get<1>(rule) == "*"))
        {
            std::cerr << win.name << std::endl;
            win.tagName = std::get<2>(rule);
            win.exempt = std::get<3>(rule);
        }
    }

    for (auto& tag : monitor.tagList)
        if (tag.name == win.tagName)
        {
            tag.windowContainer.addWindow(win);
            return;
        }
    win.tagName = monitor.tagList.at(monitor.currentTag).name;
    monitor.tagList.at(monitor.currentTag).windowContainer.addWindow(win);
}

void Setup::addWindow(Window window)
{
    if (findWindow(window.id))
        return;
    auto monitor = getCurrentMonitor();
    for (auto& tag : monitor.tagList)
    {
        if (tag.name == window.tagName)
        {
            tag.windowContainer.addWindow(window);
            return;
        }
    }
}

void Setup::removeWindow(Window window)
{
    for (auto& monitor: monitors)
    {
        for (auto& tag : monitor.tagList)
        {
            if (tag.windowContainer.removeWindow(window))
                return;
        }
    }
}

void Setup::removeWindow(xcb_window_t window)
{
    for (auto& monitor: monitors)
        for (auto& tag : monitor.tagList)
        {
            auto &win = tag.windowContainer.findWindow(window);
            if (win)
            {
                tag.windowContainer.removeWindow(win);
                return;
            }
           
        }
}

void Setup::focusWindow(xcb_window_t window)
{
    int i=0;
    Monitor &monitor = getCurrentMonitor();
	for (auto& tag : monitor.tagList)
    {
        auto &win = tag.windowContainer.findWindow(window);
        if (win)
        {
            tag.windowContainer.focusWindow(win);
            monitor.currentTag = i;
            return;
        }
		i++;
    }
}


void Setup::layoutWindows()
{
    Monitor &monitor = getCurrentMonitor();
    monitor.tagList.at(monitor.currentTag).windowContainer.layoutWindows(monitor.area);
    xcb_rectangle_t offscreenRect = monitor.area;
    offscreenRect.y = 0 - monitor.area.height;
    offscreenRect.x = 0 - monitor.area.width;
    for (auto &tag : monitor.tagList)
    {
        if (tag.name == monitor.tagList.at(monitor.currentTag).name)
        {
            continue;
        }
        tag.windowContainer.layoutWindows(offscreenRect);
    }
}

Monitor& Setup::getCurrentMonitor()
{
    int x = 0;
    int y = 0;
    auto* pointerReply = xcb_query_pointer_reply(conn, xcb_query_pointer_unchecked(conn, root), nullptr);
    if(pointerReply)
    {
        x = pointerReply->root_x;
        y = pointerReply->root_y; 
    }
    free(pointerReply);

    for (auto& monitor : monitors)
    {
        if (x >= monitor.area.x
            and x <= monitor.area.x + monitor.area.width)
        { 
            if (y >= monitor.area.y 
                and y <= monitor.area.y + monitor.area.height)
            {
                return monitor;
            }

        }
    }
    return monitors.at(0);
}

void Setup::nextTag()
{
	Monitor &monitor = getCurrentMonitor();
    xcb_rectangle_t rect = monitor.area;
    rect.x = 0 - rect.width;
    rect.y = 0 - rect.height;
    monitor.tagList.at(monitor.currentTag).windowContainer.layoutWindows(rect);
	monitor.currentTag++;

	if (monitor.currentTag > monitor.tagList.size()-1)
		monitor.currentTag = 0;

    monitor.tagList.at(monitor.currentTag).windowContainer.layoutWindows(monitor.area);
    monitor.tagList.at(monitor.currentTag).windowContainer.raiseAll();
    monitor.statusBar->setText(monitor.tagList.at(monitor.currentTag).name);
}

void Setup::prevTag()
{
	Monitor &monitor = getCurrentMonitor();
    xcb_rectangle_t rect = monitor.area;
    rect.x = 0 - rect.width;
    rect.y = 0 - rect.height;
    monitor.tagList.at(monitor.currentTag).windowContainer.layoutWindows(rect);
	monitor.currentTag--;
	if (monitor.currentTag < 0)
	{
		monitor.currentTag = monitor.tagList.size()-1;
	}

    monitor.tagList.at(monitor.currentTag).windowContainer.layoutWindows(monitor.area);
    monitor.tagList.at(monitor.currentTag).windowContainer.raiseAll();
    monitor.statusBar->setText(monitor.tagList.at(monitor.currentTag).name);

}

void Setup::launchApp(std::string command)
{
	pid_t pid1;
	pid_t pid2;
	int status;

	if (pid1 = fork()) 
	{
		/* parent process A */
		waitpid(pid1, &status, 0);
												      
	} 
	else if (!pid1) 
	{
		setsid();
		/* child process B */
		if (pid2 = fork()) 
		{
			exit(0);
		} 
		else if (!pid2) 
		{
			/* child process C */
			int stdinFd = open("/dev/null", O_RDONLY);
			dup2(stdinFd, STDIN_FILENO);
			close(stdinFd);
			int stdoutFd = open("/dev/null", O_WRONLY);
			dup2(stdoutFd, STDOUT_FILENO);
			close(stdoutFd);
			int stderrFd = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND);
			dup2(stderrFd, STDERR_FILENO);
            close(stderrFd);
			char *const argv [] = {nullptr};
			execvp(command.c_str(), argv);
																	              
		} 
		else 
		{
			/* error */
			std::cerr << "The second fork failed when trying to launch " << command << std::endl;
												             
		}
	        
	} 
	else 
	{
		/* error */								     
		std::cerr << "The first fork failed when trying to launch " << command << std::endl;
	}
}
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.