console_board.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright 2007-2008, Marta Carbone, Luigi Rizzo
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  *
00016  * $Revision: 369013 $
00017  */
00018 
00019 /* 
00020  * Message board implementation.
00021  *
00022  * A message board is a region of the SDL screen where
00023  * messages can be printed, like on a terminal window.
00024  *
00025  * At the moment we support fix-size font.
00026  *
00027  * The text is stored in a buffer
00028  * of fixed size (rows and cols). A portion of the buffer is
00029  * visible on the screen, and the visible window can be moved up and
00030  * down by dragging (not yet!)
00031  * 
00032  * TODO: font dynamic allocation
00033  *
00034  * The region where the text is displayed on the screen is defined
00035  * as keypad element, (the name is defined in the `region' variable
00036  * so the board geometry can be read from the skin or from the
00037  * configuration file).
00038  */
00039 
00040 /*** MODULEINFO
00041    <support_level>extended</support_level>
00042  ***/
00043 
00044 #include "asterisk.h"   /* ast_strdupa */
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
00046 #include "asterisk/utils.h"   /* ast_strdupa */
00047 #include "console_video.h" /* ast_strdupa */
00048 
00049 #ifdef HAVE_SDL   /* we only use this code if SDL is available */
00050 #include <SDL/SDL.h>
00051 
00052 /* Fonts characterization. XXX should be read from the file */
00053 #define FONT_H 20       /* char height, pixels */
00054 #define FONT_W 9        /* char width, pixels */
00055 
00056 struct board {
00057    int      kb_output;  /* identity of the board */
00058    /* pointer to the destination surface (on the keypad window) */
00059    SDL_Surface *screen; /* the main screen */
00060    SDL_Rect *p_rect; /* where to write on the main screen */
00061    SDL_Surface *blank;     /* original content of the window */
00062 
00063    int   v_h;  /* virtual text height, in lines */
00064    int   v_w;  /* virtual text width, in lines (probably same as p_w) */
00065    int   p_h;  /* physical (displayed) text height, in lines
00066           * XXX p_h * FONT_H = pixel_height */
00067    int   p_w;  /* physical (displayed) text width, in characters
00068           * XXX p_w * FONT_W = pixel_width */
00069 
00070    int   cur_col; /* print position (free character) on the last line */
00071    int   cur_line;   /* first (or last ?) virtual line displayed,
00072                 * 0 is the line at the bottom, 1 is the one above,...
00073                 */
00074 
00075    SDL_Surface     *font;     /* points to a surface in the gui structure */
00076    SDL_Rect *font_rects;   /* pointer to the font rects */
00077    char     *text;
00078             /* text buffer, v_h * v_w char.
00079              * We make sure the buffer is always full,
00080              * print on some position on the last line,
00081              * and scroll up when appending new text
00082              */
00083 };
00084 
00085 /*! \brief Initialize the board.
00086  * return 0 on success, 1 on error
00087  * TODO, if this is done at reload time,
00088  * free resources before allocate new ones
00089  * TODO: resource deallocation in case of error.
00090  * TODO: move the font load at gui_initialization
00091  * TODO: deallocation of the message history
00092  */
00093 struct board *board_setup(SDL_Surface *screen, SDL_Rect *dest,
00094    SDL_Surface *font, SDL_Rect *font_rects);
00095 struct board *board_setup(SDL_Surface *screen, SDL_Rect *dest,
00096    SDL_Surface *font, SDL_Rect *font_rects)
00097 {
00098    struct board *b = ast_calloc(1, sizeof (*b));
00099    SDL_Rect br;
00100 
00101    if (b == NULL)
00102       return NULL;
00103    /* font, points to the gui structure */
00104    b->font = font;
00105    b->font_rects = font_rects;
00106 
00107    /* Destination rectangle on the screen - reference is the whole screen */
00108    b->p_rect = dest;
00109    b->screen = screen;
00110 
00111    /* compute physical sizes */
00112    b->p_h = b->p_rect->h/FONT_H;
00113    b->p_w = b->p_rect->w/FONT_W;
00114 
00115    /* virtual sizes */
00116    b->v_h = b->p_h * 10; /* XXX 10 times larger */
00117    b->v_w = b->p_w;  /* same width */
00118 
00119    /* the rectangle we actually use */
00120    br.h = b->p_h * FONT_H; /* pixel sizes of the background */
00121    br.w = b->p_w * FONT_W;
00122    br.x = br.y = 0;
00123 
00124    /* allocate a buffer for the text */
00125    b->text = ast_calloc(b->v_w*b->v_h + 1, 1);
00126    if (b->text == NULL) {
00127       ast_log(LOG_WARNING, "Unable to allocate board history memory.\n");
00128       ast_free(b);
00129       return NULL;
00130    }
00131    memset(b->text, ' ', b->v_w * b->v_h); /* fill with spaces */
00132 
00133    /* make a copy of the original rectangle, for cleaning up */
00134    b->blank = SDL_CreateRGBSurface(screen->flags, br.w, br.h,
00135       screen->format->BitsPerPixel,
00136       screen->format->Rmask, screen->format->Gmask,
00137       screen->format->Bmask, screen->format->Amask);
00138 
00139    if (b->blank == NULL) { 
00140       ast_log(LOG_WARNING, "Unable to allocate board virtual screen: %s\n",
00141             SDL_GetError());
00142       ast_free(b->text);
00143       ast_free(b);
00144       return NULL;
00145    }
00146    SDL_BlitSurface(screen, b->p_rect, b->blank, &br);
00147 
00148    /* Set color key, if not alpha channel present */
00149    //colorkey = SDL_MapRGB(b->board_surface->format, 0, 0, 0);
00150    //SDL_SetColorKey(b->board_surface, SDL_SRCCOLORKEY, colorkey);
00151 
00152    b->cur_col = 0;      /* current print column */
00153    b->cur_line = 0;  /* last line displayed */
00154 
00155    if (0) ast_log(LOG_WARNING, "Message board %dx%d@%d,%d successfully initialized\n",
00156       b->p_rect->w, b->p_rect->h,
00157       b->p_rect->x, b->p_rect->y);
00158    return b;
00159 }
00160 
00161 /* Render the text on the board surface.
00162  * The first line to render is the one at v_h - p_h - cur_line,
00163  * the size is p_h * p_w.
00164  * XXX we assume here that p_w = v_w.
00165  */
00166 static void render_board(struct board *b)
00167 {
00168    int first_row = b->v_h - b->p_h - b->cur_line;
00169    int first_char = b->v_w * first_row;
00170    int last_char = first_char + b->p_h * b->v_w;
00171    int i, col;
00172    SDL_Rect dst;
00173 
00174    /* top left char on the physical surface */
00175    dst.w = FONT_W;
00176    dst.h = FONT_H;
00177    dst.x = b->p_rect->x;
00178    dst.y = b->p_rect->y;
00179 
00180 
00181    /* clean the surface board */
00182    SDL_BlitSurface(b->blank, NULL, b->screen, b->p_rect);
00183 
00184    /* blit all characters */
00185    for (i = first_char, col = 0; i <  last_char; i++) {
00186       int c = b->text[i] - 32;   /* XXX first 32 chars are not printable */
00187       if (c < 0) /* buffer terminator or anything else is a blank */
00188          c = 0;
00189       SDL_BlitSurface(b->font, &b->font_rects[c], b->screen, &dst);
00190       /* point dst to next char position */
00191       dst.x += dst.w;
00192       col++;
00193       if (col >= b->v_w) { /* next row */
00194          dst.x = b->p_rect->x;
00195          dst.y += dst.h;
00196          col = 0;
00197       }
00198    }
00199    SDL_UpdateRects(b->screen, 1, b->p_rect); /* Update the screen */
00200 }
00201 
00202 void move_message_board(struct board *b, int dy)
00203 {
00204    int cur = b->cur_line + dy;
00205    if (cur < 0)
00206       cur = 0;
00207    else if (cur >= b->v_h - b->p_h)
00208       cur = b->v_h - b->p_h - 1;
00209    b->cur_line = cur;
00210    render_board(b);
00211 }
00212 
00213 /* return the content of a board */
00214 const char *read_message(const struct board *b)
00215 {
00216    return b->text;
00217 }
00218 
00219 int reset_board(struct board *b)
00220 {
00221    memset(b->text, ' ', b->v_w * b->v_h); /* fill with spaces */
00222    b->cur_col = 0;
00223    b->cur_line = 0;
00224    render_board(b);
00225    return 0;
00226 }
00227 /* Store the message on the history board
00228  * and blit on screen if required.
00229  * XXX now easy. only regular chars
00230  */
00231 int print_message(struct board *b, const char *s)
00232 {
00233    int i, l, row, col;
00234    char *dst;
00235 
00236    if (ast_strlen_zero(s))
00237       return 0;
00238 
00239    l = strlen(s);
00240    row = 0;
00241    col = b->cur_col;
00242    /* First, only check how much space we need.
00243     * Starting from the current print position, we move
00244     * it forward and down (if necessary) according to input
00245     * characters (including newlines, tabs, backspaces...).
00246     * At the end, row tells us how many rows to scroll, and
00247     * col (ignored) is the final print position.
00248     */
00249    for (i = 0; i < l; i++) {
00250       switch (s[i]) {
00251       case '\r':
00252          col = 0;
00253          break;
00254       case '\n':
00255          col = 0;
00256          row++;
00257          break;
00258       case '\b':
00259          if (col > 0)
00260             col--;
00261          break;
00262       default:
00263          if (s[i] < 32) /* signed, so take up to 127 */
00264             break;
00265          col++;
00266          if (col >= b->v_w) {
00267             col -= b->v_w;
00268             row++;
00269          }
00270          break;
00271       }
00272    }
00273    /* scroll the text window */
00274    if (row > 0) { /* need to scroll by 'row' rows */
00275       memcpy(b->text, b->text + row * b->v_w, b->v_w * (b->v_h - row));
00276       /* clean the destination area */
00277       dst = b->text + b->v_w * (b->v_h - row - 1) + b->cur_col;
00278       memset(dst, ' ', b->v_w - b->cur_col + b->v_w * row);
00279    }
00280    /* now do the actual printing. The print position is 'row' lines up
00281     * from the bottom of the buffer, start at the same 'cur_col' as before.
00282     * dst points to the beginning of the current line.
00283     */
00284    dst = b->text + b->v_w * (b->v_h - row - 1); /* start of current line */
00285    col = b->cur_col;
00286    for (i = 0; i < l; i++) {
00287       switch (s[i]) {
00288       case '\r':
00289          col = 0;
00290          break;
00291       case '\n':  /* move to beginning of next line */
00292          dst[col] = '\0'; /* mark the rest of the line as empty */
00293          col = 0;
00294          dst += b->v_w;
00295          break;
00296       case '\b':  /* one char back */
00297          if (col > 0)
00298             col--;
00299          dst[col] = ' '; /* delete current char */
00300          break;
00301       default:
00302          if (s[i] < 32) /* signed, so take up to 127 */
00303             break;   /* non printable */
00304          dst[col] = s[i];  /* store character */
00305          col++;
00306          if (col >= b->v_w) {
00307             col -= b->v_w;
00308             dst += b->v_w;
00309          }
00310          break;
00311       }
00312    }
00313    dst[col] = '\0'; /* the current position is empty */
00314    b->cur_col = col;
00315    /* everything is printed now, must do the rendering */
00316    render_board(b);
00317    return 1;
00318 }
00319 
00320 /* deletes a board.
00321  * we make the free operation on any fields of the board structure allocated
00322  * in dynamic memory
00323  */
00324 void delete_board(struct board *b)
00325 {
00326    if (b) {
00327       /* deletes the text */
00328       if (b->text)
00329          ast_free (b->text);
00330       /* deallocates the blank surface */
00331       SDL_FreeSurface(b->blank);
00332       /* deallocates the board */
00333       ast_free(b);
00334    }
00335 }
00336 
00337 #if 0
00338 /*! \brief refresh the screen, and also grab a bunch of events.
00339  */
00340 static int scroll_message(...)
00341 {
00342 if moving up, scroll text up;
00343     if (gui->message_board.screen_cur > 0)
00344    gui->message_board.screen_cur--;
00345 otherwise scroll text down.
00346     if ((b->screen_cur + b->p_line) < b->board_next) {
00347    gui->message_board.screen_cur++;
00348 #endif /* notyet */
00349 
00350 #endif /* HAVE_SDL */

Generated on Thu Apr 16 06:27:31 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6