Mon Jun 27 16:51:12 2011

Asterisk developer's documentation


console_gui.c File Reference

#include "asterisk.h"
#include "console_video.h"
#include "asterisk/lock.h"
#include "asterisk/frame.h"
#include "asterisk/utils.h"
#include <math.h>
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#include <X11/Xlib.h>

Go to the source code of this file.

Data Structures

struct  _s_k
struct  display_window
struct  gui_info
struct  keypad_entry
struct  thumb_bd

Defines

#define BORDER   5
#define FONT_H   20
#define FONT_W   9
#define IS_ON   4
#define IS_PRIMARY   1
#define IS_SECONDARY   2
#define MY_EV   (SDL_MOUSEBUTTONDOWN|SDL_KEYDOWN)
#define N_EVENTS   32
#define POLARITY   -1
#define SRC_MSG_BD_H   20

Enumerations

enum  {
  WIN_LOCAL, WIN_REMOTE, WIN_KEYPAD, WIN_SRC1,
  WIN_SRC2, WIN_SRC3, WIN_SRC4, WIN_SRC5,
  WIN_SRC6, WIN_SRC7, WIN_SRC8, WIN_SRC9,
  WIN_MAX
}
enum  kp_type { KP_NONE, KP_RECT, KP_CIRCLE }
enum  skin_area {
  KEY_PICK_UP = 128, KEY_HANG_UP = 129, KEY_MUTE = 130, KEY_AUTOANSWER = 131,
  KEY_SENDVIDEO = 132, KEY_LOCALVIDEO = 133, KEY_REMOTEVIDEO = 134, KEY_FLASH = 136,
  KEY_MESSAGEBOARD = 140, KEY_DIALEDBOARD = 141, KEY_EDITBOARD = 142, KEY_GUI_CLOSE = 199,
  KEY_KEYPAD = 200, KEY_FONT = 201, KEY_MESSAGE = 202, KEY_DIALED = 203,
  KEY_EDIT = 204, KEY_FREEZE = 220, KEY_CAPTURE = 221, KEY_PIP = 230,
  KEY_SRCS_WIN = 231, KEY_OUT_OF_KEYPAD = 241, KEY_REM_DPY = 242, KEY_LOC_DPY = 243,
  KEY_RESET = 253, KEY_NONE = 254, KEY_DIGIT_BACKGROUND = 255
}

Functions

boardboard_setup (SDL_Surface *screen, SDL_Rect *dest, SDL_Surface *font, SDL_Rect *font_rects)
static struct gui_infocleanup_sdl (struct gui_info *gui, int device_num)
 free the resources in struct gui_info and the descriptor itself. Return NULL so we can assign the value back to the descriptor in case.
int compute_drag (int *start, int end, int magnifier)
char * console_do_answer (int fd)
static void eventhandler (struct video_desc *env, const char *caption)
 refresh the screen, and also grab a bunch of events.
static void grabber_move (struct video_device *, int dx, int dy)
static struct gui_infogui_init (const char *keypad_file, const char *font)
static int gui_map_token (const char *s)
static void handle_keyboard_input (struct video_desc *env, SDL_keysym *ks)
static void handle_mousedown (struct video_desc *env, SDL_MouseButtonEvent button)
static void init_board (struct gui_info *gui, struct board **dst, SDL_Rect *r, int dx, int dy)
 initialize the boards we have in the keypad
static int keypad_cfg_read (struct gui_info *gui, const char *val)
 read a keypad entry line in the format reset token circle xc yc diameter token circle xc yc x1 y1 h # ellipse, main diameter and height token rect x0 y0 x1 y1 h # rectangle with main side and eight token x0 y0 w h # horizontal rectangle (short format) # this is used e.g. for message boards token is the token to be returned, either a character or a symbol as KEY_* above Return 1 on success, 0 on error.
static void keypad_digit (struct video_desc *env, int digit)
static void keypad_pick_up (struct video_desc *env)
static void keypad_setup (struct gui_info *gui, const char *kp_file)
static char * keypad_toggle (struct video_desc *env, int index)
static int kp_match_area (const struct keypad_entry *e, int x, int y)
static SDL_Surface * load_image (const char *file)
static char map_key (SDL_keysym *ks)
static int my_x_handler (Display *d, XErrorEvent *e)
static void pip_move (struct video_desc *env, int dx, int dy)
 This function moves the picture in picture, controlling the limits of the containing buffer to avoid problems deriving from going through the limits.
static void sdl_setup (struct video_desc *env)
 [re]set the main sdl window, useful in case of resize. We can tell the first from subsequent calls from the value of env->gui, which is NULL the first time.
static void set_drag (struct drag_info *drag, int x, int y, enum drag_window win)
static int set_win (SDL_Surface *screen, struct display_window *win, int fmt, int w, int h, int x, int y)
static void show_frame (struct video_desc *env, int out)
static int switch_video_out (struct video_desc *env, int index, Uint8 button)
 Changes the video output (local video) source, controlling if it is already using that video device, and switching the correct fields of env->out. grabbers are always open and saved in the device table. The secondary or the primary device can be changed, according to the "button" parameter: the primary device is changed if button = SDL_BUTTON_LEFT; the secondary device is changed if button = not SDL_BUTTON_LEFT;.
static int turn_on_off (int index, struct video_desc *env)
 tries to switch the state of a device from on to off or off to on we also have to update the status of the device and the correct message board
static int update_device_info (struct video_desc *env, int i)
static int video_geom (struct fbuf_t *b, const char *s)

Variables

static struct _s_k gui_key_map []
char * src_msgs []
static const char *const us_kbd_map []


Define Documentation

#define BORDER   5

Definition at line 113 of file console_gui.c.

Referenced by handle_mousedown(), and sdl_setup().

#define FONT_H   20

#define FONT_W   9

#define IS_ON   4

Definition at line 233 of file console_gui.c.

Referenced by turn_on_off().

#define IS_PRIMARY   1

Definition at line 231 of file console_gui.c.

Referenced by switch_video_out().

#define IS_SECONDARY   2

Definition at line 232 of file console_gui.c.

Referenced by switch_video_out().

#define MY_EV   (SDL_MOUSEBUTTONDOWN|SDL_KEYDOWN)

#define N_EVENTS   32

Referenced by eventhandler().

#define POLARITY   -1

Referenced by compute_drag().

#define SRC_MSG_BD_H   20

Definition at line 114 of file console_gui.c.

Referenced by handle_mousedown(), and sdl_setup().


Enumeration Type Documentation

anonymous enum

Enumerator:
WIN_LOCAL 
WIN_REMOTE 
WIN_KEYPAD 
WIN_SRC1 
WIN_SRC2 
WIN_SRC3 
WIN_SRC4 
WIN_SRC5 
WIN_SRC6 
WIN_SRC7 
WIN_SRC8 
WIN_SRC9 
WIN_MAX 

Definition at line 89 of file console_gui.c.

enum kp_type

Enumerator:
KP_NONE 
KP_RECT 
KP_CIRCLE 

Definition at line 116 of file console_gui.c.

00116 { KP_NONE, KP_RECT, KP_CIRCLE };

enum skin_area

Enumerator:
KEY_PICK_UP 
KEY_HANG_UP 
KEY_MUTE 
KEY_AUTOANSWER 
KEY_SENDVIDEO 
KEY_LOCALVIDEO 
KEY_REMOTEVIDEO 
KEY_FLASH 
KEY_MESSAGEBOARD 
KEY_DIALEDBOARD 
KEY_EDITBOARD 
KEY_GUI_CLOSE 
KEY_KEYPAD 
KEY_FONT 
KEY_MESSAGE 
KEY_DIALED 
KEY_EDIT 
KEY_FREEZE 
KEY_CAPTURE 
KEY_PIP 
KEY_SRCS_WIN 
KEY_OUT_OF_KEYPAD 
KEY_REM_DPY 
KEY_LOC_DPY 
KEY_RESET 
KEY_NONE 
KEY_DIGIT_BACKGROUND 

Definition at line 314 of file console_gui.c.

00314                {
00315    /* answer/close functions */
00316    KEY_PICK_UP = 128,
00317    KEY_HANG_UP = 129,
00318 
00319    KEY_MUTE = 130,
00320    KEY_AUTOANSWER = 131,
00321    KEY_SENDVIDEO = 132,
00322    KEY_LOCALVIDEO = 133,
00323    KEY_REMOTEVIDEO = 134,
00324    KEY_FLASH = 136,
00325 
00326    /* sensitive areas for the various text windows */
00327    KEY_MESSAGEBOARD = 140,
00328    KEY_DIALEDBOARD = 141,
00329    KEY_EDITBOARD = 142,
00330 
00331    KEY_GUI_CLOSE = 199,    /* close gui */
00332    /* regions of the skin - displayed area, fonts, etc.
00333     * XXX NOTE these are not sensitive areas.
00334     */
00335    KEY_KEYPAD = 200,    /* the keypad - default to the whole image */
00336    KEY_FONT = 201,      /* the font. Maybe not really useful */
00337    KEY_MESSAGE = 202,   /* area for incoming messages */
00338    KEY_DIALED = 203, /* area for dialed numbers */
00339    KEY_EDIT = 204,      /* area for editing user input */
00340 
00341 #ifdef notyet /* XXX for future implementation */
00342    KEY_AUDIO_SRCS = 210,
00343    /*indexes between 210 and 219 (or more) have been reserved for the "keys"
00344    associated with the audio device markers, clicking on these markers
00345    will change the source device for audio output */
00346 
00347 #endif
00348    /* Keys related to video sources */
00349    KEY_FREEZE = 220, /* freeze the incoming video */
00350    KEY_CAPTURE = 221,   /* capture the whole SDL window as a picture */
00351    KEY_PIP = 230,
00352    /*indexes between 231 and 239 have been reserved for the "keys"
00353    associated with the device thumbnails, clicking on these pictures
00354    will change the source device for primary or secondary (PiP) video output*/
00355    KEY_SRCS_WIN = 231, /* till 239 */
00356    /* areas outside the keypad - simulated */
00357    KEY_OUT_OF_KEYPAD = 241,
00358    KEY_REM_DPY = 242,
00359    KEY_LOC_DPY = 243,
00360    KEY_RESET = 253,     /* the 'reset' keyword */
00361    KEY_NONE = 254,         /* invalid area */
00362    KEY_DIGIT_BACKGROUND = 255,   /* other areas within the keypad */
00363 };


Function Documentation

struct board* board_setup ( SDL_Surface *  screen,
SDL_Rect *  dest,
SDL_Surface *  font,
SDL_Rect *  font_rects 
)

static struct gui_info* cleanup_sdl ( struct gui_info gui,
int  device_num 
) [static]

free the resources in struct gui_info and the descriptor itself. Return NULL so we can assign the value back to the descriptor in case.

Definition at line 181 of file console_gui.c.

References ast_free, display_window::bmp, delete_board(), gui_info::font, gui_info::keypad, gui_info::kp, gui_info::outfd, gui_info::win, and WIN_MAX.

00182 {
00183    int i;
00184 
00185    if (gui == NULL)
00186       return NULL;
00187 
00188    /* unload font file */ 
00189    if (gui->font) {
00190       SDL_FreeSurface(gui->font);
00191       gui->font = NULL; 
00192    }
00193 
00194    if (gui->outfd > -1)
00195       close(gui->outfd);
00196    if (gui->keypad)
00197       SDL_FreeSurface(gui->keypad);
00198    gui->keypad = NULL;
00199    if (gui->kp)
00200       ast_free(gui->kp);
00201 
00202    /* uninitialize the SDL environment */
00203    for (i = 0; i < WIN_MAX; i++) {
00204       if (gui->win[i].bmp)
00205          SDL_FreeYUVOverlay(gui->win[i].bmp);
00206    }
00207    memset(gui, '\0', sizeof(gui));
00208 
00209    /* deallocates the space allocated for the keypad message boards */
00210    if (gui->bd_dialed)
00211       delete_board(gui->bd_dialed);
00212    if (gui->bd_msg)
00213       delete_board(gui->bd_msg);
00214 
00215    /* deallocates the space allocated for the thumbnail message boards */
00216    for (i = 0; i < device_num; i++) {
00217       if (gui->thumb_bd_array[i].board) /* may be useless */
00218          delete_board(gui->thumb_bd_array[i].board);
00219    }
00220    
00221    ast_free(gui);
00222    SDL_Quit();
00223    return NULL;
00224 }

int compute_drag ( int *  start,
int  end,
int  magnifier 
)

Definition at line 901 of file console_gui.c.

References POLARITY.

Referenced by eventhandler().

00902 {
00903    int delta = end - *start;
00904 #define POLARITY -1
00905    /* add a small quadratic term */
00906    delta += delta * delta * (delta > 0 ? 1 : -1 )/100;
00907    delta *= POLARITY * magnifier;
00908 #undef POLARITY
00909    *start = end;
00910    return delta;
00911 }

char* console_do_answer ( int  fd  ) 

static void eventhandler ( struct video_desc *  env,
const char *  caption 
) [static]

refresh the screen, and also grab a bunch of events.

Definition at line 949 of file console_gui.c.

References ast_cli_command, ast_log(), gui_info::bd_msg, compute_drag(), gui_info::drag, DRAG_LOCAL, DRAG_MESSAGE, DRAG_NONE, DRAG_PIP, drag_info::drag_window, grabber_move(), handle_keyboard_input(), handle_mousedown(), LOG_WARNING, move_message_board(), N_EVENTS, gui_info::outfd, pip_move(), type, drag_info::x_start, and drag_info::y_start.

00950 {
00951    struct gui_info *gui = env->gui;
00952    struct drag_info *drag;
00953 #define N_EVENTS  32
00954    int i, n;
00955    SDL_Event ev[N_EVENTS];
00956 
00957    if (!gui)
00958       return;
00959    drag = &gui->drag;
00960    if (caption)
00961       SDL_WM_SetCaption(caption, NULL);
00962 
00963 #define MY_EV (SDL_MOUSEBUTTONDOWN|SDL_KEYDOWN)
00964    while ( (n = SDL_PeepEvents(ev, N_EVENTS, SDL_GETEVENT, SDL_ALLEVENTS)) > 0) {
00965       for (i = 0; i < n; i++) {
00966 #if 0
00967          ast_log(LOG_WARNING, "------ event %d at %d %d\n",
00968             ev[i].type,  ev[i].button.x,  ev[i].button.y);
00969 #endif
00970          switch (ev[i].type) {
00971          default:
00972             ast_log(LOG_WARNING, "------ event %d at %d %d\n",
00973                ev[i].type,  ev[i].button.x,  ev[i].button.y);
00974             break;
00975 
00976          case SDL_ACTIVEEVENT:
00977 #if 0 /* do not react, we don't want to die because the window is minimized */
00978             if (ev[i].active.gain == 0 && ev[i].active.state & SDL_APPACTIVE) {
00979                ast_log(LOG_WARNING, "/* somebody has killed us ? */");
00980                ast_cli_command(gui->outfd, "stop now");
00981             }
00982 #endif
00983             break;
00984 
00985          case SDL_KEYUP:   /* ignore, for the time being */
00986             break;
00987 
00988          case SDL_KEYDOWN:
00989             handle_keyboard_input(env, &ev[i].key.keysym);
00990             break;
00991 
00992          case SDL_MOUSEMOTION:
00993          case SDL_MOUSEBUTTONUP:
00994             if (drag->drag_window == DRAG_LOCAL && env->out.device_num) {
00995                /* move the capture source */
00996                int dx = compute_drag(&drag->x_start, ev[i].motion.x, 3);
00997                int dy = compute_drag(&drag->y_start, ev[i].motion.y, 3);
00998                grabber_move(&env->out.devices[env->out.device_primary], dx, dy);
00999             } else if (drag->drag_window == DRAG_PIP) {
01000                /* move the PiP image inside the frames of the enc_in buffers */
01001                int dx = ev[i].motion.x - drag->x_start;
01002                int dy = ev[i].motion.y - drag->y_start;
01003                /* dx and dy value are directly applied to env->out.pip_x and
01004                env->out.pip_y, so they must work as if the format was cif */
01005                dx = (double)dx*env->enc_in.w/env->loc_dpy.w;
01006                dy = (double)dy*env->enc_in.h/env->loc_dpy.h;
01007                /* sets starts to a new value */
01008                drag->x_start = ev[i].motion.x;
01009                drag->y_start = ev[i].motion.y;
01010                /* ast_log(LOG_WARNING, "moving: %d, %d\n", dx, dy); */
01011                pip_move(env, dx, dy);
01012             } else if (drag->drag_window == DRAG_MESSAGE) {
01013                /* scroll up/down the window */
01014                int dy = compute_drag(&drag->y_start, ev[i].motion.y, 1);
01015                move_message_board(gui->bd_msg, dy);
01016             }
01017             if (ev[i].type == SDL_MOUSEBUTTONUP)
01018                drag->drag_window = DRAG_NONE;
01019             break;
01020          case SDL_MOUSEBUTTONDOWN:
01021             handle_mousedown(env, ev[i].button);
01022             break;
01023          }
01024       }
01025    }
01026    if (1) {
01027       struct timeval b, a = ast_tvnow();
01028       int i;
01029       //SDL_Lock_EventThread();
01030       SDL_PumpEvents();
01031       b = ast_tvnow();
01032       i = ast_tvdiff_ms(b, a);
01033       if (i > 3)
01034          fprintf(stderr, "-------- SDL_PumpEvents took %dms\n", i);
01035       //SDL_Unlock_EventThread();
01036    }
01037 }

static void grabber_move ( struct video_device *  ,
int  dx,
int  dy 
) [static]

Referenced by eventhandler().

static struct gui_info* gui_init ( const char *  keypad_file,
const char *  font 
) [static]

Definition at line 1058 of file console_gui.c.

References ast_calloc, ast_free, ast_log(), ast_strlen_zero(), DRAG_NONE, FONT_H, FONT_W, keypad_setup(), KO_MESSAGE, load_image(), and LOG_WARNING.

Referenced by sdl_setup().

01059 {
01060    struct gui_info *gui = ast_calloc(1, sizeof(*gui));
01061 
01062    if (gui == NULL)
01063       return NULL;
01064    /* initialize keypad status */
01065    gui->kb_output = KO_MESSAGE;  /* XXX temp */
01066    gui->drag.drag_window = DRAG_NONE;
01067    gui->outfd = -1;
01068 
01069    keypad_setup(gui, keypad_file);
01070    if (gui->keypad == NULL)   /* no keypad, we are done */
01071       return gui;
01072    /* XXX load image */
01073    if (!ast_strlen_zero(font)) {
01074       int i;
01075       SDL_Rect *r;
01076 
01077       gui->font = load_image(font);
01078       if (!gui->font) {
01079          ast_log(LOG_WARNING, "Unable to load font %s, no output available\n", font);
01080          goto error;
01081       }
01082       ast_log(LOG_WARNING, "Loaded font %s\n", font);
01083       /* XXX hardwired constants - 3 rows of 32 chars */
01084       r = gui->font_rects;
01085 #define FONT_H 20
01086 #define FONT_W 9
01087       for (i = 0; i < 96; r++, i++) {
01088                   r->x = (i % 32 ) * FONT_W;
01089                   r->y = (i / 32 ) * FONT_H;
01090                   r->w = FONT_W;
01091                   r->h = FONT_H;
01092       }
01093    }
01094 
01095    gui->outfd = open ("/dev/null", O_WRONLY);   /* discard output, temporary */
01096    if (gui->outfd < 0) {
01097       ast_log(LOG_WARNING, "Unable output fd\n");
01098       goto error;
01099    }
01100    return gui;
01101 
01102 error:
01103    ast_free(gui);
01104    return NULL;
01105 }

static int gui_map_token ( const char *  s  )  [static]

Definition at line 1532 of file console_gui.c.

References gui_key_map, _s_k::k, KEY_NONE, and _s_k::s.

Referenced by keypad_cfg_read().

01533 {
01534    /* map the string into token to be returned */
01535    int i = atoi(s);
01536    struct _s_k *p;
01537    if (i > 0 || s[1] == '\0') /* numbers or single characters */
01538       return (i > 9) ? i : s[0];
01539    for (p = gui_key_map; p->s; p++) {
01540       if (!strcasecmp(p->s, s))
01541          return p->k;
01542    }
01543    return KEY_NONE;  /* not found */
01544 }

static void handle_keyboard_input ( struct video_desc *  env,
SDL_keysym *  ks 
) [static]

Definition at line 871 of file console_gui.c.

References gui_info::bd_msg, gui_info::kb_output, keypad_pick_up(), KO_DIALED, KO_INPUT, KO_MESSAGE, map_key(), and print_message().

Referenced by eventhandler().

00872 {
00873    char buf[2] = { map_key(ks), '\0' };
00874    struct gui_info *gui = env->gui;
00875    if (buf[0] == 0)  /* modifier ? */
00876       return;
00877    switch (gui->kb_output) {
00878    default:
00879       break;
00880    case KO_INPUT: /* to be completed */
00881       break;
00882    case KO_MESSAGE:
00883       if (gui->bd_msg) {
00884          print_message(gui->bd_msg, buf);
00885          if (buf[0] == '\r' || buf[0] == '\n') {
00886             keypad_pick_up(env);
00887          }
00888       }
00889       break;
00890 
00891    case KO_DIALED: /* to be completed */
00892       break;
00893    }
00894 
00895    return;
00896 }

static void handle_mousedown ( struct video_desc *  env,
SDL_MouseButtonEvent  button 
) [static]

Definition at line 615 of file console_gui.c.

References ast_log(), BORDER, keypad_entry::c, gui_info::drag, DRAG_NONE, drag_info::drag_window, KEY_LOC_DPY, KEY_OUT_OF_KEYPAD, KEY_REM_DPY, gui_info::keypad, gui_info::kp, kp_match_area(), gui_info::kp_size, gui_info::kp_used, LOG_WARNING, MAX, SRC_MSG_BD_H, SRC_WIN_H, and SRC_WIN_W.

Referenced by eventhandler().

00616 {
00617    uint8_t index = KEY_OUT_OF_KEYPAD;  /* the key or region of the display we clicked on */
00618    struct gui_info *gui = env->gui;
00619       
00620    int i; /* integer variable used as iterator */
00621 
00622    int x; /* integer variable usable as a container */
00623    
00624    /* total width of source device thumbnails */
00625    int src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
00626 
00627    /* x coordinate of the center of the keypad */
00628    int x0 = MAX(env->rem_dpy.w+gui->keypad->w/2+2*BORDER, src_wins_tot_w/2);
00629    
00630 #if 0
00631    ast_log(LOG_WARNING, "event %d %d have %d/%d regions at %p\n",
00632       button.x, button.y, gui->kp_used, gui->kp_size, gui->kp);
00633 #endif
00634    /* for each mousedown we end previous drag */
00635    gui->drag.drag_window = DRAG_NONE;
00636    
00637    /* define keypad boundary */
00638    /* XXX this should be extended for clicks on different audio device markers */
00639    if (button.y >= (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0)) {
00640       /* if control reaches this point this means that the clicked point is
00641       below the row of the additional sources windows*/
00642       /* adjust the y coordinate as if additional devices windows were not present */
00643       button.y -= (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
00644       if (button.y < BORDER)
00645          index = KEY_OUT_OF_KEYPAD;
00646       else if (button.y >= MAX(MAX(env->rem_dpy.h, env->loc_dpy.h), gui->keypad->h))
00647          index = KEY_OUT_OF_KEYPAD;
00648       else if (button.x < x0 - gui->keypad->w/2 - BORDER - env->rem_dpy.w)
00649          index = KEY_OUT_OF_KEYPAD;
00650       else if (button.x < x0 - gui->keypad->w/2 - BORDER)
00651          index = KEY_REM_DPY;
00652       else if (button.x < x0 - gui->keypad->w/2)
00653          index = KEY_OUT_OF_KEYPAD;
00654       else if (button.x >= x0 + gui->keypad->w/2 + BORDER + env->loc_dpy.w)
00655          index = KEY_OUT_OF_KEYPAD;
00656       else if (button.x >= x0 + gui->keypad->w/2 + BORDER)
00657          index = KEY_LOC_DPY;
00658       else if (button.x >= x0 + gui->keypad->w/2)
00659          index = KEY_OUT_OF_KEYPAD;
00660       else if (gui->kp) {
00661          /* we have to calculate the first coordinate 
00662          inside the keypad before calling the kp_match_area*/
00663          int x_keypad = button.x - (x0 - gui->keypad->w/2);
00664          /* find the key clicked (if one was clicked) */
00665          for (i = 0; i < gui->kp_used; i++) {
00666             if (kp_match_area(&gui->kp[i],x_keypad, button.y - BORDER)) {
00667                index = gui->kp[i].c;
00668                break;
00669             }
00670          }
00671       }
00672    } else if (button.y < BORDER) {
00673       index = KEY_OUT_OF_KEYPAD;
00674    } else {  /* we are in the thumbnail area */
00675       x = x0 - src_wins_tot_w/2 + BORDER;
00676       if (button.y >= BORDER + SRC_WIN_H)
00677          index = KEY_OUT_OF_KEYPAD;
00678       else if (button.x < x)
00679          index = KEY_OUT_OF_KEYPAD;
00680       else if (button.x < x + src_wins_tot_w - BORDER) {
00681          /* note that the additional device windows 
00682          are numbered from left to right
00683          starting from 0, with a maximum of 8, the index associated on a click is:
00684          KEY_SRCS_WIN + number_of_the_window */
00685          for (i = 1; i <= env->out.device_num; i++) {
00686             if (button.x < x+i*(SRC_WIN_W+BORDER)-BORDER) {
00687                index = KEY_SRCS_WIN+i-1;
00688                break;
00689             } else if (button.x < x+i*(SRC_WIN_W+BORDER)) {
00690                index = KEY_OUT_OF_KEYPAD;
00691                break;
00692             }
00693          }
00694       } else
00695          index = KEY_OUT_OF_KEYPAD;
00696    }
00697 
00698    /* exec the function */
00699    if (index < 128) {   /* surely clicked on the keypad, don't care which key */
00700       keypad_digit(env, index);
00701       return;
00702    }
00703 
00704    else if (index >= KEY_SRCS_WIN && index < KEY_SRCS_WIN+env->out.device_num) {
00705       index -= KEY_SRCS_WIN; /* index of the window, equal to the device index in the table */
00706       /* if one of the additional device windows is clicked with
00707       left or right mouse button, we have to switch to that device */
00708       if (button.button == SDL_BUTTON_RIGHT || button.button == SDL_BUTTON_LEFT) {
00709          switch_video_out(env, index, button.button);
00710          return;
00711       }
00712       /* turn on or off the devices selectively with other mouse buttons */
00713       else {
00714          int ret = turn_on_off(index, env);
00715          /* print a message according to what happened */
00716          if (!ret)
00717             ast_log(LOG_WARNING, "unable to turn on device %s\n",
00718                env->out.devices[index].name);
00719          else if (ret == 1)
00720             ast_log(LOG_WARNING, "device %s changed state to on\n",
00721                env->out.devices[index].name);
00722          else if (ret == 2)
00723             ast_log(LOG_WARNING, "device %s changed state to off\n",
00724                env->out.devices[index].name);
00725          return;
00726       }
00727    }
00728 
00729    /* XXX for future implementation
00730    else if (click on audio source marker)
00731       change audio source device
00732    */
00733 
00734    switch (index) {
00735    /* answer/close function */
00736    case KEY_PICK_UP:
00737       keypad_pick_up(env);
00738       break;
00739    case KEY_HANG_UP:
00740       ast_cli_command(gui->outfd, "console hangup");
00741       break;
00742 
00743    /* other functions */
00744    case KEY_MUTE: /* send or not send the audio */
00745    case KEY_AUTOANSWER:
00746    case KEY_SENDVIDEO: /* send or not send the video */
00747    case KEY_PIP: /* activate/deactivate picture in picture mode */
00748    case KEY_FREEZE: /* freeze/unfreeze the incoming video */
00749       keypad_toggle(env, index);
00750       break;
00751 
00752    case KEY_LOCALVIDEO:
00753       break;
00754    case KEY_REMOTEVIDEO:
00755       break;
00756 
00757 #ifdef notyet /* XXX for future implementations */
00758    case KEY_CAPTURE:
00759       break;
00760 #endif
00761 
00762    case KEY_MESSAGEBOARD:
00763       if (button.button == SDL_BUTTON_LEFT)
00764          set_drag(&gui->drag, button.x, button.y, DRAG_MESSAGE);
00765       break;
00766 
00767    /* press outside the keypad. right increases size, center decreases, left drags */
00768    case KEY_LOC_DPY:
00769    case KEY_REM_DPY:
00770       if (button.button == SDL_BUTTON_LEFT) {
00771          /* values used to find the position of the picture in picture (if present) */
00772          int pip_loc_x = (double)env->out.pip_x/env->enc_in.w * env->loc_dpy.w;
00773          int pip_loc_y = (double)env->out.pip_y/env->enc_in.h * env->loc_dpy.h;
00774          /* check if picture in picture is active and the click was on it */
00775          if (index == KEY_LOC_DPY && env->out.picture_in_picture &&
00776            button.x >= x0+gui->keypad->w/2+BORDER+pip_loc_x &&
00777            button.x < x0+gui->keypad->w/2+BORDER+pip_loc_x+env->loc_dpy.w/3 &&
00778            button.y >= BORDER+pip_loc_y && 
00779            button.y < BORDER+pip_loc_y+env->loc_dpy.h/3) {
00780             /* set the y cordinate to his previous value */
00781             button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
00782             /* starts dragging the picture inside the picture */
00783             set_drag(&gui->drag, button.x, button.y, DRAG_PIP);
00784          }
00785          else if (index == KEY_LOC_DPY) {
00786             /* set the y cordinate to his previous value */
00787             button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
00788             /* click in the local display, but not on the PiP */
00789             set_drag(&gui->drag, button.x, button.y, DRAG_LOCAL);
00790          }
00791          break;
00792       } else {
00793          char buf[128];
00794          struct fbuf_t *fb = index == KEY_LOC_DPY ? &env->loc_dpy : &env->rem_dpy;
00795          sprintf(buf, "%c%dx%d", button.button == SDL_BUTTON_RIGHT ? '>' : '<',
00796             fb->w, fb->h);
00797          video_geom(fb, buf);
00798          sdl_setup(env);
00799          /* writes messages in the source boards, those can be 
00800          modified during the execution, because of the events 
00801          this must be done here, otherwise the status of sources will not be
00802          shown after sdl_setup */
00803          for (i = 0; i < env->out.device_num; i++) {
00804             update_device_info(env, i);
00805          }
00806          /* we also have to refresh other boards, 
00807          to avoid messages to disappear after video resize */
00808          print_message(gui->bd_msg, " \b");
00809          print_message(gui->bd_dialed, " \b");
00810       }
00811       break;
00812    case KEY_OUT_OF_KEYPAD:
00813       ast_log(LOG_WARNING, "nothing clicked, coordinates: %d, %d\n", button.x, button.y);
00814       break;
00815 
00816    case KEY_DIGIT_BACKGROUND:
00817       break;
00818 
00819    default:
00820       ast_log(LOG_WARNING, "function not yet defined %i\n", index);
00821    }
00822 }

static void init_board ( struct gui_info gui,
struct board **  dst,
SDL_Rect *  r,
int  dx,
int  dy 
) [static]

initialize the boards we have in the keypad

Definition at line 1182 of file console_gui.c.

References board_setup(), gui_info::font, gui_info::font_rects, and gui_info::screen.

Referenced by sdl_setup().

01183 {
01184    if (r[0].w == 0 || r[0].h == 0)
01185       return;  /* not available */
01186    r[1] = r[0];   /* copy geometry */
01187    r[1].x += dx;  /* add offset of main window */
01188    r[1].y += dy;
01189    if (*dst == NULL) {  /* initial call */
01190       *dst = board_setup(gui->screen, &r[1], gui->font, gui->font_rects);
01191    } else {
01192       /* call a refresh */
01193    }
01194 }

static int keypad_cfg_read ( struct gui_info gui,
const char *  val 
) [static]

read a keypad entry line in the format reset token circle xc yc diameter token circle xc yc x1 y1 h # ellipse, main diameter and height token rect x0 y0 x1 y1 h # rectangle with main side and eight token x0 y0 w h # horizontal rectangle (short format) # this is used e.g. for message boards token is the token to be returned, either a character or a symbol as KEY_* above Return 1 on success, 0 on error.

Definition at line 1557 of file console_gui.c.

References ast_calloc, ast_log(), ast_realloc, gui_map_token(), KEY_DIALED, KEY_EDIT, KEY_FONT, KEY_KEYPAD, KEY_MESSAGE, KEY_NONE, KEY_RESET, gui_info::kp, KP_CIRCLE, gui_info::kp_dialed, gui_info::kp_edit, gui_info::kp_msg, KP_RECT, gui_info::kp_rect, gui_info::kp_size, gui_info::kp_used, and LOG_WARNING.

Referenced by keypad_setup().

01558 {
01559    struct keypad_entry e;
01560    SDL_Rect *r = NULL;
01561    char s1[16], s2[16];
01562    int i, ret = 0; /* default, error */
01563 
01564    if (gui == NULL || val == NULL)
01565       return 0;
01566 
01567    s1[0] = s2[0] = '\0';
01568    memset(&e, '\0', sizeof(e));
01569    i = sscanf(val, "%14s %14s %d %d %d %d %d",
01570                 s1, s2, &e.x0, &e.y0, &e.x1, &e.y1, &e.h);
01571 
01572    e.c = gui_map_token(s1);
01573    if (e.c == KEY_NONE)
01574       return 0;   /* nothing found */
01575    switch (i) {
01576    default:
01577       break;
01578    case 1:  /* only "reset" is allowed */
01579       if (e.c != KEY_RESET)
01580          break;
01581       if (gui->kp)
01582          gui->kp_used = 0;
01583       break;
01584    case 5:
01585       if (e.c == KEY_KEYPAD)  /* active keypad area */
01586          r = &gui->kp_rect;
01587       else if (e.c == KEY_MESSAGE)
01588          r = gui->kp_msg;
01589       else if (e.c == KEY_DIALED)
01590          r = gui->kp_dialed;
01591       else if (e.c == KEY_EDIT)
01592          r = gui->kp_edit;
01593       if (r) {
01594          r->x = atoi(s2);  /* this becomes x0 */
01595          r->y = e.x0;      /* this becomes y0 */
01596          r->w = e.y0;      /* this becomes w  */
01597          r->h = e.x1;      /* this becomes h  */
01598          break;
01599       }
01600       if (strcasecmp(s2, "circle")) /* invalid */
01601          break;
01602       /* token circle xc yc diameter */
01603       e.h = e.x1;
01604       e.y1 = e.y0;   /* map radius in x1 y1 */
01605       e.x1 = e.x0 + e.h;   /* map radius in x1 y1 */
01606       e.x0 = e.x0 - e.h;   /* map radius in x1 y1 */
01607       /* fallthrough */
01608 
01609    case 7:
01610       if (e.c == KEY_FONT) {  /* font - x0 y0 w h rows cols */
01611          ast_log(LOG_WARNING, "font not supported yet\n");
01612          break;
01613       }
01614       /* token circle|rect x0 y0 x1 y1 h */
01615       if (e.x1 < e.x0 || e.h <= 0) {
01616          ast_log(LOG_WARNING, "error in coordinates\n");
01617          e.type = 0;
01618          break;
01619       }
01620       if (!strcasecmp(s2, "circle")) {
01621          /* for a circle we specify the diameter but store center and radii */
01622          e.type = KP_CIRCLE;
01623          e.x0 = (e.x1 + e.x0) / 2;
01624          e.y0 = (e.y1 + e.y0) / 2;
01625          e.h = e.h / 2;
01626       } else if (!strcasecmp(s2, "rect")) {
01627          e.type = KP_RECT;
01628       } else
01629          break;
01630       ret = 1;
01631    }
01632    // ast_log(LOG_WARNING, "reading [%s] returns %d %d\n", val, i, ret);
01633    if (ret == 0)
01634       return 0;
01635    if (gui->kp_size == 0) {
01636       gui->kp = ast_calloc(10, sizeof(e));
01637       if (gui->kp == NULL) {
01638          ast_log(LOG_WARNING, "cannot allocate kp");
01639          return 0;
01640       }
01641       gui->kp_size = 10;
01642    }
01643    if (gui->kp_size == gui->kp_used) { /* must allocate */
01644       struct keypad_entry *a = ast_realloc(gui->kp, sizeof(e)*(gui->kp_size+10));
01645       if (a == NULL) {
01646          ast_log(LOG_WARNING, "cannot reallocate kp");
01647          return 0;
01648       }
01649       gui->kp = a;
01650       gui->kp_size += 10;
01651    }
01652    if (gui->kp_size == gui->kp_used)
01653       return 0;
01654    gui->kp[gui->kp_used++] = e;
01655    // ast_log(LOG_WARNING, "now %d regions\n", gui->kp_used);
01656    return 1;
01657 }

static void keypad_digit ( struct video_desc *  env,
int  digit 
) [static]

Definition at line 370 of file console_gui.c.

References AST_FRAME_DTMF, ast_queue_frame(), f, and print_message().

00371 {  
00372    if (env->owner) {    /* we have a call, send the digit */
00373       struct ast_frame f = { AST_FRAME_DTMF, 0 };
00374 
00375       f.subclass = digit;
00376       ast_queue_frame(env->owner, &f);
00377    } else {    /* no call, accumulate digits */
00378       char buf[2] = { digit, '\0' };
00379       if (env->gui->bd_msg) /* XXX not strictly necessary ... */
00380          print_message(env->gui->bd_msg, buf);
00381    }
00382 }

static void keypad_pick_up ( struct video_desc *  env  )  [static]

Definition at line 428 of file console_gui.c.

References ast_cli_command, ast_log(), ast_skip_blanks(), gui_info::bd_dialed, gui_info::bd_msg, LOG_WARNING, gui_info::outfd, print_message(), read_message(), and reset_board().

Referenced by handle_keyboard_input().

00429 {
00430    struct gui_info *gui = env->gui;
00431 
00432    ast_log(LOG_WARNING, "keypad_pick_up called\n");
00433 
00434    if (env->owner) { /* someone is calling us, just answer */
00435       ast_cli_command(gui->outfd, "console answer");
00436    } else { /* we have someone to call */
00437       char buf[160];
00438       const char *who = ast_skip_blanks(read_message(gui->bd_msg));
00439       buf[sizeof(buf) - 1] = '\0';
00440       snprintf(buf, sizeof(buf), "console dial %s", who);
00441       ast_log(LOG_WARNING, "doing <%s>\n", buf);
00442       print_message(gui->bd_dialed, "\n");
00443       print_message(gui->bd_dialed, who);
00444       reset_board(gui->bd_msg);
00445       ast_cli_command(gui->outfd, buf);
00446    }
00447 }

static void keypad_setup ( struct gui_info gui,
const char *  kp_file 
) [static]

Definition at line 1123 of file console_gui.c.

References ast_log(), ast_skip_blanks(), ast_trim_blanks(), gui_info::keypad, keypad_cfg_read(), load_image(), and LOG_WARNING.

Referenced by gui_init().

01124 {
01125    FILE *fd;
01126    char buf[1024];
01127    const char region[] = "region";
01128    int reg_len = strlen(region);
01129    int in_comment = 0;
01130 
01131    if (gui->keypad)
01132       return;
01133    gui->keypad = load_image(kp_file);
01134    if (!gui->keypad)
01135       return;
01136    /* now try to read the keymap from the file. */
01137    fd = fopen(kp_file, "r");
01138    if (fd == NULL) {
01139       ast_log(LOG_WARNING, "fail to open %s\n", kp_file);
01140       return;
01141    }
01142    /*
01143     * If the keypad image has a comment field, try to read
01144     * the button location from there. The block must start with
01145     * a comment (or empty) line, and continue with entries like:
01146     * region = token shape x0 y0 x1 y1 h
01147     * ...
01148     * (basically, lines have the same format as config file entries).
01149     * You can add it to a jpeg file using wrjpgcom
01150     */
01151    while (fgets(buf, sizeof(buf), fd)) {
01152       char *s;
01153 
01154       if (!strstr(buf, region)) { /* no keyword yet */
01155          if (!in_comment)  /* still waiting for initial comment block */
01156             continue;
01157          else
01158             break;
01159       }
01160       if (!in_comment) {   /* first keyword, reset previous entries */
01161          keypad_cfg_read(gui, "reset");
01162          in_comment = 1;
01163       }
01164       s = ast_skip_blanks(buf);
01165       ast_trim_blanks(s);
01166       if (memcmp(s, region, reg_len))
01167          break;   /* keyword not found */
01168       s = ast_skip_blanks(s + reg_len); /* space between token and '=' */
01169       if (*s++ != '=')  /* missing separator */
01170          break;
01171       if (*s == '>') /* skip '>' if present */
01172          s++;
01173       keypad_cfg_read(gui, ast_skip_blanks(s));
01174    }
01175    fclose(fd);
01176 }

static char* keypad_toggle ( struct video_desc *  env,
int  index 
) [static]

Definition at line 385 of file console_gui.c.

References ast_cli_command, ast_log(), chan_oss_pvt::autoanswer, find_desc(), KEY_AUTOANSWER, KEY_FREEZE, KEY_MUTE, KEY_PIP, KEY_SENDVIDEO, LOG_WARNING, and oss_active.

00386 {
00387    ast_log(LOG_WARNING, "keypad_toggle(%i) called\n", index);
00388 
00389    switch (index) {
00390    case KEY_SENDVIDEO: /* send or do not send video */
00391       env->out.sendvideo = !env->out.sendvideo;
00392       break;
00393 
00394    case KEY_PIP: /* enable or disable Picture in Picture */
00395       env->out.picture_in_picture = !env->out.picture_in_picture;
00396       break;
00397 
00398    case KEY_MUTE: /* send or do not send audio */
00399       ast_cli_command(env->gui->outfd, "console mute toggle");
00400       break;
00401 
00402    case KEY_FREEZE: /* freeze/unfreeze the incoming frames */
00403       env->frame_freeze = !env->frame_freeze;
00404       break;
00405 
00406 #ifdef notyet
00407    case KEY_AUTOANSWER: {
00408       struct chan_oss_pvt *o = find_desc(oss_active);
00409       o->autoanswer = !o->autoanswer;
00410       }
00411       break;
00412 #endif
00413    }
00414    return NULL;
00415 }

static int kp_match_area ( const struct keypad_entry e,
int  x,
int  y 
) [static]

Definition at line 1483 of file console_gui.c.

References ast_log(), keypad_entry::c, keypad_entry::h, KP_CIRCLE, KP_RECT, LOG_WARNING, keypad_entry::type, keypad_entry::x0, keypad_entry::x1, keypad_entry::y0, and keypad_entry::y1.

Referenced by handle_mousedown().

01484 {
01485    double xp, dx = (e->x1 - e->x0);
01486    double yp, dy = (e->y1 - e->y0);
01487    double l = sqrt(dx*dx + dy*dy);
01488    int ret = 0;
01489 
01490    if (l > 1) { /* large enough */
01491       xp = ((x - e->x0)*dx + (y - e->y0)*dy)/l;
01492       yp = (-(x - e->x0)*dy + (y - e->y0)*dx)/l;
01493       if (e->type == KP_RECT) {
01494          ret = (xp >= 0 && xp < l && yp >=0 && yp < e->h);
01495       } else if (e->type == KP_CIRCLE) {
01496          dx = xp*xp/(l*l) + yp*yp/(e->h*e->h);
01497          ret = (dx < 1);
01498       }
01499    }
01500 #if 0
01501    ast_log(LOG_WARNING, "result %d [%d] for match %d,%d in type %d p0 %d,%d p1 %d,%d h %d\n",
01502       ret, e->c, x, y, e->type, e->x0, e->y0, e->x1, e->y1, e->h);
01503 #endif
01504    return ret;
01505 }

static SDL_Surface* load_image ( const char *  file  )  [static]

Definition at line 1039 of file console_gui.c.

Referenced by gui_init(), and keypad_setup().

01040 {
01041    SDL_Surface *temp;
01042  
01043 #ifdef HAVE_SDL_IMAGE
01044    temp = IMG_Load(file);
01045 #else
01046    temp = SDL_LoadBMP(file);
01047 #endif
01048    if (temp == NULL)
01049       fprintf(stderr, "Unable to load image %s: %s\n",
01050          file, SDL_GetError());
01051    return temp;
01052 }

static char map_key ( SDL_keysym *  ks  )  [static]

Definition at line 843 of file console_gui.c.

Referenced by handle_keyboard_input().

00844 {
00845    const char *s, **p = us_kbd_map;
00846    int c = ks->sym;
00847 
00848    if (c == '\r') /* map cr into lf */
00849       c = '\n';
00850    if (c >= SDLK_NUMLOCK && c <= SDLK_COMPOSE)
00851       return 0;   /* only a modifier */
00852    if (ks->mod == 0)
00853       return c;
00854    while ((s = *p) && s[0] != c)
00855       p++;
00856    if (s) { /* see if we have a modifier and a chance to use it */
00857       int l = strlen(s), mod = 0;
00858       if (l > 1)
00859          mod |= (ks->mod & KMOD_SHIFT) ? 1 : 0;
00860       if (l > 2 + mod)
00861          mod |= (ks->mod & KMOD_CTRL) ? 2 : 0;
00862       if (l > 4 + mod)
00863          mod |= (ks->mod & KMOD_ALT) ? 4 : 0;
00864       c = s[mod];
00865    }
00866    if (ks->mod & (KMOD_CAPS|KMOD_SHIFT) && c >= 'a' && c <='z')
00867       c += 'A' - 'a';
00868    return c;
00869 }

static int my_x_handler ( Display *  d,
XErrorEvent *  e 
) [static]

Definition at line 1204 of file console_gui.c.

References ast_log(), and LOG_WARNING.

Referenced by sdl_setup().

01205 {
01206    ast_log(LOG_WARNING, "%s error_code %d\n", __FUNCTION__, e->error_code);
01207    return 0;
01208 }

static void pip_move ( struct video_desc *  env,
int  dx,
int  dy 
) [static]

This function moves the picture in picture, controlling the limits of the containing buffer to avoid problems deriving from going through the limits.

Parameters:
env = pointer to the descriptor of the video environment
dx = the variation of the x position
dy = the variation of the y position

Definition at line 921 of file console_gui.c.

Referenced by eventhandler().

00921                                                              {
00922    int new_pip_x = env->out.pip_x+dx;
00923    int new_pip_y = env->out.pip_y+dy;
00924    /* going beyond the left borders */
00925    if (new_pip_x < 0)
00926       new_pip_x = 0;
00927    /* going beyond the right borders */
00928    else if (new_pip_x > env->enc_in.w - env->enc_in.w/3)
00929       new_pip_x = env->enc_in.w - env->enc_in.w/3;
00930    /* going beyond the top borders */
00931    if (new_pip_y < 0)
00932       new_pip_y = 0;
00933    /* going beyond the bottom borders */
00934    else if (new_pip_y > env->enc_in.h - env->enc_in.h/3)
00935       new_pip_y = env->enc_in.h - env->enc_in.h/3;
00936    env->out.pip_x = new_pip_x;
00937    env->out.pip_y = new_pip_y;
00938 }

static void sdl_setup ( struct video_desc *  env  )  [static]

[re]set the main sdl window, useful in case of resize. We can tell the first from subsequent calls from the value of env->gui, which is NULL the first time.

Definition at line 1215 of file console_gui.c.

References ast_log(), ast_strlen_zero(), gui_info::bd_msg, board_setup(), BORDER, gui_info::font, gui_info::font_rects, gui_init(), init_board(), gui_info::keypad, gui_info::kp_rect, LOG_ERROR, LOG_WARNING, MAX, my_x_handler(), thumb_bd::rect, gui_info::screen, set_win(), SRC_MSG_BD_H, SRC_WIN_H, SRC_WIN_W, gui_info::thumb_bd_array, gui_info::win, WIN_KEYPAD, WIN_LOCAL, WIN_REMOTE, and WIN_SRC1.

01216 {
01217    int dpy_fmt = SDL_IYUV_OVERLAY;  /* YV12 causes flicker in SDL */
01218    int depth, maxw, maxh;
01219    const SDL_VideoInfo *info;
01220    int kp_w = 0, kp_h = 0; /* keypad width and height */
01221    struct gui_info *gui = env->gui;
01222    
01223    /* Some helper variables used for filling the SDL window */
01224    int x0; /* the x coordinate of the center of the keypad */
01225    int x1; /* userful for calculating of the size of the parent window */
01226    int y0; /* y coordinate of the keypad, the remote window and the local window */
01227    int src_wins_tot_w; /* total width of the source windows */
01228    int i;
01229    int x; /* useful for the creation of the source windows; */
01230    
01231 #ifdef HAVE_X11
01232    const char *e = getenv("SDL_WINDOWID");
01233 
01234    if (!ast_strlen_zero(e)) {
01235       XWindowAttributes a;
01236       int (*old_x_handler)(Display *d, XErrorEvent *e) = XSetErrorHandler(my_x_handler);
01237       Display *d = XOpenDisplay(getenv("DISPLAY"));
01238       long w = atol(e);
01239       int success = w ? XGetWindowAttributes(d, w, &a) : 0;
01240 
01241       XSetErrorHandler(old_x_handler);
01242       if (!success) {
01243          ast_log(LOG_WARNING, "%s error in window\n", __FUNCTION__);
01244          return;
01245       }
01246    }  
01247 #endif
01248    /*
01249     * initialize the SDL environment. We have one large window
01250     * with local and remote video, and a keypad.
01251     * At the moment we arrange them statically, as follows:
01252     * - top row: thumbnails for local video sources;
01253     * - next row: message boards for local video sources
01254     * - on the left, the remote video;
01255     * - on the center, the keypad
01256     * - on the right, the local video
01257     * We need to read in the skin for the keypad before creating the main
01258     * SDL window, because the size is only known here.
01259     */
01260 
01261    if (gui == NULL && SDL_Init(SDL_INIT_VIDEO)) {
01262       ast_log(LOG_WARNING, "Could not initialize SDL - %s\n",
01263                         SDL_GetError());
01264                 /* again not fatal, just we won't display anything */
01265       return;
01266    }
01267    info = SDL_GetVideoInfo();
01268    /* We want at least 16bpp to support YUV overlays.
01269     * E.g with SDL_VIDEODRIVER = aalib the default is 8
01270     */
01271    if (!info || !info->vfmt) {
01272       ast_log(LOG_WARNING, "Bad SDL_GetVideoInfo - %s\n",
01273                         SDL_GetError());
01274       return;
01275    }
01276    depth = info->vfmt->BitsPerPixel;
01277    if (depth < 16)
01278       depth = 16;
01279    if (!gui)
01280       env->gui = gui = gui_init(env->keypad_file, env->keypad_font);
01281    if (!gui)
01282       goto no_sdl;
01283 
01284    if (gui->keypad) {
01285       if (gui->kp_rect.w > 0 && gui->kp_rect.h > 0) {
01286          kp_w = gui->kp_rect.w;
01287          kp_h = gui->kp_rect.h;
01288       } else {
01289          kp_w = gui->keypad->w;
01290          kp_h = gui->keypad->h;
01291       }
01292    }
01293    
01294    /* total width of the thumbnails */
01295    src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
01296    
01297    /* x coordinate of the center of the keypad */
01298    x0 = MAX(env->rem_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
01299    
01300    /* from center of the keypad to right border */
01301    x1 = MAX(env->loc_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
01302    
01303    /* total width of the SDL window to create */
01304    maxw = x0+x1;
01305    
01306    /* total height of the mother window to create */
01307    maxh = MAX( MAX(env->rem_dpy.h, env->loc_dpy.h), kp_h)+2*BORDER;
01308    maxh += env->out.device_num ? (2*BORDER+SRC_WIN_H+SRC_MSG_BD_H) : 0;
01309    
01310    gui->screen = SDL_SetVideoMode(maxw, maxh, depth, 0);
01311    if (!gui->screen) {
01312       ast_log(LOG_ERROR, "SDL: could not set video mode - exiting\n");
01313       goto no_sdl;
01314    }
01315 
01316 #ifdef HAVE_X11
01317    /*
01318     * Annoying as it may be, if SDL_WINDOWID is set, SDL does
01319     * not grab keyboard/mouse events or expose or other stuff,
01320     * and it does not handle resize either.
01321     * So we need to implement workarounds here.
01322     */
01323     do {
01324    /* First, handle the event mask */
01325    XWindowAttributes attr;
01326         long want;
01327         SDL_SysWMinfo info;
01328    Display *SDL_Display;
01329         Window win;
01330 
01331    const char *e = getenv("SDL_WINDOWID");
01332    if (ast_strlen_zero(e))  /* no external window, don't bother doing this */
01333       break;
01334         SDL_VERSION(&info.version); /* it is important to set the version */
01335         if (SDL_GetWMInfo(&info) != 1) {
01336                 fprintf(stderr, "no wm info\n");
01337                 break;
01338         }
01339    SDL_Display = info.info.x11.display;
01340    if (SDL_Display == NULL)
01341       break;
01342         win = info.info.x11.window;
01343 
01344    /*
01345     * A list of events we want.
01346     * Leave ResizeRedirectMask to the parent.
01347     */
01348         want = KeyPressMask | KeyReleaseMask | ButtonPressMask |
01349                            ButtonReleaseMask | EnterWindowMask |
01350                            LeaveWindowMask | PointerMotionMask |
01351                            Button1MotionMask |
01352                            Button2MotionMask | Button3MotionMask |
01353                            Button4MotionMask | Button5MotionMask |
01354                            ButtonMotionMask | KeymapStateMask |
01355                            ExposureMask | VisibilityChangeMask |
01356                            StructureNotifyMask | /* ResizeRedirectMask | */
01357                            SubstructureNotifyMask | SubstructureRedirectMask |
01358                            FocusChangeMask | PropertyChangeMask |
01359                            ColormapChangeMask | OwnerGrabButtonMask;
01360 
01361         memset(&attr, '\0', sizeof(attr));
01362    XGetWindowAttributes(SDL_Display, win, &attr);
01363 
01364    /* the following events can be delivered only to one client.
01365     * So check which ones are going to someone else, and drop
01366     * them from our request.
01367     */
01368    {
01369    /* ev are the events for a single recipient */
01370    long ev = ButtonPressMask | ResizeRedirectMask |
01371          SubstructureRedirectMask;
01372         ev &= (attr.all_event_masks & ~attr.your_event_mask);
01373    /* now ev contains 1 for single-recipient events owned by others.
01374     * We must clear those bits in 'want'
01375     * and then add the bits in 'attr.your_event_mask' to 'want'
01376     */
01377    want &= ~ev;
01378    want |= attr.your_event_mask;
01379    }
01380    XSelectInput(SDL_Display, win, want);
01381 
01382    /* Second, handle resize.
01383     * We do part of the things that X11Resize does,
01384     * but also generate a ConfigureNotify event so
01385     * the owner of the window has a chance to do something
01386     * with it.
01387     */
01388    XResizeWindow(SDL_Display, win, maxw, maxh);
01389    {
01390    XConfigureEvent ce = {
01391       .type = ConfigureNotify,
01392       .serial = 0,
01393       .send_event = 1,  /* TRUE */
01394       .display = SDL_Display,
01395       .event = win,
01396       .window = win,
01397       .x = 0,
01398       .y = 0,
01399       .width = maxw,
01400       .height = maxh,
01401       .border_width = 0,
01402       .above = 0,
01403       .override_redirect = 0 };
01404    XSendEvent(SDL_Display, win, 1 /* TRUE */, StructureNotifyMask, (XEvent *)&ce);
01405    }
01406     } while (0);
01407 #endif /* HAVE_X11 */
01408 
01409    y0 = env->out.device_num ? (3*BORDER+SRC_WIN_H+SRC_MSG_BD_H) : BORDER;
01410    
01411    SDL_WM_SetCaption("Asterisk console Video Output", NULL);
01412    
01413    /* intialize the windows for local and remote video */
01414    if (set_win(gui->screen, &gui->win[WIN_REMOTE], dpy_fmt,
01415          env->rem_dpy.w, env->rem_dpy.h, x0-kp_w/2-BORDER-env->rem_dpy.w, y0))
01416       goto no_sdl;
01417    /* unfreeze incoming frames if set (to avoid showing nothing) */
01418    env->frame_freeze = 0;
01419 
01420    if (set_win(gui->screen, &gui->win[WIN_LOCAL], dpy_fmt,
01421          env->loc_dpy.w, env->loc_dpy.h,
01422          x0+kp_w/2+BORDER, y0))
01423       goto no_sdl;
01424    
01425    /* initialize device_num source windows (thumbnails) and boards
01426    (for a maximum of 9 additional windows and boards) */
01427    x = x0 - src_wins_tot_w/2 + BORDER;
01428    for (i = 0; i < env->out.device_num; i++){
01429       struct thumb_bd *p = &gui->thumb_bd_array[i];
01430       if (set_win(gui->screen, &gui->win[i+WIN_SRC1], dpy_fmt,
01431          SRC_WIN_W, SRC_WIN_H, x+i*(BORDER+SRC_WIN_W), BORDER))
01432          goto no_sdl;
01433       /* set geometry for the rect for the message board of the device */
01434       p->rect.w = SRC_WIN_W;
01435       p->rect.h = SRC_MSG_BD_H;
01436       p->rect.x = x+i*(BORDER+SRC_WIN_W);
01437       p->rect.y = 2*BORDER+SRC_WIN_H;
01438       /* the white color is used as background */
01439       SDL_FillRect(gui->screen, &p->rect,
01440          SDL_MapRGB(gui->screen->format, 255, 255, 255));
01441       /* if necessary, initialize boards for the sources */
01442       if (!p->board)
01443          p->board =
01444             board_setup(gui->screen, &p->rect,
01445             gui->font, gui->font_rects);
01446       /* update board rect */
01447       SDL_UpdateRect(gui->screen, p->rect.x, p->rect.y, p->rect.w, p->rect.h);
01448    }
01449 
01450    /* display the skin, but do not free it as we need it later to
01451    restore text areas and maybe sliders too */
01452    if (gui->keypad) {
01453       struct SDL_Rect *dest = &gui->win[WIN_KEYPAD].rect;
01454       struct SDL_Rect *src = (gui->kp_rect.w > 0 && gui->kp_rect.h > 0) ? & gui->kp_rect : NULL;
01455       /* set the coordinates of the keypad relative to the main screen */
01456       dest->x = x0-kp_w/2;
01457       dest->y = y0;
01458       dest->w = kp_w;
01459       dest->h = kp_h;
01460       SDL_BlitSurface(gui->keypad, src, gui->screen, dest);
01461       init_board(gui, &gui->bd_msg, gui->kp_msg, dest->x, dest->y);
01462       init_board(gui, &gui->bd_dialed, gui->kp_dialed, dest->x, dest->y);
01463       SDL_UpdateRects(gui->screen, 1, dest);
01464    }
01465    return;
01466 
01467 no_sdl:
01468    /* free resources in case of errors */
01469    env->gui = cleanup_sdl(gui, env->out.device_num);
01470 }

static void set_drag ( struct drag_info drag,
int  x,
int  y,
enum drag_window  win 
) [static]

Definition at line 478 of file console_gui.c.

References gui_info::drag, drag_info::drag_window, drag_info::x_start, and drag_info::y_start.

00479 {
00480    drag->x_start = x;
00481    drag->y_start = y;
00482    drag->drag_window = win;
00483 }

static int set_win ( SDL_Surface *  screen,
struct display_window win,
int  fmt,
int  w,
int  h,
int  x,
int  y 
) [static]

Definition at line 1108 of file console_gui.c.

References display_window::bmp, display_window::rect, and gui_info::win.

Referenced by sdl_setup().

01110 {
01111    win->bmp = SDL_CreateYUVOverlay(w, h, fmt, screen);
01112    if (win->bmp == NULL)
01113       return -1;  /* error */
01114    win->rect.x = x;
01115    win->rect.y = y;
01116    win->rect.w = w;
01117    win->rect.h = h;
01118    return 0;
01119 }

static void show_frame ( struct video_desc *  env,
int  out 
) [static]

Definition at line 255 of file console_gui.c.

References display_window::bmp, fbuf_t::h, fbuf_t::pix_fmt, display_window::rect, fbuf_t::w, gui_info::win, WIN_LOCAL, WIN_REMOTE, and WIN_SRC1.

Referenced by hook_event_cb().

00256 {
00257    AVPicture *p_in, p_out;
00258    struct fbuf_t *b_in, *b_out;
00259    SDL_Overlay *bmp;
00260    struct gui_info *gui = env->gui;
00261 
00262    if (!gui)
00263       return;
00264 
00265    if (out == WIN_LOCAL) { /* webcam/x11 to sdl */
00266       b_in = &env->enc_in;
00267       b_out = &env->loc_dpy;
00268       p_in = NULL;
00269    } else if (out == WIN_REMOTE) {
00270       /* copy input format from the decoding context */
00271       AVCodecContext *c;
00272       if (env->in == NULL) /* XXX should not happen - decoder not ready */
00273          return;
00274       c = env->in->dec_ctx;
00275       b_in = &env->in->dec_out;
00276                 b_in->pix_fmt = c->pix_fmt;
00277                 b_in->w = c->width;
00278                 b_in->h = c->height;
00279 
00280       b_out = &env->rem_dpy;
00281       p_in = (AVPicture *)env->in->d_frame;
00282    } else {
00283       int i = out-WIN_SRC1;
00284       b_in = env->out.devices[i].dev_buf;
00285       if (b_in == NULL)
00286          return;
00287       p_in = NULL;
00288       b_out = &env->src_dpy[i];
00289    }     
00290    bmp = gui->win[out].bmp;
00291    SDL_LockYUVOverlay(bmp);
00292    /* output picture info - this is sdl, YUV420P */
00293    memset(&p_out, '\0', sizeof(p_out));
00294    p_out.data[0] = bmp->pixels[0];
00295    p_out.data[1] = bmp->pixels[1];
00296    p_out.data[2] = bmp->pixels[2];
00297    p_out.linesize[0] = bmp->pitches[0];
00298    p_out.linesize[1] = bmp->pitches[1];
00299    p_out.linesize[2] = bmp->pitches[2];
00300 
00301    my_scale(b_in, p_in, b_out, &p_out);
00302 
00303    /* lock to protect access to Xlib by different threads. */
00304    SDL_DisplayYUVOverlay(bmp, &gui->win[out].rect);
00305    SDL_UnlockYUVOverlay(bmp);
00306 }

static int switch_video_out ( struct video_desc *  env,
int  index,
Uint8  button 
) [static]

Changes the video output (local video) source, controlling if it is already using that video device, and switching the correct fields of env->out. grabbers are always open and saved in the device table. The secondary or the primary device can be changed, according to the "button" parameter: the primary device is changed if button = SDL_BUTTON_LEFT; the secondary device is changed if button = not SDL_BUTTON_LEFT;.

the correct message boards of the sources are also updated with the new status

Parameters:
env = pointer to the video environment descriptor
index = index of the device the caller wants to use are primary or secondary device
button = button clicked on the mouse
returns 0 on success, returns 1 on error

Definition at line 512 of file console_gui.c.

References ast_log(), IS_PRIMARY, IS_SECONDARY, LOG_WARNING, and update_device_info().

00513 {
00514    int *p; /* pointer to the index of the device to select */
00515 
00516    if (index >= env->out.device_num) {
00517       ast_log(LOG_WARNING, "no devices\n");
00518       return 1;
00519    }
00520    /* select primary or secondary */
00521    p = (button == SDL_BUTTON_LEFT) ? &env->out.device_primary :
00522       &env->out.device_secondary;
00523    /* controls if the device is already selected */
00524    if (index == *p) {
00525       ast_log(LOG_WARNING, "device %s already selected\n", env->out.devices[index].name);
00526       return 0;
00527    }
00528    ast_log(LOG_WARNING, "switching to %s...\n", env->out.devices[index].name);
00529    /* already open */
00530    if (env->out.devices[index].grabber) {
00531       /* we also have to update the messages in the source 
00532       message boards below the source windows */
00533       /* first we update the board of the previous source */
00534       if (p == &env->out.device_primary)
00535          env->out.devices[*p].status_index &= ~IS_PRIMARY;
00536       else
00537          env->out.devices[*p].status_index &= ~IS_SECONDARY;
00538       update_device_info(env, *p);
00539       /* update the index used as primary or secondary */
00540       *p = index;
00541       ast_log(LOG_WARNING, "done\n");
00542       /* then we update the board of the new primary or secondary source */
00543       if (p == &env->out.device_primary)
00544          env->out.devices[*p].status_index |= IS_PRIMARY;
00545       else
00546          env->out.devices[*p].status_index |= IS_SECONDARY;
00547       update_device_info(env, *p);
00548       return 0;
00549    }
00550    /* device is off, just do nothing */
00551    ast_log(LOG_WARNING, "device is down\n");
00552    return 1;
00553 }

static int turn_on_off ( int  index,
struct video_desc *  env 
) [static]

tries to switch the state of a device from on to off or off to on we also have to update the status of the device and the correct message board

Parameters:
index = the device that must be turned on or off
env = pointer to the video environment descriptor
returns:

Definition at line 566 of file console_gui.c.

References ast_log(), console_grabbers, IS_ON, LOG_WARNING, grab_desc::open, and update_device_info().

00567 {
00568    struct video_device *p = &env->out.devices[index];
00569 
00570    if (index >= env->out.device_num) {
00571       ast_log(LOG_WARNING, "no devices\n");
00572       return 0;
00573    }
00574 
00575    if (!p->grabber) { /* device off */
00576       void *g_data; /* result of grabber_open() */
00577       struct grab_desc *g;
00578       int i;
00579 
00580       /* see if the device can be used by one of the existing drivers */
00581       for (i = 0; (g = console_grabbers[i]); i++) {
00582          /* try open the device */
00583          g_data = g->open(p->name, &env->out.loc_src_geometry, env->out.fps);
00584          if (!g_data)   /* no luck, try the next driver */
00585             continue;
00586          p->grabber = g;
00587          p->grabber_data = g_data;
00588          /* update the status of the source */
00589          p->status_index |= IS_ON;
00590          /* print the new message in the message board */
00591          update_device_info(env, index);
00592          return 1; /* open succeded */
00593       }
00594       return 0; /* failure */
00595    } else {
00596       /* the grabber must be closed */
00597       p->grabber_data = p->grabber->close(p->grabber_data);
00598       p->grabber = NULL;
00599       /* dev_buf is already freed by grabber->close() */
00600       p->dev_buf = NULL;
00601       /* update the status of the source */
00602       p->status_index &= ~IS_ON;
00603       /* print the new message in the message board */
00604       update_device_info(env, index);
00605       return 2; /* closed */
00606    }  
00607 }

static int update_device_info ( struct video_desc *  env,
int  i 
) [static]

Definition at line 485 of file console_gui.c.

References print_message(), reset_board(), and src_msgs.

Referenced by switch_video_out(), and turn_on_off().

00486 {
00487    reset_board(env->gui->thumb_bd_array[i].board);
00488    print_message(env->gui->thumb_bd_array[i].board,
00489       src_msgs[env->out.devices[i].status_index]);
00490    return 0;
00491 }

static int video_geom ( struct fbuf_t b,
const char *  s 
) [static]


Variable Documentation

struct _s_k gui_key_map[] [static]

Definition at line 1508 of file console_gui.c.

Referenced by gui_map_token().

char* src_msgs[]

Definition at line 235 of file console_gui.c.

Referenced by update_device_info().

const char* const us_kbd_map[] [static]

Definition at line 835 of file console_gui.c.


Generated on Mon Jun 27 16:51:12 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7