aboutsummaryrefslogtreecommitdiff
path: root/x11.c
blob: 26ae535b269304a1bfa7bd0f1259f62d2ac818aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <stdbool.h>
#include <assert.h>
#include <glib.h>
#include <math.h>
#include <cairo.h>
#include <cairo-xcb.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xproto.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_xrm.h>

#include "x11.h"

struct Window {
    xcb_screen_t *screen;
    xcb_connection_t *connection;
	xcb_xrm_database_t *database;
    xcb_drawable_t window;
    xcb_visualtype_t *visual_type;
    cairo_surface_t *surface;
    cairo_t *cr;
	double dpi;
};

Window *window_create(void)
{
    Window *win = g_malloc0(sizeof(Window));

    int preferred_screen = 0;
    win->connection = xcb_connect(NULL, &preferred_screen);
	assert(win->connection != NULL && !xcb_connection_has_error(win->connection));

	win->database = xcb_xrm_database_from_default(win->connection);
	assert(win->database != NULL);

	char *dpi_value;
	if (xcb_xrm_resource_get_string(win->database, "Xft.dpi", "Xft.dpi", &dpi_value) >= 0) {
		win->dpi = strtod(dpi_value, NULL);
		g_free(dpi_value);
	} else {
		// TODO: Calculate automatically somehow
		win->dpi = 96.0;
	}

    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(win->connection));

    while (preferred_screen != 0 && iter.rem) {
        xcb_screen_next(&iter);
        preferred_screen--;
    }

    win->screen = iter.data;
    win->window = xcb_generate_id(win->connection);

    int y = 0, x = 0, h = 300, w = 400;
    xcb_create_window(win->connection,
                      XCB_COPY_FROM_PARENT,
                      win->window, win->screen->root,
                      y, x, h, w, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      win->screen->root_visual,
					  XCB_CW_BACK_PIXEL,
                      //XCB_CW_BACK_PIXEL | XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT |
                      //    XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
                      &win->screen->white_pixel);

    xcb_icccm_set_wm_name(win->connection, win->window, XCB_ATOM_STRING, 8, strlen("comet"), "comet");
    xcb_map_window(win->connection, win->window);
    xcb_flush(win->connection);

    xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(win->screen);

    while (depth_iter.rem) {
        xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);

        while (visual_iter.rem) {
            if (win->screen->root_visual == visual_iter.data->visual_id) {
                win->visual_type = visual_iter.data;
                goto done;
            }
            xcb_visualtype_next(&visual_iter);
        }
        xcb_depth_next(&depth_iter);
    }

done:

    win->surface = cairo_xcb_surface_create(win->connection, win->window, win->visual_type, w, h);
    win->cr = cairo_create(win->surface);

    return win;
}

cairo_t *window_get_context(Window *win)
{
    return win->cr;
}

double window_get_scale(Window *win)
{
    return MAX(1, win->dpi/96.);
}

void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int height)
{
    double scale = window_get_scale(win);

    cairo_xcb_surface_set_size(win->surface, round(width * scale), round(height * scale));

    xcb_clear_area(win->connection, false, win->window, 0, 0, 0, 0);

    cairo_set_source_surface(win->cr, surface, 0, 0);
    cairo_paint(win->cr);
    cairo_show_page(win->cr);

    xcb_flush(win->connection);
}

void window_destroy(Window *win)
{
    cairo_destroy(win->cr);
    cairo_surface_destroy(win->surface);
    xcb_xrm_database_free(win->database);
    xcb_disconnect(win->connection);
    g_free(win);
}

// vim: ts=4 sw=4 et