]> git.sesse.net Git - ccbs/blob - bigscreen/theme.cpp
Shape text using Pango and HarfBuzz; gives us nice ligatures and exotic scripts.
[ccbs] / bigscreen / theme.cpp
1 #include <cstdio>
2 #include <cstring>
3 #include <cstdlib>
4 #include <map>
5 #include <string>
6 #include <stdexcept>
7
8 #include "theme.h"
9
10 std::map<std::string, std::string> config;
11
12 void read_config(const char *filename)
13 {
14         FILE *fp = fopen(filename, "r");
15         if (fp == NULL)
16                 throw std::runtime_error("Couldn't open theme file.");
17
18         while (!feof(fp)) {
19                 char buf[1024];
20                 if (fgets(buf, 1024, fp) == NULL) {
21                         break;
22                 }
23
24                 char *ptr = strchr(buf, '\n');
25                 if (ptr != NULL)
26                         *ptr = 0;
27
28                 ptr = strchr(buf, '\r');
29                 if (ptr != NULL)
30                         *ptr = 0;
31
32                 ptr = strchr(buf, '#');
33                 if (ptr != NULL)
34                         *ptr = 0;
35
36                 int len = strlen(buf);
37                 while (len > 0 && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) {
38                         buf[--len] = 0;
39                 }
40                         
41                 if (len == 0) {
42                         continue;
43                 }
44
45                 char key[1024], value[1024];
46                 if (sscanf(buf, "%[^=] = %[^=]", key, value) != 2) {
47                         fprintf(stderr, "Warning: Ignoring malformed line '%s'.\n", buf);
48                         continue;
49                 }
50
51                 config[key] = value;
52         }
53         fclose(fp);
54 }
55
56 void init_theme()
57 {
58         read_config("theme.config");
59         try {
60                 read_config("theme.config.local");
61         } catch (...) {
62                 // Ignore.
63         }
64 }
65
66 std::string get_theme_config(const std::string &key, const std::string subkey)
67 {
68         if (config.count(key + "." + subkey)) {
69                 return config[key + "." + subkey];
70         }
71
72         std::string modkey = key;
73         while (modkey.find_last_of(".") != std::string::npos) {
74                 modkey.resize(modkey.find_last_of("."));
75                 if (config.count(modkey + "." + subkey)) {
76                         return config[modkey + "." + subkey];
77                 }
78         }
79
80         return config["default." + subkey];
81 }
82
83 void fill_background(unsigned char *buf, const std::string &screen_name, unsigned width, unsigned height)
84 {
85         std::string key = "background." + screen_name;
86         int bg_r = atoi(get_theme_config(key, "red").c_str());
87         int bg_g = atoi(get_theme_config(key, "green").c_str());
88         int bg_b = atoi(get_theme_config(key, "blue").c_str());
89
90         unsigned char *ptr = buf;
91         for (unsigned i = 0; i < width * height; ++i) {
92                 *ptr++ = bg_b;
93                 *ptr++ = bg_g;
94                 *ptr++ = bg_r;
95                 *ptr++ = 0;
96         }
97
98         for (unsigned i = 0; i < 10; ++i) {
99                 char rectkey[1024];
100                 snprintf(rectkey, sizeof(rectkey), "background.%s.rect%u", screen_name.c_str(), i);
101                 if (get_theme_config(rectkey, "x0").empty()) {
102                         continue;
103                 }
104
105                 int x0 = std::max<int>(atoi(get_theme_config(rectkey, "x0").c_str()) * width / LOGICAL_SCREEN_WIDTH, 0);
106                 int y0 = std::max<int>(atoi(get_theme_config(rectkey, "y0").c_str()) * height / LOGICAL_SCREEN_HEIGHT, 0);
107                 int x1 = std::min<int>(atoi(get_theme_config(rectkey, "x1").c_str()) * width / LOGICAL_SCREEN_WIDTH, width);
108                 int y1 = std::min<int>(atoi(get_theme_config(rectkey, "y1").c_str()) * height / LOGICAL_SCREEN_HEIGHT, height);
109                 int r = atoi(get_theme_config(rectkey, "red").c_str());
110                 int g = atoi(get_theme_config(rectkey, "green").c_str());
111                 int b = atoi(get_theme_config(rectkey, "blue").c_str());
112
113                 for (int y = y0; y < y1; ++y) {
114                         unsigned char *ptr = buf + (y * width + x0) * 4;
115                         for (int x = x0; x < x1; ++x) {
116                                 *ptr++ = b;
117                                 *ptr++ = g;
118                                 *ptr++ = r;
119                                 *ptr++ = 0;
120                         }
121                 }
122         }
123 }