Massive changes (first commit), including but not limited to:
* Ability to specify port and address to bind to * By default, binds only to 127.0.0.1 port 13666 * Client commands now return usage when no options given * New driver command: getinfo * Added comments all over the place * Used #defines to further document code * Used #defines to set up compile-time defaults, etc. * Cleaned up client command argument analysis in client_functions.c * Beginning support of syslog * Some bug fixes
This commit is contained in:
@@ -153,7 +153,7 @@ main (int argc, char **argv)
|
|||||||
usleep (500000); // wait for the server to start up
|
usleep (500000); // wait for the server to start up
|
||||||
sock = sock_connect (server, port);
|
sock = sock_connect (server, port);
|
||||||
if (sock <= 0) {
|
if (sock <= 0) {
|
||||||
printf ("Error connecting to server %s on port %i.\n", server, port);
|
printf ("Error connecting to LCD server %s on port %i.\nCheck to see that the server is running and operating normally.\n", server, port);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sock_send_string (sock, "hello\n");
|
sock_send_string (sock, "hello\n");
|
||||||
|
|||||||
+11
-5
@@ -16,6 +16,12 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "screenlist.h"
|
#include "screenlist.h"
|
||||||
|
|
||||||
|
#define ResetScreenList(a) LL_Rewind(a)
|
||||||
|
#define NewScreen LL_new
|
||||||
|
#define NextScreen(a) (screen *)LL_Get(a)
|
||||||
|
#define MoreScreens(a) (LL_Next(a) == 0)
|
||||||
|
#define DestroyScreenList(a) LL_Destroy(a)
|
||||||
|
|
||||||
int
|
int
|
||||||
client_data_init (client_data * d)
|
client_data_init (client_data * d)
|
||||||
{
|
{
|
||||||
@@ -26,7 +32,7 @@ client_data_init (client_data * d)
|
|||||||
d->name = NULL;
|
d->name = NULL;
|
||||||
d->client_keys = NULL;
|
d->client_keys = NULL;
|
||||||
|
|
||||||
d->screenlist = LL_new ();
|
d->screenlist = NewScreen();
|
||||||
if (!d->screenlist) {
|
if (!d->screenlist) {
|
||||||
fprintf (stderr, "client_data_init: Error allocating screenlist\n");
|
fprintf (stderr, "client_data_init: Error allocating screenlist\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -64,9 +70,9 @@ client_data_destroy (client_data * d)
|
|||||||
|
|
||||||
// Clean up the screenlist...
|
// Clean up the screenlist...
|
||||||
debug ("client_data_destroy: Cleaning screenlist\n");
|
debug ("client_data_destroy: Cleaning screenlist\n");
|
||||||
LL_Rewind (d->screenlist);
|
ResetScreenList (d->screenlist);
|
||||||
do {
|
do {
|
||||||
s = (screen *) LL_Get (d->screenlist);
|
s = NextScreen(d->screenlist);
|
||||||
if (s) {
|
if (s) {
|
||||||
debug ("client_data_destroy: removing screen %s\n", s->id);
|
debug ("client_data_destroy: removing screen %s\n", s->id);
|
||||||
|
|
||||||
@@ -80,8 +86,8 @@ client_data_destroy (client_data * d)
|
|||||||
// Free its memory...
|
// Free its memory...
|
||||||
screen_destroy (s);
|
screen_destroy (s);
|
||||||
}
|
}
|
||||||
} while (LL_Next (d->screenlist) == 0);
|
} while (MoreScreens(d->screenlist));
|
||||||
LL_Destroy (d->screenlist);
|
DestroyScreenList(d->screenlist);
|
||||||
|
|
||||||
// TODO: clean up the rest of the data...
|
// TODO: clean up the rest of the data...
|
||||||
|
|
||||||
|
|||||||
+474
-175
File diff suppressed because it is too large
Load Diff
+13
-9
@@ -15,7 +15,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "sock.h"
|
||||||
#include "clients.h"
|
#include "clients.h"
|
||||||
#include "client_data.h"
|
#include "client_data.h"
|
||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
@@ -40,7 +42,6 @@ client_init ()
|
|||||||
int
|
int
|
||||||
client_shutdown ()
|
client_shutdown ()
|
||||||
{
|
{
|
||||||
// TODO: Close all connections first...
|
|
||||||
client *c;
|
client *c;
|
||||||
|
|
||||||
debug ("client_shutdown()\n");
|
debug ("client_shutdown()\n");
|
||||||
@@ -52,7 +53,7 @@ client_shutdown ()
|
|||||||
debug ("client_shutdown: ...\n");
|
debug ("client_shutdown: ...\n");
|
||||||
if (c) {
|
if (c) {
|
||||||
debug ("client_shutdown: ... %i ...\n", c->sock);
|
debug ("client_shutdown: ... %i ...\n", c->sock);
|
||||||
if (0 != client_destroy (c)) {
|
if (client_destroy (c) != 0) {
|
||||||
fprintf (stderr, "client_shutdown: Error freeing client\n");
|
fprintf (stderr, "client_shutdown: Error freeing client\n");
|
||||||
} else {
|
} else {
|
||||||
debug ("client_shutdown: Freed client...\n");
|
debug ("client_shutdown: Freed client...\n");
|
||||||
@@ -70,6 +71,9 @@ client_shutdown ()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A client is identified by the file descriptor
|
||||||
|
// associated with it.
|
||||||
|
//
|
||||||
// Create and destroy clients....
|
// Create and destroy clients....
|
||||||
client *
|
client *
|
||||||
client_create (int sock)
|
client_create (int sock)
|
||||||
@@ -117,7 +121,6 @@ client_create (int sock)
|
|||||||
int
|
int
|
||||||
client_destroy (client * c)
|
client_destroy (client * c)
|
||||||
{
|
{
|
||||||
// TODO: Close the socket connection here?
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
char *str;
|
char *str;
|
||||||
@@ -136,17 +139,18 @@ client_destroy (client * c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close socket...
|
||||||
|
if (c->sock) {
|
||||||
|
// sock_send_string (c->sock, "bye\n");
|
||||||
|
close(c->sock);
|
||||||
|
syslog(LOG_NOTICE, "closed socket for #%d\n", c->sock);
|
||||||
|
}
|
||||||
|
|
||||||
err = LL_Destroy (c->messages);
|
err = LL_Destroy (c->messages);
|
||||||
|
|
||||||
// Free client's other data
|
// Free client's other data
|
||||||
client_data_destroy (c->data);
|
client_data_destroy (c->data);
|
||||||
|
|
||||||
/*
|
|
||||||
// FIXME? Should the connection get closed here or elsewhere?
|
|
||||||
if(c->sock) close(c->sock);
|
|
||||||
c->sock = 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Remove the client from the clients list...
|
// Remove the client from the clients list...
|
||||||
LL_Remove (clients, c);
|
LL_Remove (clients, c);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
typedef struct client {
|
typedef struct client {
|
||||||
int sock;
|
int sock;
|
||||||
|
char addr[64];
|
||||||
LL *messages;
|
LL *messages;
|
||||||
client_data *data;
|
client_data *data;
|
||||||
|
|
||||||
|
|||||||
+364
-84
@@ -1,10 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Matrix Orbital driver
|
||||||
|
*
|
||||||
|
* For the Matrix Orbital LCD* LKD* VFD* and VKD* displays
|
||||||
|
*
|
||||||
|
* September 16, 2001
|
||||||
|
*
|
||||||
|
* NOTE: GLK displays have a different driver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
@@ -16,6 +30,26 @@
|
|||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
#include "shared/str.h"
|
#include "shared/str.h"
|
||||||
|
|
||||||
|
#define DEFAULT_CONTRAST 140
|
||||||
|
#define DEFAULT_DEVICE "/dev/lcd"
|
||||||
|
#define DEFAULT_SPEED B19200
|
||||||
|
#define DEFAULT_LINEWRAP 1
|
||||||
|
#define DEFAULT_AUTOSCROLL 1
|
||||||
|
#define DEFAULT_CURSORBLINK 0
|
||||||
|
|
||||||
|
#define GENERIC (void *) -1
|
||||||
|
|
||||||
|
#define IS_LCD_DISPLAY (MtxOrb_type == MTXORB_LCD)
|
||||||
|
#define IS_LKD_DISPLAY (MtxOrb_type == MTXORB_LKD)
|
||||||
|
#define IS_VFD_DISPLAY (MtxOrb_type == MTXORB_VFD)
|
||||||
|
#define IS_VKD_DISPLAY (MtxOrb_type == MTXORB_VKD)
|
||||||
|
|
||||||
|
#define NotEnoughArgs (i + 1 > argc)
|
||||||
|
|
||||||
|
// NOTE: This does not appear to make use of the
|
||||||
|
// hbar and vbar functions present in the LKD202-25.
|
||||||
|
// Why I do not know.
|
||||||
|
|
||||||
static int custom = 0;
|
static int custom = 0;
|
||||||
static enum {MTXORB_LCD, MTXORB_LKD, MTXORB_VFD, MTXORB_VKD} MtxOrb_type;
|
static enum {MTXORB_LCD, MTXORB_LKD, MTXORB_VFD, MTXORB_VKD} MtxOrb_type;
|
||||||
|
|
||||||
@@ -65,25 +99,102 @@ static void MtxOrb_linewrap (int on);
|
|||||||
static void MtxOrb_autoscroll (int on);
|
static void MtxOrb_autoscroll (int on);
|
||||||
static void MtxOrb_cursorblink (int on);
|
static void MtxOrb_cursorblink (int on);
|
||||||
|
|
||||||
|
int
|
||||||
|
MtxOrb_set_type (char * str) {
|
||||||
|
char c;
|
||||||
|
c = str[0];
|
||||||
|
|
||||||
|
if (c == 'l') {
|
||||||
|
if (strcmp(str, "lcd") == 0) {
|
||||||
|
return MTXORB_LCD;
|
||||||
|
} else if (strcmp(str, "lkd") == 0) {
|
||||||
|
return MTXORB_LKD;
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str);
|
||||||
|
}
|
||||||
|
} else if (c == 'v') {
|
||||||
|
if (strcmp (str, "vfd") == 0) {
|
||||||
|
return MTXORB_VFD;
|
||||||
|
} else if (strcmp (str, "vkd") == 0) {
|
||||||
|
return MTXORB_VKD;
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MtxOrb_get_speed (char *arg) {
|
||||||
|
int speed;
|
||||||
|
|
||||||
|
switch (atoi(arg)) {
|
||||||
|
case 1200: speed = B1200; break;
|
||||||
|
case 2400: speed = B2400; break;
|
||||||
|
case 9600: speed = B9600; break;
|
||||||
|
case 19200: speed = B19200; break;
|
||||||
|
default:
|
||||||
|
speed = DEFAULT_SPEED;
|
||||||
|
fprintf (stderr, "MtxOrb_init: argument must be 1200, 2400, 9600 or 19200. Using default value");
|
||||||
|
switch (speed) {
|
||||||
|
case B1200: fprintf(stderr, " of 1200 baud.\n"); break;
|
||||||
|
case B2400: fprintf(stderr, " of 2400 baud.\n"); break;
|
||||||
|
case B9600: fprintf(stderr, " of 9600 baud.\n"); break;
|
||||||
|
case B19200: fprintf(stderr, " of 19200 baud.\n"); break;
|
||||||
|
default: fprintf(stderr, ".\n"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MtxOrb_usage (void) {
|
||||||
|
printf ("LCDproc Matrix-Orbital LCD driver\n"
|
||||||
|
"\t-d\t--device\tSelect the output device to use [/dev/lcd]\n"
|
||||||
|
// "\t-t\t--type\t\tSelect the LCD type (size) [20x4]\n"
|
||||||
|
// "\t-b\t--backlight\tSelect the backlight state [on]\n"
|
||||||
|
"\t-c\t--contrast\tSet the initial contrast [140]\n"
|
||||||
|
"\t-s\t--speed\t\tSet the communication speed [19200]\n"
|
||||||
|
"\t-h\t--help\t\tShow this help information\n"
|
||||||
|
"\t-t\t--type\t\tdisplay type: lcd, lkd, vfd, vkd\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MtxOrb_set_contrast (char * str) {
|
||||||
|
int contrast;
|
||||||
|
|
||||||
|
contrast = atoi (str);
|
||||||
|
if ((contrast < 0) || (contrast > 255)) {
|
||||||
|
fprintf(stderr, "MtxOrb_init: argument must between 0 and 255 (found %s). Using default contrast value of %d.\n", str, DEFAULT_CONTRAST);
|
||||||
|
contrast = DEFAULT_CONTRAST;
|
||||||
|
}
|
||||||
|
return contrast;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get rid of this variable?
|
// TODO: Get rid of this variable?
|
||||||
lcd_logical_driver *MtxOrb;
|
lcd_logical_driver *MtxOrb; // set by MtxOrb_init(); doesn't seem to be used anywhere
|
||||||
// TODO: Get the frame buffers working right
|
// TODO: Get the frame buffers working right
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Opens com port and sets baud correctly...
|
// Opens com port and sets baud correctly...
|
||||||
//
|
//
|
||||||
|
// Called to initialize driver settings
|
||||||
|
//
|
||||||
int
|
int
|
||||||
MtxOrb_init (lcd_logical_driver * driver, char *args)
|
MtxOrb_init (lcd_logical_driver * driver, char *args)
|
||||||
{
|
{
|
||||||
char *argv[64];
|
char *argv[64]; // Notice: 64 arguments - overflows?
|
||||||
int argc;
|
int argc;
|
||||||
struct termios portset;
|
struct termios portset;
|
||||||
int i;
|
int i;
|
||||||
int tmp;
|
int tmp;
|
||||||
|
|
||||||
int contrast = 140;
|
int contrast = DEFAULT_CONTRAST;
|
||||||
char device[256] = "/dev/lcd";
|
char device[256] = DEFAULT_DEVICE;
|
||||||
int speed = B19200;
|
int speed = DEFAULT_SPEED;
|
||||||
MtxOrb_type = MTXORB_LKD ; // Assume it's an LCD w/keypad
|
MtxOrb_type = MTXORB_LKD ; // Assume it's an LCD w/keypad
|
||||||
|
|
||||||
MtxOrb = driver;
|
MtxOrb = driver;
|
||||||
@@ -166,10 +277,19 @@ MtxOrb_init (lcd_logical_driver * driver, char *args)
|
|||||||
// Set up io port correctly, and open it...
|
// Set up io port correctly, and open it...
|
||||||
fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY);
|
fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fprintf (stderr, "MtxOrb_init: failed (%s)\n", strerror (errno));
|
switch (errno) {
|
||||||
return -1;
|
case ENOENT: fprintf(stderr, "MtxOrb_init: %s device file missing!\n", device);
|
||||||
|
break;
|
||||||
|
case EACCES: fprintf(stderr, "MtxOrb_init: %s device could not be opened...\n", device);
|
||||||
|
fprintf(stderr, "MtxOrb_init: perhaps you should run LCDd as root?\n");
|
||||||
|
break;
|
||||||
|
default: fprintf (stderr, "MtxOrb_init: failed (%s)\n", strerror (errno));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
//else fprintf(stderr, "MtxOrb_init: opened device %s\n", device);
|
return -1;
|
||||||
|
} else
|
||||||
|
syslog(LOG_INFO, "opened Matrix Orbital display on %s\n", device);
|
||||||
|
|
||||||
tcgetattr (fd, &portset);
|
tcgetattr (fd, &portset);
|
||||||
|
|
||||||
// We use RAW mode
|
// We use RAW mode
|
||||||
@@ -193,29 +313,32 @@ MtxOrb_init (lcd_logical_driver * driver, char *args)
|
|||||||
// Do it...
|
// Do it...
|
||||||
tcsetattr (fd, TCSANOW, &portset);
|
tcsetattr (fd, TCSANOW, &portset);
|
||||||
|
|
||||||
// Set display-specific stuff..
|
/*
|
||||||
MtxOrb_linewrap (1);
|
* Configure display
|
||||||
MtxOrb_autoscroll (1);
|
*/
|
||||||
MtxOrb_cursorblink (0);
|
|
||||||
|
MtxOrb_linewrap (DEFAULT_LINEWRAP);
|
||||||
|
MtxOrb_autoscroll (DEFAULT_AUTOSCROLL);
|
||||||
|
MtxOrb_cursorblink (DEFAULT_CURSORBLINK);
|
||||||
|
MtxOrb_contrast (contrast);
|
||||||
|
|
||||||
if (!driver->framebuf) {
|
if (!driver->framebuf) {
|
||||||
fprintf (stderr, "MtxOrb_init: No frame buffer.\n");
|
fprintf (stderr, "MtxOrb_init: No frame buffer.\n");
|
||||||
driver->close ();
|
driver->close ();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Set the functions the driver supports...
|
|
||||||
|
|
||||||
// driver->clear = (void *)-1;
|
/*
|
||||||
driver->clear = MtxOrb_clear;
|
* Configure the display functions
|
||||||
driver->string = (void *) -1;
|
*/
|
||||||
// driver->chr = MtxOrb_chr;
|
|
||||||
driver->chr = (void *) -1;
|
driver->clear = MtxOrb_clear; // was GENERIC
|
||||||
|
driver->string = GENERIC;
|
||||||
|
driver->chr = MtxOrb_chr; // was GENERIC
|
||||||
driver->vbar = MtxOrb_vbar;
|
driver->vbar = MtxOrb_vbar;
|
||||||
driver->init_vbar = MtxOrb_init_vbar;
|
driver->init_vbar = MtxOrb_init_vbar; // was GENERIC
|
||||||
// driver->init_vbar = (void *)-1;
|
|
||||||
driver->hbar = MtxOrb_hbar;
|
driver->hbar = MtxOrb_hbar;
|
||||||
driver->init_hbar = MtxOrb_init_hbar;
|
driver->init_hbar = MtxOrb_init_hbar; // was GENERIC
|
||||||
// driver->init_hbar = (void *)-1;
|
|
||||||
driver->num = MtxOrb_num;
|
driver->num = MtxOrb_num;
|
||||||
driver->init_num = MtxOrb_init_num;
|
driver->init_num = MtxOrb_init_num;
|
||||||
|
|
||||||
@@ -231,8 +354,7 @@ MtxOrb_init (lcd_logical_driver * driver, char *args)
|
|||||||
driver->draw_frame = MtxOrb_draw_frame;
|
driver->draw_frame = MtxOrb_draw_frame;
|
||||||
|
|
||||||
driver->getkey = MtxOrb_getkey;
|
driver->getkey = MtxOrb_getkey;
|
||||||
|
driver->getinfo = MtxOrb_getinfo;
|
||||||
MtxOrb_contrast (contrast);
|
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
@@ -243,11 +365,15 @@ MtxOrb_init (lcd_logical_driver * driver, char *args)
|
|||||||
// forget bar caracter not in use anymore and reuse the
|
// forget bar caracter not in use anymore and reuse the
|
||||||
// slot for another bar caracter.
|
// slot for another bar caracter.
|
||||||
//
|
//
|
||||||
|
// Why not just use Matrix Orbital's "clear screen" function or output a "^L"?
|
||||||
|
// This reliance on drv_base_clear seems suspicious... especially as
|
||||||
|
// using a (void *) -1 in the driver structure does the same thing...
|
||||||
|
//
|
||||||
void
|
void
|
||||||
MtxOrb_clear ()
|
MtxOrb_clear ()
|
||||||
{
|
{
|
||||||
// REMOVE: fprintf(stderr, "GLU: MtxOrb_clear.\n");
|
drv_base_clear (); // do we need this?
|
||||||
drv_base_clear ();
|
write(fd, "\x0FEX", 2); // instant clear...
|
||||||
clear = 1;
|
clear = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +406,7 @@ MtxOrb_flush_box (int lft, int top, int rgt, int bot)
|
|||||||
// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot);
|
// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot);
|
||||||
|
|
||||||
for (y = top; y <= bot; y++) {
|
for (y = top; y <= bot; y++) {
|
||||||
sprintf (out, "%cG%c%c", 254, lft, y);
|
sprintf (out, "\x0FEG%c%c", lft, y);
|
||||||
write (fd, out, 4);
|
write (fd, out, 4);
|
||||||
write (fd, lcd.framebuf + (y * lcd.wid) + lft, rgt - lft + 1);
|
write (fd, lcd.framebuf + (y * lcd.wid) + lft, rgt - lft + 1);
|
||||||
|
|
||||||
@@ -295,9 +421,25 @@ MtxOrb_flush_box (int lft, int top, int rgt, int bot)
|
|||||||
void
|
void
|
||||||
MtxOrb_chr (int x, int y, char c)
|
MtxOrb_chr (int x, int y, char c)
|
||||||
{
|
{
|
||||||
y--;
|
char out[10];
|
||||||
x--;
|
|
||||||
|
|
||||||
|
// validate x and y
|
||||||
|
if (y > lcd.hgt)
|
||||||
|
y = lcd.hgt;
|
||||||
|
if (x > lcd.wid)
|
||||||
|
x = lcd.wid;
|
||||||
|
if (y < 1)
|
||||||
|
y = 1;
|
||||||
|
if (x < 1)
|
||||||
|
x = 1;
|
||||||
|
|
||||||
|
// write immediately to screen... this code was taken
|
||||||
|
// from the LK202-25; should work for others, yes?
|
||||||
|
sprintf(out, "\x0FEG%c%c%c", x, y, c);
|
||||||
|
write (fd, out, 4);
|
||||||
|
|
||||||
|
// write to frame buffer
|
||||||
|
y--; x--;
|
||||||
lcd.framebuf[(y * lcd.wid) + x] = c;
|
lcd.framebuf[(y * lcd.wid) + x] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,34 +452,48 @@ int
|
|||||||
MtxOrb_contrast (int contrast)
|
MtxOrb_contrast (int contrast)
|
||||||
{
|
{
|
||||||
char out[4];
|
char out[4];
|
||||||
static int status = 140;
|
|
||||||
|
|
||||||
if ( ((MtxOrb_type == MTXORB_LCD) || (MtxOrb_type == MTXORB_LKD)) &&
|
// validate contrast value
|
||||||
(contrast > 0) ) {
|
if (contrast > 255)
|
||||||
status = contrast;
|
contrast = 255;
|
||||||
sprintf (out, "%cP%c", 254, status);
|
if (contrast < 0)
|
||||||
|
contrast = 0;
|
||||||
|
|
||||||
|
if (IS_LCD_DISPLAY || IS_LKD_DISPLAY) {
|
||||||
|
sprintf (out, "\x0FEP%c", contrast);
|
||||||
write (fd, out, 3);
|
write (fd, out, 3);
|
||||||
}
|
}
|
||||||
|
return contrast;
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Sets the backlight on or off -- can be done quickly for
|
// Sets the backlight on or off -- can be done quickly for
|
||||||
// an intermediate brightness...
|
// an intermediate brightness...
|
||||||
// WARN: off switches vfd/vkd displays off
|
|
||||||
// -> so it's maybe the best to start LCDd with -b on
|
|
||||||
//
|
//
|
||||||
|
// WARNING: off switches vfd/vkd displays off entirely
|
||||||
|
// so maybe it is best to start LCDd with -b on
|
||||||
|
//
|
||||||
|
// WARNING: there seems to be a movement afoot to add more
|
||||||
|
// functions than just on/off to this..
|
||||||
|
|
||||||
|
#define BACKLIGHT_OFF 0
|
||||||
|
#define BACKLIGHT_ON 1
|
||||||
|
|
||||||
void
|
void
|
||||||
MtxOrb_backlight (int on)
|
MtxOrb_backlight (int on)
|
||||||
{
|
{
|
||||||
char out[4];
|
switch (on) {
|
||||||
if (on) {
|
case BACKLIGHT_ON:
|
||||||
sprintf (out, "%cB%c", 254, 0);
|
write (fd, "\x0FE" "F", 2);
|
||||||
write (fd, out, 3);
|
break;
|
||||||
} else {
|
case BACKLIGHT_OFF:
|
||||||
sprintf (out, "%cF", 254);
|
if (IS_VKD_DISPLAY || IS_VFD_DISPLAY)
|
||||||
write (fd, out, 2);
|
; // turns display off entirely (whoops!)
|
||||||
|
else
|
||||||
|
write (fd, "\x0FE" "B" "\x000", 3);
|
||||||
|
break;
|
||||||
|
default: // ignored...
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,21 +506,24 @@ void
|
|||||||
MtxOrb_output (int on)
|
MtxOrb_output (int on)
|
||||||
{
|
{
|
||||||
char out[5];
|
char out[5];
|
||||||
if ( ((MtxOrb_type == MTXORB_LCD) || (MtxOrb_type == MTXORB_VFD)) ) {
|
|
||||||
if (on) {
|
if (IS_LCD_DISPLAY || IS_VFD_DISPLAY) {
|
||||||
sprintf (out, "%cW", 254);
|
// LCD and VFD displays only have one output port
|
||||||
} else {
|
(on) ?
|
||||||
sprintf (out, "%cV", 254);
|
write (fd, "\x0FEW", 2) :
|
||||||
}
|
write (fd, "\x0FEV", 2);
|
||||||
write (fd, out, 2);
|
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<6; i++) {
|
|
||||||
if ( on & (1 << i) ) {
|
// Other displays have six output ports;
|
||||||
sprintf (out, "%cW%c", 254, i+1);
|
// the value "on" is a binary value determining which
|
||||||
} else {
|
// ports are turned on (1) and off (0).
|
||||||
sprintf (out, "%cV%c", 254, i+1);
|
|
||||||
}
|
on = on & 077; // strip to six bits
|
||||||
|
for(i = 0; i < 6; i++) {
|
||||||
|
(on & (1 << i)) ?
|
||||||
|
sprintf (out, "\x0FEW%c", i + 1) :
|
||||||
|
sprintf (out, "\x0FEV%c", i + 1);
|
||||||
write (fd, out, 3);
|
write (fd, out, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,12 +535,7 @@ MtxOrb_output (int on)
|
|||||||
static void
|
static void
|
||||||
MtxOrb_linewrap (int on)
|
MtxOrb_linewrap (int on)
|
||||||
{
|
{
|
||||||
char out[4];
|
(on) ? write (fd, "\x0FE" "C", 2) : write (fd, "\x0FE" "D", 2);
|
||||||
if (on)
|
|
||||||
sprintf (out, "%cC", 254);
|
|
||||||
else
|
|
||||||
sprintf (out, "%cD", 254);
|
|
||||||
write (fd, out, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
@@ -390,12 +544,7 @@ MtxOrb_linewrap (int on)
|
|||||||
static void
|
static void
|
||||||
MtxOrb_autoscroll (int on)
|
MtxOrb_autoscroll (int on)
|
||||||
{
|
{
|
||||||
char out[4];
|
(on) ? write (fd, "\x0FEQ", 2) : write (fd, "\x0FER", 2);
|
||||||
if (on)
|
|
||||||
sprintf (out, "%cQ", 254);
|
|
||||||
else
|
|
||||||
sprintf (out, "%cR", 254);
|
|
||||||
write (fd, out, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make sure this doesn't mess up non-VFD displays
|
// TODO: make sure this doesn't mess up non-VFD displays
|
||||||
@@ -405,12 +554,7 @@ MtxOrb_autoscroll (int on)
|
|||||||
static void
|
static void
|
||||||
MtxOrb_cursorblink (int on)
|
MtxOrb_cursorblink (int on)
|
||||||
{
|
{
|
||||||
char out[4];
|
(on) ? write (fd, "\x0FES", 2) : write (fd, "\x0FET", 2);
|
||||||
if (on)
|
|
||||||
sprintf (out, "%cS", 254);
|
|
||||||
else
|
|
||||||
sprintf (out, "%cT", 254);
|
|
||||||
write (fd, out, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//// TODO: Might not be needed anymore...
|
//// TODO: Might not be needed anymore...
|
||||||
@@ -420,6 +564,7 @@ MtxOrb_cursorblink (int on)
|
|||||||
void
|
void
|
||||||
MtxOrb_init_vbar ()
|
MtxOrb_init_vbar ()
|
||||||
{
|
{
|
||||||
|
// Isn't this function supposed to go away?
|
||||||
MtxOrb_init_all (vbar);
|
MtxOrb_init_all (vbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,9 +575,132 @@ MtxOrb_init_vbar ()
|
|||||||
void
|
void
|
||||||
MtxOrb_init_hbar ()
|
MtxOrb_init_hbar ()
|
||||||
{
|
{
|
||||||
|
// Isn't this function supposed to go away?
|
||||||
MtxOrb_init_all (hbar);
|
MtxOrb_init_all (hbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Returns string with general information about the display
|
||||||
|
//
|
||||||
|
char *
|
||||||
|
MtxOrb_getinfo (void)
|
||||||
|
{
|
||||||
|
char in = 0;
|
||||||
|
static char info[255];
|
||||||
|
char tmp[255], buf[64];
|
||||||
|
int i = 0;
|
||||||
|
fd_set rfds;
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
memset(info, '\0', sizeof(info));
|
||||||
|
strcpy(info, "Matrix Orbital Driver ");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read type of display
|
||||||
|
*/
|
||||||
|
|
||||||
|
write(fd, "\x0FE" "7", 2);
|
||||||
|
|
||||||
|
/* Watch fd to see when it has input. */
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(fd, &rfds);
|
||||||
|
|
||||||
|
/* Wait the specified amount of time. */
|
||||||
|
tv.tv_sec = 0; // seconds
|
||||||
|
tv.tv_usec = 500; // microseconds
|
||||||
|
|
||||||
|
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||||
|
|
||||||
|
if (retval) {
|
||||||
|
if (read (fd, &in, 1) < 0) {
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data");
|
||||||
|
} else {
|
||||||
|
switch (in) {
|
||||||
|
case '\x01': strcat(info, "LCD0821 "); break;
|
||||||
|
case '\x03': strcat(info, "LCD2021 "); break;
|
||||||
|
case '\x04': strcat(info, "LCD1641 "); break;
|
||||||
|
case '\x05': strcat(info, "LCD2041 "); break;
|
||||||
|
case '\x06': strcat(info, "LCD4021 "); break;
|
||||||
|
case '\x07': strcat(info, "LCD4041 "); break;
|
||||||
|
case '\x08': strcat(info, "LK202-25 "); break;
|
||||||
|
case '\x09': strcat(info, "LK204-25 "); break;
|
||||||
|
case '\x0A': strcat(info, "LK404-55 "); break;
|
||||||
|
case '\x0B': strcat(info, "VFD2021 "); break;
|
||||||
|
case '\x0C': strcat(info, "VFD2041 "); break;
|
||||||
|
case '\x0D': strcat(info, "VFD4021 "); break;
|
||||||
|
case '\x0E': strcat(info, "VK202-25 "); break;
|
||||||
|
case '\x0F': strcat(info, "VK204-25 "); break;
|
||||||
|
case '\x10': strcat(info, "GLC12232 "); break;
|
||||||
|
case '\x11': strcat(info, "GLC12864 "); break;
|
||||||
|
case '\x12': strcat(info, "GLC128128 "); break;
|
||||||
|
case '\x13': strcat(info, "GLC24064 "); break;
|
||||||
|
case '\x14': strcat(info, "GLK12864-25 "); break;
|
||||||
|
case '\x15': strcat(info, "GLK24064-25 "); break;
|
||||||
|
case '\x21': strcat(info, "GLK128128-25 "); break;
|
||||||
|
case '\x22': strcat(info, "GLK12232-25 "); break;
|
||||||
|
case '\x31': strcat(info, "LK404-AT "); break;
|
||||||
|
case '\x32': strcat(info, "VFD1621 "); break;
|
||||||
|
case '\x33': strcat(info, "LK402-12 "); break;
|
||||||
|
case '\x34': strcat(info, "LK162-12 "); break;
|
||||||
|
case '\x35': strcat(info, "LK204-25PC "); break;
|
||||||
|
default: //sprintf(tmp, "Unknown (%X) ", in); strcat(info, tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device type");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read serial number of display
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(tmp, '\0', sizeof(tmp));
|
||||||
|
write(fd, "\x0FE" "5", 2);
|
||||||
|
|
||||||
|
/* Wait the specified amount of time. */
|
||||||
|
tv.tv_sec = 0; // seconds
|
||||||
|
tv.tv_usec = 500; // microseconds
|
||||||
|
|
||||||
|
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||||
|
|
||||||
|
if (retval) {
|
||||||
|
if (read (fd, &tmp, 2) < 0) {
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data");
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "Serial No: %ld ", (long int) tmp);
|
||||||
|
strcat(info, buf);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device serial number");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read firmware revision number
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(tmp, '\0', sizeof(tmp));
|
||||||
|
write(fd, "\x0FE" "6", 2);
|
||||||
|
|
||||||
|
/* Wait the specified amount of time. */
|
||||||
|
tv.tv_sec = 0; // seconds
|
||||||
|
tv.tv_usec = 500; // microseconds
|
||||||
|
|
||||||
|
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||||
|
|
||||||
|
if (retval) {
|
||||||
|
if (read (fd, &tmp, 2) < 0) {
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data");
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "Firmware Rev. %ld ", (long int) tmp);
|
||||||
|
strcat(info, buf);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device firmware revision");
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Finish the support for bar growing reverse way.
|
// TODO: Finish the support for bar growing reverse way.
|
||||||
// TODO: Need a "y" as input also !!!
|
// TODO: Need a "y" as input also !!!
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
@@ -447,9 +715,9 @@ MtxOrb_vbar (int x, int len)
|
|||||||
|
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
// TODO: REMOVE THE NEXT LINE FOR TESTING ONLY...
|
// REMOVE THE NEXT LINE FOR TESTING ONLY...
|
||||||
// len=-len;
|
// len=-len;
|
||||||
// TODO: REMOVE THE PREVIOUS LINE FOR TESTING ONLY...
|
// REMOVE THE PREVIOUS LINE FOR TESTING ONLY...
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
for (y = lcd.hgt; y > 0 && len > 0; y--) {
|
for (y = lcd.hgt; y > 0 && len > 0; y--) {
|
||||||
@@ -518,10 +786,8 @@ MtxOrb_hbar (int x, int y, int len)
|
|||||||
void
|
void
|
||||||
MtxOrb_init_num ()
|
MtxOrb_init_num ()
|
||||||
{
|
{
|
||||||
char out[3];
|
|
||||||
if (custom != bign) {
|
if (custom != bign) {
|
||||||
sprintf (out, "%cn", 254);
|
write (fd, "\x0FEn", 2);
|
||||||
write (fd, out, 2);
|
|
||||||
custom = bign;
|
custom = bign;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -535,7 +801,7 @@ void
|
|||||||
MtxOrb_num (int x, int num)
|
MtxOrb_num (int x, int num)
|
||||||
{
|
{
|
||||||
char out[5];
|
char out[5];
|
||||||
sprintf (out, "%c#%c%c", 254, x, num);
|
sprintf (out, "\x0FE#%c%c", x, num);
|
||||||
write (fd, out, 4);
|
write (fd, out, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +826,7 @@ MtxOrb_set_char (int n, char *dat)
|
|||||||
if (!dat)
|
if (!dat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sprintf (out, "%cN%c", 254, n);
|
sprintf (out, "\x0FEN%c", n);
|
||||||
write (fd, out, 3);
|
write (fd, out, 3);
|
||||||
|
|
||||||
for (row = 0; row < lcd.cellhgt; row++) {
|
for (row = 0; row < lcd.cellhgt; row++) {
|
||||||
@@ -636,7 +902,7 @@ MtxOrb_draw_frame (char *dat)
|
|||||||
write(fd, dat, lcd.wid*lcd.hgt);
|
write(fd, dat, lcd.wid*lcd.hgt);
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < lcd.hgt; i++) {
|
for (i = 0; i < lcd.hgt; i++) {
|
||||||
sprintf (out, "%cG%c%c", 254, 1, i + 1);
|
sprintf (out, "\x0FEG\x001%c", i + 1);
|
||||||
write (fd, out, 4);
|
write (fd, out, 4);
|
||||||
write (fd, dat + (lcd.wid * i), lcd.wid);
|
write (fd, dat + (lcd.wid * i), lcd.wid);
|
||||||
}
|
}
|
||||||
@@ -650,6 +916,7 @@ char
|
|||||||
MtxOrb_getkey ()
|
MtxOrb_getkey ()
|
||||||
{
|
{
|
||||||
char in = 0;
|
char in = 0;
|
||||||
|
|
||||||
read (fd, &in, 1);
|
read (fd, &in, 1);
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
@@ -802,6 +1069,17 @@ MtxOrb_ask_bar (int type)
|
|||||||
return (pos);
|
return (pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Does the heartbeat...
|
||||||
|
//
|
||||||
|
char
|
||||||
|
MtxOrb_heartbeat (int timer)
|
||||||
|
{
|
||||||
|
MtxOrb_icon (!((timer + 4) & 5), 0);
|
||||||
|
MtxOrb_chr (lcd.wid, 1, 0);
|
||||||
|
return (char) 0;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Sets up a well known character for use.
|
// Sets up a well known character for use.
|
||||||
//
|
//
|
||||||
@@ -1044,6 +1322,8 @@ MtxOrb_set_known_char (int car, int type)
|
|||||||
|
|
||||||
// TODO: Remove this code wich was use for developpement.
|
// TODO: Remove this code wich was use for developpement.
|
||||||
// PS: There might be reference to this code left, so keep it for some time.
|
// PS: There might be reference to this code left, so keep it for some time.
|
||||||
|
//
|
||||||
|
// MtxOrb_init_hbar and MtxOrb_init_vbar use it; it's prototyped in MtxOrb.h ...
|
||||||
void
|
void
|
||||||
MtxOrb_init_all (int type)
|
MtxOrb_init_all (int type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ void MtxOrb_set_char (int n, char *dat);
|
|||||||
void MtxOrb_icon (int which, char dest);
|
void MtxOrb_icon (int which, char dest);
|
||||||
void MtxOrb_draw_frame (char *dat);
|
void MtxOrb_draw_frame (char *dat);
|
||||||
char MtxOrb_getkey ();
|
char MtxOrb_getkey ();
|
||||||
|
char * MtxOrb_getinfo ();
|
||||||
|
|
||||||
void MtxOrb_init_all (int type);
|
|
||||||
int MtxOrb_ask_bar (int type);
|
int MtxOrb_ask_bar (int type);
|
||||||
void MtxOrb_set_known_char (int car, int type);
|
void MtxOrb_set_known_char (int car, int type);
|
||||||
|
|
||||||
|
// Isn't this function supposed to go away?
|
||||||
|
void MtxOrb_init_all (int type);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+17
-4
@@ -1,3 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Joystick input driver for LCDd
|
||||||
|
*
|
||||||
|
* Only two unique functions are defined:
|
||||||
|
*
|
||||||
|
* joy_getkey
|
||||||
|
* joy_close
|
||||||
|
*
|
||||||
|
* All others are at their defaults.
|
||||||
|
*
|
||||||
|
* The code here is configured for a Gravis Gamepad (2 axis, 4 button)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -9,6 +23,9 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <linux/joystick.h>
|
#include <linux/joystick.h>
|
||||||
|
#ifndef JSIOCGNAME
|
||||||
|
#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
#include "shared/str.h"
|
#include "shared/str.h"
|
||||||
@@ -18,10 +35,6 @@
|
|||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
#include "joy.h"
|
#include "joy.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////////////////////// Base "class" to derive from ///////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
lcd_logical_driver *joy;
|
lcd_logical_driver *joy;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|||||||
+59
-1
@@ -11,6 +11,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "shared/LL.h"
|
#include "shared/LL.h"
|
||||||
|
#include "shared/debug.h"
|
||||||
|
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
|
||||||
@@ -68,6 +69,15 @@
|
|||||||
#include "glk.h"
|
#include "glk.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Make program more readable and understandable;
|
||||||
|
// hide details...
|
||||||
|
#define ResetList(a) LL_Rewind(a)
|
||||||
|
#define GetDriverData(a) ((lcd_logical_driver *)LL_Get(a))
|
||||||
|
#define NextDriver(a) (LL_Next(a))
|
||||||
|
#define MoreDrivers(a) (LL_Next(a) == 0)
|
||||||
|
#define DriverPresent(a) (a)
|
||||||
|
#define FunctionPresent(a) ((a) != 0)
|
||||||
|
|
||||||
// TODO: Make a Windows server, and clients...?
|
// TODO: Make a Windows server, and clients...?
|
||||||
|
|
||||||
lcd_logical_driver lcd;
|
lcd_logical_driver lcd;
|
||||||
@@ -120,7 +130,9 @@ lcd_physical_driver drivers[] = {
|
|||||||
LL *list;
|
LL *list;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// This sets up which driver to use and initializes stuff.
|
// This function initializes a few basics as well as the
|
||||||
|
// "base" array. To initialize a specific driver, use the
|
||||||
|
// lcd_add_driver() function.
|
||||||
//
|
//
|
||||||
int
|
int
|
||||||
lcd_init (char *args)
|
lcd_init (char *args)
|
||||||
@@ -134,8 +146,12 @@ lcd_init (char *args)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This sets up functions which call all drivers in
|
||||||
|
// round-robin fashion
|
||||||
lcd_drv_init (NULL, NULL);
|
lcd_drv_init (NULL, NULL);
|
||||||
|
|
||||||
|
// "base" driver is a special driver which is always
|
||||||
|
// loaded...
|
||||||
err = lcd_add_driver ("base", args);
|
err = lcd_add_driver ("base", args);
|
||||||
|
|
||||||
lcd.wid = 20;
|
lcd.wid = 20;
|
||||||
@@ -162,6 +178,10 @@ lcd_init (char *args)
|
|||||||
|
|
||||||
// TODO: lcd_remove_driver()
|
// TODO: lcd_remove_driver()
|
||||||
|
|
||||||
|
// This initializes the specified driver and sends parameters to
|
||||||
|
// it. This is the function which calls, for example,
|
||||||
|
// MtxOrb_init. The specifics come from the drivers[] array.
|
||||||
|
//
|
||||||
int
|
int
|
||||||
lcd_add_driver (char *driver, char *args)
|
lcd_add_driver (char *driver, char *args)
|
||||||
{
|
{
|
||||||
@@ -177,6 +197,8 @@ lcd_add_driver (char *driver, char *args)
|
|||||||
|
|
||||||
//printf("Found driver: %s (%s)\n", drivers[i].name, driver);
|
//printf("Found driver: %s (%s)\n", drivers[i].name, driver);
|
||||||
|
|
||||||
|
// This creates an instance of the lcd structure specific to the
|
||||||
|
// driver... it is passed to the driver's init routine...
|
||||||
add = malloc (sizeof (lcd_logical_driver));
|
add = malloc (sizeof (lcd_logical_driver));
|
||||||
if (!add) {
|
if (!add) {
|
||||||
printf ("Couldn't allocate driver \"%s\".\n", driver);
|
printf ("Couldn't allocate driver \"%s\".\n", driver);
|
||||||
@@ -204,6 +226,7 @@ lcd_add_driver (char *driver, char *args)
|
|||||||
|
|
||||||
LL_Push (list, (void *) add);
|
LL_Push (list, (void *) add);
|
||||||
|
|
||||||
|
// This is where the driver itself is actually called;
|
||||||
return drivers[i].init (add, args);
|
return drivers[i].init (add, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,6 +264,9 @@ lcd_shutdown ()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This sets up all of the "wrapper" driver functions
|
||||||
|
// which call all of the drivers in turn.
|
||||||
|
//
|
||||||
int
|
int
|
||||||
lcd_drv_init (struct lcd_logical_driver *driver, char *args)
|
lcd_drv_init (struct lcd_logical_driver *driver, char *args)
|
||||||
{
|
{
|
||||||
@@ -290,6 +316,7 @@ lcd_drv_init (struct lcd_logical_driver *driver, char *args)
|
|||||||
lcd.draw_frame = lcd_drv_draw_frame;
|
lcd.draw_frame = lcd_drv_draw_frame;
|
||||||
|
|
||||||
lcd.getkey = lcd_drv_getkey;
|
lcd.getkey = lcd_drv_getkey;
|
||||||
|
lcd.getinfo = lcd_drv_getinfo;
|
||||||
|
|
||||||
return 1; // 1 is arbitrary. (must be 1 or more)
|
return 1; // 1 is arbitrary. (must be 1 or more)
|
||||||
}
|
}
|
||||||
@@ -713,3 +740,34 @@ lcd_drv_getkey ()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_INFO_BUF 1024
|
||||||
|
|
||||||
|
char *
|
||||||
|
lcd_drv_getinfo ()
|
||||||
|
{
|
||||||
|
static char info[MAX_INFO_BUF];
|
||||||
|
char *p;
|
||||||
|
lcd_logical_driver *driver;
|
||||||
|
|
||||||
|
memset(info, '\0', sizeof(info));
|
||||||
|
|
||||||
|
ResetList(list);
|
||||||
|
do {
|
||||||
|
driver = GetDriverData(list);
|
||||||
|
|
||||||
|
if (DriverPresent(driver)) {
|
||||||
|
if (FunctionPresent(driver->getinfo)) {
|
||||||
|
p = (char *) driver->getinfo ();
|
||||||
|
if (strlen(p) + strlen(info) < (MAX_INFO_BUF - 2)) {
|
||||||
|
strcat(info, p);
|
||||||
|
}
|
||||||
|
strcat(info, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (MoreDrivers(list));
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ typedef struct lcd_logical_driver {
|
|||||||
// Returns 0 for "no key pressed", or (A-Z).
|
// Returns 0 for "no key pressed", or (A-Z).
|
||||||
char (*getkey) ();
|
char (*getkey) ();
|
||||||
|
|
||||||
|
// Returns pointer to static string.
|
||||||
|
char * (*getinfo) ();
|
||||||
|
|
||||||
// more?
|
// more?
|
||||||
|
|
||||||
} lcd_logical_driver;
|
} lcd_logical_driver;
|
||||||
@@ -83,5 +86,6 @@ void lcd_drv_icon (int which, char dest);
|
|||||||
void lcd_drv_flush_box (int lft, int top, int rgt, int bot);
|
void lcd_drv_flush_box (int lft, int top, int rgt, int bot);
|
||||||
void lcd_drv_draw_frame ();
|
void lcd_drv_draw_frame ();
|
||||||
char lcd_drv_getkey ();
|
char lcd_drv_getkey ();
|
||||||
|
char *lcd_drv_getinfo ();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+95
-30
@@ -24,9 +24,49 @@
|
|||||||
E-Z Ignored
|
E-Z Ignored
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// These are the keys for a (likely) properly functioning LK202-25...
|
||||||
|
// #define KEY_UP 'I'
|
||||||
|
// #define KEY_DOWN 'J'
|
||||||
|
// #define KEY_LEFT 'O'
|
||||||
|
// #define KEY_RIGHT 'E'
|
||||||
|
// #define KEY_F1 'N'
|
||||||
|
// #define KEY_F2 'M'
|
||||||
|
// #define KEY_ENTER 'H'
|
||||||
|
|
||||||
|
// These are the keys for my (possibly) broken LK202-25...
|
||||||
|
#define KEY_UP 'I'
|
||||||
|
#define KEY_DOWN 'F'
|
||||||
|
#define KEY_LEFT 'K'
|
||||||
|
#define KEY_RIGHT 'A'
|
||||||
|
#define KEY_F1 'N'
|
||||||
|
// #define KEY_F2 'M'
|
||||||
|
// #define KEY_ENTER 'H'
|
||||||
|
|
||||||
|
// TODO: Generalize these into each driver...
|
||||||
|
//
|
||||||
|
// Really, what this comes down to, is different settings for
|
||||||
|
// different displays. Unless you want to recompile for all
|
||||||
|
// the defaults, these key settings must be in the driver.
|
||||||
|
//
|
||||||
|
// But then, which driver is active and which screen takes which
|
||||||
|
// input and... (sigh).
|
||||||
|
//
|
||||||
|
#define PAUSE_KEY KEY_F1
|
||||||
|
#define BACK_KEY KEY_LEFT
|
||||||
|
#define FORWARD_KEY KEY_RIGHT
|
||||||
|
#define MAIN_MENU_KEY KEY_DOWN
|
||||||
|
|
||||||
|
// This seems somewhat arbitrary, but it IS the original settings:
|
||||||
|
//
|
||||||
|
// #define PAUSE_KEY 'A'
|
||||||
|
// #define BACK_KEY 'B'
|
||||||
|
// #define FORWARD_KEY 'C'
|
||||||
|
// #define MAIN_MENU_KEY 'D'
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "shared/sockets.h"
|
#include "shared/sockets.h"
|
||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
@@ -42,6 +82,11 @@
|
|||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
|
#define KeyWanted(a,b) ((a) && strchr((a), (b)))
|
||||||
|
#define CurrentScreen screenlist_current
|
||||||
|
#define FirstClient(a) (client *)LL_GetFirst(a);
|
||||||
|
#define NextClient(a) (client *)LL_GetNext(a);
|
||||||
|
|
||||||
int server_input (int key);
|
int server_input (int key);
|
||||||
|
|
||||||
// FIXME! The server tends to crash when "E" is pressed.. (?!)
|
// FIXME! The server tends to crash when "E" is pressed.. (?!)
|
||||||
@@ -51,46 +96,65 @@ int server_input (int key);
|
|||||||
int
|
int
|
||||||
handle_input ()
|
handle_input ()
|
||||||
{
|
{
|
||||||
char str[256];
|
char str[15];
|
||||||
int key;
|
int key;
|
||||||
screen *s;
|
screen *s;
|
||||||
widget *w;
|
widget *w;
|
||||||
client *c;
|
client *c;
|
||||||
|
|
||||||
key = lcd.getkey ();
|
if ((key = lcd.getkey ()) == 0)
|
||||||
|
|
||||||
if (!key)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
debug ("handle_input(%c)\n", (char) key);
|
//debug ("handle_input(%c)\n", (char) key);
|
||||||
|
|
||||||
|
// Sequence:
|
||||||
|
// Does the current screen want the key?
|
||||||
|
// IfTrue: handle and quit
|
||||||
|
// IfFalse:
|
||||||
|
// Let ALL clients handle it if they want
|
||||||
|
// Let Server handle it, too
|
||||||
|
//
|
||||||
|
// This leads to a unique situation:
|
||||||
|
// First: multiple clients may handle the same key in multiple ways
|
||||||
|
// Second: the server may handle the key differently yet
|
||||||
|
//
|
||||||
|
// Solution: Only the current screen can handle the key press.
|
||||||
|
// Alternately, only one client can handle the key press.
|
||||||
|
|
||||||
if (key) {
|
|
||||||
// TODO: Interpret and translate keys!
|
// TODO: Interpret and translate keys!
|
||||||
|
|
||||||
// Give current screen a shot at the key first
|
// Give current screen a shot at the key first
|
||||||
s = screenlist_current ();
|
s = CurrentScreen ();
|
||||||
if( s->keys && strchr( s->keys, key ) ) {
|
|
||||||
|
if (KeyWanted(s->keys, key)) {
|
||||||
// This screen wants this key. Tell it we got one
|
// This screen wants this key. Tell it we got one
|
||||||
sprintf(str, "key %c\n", key);
|
snprintf(str, sizeof(str), "key %c\n", key);
|
||||||
sock_send_string(s->parent->sock, str);
|
sock_send_string(s->parent->sock, str);
|
||||||
// Nobody else gets this key
|
// Nobody else gets this key
|
||||||
} else {
|
|
||||||
// Give key to clients who want it
|
|
||||||
c = (client *)LL_GetFirst(clients);
|
|
||||||
while(c) {
|
|
||||||
// If the client should have this keypress...
|
|
||||||
if( c->data->client_keys && strchr(c->data->client_keys, key) ) {
|
|
||||||
// Send keypress to client
|
|
||||||
sprintf(str, "key %c\n", key);
|
|
||||||
sock_send_string(c->sock, str);
|
|
||||||
};
|
|
||||||
c = (client *)LL_GetNext(clients);
|
|
||||||
} // while clients
|
|
||||||
|
|
||||||
// Give server a shot at all keys
|
|
||||||
server_input (key);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
// if the current screen doesn't want it,
|
||||||
|
// ignore the key...
|
||||||
|
|
||||||
|
// else {
|
||||||
|
// // Give key to clients who want it
|
||||||
|
//
|
||||||
|
// c = FirstClient(clients);
|
||||||
|
//
|
||||||
|
// while (c) {
|
||||||
|
// // If the client should have this keypress...
|
||||||
|
// if(KeyWanted(c->data->client_keys,key)) {
|
||||||
|
// // Send keypress to client
|
||||||
|
// snprintf(str, sizeof(str), "key %c\n", key);
|
||||||
|
// sock_send_string(c->sock, str);
|
||||||
|
// break; // first come, first serve
|
||||||
|
// };
|
||||||
|
// c = NextClient(clients);
|
||||||
|
// } // while clients
|
||||||
|
//
|
||||||
|
// // Give server a shot at all keys
|
||||||
|
// server_input (key);
|
||||||
|
// }
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -99,23 +163,24 @@ int
|
|||||||
server_input (int key)
|
server_input (int key)
|
||||||
{
|
{
|
||||||
debug ("server_input(%c)\n", (char) key);
|
debug ("server_input(%c)\n", (char) key);
|
||||||
|
syslog(LOG_DEBUG, "key %d pressed on device", key);
|
||||||
|
|
||||||
switch (key) {
|
switch ((char) key) {
|
||||||
case 'A':
|
case PAUSE_KEY:
|
||||||
if (screenlist_action == SCR_HOLD)
|
if (screenlist_action == SCR_HOLD)
|
||||||
screenlist_action = 0;
|
screenlist_action = 0;
|
||||||
else
|
else
|
||||||
screenlist_action = SCR_HOLD;
|
screenlist_action = SCR_HOLD;
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case BACK_KEY:
|
||||||
screenlist_action = SCR_BACK;
|
screenlist_action = SCR_BACK;
|
||||||
screenlist_prev ();
|
screenlist_prev ();
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case FORWARD_KEY:
|
||||||
screenlist_action = SCR_SKIP;
|
screenlist_action = SCR_SKIP;
|
||||||
screenlist_next ();
|
screenlist_next ();
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case MAIN_MENU_KEY:
|
||||||
debug ("got the menu key!\n");
|
debug ("got the menu key!\n");
|
||||||
server_menu ();
|
server_menu ();
|
||||||
break;
|
break;
|
||||||
|
|||||||
+121
-12
@@ -18,6 +18,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
|
|
||||||
@@ -32,10 +36,30 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
#define MAX_TIMER 0x10000
|
||||||
|
#define DEFAULT_USER "nobody"
|
||||||
|
|
||||||
char *version = VERSION;
|
char *version = VERSION;
|
||||||
char *protocol_version = PROTOCOL_VERSION;
|
char *protocol_version = PROTOCOL_VERSION;
|
||||||
char *build_date = __DATE__;
|
char *build_date = __DATE__;
|
||||||
|
|
||||||
|
/* Socket to bind to...
|
||||||
|
|
||||||
|
Using loopback is much more secure; it means that this port is
|
||||||
|
accessible only to programs running locally on the same host as LCDd.
|
||||||
|
|
||||||
|
Using variables for these means that (later) we can select which port
|
||||||
|
and which address to bind to at run time. */
|
||||||
|
|
||||||
|
char bind_addr[64] = "127.0.0.1";
|
||||||
|
int lcd_port = LCDPORT;
|
||||||
|
|
||||||
|
// The parameter structure and args[] should
|
||||||
|
// be removed when getopt(3) is implemented,
|
||||||
|
// as there won't be any need for them then.
|
||||||
|
typedef struct parameter {
|
||||||
|
char *sh, *lg; // short and long versions
|
||||||
|
} parameter;
|
||||||
|
|
||||||
// This is currently only a list of available arguments, but doesn't
|
// This is currently only a list of available arguments, but doesn't
|
||||||
// really *do* anything. It just helps to figure out which parameters
|
// really *do* anything. It just helps to figure out which parameters
|
||||||
@@ -54,6 +78,34 @@ static parameter args[] = {
|
|||||||
void exit_program (int val);
|
void exit_program (int val);
|
||||||
void HelpScreen ();
|
void HelpScreen ();
|
||||||
|
|
||||||
|
// At this point, this function will only succeed;
|
||||||
|
// all other options will stop the program.
|
||||||
|
// However, it may not always be thus; so we prepared
|
||||||
|
// for this possibility by making it return an int.
|
||||||
|
//
|
||||||
|
int drop_privs(char *user) {
|
||||||
|
struct passwd *pwent;
|
||||||
|
|
||||||
|
if (getuid() == 0 || geteuid() == 0) {
|
||||||
|
if ((pwent = getpwnam(user)) == NULL) {
|
||||||
|
if (errno) {
|
||||||
|
perror("LCDd: getpwnam");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "user %s not a valid user!", user);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (setuid(pwent->pw_uid) < 0) {
|
||||||
|
fprintf(stderr, "unable to switch to user %s\n", user);
|
||||||
|
perror("LCDd: setuid");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -64,6 +116,7 @@ main (int argc, char **argv)
|
|||||||
int disable_server_screen = 1;
|
int disable_server_screen = 1;
|
||||||
screen *s = NULL;
|
screen *s = NULL;
|
||||||
char *str, *ing; // strings for commandline handling
|
char *str, *ing; // strings for commandline handling
|
||||||
|
char *user = DEFAULT_USER;
|
||||||
|
|
||||||
// Ctrl-C will cause a clean exit...
|
// Ctrl-C will cause a clean exit...
|
||||||
signal (SIGINT, exit_program);
|
signal (SIGINT, exit_program);
|
||||||
@@ -86,14 +139,31 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
// Now, go into daemon mode...
|
// Now, go into daemon mode...
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
|
openlog("LCDd", LOG_PID, LOG_DAEMON);
|
||||||
|
syslog(LOG_NOTICE, "server version %s starting up (protocol version %s)",
|
||||||
|
version, protocol_version);
|
||||||
|
syslog(LOG_NOTICE, "server built on %s",
|
||||||
|
build_date);
|
||||||
|
|
||||||
if (daemon_mode) {
|
if (daemon_mode) {
|
||||||
int child;
|
int child;
|
||||||
|
|
||||||
|
syslog(LOG_NOTICE, "server forking to background");
|
||||||
|
|
||||||
if ((child = fork ()) != 0) {
|
if ((child = fork ()) != 0) {
|
||||||
usleep (1500000); // Wait for child to initialize
|
usleep (1500000); // Wait for child to initialize
|
||||||
exit (0); /* PARENT EXITS */
|
exit (0); /* PARENT EXITS */
|
||||||
}
|
}
|
||||||
// This line removed because it eats error messages...
|
// This line removed because it eats error messages...
|
||||||
//setsid(); /* RELEASE TTY */
|
//setsid(); /* RELEASE TTY */
|
||||||
|
//
|
||||||
|
// After this point, as a daemon, no error messages should
|
||||||
|
// go to the console unless drastic; rather, they should go to syslog
|
||||||
|
//
|
||||||
|
// However, option processing is not yet done, nor is any initialization (!)
|
||||||
|
// So we must wait until the main loop.
|
||||||
|
} else {
|
||||||
|
syslog(LOG_NOTICE, "server running in foreground");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -195,13 +265,20 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now init a bunch of required stuff...
|
// switch to a different user for the real work...
|
||||||
|
if (lcd_port >= 1024)
|
||||||
|
drop_privs(user);
|
||||||
|
|
||||||
if (sock_create_server () <= 0) {
|
if (sock_create_server (&bind_addr, lcd_port) <= 0) {
|
||||||
printf ("Error opening socket.\n");
|
printf ("Error opening socket.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lcd_port > 1024)
|
||||||
|
drop_privs(user);
|
||||||
|
|
||||||
|
// Now init a bunch of required stuff...
|
||||||
|
|
||||||
if (client_init () < 0) {
|
if (client_init () < 0) {
|
||||||
printf ("Error initializing client list\n");
|
printf ("Error initializing client list\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -218,29 +295,48 @@ main (int argc, char **argv)
|
|||||||
} else if (disable_server_screen) {
|
} else if (disable_server_screen) {
|
||||||
server_screen->priority = 256;
|
server_screen->priority = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Probably a better place to fork
|
||||||
|
//
|
||||||
// Main loop...
|
// Main loop...
|
||||||
|
|
||||||
|
syslog(LOG_NOTICE, "using %dx%d LCD with cells %dx%d",
|
||||||
|
lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
sock_poll_clients ();
|
sock_poll_clients (); // poll clients for input
|
||||||
parse_all_client_messages ();
|
parse_all_client_messages (); // analyze input from network clients
|
||||||
handle_input ();
|
handle_input (); // handle key input from devices
|
||||||
|
|
||||||
// TODO: Move this code to screenlist.c...
|
// TODO: Move this code to screenlist.c...
|
||||||
// ... it should just say "handle_screens();"
|
// ... it should just say "handle_screens();"
|
||||||
// Timer gets reset by screenlist_next()
|
// Timer gets reset by screenlist_next()
|
||||||
|
|
||||||
timer++;
|
timer++;
|
||||||
|
|
||||||
// this line's here because s was getting overwritten at one time...
|
// this line's here because s was getting overwritten at one time...
|
||||||
//s = screenlist_current();
|
//s = screenlist_current();
|
||||||
|
|
||||||
if (s && (timer >= s->duration)) {
|
if (s && (timer >= s->duration)) {
|
||||||
screenlist_next ();
|
screenlist_next ();
|
||||||
}
|
}
|
||||||
// Just in case it gets out of hand...
|
|
||||||
if (timer >= 0x10000)
|
|
||||||
timer = 0;
|
|
||||||
update_server_screen (timer);
|
|
||||||
s = screenlist_current ();
|
|
||||||
|
|
||||||
// render something here...
|
// Just in case it gets out of hand...
|
||||||
if (s)
|
if (timer >= MAX_TIMER)
|
||||||
|
timer = 0;
|
||||||
|
|
||||||
|
// Update server screen with the right number
|
||||||
|
// of clients and screens...
|
||||||
|
//
|
||||||
|
// TODO: Move this call to every client connection
|
||||||
|
// and every screen add...
|
||||||
|
|
||||||
|
update_server_screen (timer);
|
||||||
|
|
||||||
|
// draw the current scren
|
||||||
|
|
||||||
|
if ((s = screenlist_current ()) != NULL)
|
||||||
|
|
||||||
draw_screen (s, timer);
|
draw_screen (s, timer);
|
||||||
else
|
else
|
||||||
no_screen_screen (timer);
|
no_screen_screen (timer);
|
||||||
@@ -257,9 +353,22 @@ main (int argc, char **argv)
|
|||||||
void
|
void
|
||||||
exit_program (int val)
|
exit_program (int val)
|
||||||
{
|
{
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
// TODO: These things shouldn't be so interdependent. The order
|
// TODO: These things shouldn't be so interdependent. The order
|
||||||
// things are shut down in shouldn't matter...
|
// things are shut down in shouldn't matter...
|
||||||
|
|
||||||
|
strcpy(buf, "server shutting down on ");
|
||||||
|
switch(val) {
|
||||||
|
case 1: strcat(buf, "SIGHUP"); break;
|
||||||
|
case 2: strcat(buf, "SIGINT"); break;
|
||||||
|
case 15: strcat(buf, "SIGTERM"); break;
|
||||||
|
default: sprintf(buf, "server shutting down on signal %d", val); break;
|
||||||
|
// Other values should not be seen, but just in case..
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make note in the logs...
|
||||||
|
syslog(LOG_NOTICE, buf);
|
||||||
// Say goodbye!
|
// Say goodbye!
|
||||||
goodbye_screen ();
|
goodbye_screen ();
|
||||||
// Can go anywhere...
|
// Can go anywhere...
|
||||||
|
|||||||
+3
-3
@@ -26,8 +26,8 @@ typedef struct screen_size {
|
|||||||
int wid, hgt;
|
int wid, hgt;
|
||||||
} screen_size;
|
} screen_size;
|
||||||
|
|
||||||
typedef struct parameter {
|
#define DEFAULT_SCREEN_PRIORITY 128
|
||||||
char *sh, *lg; // short and long versions
|
#define DEFAULT_SCREEN_DURATION 32
|
||||||
} parameter;
|
#define DEFAULT_HEARTBEAT 1
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -303,7 +303,7 @@ slid_func (menu_item * item)
|
|||||||
value = readfunc (MENU_READ);
|
value = readfunc (MENU_READ);
|
||||||
if (value < 0 || value >= MENU_CLOSE)
|
if (value < 0 || value >= MENU_CLOSE)
|
||||||
return value;
|
return value;
|
||||||
sprintf (str, "%i", value);
|
snprintf (str, sizeof(str), "%i", value);
|
||||||
if (lcd.hgt >= 4) {
|
if (lcd.hgt >= 4) {
|
||||||
lcd.string (8, 4, str);
|
lcd.string (8, 4, str);
|
||||||
value = (lcd.wid * lcd.cellwid * value / 256);
|
value = (lcd.wid * lcd.cellwid * value / 256);
|
||||||
|
|||||||
+1
-1
@@ -260,7 +260,7 @@ Server_screen_func (int input)
|
|||||||
if (server_screen->priority < 256)
|
if (server_screen->priority < 256)
|
||||||
server_screen->priority = 256;
|
server_screen->priority = 256;
|
||||||
else
|
else
|
||||||
server_screen->priority = 128;
|
server_screen->priority = DEFAULT_SCREEN_PRIORITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (MENU_OK | (server_screen->priority < 256));
|
return (MENU_OK | (server_screen->priority < 256));
|
||||||
|
|||||||
+96
-54
@@ -20,21 +20,32 @@
|
|||||||
#include "client_functions.h"
|
#include "client_functions.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
|
// This is a big function... TOO big. How to trim....
|
||||||
|
// TODO: Simplify... simplify...
|
||||||
int
|
int
|
||||||
parse_all_client_messages ()
|
parse_all_client_messages ()
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j, len;
|
||||||
int newtoken, inquote;
|
int newtoken, inquote;
|
||||||
client *c;
|
client *c;
|
||||||
char *str;
|
char *str, *p, *q, *s;
|
||||||
// char *tok;
|
// char *tok;
|
||||||
int argc;
|
int argc;
|
||||||
char *argv[256];
|
char *argv[256];
|
||||||
char delimiters[] = " \0";
|
char delimiters[] = " ";
|
||||||
char leftquote[] = "\0\"'`([{\0";
|
char leftquote[] = "\"'`([{";
|
||||||
char rightquote[] = "\0\"'`)]}\0";
|
char rightquote[] = "\"'`)]}";
|
||||||
char errmsg[256];
|
char errmsg[256];
|
||||||
int invalid = 0;
|
int invalid = 0;
|
||||||
|
int quoteindex;
|
||||||
|
|
||||||
|
for (i = 0; i <= 256; i++) {
|
||||||
|
argv[i] == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SEPARATOR_CHAR ' '
|
||||||
|
#define LINE_TERM_CHAR '\0'
|
||||||
|
#define COMMENT_CHAR '#'
|
||||||
|
|
||||||
//debug("parse: Rewinding list...\n");
|
//debug("parse: Rewinding list...\n");
|
||||||
LL_Rewind (clients);
|
LL_Rewind (clients);
|
||||||
@@ -48,76 +59,107 @@ parse_all_client_messages ()
|
|||||||
for (str = client_get_message (c); str; str = client_get_message (c)) {
|
for (str = client_get_message (c); str; str = client_get_message (c)) {
|
||||||
debug ("parse: ...%s\n", str);
|
debug ("parse: ...%s\n", str);
|
||||||
// Now, split up the string...
|
// Now, split up the string...
|
||||||
//len = strlen(str);
|
|
||||||
argc = 0;
|
argc = 0;
|
||||||
newtoken = 1;
|
i = 0;
|
||||||
inquote = 0;
|
q = p = str;
|
||||||
for (i = 0; str[i]; i++) {
|
|
||||||
if (inquote) // Scan for the end of the quote
|
if (*p == COMMENT_CHAR) {
|
||||||
{
|
continue; // found a comment line - skip it...
|
||||||
if (str[i] == rightquote[inquote]) { // Found the end of the quote
|
|
||||||
inquote = 0;
|
|
||||||
str[i] = 0;
|
|
||||||
newtoken = 1;
|
|
||||||
}
|
}
|
||||||
} else // Normal operation; split at delimiters
|
|
||||||
{
|
//fprintf(stderr, "starting string scan...\n");
|
||||||
for (j = 1; leftquote[j]; j++) {
|
|
||||||
// Found the beginning of a new quote...
|
do {
|
||||||
if (str[i] == leftquote[j]) {
|
// bypass initial white space...
|
||||||
inquote = j;
|
while ((*p == SEPARATOR_CHAR) && (*p)) {
|
||||||
str[i] = 0;
|
p++;
|
||||||
continue;
|
q++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If (*p) is null here, we reached the end of
|
||||||
|
// an empty parameter... so one of two things
|
||||||
|
// is true:
|
||||||
|
//
|
||||||
|
// 1. There is nothing but white space on this line (odd..)
|
||||||
|
// 2. This is trailing white space (odd... but allowable)
|
||||||
|
|
||||||
|
if (*p == LINE_TERM_CHAR) {
|
||||||
|
break;
|
||||||
|
// if there are no arguments, argc == 0 and will fail
|
||||||
|
// appropriately...
|
||||||
|
//
|
||||||
|
// if this is trailing white space, ignore the argc++ at the
|
||||||
|
// end and claim this as the end...
|
||||||
}
|
}
|
||||||
for (j = 0; delimiters[j]; j++) {
|
|
||||||
// Break into a new string...
|
// Handle quoted strings...
|
||||||
if (str[i] == delimiters[j]) {
|
if ((s = strchr(leftquote, *p)) != NULL) {
|
||||||
str[i] = 0;
|
quoteindex = s - leftquote;
|
||||||
newtoken = 1;
|
//fprintf(stderr, "found <%c> at index [%d] = <%c>\n", *p, quoteindex, leftquote[quoteindex]);
|
||||||
continue;
|
q = ++p; // past open quote...
|
||||||
|
while ((rightquote[quoteindex] != *p) && (*p != LINE_TERM_CHAR)) {
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
}
|
if (*p == LINE_TERM_CHAR) {
|
||||||
}
|
// We just sucked up the rest of the command line: ERROR!!
|
||||||
if (newtoken && str[i]) {
|
snprintf (errmsg, sizeof(errmsg), "huh? unterminated string! missing ending %c\n",
|
||||||
newtoken = 0;
|
rightquote[quoteindex]);
|
||||||
argv[argc] = str + i;
|
|
||||||
argc++;
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inquote) {
|
|
||||||
sprintf (errmsg, "huh? Unterminated string: missing %c\n", rightquote[inquote]);
|
|
||||||
sock_send_string (c->sock, errmsg);
|
sock_send_string (c->sock, errmsg);
|
||||||
continue;
|
continue;
|
||||||
|
} else {
|
||||||
|
*p = LINE_TERM_CHAR; // terminate string
|
||||||
|
p++; // bypass to next character
|
||||||
|
// Note that next character could be a EndOfLine (null)
|
||||||
|
// if the string was last on the line, or it could be
|
||||||
|
// something else... is it a blank?
|
||||||
|
if (*p != SEPARATOR_CHAR && *p != LINE_TERM_CHAR) {
|
||||||
|
sock_send_string (c->sock, "huh? improperly terminated string! (missing whitespace)\n");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
/*
|
}
|
||||||
for(tok = strtok(str, delimiters);
|
|
||||||
tok;
|
// Otherwise, normal string...
|
||||||
tok=strtok(NULL, delimiters))
|
} else {
|
||||||
{
|
while (*p != SEPARATOR_CHAR && *p != LINE_TERM_CHAR)
|
||||||
argv[argc] = tok;
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not end of line?
|
||||||
|
if (*p) {
|
||||||
|
*p = LINE_TERM_CHAR;
|
||||||
|
//fprintf(stderr, "found new token: %s\n", q);
|
||||||
|
argv[i++] = q;
|
||||||
|
q = ++p;
|
||||||
|
} else {
|
||||||
|
//fprintf(stderr, "found new token: %s\n", q);
|
||||||
|
argv[i++] = q;
|
||||||
|
}
|
||||||
|
// At the end of this statement,
|
||||||
|
// *p will be '\0' if end of input reached;
|
||||||
|
// otherwise, it is the first character of the
|
||||||
|
// next part of the string.
|
||||||
|
|
||||||
|
|
||||||
argc++;
|
argc++;
|
||||||
}
|
} while (*p);
|
||||||
*/
|
|
||||||
|
//fprintf(stderr, "exiting string scan...\n");
|
||||||
|
|
||||||
argv[argc] = NULL;
|
argv[argc] = NULL;
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Now find and call the appropriate function...
|
// Now find and call the appropriate function...
|
||||||
// debug("parse: Finding function...\n");
|
|
||||||
invalid = 1;
|
invalid = 1;
|
||||||
for (i = 0; commands[i].keyword; i++) {
|
for (i = 0; commands[i].keyword; i++) {
|
||||||
// debug("(checking %s)\n", commands[i].keyword);
|
|
||||||
if (0 == strcmp (argv[0], commands[i].keyword)) {
|
if (0 == strcmp (argv[0], commands[i].keyword)) {
|
||||||
// debug("(FOUND %s)\n", commands[i].keyword);
|
|
||||||
invalid = commands[i].function (c, argc, argv);
|
invalid = commands[i].function (c, argc, argv);
|
||||||
// debug("parse: Returned %i...\n", err);
|
break; // found our function - don't continue on...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
// FIXME: Check for buffer overflows here...
|
snprintf (errmsg, sizeof(errmsg), "huh? Invalid command \"%s\"\n", argv[0]);
|
||||||
sprintf (errmsg, "huh? Invalid command \"%s\"\n", argv[0]);
|
|
||||||
sock_send_string (c->sock, errmsg);
|
sock_send_string (c->sock, errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+65
-15
@@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :)
|
THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :)
|
||||||
|
|
||||||
|
NOTE: (from David Douthitt) Multiple screen sizes? Multiple simultaneous
|
||||||
|
screens? Horrors of horrors... next thing you know it'll be making coffee...
|
||||||
|
Better believe it'll take a while to do...
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -59,16 +63,28 @@ draw_screen (screen * s, int timer)
|
|||||||
reset = 0;
|
reset = 0;
|
||||||
old_s = s;
|
old_s = s;
|
||||||
|
|
||||||
|
// Clear the LCD screen...
|
||||||
lcd.clear ();
|
lcd.clear ();
|
||||||
|
|
||||||
switch (backlight_state) {
|
// lcd.backlight --
|
||||||
|
//
|
||||||
|
// This should be in a separate function altogether.
|
||||||
|
// Perhaps several: lcd.backlight_off, lcd.backlight_on,
|
||||||
|
// lcd.backlight_brightness, lcd.backlight_flash ...
|
||||||
|
//
|
||||||
|
// Set up backlight to the correct state...
|
||||||
|
// NOTE: dirty stripping of other options...
|
||||||
|
switch (backlight_state & 1) {
|
||||||
|
// Backlight off (easy)
|
||||||
case BACKLIGHT_OFF:
|
case BACKLIGHT_OFF:
|
||||||
lcd.backlight (backlight_off_brightness);
|
lcd.backlight (BACKLIGHT_OFF);
|
||||||
break;
|
break;
|
||||||
|
// Backlight on (easy)
|
||||||
case BACKLIGHT_ON:
|
case BACKLIGHT_ON:
|
||||||
lcd.backlight (backlight_brightness);
|
lcd.backlight (BACKLIGHT_ON);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// Backlight flash: check timer and flip backlight as appropriate
|
||||||
if (backlight_state & BACKLIGHT_FLASH) {
|
if (backlight_state & BACKLIGHT_FLASH) {
|
||||||
tmp = (!((timer & 7) == 7));
|
tmp = (!((timer & 7) == 7));
|
||||||
if (backlight_state & 1)
|
if (backlight_state & 1)
|
||||||
@@ -77,6 +93,8 @@ draw_screen (screen * s, int timer)
|
|||||||
else
|
else
|
||||||
lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness);
|
lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness);
|
||||||
//lcd.backlight(backlight_brightness * ((timer&7) == 7));
|
//lcd.backlight(backlight_brightness * ((timer&7) == 7));
|
||||||
|
|
||||||
|
// Backlight blink: check timer and flip backlight as appropriate
|
||||||
} else if (backlight_state & BACKLIGHT_BLINK) {
|
} else if (backlight_state & BACKLIGHT_BLINK) {
|
||||||
tmp = (!((timer & 14) == 14));
|
tmp = (!((timer & 14) == 14));
|
||||||
if (backlight_state & 1)
|
if (backlight_state & 1)
|
||||||
@@ -89,25 +107,31 @@ draw_screen (screen * s, int timer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output ports from LCD - outputs depend on the current screen
|
||||||
lcd.output (output_state);
|
lcd.output (output_state);
|
||||||
|
|
||||||
|
// Draw a frame...
|
||||||
draw_frame (s->widgets, 'v', 0, 0, lcd.wid, lcd.hgt, s->wid, s->hgt, s->duration / s->hgt, timer);
|
draw_frame (s->widgets, 'v', 0, 0, lcd.wid, lcd.hgt, s->wid, s->hgt, s->duration / s->hgt, timer);
|
||||||
|
|
||||||
//debug("draw_screen done\n");
|
//debug("draw_screen done\n");
|
||||||
|
|
||||||
if (heartbeat) {
|
if (heartbeat) {
|
||||||
if ((s->heartbeat == 1) || heartbeat == HEART_ON) {
|
if ((s->heartbeat == HEART_ON) || heartbeat == HEART_ON) {
|
||||||
// Set this to pulsate like a real heart beat...
|
// Set this to pulsate like a real heart beat...
|
||||||
// (binary is fun... :)
|
// (binary is fun... :)
|
||||||
|
// lcd.heartbeat ();
|
||||||
lcd.icon (!((timer + 4) & 5), 0);
|
lcd.icon (!((timer + 4) & 5), 0);
|
||||||
lcd.chr (lcd.wid, 1, 0);
|
lcd.chr (lcd.wid, 1, 0);
|
||||||
}
|
}
|
||||||
if ((s->heartbeat == 2) && heartbeat != HEART_OFF) {
|
// else
|
||||||
char *phases = "-\\|/";
|
// This seems unnecessary... heartbeat is nicer...
|
||||||
lcd.chr (lcd.wid, 1, phases[timer & 3]);
|
// if ((s->heartbeat == HEART_OPEN) && heartbeat != HEART_OFF) {
|
||||||
}
|
// char *phases = "-\\|/";
|
||||||
|
// lcd.chr (lcd.wid, 1, phases[timer & 3]);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flush display out, frame and all...
|
||||||
lcd.flush ();
|
lcd.flush ();
|
||||||
|
|
||||||
//debug("draw_screen: %8x, %i\n", s, timer);
|
//debug("draw_screen: %8x, %i\n", s, timer);
|
||||||
@@ -116,9 +140,25 @@ draw_screen (screen * s, int timer)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following function is positively ghastly (as was mentioned above!)
|
||||||
|
// Best thing to do is to remove support for frames... but anyway...
|
||||||
|
//
|
||||||
static int
|
static int
|
||||||
draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, int fwid, int fhgt, int fspeed, int timer)
|
draw_frame (LL * list,
|
||||||
|
char fscroll, // direction of scrolling
|
||||||
|
int left, // left edge of frame
|
||||||
|
int top, // top edge of frame
|
||||||
|
int right, // right edge of frame
|
||||||
|
int bottom, // bottom edge of frame
|
||||||
|
int fwid, // frame width?
|
||||||
|
int fhgt, // frame height?
|
||||||
|
int fspeed, // speed of scrolling...
|
||||||
|
int timer) // ?
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#define VerticalScrolling (fscroll == 'v')
|
||||||
|
#define HorizontalScrolling (fscroll == 'h')
|
||||||
|
|
||||||
char str[BUFSIZE]; // scratch buffer
|
char str[BUFSIZE]; // scratch buffer
|
||||||
widget *w;
|
widget *w;
|
||||||
|
|
||||||
@@ -135,18 +175,22 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i
|
|||||||
|
|
||||||
fx = 0;
|
fx = 0;
|
||||||
fy = 0;
|
fy = 0;
|
||||||
if (fscroll == 'v') {
|
if (VerticalScrolling) {
|
||||||
|
|
||||||
if (fspeed > 0)
|
if (fspeed > 0)
|
||||||
fy = (timer - fspeed) / fspeed;
|
fy = (timer - fspeed) / fspeed;
|
||||||
if (fspeed < 0)
|
else if (fspeed < 0)
|
||||||
fy = (-fspeed) * timer;
|
fy = (-fspeed) * timer;
|
||||||
|
|
||||||
if (fy < 0)
|
if (fy < 0)
|
||||||
fy = 0;
|
fy = 0;
|
||||||
|
|
||||||
// Make sure the whole frame gets displayed, at least...
|
// Make sure the whole frame gets displayed, at least...
|
||||||
|
// ...by setting the action to RENDER_HOLD if no other action
|
||||||
|
// is currently defined...
|
||||||
|
|
||||||
if (!screenlist_action)
|
if (!screenlist_action)
|
||||||
screenlist_action = RENDER_HOLD;
|
screenlist_action = RENDER_HOLD;
|
||||||
|
|
||||||
if ((fy) > fhgt - 1) {
|
if ((fy) > fhgt - 1) {
|
||||||
// Release hold after it has been displayed
|
// Release hold after it has been displayed
|
||||||
if (!screenlist_action || screenlist_action == RENDER_HOLD)
|
if (!screenlist_action || screenlist_action == RENDER_HOLD)
|
||||||
@@ -156,8 +200,9 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i
|
|||||||
fy %= fhgt;
|
fy %= fhgt;
|
||||||
if (fy > fhgt - hgt)
|
if (fy > fhgt - hgt)
|
||||||
fy = fhgt - hgt;
|
fy = fhgt - hgt;
|
||||||
} else if (fscroll == 'h') { // TODO: Frames don't scroll horizontally yet!
|
|
||||||
|
|
||||||
|
} else if (HorizontalScrolling) {
|
||||||
|
// TODO: Frames don't scroll horizontally yet!
|
||||||
}
|
}
|
||||||
//debug("draw_screen: %8x, %i\n", s, timer);
|
//debug("draw_screen: %8x, %i\n", s, timer);
|
||||||
|
|
||||||
@@ -166,6 +211,11 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i
|
|||||||
|
|
||||||
//debug("draw_frame: %8x, %i\n", frame, timer);
|
//debug("draw_frame: %8x, %i\n", frame, timer);
|
||||||
|
|
||||||
|
#define PositiveX(a) ((a)->x > 0)
|
||||||
|
#define PositiveY(a) ((a)->y > 0)
|
||||||
|
#define ValidPoint(a) (PositiveX(a) && PositiveY(a))
|
||||||
|
#define TextPresent(a) ((a)->text)
|
||||||
|
|
||||||
LL_Rewind (list);
|
LL_Rewind (list);
|
||||||
do {
|
do {
|
||||||
w = (widget *) LL_Get (list);
|
w = (widget *) LL_Get (list);
|
||||||
@@ -175,9 +225,9 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i
|
|||||||
// TODO: Make this cleaner and more flexible!
|
// TODO: Make this cleaner and more flexible!
|
||||||
switch (w->type) {
|
switch (w->type) {
|
||||||
case WID_STRING:
|
case WID_STRING:
|
||||||
if ((w->x > 0) && (w->y > 0) && (w->text)) {
|
if (ValidPoint(w) && TextPresent(w)) {
|
||||||
if ((w->y <= hgt + fy) && (w->y > fy)) {
|
if ((w->y <= hgt + fy) && (w->y > fy)) {
|
||||||
if (w->x > wid) { w->x=wid; };
|
if (w->x > wid) w->x=wid;
|
||||||
strncpy (str, w->text, wid - w->x + 1);
|
strncpy (str, w->text, wid - w->x + 1);
|
||||||
str[wid - w->x + 1] = 0;
|
str[wid - w->x + 1] = 0;
|
||||||
lcd.string (w->x + left, w->y + top - fy, str);
|
lcd.string (w->x + left, w->y + top - fy, str);
|
||||||
|
|||||||
+4
-3
@@ -11,6 +11,7 @@
|
|||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "screenlist.h"
|
#include "screenlist.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
int default_priority = 128 ;
|
int default_priority = 128 ;
|
||||||
int default_duration = 64 ; // About 8 seconds
|
int default_duration = 64 ; // About 8 seconds
|
||||||
@@ -28,9 +29,9 @@ screen_create ()
|
|||||||
|
|
||||||
s->id = NULL;
|
s->id = NULL;
|
||||||
s->name = NULL;
|
s->name = NULL;
|
||||||
s->priority = default_priority ;
|
s->priority = DEFAULT_SCREEN_PRIORITY;
|
||||||
s->duration = default_duration ;
|
s->duration = DEFAULT_SCREEN_DURATION;
|
||||||
s->heartbeat = 1;
|
s->heartbeat = DEFAULT_HEARTBEAT;
|
||||||
s->wid = lcd.wid;
|
s->wid = lcd.wid;
|
||||||
s->hgt = lcd.hgt;
|
s->hgt = lcd.hgt;
|
||||||
s->keys = NULL;
|
s->keys = NULL;
|
||||||
|
|||||||
+2
-2
@@ -112,7 +112,7 @@ screenlist_current ()
|
|||||||
c = old_s->parent;
|
c = old_s->parent;
|
||||||
if (c) // Tell the client we're not listening any more...
|
if (c) // Tell the client we're not listening any more...
|
||||||
{
|
{
|
||||||
sprintf (str, "ignore %s\n", old_s->id);
|
snprintf (str, sizeof(str), "ignore %s\n", old_s->id);
|
||||||
sock_send_string (c->sock, str);
|
sock_send_string (c->sock, str);
|
||||||
} else // The server has the display, so do nothing
|
} else // The server has the display, so do nothing
|
||||||
{
|
{
|
||||||
@@ -125,7 +125,7 @@ screenlist_current ()
|
|||||||
c = s->parent;
|
c = s->parent;
|
||||||
if (c) // Tell the client we're paying attention...
|
if (c) // Tell the client we're paying attention...
|
||||||
{
|
{
|
||||||
sprintf (str, "listen %s\n", s->id);
|
snprintf (str, sizeof(str), "listen %s\n", s->id);
|
||||||
sock_send_string (c->sock, str);
|
sock_send_string (c->sock, str);
|
||||||
} else // The server has the display, so do nothing
|
} else // The server has the display, so do nothing
|
||||||
{
|
{
|
||||||
|
|||||||
+61
-44
@@ -26,6 +26,11 @@ char one[256] = "";
|
|||||||
char two[256] = "";
|
char two[256] = "";
|
||||||
char three[256] = "";
|
char three[256] = "";
|
||||||
|
|
||||||
|
#define WidgetXPos(w,a) (w)->x = (a)
|
||||||
|
#define WidgetYPos(w,a) (w)->y = (a)
|
||||||
|
#define WidgetText(w,a) (w)->text = (a)
|
||||||
|
#define WidgetString(w,a,b,t) {WidgetXPos(w,a);WidgetYPos(w,b);WidgetText(w,t);}
|
||||||
|
|
||||||
int
|
int
|
||||||
server_screen_init ()
|
server_screen_init ()
|
||||||
{
|
{
|
||||||
@@ -44,46 +49,39 @@ server_screen_init ()
|
|||||||
server_screen->name = name;
|
server_screen->name = name;
|
||||||
server_screen->duration = 8; // 1 second, instead of 4...
|
server_screen->duration = 8; // 1 second, instead of 4...
|
||||||
|
|
||||||
// TODO: Error-checking?
|
if (widget_add (server_screen, "title", "title", NULL, 1) != 0) {
|
||||||
widget_add (server_screen, "title", "title", NULL, 1);
|
fprintf (stderr, "server_screen_init: internal error: could not add title widget\n");
|
||||||
widget_add (server_screen, "one", "string", NULL, 1);
|
}
|
||||||
widget_add (server_screen, "two", "string", NULL, 1);
|
if (widget_add (server_screen, "one", "string", NULL, 1) != 0) {
|
||||||
widget_add (server_screen, "three", "string", NULL, 1);
|
fprintf (stderr, "server_screen_init: internal error: could not add title widget\n");
|
||||||
|
}
|
||||||
|
if (widget_add (server_screen, "two", "string", NULL, 1) != 0) {
|
||||||
|
fprintf (stderr, "server_screen_init: internal error: could not add title widget\n");
|
||||||
|
}
|
||||||
|
if (widget_add (server_screen, "three", "string", NULL, 1) != 0) {
|
||||||
|
fprintf (stderr, "server_screen_init: internal error: could not add title widget\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Now, initialize all the widgets...
|
// Now, initialize all the widgets...
|
||||||
w = widget_find (server_screen, "title");
|
if ((w = widget_find (server_screen, "title")) != NULL) {
|
||||||
if (w) {
|
WidgetText(w,title);
|
||||||
w->text = title;
|
} else
|
||||||
} else {
|
|
||||||
fprintf (stderr, "server_screen_init: Can't find title\n");
|
fprintf (stderr, "server_screen_init: Can't find title\n");
|
||||||
}
|
|
||||||
|
|
||||||
w = widget_find (server_screen, "one");
|
if ((w = widget_find (server_screen, "one")) != NULL)
|
||||||
if (w) {
|
WidgetString(w,1,2,one)
|
||||||
w->x = 1;
|
else
|
||||||
w->y = 2;
|
|
||||||
w->text = one;
|
|
||||||
} else {
|
|
||||||
fprintf (stderr, "server_screen_init: Can't find widget one\n");
|
fprintf (stderr, "server_screen_init: Can't find widget one\n");
|
||||||
}
|
|
||||||
|
|
||||||
w = widget_find (server_screen, "two");
|
if ((w = widget_find (server_screen, "two")) != NULL)
|
||||||
if (w) {
|
WidgetString(w,1,3,two)
|
||||||
w->x = 1;
|
else
|
||||||
w->y = 3;
|
|
||||||
w->text = two;
|
|
||||||
} else {
|
|
||||||
fprintf (stderr, "server_screen_init: Can't find widget two\n");
|
fprintf (stderr, "server_screen_init: Can't find widget two\n");
|
||||||
}
|
|
||||||
|
|
||||||
w = widget_find (server_screen, "three");
|
if ((w = widget_find (server_screen, "three")) != NULL)
|
||||||
if (w) {
|
WidgetString(w,1,4,three)
|
||||||
w->x = 1;
|
else
|
||||||
w->y = 4;
|
|
||||||
w->text = three;
|
|
||||||
} else {
|
|
||||||
fprintf (stderr, "server_screen_init: Can't find widget three\n");
|
fprintf (stderr, "server_screen_init: Can't find widget three\n");
|
||||||
}
|
|
||||||
|
|
||||||
// And enqueue the screen
|
// And enqueue the screen
|
||||||
screenlist_add (server_screen);
|
screenlist_add (server_screen);
|
||||||
@@ -93,6 +91,20 @@ server_screen_init ()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
screen_count (client *c) {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
LL_Rewind (c->data->screenlist);
|
||||||
|
do {
|
||||||
|
if (LL_Get (c->data->screenlist) != NULL)
|
||||||
|
n++;
|
||||||
|
} while (LL_Next (c->data->screenlist) == 0);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
update_server_screen (int timer)
|
update_server_screen (int timer)
|
||||||
{
|
{
|
||||||
@@ -112,24 +124,31 @@ update_server_screen (int timer)
|
|||||||
c = LL_Get (clients);
|
c = LL_Get (clients);
|
||||||
if (c) {
|
if (c) {
|
||||||
num_clients++;
|
num_clients++;
|
||||||
LL_Rewind (c->data->screenlist);
|
num_screens += screen_count(c);
|
||||||
do {
|
// LL_Rewind (c->data->screenlist);
|
||||||
s = LL_Get (c->data->screenlist);
|
// do {
|
||||||
if (s) {
|
// s = LL_Get (c->data->screenlist);
|
||||||
num_screens++;
|
// if (s) {
|
||||||
}
|
// num_screens++;
|
||||||
} while (LL_Next (c->data->screenlist) == 0);
|
// }
|
||||||
|
// } while (LL_Next (c->data->screenlist) == 0);
|
||||||
}
|
}
|
||||||
} while (LL_Next (clients) == 0);
|
} while (LL_Next (clients) == 0);
|
||||||
|
|
||||||
|
// Format strings for the appropriate size display...
|
||||||
|
//
|
||||||
if (lcd.hgt >= 3) {
|
if (lcd.hgt >= 3) {
|
||||||
sprintf (one, "Clients: %i", num_clients);
|
snprintf (one, sizeof(one), "Clients: %i", num_clients);
|
||||||
sprintf (two, "Screens: %i", num_screens);
|
snprintf (two, sizeof(two), "Screens: %i", num_screens);
|
||||||
} else {
|
} else {
|
||||||
if (lcd.wid >= 20)
|
if (lcd.wid >= 20)
|
||||||
sprintf (one, "%i Client%s, %i Screen%s", num_clients, (num_clients == 1) ? "" : "s", num_screens, (num_screens == 1) ? "" : "s");
|
snprintf (one, sizeof(one), "%i Client%s, %i Screen%s", num_clients,
|
||||||
|
(num_clients == 1) ? "" : "s", num_screens,
|
||||||
|
(num_screens == 1) ? "" : "s");
|
||||||
else // 16x2 size
|
else // 16x2 size
|
||||||
sprintf (one, "%i Cli%s, %i Scr%s", num_clients, (num_clients == 1) ? "" : "s", num_screens, (num_screens == 1) ? "" : "s");
|
snprintf (one, sizeof(one), "%i Cli%s, %i Scr%s", num_clients,
|
||||||
|
(num_clients == 1) ? "" : "s", num_screens,
|
||||||
|
(num_screens == 1) ? "" : "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -140,9 +159,7 @@ no_screen_screen (int timer)
|
|||||||
{
|
{
|
||||||
|
|
||||||
lcd.clear ();
|
lcd.clear ();
|
||||||
|
|
||||||
lcd.string (1, 1, "Error: No screen!");
|
lcd.string (1, 1, "Error: No screen!");
|
||||||
|
|
||||||
lcd.flush ();
|
lcd.flush ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+46
-18
@@ -17,6 +17,10 @@
|
|||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#include "clients.h"
|
#include "clients.h"
|
||||||
#include "shared/debug.h"
|
#include "shared/debug.h"
|
||||||
|
#include "syslog.h"
|
||||||
|
|
||||||
|
extern char bind_addr[64];
|
||||||
|
extern int lcd_port;
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
LCDproc sockets code...
|
LCDproc sockets code...
|
||||||
@@ -34,7 +38,7 @@ int read_from_client (int filedes);
|
|||||||
|
|
||||||
// Creates a socket in internet space
|
// Creates a socket in internet space
|
||||||
int
|
int
|
||||||
sock_create_inet_socket (unsigned short int port)
|
sock_create_inet_socket (char * addr, unsigned int port)
|
||||||
{
|
{
|
||||||
struct sockaddr_in name;
|
struct sockaddr_in name;
|
||||||
int sock;
|
int sock;
|
||||||
@@ -46,6 +50,7 @@ sock_create_inet_socket (unsigned short int port)
|
|||||||
sock = socket (PF_INET, SOCK_STREAM, 0);
|
sock = socket (PF_INET, SOCK_STREAM, 0);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
perror ("Error creating socket");
|
perror ("Error creating socket");
|
||||||
|
syslog(LOG_ALERT, "could not create socket", port);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,10 +58,14 @@ sock_create_inet_socket (unsigned short int port)
|
|||||||
//debug("Binding Inet Socket\n");
|
//debug("Binding Inet Socket\n");
|
||||||
name.sin_family = AF_INET;
|
name.sin_family = AF_INET;
|
||||||
name.sin_port = htons (port);
|
name.sin_port = htons (port);
|
||||||
name.sin_addr.s_addr = htonl (INADDR_ANY);
|
inet_aton(addr, &name.sin_addr);
|
||||||
|
|
||||||
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
|
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
|
||||||
perror ("Error binding socket");
|
perror ("Error binding socket");
|
||||||
|
syslog(LOG_ALERT, "could not bind to port %d", port);
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
syslog(LOG_NOTICE, "listening for queries on port %d", port);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
@@ -65,14 +74,14 @@ sock_create_inet_socket (unsigned short int port)
|
|||||||
|
|
||||||
//int StartSocketServer()
|
//int StartSocketServer()
|
||||||
int
|
int
|
||||||
sock_create_server ()
|
sock_create_server (char *bind_addr, int lcd_port)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
|
|
||||||
debug ("sock_create_server()\n");
|
debug ("sock_create_server()\n");
|
||||||
|
|
||||||
/* Create the socket and set it up to accept connections. */
|
/* Create the socket and set it up to accept connections. */
|
||||||
sock = sock_create_inet_socket (LCDPORT);
|
sock = sock_create_inet_socket (bind_addr, lcd_port);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
perror ("sock_create_server: Error creating socket");
|
perror ("sock_create_server: Error creating socket");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -80,6 +89,7 @@ sock_create_server ()
|
|||||||
|
|
||||||
if (listen (sock, 1) < 0) {
|
if (listen (sock, 1) < 0) {
|
||||||
perror ("sock_create_server: Listen error");
|
perror ("sock_create_server: Listen error");
|
||||||
|
syslog(LOG_ALERT, "error in attempting to listen to port");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +117,8 @@ sock_create_server ()
|
|||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Service all clients with input pending...
|
||||||
|
|
||||||
int
|
int
|
||||||
sock_poll_clients ()
|
sock_poll_clients ()
|
||||||
{
|
{
|
||||||
@@ -140,9 +152,12 @@ sock_poll_clients ()
|
|||||||
new = accept (orig_sock, (struct sockaddr *) &clientname, &size);
|
new = accept (orig_sock, (struct sockaddr *) &clientname, &size);
|
||||||
if (new < 0) {
|
if (new < 0) {
|
||||||
perror ("sock_poll_clients: Accept error");
|
perror ("sock_poll_clients: Accept error");
|
||||||
|
syslog(LOG_WARNING, "error in accepting client");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
debug ("sock_poll_clients: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port));
|
debug ("sock_poll_clients: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port));
|
||||||
|
syslog(LOG_NOTICE, "connect from host %s:%hd on #%d",
|
||||||
|
inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port), new);
|
||||||
FD_SET (new, &active_fd_set);
|
FD_SET (new, &active_fd_set);
|
||||||
|
|
||||||
fcntl (new, F_SETFL, O_NONBLOCK);
|
fcntl (new, F_SETFL, O_NONBLOCK);
|
||||||
@@ -168,6 +183,7 @@ sock_poll_clients ()
|
|||||||
close (i);
|
close (i);
|
||||||
FD_CLR (i, &active_fd_set);
|
FD_CLR (i, &active_fd_set);
|
||||||
debug ("sock_poll_clients: Closed connection %i\n", i);
|
debug ("sock_poll_clients: Closed connection %i\n", i);
|
||||||
|
syslog(LOG_NOTICE, "closed connection #%i", i);
|
||||||
} else
|
} else
|
||||||
fprintf (stderr, "sock_poll_clients: Can't find client %i\n", i);
|
fprintf (stderr, "sock_poll_clients: Can't find client %i\n", i);
|
||||||
}
|
}
|
||||||
@@ -186,22 +202,22 @@ read_from_client (int filedes)
|
|||||||
int nbytes, i;
|
int nbytes, i;
|
||||||
client *c;
|
client *c;
|
||||||
|
|
||||||
// nbytes = read (filedes, buffer, MAXMSG);
|
//nbytes = read (filedes, buffer, MAXMSG);
|
||||||
//debug("read_from_client(%i): reading...\n", filedes);
|
//debug("read_from_client(%i): reading...\n", filedes);
|
||||||
nbytes = sock_recv (filedes, buffer, MAXMSG);
|
//nbytes = sock_recv (filedes, buffer, MAXMSG);
|
||||||
//debug("read_from_client(%i): ...done\n", filedes);
|
//debug("read_from_client(%i): ...done\n", filedes);
|
||||||
debug ("read_from_client(%i): %i bytes\n", filedes, nbytes);
|
//debug ("read_from_client(%i): %i bytes\n", filedes, nbytes);
|
||||||
|
|
||||||
if (nbytes < 0) // Read error? No data available?
|
errno = 0;
|
||||||
{
|
if ((nbytes = sock_recv (filedes, buffer, MAXMSG)) < 0) {
|
||||||
// TODO: check errno here!
|
if (errno != EAGAIN)
|
||||||
//fprintf (stderr,"read_from_client: Read error\n");
|
fprintf (stderr, "read_from_client: (fd %d) %s\n", filedes, strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
} else if (nbytes == 0) // EOF
|
} else if (nbytes == 0) // EOF
|
||||||
return -1;
|
return -1;
|
||||||
else if (nbytes > (MAXMSG - (MAXMSG / 8))) // Very noisy client...
|
else if (nbytes > (MAXMSG - (MAXMSG / 8))) // Very noisy client...
|
||||||
{
|
{
|
||||||
sock_send_string (filedes, "huh? Shut up!\n");
|
sock_send_string (filedes, "huh? Too much data received... quiet down!\n");
|
||||||
return -1;
|
return -1;
|
||||||
} else // Data Read
|
} else // Data Read
|
||||||
{
|
{
|
||||||
@@ -229,16 +245,28 @@ read_from_client (int filedes)
|
|||||||
int
|
int
|
||||||
sock_close_all ()
|
sock_close_all ()
|
||||||
{
|
{
|
||||||
int i;
|
int fd;
|
||||||
|
|
||||||
debug ("sock_close_all()\n");
|
debug ("sock_close_all()\n");
|
||||||
|
|
||||||
for (i = 0; i < FD_SETSIZE; i++) {
|
for (fd = 0; fd < FD_SETSIZE; fd++) {
|
||||||
// TODO: Destroy a "client" here...? Nope.
|
// TODO: Destroy a "client" here...? Nope.
|
||||||
sock_send_string (i, "bye\n");
|
|
||||||
close (i);
|
// Instead of using STDIN_FILENO, STDOUT_FILENO,
|
||||||
FD_CLR (i, &active_fd_set);
|
// and STDERR_FILENO, one could use "fd = 4" in the
|
||||||
debug ("sock_close_all: Closed connection %i\n", i);
|
// for() call - but this would probably not be good
|
||||||
|
// practice...
|
||||||
|
|
||||||
|
if ( fd == STDIN_FILENO ||
|
||||||
|
fd == STDOUT_FILENO ||
|
||||||
|
fd == STDERR_FILENO)
|
||||||
|
continue;
|
||||||
|
else {
|
||||||
|
//sock_send_string (fd, "bye\n");
|
||||||
|
close (fd);
|
||||||
|
FD_CLR (fd, &active_fd_set);
|
||||||
|
debug ("sock_close_all: Closed connection %i\n", fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+8
-5
@@ -167,6 +167,7 @@ widget_add (screen * s, char *id, char *type, char *in, int sock)
|
|||||||
s->heartbeat = 1;
|
s->heartbeat = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure this screen doesn't already exist...
|
// Make sure this screen doesn't already exist...
|
||||||
w = widget_find (s, id);
|
w = widget_find (s, id);
|
||||||
if (w) {
|
if (w) {
|
||||||
@@ -193,13 +194,16 @@ widget_add (screen * s, char *id, char *type, char *in, int sock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it's a valid widget type
|
// Make sure it's a valid widget type
|
||||||
for (i = 1; types[i]; i++) {
|
for (i = 1; types[i]; i++) {
|
||||||
if (0 == strcmp (types[i], type)) {
|
if (0 == strcmp (types[i], type)) {
|
||||||
valid = 1;
|
valid = 1;
|
||||||
wid_type = i;
|
wid_type = i;
|
||||||
|
break; // it's valid: skip out...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
// invalid widget type
|
// invalid widget type
|
||||||
sock_send_string (sock, "huh? Invalid widget type\n");
|
sock_send_string (sock, "huh? Invalid widget type\n");
|
||||||
@@ -233,6 +237,7 @@ widget_add (screen * s, char *id, char *type, char *in, int sock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check for errors here?
|
// TODO: Check for errors here?
|
||||||
LL_Push (list, (void *) w);
|
LL_Push (list, (void *) w);
|
||||||
|
|
||||||
@@ -266,15 +271,13 @@ widget_remove (screen * s, char *id, int sock)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// TODO: Check for errors here?
|
||||||
// TODO: Check for errors here?
|
// TODO: Make this work with frames...
|
||||||
// TODO: Make this work with frames...
|
|
||||||
// LL_Remove(list, (void *)w);
|
// LL_Remove(list, (void *)w);
|
||||||
|
|
||||||
|
|
||||||
// TODO: Check for errors here?
|
// TODO: Check for errors here?
|
||||||
// widget_destroy(w);
|
// widget_destroy(w);
|
||||||
*/
|
|
||||||
|
|
||||||
return widget_remover (list, w);
|
return widget_remover (list, w);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user