]> git.sesse.net Git - ccbs/blob - bigscreen/ccbs_bigscreen.cpp
5df9dcdc989ec6defcdc0d4f0f61a710f49adf4a
[ccbs] / bigscreen / ccbs_bigscreen.cpp
1 #include <cstdio>
2 #include <cstring>
3 #include <iconv.h>
4 #include <unistd.h>
5 #include <pqxx/pqxx>
6 #include <ft2build.h>
7 #include FT_FREETYPE_H
8
9 #include "glwindow.h"
10
11 iconv_t ucs4_iconv;
12
13 // UCS-4 string
14 class widestring : public std::basic_string<unsigned>
15 {
16 public:
17         void operator= (const char *from)
18         {
19                 unsigned bytes = std::strlen(from);
20                 char *from_buf = strdup(from);
21                 unsigned *to_buf = new unsigned[bytes + 1];
22
23                 char *inptr = from_buf, *outptr = reinterpret_cast<char *> (to_buf);
24
25                 size_t in_left = bytes;
26                 size_t out_left = bytes * sizeof(unsigned);
27
28                 size_t ret = iconv(ucs4_iconv, NULL, NULL, &outptr, &out_left);
29                 if (ret == (size_t)(-1)) {
30                         throw std::runtime_error("Error in iconv during initialization");
31                 }
32
33                 ret = iconv(ucs4_iconv, &inptr, &in_left, &outptr, &out_left);
34                 if (ret == (size_t)(-1)) {
35                         perror("iconv");
36                         throw std::runtime_error("Error in iconv during conversion");
37                 }
38
39                 erase(begin(), end());
40                 std::copy(to_buf, reinterpret_cast<unsigned *> (outptr), std::back_inserter(*this));
41
42                 free(from_buf);
43                 delete[] to_buf;
44         }
45 };
46
47 template<>
48 void std::char_traits<unsigned>::assign(unsigned &to, unsigned const &from)
49 {
50         to = from;
51 }
52
53 template<>
54 unsigned *std::char_traits<unsigned>::copy(unsigned *to, unsigned const *from, unsigned n)
55 {
56         return static_cast<unsigned *>(memcpy(to, from, n * sizeof(unsigned)));
57 }
58
59 template<>
60 unsigned *std::char_traits<unsigned>::move(unsigned *to, unsigned const *from, unsigned n)
61 {
62         return static_cast<unsigned *>(memmove(to, from, n * sizeof(unsigned)));
63 }
64
65 template<>
66 unsigned *std::char_traits<unsigned>::assign(unsigned *to, size_t n, unsigned a)
67 {
68         for (unsigned i = 0; i < n; ++i)
69                 *to++ = a;
70         return to;
71 }
72
73
74 template<>
75 void pqxx::from_string<widestring>(const char *from, widestring &to)
76 {
77         to = from;
78 }
79
80 class Tournament {
81 public:
82         int id;
83         widestring name;
84 };
85
86 Tournament active_tournament;
87 FT_Face font;
88
89 /* A trigger that sets a flag whenever it's trigged. */
90 class FlagTrigger : pqxx::trigger {
91 private:
92         bool flag;
93         
94 public:
95         FlagTrigger(pqxx::connection_base &conn, const PGSTD::string &name)
96                 : pqxx::trigger(conn, name), flag(false) {}
97         virtual ~FlagTrigger() throw () {}
98         
99         virtual void operator() (int pid)
100         {
101                 flag = true;
102                 std::fprintf(stderr, "Received a flag trigger from pid %u\n", pid);
103         }
104
105         bool get_flag() const
106         {
107                 return flag;
108         }
109
110         void reset_flag()
111         {
112                 flag = false;
113         }
114 };
115
116 /* A transactor that fetches the current tournament and some information about it. */
117 class FetchCurrentTournament : public pqxx::transactor<> {
118 private:
119         Tournament *tourn;
120
121 public:
122         FetchCurrentTournament(Tournament *tourn) : tourn(tourn) {}
123         void operator() (pqxx::transaction<> &t)
124         {
125                 pqxx::result res( t.exec("SELECT * FROM bigscreen.active_tournament NATURAL JOIN tournaments") );
126                 try {
127                         pqxx::result::tuple tournament = res.at(0);
128
129                         tourn->id = tournament["tournament"].as(tourn->id);
130                         tourn->name = tournament["tournamentname"].as(tourn->name);
131                 } catch (PGSTD::out_of_range &e) {
132                         tourn->id = -1;
133                         tourn->name = "";
134                 }
135         }
136 };
137
138 void init(pqxx::connection &conn)
139 {
140         conn.perform(FetchCurrentTournament(&active_tournament));
141
142         if (active_tournament.id == -1) {
143                 std::fprintf(stderr, "No active tournament\n");
144         } else {
145                 std::fprintf(stderr, "Current tournament is %d (name: '%s')\n",
146                         active_tournament.id, active_tournament.name.c_str());
147         }
148 }
149
150 void main_loop(pqxx::connection &conn)
151 {
152         if (active_tournament.id == -1) {
153                 // No active tournament, sleep a second or so and exit
154                 sleep(1);
155                 return;
156         }
157         
158         pqxx::work t(conn, "trx");
159
160         // fetch all songs
161         pqxx::result res( t.exec("SELECT * FROM songs") );
162         for (pqxx::result::const_iterator i = res.begin(); i != res.end(); ++i) {
163                 std::fprintf(stderr, "%s\n", i["title"].c_str());
164         }
165         t.commit();
166         
167         sleep(1);
168 }
169
170 void init_freetype()
171 {
172         FT_Library library;
173         if (FT_Init_FreeType(&library))
174                 throw std::logic_error("FreeType init failed.");
175         if (FT_New_Face(library, "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf", 0, &font))
176                 throw std::logic_error("Face opening failed.");
177         if (FT_Set_Char_Size(font, 0, 12, 96, 96))
178                 throw std::logic_error("Size set failed.");
179 }
180
181 int main(int argc, char **argv)
182 {
183         ucs4_iconv = iconv_open("ucs-4", "utf-8");
184         
185         GLWindow glw("CCBS bigscreen", 800, 600, 32, false, 16, -1);
186         
187         try {
188                 init_freetype();
189                 pqxx::connection conn("dbname=ccbs host=altersex.samfundet.no user=ccbs password=GeT|>>B_");
190                 FlagTrigger tournament_changed(conn, "active_tournament");
191                 
192                 // when active_tournament is changed, we destroy everything and start from scratch
193                 for ( ;; ) {
194                         tournament_changed.reset_flag();
195                         init(conn);
196                         do {
197                                 main_loop(conn);
198                                 conn.get_notifs();
199                         } while (!tournament_changed.get_flag());
200                         std::fprintf(stderr, "active_tournament changed, resetting...\n");
201                 }
202         } catch (const std::exception &e) {
203                 std::fprintf(stderr, "Exception: %s\n", e.what());
204                 exit(1);
205         }
206         
207         return 0;
208 }