diff --git a/server/client.c b/server/client.c index 751de7b..2be51d1 100644 --- a/server/client.c +++ b/server/client.c @@ -19,6 +19,8 @@ #include "client.h" #include "screenlist.h" #include "render.h" +#include "input.h" +#include "menuitem.h" #include "shared/report.h" #include "shared/LL.h" @@ -50,7 +52,7 @@ Client * client_create (int sock) c->ack = 0; c->name = NULL; - c->client_keys = NULL; + c->menu = NULL; c->screenlist = LL_new(); @@ -74,30 +76,10 @@ client_destroy (Client * c) client_close_sock (c); - /*Free client's other data*/ - c->ack = 0; - - /* Clean up the name...*/ - if (c->name) - free (c->name); - - /* Clean up the key list...*/ - //if (d->client_keys) - // free (d->client_keys); - /* Clean up the screenlist...*/ debug( RPT_DEBUG, "client_data_destroy: Cleaning screenlist"); for( s=LL_GetFirst (c->screenlist); s; s=LL_GetNext(c->screenlist) ) { - debug( RPT_DEBUG, "client_data_destroy: removing screen %s", s->id); - - /* FIXME? This shouldn't be handled here... - * Now, remove it from the screenlist...*/ - if (screenlist_remove_all (s) < 0) { - /* Not a serious error..*/ - report( RPT_ERR, "client_data_destroy: Error dequeueing screen"); - return 0; - } /* Free its memory...*/ screen_destroy (s); /* Note that the screen is not removed from the list because @@ -106,6 +88,20 @@ client_destroy (Client * c) } LL_Destroy( c->screenlist); + /* Destroy the client's menu, if it exists */ + if (c->menu) + menuitem_destroy (c->menu); + + /* Forget client's key reservations */ + input_release_client_keys (c); + + /* Free client's other data */ + c->ack = 0; + + /* Clean up the name...*/ + if (c->name) + free (c->name); + /* Remove structure */ free (c); diff --git a/server/client.h b/server/client.h index aeabc04..4cfedb6 100644 --- a/server/client.h +++ b/server/client.h @@ -1,3 +1,20 @@ +/* + * client.h + * This file is part of LCDd, the lcdproc server. + * + * This file is released under the GNU General Public License. Refer to the + * COPYING file distributed with this package. + * + * Copyright (c) 1999, William Ferrell, Scott Scriven + * 2002, Joris Robijn + * + * Defines all the client data and actions. + */ + +#include "menu.h" +#include "menuitem.h" +/* These headers are placed here on purpose ! (circular references) */ + #ifndef CLIENT_H #define CLIENT_H @@ -16,22 +33,16 @@ typedef struct Client { LinkedList *messages; - /* and other stuff... doesn't matter yet*/ + /* The list of screens */ LinkedList *screenlist; - /* TO BE REMOVED */ - char *client_keys; - - /* list of requested keys */ - //LinkedList *keylist; - /* list of client supplied menus */ - //LinkedList *menulist; + /* Maybe it has created a menu */ + Menu * menu; } Client; #include "screen.h" - /* When a new client connects, set up a new client data struct */ Client * client_create (int sock); diff --git a/server/commands/client_commands.c b/server/commands/client_commands.c index c2878af..ba8205c 100644 --- a/server/commands/client_commands.c +++ b/server/commands/client_commands.c @@ -32,6 +32,7 @@ #include "drivers.h" #include "render.h" #include "client.h" +#include "input.h" /*************************************************************** * Debugging only.. prints out a list of arguments it receives @@ -165,59 +166,51 @@ client_set_func (Client * c, int argc, char **argv) * Tells the server the client would like to accept keypresses * of a particular type * - * usage: client_add_key + * usage: client_add_key [-exclusively|-shared] {}+ */ +#define BUFLEN 80 int client_add_key_func (Client * c, int argc, char **argv) { - char * keys ; + int exclusively = 0; + int argnr; + char errmsg[BUFLEN]; if (!c->ack) return 1; - if (argc != 2) { + if (argc < 2) { switch (argc) { case 1: - sock_send_string (c->sock, "huh? usage: client_add_key \n"); - break; - default: - sock_send_string (c->sock, "huh? Too many parameters...\n"); + sock_send_string (c->sock, "huh? Usage: client_add_key [-exclusively|-shared] {}+\n"); break; } return 0; } - keys = argv[1]; - debug(RPT_DEBUG, "client_add_key: current client will handle key(s) %s", keys); - - if (!c->client_keys) { - /* No keys list, create a new one*/ - c->client_keys = strdup( keys ); - } else { - /* Add supplied keys to existing list - * NOTE: There could be duplicates in the resulting list - * That's OK, it's the existence of the key in the list - * that's important. We'll be more careful in the delete - * key function. - */ - char * new ; - int new_len = strlen(c->client_keys) + strlen(keys) + 1 ; - - new = realloc( c->client_keys, new_len ); - if( new ) { - c->client_keys = new ; - strcat( new, keys ); - } else { - sock_send_string(c->sock, "huh? could not allocate memory for new keys\n"); - return 0; + argnr = 1; + if( argv[argnr][0] == '-' ) { + if( strcmp( argv[argnr], "-shared") == 0 ) { + exclusively = 0; + } + else if( strcmp( argv[argnr], "-exclusively") == 0 ) { + exclusively = 1; + } + else { + snprintf( errmsg, BUFLEN-1, "huh? Invalid option: %s\n", argv[argnr] ); + errmsg[BUFLEN-1] = 0; + sock_send_string( c->sock, errmsg ); + } + argnr ++; + } + for ( ; argnr < argc; argnr++ ) { + if( input_reserve_key( argv[argnr], exclusively, c ) < 0 ) { + snprintf( errmsg, BUFLEN-1, "huh? Could not reserve key \"%s\"\n", argv[argnr] ); + errmsg[BUFLEN-1] = 0; + sock_send_string( c->sock, errmsg ); } } - - if (c->client_keys) { - sock_send_string(c->sock, "success\n"); - } else { - sock_send_string(c->sock, "huh? failed\n"); - } + sock_send_string(c->sock, "success\n"); return 0; } @@ -226,52 +219,24 @@ client_add_key_func (Client * c, int argc, char **argv) * Tells the server the client would NOT like to accept keypresses * of a particular type * - * usage: client_del_key + * usage: client_del_key {}+ */ int client_del_key_func (Client * c, int argc, char **argv) { - char * keys ; + int argnr; if (!c->ack) return 1; - if (argc != 2) { - if (argc == 1) { - sock_send_string (c->sock, "huh? usage: client_del_key \n"); - return 0; - } else { - sock_send_string (c->sock, "huh? Too many parameters...\n"); - return 0; - } + if (argc < 2) { + sock_send_string (c->sock, "huh? Usage: client_del_key {}+\n"); + return 0; } - keys = argv[1] ; - debug(RPT_DEBUG, "client_del_key: Deleting key(s) %s from client_keys", keys); - - if (c->client_keys) { - /* Client has keys, remove keys from the list - * NOTE: We let malloc/realloc remember the length - * of the allocated storage. If keys are later - * added, realloc (in add_key above) will make - * sure there is enough space at c->data->client_keys - */ - char * from ; - char * to ; - - to = from = c->client_keys ; - while( *from ) { - /* Is this key to be deleted from the list?*/ - if( strchr( keys, *from ) ) { - /* Yes, skip it*/ - ++from ; - } else { - /* No, save it*/ - *to++ = *from++ ; - } - } + for( argnr=1; argnr < argc; argnr++) { + input_release_key( argv[argnr], c ); } - sock_send_string(c->sock, "success\n"); return 0; diff --git a/server/commands/command_list.c b/server/commands/command_list.c index 05bed6a..cf5871a 100644 --- a/server/commands/command_list.c +++ b/server/commands/command_list.c @@ -12,7 +12,7 @@ * The functions here are to be called only from parse.c's interpreter. * * The client's available function set is defined here, as is the syntax - * for each command. + * for each command. <-- TODO ! * */ @@ -39,9 +39,6 @@ client_function commands[] = { {"widget_add", widget_add_func}, {"widget_del", widget_del_func}, {"widget_set", widget_set_func}, - {"menu_add", menu_add_func}, - {"menu_del", menu_del_func}, - {"menu_set", menu_set_func}, {"menu_add_item", menu_add_item_func}, {"menu_del_item", menu_del_item_func}, {"menu_set_item", menu_set_item_func}, diff --git a/server/commands/menu_commands.c b/server/commands/menu_commands.c index bc80c67..a01ee56 100644 --- a/server/commands/menu_commands.c +++ b/server/commands/menu_commands.c @@ -19,121 +19,640 @@ * */ -#include #include #include +#include +#include #include #include +#include #include #include "shared/report.h" #include "shared/sockets.h" +#include "menu.h" +#include "menuitem.h" +#include "menuscreens.h" #include "client.h" -/************************************************************* - * Adds a menu to the client; handled by the server... - * - * usage: menu_add ...? - */ -int -menu_add_func (Client * c, int argc, char **argv) -{ - - if (!c->ack) - return 1; - - sock_send_string (c->sock, "huh? Not implemented yet.\n"); - - return 0; -} - -/**************************************************************** - * Removes a client's menu and all contents from the server - * - * usage: menu_del ...? - */ -int -menu_del_func (Client * c, int argc, char **argv) -{ - - if (!c->ack) - return 1; - - sock_send_string (c->sock, "huh? Not implemented yet.\n"); - - return 0; -} - -/*********************************************************************** - * Sets info about a menu, but not its items - * - * For example, should the menu be top-level, or buried somewhere? - * - * usage: menu_set ...? - */ -int -menu_set_func (Client * c, int argc, char **argv) -{ - - if (!c->ack) - return 1; - - sock_send_string (c->sock, "huh? Not implemented yet.\n"); - - return 0; -} +MenuEventFunc(menu_commands_handler); /************************************************************************* + * menu_add_item_func + * * Adds an item to a menu * - * usage: menu_add_item ...? + * Usage: menu_add_item [] + * You should use "" as id for the client's main menu. This menu will be + * created automatically when you add an item to it the first time. + * You (currently?) cannot create a menu in the main level yourself. + * The names you use for items should be unique for your client. + * The text is the visible text for the item. + * + * The following types are available: + * - menu + * - action + * - checkbox + * - ring (a kind of listbox of one line) + * - slider + * - numeric + * - alpha */ + int menu_add_item_func (Client * c, int argc, char **argv) { + char * menu_id; + char * item_id; + char * text = NULL; + Menu * menu = NULL; + MenuItem * item; + MenuItemType itemtype; if (!c->ack) return 1; - sock_send_string (c->sock, "huh? Not implemented yet.\n"); + if (!c->name) { + sock_send_string (c->sock, "huh? You need to give your client a name first\n"); + return 0; + } + if ((argc < 4 )) { + sock_send_string (c->sock, "huh? Usage: menu_add_item []\n"); + return 0; + } + + menu_id = argv[1]; + item_id = argv[2]; + + /* Does the client have a menu already ? */ + if (!c->menu) { + /* We need to create it */ + c->menu = menu_create ("_client_menu_", menu_commands_handler, c->name, c); + menu_add_item (main_menu, c->menu); + } + + if ( menu_id[0] == 0 ) { + /* No menu specified = client's main menu */ + menu = c->menu; + } else { + /* A specified menu */ + menu = menu_find_item (c->menu, menu_id, true); + } + if (!menu) { + sock_send_string (c->sock, "huh? Cannot find menu id\n"); + return 0; + } + + item = menu_find_item (c->menu, item_id, true); + if (item) { + sock_send_string (c->sock, "huh? Item id already in use\n"); + return 0; + } + + /* Find menuitem type */ + itemtype = menuitem_typename_to_type (argv[3]); + if (itemtype == -1) { + sock_send_string (c->sock, "huh? Invalid menuitem type\n"); + return 0; + } + + /* Is a text given ? */ + if (argc >= 5) { + text = argv[4]; + } + else { + text = ""; + } + + /* Create the menuitem */ + switch (itemtype) { + case MENUITEM_MENU: + item = menu_create (item_id, menu_commands_handler, text, c); + break; + case MENUITEM_ACTION: + item = menuitem_create_action (item_id, menu_commands_handler, text, + MENURESULT_NONE); + break; + case MENUITEM_CHECKBOX: + item = menuitem_create_checkbox (item_id, menu_commands_handler, text, + false, false); + break; + case MENUITEM_RING: + item = menuitem_create_ring (item_id, menu_commands_handler, text, + "", 0); + break; + case MENUITEM_SLIDER: + item = menuitem_create_slider (item_id, menu_commands_handler, text, + "", "", 0, 100, 1, 25); + break; + case MENUITEM_NUMERIC: + item = menuitem_create_numeric (item_id, menu_commands_handler, text, + 0, 100, 0); + break; + case MENUITEM_ALPHA: + item = menuitem_create_alpha (item_id, menu_commands_handler, text, + 0, 0, 10, true, false, true, "-./", ""); + break; + } + menu_add_item (menu, item); + sock_send_string(c->sock, "success\n"); return 0; } /************************************************************************* + * menu_del_item_func + * * Deletes an item from a menu * - + usage: menu_del_item ...? + * Usage: menu_del_item + * The given item in the given menu will be deleted. If you have deleted all + * the items from your client menu, that menu will automatically be removed. */ int menu_del_item_func (Client * c, int argc, char **argv) { + Menu * menu; + MenuItem * item; + char * menu_id; + char * item_id; if (!c->ack) return 1; - sock_send_string (c->sock, "huh? Not implemented yet.\n"); + if ((argc < 4 )) { + sock_send_string (c->sock, "huh? Usage: menu_del_item \n"); + return 0; + } + menu_id = argv[1]; + item_id = argv[2]; + + if ( menu_id[0] == 0 ) { + /* No menu specified = client's main menu */ + menu = c->menu; + } else { + /* A specified menu */ + menu = menu_find_item (c->menu, menu_id, true); + } + if (!menu) { + sock_send_string (c->sock, "huh? Cannot find menu id\n"); + return 0; + } + + item = menu_find_item (c->menu, item_id, true); + if (!item) { + sock_send_string (c->sock, "huh? Cannot find item\n"); + return 0; + } + menu_remove_item (menu, item); + menuitem_destroy (item); + + sock_send_string(c->sock, "success\n"); return 0; } /************************************************************************** + * menu_set_item_func * Sets the info about a menu item * - * For example, text displayed, widget type, value, etc... + * For example, text displayed, value, etc... * - * usage: menu_set_item ...? + * Usage: menu_set_item {