11 #include <sys/types.h>
18 #include "libmpcodecs/img_format.h"
19 #include "libmpcodecs/mp_image.h"
25 #include "libvo/font_load.h"
26 #include "osdep/keycodes.h"
27 #include "input/input.h"
28 #include "osdep/timer.h"
30 typedef struct history_st history_t
;
40 char** lines
; // Our buffer
46 pid_t child
; // Child process if we are running a shell cmd
47 int child_fd
[3]; // The 3 default fd
49 //int max_lines; // Max number of lines with the last mpi
51 history_t
* cur_history
;
56 int buf_lines
; // Buffer size (in line)
57 int height
; // Display size in %
61 unsigned int hide_time
;
62 unsigned int show_time
;
67 static struct menu_priv_s cfg_dflt
= {
94 #define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m)
96 static m_option_t cfg_fields
[] = {
97 { "prompt", ST_OFF(mp_prompt
), CONF_TYPE_STRING
, M_OPT_MIN
, 1, 0, NULL
},
98 { "child-prompt", ST_OFF(child_prompt
), CONF_TYPE_STRING
, M_OPT_MIN
, 1, 0, NULL
},
99 { "buffer-lines", ST_OFF(buf_lines
), CONF_TYPE_INT
, M_OPT_MIN
, 5, 0, NULL
},
100 { "height", ST_OFF(height
), CONF_TYPE_INT
, M_OPT_RANGE
, 1, 100, NULL
},
101 { "minbor", ST_OFF(minb
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
102 { "vspace", ST_OFF(vspace
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
103 { "bg", ST_OFF(bg
), CONF_TYPE_INT
, M_OPT_RANGE
, -1, 255, NULL
},
104 { "bg-alpha", ST_OFF(bg_alpha
), CONF_TYPE_INT
, M_OPT_RANGE
, 0, 255, NULL
},
105 { "show-time",ST_OFF(show_time
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
106 { "hide-time",ST_OFF(hide_time
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
107 { "history-size",ST_OFF(history_max
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
108 { "raw-child", ST_OFF(raw_child
), CONF_TYPE_FLAG
, 0, 0, 1, NULL
},
109 { NULL
, NULL
, NULL
, 0,0,0,NULL
}
112 #define mpriv (menu->priv)
114 static void check_child(menu_t
* menu
);
116 static void add_line(struct menu_priv_s
* priv
, char* l
) {
117 char* eol
= strchr(l
,'\n');
124 if(eol
[1]) add_line(priv
,eol
+1);
128 if(priv
->num_lines
>= priv
->buf_lines
&& priv
->lines
[priv
->last_line
])
129 free(priv
->lines
[priv
->last_line
]);
133 priv
->lines
[priv
->last_line
] = strdup(l
);
134 priv
->last_line
= (priv
->last_line
+ 1) % priv
->buf_lines
;
138 static void add_string(struct menu_priv_s
* priv
, char* l
) {
139 char* eol
= strchr(l
,'\n');
140 int ll
= priv
->last_line
> 0 ? priv
->last_line
- 1 : priv
->buf_lines
-1;
142 if(priv
->num_lines
<= 0 || priv
->add_line
|| eol
== l
) {
152 add_line(priv
,eol
+1);
158 priv
->lines
[ll
] = realloc(priv
->lines
[ll
],strlen(priv
->lines
[ll
]) + strlen(l
) + 1);
159 if ( priv
->lines
[ll
] != NULL
)
161 strcat(priv
->lines
[ll
],l
);
165 static void draw(menu_t
* menu
, mp_image_t
* mpi
) {
166 int h
= mpi
->h
*mpriv
->height
/100;
167 int w
= mpi
->w
- 2* mpriv
->minb
;
168 int x
= mpriv
->minb
, y
;
171 if(mpriv
->child
) check_child(menu
);
173 ll
= mpriv
->last_line
- 1;
176 unsigned int t
= GetTimerMS() - mpriv
->hide_ts
;
177 if(t
>= mpriv
->hide_time
) {
182 h
= mpi
->h
*(mpriv
->height
- (mpriv
->height
* t
/mpriv
->hide_time
))/100;
183 } else if(mpriv
->show_time
&& mpriv
->show_ts
== 0) {
184 mpriv
->show_ts
= GetTimerMS();
186 } else if(mpriv
->show_ts
> 0) {
187 unsigned int t
= GetTimerMS() - mpriv
->show_ts
;
188 if(t
> mpriv
->show_time
)
191 h
= mpi
->h
*(mpriv
->height
* t
/mpriv
->hide_time
)/100;
194 y
= h
- mpriv
->vspace
;
196 if(x
< 0 || y
< 0 || w
<= 0 || h
<= 0 )
200 menu_draw_box(mpi
,mpriv
->bg
,mpriv
->bg_alpha
,0,0,mpi
->w
,h
);
202 if(!mpriv
->child
|| !mpriv
->raw_child
){
203 char input
[strlen(mpriv
->cur_history
->buffer
) + strlen(mpriv
->prompt
) + 1];
204 sprintf(input
,"%s%s",mpriv
->prompt
,mpriv
->cur_history
->buffer
);
205 menu_text_size(input
,w
,mpriv
->vspace
,1,&lw
,&lh
);
206 menu_draw_text_full(mpi
,input
,x
,y
,w
,h
,mpriv
->vspace
,1,
207 MENU_TEXT_BOT
|MENU_TEXT_LEFT
,
208 MENU_TEXT_BOT
|MENU_TEXT_LEFT
);
209 y
-= lh
+ mpriv
->vspace
;
213 for( i
= 0 ; y
> mpriv
->minb
&& i
< mpriv
->num_lines
; i
++){
214 int c
= (ll
- i
) >= 0 ? ll
- i
: mpriv
->buf_lines
+ ll
- i
;
215 menu_text_size(mpriv
->lines
[c
],w
,mpriv
->vspace
,1,&lw
,&lh
);
216 menu_draw_text_full(mpi
,mpriv
->lines
[c
],x
,y
,w
,h
,mpriv
->vspace
,1,
217 MENU_TEXT_BOT
|MENU_TEXT_LEFT
,
218 MENU_TEXT_BOT
|MENU_TEXT_LEFT
);
219 y
-= lh
+ mpriv
->vspace
;
224 static void check_child(menu_t
* menu
) {
228 int max_fd
= mpriv
->child_fd
[2] > mpriv
->child_fd
[1] ? mpriv
->child_fd
[2] :
230 int i
,r
,child_status
,w
;
233 if(!mpriv
->child
) return;
235 memset(&tv
,0,sizeof(struct timeval
));
237 FD_SET(mpriv
->child_fd
[1],&rfd
);
238 FD_SET(mpriv
->child_fd
[2],&rfd
);
240 r
= select(max_fd
+1,&rfd
, NULL
, NULL
, &tv
);
242 r
= waitpid(mpriv
->child
,&child_status
,WNOHANG
);
244 if(errno
==ECHILD
){ ///exiting children get handled in mplayer.c
245 for(i
= 0 ; i
< 3 ; i
++)
246 close(mpriv
->child_fd
[i
]);
248 mpriv
->prompt
= mpriv
->mp_prompt
;
249 //add_line(mpriv,"Child process exited");
251 else mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WaitPidError
,strerror(errno
));
254 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_SelectError
);
259 for(i
= 1 ; i
< 3 ; i
++) {
260 if(FD_ISSET(mpriv
->child_fd
[i
],&rfd
)){
261 if(w
) mpriv
->add_line
= 1;
262 r
= read(mpriv
->child_fd
[i
],buffer
,255);
264 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ReadErrorOnChildFD
, i
== 1 ? "stdout":"stderr");
267 add_string(mpriv
,buffer
);
276 #define close_pipe(pipe) close(pipe[0]); close(pipe[1])
278 static int run_shell_cmd(menu_t
* menu
, char* cmd
) {
280 int in
[2],out
[2],err
[2];
282 mp_msg(MSGT_GLOBAL
,MSGL_INFO
,MSGTR_LIBMENU_ConsoleRun
,cmd
);
284 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_AChildIsAlreadyRunning
);
292 mpriv
->child
= fork();
293 if(mpriv
->child
< 0) {
294 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ForkFailed
);
300 if(!mpriv
->child
) { // Chlid process
302 FILE* errf
= fdopen(err_fd
,"w");
303 // Bind the std fd to our pipes
307 execl("/bin/sh","sh","-c",cmd
,(void*)NULL
);
308 fprintf(errf
,"exec failed : %s\n",strerror(errno
));
312 mpriv
->child_fd
[0] = in
[1];
313 mpriv
->child_fd
[1] = out
[0];
314 mpriv
->child_fd
[2] = err
[0];
315 mpriv
->prompt
= mpriv
->child_prompt
;
316 //add_line(mpriv,"Child process started");
321 static void enter_cmd(menu_t
* menu
) {
323 char input
[strlen(mpriv
->cur_history
->buffer
) + strlen(mpriv
->prompt
) + 1];
325 sprintf(input
,"%s%s",mpriv
->prompt
,mpriv
->cur_history
->buffer
);
326 add_line(mpriv
,input
);
328 if(mpriv
->history
== mpriv
->cur_history
) {
329 if(mpriv
->history_size
>= mpriv
->history_max
) {
331 for(i
= mpriv
->history
; i
->prev
; i
= i
->prev
)
333 i
->next
->prev
= NULL
;
337 mpriv
->history_size
++;
338 h
= calloc(1,sizeof(history_t
));
340 h
->buffer
= calloc(h
->size
,1);
341 h
->prev
= mpriv
->history
;
342 mpriv
->history
->next
= h
;
345 mpriv
->history
->buffer
[0] = '\0';
347 mpriv
->cur_history
= mpriv
->history
;
348 //mpriv->input = mpriv->cur_history->buffer;
351 static void read_cmd(menu_t
* menu
,int cmd
) {
353 case MENU_CMD_CANCEL
:
355 mpriv
->hide_ts
= GetTimerMS();
363 char *str
= mpriv
->cur_history
->buffer
;
366 int w
= write(mpriv
->child_fd
[0],str
,l
);
368 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WriteError
);
374 if(write(mpriv
->child_fd
[0],"\n",1) < 0)
375 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WriteError
);
379 c
= mp_input_parse_cmd(mpriv
->cur_history
->buffer
);
382 add_line(mpriv
,"Invalid command try help");
386 add_line(mpriv
,"MPlayer console 0.01");
387 add_line(mpriv
,"TODO: meaningful help message ;)");
388 add_line(mpriv
,"Enter any slave command");
389 add_line(mpriv
,"exit close this console");
397 mpriv
->hide_ts
= GetTimerMS();
403 run_shell_cmd(menu
,c
->args
[0].v
.s
);
405 default: // Send the other commands to mplayer
406 mp_input_queue_cmd(c
);
412 if(mpriv
->cur_history
->prev
)
413 mpriv
->cur_history
= mpriv
->cur_history
->prev
;
416 if(mpriv
->cur_history
->next
)
417 mpriv
->cur_history
= mpriv
->cur_history
->next
;
422 static int read_key(menu_t
* menu
,int c
) {
423 if(mpriv
->child
&& mpriv
->raw_child
) {
424 write(mpriv
->child_fd
[0],&c
,sizeof(int));
428 if (c
== KEY_DELETE
|| c
== KEY_BS
) {
429 unsigned int i
= strlen(mpriv
->cur_history
->buffer
);
431 mpriv
->cur_history
->buffer
[i
-1] = '\0';
434 if (menu_dflt_read_key(menu
, c
))
438 int l
= strlen(mpriv
->cur_history
->buffer
);
439 if(l
>= mpriv
->cur_history
->size
) {
440 mpriv
->cur_history
->size
+= 255;
441 mpriv
->cur_history
->buffer
= realloc(mpriv
->cur_history
,mpriv
->cur_history
->size
);
443 mpriv
->cur_history
->buffer
[l
] = (char)c
;
444 mpriv
->cur_history
->buffer
[l
+1] = '\0';
451 static int openMenu(menu_t
* menu
, char* args
) {
455 menu
->read_cmd
= read_cmd
;
456 menu
->read_key
= read_key
;
458 mpriv
->lines
= calloc(mpriv
->buf_lines
,sizeof(char*));
459 mpriv
->prompt
= mpriv
->mp_prompt
;
460 mpriv
->cur_history
= mpriv
->history
= calloc(1,sizeof(history_t
));
461 mpriv
->cur_history
->buffer
= calloc(255,1);
462 mpriv
->cur_history
->size
= 255;
465 add_line(mpriv
,args
);
470 const menu_info_t menu_info_console
= {
477 sizeof(struct menu_priv_s
),