Mon Oct 8 12:39:21 2012

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 117 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 237 of file console_gui.c.

Referenced by turn_on_off().

#define IS_PRIMARY   1

Definition at line 235 of file console_gui.c.

Referenced by switch_video_out().

#define IS_SECONDARY   2

Definition at line 236 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 118 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 93 of file console_gui.c.

enum kp_type

Enumerator:
KP_NONE 
KP_RECT 
KP_CIRCLE 

Definition at line 120 of file console_gui.c.

00120 { 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 318 of file console_gui.c.

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


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 185 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.

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

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

Definition at line 905 of file console_gui.c.

References POLARITY.

Referenced by eventhandler().

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

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 953 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.

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

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 1062 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().

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

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

Definition at line 1536 of file console_gui.c.

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

Referenced by keypad_cfg_read().

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

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

Definition at line 875 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().

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

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

Definition at line 619 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().

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

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 1186 of file console_gui.c.

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

Referenced by sdl_setup().

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

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 1561 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().

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

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

Definition at line 374 of file console_gui.c.

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

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

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

Definition at line 432 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().

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

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

Definition at line 1127 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().

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

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

Definition at line 389 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.

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

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

Definition at line 1487 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().

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

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

Definition at line 1043 of file console_gui.c.

Referenced by gui_init(), and keypad_setup().

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

static char map_key ( SDL_keysym *  ks  )  [static]

Definition at line 847 of file console_gui.c.

Referenced by handle_keyboard_input().

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

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

Definition at line 1208 of file console_gui.c.

References ast_log(), and LOG_WARNING.

Referenced by sdl_setup().

01209 {
01210    ast_log(LOG_WARNING, "%s error_code %d\n", __FUNCTION__, e->error_code);
01211    return 0;
01212 }

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 925 of file console_gui.c.

Referenced by eventhandler().

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

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 1219 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.

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

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

Definition at line 482 of file console_gui.c.

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

00483 {
00484    drag->x_start = x;
00485    drag->y_start = y;
00486    drag->drag_window = win;
00487 }

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 1112 of file console_gui.c.

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

Referenced by sdl_setup().

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

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

Definition at line 259 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().

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

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 516 of file console_gui.c.

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

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

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 570 of file console_gui.c.

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

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

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

Definition at line 489 of file console_gui.c.

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

Referenced by switch_video_out(), and turn_on_off().

00490 {
00491    reset_board(env->gui->thumb_bd_array[i].board);
00492    print_message(env->gui->thumb_bd_array[i].board,
00493       src_msgs[env->out.devices[i].status_index]);
00494    return 0;
00495 }

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


Variable Documentation

struct _s_k gui_key_map[] [static]

Definition at line 1512 of file console_gui.c.

Referenced by gui_map_token().

char* src_msgs[]

Definition at line 239 of file console_gui.c.

Referenced by update_device_info().

const char* const us_kbd_map[] [static]

Definition at line 839 of file console_gui.c.


Generated on Mon Oct 8 12:39:21 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7