Code

fix unused parameter warnings
[ncmpc.git] / src / screen_file.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include "config.h"
22 #include "ncmpc.h"
23 #include "options.h"
24 #include "support.h"
25 #include "mpdclient.h"
26 #include "strfsong.h"
27 #include "command.h"
28 #include "screen.h"
29 #include "screen_utils.h"
30 #include "screen_browse.h"
31 #include "screen_play.h"
32 #include "gcc.h"
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <glib.h>
38 #include <ncurses.h>
40 #define USE_OLD_LAYOUT
41 #undef  USE_OLD_ADD
43 #define BUFSIZE 1024
45 #define HIGHLIGHT  (0x01)
48 static list_window_t *lw = NULL;
49 static list_window_state_t *lw_state = NULL;
50 static mpdclient_filelist_t *filelist = NULL;
53 /* clear the highlight flag for all items in the filelist */
54 void
55 clear_highlights(mpdclient_filelist_t *fl)
56 {
57         GList *list = g_list_first(fl->list);
59         while( list ) {
60                 filelist_entry_t *entry = list->data;
62                 entry->flags &= ~HIGHLIGHT;
63                 list = list->next;
64         }
65 }
67 /* change the highlight flag for a song */
68 void
69 set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight)
70 {
71         GList *list = g_list_first(fl->list);
73         if( !song )
74                 return;
76         while( list ) {
77                 filelist_entry_t *entry = list->data;
78                 mpd_InfoEntity *entity  = entry->entity;
80                 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
81                         mpd_Song *song2 = entity->info.song;
83                         if( strcmp(song->file, song2->file) == 0 ) {
84                                 if(highlight)
85                                         entry->flags |= HIGHLIGHT;
86                                 else
87                                         entry->flags &= ~HIGHLIGHT;
88                         }
89                 }
90                 list = list->next;
91         }
92 }
94 /* sync highlight flags with playlist */
95 void
96 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
97 {
98         GList *list = g_list_first(fl->list);
100         while(list) {
101                 filelist_entry_t *entry = list->data;
102                 mpd_InfoEntity *entity = entry->entity;
104                 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
105                         mpd_Song *song = entity->info.song;
107                         if( playlist_get_index_from_file(c, song->file) >= 0 )
108                                 entry->flags |= HIGHLIGHT;
109                         else
110                                 entry->flags &= ~HIGHLIGHT;
111                 }
112                 list=list->next;
113         }
116 /* the db have changed -> update the filelist */
117 static void
118 file_changed_callback(mpdclient_t *c, mpd_unused int event,
119                       mpd_unused gpointer data)
121         D("screen_file.c> filelist_callback() [%d]\n", event);
122         filelist = mpdclient_filelist_update(c, filelist);
123         sync_highlights(c, filelist);
124         list_window_check_selected(lw, filelist->length);
127 /* the playlist have been updated -> fix highlights */
128 static void
129 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
131         D("screen_file.c> playlist_callback() [%d]\n", event);
132         switch(event) {
133         case PLAYLIST_EVENT_CLEAR:
134                 clear_highlights(filelist);
135                 break;
136         case PLAYLIST_EVENT_ADD:
137                 set_highlight(filelist, (mpd_Song *) data, 1);
138                 break;
139         case PLAYLIST_EVENT_DELETE:
140                 set_highlight(filelist, (mpd_Song *) data, 0);
141                 break;
142         case PLAYLIST_EVENT_MOVE:
143                 break;
144         default:
145                 sync_highlights(c, filelist);
146                 break;
147         }
150 /* list_window callback */
151 const char *
152 browse_lw_callback(unsigned idx, int *highlight, void *data)
154         static char buf[BUFSIZE];
155         mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
156         filelist_entry_t *entry;
157         mpd_InfoEntity *entity;
159         *highlight = 0;
160         if( (entry=(filelist_entry_t *)g_list_nth_data(fl->list,idx))==NULL )
161                 return NULL;
163         entity = entry->entity;
164         *highlight = (entry->flags & HIGHLIGHT);
166         if( entity == NULL )
167                 return "[..]";
169         if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
170                 mpd_Directory *dir = entity->info.directory;
171                 char *directory = utf8_to_locale(basename(dir->path));
173                 g_snprintf(buf, BUFSIZE, "[%s]", directory);
174                 g_free(directory);
175                 return buf;
176         } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
177                 mpd_Song *song = entity->info.song;
179                 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
180                 return buf;
181         } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
182                 mpd_PlaylistFile *plf = entity->info.playlistFile;
183                 char *filename = utf8_to_locale(basename(plf->path));
185 #ifdef USE_OLD_LAYOUT
186                 g_snprintf(buf, BUFSIZE, "*%s*", filename);
187 #else
188                 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
189 #endif
190                 g_free(filename);
191                 return buf;
192         }
194         return "Error: Unknown entry!";
197 /* chdir */
198 static int
199 change_directory(mpd_unused screen_t *screen, mpdclient_t *c,
200                  filelist_entry_t *entry, const char *new_path)
202         mpd_InfoEntity *entity = NULL;
203         gchar *path = NULL;
205         if( entry!=NULL )
206                 entity = entry->entity;
207         else if( new_path==NULL )
208                 return -1;
210         if( entity==NULL ) {
211                 if( entry || 0==strcmp(new_path, "..") ) {
212                         /* return to parent */
213                         char *parent = g_path_get_dirname(filelist->path);
214                         if( strcmp(parent, ".") == 0 )
215                                 parent[0] = '\0';
216                         path = g_strdup(parent);
217                         list_window_reset(lw);
218                         /* restore previous list window state */
219                         list_window_pop_state(lw_state,lw);
220                 } else {
221                         /* entry==NULL, then new_path ("" is root) */
222                         path = g_strdup(new_path);
223                         list_window_reset(lw);
224                         /* restore first list window state (pop while returning true) */
225                         while(list_window_pop_state(lw_state,lw));
226                 }
227         } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
228                 /* enter sub */
229                 mpd_Directory *dir = entity->info.directory;
230                 path = utf8_to_locale(dir->path);
231                 /* save current list window state */
232                 list_window_push_state(lw_state,lw);
233         } else
234                 return -1;
236         filelist = mpdclient_filelist_free(filelist);
237         filelist = mpdclient_filelist_get(c, path);
238         sync_highlights(c, filelist);
239         list_window_check_selected(lw, filelist->length);
240         g_free(path);
241         return 0;
244 static int
245 load_playlist(mpd_unused screen_t *screen, mpdclient_t *c,
246               filelist_entry_t *entry)
248         mpd_InfoEntity *entity = entry->entity;
249         mpd_PlaylistFile *plf = entity->info.playlistFile;
250         char *filename = utf8_to_locale(plf->path);
252         if( mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0 )
253                 screen_status_printf(_("Loading playlist %s..."), basename(filename));
254         g_free(filename);
255         return 0;
258 static int
259 handle_save(screen_t *screen, mpdclient_t *c)
261         filelist_entry_t *entry;
262         char *defaultname = NULL;
265         entry=( filelist_entry_t *) g_list_nth_data(filelist->list,lw->selected);
266         if( entry && entry->entity ) {
267                 mpd_InfoEntity *entity = entry->entity;
268                 if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
269                         mpd_PlaylistFile *plf = entity->info.playlistFile;
270                         defaultname = plf->path;
271                 }
272         }
274         return playlist_save(screen, c, NULL, defaultname);
277 static int
278 handle_delete(screen_t *screen, mpdclient_t *c)
280         filelist_entry_t *entry;
281         mpd_InfoEntity *entity;
282         mpd_PlaylistFile *plf;
283         char *str, *buf;
284         int key;
286         entry=( filelist_entry_t *) g_list_nth_data(filelist->list,lw->selected);
287         if( entry==NULL || entry->entity==NULL )
288                 return -1;
290         entity = entry->entity;
292         if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
293                 screen_status_printf(_("You can only delete playlists!"));
294                 screen_bell();
295                 return -1;
296         }
298         plf = entity->info.playlistFile;
299         str = utf8_to_locale(basename(plf->path));
300         buf = g_strdup_printf(_("Delete playlist %s [%s/%s] ? "), str, YES, NO);
301         g_free(str);
302         key = tolower(screen_getch(screen->status_window.w, buf));
303         g_free(buf);
304         if( key==KEY_RESIZE )
305                 screen_resize();
306         if( key != YES[0] ) {
307                 screen_status_printf(_("Aborted!"));
308                 return 0;
309         }
311         if( mpdclient_cmd_delete_playlist_utf8(c, plf->path) )
312                 return -1;
314         screen_status_printf(_("Playlist deleted!"));
315         return 0;
318 static int
319 enqueue_and_play(mpd_unused screen_t *screen, mpdclient_t *c,
320                  filelist_entry_t *entry)
322         int idx;
323         mpd_InfoEntity *entity = entry->entity;
324         mpd_Song *song = entity->info.song;
326         if(!( entry->flags & HIGHLIGHT )) {
327                 if( mpdclient_cmd_add(c, song) == 0 ) {
328                         char buf[BUFSIZE];
330                         entry->flags |= HIGHLIGHT;
331                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
332                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
333                         mpdclient_update(c); /* get song id */
334                 } else
335                         return -1;
336         }
338         idx = playlist_get_index_from_file(c, song->file);
339         mpdclient_cmd_play(c, idx);
340         return 0;
343 int
344 browse_handle_enter(screen_t *screen,
345                     mpdclient_t *c,
346                     list_window_t *local_lw,
347                     mpdclient_filelist_t *fl)
349         filelist_entry_t *entry;
350         mpd_InfoEntity *entity;
352         if ( fl==NULL )
353                 return -1;
354         entry = ( filelist_entry_t *) g_list_nth_data(fl->list, local_lw->selected);
355         if( entry==NULL )
356                 return -1;
358         entity = entry->entity;
359         if( entity==NULL || entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
360                 return change_directory(screen, c, entry, NULL);
361         else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
362                 return load_playlist(screen, c, entry);
363         else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG )
364                 return enqueue_and_play(screen, c, entry);
365         return -1;
369 #ifdef USE_OLD_ADD
370 /* NOTE - The add_directory functions should move to mpdclient.c */
371 extern gint mpdclient_finish_command(mpdclient_t *c);
373 static int
374 add_directory(mpdclient_t *c, char *dir)
376         mpd_InfoEntity *entity;
377         GList *subdir_list = NULL;
378         GList *list = NULL;
379         char *dirname;
381         dirname = utf8_to_locale(dir);
382         screen_status_printf(_("Adding directory %s...\n"), dirname);
383         doupdate();
384         g_free(dirname);
385         dirname = NULL;
387         mpd_sendLsInfoCommand(c->connection, dir);
388         mpd_sendCommandListBegin(c->connection);
389         while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
390                 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
391                         mpd_Song *song = entity->info.song;
392                         mpd_sendAddCommand(c->connection, song->file);
393                         mpd_freeInfoEntity(entity);
394                 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
395                         subdir_list = g_list_append(subdir_list, (gpointer) entity);
396                 } else
397                         mpd_freeInfoEntity(entity);
398         }
399         mpd_sendCommandListEnd(c->connection);
400         mpdclient_finish_command(c);
401         c->need_update = TRUE;
403         list = g_list_first(subdir_list);
404         while( list!=NULL ) {
405                 mpd_Directory *dir;
407                 entity = list->data;
408                 dir = entity->info.directory;
409                 add_directory(c, dir->path);
410                 mpd_freeInfoEntity(entity);
411                 list->data=NULL;
412                 list=list->next;
413         }
414         g_list_free(subdir_list);
415         return 0;
417 #endif
419 int
420 browse_handle_select(screen_t *screen,
421                      mpdclient_t *c,
422                      list_window_t *local_lw,
423                      mpdclient_filelist_t *fl)
425         filelist_entry_t *entry;
427         if ( fl==NULL )
428                 return -1;
429         entry=( filelist_entry_t *) g_list_nth_data(fl->list,
430                                                     local_lw->selected);
431         if( entry==NULL || entry->entity==NULL)
432                 return -1;
434         if( entry->entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
435                 return load_playlist(screen, c, entry);
437         if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
438                 mpd_Directory *dir = entry->entity->info.directory;
439 #ifdef USE_OLD_ADD
440                 add_directory(c, tmp);
441 #else
442                 if( mpdclient_cmd_add_path_utf8(c, dir->path) == 0 ) {
443                         char *tmp = utf8_to_locale(dir->path);
445                         screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
446                         g_free(tmp);
447                 }
448 #endif
449                 return 0;
450         }
452         if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG )
453                 return -1;
455         if( entry->flags & HIGHLIGHT )
456                 entry->flags &= ~HIGHLIGHT;
457         else
458                 entry->flags |= HIGHLIGHT;
460         if( entry->flags & HIGHLIGHT ) {
461                 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
462                         mpd_Song *song = entry->entity->info.song;
464                         if( mpdclient_cmd_add(c, song) == 0 ) {
465                                 char buf[BUFSIZE];
467                                 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
468                                 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
469                         }
470                 }
471         } else {
472                 /* remove song from playlist */
473                 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
474                         mpd_Song *song = entry->entity->info.song;
476                         if( song ) {
477                                 int idx = playlist_get_index_from_file(c, song->file);
479                                 while( (idx=playlist_get_index_from_file(c, song->file))>=0 )
480                                         mpdclient_cmd_delete(c, idx);
481                         }
482                 }
483         }
484         return 0;
487 int
488 browse_handle_select_all (screen_t *screen,
489                           mpdclient_t *c,
490                           mpd_unused list_window_t *local_lw,
491                           mpdclient_filelist_t *fl)
493         filelist_entry_t *entry;
494         GList *temp = fl->list;
496         if ( fl==NULL )
497                 return -1;
498         for (fl->list = g_list_first(fl->list);
499              fl->list;
500              fl->list = g_list_next(fl->list)) {
501                 entry=( filelist_entry_t *) fl->list->data;
502                 if( entry==NULL || entry->entity==NULL)
503                         return -1;
505                 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
506                         load_playlist(screen, c, entry);
508                 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
509                         mpd_Directory *dir = entry->entity->info.directory;
510 #ifdef USE_OLD_ADD
511                         add_directory(c, tmp);
512 #else
513                         if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
514                                 char *tmp = utf8_to_locale(dir->path);
516                                 screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
517                                 g_free(tmp);
518                         }
519 #endif
520                 }
522                 if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG )
523                         continue;
525                 entry->flags |= HIGHLIGHT;
527                 if( entry->flags & HIGHLIGHT ) {
528                         if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
529                                 mpd_Song *song = entry->entity->info.song;
531                                 if( mpdclient_cmd_add(c, song) == 0 ) {
532                                         char buf[BUFSIZE];
534                                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
535                                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
536                                 }
537                         }
538                 }
539                 /*
540                 else {
541                         //remove song from playlist
542                         if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
543                                 mpd_Song *song = entry->entity->info.song;
545                                 if( song ) {
546                                         int idx = playlist_get_index_from_file(c, song->file);
548                                         while( (idx=playlist_get_index_from_file(c, song->file))>=0 )
549                                                 mpdclient_cmd_delete(c, idx);
550                                 }
551                         }
552                 }
553                 */
554                 return 0;
555         }
557         fl->list = temp;
558         return 0;
561 static void
562 browse_init(WINDOW *w, int cols, int rows)
564         lw = list_window_init(w, cols, rows);
565         lw_state = list_window_init_state();
568 static void
569 browse_resize(int cols, int rows)
571         lw->cols = cols;
572         lw->rows = rows;
575 static void
576 browse_exit(void)
578         if( filelist )
579                 filelist = mpdclient_filelist_free(filelist);
580         lw = list_window_free(lw);
581         lw_state = list_window_free_state(lw_state);
584 static void
585 browse_open(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c)
587         if( filelist == NULL ) {
588                 filelist = mpdclient_filelist_get(c, "");
589                 mpdclient_install_playlist_callback(c, playlist_changed_callback);
590                 mpdclient_install_browse_callback(c, file_changed_callback);
591         }
594 static void
595 browse_close(void)
599 static const char *
600 browse_title(char *str, size_t size)
602         char *pathcopy;
603         char *parentdir;
605         pathcopy = strdup(filelist->path);
606         parentdir = dirname(pathcopy);
607         parentdir = basename(parentdir);
609         if( parentdir[0] == '.' && strlen(parentdir) == 1 ) {
610                 parentdir = NULL;
611         }
613         g_snprintf(str, size, _("Browse: %s%s%s"),
614                    parentdir ? parentdir : "",
615                    parentdir ? "/" : "",
616                    basename(filelist->path));
617         free(pathcopy);
618         return str;
621 static void
622 browse_paint(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c)
624         lw->clear = 1;
626         list_window_paint(lw, browse_lw_callback, (void *) filelist);
627         wnoutrefresh(lw->w);
630 static void
631 browse_update(screen_t *screen, mpdclient_t *c)
633         if( filelist->updated ) {
634                 browse_paint(screen, c);
635                 filelist->updated = FALSE;
636                 return;
637         }
639         list_window_paint(lw, browse_lw_callback, (void *) filelist);
640         wnoutrefresh(lw->w);
644 #ifdef HAVE_GETMOUSE
645 int
646 browse_handle_mouse_event(screen_t *screen,
647                           mpdclient_t *c,
648                           list_window_t *local_lw,
649                           mpdclient_filelist_t *fl)
651         int row;
652         unsigned prev_selected = local_lw->selected;
653         unsigned long bstate;
654         int length;
656         if ( fl )
657                 length = fl->length;
658         else
659                 length = 0;
661         if( screen_get_mouse_event(c, local_lw, length, &bstate, &row) )
662                 return 1;
664         local_lw->selected = local_lw->start+row;
665         list_window_check_selected(local_lw, length);
667         if( bstate & BUTTON1_CLICKED ) {
668                 if( prev_selected == local_lw->selected )
669                         browse_handle_enter(screen, c, local_lw, fl);
670         } else if( bstate & BUTTON3_CLICKED ) {
671                 if( prev_selected == local_lw->selected )
672                         browse_handle_select(screen, c, local_lw, fl);
673         }
675         return 1;
677 #endif
679 static int
680 browse_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
682         switch(cmd)
683                 {
684                 case CMD_PLAY:
685                         browse_handle_enter(screen, c, lw, filelist);
686                         return 1;
687                 case CMD_GO_ROOT_DIRECTORY:
688                         return change_directory(screen, c, NULL, "");
689                         break;
690                 case CMD_GO_PARENT_DIRECTORY:
691                         return change_directory(screen, c, NULL, "..");
692                         break;
693                 case CMD_SELECT:
694                         if( browse_handle_select(screen, c, lw, filelist) == 0 )
695                                 {
696                                         /* continue and select next item... */
697                                         cmd = CMD_LIST_NEXT;
698                                 }
699                         break;
700                 case CMD_DELETE:
701                         handle_delete(screen, c);
702                         break;
703                 case CMD_SAVE_PLAYLIST:
704                         handle_save(screen, c);
705                         break;
706                 case CMD_SCREEN_UPDATE:
707                         screen->painted = 0;
708                         lw->clear = 1;
709                         lw->repaint = 1;
710                         filelist = mpdclient_filelist_update(c, filelist);
711                         list_window_check_selected(lw, filelist->length);
712                         screen_status_printf(_("Screen updated!"));
713                         return 1;
714                 case CMD_DB_UPDATE:
715                         if( !c->status->updatingDb )
716                                 {
717                                         if( mpdclient_cmd_db_update_utf8(c,filelist->path)==0 )
718                                                 {
719                                                         if(strcmp(filelist->path,"")) {
720                                                                 screen_status_printf(_("Database update of %s started!"),
721                                                                                      filelist->path);
722                                                         } else {
723                                                                 screen_status_printf(_("Database update started!"));
724                                                         }
725                                                         /* set updatingDb to make shure the browse callback gets called
726                                                          * even if the updated has finished before status is updated */
727                                                         c->status->updatingDb = 1;
728                                                 }
729                                 }
730                         else
731                                 screen_status_printf(_("Database update running..."));
732                         return 1;
733                 case CMD_LIST_FIND:
734                 case CMD_LIST_RFIND:
735                 case CMD_LIST_FIND_NEXT:
736                 case CMD_LIST_RFIND_NEXT:
737                         return screen_find(screen,
738                                            lw, filelist->length,
739                                            cmd, browse_lw_callback, (void *) filelist);
740                 case CMD_MOUSE_EVENT:
741                         return browse_handle_mouse_event(screen,c,lw,filelist);
742                 default:
743                         break;
744                 }
745         return list_window_cmd(lw, filelist->length, cmd);
748 static list_window_t *
749 get_filelist_window(void)
751         return lw;
754 screen_functions_t *
755 get_screen_browse(void)
757         static screen_functions_t functions;
759         memset(&functions, 0, sizeof(screen_functions_t));
760         functions.init = browse_init;
761         functions.exit = browse_exit;
762         functions.open = browse_open;
763         functions.close = browse_close;
764         functions.resize = browse_resize;
765         functions.paint = browse_paint;
766         functions.update = browse_update;
767         functions.cmd = browse_cmd;
768         functions.get_lw = get_filelist_window;
769         functions.get_title = browse_title;
771         return &functions;