aboutsummaryrefslogtreecommitdiffstats
path: root/wayland/client.c
blob: 4d4a6bbb12aad8e3d705329cb169de05ff87069c (plain) (blame)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <wayland-client.h>
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "client/client.h"
#include "client/buffer.h"
#include "list.h"
#include "log.h"

static void display_handle_mode(void *data, struct wl_output *wl_output,
		     uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
	struct output_state *state = data;
	if (flags & WL_OUTPUT_MODE_CURRENT) {
		state->flags = flags;
		state->width = width;
		state->height = height;
	}
}

static void display_handle_geometry(void *data, struct wl_output *wl_output,
			 int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
			 int32_t subpixel, const char *make, const char *model, int32_t transform) {
	// this space intentionally left blank
}

static void display_handle_done(void *data, struct wl_output *wl_output) {
	// this space intentionally left blank
}

static void display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) {
	// this space intentionally left blank
}

static const struct wl_output_listener output_listener = {
	.mode = display_handle_mode,
	.geometry = display_handle_geometry,
	.done = display_handle_done,
	.scale = display_handle_scale
};

static void registry_global(void *data, struct wl_registry *registry,
		uint32_t name, const char *interface, uint32_t version) {
	struct client_state *state = data;

	if (strcmp(interface, wl_compositor_interface.name) == 0) {
		state->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version);
	} else if (strcmp(interface, wl_shm_interface.name) == 0) {
		state->shm = wl_registry_bind(registry, name, &wl_shm_interface, version);
	} else if (strcmp(interface, wl_shell_interface.name) == 0) {
		state->shell = wl_registry_bind(registry, name, &wl_shell_interface, version);
	} else if (strcmp(interface, wl_seat_interface.name) == 0) {
		state->seat = wl_registry_bind(registry, name, &wl_seat_interface, version);
		state->pointer = wl_seat_get_pointer(state->seat);
	} else if (strcmp(interface, wl_output_interface.name) == 0) {
		struct wl_output *output = wl_registry_bind(registry, name, &wl_output_interface, version);
		struct output_state *ostate = malloc(sizeof(struct output_state));
		ostate->output = output;
		wl_output_add_listener(output, &output_listener, ostate);
		list_add(state->outputs, ostate);
	}
}

static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) {
	// this space intentionally left blank
}

static const struct wl_registry_listener registry_listener = {
	.global = registry_global,
	.global_remove = registry_global_remove
};

struct client_state *client_setup(uint32_t width, uint32_t height) {
	struct client_state *state = malloc(sizeof(struct client_state));
	memset(state, 0, sizeof(struct client_state));
	state->outputs = create_list();
	state->width = width;
	state->height = height;

	state->display = wl_display_connect(NULL);
	if (!state->display) {
		sway_log(L_ERROR, "Error opening display");
		client_teardown(state);
		return NULL;
	}

	struct wl_registry *registry = wl_display_get_registry(state->display);
	wl_registry_add_listener(registry, &registry_listener, state);
	wl_display_dispatch(state->display);
	wl_display_roundtrip(state->display);
	wl_registry_destroy(registry);

	state->surface = wl_compositor_create_surface(state->compositor);
	state->shell_surface = wl_shell_get_shell_surface(state->shell, state->surface);
	wl_shell_surface_set_toplevel(state->shell_surface);

	return state;
}

static void frame_callback(void *data, struct wl_callback *callback, uint32_t time) {
	struct client_state *state = data;
	wl_callback_destroy(callback);
	state->frame_cb = NULL;
}

static const struct wl_callback_listener listener = {
	frame_callback
};

int client_prerender(struct client_state *state) {
	if (state->frame_cb) {
		return 0;
	}

	get_next_buffer(state);
	return 1;
}

int client_render(struct client_state *state) {
	state->frame_cb = wl_surface_frame(state->surface);
	wl_callback_add_listener(state->frame_cb, &listener, state);

	wl_surface_damage(state->surface, 0, 0, state->buffer->width, state->buffer->height);
	wl_surface_attach(state->surface, state->buffer->buffer, 0, 0);
	wl_surface_commit(state->surface);

	return 1;
}

void client_teardown(struct client_state *state) {
	if (state->pointer) {
		wl_pointer_destroy(state->pointer);
	}
	if (state->seat) {
		wl_seat_destroy(state->seat);
	}
	if (state->shell) {
		wl_shell_destroy(state->shell);
	}
	if (state->shm) {
		wl_shm_destroy(state->shm);
	}
	if (state->compositor) {
		wl_compositor_destroy(state->compositor);
	}
	if (state->display) {
		wl_display_disconnect(state->display);
	}
	if (state->outputs) {
		// TODO: Free the outputs themselves
		list_free(state->outputs);
	}
}