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
158
159
160
|
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include <time.h>
#include <GLES3/gl3.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include "otd.h"
#include "drm.h"
#include "event.h"
// I know this is pretty crappy,
// but it's just for the example's sake
struct {
char *name;
char *mode;
} displays[8];
int num_displays = 0;
noreturn void usage(const char *name, int ret)
{
fprintf(stderr, "usage: %s [-o <name> [-m <mode>]]*\n"
"\n"
" -h \tDisplay this help text\n"
" -o <name>\tWhich diplay to use. e.g. DVI-I-1.\n"
" -m <mode>\tWhich mode to use. It must come after an -o option.\n"
" \tMust be either 'preferred', 'current', widthxheight\n"
" \tor widthxheight@rate. Defaults to 'preferred'.\n"
"\n"
"example: %s -o DVI-I-1 -m 1920x1080@60 -o DP-1 -m 1920x1200\n",
name, name);
exit(ret);
}
void parse_args(int argc, char *argv[])
{
int c;
int i = -1;
while ((c = getopt(argc, argv, "ho:m:")) != -1) {
switch (c) {
case 'h':
usage(argv[0], 0);
case 'o':
i = num_displays++;
if (num_displays == 8) {
fprintf(stderr, "Too many displays\n");
exit(1);
}
displays[i].name = strdup(optarg);
break;
case 'm':
if (i == -1) {
fprintf(stderr, "A display is required first\n");
exit(1);
}
fprintf(stderr, "Assigned '%s' to '%s'\n", optarg, displays[i].name);
displays[i].mode = optarg;
i = -1;
break;
default:
usage(argv[0], 1);
}
}
// Trailing args
if (optind != argc) {
usage(argv[0], 1);
}
}
int main(int argc, char *argv[])
{
parse_args(argc, argv);
struct otd *otd = otd_start();
if (!otd)
return 1;
float colour[3] = {1.0, 0.0, 0.0};
int dec = 0;
struct timespec start, now;
clock_gettime(CLOCK_MONOTONIC, &start);
struct timespec last = start;
while (clock_gettime(CLOCK_MONOTONIC, &now) == 0 &&
now.tv_sec < start.tv_sec + 10) {
struct otd_event ev;
if (!otd_get_event(otd, &ev))
continue;
struct otd_display *disp = ev.display;
switch (ev.type) {
case OTD_EV_RENDER:
rendering_begin(disp);
// This is all just calculating the colours.
// It's not particularly important.
long ms = (now.tv_sec - last.tv_sec) * 1000 +
(now.tv_nsec - last.tv_nsec) / 1000000;
int inc = (dec + 1) % 3;
colour[dec] -= ms / 2000.0f;
colour[inc] += ms / 2000.0f;
if (colour[dec] < 0.0f) {
colour[dec] = 0.0f;
colour[inc] = 1.0f;
dec = (dec + 1) % 3;
}
last = now;
glViewport(0, 0, disp->width, disp->height);
glClearColor(colour[0], colour[1], colour[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
rendering_end(disp);
break;
case OTD_EV_DISPLAY_REM:
printf("%s removed\n", disp->name);
break;
case OTD_EV_DISPLAY_ADD:
printf("%s added\n", disp->name);
const char *mode = NULL;
for (int i = 0; i < num_displays; ++i) {
if (strcmp(disp->name, displays[i].name) == 0) {
mode = displays[i].mode;
}
}
if (!mode)
mode = "preferred";
if (!modeset_str(otd, ev.display, mode)) {
fprintf(stderr, "Modesetting %s failed\n", disp->name);
goto out;
}
break;
default:
break;
}
}
out:
otd_finish(otd);
}
|