16 #include "img_format.h"
23 #include "libvo/font_load.h"
24 #include "osdep/keycodes.h"
25 #include "input/input.h"
26 #include "osdep/timer.h"
28 typedef struct history_st history_t
;
38 char** lines
; // Our buffer
44 pid_t child
; // Child process if we are running a shell cmd
45 int child_fd
[3]; // The 3 default fd
47 //int max_lines; // Max number of lines with the last mpi
49 history_t
* cur_history
;
54 int buf_lines
; // Buffer size (in line)
55 int height
; // Display size in %
58 unsigned int hide_time
;
59 unsigned int show_time
;
64 static struct menu_priv_s cfg_dflt
= {
90 #define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m)
92 static m_option_t cfg_fields
[] = {
93 { "prompt", ST_OFF(mp_prompt
), CONF_TYPE_STRING
, M_OPT_MIN
, 1, 0, NULL
},
94 { "child-prompt", ST_OFF(child_prompt
), CONF_TYPE_STRING
, M_OPT_MIN
, 1, 0, NULL
},
95 { "buffer-lines", ST_OFF(buf_lines
), CONF_TYPE_INT
, M_OPT_MIN
, 5, 0, NULL
},
96 { "height", ST_OFF(height
), CONF_TYPE_INT
, M_OPT_RANGE
, 1, 100, NULL
},
97 { "minbor", ST_OFF(minb
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
98 { "vspace", ST_OFF(vspace
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
99 { "show-time",ST_OFF(show_time
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
100 { "hide-time",ST_OFF(hide_time
), CONF_TYPE_INT
, M_OPT_MIN
, 0, 0, NULL
},
101 { "history-size",ST_OFF(history_max
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
102 { "raw-child", ST_OFF(raw_child
), CONF_TYPE_FLAG
, 0, 0, 1, NULL
},
103 { NULL
, NULL
, NULL
, 0,0,0,NULL
}
106 #define mpriv (menu->priv)
108 static void check_child(menu_t
* menu
);
110 static void add_line(struct menu_priv_s
* priv
, char* l
) {
111 char* eol
= strchr(l
,'\n');
118 if(eol
[1]) add_line(priv
,eol
+1);
122 if(priv
->num_lines
>= priv
->buf_lines
&& priv
->lines
[priv
->last_line
])
123 free(priv
->lines
[priv
->last_line
]);
127 priv
->lines
[priv
->last_line
] = strdup(l
);
128 priv
->last_line
= (priv
->last_line
+ 1) % priv
->buf_lines
;
132 static void add_string(struct menu_priv_s
* priv
, char* l
) {
133 char* eol
= strchr(l
,'\n');
134 int ll
= priv
->last_line
> 0 ? priv
->last_line
- 1 : priv
->buf_lines
-1;
136 if(priv
->num_lines
<= 0 || priv
->add_line
|| eol
== l
) {
146 add_line(priv
,eol
+1);
152 priv
->lines
[ll
] = realloc(priv
->lines
[ll
],strlen(priv
->lines
[ll
]) + strlen(l
) + 1);
153 if ( priv
->lines
[ll
] != NULL
)
155 strcat(priv
->lines
[ll
],l
);
159 static void draw(menu_t
* menu
, mp_image_t
* mpi
) {
160 int h
= mpi
->h
*mpriv
->height
/100;
161 int w
= mpi
->w
- 2* mpriv
->minb
;
162 int x
= mpriv
->minb
, y
;
165 if(mpriv
->child
) check_child(menu
);
167 ll
= mpriv
->last_line
- 1;
170 unsigned int t
= GetTimerMS() - mpriv
->hide_ts
;
171 if(t
>= mpriv
->hide_time
) {
176 h
= mpi
->h
*(mpriv
->height
- (mpriv
->height
* t
/mpriv
->hide_time
))/100;
177 } else if(mpriv
->show_time
&& mpriv
->show_ts
== 0) {
178 mpriv
->show_ts
= GetTimerMS();
180 } else if(mpriv
->show_ts
> 0) {
181 unsigned int t
= GetTimerMS() - mpriv
->show_ts
;
182 if(t
> mpriv
->show_time
)
185 h
= mpi
->h
*(mpriv
->height
* t
/mpriv
->hide_time
)/100;
188 y
= h
- mpriv
->vspace
;
190 if(x
< 0 || y
< 0 || w
<= 0 || h
<= 0 )
193 if(!mpriv
->child
|| !mpriv
->raw_child
){
194 char input
[strlen(mpriv
->cur_history
->buffer
) + strlen(mpriv
->prompt
) + 1];
195 sprintf(input
,"%s%s",mpriv
->prompt
,mpriv
->cur_history
->buffer
);
196 menu_text_size(input
,w
,mpriv
->vspace
,1,&lw
,&lh
);
197 menu_draw_text_full(mpi
,input
,x
,y
,w
,h
,mpriv
->vspace
,1,
198 MENU_TEXT_BOT
|MENU_TEXT_LEFT
,
199 MENU_TEXT_BOT
|MENU_TEXT_LEFT
);
200 y
-= lh
+ mpriv
->vspace
;
204 for( i
= 0 ; y
> mpriv
->minb
&& i
< mpriv
->num_lines
; i
++){
205 int c
= (ll
- i
) >= 0 ? ll
- i
: mpriv
->buf_lines
+ ll
- i
;
206 menu_text_size(mpriv
->lines
[c
],w
,mpriv
->vspace
,1,&lw
,&lh
);
207 menu_draw_text_full(mpi
,mpriv
->lines
[c
],x
,y
,w
,h
,mpriv
->vspace
,1,
208 MENU_TEXT_BOT
|MENU_TEXT_LEFT
,
209 MENU_TEXT_BOT
|MENU_TEXT_LEFT
);
210 y
-= lh
+ mpriv
->vspace
;
215 static void read_cmd(menu_t
* menu
,int cmd
) {
222 case MENU_CMD_CANCEL
:
229 static void check_child(menu_t
* menu
) {
233 int max_fd
= mpriv
->child_fd
[2] > mpriv
->child_fd
[1] ? mpriv
->child_fd
[2] :
235 int i
,r
,child_status
,w
;
238 if(!mpriv
->child
) return;
240 memset(&tv
,0,sizeof(struct timeval
));
242 FD_SET(mpriv
->child_fd
[1],&rfd
);
243 FD_SET(mpriv
->child_fd
[2],&rfd
);
245 r
= select(max_fd
+1,&rfd
, NULL
, NULL
, &tv
);
247 r
= waitpid(mpriv
->child
,&child_status
,WNOHANG
);
249 if(errno
==ECHILD
){ ///exiting childs get handled in mplayer.c
250 for(i
= 0 ; i
< 3 ; i
++)
251 close(mpriv
->child_fd
[i
]);
253 mpriv
->prompt
= mpriv
->mp_prompt
;
254 //add_line(mpriv,"Child process exited");
256 else printf("waitpid error: %s\n",strerror(errno
));
259 printf("select error\n");
264 for(i
= 1 ; i
< 3 ; i
++) {
265 if(FD_ISSET(mpriv
->child_fd
[i
],&rfd
)){
266 if(w
) mpriv
->add_line
= 1;
267 r
= read(mpriv
->child_fd
[i
],buffer
,255);
269 printf("Read error on child's %s \n", i
== 1 ? "stdout":"stderr");
272 add_string(mpriv
,buffer
);
281 #define close_pipe(pipe) close(pipe[0]); close(pipe[1])
283 static int run_shell_cmd(menu_t
* menu
, char* cmd
) {
285 int in
[2],out
[2],err
[2];
287 printf("Console run %s ...\n",cmd
);
289 printf("A child is alredy running\n");
297 mpriv
->child
= fork();
298 if(mpriv
->child
< 0) {
299 printf("Fork failed !!!\n");
305 if(!mpriv
->child
) { // Chlid process
307 FILE* errf
= fdopen(err_fd
,"w");
308 // Bind the std fd to our pipes
312 execl("/bin/sh","sh","-c",cmd
,(void*)NULL
);
313 fprintf(errf
,"exec failed : %s\n",strerror(errno
));
317 mpriv
->child_fd
[0] = in
[1];
318 mpriv
->child_fd
[1] = out
[0];
319 mpriv
->child_fd
[2] = err
[0];
320 mpriv
->prompt
= mpriv
->child_prompt
;
321 //add_line(mpriv,"Child process started");
326 static void enter_cmd(menu_t
* menu
) {
328 char input
[strlen(mpriv
->cur_history
->buffer
) + strlen(mpriv
->prompt
) + 1];
330 sprintf(input
,"%s%s",mpriv
->prompt
,mpriv
->cur_history
->buffer
);
331 add_line(mpriv
,input
);
333 if(mpriv
->history
== mpriv
->cur_history
) {
334 if(mpriv
->history_size
>= mpriv
->history_max
) {
336 for(i
= mpriv
->history
; i
->prev
; i
= i
->prev
)
338 i
->next
->prev
= NULL
;
342 mpriv
->history_size
++;
343 h
= calloc(1,sizeof(history_t
));
345 h
->buffer
= calloc(h
->size
,1);
346 h
->prev
= mpriv
->history
;
347 mpriv
->history
->next
= h
;
350 mpriv
->history
->buffer
[0] = '\0';
352 mpriv
->cur_history
= mpriv
->history
;
353 //mpriv->input = mpriv->cur_history->buffer;
356 static void read_key(menu_t
* menu
,int c
) {
357 if(!mpriv
->child
|| !mpriv
->raw_child
) switch(c
) {
360 mpriv
->hide_ts
= GetTimerMS();
368 char *str
= mpriv
->cur_history
->buffer
;
371 int w
= write(mpriv
->child_fd
[0],str
,l
);
373 printf("Write error\n");
379 if(write(mpriv
->child_fd
[0],"\n",1) < 0)
380 printf("Write error\n");
384 c
= mp_input_parse_cmd(mpriv
->cur_history
->buffer
);
387 add_line(mpriv
,"Invalid command try help");
391 add_line(mpriv
,"MPlayer console 0.01");
392 add_line(mpriv
,"TODO: meaningful help message ;)");
393 add_line(mpriv
,"Enter any slave command");
394 add_line(mpriv
,"exit close this console");
402 mpriv
->hide_ts
= GetTimerMS();
408 run_shell_cmd(menu
,c
->args
[0].v
.s
);
410 default: // Send the other commands to mplayer
411 mp_input_queue_cmd(c
);
418 unsigned int i
= strlen(mpriv
->cur_history
->buffer
);
420 mpriv
->cur_history
->buffer
[i
-1] = '\0';
424 if(mpriv
->cur_history
->prev
)
425 mpriv
->cur_history
= mpriv
->cur_history
->prev
;
428 if(mpriv
->cur_history
->next
)
429 mpriv
->cur_history
= mpriv
->cur_history
->next
;
433 if(mpriv
->child
&& mpriv
->raw_child
) {
434 write(mpriv
->child_fd
[0],&c
,sizeof(int));
439 int l
= strlen(mpriv
->cur_history
->buffer
);
440 if(l
>= mpriv
->cur_history
->size
) {
441 mpriv
->cur_history
->size
+= 255;
442 mpriv
->cur_history
->buffer
= realloc(mpriv
->cur_history
,mpriv
->cur_history
->size
);
444 mpriv
->cur_history
->buffer
[l
] = (char)c
;
445 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,sizeof(char));
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
),