00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 #include "asterisk.h"
00086 #include "console_video.h"
00087 #include "asterisk/lock.h"
00088 #include "asterisk/frame.h"
00089 #include "asterisk/utils.h"
00090 #include <math.h>
00091
00092
00093 enum { WIN_LOCAL, WIN_REMOTE, WIN_KEYPAD, WIN_SRC1,
00094 WIN_SRC2, WIN_SRC3, WIN_SRC4, WIN_SRC5,
00095 WIN_SRC6, WIN_SRC7, WIN_SRC8, WIN_SRC9, WIN_MAX };
00096
00097 #ifndef HAVE_SDL
00098 static void show_frame(struct video_desc *env, int out) {}
00099 static void sdl_setup(struct video_desc *env) {}
00100 static struct gui_info *cleanup_sdl(struct gui_info* g, int n) { return NULL; }
00101 static void eventhandler(struct video_desc *env, const char *caption) {}
00102 static int keypad_cfg_read(struct gui_info *gui, const char *val) { return 0; }
00103
00104 #else
00105
00106 #include <SDL/SDL.h>
00107 #include <SDL/SDL_syswm.h>
00108 #ifdef HAVE_SDL_IMAGE
00109 #include <SDL/SDL_image.h>
00110 #endif
00111
00112 #ifdef HAVE_X11
00113
00114 #include <X11/Xlib.h>
00115 #endif
00116
00117 #define BORDER 5
00118 #define SRC_MSG_BD_H 20
00119
00120 enum kp_type { KP_NONE, KP_RECT, KP_CIRCLE };
00121 struct keypad_entry {
00122 int c;
00123 int x0, y0, x1, y1, h;
00124 enum kp_type type;
00125 };
00126
00127
00128
00129
00130 struct display_window {
00131 SDL_Overlay *bmp;
00132 SDL_Rect rect;
00133 };
00134
00135
00136
00137 struct thumb_bd {
00138 SDL_Rect rect;
00139 struct board *board;
00140 };
00141
00142 struct gui_info {
00143 enum kb_output kb_output;
00144 struct drag_info drag;
00145
00146 SDL_Surface *screen;
00147
00148 int outfd;
00149 SDL_Surface *keypad;
00150 SDL_Rect kp_rect;
00151 SDL_Surface *font;
00152 SDL_Rect font_rects[96];
00153
00154
00155
00156
00157
00158
00159
00160 SDL_Rect kp_msg[2];
00161 struct board *bd_msg;
00162
00163 SDL_Rect kp_edit[2];
00164 struct board *bd_edit;
00165
00166 SDL_Rect kp_dialed[2];
00167 struct board *bd_dialed;
00168
00169
00170
00171
00172
00173 struct thumb_bd thumb_bd_array[MAX_VIDEO_SOURCES];
00174
00175
00176 int kp_size, kp_used;
00177 struct keypad_entry *kp;
00178
00179 struct display_window win[WIN_MAX];
00180 };
00181
00182
00183
00184
00185 static struct gui_info *cleanup_sdl(struct gui_info *gui, int device_num)
00186 {
00187 int i;
00188
00189 if (gui == NULL)
00190 return NULL;
00191
00192
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
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
00214 if (gui->bd_dialed)
00215 delete_board(gui->bd_dialed);
00216 if (gui->bd_msg)
00217 delete_board(gui->bd_msg);
00218
00219
00220 for (i = 0; i < device_num; i++) {
00221 if (gui->thumb_bd_array[i].board)
00222 delete_board(gui->thumb_bd_array[i].board);
00223 }
00224
00225 ast_free(gui);
00226 SDL_Quit();
00227 return NULL;
00228 }
00229
00230
00231
00232
00233
00234
00235 #define IS_PRIMARY 1
00236 #define IS_SECONDARY 2
00237 #define IS_ON 4
00238
00239 char* src_msgs[] = {
00240 " OFF",
00241 "1 OFF",
00242 " 2 OFF",
00243 "1+2 OFF",
00244 " ON",
00245 "1 ON",
00246 " 2 ON",
00247 "1+2 ON",
00248 };
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 static void show_frame(struct video_desc *env, int out)
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) {
00270 b_in = &env->enc_in;
00271 b_out = &env->loc_dpy;
00272 p_in = NULL;
00273 } else if (out == WIN_REMOTE) {
00274
00275 AVCodecContext *c;
00276 if (env->in == NULL)
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
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
00308 SDL_DisplayYUVOverlay(bmp, &gui->win[out].rect);
00309 SDL_UnlockYUVOverlay(bmp);
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 enum skin_area {
00319
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
00331 KEY_MESSAGEBOARD = 140,
00332 KEY_DIALEDBOARD = 141,
00333 KEY_EDITBOARD = 142,
00334
00335 KEY_GUI_CLOSE = 199,
00336
00337
00338
00339 KEY_KEYPAD = 200,
00340 KEY_FONT = 201,
00341 KEY_MESSAGE = 202,
00342 KEY_DIALED = 203,
00343 KEY_EDIT = 204,
00344
00345 #ifdef notyet
00346 KEY_AUDIO_SRCS = 210,
00347
00348
00349
00350
00351 #endif
00352
00353 KEY_FREEZE = 220,
00354 KEY_CAPTURE = 221,
00355 KEY_PIP = 230,
00356
00357
00358
00359 KEY_SRCS_WIN = 231,
00360
00361 KEY_OUT_OF_KEYPAD = 241,
00362 KEY_REM_DPY = 242,
00363 KEY_LOC_DPY = 243,
00364 KEY_RESET = 253,
00365 KEY_NONE = 254,
00366 KEY_DIGIT_BACKGROUND = 255,
00367 };
00368
00369
00370
00371
00372
00373
00374 static void keypad_digit(struct video_desc *env, int digit)
00375 {
00376 if (env->owner) {
00377 struct ast_frame f = { AST_FRAME_DTMF, 0 };
00378
00379 f.subclass = digit;
00380 ast_queue_frame(env->owner, &f);
00381 } else {
00382 char buf[2] = { digit, '\0' };
00383 if (env->gui->bd_msg)
00384 print_message(env->gui->bd_msg, buf);
00385 }
00386 }
00387
00388
00389 static char *keypad_toggle(struct video_desc *env, int index)
00390 {
00391 ast_log(LOG_WARNING, "keypad_toggle(%i) called\n", index);
00392
00393 switch (index) {
00394 case KEY_SENDVIDEO:
00395 env->out.sendvideo = !env->out.sendvideo;
00396 break;
00397
00398 case KEY_PIP:
00399 env->out.picture_in_picture = !env->out.picture_in_picture;
00400 break;
00401
00402 case KEY_MUTE:
00403 ast_cli_command(env->gui->outfd, "console mute toggle");
00404 break;
00405
00406 case KEY_FREEZE:
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 }
00420
00421 char *console_do_answer(int fd);
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 static void keypad_pick_up(struct video_desc *env)
00433 {
00434 struct gui_info *gui = env->gui;
00435
00436 ast_log(LOG_WARNING, "keypad_pick_up called\n");
00437
00438 if (env->owner) {
00439 ast_cli_command(gui->outfd, "console answer");
00440 } else {
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 }
00452
00453 #if 0
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472 static int gui_output(struct video_desc *env, const char *text)
00473 {
00474 return 1;
00475 }
00476 #endif
00477
00478 static int video_geom(struct fbuf_t *b, const char *s);
00479 static void sdl_setup(struct video_desc *env);
00480 static int kp_match_area(const struct keypad_entry *e, int x, int y);
00481
00482 static void set_drag(struct drag_info *drag, int x, int y, enum drag_window win)
00483 {
00484 drag->x_start = x;
00485 drag->y_start = y;
00486 drag->drag_window = win;
00487 }
00488
00489 static int update_device_info(struct video_desc *env, int i)
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 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 static int switch_video_out(struct video_desc *env, int index, Uint8 button)
00517 {
00518 int *p;
00519
00520 if (index >= env->out.device_num) {
00521 ast_log(LOG_WARNING, "no devices\n");
00522 return 1;
00523 }
00524
00525 p = (button == SDL_BUTTON_LEFT) ? &env->out.device_primary :
00526 &env->out.device_secondary;
00527
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
00534 if (env->out.devices[index].grabber) {
00535
00536
00537
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
00544 *p = index;
00545 ast_log(LOG_WARNING, "done\n");
00546
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
00555 ast_log(LOG_WARNING, "device is down\n");
00556 return 1;
00557 }
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 static int turn_on_off(int index, struct video_desc *env)
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) {
00580 void *g_data;
00581 struct grab_desc *g;
00582 int i;
00583
00584
00585 for (i = 0; (g = console_grabbers[i]); i++) {
00586
00587 g_data = g->open(p->name, &env->out.loc_src_geometry, env->out.fps);
00588 if (!g_data)
00589 continue;
00590 p->grabber = g;
00591 p->grabber_data = g_data;
00592
00593 p->status_index |= IS_ON;
00594
00595 update_device_info(env, index);
00596 return 1;
00597 }
00598 return 0;
00599 } else {
00600
00601 p->grabber_data = p->grabber->close(p->grabber_data);
00602 p->grabber = NULL;
00603
00604 p->dev_buf = NULL;
00605
00606 p->status_index &= ~IS_ON;
00607
00608 update_device_info(env, index);
00609 return 2;
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00618
00619 static void handle_mousedown(struct video_desc *env, SDL_MouseButtonEvent button)
00620 {
00621 uint8_t index = KEY_OUT_OF_KEYPAD;
00622 struct gui_info *gui = env->gui;
00623
00624 int i;
00625
00626 int x;
00627
00628
00629 int src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
00630
00631
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
00639 gui->drag.drag_window = DRAG_NONE;
00640
00641
00642
00643 if (button.y >= (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0)) {
00644
00645
00646
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
00666
00667 int x_keypad = button.x - (x0 - gui->keypad->w/2);
00668
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 {
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
00686
00687
00688
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
00703 if (index < 128) {
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;
00710
00711
00712 if (button.button == SDL_BUTTON_RIGHT || button.button == SDL_BUTTON_LEFT) {
00713 switch_video_out(env, index, button.button);
00714 return;
00715 }
00716
00717 else {
00718 int ret = turn_on_off(index, env);
00719
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
00734
00735
00736
00737
00738 switch (index) {
00739
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
00748 case KEY_MUTE:
00749 case KEY_AUTOANSWER:
00750 case KEY_SENDVIDEO:
00751 case KEY_PIP:
00752 case KEY_FREEZE:
00753 keypad_toggle(env, index);
00754 break;
00755
00756 case KEY_LOCALVIDEO:
00757 break;
00758 case KEY_REMOTEVIDEO:
00759 break;
00760
00761 #ifdef notyet
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
00772 case KEY_LOC_DPY:
00773 case KEY_REM_DPY:
00774 if (button.button == SDL_BUTTON_LEFT) {
00775
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
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
00785 button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
00786
00787 set_drag(&gui->drag, button.x, button.y, DRAG_PIP);
00788 }
00789 else if (index == KEY_LOC_DPY) {
00790
00791 button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
00792
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
00804
00805
00806
00807 for (i = 0; i < env->out.device_num; i++) {
00808 update_device_info(env, i);
00809 }
00810
00811
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 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 static const char * const us_kbd_map[] = {
00840 "`~", "1!", "2@", "3#", "4$", "5%", "6^",
00841 "7&", "8*", "9(", "0)", "-_", "=+", "[{",
00842 "]}", "\\|", ";:", "'\"", ",<", ".>", "/?",
00843 "jJ\n",
00844 NULL
00845 };
00846
00847 static char map_key(SDL_keysym *ks)
00848 {
00849 const char *s, **p = us_kbd_map;
00850 int c = ks->sym;
00851
00852 if (c == '\r')
00853 c = '\n';
00854 if (c >= SDLK_NUMLOCK && c <= SDLK_COMPOSE)
00855 return 0;
00856 if (ks->mod == 0)
00857 return c;
00858 while ((s = *p) && s[0] != c)
00859 p++;
00860 if (s) {
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 }
00874
00875 static void handle_keyboard_input(struct video_desc *env, SDL_keysym *ks)
00876 {
00877 char buf[2] = { map_key(ks), '\0' };
00878 struct gui_info *gui = env->gui;
00879 if (buf[0] == 0)
00880 return;
00881 switch (gui->kb_output) {
00882 default:
00883 break;
00884 case KO_INPUT:
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:
00896 break;
00897 }
00898
00899 return;
00900 }
00901
00902 static void grabber_move(struct video_device *, int dx, int dy);
00903
00904 int compute_drag(int *start, int end, int magnifier);
00905 int compute_drag(int *start, int end, int magnifier)
00906 {
00907 int delta = end - *start;
00908 #define POLARITY -1
00909
00910 delta += delta * delta * (delta > 0 ? 1 : -1 )/100;
00911 delta *= POLARITY * magnifier;
00912 #undef POLARITY
00913 *start = end;
00914 return delta;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925 static void pip_move(struct video_desc* env, int dx, int dy) {
00926 int new_pip_x = env->out.pip_x+dx;
00927 int new_pip_y = env->out.pip_y+dy;
00928
00929 if (new_pip_x < 0)
00930 new_pip_x = 0;
00931
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
00935 if (new_pip_y < 0)
00936 new_pip_y = 0;
00937
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 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953 static void eventhandler(struct video_desc *env, const char *caption)
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
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:
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
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
01005 int dx = ev[i].motion.x - drag->x_start;
01006 int dy = ev[i].motion.y - drag->y_start;
01007
01008
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
01012 drag->x_start = ev[i].motion.x;
01013 drag->y_start = ev[i].motion.y;
01014
01015 pip_move(env, dx, dy);
01016 } else if (drag->drag_window == DRAG_MESSAGE) {
01017
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
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
01040 }
01041 }
01042
01043 static SDL_Surface *load_image(const char *file)
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 }
01057
01058 static void keypad_setup(struct gui_info *gui, const char *kp_file);
01059
01060
01061
01062 static struct gui_info *gui_init(const char *keypad_file, const char *font)
01063 {
01064 struct gui_info *gui = ast_calloc(1, sizeof(*gui));
01065
01066 if (gui == NULL)
01067 return NULL;
01068
01069 gui->kb_output = KO_MESSAGE;
01070 gui->drag.drag_window = DRAG_NONE;
01071 gui->outfd = -1;
01072
01073 keypad_setup(gui, keypad_file);
01074 if (gui->keypad == NULL)
01075 return gui;
01076
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
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);
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 }
01110
01111
01112 static int set_win(SDL_Surface *screen, struct display_window *win, int fmt,
01113 int w, int h, int x, int y)
01114 {
01115 win->bmp = SDL_CreateYUVOverlay(w, h, fmt, screen);
01116 if (win->bmp == NULL)
01117 return -1;
01118 win->rect.x = x;
01119 win->rect.y = y;
01120 win->rect.w = w;
01121 win->rect.h = h;
01122 return 0;
01123 }
01124
01125 static int keypad_cfg_read(struct gui_info *gui, const char *val);
01126
01127 static void keypad_setup(struct gui_info *gui, const char *kp_file)
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
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
01148
01149
01150
01151
01152
01153
01154
01155 while (fgets(buf, sizeof(buf), fd)) {
01156 char *s;
01157
01158 if (!strstr(buf, region)) {
01159 if (!in_comment)
01160 continue;
01161 else
01162 break;
01163 }
01164 if (!in_comment) {
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;
01172 s = ast_skip_blanks(s + reg_len);
01173 if (*s++ != '=')
01174 break;
01175 if (*s == '>')
01176 s++;
01177 keypad_cfg_read(gui, ast_skip_blanks(s));
01178 }
01179 fclose(fd);
01180 }
01181
01182 struct board *board_setup(SDL_Surface *screen, SDL_Rect *dest,
01183 SDL_Surface *font, SDL_Rect *font_rects);
01184
01185
01186 static void init_board(struct gui_info *gui, struct board **dst, SDL_Rect *r, int dx, int dy)
01187 {
01188 if (r[0].w == 0 || r[0].h == 0)
01189 return;
01190 r[1] = r[0];
01191 r[1].x += dx;
01192 r[1].y += dy;
01193 if (*dst == NULL) {
01194 *dst = board_setup(gui->screen, &r[1], gui->font, gui->font_rects);
01195 } else {
01196
01197 }
01198 }
01199
01200 #ifdef HAVE_X11
01201
01202
01203
01204
01205
01206
01207
01208 static int my_x_handler(Display *d, XErrorEvent *e)
01209 {
01210 ast_log(LOG_WARNING, "%s error_code %d\n", __FUNCTION__, e->error_code);
01211 return 0;
01212 }
01213 #endif
01214
01215
01216
01217
01218
01219 static void sdl_setup(struct video_desc *env)
01220 {
01221 int dpy_fmt = SDL_IYUV_OVERLAY;
01222 int depth, maxw, maxh;
01223 const SDL_VideoInfo *info;
01224 int kp_w = 0, kp_h = 0;
01225 struct gui_info *gui = env->gui;
01226
01227
01228 int x0;
01229 int x1;
01230 int y0;
01231 int src_wins_tot_w;
01232 int i;
01233 int x;
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
01254
01255
01256
01257
01258
01259
01260
01261
01262
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
01269 return;
01270 }
01271 info = SDL_GetVideoInfo();
01272
01273
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
01299 src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
01300
01301
01302 x0 = MAX(env->rem_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
01303
01304
01305 x1 = MAX(env->loc_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
01306
01307
01308 maxw = x0+x1;
01309
01310
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
01323
01324
01325
01326
01327 do {
01328
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))
01337 break;
01338 SDL_VERSION(&info.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
01350
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 |
01361 SubstructureNotifyMask | SubstructureRedirectMask |
01362 FocusChangeMask | PropertyChangeMask |
01363 ColormapChangeMask | OwnerGrabButtonMask;
01364
01365 memset(&attr, '\0', sizeof(attr));
01366 XGetWindowAttributes(SDL_Display, win, &attr);
01367
01368
01369
01370
01371
01372 {
01373
01374 long ev = ButtonPressMask | ResizeRedirectMask |
01375 SubstructureRedirectMask;
01376 ev &= (attr.all_event_masks & ~attr.your_event_mask);
01377
01378
01379
01380
01381 want &= ~ev;
01382 want |= attr.your_event_mask;
01383 }
01384 XSelectInput(SDL_Display, win, want);
01385
01386
01387
01388
01389
01390
01391
01392 XResizeWindow(SDL_Display, win, maxw, maxh);
01393 {
01394 XConfigureEvent ce = {
01395 .type = ConfigureNotify,
01396 .serial = 0,
01397 .send_event = 1,
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 , StructureNotifyMask, (XEvent *)&ce);
01409 }
01410 } while (0);
01411 #endif
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
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
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
01430
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
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
01443 SDL_FillRect(gui->screen, &p->rect,
01444 SDL_MapRGB(gui->screen->format, 255, 255, 255));
01445
01446 if (!p->board)
01447 p->board =
01448 board_setup(gui->screen, &p->rect,
01449 gui->font, gui->font_rects);
01450
01451 SDL_UpdateRect(gui->screen, p->rect.x, p->rect.y, p->rect.w, p->rect.h);
01452 }
01453
01454
01455
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
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
01473 env->gui = cleanup_sdl(gui, env->out.device_num);
01474 }
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487 static int kp_match_area(const struct keypad_entry *e, int x, int y)
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) {
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 }
01510
01511 struct _s_k { const char *s; int k; };
01512 static const struct _s_k gui_key_map[] = {
01513 {"FREEZE", KEY_FREEZE},
01514 {"PIP", KEY_PIP},
01515 {"PICK_UP", KEY_PICK_UP },
01516 {"PICKUP", KEY_PICK_UP },
01517 {"HANG_UP", KEY_HANG_UP },
01518 {"HANGUP", KEY_HANG_UP },
01519 {"MUTE", KEY_MUTE },
01520 {"FLASH", KEY_FLASH },
01521 {"AUTOANSWER", KEY_AUTOANSWER },
01522 {"SENDVIDEO", KEY_SENDVIDEO },
01523 {"LOCALVIDEO", KEY_LOCALVIDEO },
01524 {"REMOTEVIDEO", KEY_REMOTEVIDEO },
01525 {"GUI_CLOSE", KEY_GUI_CLOSE },
01526 {"MESSAGEBOARD", KEY_MESSAGEBOARD },
01527 {"DIALEDBOARD", KEY_DIALEDBOARD },
01528 {"EDITBOARD", KEY_EDITBOARD },
01529 {"KEYPAD", KEY_KEYPAD },
01530 {"MESSAGE", KEY_MESSAGE },
01531 {"DIALED", KEY_DIALED },
01532 {"EDIT", KEY_EDIT },
01533 {"FONT", KEY_FONT },
01534 {NULL, 0 } };
01535
01536 static int gui_map_token(const char *s)
01537 {
01538
01539 int i = atoi(s);
01540 struct _s_k *p;
01541 if (i > 0 || s[1] == '\0')
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;
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561 static int keypad_cfg_read(struct gui_info *gui, const char *val)
01562 {
01563 struct keypad_entry e;
01564 SDL_Rect *r = NULL;
01565 char s1[16], s2[16];
01566 int i, ret = 0;
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;
01579 switch (i) {
01580 default:
01581 break;
01582 case 1:
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)
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);
01599 r->y = e.x0;
01600 r->w = e.y0;
01601 r->h = e.x1;
01602 break;
01603 }
01604 if (strcasecmp(s2, "circle"))
01605 break;
01606
01607 e.h = e.x1;
01608 e.y1 = e.y0;
01609 e.x1 = e.x0 + e.h;
01610 e.x0 = e.x0 - e.h;
01611
01612
01613 case 7:
01614 if (e.c == KEY_FONT) {
01615 ast_log(LOG_WARNING, "font not supported yet\n");
01616 break;
01617 }
01618
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
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
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) {
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
01660 return 1;
01661 }
01662 #endif