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 read_cmd(menu_t
* menu
,int cmd
) {
231 case MENU_CMD_CANCEL
:
238 static void check_child(menu_t
* menu
) {
242 int max_fd
= mpriv
->child_fd
[2] > mpriv
->child_fd
[1] ? mpriv
->child_fd
[2] :
244 int i
,r
,child_status
,w
;
247 if(!mpriv
->child
) return;
249 memset(&tv
,0,sizeof(struct timeval
));
251 FD_SET(mpriv
->child_fd
[1],&rfd
);
252 FD_SET(mpriv
->child_fd
[2],&rfd
);
254 r
= select(max_fd
+1,&rfd
, NULL
, NULL
, &tv
);
256 r
= waitpid(mpriv
->child
,&child_status
,WNOHANG
);
258 if(errno
==ECHILD
){ ///exiting children get handled in mplayer.c
259 for(i
= 0 ; i
< 3 ; i
++)
260 close(mpriv
->child_fd
[i
]);
262 mpriv
->prompt
= mpriv
->mp_prompt
;
263 //add_line(mpriv,"Child process exited");
265 else mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WaitPidError
,strerror(errno
));
268 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_SelectError
);
273 for(i
= 1 ; i
< 3 ; i
++) {
274 if(FD_ISSET(mpriv
->child_fd
[i
],&rfd
)){
275 if(w
) mpriv
->add_line
= 1;
276 r
= read(mpriv
->child_fd
[i
],buffer
,255);
278 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ReadErrorOnChildFD
, i
== 1 ? "stdout":"stderr");
281 add_string(mpriv
,buffer
);
290 #define close_pipe(pipe) close(pipe[0]); close(pipe[1])
292 static int run_shell_cmd(menu_t
* menu
, char* cmd
) {
294 int in
[2],out
[2],err
[2];
296 mp_msg(MSGT_GLOBAL
,MSGL_INFO
,MSGTR_LIBMENU_ConsoleRun
,cmd
);
298 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_AChildIsAlreadyRunning
);
306 mpriv
->child
= fork();
307 if(mpriv
->child
< 0) {
308 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_ForkFailed
);
314 if(!mpriv
->child
) { // Chlid process
316 FILE* errf
= fdopen(err_fd
,"w");
317 // Bind the std fd to our pipes
321 execl("/bin/sh","sh","-c",cmd
,(void*)NULL
);
322 fprintf(errf
,"exec failed : %s\n",strerror(errno
));
326 mpriv
->child_fd
[0] = in
[1];
327 mpriv
->child_fd
[1] = out
[0];
328 mpriv
->child_fd
[2] = err
[0];
329 mpriv
->prompt
= mpriv
->child_prompt
;
330 //add_line(mpriv,"Child process started");
335 static void enter_cmd(menu_t
* menu
) {
337 char input
[strlen(mpriv
->cur_history
->buffer
) + strlen(mpriv
->prompt
) + 1];
339 sprintf(input
,"%s%s",mpriv
->prompt
,mpriv
->cur_history
->buffer
);
340 add_line(mpriv
,input
);
342 if(mpriv
->history
== mpriv
->cur_history
) {
343 if(mpriv
->history_size
>= mpriv
->history_max
) {
345 for(i
= mpriv
->history
; i
->prev
; i
= i
->prev
)
347 i
->next
->prev
= NULL
;
351 mpriv
->history_size
++;
352 h
= calloc(1,sizeof(history_t
));
354 h
->buffer
= calloc(h
->size
,1);
355 h
->prev
= mpriv
->history
;
356 mpriv
->history
->next
= h
;
359 mpriv
->history
->buffer
[0] = '\0';
361 mpriv
->cur_history
= mpriv
->history
;
362 //mpriv->input = mpriv->cur_history->buffer;
365 static void read_key(menu_t
* menu
,int c
) {
366 if(!mpriv
->child
|| !mpriv
->raw_child
) switch(c
) {
369 mpriv
->hide_ts
= GetTimerMS();
377 char *str
= mpriv
->cur_history
->buffer
;
380 int w
= write(mpriv
->child_fd
[0],str
,l
);
382 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WriteError
);
388 if(write(mpriv
->child_fd
[0],"\n",1) < 0)
389 mp_msg(MSGT_GLOBAL
,MSGL_ERR
,MSGTR_LIBMENU_WriteError
);
393 c
= mp_input_parse_cmd(mpriv
->cur_history
->buffer
);
396 add_line(mpriv
,"Invalid command try help");
400 add_line(mpriv
,"MPlayer console 0.01");
401 add_line(mpriv
,"TODO: meaningful help message ;)");
402 add_line(mpriv
,"Enter any slave command");
403 add_line(mpriv
,"exit close this console");
411 mpriv
->hide_ts
= GetTimerMS();
417 run_shell_cmd(menu
,c
->args
[0].v
.s
);
419 default: // Send the other commands to mplayer
420 mp_input_queue_cmd(c
);
427 unsigned int i
= strlen(mpriv
->cur_history
->buffer
);
429 mpriv
->cur_history
->buffer
[i
-1] = '\0';
433 if(mpriv
->cur_history
->prev
)
434 mpriv
->cur_history
= mpriv
->cur_history
->prev
;
437 if(mpriv
->cur_history
->next
)
438 mpriv
->cur_history
= mpriv
->cur_history
->next
;
442 if(mpriv
->child
&& mpriv
->raw_child
) {
443 write(mpriv
->child_fd
[0],&c
,sizeof(int));
448 int l
= strlen(mpriv
->cur_history
->buffer
);
449 if(l
>= mpriv
->cur_history
->size
) {
450 mpriv
->cur_history
->size
+= 255;
451 mpriv
->cur_history
->buffer
= realloc(mpriv
->cur_history
,mpriv
->cur_history
->size
);
453 mpriv
->cur_history
->buffer
[l
] = (char)c
;
454 mpriv
->cur_history
->buffer
[l
+1] = '\0';
460 static int openMenu(menu_t
* menu
, char* args
) {
464 menu
->read_cmd
= read_cmd
;
465 menu
->read_key
= read_key
;
467 mpriv
->lines
= calloc(mpriv
->buf_lines
,sizeof(char*));
468 mpriv
->prompt
= mpriv
->mp_prompt
;
469 mpriv
->cur_history
= mpriv
->history
= calloc(1,sizeof(history_t
));
470 mpriv
->cur_history
->buffer
= calloc(255,1);
471 mpriv
->cur_history
->size
= 255;
474 add_line(mpriv
,args
);
479 const menu_info_t menu_info_console
= {
486 sizeof(struct menu_priv_s
),