/* * menu_dir2.c - * Demonstrate the use of an XView menu in a canvas subwindow. * A menu is brought up with the MENU mouse button and displays * menu choices representing the files in the directory. If a * directory entry is found, a new pullright item is created with * that subdir as the pullright menu's contents. This implementation * creates directories on an as-needed basis. Thus, we provide a * MENU_GEN_PULLRIGHT procedure. * * argv[1] indicates which directory to start from. */ #include <xview/xview.h> #include <xview/canvas.h> #include <sys/stat.h> #include <dirent.h> #if defined(__linux__) && defined(__GLIBC__) /* martin.buck@bigfoot.com */ #include <dirent.h> #else // #include <sys/dirent.h> #endif // #include <X11/Xos.h> #ifndef MAXPATHLEN #include <sys/param.h> #endif // /* MAXPATHLEN */ Frame frame; Menu_item add_path_to_menu(); void my_event_proc(); main(argc,argv) int argc; char *argv[]; { Canvas canvas; extern void exit(); Menu menu; Menu_item mi; xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL); frame = (Frame)xv_create(NULL, FRAME, FRAME_LABEL, argv[1]? argv[1] : "cwd", FRAME_SHOW_FOOTER, TRUE, NULL); canvas = (Canvas)xv_create(frame, CANVAS, FRAME_LABEL, argv[0], XV_WIDTH, 400, XV_HEIGHT, 100, NULL); mi = add_path_to_menu(argc > 1? argv[1] : "."); menu = (Menu)xv_get(mi, MENU_PULLRIGHT); /* We no longer need the item since we have the menu from it */ xv_destroy(mi); /* associate the menu to the canvas win for easy etreival */ xv_set(canvas_paint_window(canvas), WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, NULL, WIN_EVENT_PROC, my_event_proc, WIN_CLIENT_DATA, menu, NULL); window_fit(frame); window_main_loop(frame); } /* * my_action_proc - display the selected item in the frame footer. */ void my_action_proc(menu, menu_item) Menu menu; Menu_item menu_item; { xv_set(frame, FRAME_LEFT_FOOTER, xv_get(menu_item, MENU_STRING), NULL); } /* * Call menu_show() to display menu on right mouse button push. */ void my_event_proc(paint_win, event) Xv_Window paint_win; Event *event; { if ((event_id(event) == MS_RIGHT) && event_is_down(event)) { Menu menu = (Menu)xv_get(paint_win, WIN_CLIENT_DATA); menu_show(menu, paint_win, event, NULL); } } /* * return an allocated char * that points to the last item in a path. */ char * getfilename(path) char *path; { char *p; if (p = rindex(path, '/')) p++; else p = path; return strcpy(malloc(strlen(p)+1), p); } /* gen_pullright() is called in the following order: * Pullright menu needs to be displayed. (MENU_PULLRIGHT) * Menu is about to be dismissed (MENU_DISPLAY_DONE) * User made a selection (before menu notify function) * After the notify routine has been called. * The above order is done whether or not the user makes a * menu selection. */ Menu gen_pullright(mi, op) Menu_item mi; Menu_generate op; { Menu menu; Menu_item new, old = mi; char buf[MAXPATHLEN]; if (op == MENU_DISPLAY) { menu = (Menu)xv_get(mi, MENU_PARENT); sprintf(buf, "%s/%s", (char *)xv_get(menu, MENU_CLIENT_DATA), (char *)xv_get(mi, MENU_STRING)); /* get old menu and free it -- we're going to build another */ if (menu = (Menu)xv_get(mi, MENU_PULLRIGHT)) { free((char *)xv_get(menu, MENU_CLIENT_DATA)); xv_destroy(menu); } if (new = add_path_to_menu(buf)) { menu = (Menu)xv_get(new, MENU_PULLRIGHT); xv_destroy(new); return menu; } } if (!(menu = (Menu)xv_get(mi, MENU_PULLRIGHT))) menu = (Menu)xv_create(NULL, MENU, MENU_STRINGS, "Couldn't build a menu.", NULL, NULL); return menu; } /* * The path passed in is scanned via readdir(). For each file in the * path, a menu item is created and inserted into a new menu. That * new menu is made the PULLRIGHT_MENU of a newly created panel item * for the path item originally passed it. Since this routine is * recursive, a new menu is created for each subdirectory under the * original path. */ Menu_item add_path_to_menu(path) char *path; { DIR *dirp; struct dirent *dp; struct stat s_buf; Menu_item mi; Menu next_menu; char buf[MAXPATHLEN]; static int recursion; /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return NULL; if (s_buf.st_mode & S_IFDIR) { int cnt = 0; if (!(dirp = opendir(path))) /* don't bother adding to list if we can't scan it */ return NULL; if (recursion) return (Menu_item)-1; recursion++; next_menu = (Menu)xv_create(XV_NULL, MENU, NULL); while (dp = readdir(dirp)) if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { (void) sprintf(buf, "%s/%s", path, dp->d_name); mi = add_path_to_menu(buf); if (!mi || mi == (Menu_item)-1) { int do_gen_pullright = (mi == (Menu_item)-1); /* unreadable file or dir - deactivate item */ mi = (Menu_item)xv_create(XV_NULL, MENUITEM, MENU_STRING, getfilename(dp->d_name), MENU_RELEASE, MENU_RELEASE_IMAGE, NULL); if (do_gen_pullright) xv_set(mi, MENU_GEN_PULLRIGHT, gen_pullright, NULL); else xv_set(mi, MENU_INACTIVE, TRUE, NULL); } xv_set(next_menu, MENU_APPEND_ITEM, mi, NULL); cnt++; } closedir(dirp); mi = (Menu_item)xv_create(XV_NULL, MENUITEM, MENU_STRING, getfilename(path), MENU_RELEASE, MENU_RELEASE_IMAGE, MENU_NOTIFY_PROC, my_action_proc, NULL); if (!cnt) { xv_destroy(next_menu); /* An empty or unsearchable directory - deactivate item */ xv_set(mi, MENU_INACTIVE, TRUE, NULL); } else { xv_set(next_menu, MENU_TITLE_ITEM, strcpy(malloc(strlen(path)+1), path), MENU_CLIENT_DATA, strcpy(malloc(strlen(path)+1), path), NULL); xv_set(mi, MENU_PULLRIGHT, next_menu, NULL); } recursion--; return mi; } return (Menu_item)xv_create(NULL, MENUITEM, MENU_STRING, getfilename(path), MENU_RELEASE, MENU_RELEASE_IMAGE, MENU_NOTIFY_PROC, my_action_proc, NULL); }