1 /*
2  * This file is part of g15daemon.
3  *
4  * g15daemon is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * g15daemon is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with g15daemon; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * (c) 2006-2021 Mike Lampard, Philip Lawatsch, Daniel Menelkir and others
19  *
20  * This daemon listens on localhost port 15550 for client connections,
21  * and arbitrates LCD display.  Allows for multiple simultaneous clients.
22  * Client screens can be cycled through by pressing the 'L1' key.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pthread.h>
28 #include <g15daemon.h>
29 #include <libg15.h>
30 
31 extern lcd_t *keyhandler;
32 extern unsigned int client_handles_keys;
33 extern plugin_info_t *generic_info;
34 
35 lcd_t static * ll_create_lcd () {
36 	lcd_t *lcd = g15daemon_xmalloc (sizeof (lcd_t));
37 	lcd->max_x = LCD_WIDTH;
38 	lcd->max_y = LCD_HEIGHT;
39 	lcd->backlight_state = G15_BRIGHTNESS_MEDIUM;
40 	lcd->mkey_state = 0;
41 	lcd->contrast_state = G15_CONTRAST_MEDIUM;
42 	lcd->state_changed = 1;
43 	lcd->usr_foreground = 0;
44 	lcd->g15plugin = g15daemon_xmalloc(sizeof (plugin_s));
45 	lcd->g15plugin->plugin_handle = NULL;
46 	lcd->g15plugin->info = (void*)&generic_info;
47 	return (lcd);
48 }
49 
50 static void ll_quit_lcd (lcd_t * lcd) {
51 	free (lcd->g15plugin);
52 	free (lcd);
53 }
54 
55 /* initialise a new masterlist, and add an initial node at the tail (used for the clock) */
56 g15daemon_t *ll_lcdlist_init () {
57 	g15daemon_t *masterlist = NULL;
58 	pthread_mutex_init(&lcdlist_mutex, NULL);
59 	pthread_mutex_lock(&lcdlist_mutex);
60 	masterlist = g15daemon_xmalloc(sizeof(g15daemon_t));
61 	masterlist->head = g15daemon_xmalloc(sizeof(lcdnode_t));
62 	masterlist->tail = masterlist->head;
63 	masterlist->current = masterlist->head;
64 	masterlist->head->lcd = ll_create_lcd();
65 	masterlist->head->lcd->mkey_state = 0;
66 	masterlist->head->lcd->masterlist = masterlist;
67 	/* first screen is the clock/menu */
68 	masterlist->head->lcd->g15plugin->info = NULL;
69 	masterlist->head->prev = masterlist->head;
70 	masterlist->head->next = masterlist->head;
71 	masterlist->head->list = masterlist;
72 	masterlist->keyboard_handler = NULL;
73 	masterlist->numclients = 0;
74 	pthread_mutex_unlock(&lcdlist_mutex);
75 	return masterlist;
76 }
77 
78 lcdnode_t *g15daemon_lcdnode_add(g15daemon_t **masterlist) {
79 	lcdnode_t *new = NULL;
80 	pthread_mutex_lock(&lcdlist_mutex);
81 	new = g15daemon_xmalloc(sizeof(lcdnode_t));
82 	new->prev = (*masterlist)->head;
83 	new->next = (*masterlist)->tail;
84 	new->lcd = ll_create_lcd();
85 	new->lcd->masterlist = (*masterlist);
86 	new->last_priority = NULL;
87 	new->list = *masterlist;
88 	(*masterlist)->head->next=new;
89 	(*masterlist)->current = new;
90 	(*masterlist)->head = new;
91 	(*masterlist)->head->list = *masterlist;
92 	(*masterlist)->numclients++;
93 	pthread_mutex_unlock(&lcdlist_mutex);
94 	return new;
95 }
96 
97 /* cycle through connected client displays */
98 void g15daemon_lcdnode_cycle(g15daemon_t *masterlist){
99 	lcdnode_t *current_screen = NULL;
100 	pthread_mutex_lock(&lcdlist_mutex);
101 	skip:
102 		current_screen = masterlist->current;
103 		g15daemon_send_event(current_screen->lcd, G15_EVENT_VISIBILITY_CHANGED, SCR_HIDDEN);
104 	do{
105 		masterlist->current->lcd->usr_foreground=0;
106 		if(masterlist->tail == masterlist->current){
107 			masterlist->current = masterlist->head;
108 		}
109 		else{
110 			masterlist->current = masterlist->current->prev;
111 		}
112 	}
113 	while (current_screen != masterlist->current);
114 	if(masterlist->tail == masterlist->current) {
115 		masterlist->current = masterlist->head;
116 	}
117 	else {
118 		masterlist->current = masterlist->current->prev;
119 	}
120 	if(masterlist->current->lcd->never_select==1) {
121 		goto skip;
122 	}
123 	masterlist->current->last_priority =  masterlist->current;
124 	pthread_mutex_unlock(&lcdlist_mutex);
125 	masterlist->current->lcd->usr_foreground=1;
126 	g15daemon_send_event(masterlist->current->lcd, G15_EVENT_VISIBILITY_CHANGED, SCR_VISIBLE);
127 }
128 
129 void g15daemon_lcdnode_remove (lcdnode_t *oldnode) {
130 	g15daemon_t **masterlist = NULL;
131 	lcdnode_t **prev = NULL;
132 	lcdnode_t **next = NULL;
133 	pthread_mutex_lock(&lcdlist_mutex);
134 	masterlist = &oldnode->list;
135 	prev = &oldnode->prev;
136 	next = &oldnode->next;
137 	ll_quit_lcd(oldnode->lcd);
138 	(*masterlist)->numclients--;
139 	if((*masterlist)->current == oldnode) {
140 		if((*masterlist)->current!=(*masterlist)->head){
141 			(*masterlist)->current = oldnode->next;
142 		}
143 		else {
144 			(*masterlist)->current = oldnode->prev;
145 		}
146 		(*masterlist)->current->lcd->state_changed = 1;
147 	}
148 	if(&oldnode->lcd == (void*)keyhandler) {
149 		client_handles_keys = 0;
150 		keyhandler = NULL;
151 		g15daemon_log(LOG_WARNING,"Client key handler quit, going back to defaults");
152 	}
153 	if((*masterlist)->head!=oldnode){
154 		(*next)->prev = oldnode->prev;
155 		(*prev)->next = oldnode->next;
156 	}
157 	else{
158 		(*prev)->next = (*masterlist)->tail;
159 		(*masterlist)->head = oldnode->prev;
160 	}
161 	g15daemon_send_refresh((*masterlist)->current->lcd);
162 	free(oldnode);
163 	pthread_mutex_unlock(&lcdlist_mutex);
164 }
165 
166 void ll_lcdlist_destroy(g15daemon_t **masterlist) {
167 	int i = 0;
168 	while ((*masterlist)->head != (*masterlist)->tail) {
169 		i++;
170 		g15daemon_lcdnode_remove((*masterlist)->head);
171 	}
172 	free((*masterlist)->tail->lcd);
173 	free((*masterlist)->tail);
174 	free(*masterlist);
175 	pthread_mutex_destroy(&lcdlist_mutex);
176 }
177 
178