/* * screenlist.c * This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Scott Scriven * 2003, Joris Robijn * * * All actions that can be performed on the list of screens. * This file also manages the rotation of screens. * */ #include #include #include "shared/LL.h" #include "shared/sockets.h" #include "shared/report.h" #include "screenlist.h" #include "screen.h" #include "main.h" /* for timer */ /* Local functions */ int compare_priority (void *one, void *two); bool autorotate = 1; /* If on, INFO and FOREGROUND screens will rotate */ LinkedList *screenlist = NULL; Screen * current_screen = NULL; long int current_screen_start_time = 0; int screenlist_init () { report (RPT_DEBUG, "%s()", __FUNCTION__); screenlist = LL_new (); if (!screenlist) { report(RPT_ERR, "%s: Error allocating", __FUNCTION__); return -1; } return 0; } int screenlist_shutdown () { report (RPT_DEBUG, "%s()", __FUNCTION__); if( !screenlist ) { /* Program shutdown before completed startup */ return -1; } LL_Destroy (screenlist); return 0; } int screenlist_add (Screen * s) { if (!screenlist) return -1; return LL_Push (screenlist, s); } int screenlist_remove (Screen * s) { debug (RPT_DEBUG, "%s( s=[%.40s] )", __FUNCTION__, s->id); if (!screenlist) return -1; /* Are we trying to remove the current screen ? */ if (s == current_screen) { screenlist_goto_next (); if (s == current_screen) { /* Hmm, no other screen had same priority */ void * res = LL_Remove (screenlist, s); /* And now once more */ screenlist_goto_next (); return (res == NULL) ? -1 : 0; } } return (LL_Remove (screenlist, s) == NULL) ? -1 : 0; } void screenlist_process () { Screen * s; Screen * f; report (RPT_DEBUG, "%s()", __FUNCTION__); if (!screenlist) return; /* Sort the list acfording to priority class */ LL_Sort (screenlist, compare_priority); f = LL_GetFirst(screenlist); /**** First we need to check out the current situation. ****/ /* Check whether there is an active screen */ s = screenlist_current (); if (!s) { /* We have no active screen yet. * Try to switch to the first screen in the list... */ s = f; if (!s) { /* There was no screen in the list */ return; } screenlist_switch (s); return; } else { /* There already was an active screen. * Check to see if it has an expiry time. If so, decrease it * and then check to see if it has expired. Remove the screen * if expired. */ if (s->timeout != -1) { --(s->timeout); report(RPT_DEBUG, "Active screen [%.40s] has timeout->%d", s->id, s->timeout); if (s->timeout <= 0) { /* Expired, we can destroy it */ report(RPT_DEBUG, "Removing expired screen [%.40s]", s->id); client_remove_screen (s->client, s); screen_destroy (s); } } } /**** OK, current situation examined. We can now see if we need to switch. */ /* Is there a screen of a higher priority class than the * current one ? */ if (f->priority > s->priority) { /* Yes, switch to that screen, job done */ screenlist_switch(f); return; } /* Current screen has been visible long enough and is it of 'normal' * priority ? */ if (autorotate && (timer - current_screen_start_time >= s->duration) && s->priority > PRI_BACKGROUND && s->priority <= PRI_FOREGROUND) { /* Ah, rotate! */ screenlist_goto_next(); } } void screenlist_switch (Screen * s) { Client * c; char str[256]; if (!s) return; report (RPT_DEBUG, "%s( s=[%.40s] )", __FUNCTION__, s->id ); if (s == current_screen) { /* Nothing to be done */ return; } if (current_screen) { c = current_screen->client; if (c) { /* Tell the client we're not listening any more...*/ snprintf (str, sizeof(str), "ignore %s\n", current_screen->id); sock_send_string (c->sock, str); } else { /* It's a server screen, no need to inform it. */ } } c = s->client; if (c) { /* Tell the client we're paying attention...*/ snprintf (str, sizeof(str), "listen %s\n", s->id); sock_send_string (c->sock, str); } else { /* It's a server screen, no need to inform it. */ } report (RPT_INFO, "%s: switched to screen [%.40s]", __FUNCTION__, s->id ); current_screen = s; current_screen_start_time = timer; } Screen * screenlist_current () { return current_screen; } int screenlist_goto_next () { Screen *s; debug (RPT_DEBUG, "%s()", __FUNCTION__); if (!current_screen) return -1; /* Find current screen in screenlist */ for( s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist) ); /* One step forward */ s = LL_GetNext(screenlist); if( !s || s->priority < current_screen->priority) { /* To far, go back to start of screenlist */ s = LL_GetFirst(screenlist); } screenlist_switch (s); return 0; } int screenlist_goto_prev () { Screen *s; debug (RPT_DEBUG, "%s()", __FUNCTION__); if (!current_screen) return -1; /* Find current screen in screenlist */ for( s = LL_GetFirst(screenlist); s && s != current_screen; s = LL_GetNext(screenlist) ); /* One step back */ s = LL_GetPrev(screenlist); if( !s ) { /* We're at the start of the screenlist. We should find the * last screen with the same priority as the first screen. */ Screen * f = LL_GetFirst(screenlist); Screen * n; s = f; while( (n = LL_GetNext(screenlist)) && n->priority == f->priority ) { s = n; } } screenlist_switch (s); return 0; } /* Internal function for sorting. */ int compare_priority (void *one, void *two) { Screen *a, *b; /*debug(RPT_DEBUG, "compare_priority: %8x %8x", one, two);*/ if (!one) return 0; if (!two) return 0; a = (Screen *) one; b = (Screen *) two; /*debug(RPT_DEBUG, "compare_priority: done?");*/ return (b->priority - a->priority); }