Base: LCDproc 0.5.2
[lcdproc-de200c.git] / server / screenlist.c
blob800234eb2c22e35fbf573352cb2018a08bf25a3f
1 /*
2 * screenlist.c
3 * This file is part of LCDd, the lcdproc server.
5 * This file is released under the GNU General Public License. Refer to the
6 * COPYING file distributed with this package.
8 * Copyright (c) 1999, William Ferrell, Scott Scriven
9 * 2003, Joris Robijn
12 * All actions that can be performed on the list of screens.
13 * This file also manages the rotation of screens.
17 #include <stdlib.h>
18 #include <stdio.h>
20 #include "shared/LL.h"
21 #include "shared/sockets.h"
22 #include "shared/report.h"
23 #include "screenlist.h"
24 #include "screen.h"
26 #include "main.h" /* for timer */
28 /* Local functions */
29 int compare_priority(void *one, void *two);
31 bool autorotate = 1; /* If on, INFO and FOREGROUND screens will rotate */
32 LinkedList *screenlist = NULL;
33 Screen *current_screen = NULL;
34 long int current_screen_start_time = 0;
37 int
38 screenlist_init(void)
40 report(RPT_DEBUG, "%s()", __FUNCTION__);
42 screenlist = LL_new();
43 if (!screenlist) {
44 report(RPT_ERR, "%s: Error allocating", __FUNCTION__);
45 return -1;
47 return 0;
51 int
52 screenlist_shutdown(void)
54 report(RPT_DEBUG, "%s()", __FUNCTION__);
56 if (!screenlist) {
57 /* Program shutdown before completed startup */
58 return -1;
60 LL_Destroy(screenlist);
62 return 0;
66 int
67 screenlist_add(Screen *s)
69 if (!screenlist)
70 return -1;
71 return LL_Push(screenlist, s);
75 int
76 screenlist_remove(Screen *s)
78 debug(RPT_DEBUG, "%s(s=[%.40s])", __FUNCTION__, s->id);
80 if (!screenlist)
81 return -1;
83 /* Are we trying to remove the current screen ? */
84 if (s == current_screen) {
85 screenlist_goto_next();
86 if (s == current_screen) {
87 /* Hmm, no other screen had same priority */
88 void *res = LL_Remove(screenlist, s);
89 /* And now once more */
90 screenlist_goto_next();
91 return (res == NULL) ? -1 : 0;
94 return (LL_Remove(screenlist, s) == NULL) ? -1 : 0;
98 void
99 screenlist_process(void)
101 Screen *s;
102 Screen *f;
104 report(RPT_DEBUG, "%s()", __FUNCTION__);
106 if (!screenlist)
107 return;
109 /* Sort the list acfording to priority class */
110 LL_Sort(screenlist, compare_priority);
111 f = LL_GetFirst(screenlist);
113 /**** First we need to check out the current situation. ****/
115 /* Check whether there is an active screen */
116 s = screenlist_current();
117 if (!s) {
118 /* We have no active screen yet.
119 * Try to switch to the first screen in the list... */
121 s = f;
122 if (!s) {
123 /* There was no screen in the list */
124 return;
126 screenlist_switch(s);
127 return;
129 else {
130 /* There already was an active screen.
131 * Check to see if it has an expiry time. If so, decrease it
132 * and then check to see if it has expired. Remove the screen
133 * if expired. */
134 if (s->timeout != -1) {
135 --(s->timeout);
136 report(RPT_DEBUG, "Active screen [%.40s] has timeout->%d", s->id, s->timeout);
137 if (s->timeout <= 0) {
138 /* Expired, we can destroy it */
139 report(RPT_DEBUG, "Removing expired screen [%.40s]", s->id);
140 client_remove_screen(s->client, s);
141 screen_destroy(s);
146 /**** OK, current situation examined. We can now see if we need to switch. */
148 /* Is there a screen of a higher priority class than the
149 * current one ? */
150 if (f->priority > s->priority) {
151 /* Yes, switch to that screen, job done */
152 screenlist_switch(f);
153 return;
156 /* Current screen has been visible long enough and is it of 'normal'
157 * priority ?
159 if (autorotate && (timer - current_screen_start_time >= s->duration)
160 && s->priority > PRI_BACKGROUND && s->priority <= PRI_FOREGROUND) {
161 /* Ah, rotate! */
162 screenlist_goto_next();
167 void
168 screenlist_switch(Screen *s)
170 Client *c;
171 char str[256];
173 if (!s) return;
175 report(RPT_DEBUG, "%s(s=[%.40s])", __FUNCTION__, s->id);
177 if (s == current_screen) {
178 /* Nothing to be done */
179 return;
182 if (current_screen) {
183 c = current_screen->client;
184 if (c) {
185 /* Tell the client we're not listening any more...*/
186 snprintf(str, sizeof(str), "ignore %s\n", current_screen->id);
187 sock_send_string(c->sock, str);
188 } else {
189 /* It's a server screen, no need to inform it. */
192 c = s->client;
193 if (c) {
194 /* Tell the client we're paying attention...*/
195 snprintf(str, sizeof(str), "listen %s\n", s->id);
196 sock_send_string(c->sock, str);
197 } else {
198 /* It's a server screen, no need to inform it. */
200 report(RPT_INFO, "%s: switched to screen [%.40s]", __FUNCTION__, s->id);
201 current_screen = s;
202 current_screen_start_time = timer;
206 Screen *
207 screenlist_current(void)
209 return current_screen;
214 screenlist_goto_next(void)
216 Screen *s;
218 debug(RPT_DEBUG, "%s()", __FUNCTION__);
220 if (!current_screen)
221 return -1;
223 /* Find current screen in screenlist */
224 for (s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist));
226 /* One step forward */
227 s = LL_GetNext(screenlist);
228 if (!s || s->priority < current_screen->priority) {
229 /* To far, go back to start of screenlist */
230 s = LL_GetFirst(screenlist);
232 screenlist_switch(s);
233 return 0;
238 screenlist_goto_prev(void)
240 Screen *s;
242 debug(RPT_DEBUG, "%s()", __FUNCTION__);
244 if (!current_screen)
245 return -1;
247 /* Find current screen in screenlist */
248 for (s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist));
250 /* One step back */
251 s = LL_GetPrev(screenlist);
252 if (!s) {
253 /* We're at the start of the screenlist. We should find the
254 * last screen with the same priority as the first screen.
256 Screen *f = LL_GetFirst(screenlist);
257 Screen *n;
259 s = f;
260 while ((n = LL_GetNext(screenlist)) && n->priority == f->priority) {
261 s = n;
264 screenlist_switch(s);
265 return 0;
268 /* Internal function for sorting. */
270 compare_priority(void *one, void *two)
272 Screen *a, *b;
274 /*debug(RPT_DEBUG, "compare_priority: %8x %8x", one, two);*/
276 if (!one)
277 return 0;
278 if (!two)
279 return 0;
281 a = (Screen *) one;
282 b = (Screen *) two;
284 /*debug(RPT_DEBUG, "compare_priority: done?");*/
286 return (b->priority - a->priority);