home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFM / XFM-1.3 / XFM-1 / xfm-1.3 / xfm / FmFw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  40.1 KB  |  1,422 lines

  1. /*-----------------------------------------------------------------------------
  2.   Module FmFw.c                                                             
  3.  
  4.   (c) Simon Marlow 1991
  5.   (c) Albert Graef 1994
  6.                                                                            
  7.   functions & data for creating a file window, and various functions        
  8.   related to file windows                                                   
  9. -----------------------------------------------------------------------------*/
  10.  
  11. #include <pwd.h>
  12. #include <time.h>
  13. #include <string.h>
  14. #include <sys/wait.h>
  15.  
  16. #include <X11/Intrinsic.h>
  17. #include <X11/Shell.h>
  18. #include <X11/StringDefs.h>
  19. #include <X11/Xaw/Form.h>
  20. #include <X11/Xaw/Box.h>
  21. #include <X11/Xaw/Viewport.h>
  22. #include <X11/Xaw/Toggle.h>
  23. #include <X11/Xaw/Label.h>
  24.  
  25. #include "Am.h"
  26. #include "Fm.h"
  27.  
  28. #define FW_WIDTH 400
  29. #define FW_HEIGHT 300
  30. #define TEXT_PADDING 10
  31. #define MAXCFGLINELEN 1024
  32.  
  33. /*-----------------------------------------------------------------------------
  34.   PUBLIC DATA                                       
  35. -----------------------------------------------------------------------------*/
  36.  
  37. FileWindowList file_windows = NULL;
  38. FileWindowRec *popup_fw;
  39. Widget file_popup_widget, *file_popup_items;
  40. Widget dir_popup_widget, *dir_popup_items;
  41.  
  42. int n_types;
  43. TypeList types;
  44.  
  45. int n_devices;
  46. DevList devs;
  47.  
  48. /*-----------------------------------------------------------------------------
  49.   STATIC DATA                                       
  50. -----------------------------------------------------------------------------*/
  51.  
  52. static MenuItemRec file_popup_menu[] = {
  53.   { "edit", "Edit", fileEditCb },
  54.   { "line1", NULL, NULL },
  55.   { "move", "Move...", movePopup },
  56.   { "copy", "Copy...", copyPopup },
  57.   { "delete", "Delete", deleteItems },
  58.   { "line2", NULL, NULL },
  59.   { "info", "Information...", infoPopup },
  60.   { "chmod", "Permissions...", chmodPopup }
  61. };
  62.  
  63. static MenuItemRec dir_popup_menu[] = {
  64.   { "open", "Open", fileOpenCb },
  65.   { "line1", NULL, NULL },
  66.   { "move", "Move...", movePopup },
  67.   { "copy", "Copy...", copyPopup },
  68.   { "delete", "Delete", deleteItems },
  69.   { "line2", NULL, NULL },
  70.   { "info", "Information...", infoPopup },
  71.   { "chmod", "Permissions...", chmodPopup }
  72. };
  73.  
  74. static MenuItemRec file_menu[] = {
  75.   { "new", "New...", createFilePopup },
  76.   { "line1", NULL, NULL },
  77.   { "move", "Move...", movePopup },
  78.   { "copy", "Copy...", copyPopup },
  79.   { "link", "Link...", linkPopup },
  80.   { "line2", NULL, NULL },
  81.   { "delete", "Delete",  deleteItems },
  82.   { "line3", NULL, NULL },
  83.   { "select", "Select...", selectPopup },
  84.   { "select all", "Select all", fileSelectAllCb },
  85.   { "deselect all", "Deselect all", fileDeselectCb },
  86.   { "line4", NULL, NULL },
  87.   { "quit", "Quit", appCloseCb },
  88. };
  89.  
  90. static MenuItemRec folder_menu[] = {
  91.   { "new", "New...", mkdirPopup },
  92.   { "line1", NULL, NULL },
  93.   { "goto", "Go to...", goToPopup },
  94.   { "home", "Home", fileHomeCb },
  95.   { "up", "Up", fileUpCb },
  96.   { "line2", NULL, NULL },
  97.   { "empty", "Empty", emptyDir },
  98.   { "line3", NULL, NULL },
  99.   { "close", "Close", fileCloseCb },
  100. };
  101.  
  102. static MenuItemRec view_menu[] = {
  103.   { "tree", "Tree",  fileTreeCb },
  104.   { "icons", "Icons",  fileIconsCb },
  105.   { "text", "Text",  fileTextCb },
  106.   { "line1", NULL,  NULL },
  107.   { "sort by name", "Sort by name",  fileSortNameCb },
  108.   { "sort by size", "Sort by size",  fileSortSizeCb },
  109.   { "sort by mtime", "Sort by date",  fileSortMTimeCb },
  110.   { "line2", NULL,  NULL },
  111.   { "hide folders", "Hide folders",  fileShowDirsCb },
  112.   { "mix folders/files", "Mix folders/files",
  113.        fileDirsFirstCb },
  114.   { "show hidden files", "Show hidden files", fileShowHiddenCb },
  115. };
  116.  
  117. /*-----------------------------------------------------------------------------
  118.   Widget Argument Lists
  119. -----------------------------------------------------------------------------*/
  120.  
  121. static Arg shell_args[] = {
  122.   { XtNtitle, (XtArgVal) NULL },
  123.   { XtNiconPixmap, (XtArgVal) NULL },
  124.   { XtNiconMask, (XtArgVal) NULL }
  125. };
  126.  
  127. static Arg form_args[] = {
  128.   { XtNdefaultDistance, (XtArgVal) 0 }
  129. };
  130.  
  131. static Arg button_box_args[] = {
  132.   { XtNtop, XtChainTop },
  133.   { XtNbottom, XtChainTop },
  134.   { XtNleft, XtChainLeft },
  135.   { XtNright, XtChainLeft },
  136. };
  137.  
  138. static Arg label_args[] = {
  139.   { XtNfromVert, (XtArgVal) NULL },
  140.   { XtNlabel, (XtArgVal) NULL },
  141.   { XtNwidth, (XtArgVal) FW_WIDTH },
  142.   { XtNfont, (XtArgVal) NULL },
  143.   { XtNresize, (XtArgVal) False },
  144.   { XtNtop, XtChainTop },
  145.   { XtNbottom, XtChainTop },
  146.   { XtNleft, XtChainLeft },
  147.   { XtNright, XtChainRight },
  148.   { XtNtranslations, (XtArgVal) NULL },
  149. };
  150.  
  151. static Arg viewport_args[] = {
  152.   { XtNfromVert, (XtArgVal) NULL },
  153.   { XtNwidth, (XtArgVal) FW_WIDTH },
  154.   { XtNtop, XtChainTop },
  155.   { XtNbottom, XtChainBottom },
  156.   { XtNleft, XtChainLeft },
  157.   { XtNright, XtChainRight },
  158.   { XtNallowVert, (XtArgVal) True }
  159. };
  160.  
  161. static Arg status_args[] = {
  162.   { XtNfromVert, (XtArgVal) NULL },
  163.   { XtNlabel, (XtArgVal) NULL },
  164.   { XtNwidth, (XtArgVal) FW_WIDTH },
  165.   { XtNfont, (XtArgVal) NULL },
  166.   { XtNresize, (XtArgVal) False },
  167.   { XtNtop, XtChainBottom },
  168.   { XtNbottom, XtChainBottom },
  169.   { XtNleft, XtChainLeft },
  170.   { XtNright, XtChainRight },
  171.   { XtNjustify, XtJustifyLeft }
  172. };
  173.  
  174. static Arg icon_box_args[] = {
  175.   { XtNwidth, (XtArgVal) 0 },
  176.   { XtNtranslations, (XtArgVal) NULL }
  177. };
  178.  
  179. static Arg tree_box_args[] = {
  180.   { XtNwidth, (XtArgVal) 1 },
  181.   { XtNdefaultDistance, (XtArgVal) 0 },
  182.   { XtNheight, (XtArgVal) 1 }
  183. };
  184.  
  185. static Arg icon_form_args[] = {
  186.   { XtNdefaultDistance, (XtArgVal) 0 },
  187.   { XtNwidth, (XtArgVal) 0 }
  188. };
  189.  
  190. static Arg tree_form_args[] = {
  191.   { XtNfromHoriz, (XtArgVal) NULL },
  192.   { XtNfromVert, (XtArgVal) NULL },
  193.   { XtNdefaultDistance, (XtArgVal) 0 },
  194.   { XtNwidth, (XtArgVal) 0 },
  195.   { XtNtop, XtChainTop },
  196.   { XtNbottom, XtChainTop },
  197.   { XtNleft, XtChainLeft },
  198.   { XtNright, XtChainLeft }
  199. };
  200.  
  201. static Arg icon_toggle_args[] = {
  202.   { XtNfromHoriz, (XtArgVal) NULL },
  203.   { XtNfromVert, (XtArgVal) NULL },
  204.   { XtNbitmap, (XtArgVal) NULL },
  205.   { XtNtranslations, (XtArgVal) NULL },
  206.   { XtNwidth, (XtArgVal) 0 },
  207.   { XtNheight, (XtArgVal) 0 }
  208. };
  209.  
  210. static Arg icon_label_args[] = {
  211.   { XtNfromHoriz, (XtArgVal) NULL },
  212.   { XtNfromVert, (XtArgVal) NULL },
  213.   { XtNlabel, (XtArgVal) NULL },
  214.   { XtNfont, (XtArgVal) NULL },
  215.   { XtNwidth, (XtArgVal) 0 },
  216.   { XtNtranslations, (XtArgVal) NULL },
  217.   { XtNinternalWidth, (XtArgVal) 0 },
  218.   { XtNinternalHeight, (XtArgVal) 0 },
  219. };
  220.  
  221. static Arg text_label_args[] = {
  222.   { XtNfromHoriz, (XtArgVal) NULL },
  223.   { XtNfromVert, (XtArgVal) NULL },
  224.   { XtNlabel, (XtArgVal) NULL },
  225.   { XtNfont, (XtArgVal) NULL },
  226.   { XtNwidth, (XtArgVal) 0 },
  227.   { XtNjustify, XtJustifyLeft },
  228.   { XtNhorizDistance, (XtArgVal) TEXT_PADDING },
  229.   { XtNinternalWidth, (XtArgVal) 0 },
  230.   { XtNinternalHeight, (XtArgVal) 0 }
  231. };
  232.  
  233. static Arg text_toggle_args[] = {
  234.   { XtNfromHoriz, (XtArgVal) NULL },
  235.   { XtNfromVert, (XtArgVal) NULL },
  236.   { XtNlabel, (XtArgVal) NULL },
  237.   { XtNfont, (XtArgVal) NULL },
  238.   { XtNwidth, (XtArgVal) 0 },
  239.   { XtNtranslations, (XtArgVal) NULL },
  240.   { XtNjustify, XtJustifyLeft },
  241.   { XtNinternalWidth, (XtArgVal) 0 },
  242.   { XtNinternalHeight, (XtArgVal) 0 }
  243. };
  244.  
  245. static Arg arrow_args[] = {
  246.   { XtNfromHoriz, (XtArgVal) NULL },
  247.   { XtNfromVert, (XtArgVal) NULL },
  248.   { XtNbitmap, (XtArgVal) NULL },
  249.   { XtNsensitive, (XtArgVal) True },
  250.   { XtNtop, XtChainTop },
  251.   { XtNbottom, XtChainTop },
  252.   { XtNleft, XtChainLeft },
  253.   { XtNright, XtChainLeft },
  254.   { XtNinternalWidth, (XtArgVal) 0 },
  255.   { XtNinternalHeight, (XtArgVal) 0 },
  256.   { XtNhighlightThickness, (XtArgVal) 0 }
  257. };
  258.  
  259. static Arg line_args[] = {
  260.   { XtNfromHoriz, (XtArgVal) NULL },
  261.   { XtNfromVert, (XtArgVal) NULL },
  262.   { XtNbitmap, (XtArgVal) NULL },
  263.   { XtNtop, XtChainTop },
  264.   { XtNbottom, XtChainTop },
  265.   { XtNleft, XtChainLeft },
  266.   { XtNright, XtChainLeft },
  267.   { XtNinternalWidth, (XtArgVal) 0 },
  268.   { XtNinternalHeight, (XtArgVal) 0 }
  269. };
  270.  
  271. /*-----------------------------------------------------------------------------
  272.   Translation tables
  273. -----------------------------------------------------------------------------*/
  274.  
  275. static char label_translations_s[] = "\
  276.   <Btn1Up>(2)         : fileRefresh()\n";
  277.  
  278. static char tree_translations_s[] = "\
  279.   <Enter>             : fileHighlight()\n\
  280.   <Leave>             : resetCursor()\n\
  281.   <Btn1Down>,<Btn1Up> : fileSelect()\n\
  282.   <Btn1Down>,<Leave>  : fileBeginDrag(1,move)\n\
  283.   <Btn2Down>,<Btn2Up> : fileToggle()\n\
  284.   <Btn2Down>,<Leave>  : fileBeginDrag(2,copy)\n\
  285.   <Btn3Down>          : dirPopup()\n";
  286.  
  287.  
  288. static char dir_translations_s[] = "\
  289.   <Enter>             : fileHighlight()\n\
  290.   <Leave>             : resetCursor()\n\
  291.   <Btn1Down>,<Btn1Up> : fileSelect()\n\
  292.   <Btn1Down>,<Leave>  : fileBeginDrag(1,move)\n\
  293.   <Btn1Up>(2)         : fileOpenDir()\n\
  294.   <Btn2Down>,<Btn2Up> : fileToggle()\n\
  295.   <Btn2Down>,<Leave>  : fileBeginDrag(2,copy)\n\
  296.   <Btn3Down>          : dirPopup()\n";
  297.  
  298. static char file_translations_s[] = "\
  299.   <Enter>             : fileMaybeHighlight()\n\
  300.   <Leave>             : unhighlight()\n\
  301.   <Btn1Up>(2)         : fileExecAction()\n\
  302.   <Btn1Down>,<Btn1Up> : fileSelect()\n\
  303.   <Btn1Down>,<Leave>  : fileBeginDrag(1,move)\n\
  304.   <Btn2Down>,<Btn2Up> : fileToggle()\n\
  305.   <Btn2Down>,<Leave>  : fileBeginDrag(2,copy)\n\
  306.   <Btn3Down>          : filePopup()\n";
  307.  
  308. static char exec_translations_s[] = "\
  309.   <Enter>             : fileHighlight()\n\
  310.   <Leave>             : resetCursor()\n\
  311.   <Btn1Up>(2)         : fileExecFile()\n\
  312.   <Btn1Down>,<Btn1Up> : fileSelect()\n\
  313.   <Btn1Down>,<Leave>  : fileBeginDrag(1,move)\n\
  314.   <Btn2Down>,<Btn2Up> : fileToggle()\n\
  315.   <Btn2Down>,<Leave>  : fileBeginDrag(2,copy)\n\
  316.   <Btn3Down>          : filePopup()\n";
  317.  
  318. /* This is a hack to get the icon box to recognise button events */
  319. static char iconbox_translations_s[] = "\
  320.     <Btn2Up> : dummy()\n\
  321.     <Btn3Up> : dummy()\n";
  322.   
  323. static void dummy(Widget w, XEvent *event, String *params, 
  324.                Cardinal *num_params) {}
  325.  
  326. static XtActionsRec file_actions[] = {
  327.   { "fileRefresh", fileRefresh },
  328.   { "fileToggle", fileToggle },
  329.   { "fileSelect", fileSelect },
  330.   { "fileHighlight", fileHighlight },
  331.   { "fileOpenDir", fileOpenDir },
  332.   { "fileBeginDrag", fileBeginDrag },
  333.   { "fileExecFile", fileExecFile },
  334.   { "fileExecAction", fileExecAction },
  335.   { "resetCursor", resetCursor },
  336.   { "fileMaybeHighlight", fileMaybeHighlight },
  337.   { "filePopup", filePopup },
  338.   { "dirPopup", dirPopup },
  339.   { "dummy", dummy }
  340. };
  341.  
  342. static XtTranslations label_translations, dir_translations, file_translations, 
  343.   iconbox_translations, tree_translations, exec_translations;
  344.  
  345. /*-----------------------------------------------------------------------------
  346.   PRIVATE FUNCTIONS
  347. -----------------------------------------------------------------------------*/
  348.  
  349. static int longestName(FileWindowRec *fw)
  350. {
  351.   int i,l;
  352.   int longest = 0;
  353.  
  354.   for (i=0; i<fw->n_files; i++)
  355.     if ((l = XTextWidth(resources.icon_font, fw->files[i]->name, 
  356.             strlen(fw->files[i]->name))) > longest)
  357.       longest = l;
  358.   return longest;
  359. }
  360.  
  361. /*---------------------------------------------------------------------------*/
  362.  
  363. static int parseType(FILE *fp, char **pattern, char **icon, char **push_action,
  364.              char **drop_action)
  365. {
  366.   static char s[MAXCFGLINELEN];
  367.   int l;
  368.  
  369.  start:
  370.   if (feof(fp)||!fgets(s, MAXCFGLINELEN, fp))
  371.     return 0;
  372.   l = strlen(s);
  373.   if (s[l-1] == '\n')
  374.     s[--l] = '\0';
  375.   if (!l || *s == '#')
  376.     goto start;
  377.   if (!(*pattern = split(s, ':')))
  378.     return -1;
  379.   if (!(*icon = split(NULL, ':')))
  380.     return -1;
  381.   if (!(*push_action = split(NULL, ':')))
  382.     return -1;
  383.   if (!(*drop_action = split(NULL, ':')))
  384.     return -1;
  385.   return l;
  386. }
  387.  
  388. /*---------------------------------------------------------------------------*/
  389.  
  390. static void readFileBitmaps()
  391. {
  392.   int i;
  393.  
  394.   for (i=0; i<n_types; i++)
  395.     if (!types[i].icon[0])
  396.       types[i].icon_bm = bm[FILE_BM];
  397.     else if ((types[i].icon_bm = readIcon(types[i].icon)) == None) {
  398.       fprintf(stderr, "%s: can't read icon for type %s%s%s\n", progname,
  399.           types[i].dir<0?"*":"", types[i].pattern,
  400.           types[i].dir>0?"*":"");
  401.       types[i].icon_bm = bm[FILE_BM];
  402.     }
  403. }
  404.  
  405. /*---------------------------------------------------------------------------*/
  406.  
  407. static void readFileTypes(String path)
  408. {
  409.   FILE *fp;
  410.   char *pattern, *icon, *push_action, *drop_action;
  411.   char s[MAXCFGSTRINGLEN];
  412.   int i, l, p;
  413.   
  414.   n_types = 0;
  415.   types = NULL;
  416.   
  417.   if (!(fp = fopen(path, "r"))) return;
  418.  
  419.   for (i=0; (p = parseType(fp, &pattern, &icon, &push_action,
  420.                &drop_action)) > 0; i++) {
  421.     types = (TypeList) XTREALLOC(types, (i+1)*sizeof(TypeRec) );
  422.     l = strlen(pattern);
  423.     if (pattern[0] == '*') {
  424.       types[i].dir = -1;
  425.       strparse(s, pattern+1, "\\:");
  426.     } else if (pattern[l-1] == '*') {
  427.       types[i].dir = 1;
  428.       pattern[l-1] = '\0';
  429.       strparse(s, pattern, "\\:");
  430.     } else {
  431.       types[i].dir = 0;
  432.       strparse(s, pattern, "\\:");
  433.     }
  434.     types[i].len = strlen(s);
  435.     types[i].pattern = XtNewString(s);
  436.     types[i].icon = XtNewString(strparse(s, icon, "\\:"));
  437.     types[i].push_action = XtNewString(strparse(s, push_action, "\\:"));
  438.     types[i].drop_action = XtNewString(strparse(s, drop_action, "\\:"));
  439.   }
  440.  
  441.   if (p == -1)
  442.     error("Error in configuration file", "");
  443.  
  444.   n_types = i;
  445.   
  446.   if (fclose(fp))
  447.     sysError("Error reading configuration file:");
  448.  
  449.   readFileBitmaps();
  450. }
  451.  
  452. /*---------------------------------------------------------------------------*/
  453.  
  454. static TypeRec *fileType(char *name)
  455. {
  456.   int i, l = strlen(name);
  457.  
  458.   for (i = 0; i < n_types; i++)
  459.     switch (types[i].dir) {
  460.     case 0:
  461.       if (!strcmp(name, types[i].pattern))
  462.     return types+i;
  463.       break;
  464.     case 1:
  465.       if (!strncmp(types[i].pattern, name, types[i].len))
  466.     return types+i;
  467.       break;
  468.     case -1:
  469.       if (l >= types[i].len && !strncmp(types[i].pattern, name+l-types[i].len,
  470.                     types[i].len))
  471.     return types+i;
  472.       break;
  473.     }
  474.   return NULL;
  475. }
  476.  
  477. /*---------------------------------------------------------------------------*/
  478.  
  479. static int parseDev(FILE *fp, char **name, char **mount_action,
  480.             char **umount_action)
  481. {
  482.   static char s[MAXCFGLINELEN];
  483.   int l;
  484.  
  485.  start:
  486.   if (feof(fp)||!fgets(s, MAXCFGLINELEN, fp))
  487.     return 0;
  488.   l = strlen(s);
  489.   if (s[l-1] == '\n')
  490.     s[--l] = '\0';
  491.   if (!l || *s == '#')
  492.     goto start;
  493.   if (!(*name = split(s, ':')))
  494.     return -1;
  495.   if (!(*mount_action = split(NULL, ':')))
  496.     return -1;
  497.   if (!(*umount_action = split(NULL, ':')))
  498.     return -1;
  499.   return l;
  500. }
  501.  
  502. /*---------------------------------------------------------------------------*/
  503.  
  504. static void readDevices(String path)
  505. {
  506.   FILE *fp;
  507.   char *name, *mount_action, *umount_action;
  508.   char s[MAXCFGSTRINGLEN];
  509.   int i, p;
  510.   
  511.   n_devices = 0;
  512.   devs = NULL;
  513.   
  514.   if (!(fp = fopen(path, "r"))) return;
  515.  
  516.   for (i=0; (p = parseDev(fp, &name, &mount_action, &umount_action)) > 0;
  517.        i++) {
  518.     devs = (DevList) XTREALLOC(devs, (i+1)*sizeof(DevRec) );
  519.     devs[i].name = XtNewString(strparse(s, name, "\\:"));
  520.     devs[i].mount_action = XtNewString(strparse(s, mount_action, "\\:"));
  521.     devs[i].umount_action = XtNewString(strparse(s, umount_action, "\\:"));
  522.     devs[i].mounted = 0;
  523.   }
  524.  
  525.   if (p == -1)
  526.     error("Error in devices file", "");
  527.  
  528.   n_devices = i;
  529.   
  530.   if (fclose(fp))
  531.     sysError("Error reading devices file:");
  532. }
  533.  
  534. /*---------------------------------------------------------------------------*/
  535.  
  536. static int devAction(int d, char *action)
  537. {
  538.   int pid, status;
  539.  
  540.   if ((pid = fork()) == -1) {
  541.     sysError("Can't fork:");
  542.     return 0;
  543.   } else if (chdir(user.home)) {
  544.     sysError("Can't chdir:");
  545.     return 0;
  546.   } else if (!pid) {
  547.     if (resources.echo_actions)
  548.       fprintf(stderr, "%s\n", action);
  549.     freopen("/dev/null", "r", stdin);
  550.     execlp(user.shell, user.shell, "-c", action, NULL);
  551.     perror("Exec failed");
  552.     exit(1);
  553.   } else if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) ||
  554.          WEXITSTATUS(status))
  555.     return 0;
  556.   else
  557.     return 1;
  558. }
  559.  
  560. /*---------------------------------------------------------------------------*/
  561.  
  562. static void createFileIcons(FileWindowRec *fw)
  563. {
  564.   int i;
  565.   Dimension width;
  566.   FileRec *file;
  567.   Pixmap icon;
  568.   char *iconname[4] = {"dir_icon","file_icon","exe_icon","other_icon"};
  569.   int icontype;
  570.  
  571.   XtVaGetValues(fw->viewport, XtNwidth, &width, NULL);
  572.   icon_box_args[0].value = (XtArgVal) width;
  573.  
  574.   width = longestName(fw);
  575.   if (width < resources.file_icon_width)
  576.     width = resources.file_icon_width;
  577.   icon_form_args[1].value = (XtArgVal) width;
  578.   icon_toggle_args[4].value = (XtArgVal) width;
  579.   icon_toggle_args[5].value = (XtArgVal) resources.file_icon_height;
  580.   icon_label_args[4].value = (XtArgVal) width;
  581.  
  582.   fw->icon_box = XtCreateWidget("icon box",  boxWidgetClass,
  583.     fw->viewport, icon_box_args, XtNumber(icon_box_args) );
  584.  
  585.   for (i=0; i < fw->n_files; i++) {
  586.     Pixel back;
  587.     
  588.     file = fw->files[i];
  589.     file->icon.form = XtCreateManagedWidget(file->name,
  590.       formWidgetClass, fw->icon_box, icon_form_args,
  591.       XtNumber(icon_form_args) );
  592.  
  593.     icon = None;
  594.     icontype = 3;
  595.  
  596.     /* Symbolic link to non-existent file */
  597.     if (S_ISLNK(file->stats.st_mode)) {
  598.       icon_toggle_args[3].value = (XtArgVal) file_translations;
  599.       icon = (XtArgVal) bm[BLACKHOLE_BM];
  600.     }
  601.  
  602.     else if (S_ISDIR(file->stats.st_mode)) {
  603.       icon_toggle_args[3].value = (XtArgVal) dir_translations;
  604.       if (icon == None)
  605.     if (file->sym_link)
  606.       icon = (XtArgVal) bm[DIRLNK_BM];
  607.     else if (!strcmp(file->name, ".."))
  608.       icon = (XtArgVal) bm[UPDIR_BM];
  609.         else
  610.       icon = (XtArgVal) bm[DIR_BM];
  611.       icontype = 0;
  612.     }
  613.     else if (file->stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
  614.       icon_toggle_args[3].value = (XtArgVal) exec_translations;
  615.       if (icon == None)
  616.     if (file->sym_link)
  617.       icon = (XtArgVal) bm[EXECLNK_BM];
  618.     else
  619.       icon = (XtArgVal) bm[EXEC_BM];
  620.       icontype = 2;
  621.     }
  622.     else {
  623.       icon_toggle_args[3].value = (XtArgVal) file_translations;
  624.       file->type = fileType(file->name);
  625.       if (icon == None)
  626.         if (file->type)
  627.       icon = (XtArgVal) file->type->icon_bm;
  628.     else if (file->sym_link)
  629.       icon = (XtArgVal) bm[SYMLNK_BM];
  630.     else
  631.       icon = (XtArgVal) bm[FILE_BM];
  632.       icontype = 1;
  633.     }
  634.     icon_toggle_args[2].value = icon;
  635.  
  636.     file->icon.toggle = XtCreateManagedWidget(iconname[icontype],
  637.       toggleWidgetClass, file->icon.form, icon_toggle_args,
  638.       XtNumber(icon_toggle_args) );
  639.     
  640.     XtVaGetValues(file->icon.toggle, XtNbackground, &back, NULL);
  641.     XtVaSetValues(file->icon.toggle, XtNborder, (XtArgVal) back, NULL);
  642.  
  643.     icon_label_args[0].value = (XtArgVal) NULL;
  644.     icon_label_args[1].value = (XtArgVal) file->icon.toggle;
  645.     icon_label_args[2].value = (XtArgVal) file->name;
  646.     file->icon.label = XtCreateManagedWidget("label",
  647.       labelWidgetClass, file->icon.form, icon_label_args,
  648.       XtNumber(icon_label_args) );
  649.   }
  650. }
  651.  
  652. /*----------------------------------------------------------------------------*/
  653.  
  654. static void createTextDisplay(FileWindowRec *fw)
  655. {
  656.   int i, l;
  657.   Widget w;
  658.   Dimension width, m_width, name_w, size_w, perm_w, own_w = 0, date_w;
  659.   char s[10], name[FILENAME_MAX];
  660.   struct passwd *pw;
  661.   char **owners = NULL;
  662.   FileRec *file;
  663.  
  664.   XtVaGetValues(fw->viewport, XtNwidth, &width, NULL);
  665.   icon_box_args[0].value = (XtArgVal) width;
  666.  
  667.   m_width = XTextWidth(resources.icon_font, "m", 1);
  668.   name_w = longestName(fw) + 2*m_width;
  669.   size_w = m_width * 7;
  670.   perm_w = m_width * 9;
  671.   date_w = m_width * 20;
  672.   
  673.   if (resources.show_owner) {
  674.     owners = (char **) XtMalloc(fw->n_files * sizeof(char *));
  675.     own_w = 0;
  676.     for (i=0; i<fw->n_files; i++) { 
  677.       /* bug fixed by hkarhune@hydra.helsinki.fi - Thanks */
  678.       if((pw = getpwuid(fw->files[i]->stats.st_uid)) == NULL) {
  679.     char tmp[11];
  680.      
  681.     sprintf(tmp, "%d", fw->files[i]->stats.st_uid);
  682.     owners[i] = XtNewString(tmp);
  683.       }
  684.       else
  685.     owners[i] = XtNewString(pw->pw_name);
  686.       l = XTextWidth(resources.icon_font, owners[i], strlen(owners[i]));
  687.       if (l > own_w)
  688.     own_w = l;
  689.     }
  690.   }
  691.  
  692.   fw->icon_box = XtCreateWidget("icon box",  boxWidgetClass,
  693.                 fw->viewport, icon_box_args,
  694.                 XtNumber(icon_box_args) );
  695.  
  696.   for (i=0; i<fw->n_files; i++) {
  697.     Pixel pix;
  698.     
  699.     file = fw->files[i];
  700.     if (S_ISDIR(file->stats.st_mode)) {
  701.       sprintf(name, "[%s]", file->name);
  702.       text_toggle_args[2].value = (XtArgVal) name;
  703.       text_toggle_args[5].value = (XtArgVal) dir_translations;
  704.     }
  705.     else  {
  706.       text_toggle_args[2].value = (XtArgVal) file->name;
  707.       if (file->stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
  708.     text_toggle_args[5].value = (XtArgVal) exec_translations;
  709.       else
  710.     text_toggle_args[5].value = (XtArgVal) file_translations;
  711.     }
  712.  
  713.     file->icon.form = XtCreateManagedWidget(file->name,
  714.       formWidgetClass, fw->icon_box, icon_form_args,
  715.       XtNumber(icon_form_args) );
  716.  
  717.     text_toggle_args[0].value = (XtArgVal) NULL;
  718.     text_toggle_args[4].value = (XtArgVal) name_w;
  719.     w = file->icon.toggle = XtCreateManagedWidget("name", 
  720.       toggleWidgetClass, file->icon.form, text_toggle_args,
  721.       XtNumber(text_toggle_args) );
  722.  
  723.     XtVaGetValues(file->icon.toggle, file->selected?XtNforeground:
  724.           XtNbackground, &pix, NULL);
  725.     XtVaSetValues(file->icon.toggle, XtNborder, (XtArgVal) pix, NULL);
  726.  
  727.     if (resources.show_length) {
  728.       sprintf(s, "%ld", (long) file->stats.st_size);
  729.       text_label_args[0].value = (XtArgVal) w;
  730.       text_label_args[2].value = (XtArgVal) s;
  731.       text_label_args[4].value = (XtArgVal) size_w;
  732.       text_label_args[5].value = (XtArgVal) XtJustifyRight;
  733.       w = XtCreateManagedWidget("size", labelWidgetClass, 
  734.                 file->icon.form, text_label_args,
  735.                 XtNumber(text_label_args) );
  736.     }
  737.  
  738.     if (resources.show_owner) {
  739.       text_label_args[0].value = (XtArgVal) w;
  740.       text_label_args[2].value = (XtArgVal) owners[i];
  741.       text_label_args[4].value = (XtArgVal) own_w;
  742.       text_label_args[5].value = (XtArgVal) XtJustifyLeft;
  743.       w = XtCreateManagedWidget("owner", labelWidgetClass, 
  744.                 file->icon.form, text_label_args,
  745.                 XtNumber(text_label_args) );
  746.     }
  747.  
  748.     if (resources.show_perms) {
  749.       makePermissionsString(s, file->stats.st_mode);
  750.       text_label_args[0].value = (XtArgVal) w;
  751.       text_label_args[2].value = (XtArgVal) s;
  752.       text_label_args[4].value = (XtArgVal) perm_w;
  753.       text_label_args[5].value = (XtArgVal) XtJustifyLeft;
  754.       w = XtCreateManagedWidget("permissions", labelWidgetClass, 
  755.                 file->icon.form, text_label_args,
  756.                 XtNumber(text_label_args) );
  757.     }
  758.  
  759.     if (resources.show_date) {
  760.       text_label_args[0].value = (XtArgVal) w;
  761.       text_label_args[2].value = (XtArgVal)ctime(&file->stats.st_mtime);
  762.       text_label_args[4].value = (XtArgVal) date_w;
  763.       text_label_args[5].value = (XtArgVal) XtJustifyLeft;
  764.       w = XtCreateManagedWidget("date", labelWidgetClass, 
  765.                 file->icon.form, text_label_args,
  766.                 XtNumber(text_label_args) );
  767.     }
  768.   }
  769.  
  770.   if (resources.show_owner) {
  771.     for(i=0; i<fw->n_files; i++)
  772.       XTFREE(owners[i]);
  773.     XTFREE(owners);
  774.   }
  775. }
  776.  
  777.  
  778. /*----------------------------------------------------------------------------*/
  779.  
  780. /* create a directory icon in position specified by horiz & vert */
  781. static Widget createDirIcon(FileWindowRec *fw, int i, Widget horiz,Widget vert)
  782. {
  783.   FileRec *file = fw->files[i];
  784.   char *dirlabel;
  785.   Pixel back;
  786.  
  787.   /* create form */
  788.   tree_form_args[0].value = (XtArgVal) horiz;
  789.   tree_form_args[1].value = (XtArgVal) vert;
  790.   file->icon.form = XtCreateManagedWidget(file->name,
  791.     formWidgetClass, fw->icon_box, tree_form_args, XtNumber(tree_form_args) );
  792.  
  793.   /* create icon */
  794.   icon_toggle_args[0].value = (XtArgVal) NULL;
  795.   icon_toggle_args[1].value = (XtArgVal) NULL;
  796.   icon_toggle_args[2].value = (XtArgVal) bm[DIR_BM];
  797.   icon_toggle_args[3].value = (XtArgVal) tree_translations;
  798.   file->icon.toggle = XtCreateManagedWidget("icon",
  799.     toggleWidgetClass, file->icon.form, icon_toggle_args,
  800.     XtNumber(icon_toggle_args) );
  801.  
  802.   XtVaGetValues(file->icon.toggle, XtNbackground, &back, NULL);
  803.   XtVaSetValues(file->icon.toggle, XtNborder, (XtArgVal) back, NULL);
  804.  
  805.  
  806.   /* create label */
  807.   icon_label_args[0].value = (XtArgVal) NULL;
  808.   icon_label_args[1].value = (XtArgVal) file->icon.toggle;
  809.   if (i == 0)
  810.     dirlabel = fw->directory[1]?strrchr(fw->directory, '/')+1:fw->directory;
  811.   else
  812.     dirlabel = file->name;
  813.   icon_label_args[2].value = (XtArgVal)dirlabel;
  814.   file->icon.label = XtCreateManagedWidget("label",
  815.     labelWidgetClass, file->icon.form, icon_label_args,
  816.     XtNumber(icon_label_args) );
  817.  
  818.   return file->icon.form;
  819. }
  820.  
  821. /*----------------------------------------------------------------------------*/
  822.  
  823. /* create the icons for the directory display */
  824. static void createTreeDisplay(FileWindowRec *fw)
  825. {
  826.   int i;
  827.   Widget vert, horiz;
  828.   Pixmap line_bm;
  829.   Dimension width;
  830.   FileList files = fw->files;
  831.  
  832.   /* find width of icons */
  833.   width = longestName(fw);
  834.   if (width < resources.tree_icon_width)
  835.     width = resources.tree_icon_width;
  836.   tree_form_args[3].value = (XtArgVal) width;
  837.   icon_toggle_args[4].value = (XtArgVal) width;
  838.   icon_toggle_args[5].value = (XtArgVal) resources.tree_icon_height;
  839.   icon_label_args[4].value = (XtArgVal) width;
  840.  
  841.   /* create icon box in viewport */
  842.   XtVaGetValues(fw->viewport, XtNwidth, &width, NULL);
  843.   tree_box_args[0].value = (XtArgVal) width;
  844.   fw->icon_box = XtCreateWidget("icon box", formWidgetClass,
  845.     fw->viewport, tree_box_args, XtNumber(tree_box_args) );
  846.  
  847.   /* The '..' directory is not displayed, and no arrow for '.'  */
  848.   files[1]->icon.form = files[1]->icon.toggle = 
  849.     files[1]->icon.label = NULL;
  850.   files[0]->icon.arrow = NULL;
  851.     
  852.   /* create left arrow */
  853.   arrow_args[0].value = (XtArgVal) NULL;
  854.   arrow_args[1].value = (XtArgVal) NULL;
  855.   if (!permission(&files[1]->stats, P_EXECUTE)) {
  856.     arrow_args[2].value = bm[NOENTRY_CBM];
  857.     arrow_args[3].value = False;
  858.   }
  859.   else {
  860.     arrow_args[2].value = bm[LARROW_BM];
  861.     arrow_args[3].value = True;
  862.   }
  863.   horiz = files[1]->icon.arrow = XtCreateManagedWidget("left arrow",
  864.     commandWidgetClass, fw->icon_box, arrow_args, XtNumber(arrow_args) );
  865.   XtAddCallback(horiz, XtNcallback, (XtCallbackProc) mainArrowCb, fw);
  866.  
  867.   /* create current directory icon */
  868.   horiz = createDirIcon(fw, 0,  horiz, NULL);
  869.  
  870.   vert = NULL;
  871.  
  872.   for(i = 2; i < fw->n_files; i++, horiz = files[0]->icon.form) {
  873.     
  874.     /* create line */
  875.     if (i == 2)
  876.       if (fw->n_files == 3)
  877.     line_bm = bm[LLINE_BM];
  878.       else
  879.     line_bm = bm[TLINE_BM];
  880.     else
  881.       if (i == fw->n_files - 1)
  882.     line_bm = bm[CLINE_BM];
  883.       else
  884.     line_bm = bm[FLINE_BM];
  885.     line_args[0].value = (XtArgVal) horiz;
  886.     line_args[1].value = (XtArgVal) vert;
  887.     line_args[2].value = (XtArgVal) line_bm;
  888.     horiz  = XtCreateManagedWidget("line", labelWidgetClass, 
  889.       fw->icon_box, line_args, XtNumber(line_args) );
  890.     
  891.     /* create icon */
  892.     horiz = createDirIcon(fw, i, horiz, vert);
  893.     
  894.     /* create right arrow */
  895.     arrow_args[0].value = (XtArgVal) horiz;
  896.     arrow_args[1].value = (XtArgVal) vert;
  897.     if (!permission(&files[i]->stats, P_EXECUTE)) {
  898.       arrow_args[2].value = bm[NOENTRY_CBM];
  899.       arrow_args[3].value = False;
  900.     }
  901.     else if (files[i]->sym_link) {
  902.       arrow_args[2].value = bm[WAVY_BM];
  903.       arrow_args[3].value = True;
  904.     }
  905.     else {
  906.       arrow_args[2].value = bm[RARROW_BM];
  907.       arrow_args[3].value = True;
  908.     }
  909.     vert = files[i]->icon.arrow 
  910.       = XtCreateManagedWidget("right arrow", commandWidgetClass, fw->icon_box, 
  911.                   arrow_args, XtNumber(arrow_args) );
  912.     XtAddCallback(vert, XtNcallback, (XtCallbackProc) mainArrowCb, fw);
  913.   }
  914. }
  915.  
  916. /*-----------------------------------------------------------------------------
  917.   PUBLIC FUNCTIONS
  918. -----------------------------------------------------------------------------*/
  919.  
  920. /* find the device for a directory */
  921. int findDev(char *path)
  922. {
  923.   int d;
  924.  
  925.   for (d = 0; d < n_devices; d++)
  926.     if (prefix(devs[d].name, path))
  927.       return d;
  928.   return -1;
  929. }
  930.  
  931. /*---------------------------------------------------------------------------*/
  932. /* mount a device */
  933. void mountDev(int d)
  934. {
  935.   if (d == -1)
  936.     ;
  937.   else if (devs[d].mounted)
  938.     devs[d].mounted++;
  939.   else
  940.     devs[d].mounted += devAction(d, devs[d].mount_action);
  941. }
  942.  
  943. /*---------------------------------------------------------------------------*/
  944. /* unmount a device */
  945. void umountDev(int d)
  946. {
  947.   if (d == -1 || !devs[d].mounted)
  948.     ;
  949.   else if (devs[d].mounted > 1)
  950.     devs[d].mounted--;
  951.   else
  952.     devs[d].mounted -= devAction(d, devs[d].umount_action);
  953. }
  954.  
  955. /*---------------------------------------------------------------------------*/
  956. /* initialise the file Windows module */
  957. void initFileWindows()
  958. {
  959.   XtAppAddActions(app_context, file_actions, XtNumber(file_actions));
  960.   label_translations = XtParseTranslationTable(label_translations_s);
  961.   dir_translations = XtParseTranslationTable(dir_translations_s);
  962.   file_translations = XtParseTranslationTable(file_translations_s);
  963.   iconbox_translations = XtParseTranslationTable(iconbox_translations_s);
  964.   tree_translations = XtParseTranslationTable(tree_translations_s);
  965.   exec_translations = XtParseTranslationTable(exec_translations_s);
  966.  
  967.   icon_box_args[1].value = (XtArgVal) iconbox_translations;
  968.   label_args[9].value = (XtArgVal) label_translations;
  969.  
  970.   label_args[3].value = (XtArgVal) resources.label_font;
  971.   status_args[3].value = (XtArgVal) resources.status_font;
  972.   icon_label_args[3].value = (XtArgVal) resources.icon_font;
  973.   text_toggle_args[3].value = (XtArgVal) resources.icon_font;
  974.   text_label_args[3].value = (XtArgVal) resources.icon_font;
  975.   shell_args[1].value = (XtArgVal) bm[ICON_BM];
  976.   shell_args[2].value = (XtArgVal) bm[ICONMSK_BM];
  977.  
  978.   file_popup_items = createFloatingMenu("file popup", file_popup_menu,
  979.                     XtNumber(file_popup_menu), 4, aw.shell,
  980.                     NULL, &file_popup_widget);
  981.   XtRegisterGrabAction(filePopup, True, ButtonPressMask | ButtonReleaseMask,
  982.                GrabModeAsync, GrabModeAsync);
  983.   dir_popup_items = createFloatingMenu("dir popup", dir_popup_menu,
  984.                     XtNumber(dir_popup_menu), 4, aw.shell,
  985.                     NULL, &dir_popup_widget);
  986.   XtRegisterGrabAction(dirPopup, True, ButtonPressMask | ButtonReleaseMask,
  987.                GrabModeAsync, GrabModeAsync);
  988.   readFileTypes(resources.cfg_file);
  989.   readDevices(resources.dev_file);
  990. }
  991.  
  992. /*---------------------------------------------------------------------------*/
  993. /* Create a file Window at the specified path, in the specified format */
  994.  
  995. static FileWindowRec *createFileWindow(String path, String title, 
  996.                        DisplayType format)
  997. {
  998.   FileWindowRec *fw;
  999.   char *shell_name;
  1000.   
  1001. #ifdef DEBUG_MALLOC
  1002.   fprintf(stderr, "entering createFileWindow: %lu\n", malloc_inuse(NULL));
  1003. #endif
  1004.  
  1005.   if (chdir(path)) {
  1006.     sysError("Can't open folder:");
  1007.     return NULL;
  1008.   }
  1009.  
  1010.   /* put at front of linked list */
  1011.   fw = (FileWindowRec *) XtMalloc(sizeof(FileWindowRec));
  1012.   fw->next = file_windows;
  1013.   file_windows = fw;
  1014.   
  1015.   if (!getwd(fw->directory)) {
  1016.     sysError("Can't open folder:");
  1017.     return NULL;
  1018.   }
  1019.  
  1020.   /* set up defaults */
  1021.   fw->dev = -1;
  1022.   fw->display_type = format;
  1023.   fw->sort_type = resources.default_sort_type;
  1024.   fw->show_dirs = True;
  1025.   fw->show_hidden = False;
  1026.   fw->dirs_first = True;
  1027.   fw->n_selections = 0;
  1028.   fw->n_bytes_selected = 0;
  1029.   fw->unreadable = NULL;
  1030.   fw->files = NULL;
  1031.   fw->n_files = 0;
  1032.   fw->n_bytes = 0;
  1033.   fw->update = False;
  1034.  
  1035.   shell_name = "file window";
  1036.   shell_args[0].value = (XtArgVal) title;
  1037.   fw->shell = XtCreatePopupShell(shell_name, topLevelShellWidgetClass,
  1038.                  aw.shell, shell_args, XtNumber(shell_args) );
  1039.   if (resources.init_geometry)
  1040.     XtVaSetValues(fw->shell, XtNgeometry, resources.init_geometry, NULL);
  1041.   
  1042.   /* create form */
  1043.   fw->form = XtCreateManagedWidget("form", formWidgetClass, fw->shell,
  1044.                    form_args, XtNumber(form_args) );
  1045.   
  1046.   /* create button box */
  1047.   fw->button_box = XtCreateManagedWidget("button box", boxWidgetClass,
  1048.                      fw->form, button_box_args, 
  1049.                      XtNumber(button_box_args) );
  1050.   
  1051.   /* create the menus */
  1052.   fw->file_items = createMenu("file", "File", file_menu, XtNumber(file_menu),
  1053.                   4, fw->button_box, (XtPointer) fw);
  1054.   fw->folder_items = createMenu("folder", "Folder", folder_menu, 
  1055.                 XtNumber(folder_menu), 4, fw->button_box,
  1056.                 (XtPointer) fw);
  1057.   fw->view_items = createMenu("view", "View", view_menu, XtNumber(view_menu),
  1058.                   16, fw->button_box, (XtPointer) fw);
  1059.  
  1060.   /* create folder label */
  1061.   label_args[0].value = (XtArgVal) fw->button_box;
  1062.   label_args[1].value = (XtArgVal) fw->directory;
  1063.   fw->label = XtCreateManagedWidget("label", labelWidgetClass, fw->form,
  1064.                     label_args, XtNumber(label_args) );
  1065.   
  1066.   /* create viewport */
  1067.   viewport_args[0].value = (XtArgVal) fw->label;
  1068.   fw->viewport = XtCreateManagedWidget("viewport", viewportWidgetClass,
  1069.                        fw->form, viewport_args, 
  1070.                        XtNumber(viewport_args) );
  1071.  
  1072.   /* create status line */
  1073.   status_args[0].value = (XtArgVal) fw->viewport;
  1074.   status_args[1].value = (XtArgVal) "";
  1075.   fw->status = XtCreateManagedWidget("status", labelWidgetClass, fw->form,
  1076.                      status_args, XtNumber(status_args) );
  1077.   
  1078. #ifdef DEBUG_MALLOC
  1079.   fprintf(stderr, "exiting createFileWindow: %lu\n", malloc_inuse(NULL));
  1080. #endif
  1081.  
  1082.   return fw;
  1083. }
  1084.  
  1085. /*----------------------------------------------------------------------------*/
  1086.  
  1087. void newFileWindow(String path, DisplayType d, Boolean by_cursor)
  1088. {
  1089.   FileWindowRec *fw;
  1090.  
  1091. #ifdef DEBUG_MALLOC
  1092.   fprintf(stderr, "entering newFileWindow: %lu\n", malloc_inuse(NULL));
  1093. #endif
  1094.  
  1095.   if (!(fw = createFileWindow(path, "File Manager", d)))
  1096.     return;
  1097.   createFileDisplay(fw);
  1098.   XtRealizeWidget(fw->shell);
  1099.   XSetIconName(XtDisplay(fw->shell), XtWindow(fw->shell), fw->directory);
  1100.   XSetWMProtocols(XtDisplay(fw->shell), XtWindow(fw->shell),
  1101.             &wm_delete_window, 1);
  1102.   XtAddEventHandler(fw->shell, (EventMask)0L, True,
  1103.             (XtEventHandler)clientMessageHandler, (XtPointer)NULL);
  1104.   if (by_cursor)
  1105.     popupByCursor(fw->shell, XtGrabNone);
  1106.   else
  1107.     XtPopup(fw->shell, XtGrabNone);
  1108.  
  1109. #ifdef DEBUG_MALLOC
  1110.   fprintf(stderr, "exiting newFileWindow: %lu\n", malloc_inuse(NULL));
  1111. #endif
  1112. }
  1113.  
  1114. /*---------------------------------------------------------------------------*/
  1115.  
  1116. /* Main procedure to create the display in the viewport */
  1117. void createFileDisplay(FileWindowRec *fw)
  1118. {
  1119.   int i;
  1120.  
  1121. #ifdef DEBUG_MALLOC
  1122.   fprintf(stderr, "entering createFileDisplay: %lu\n", malloc_inuse(NULL));
  1123. #endif
  1124.  
  1125.   XtVaSetValues(fw->label, XtNlabel, (XtArgVal) fw->directory, NULL);
  1126.  
  1127.   fw->icon_box = NULL;
  1128.  
  1129.   if (fw->unreadable) {
  1130.     XtDestroyWidget(fw->unreadable);
  1131.     fw->unreadable = NULL;
  1132.   }
  1133.  
  1134.   if (!readDirectory(fw)) {
  1135.     fw->unreadable = 
  1136.       XtVaCreateManagedWidget("label", labelWidgetClass, fw->viewport,
  1137.                   XtNlabel, "Directory is unreadable",
  1138.                   XtNfont, resources.label_font, NULL);
  1139.     return;
  1140.   }
  1141.  
  1142.   for (i=0; i<fw->n_files; i++)
  1143.     fw->files[i]->selected = False;
  1144.   fw->n_selections = 0;
  1145.   fw->n_bytes_selected = 0;
  1146.  
  1147.   switch (fw->display_type) {
  1148.   case Tree:
  1149.     filterDirectory(fw, Directories);
  1150.     sortDirectory(fw->files+2, fw->n_files-2, fw->sort_type, False);
  1151.     createTreeDisplay(fw);
  1152.     break;
  1153.   case Icons:
  1154.     filterDirectory(fw, fw->show_dirs ? All : Files);
  1155.     sortDirectory(fw->files, fw->n_files, fw->sort_type, fw->dirs_first);
  1156.     createFileIcons(fw);
  1157.     break;
  1158.   case Text:
  1159.     filterDirectory(fw, fw->show_dirs ? All : Files);
  1160.     sortDirectory(fw->files, fw->n_files, fw->sort_type, fw->dirs_first);
  1161.     createTextDisplay(fw);
  1162.     break;
  1163.   }
  1164.  
  1165.   updateStatus(fw);
  1166.  
  1167.   XtManageChild(fw->icon_box);
  1168.  
  1169. #ifdef DEBUG_MALLOC
  1170.   fprintf(stderr, "exiting createFileDisplay: %lu\n", malloc_inuse(NULL));
  1171. #endif
  1172. }
  1173.  
  1174. /*---------------------------------------------------------------------------*/
  1175.  
  1176. /* Update the display in the viewport */
  1177. void updateFileDisplay(FileWindowRec *fw)
  1178. {
  1179.   int d;
  1180.  
  1181. #ifdef DEBUG_MALLOC
  1182.   fprintf(stderr, "entering updateFileDisplay: %lu\n", malloc_inuse(NULL));
  1183. #endif
  1184.  
  1185.   zzz();
  1186.  
  1187.   d = fw->dev;
  1188.  
  1189.   if (fw->icon_box)
  1190.     XtDestroyWidget(fw->icon_box);
  1191.  
  1192.   freeFileList(fw);
  1193.   createFileDisplay(fw);
  1194.  
  1195.   if (d != -1) umountDev(d);
  1196.  
  1197.   XSetIconName(XtDisplay(fw->shell), XtWindow(fw->shell), fw->directory);
  1198.  
  1199.   wakeUp();
  1200.  
  1201. #ifdef DEBUG_MALLOC
  1202.   fprintf(stderr, "exiting updateFileDisplay: %lu\n", malloc_inuse(NULL));
  1203. #endif
  1204. }
  1205.  
  1206. /*---------------------------------------------------------------------------*/
  1207.  
  1208. /* resort the icons in the display */
  1209. void reSortFileDisplay(FileWindowRec *fw)
  1210. {
  1211. #ifdef DEBUG_MALLOC
  1212.   fprintf(stderr, "entering resortFileDisplay: %lu\n", malloc_inuse(NULL));
  1213. #endif
  1214.  
  1215.   if (fw->unreadable)
  1216.     return;
  1217.  
  1218.   zzz();
  1219.  
  1220.   XtDestroyWidget(fw->icon_box);
  1221.   fw->n_selections = 0;
  1222.   fw->n_bytes_selected = 0;
  1223.  
  1224.   switch (fw->display_type) {
  1225.   case Tree:
  1226.     sortDirectory(fw->files+2, fw->n_files-2, fw->sort_type, False);
  1227.     createTreeDisplay(fw);
  1228.     break;
  1229.   case Icons:
  1230.     sortDirectory(fw->files, fw->n_files, fw->sort_type, fw->dirs_first);
  1231.     createFileIcons(fw);
  1232.     break;
  1233.   case Text:
  1234.     sortDirectory(fw->files, fw->n_files, fw->sort_type, fw->dirs_first);
  1235.     createTextDisplay(fw);
  1236.     break;
  1237.   }
  1238.  
  1239.   updateStatus(fw);
  1240.   XtManageChild(fw->icon_box);
  1241.  
  1242.   wakeUp();
  1243.  
  1244. #ifdef DEBUG_MALLOC
  1245.   fprintf(stderr, "exiting resortFileDisplay: %lu\n", malloc_inuse(NULL));
  1246. #endif
  1247. }
  1248.  
  1249. /*---------------------------------------------------------------------------*/
  1250.  
  1251. void reDisplayFileWindow(FileWindowRec *fw)
  1252. {
  1253. #ifdef DEBUG_MALLOC
  1254.   fprintf(stderr, "entering redisplayFileWindow: %lu\n", malloc_inuse(NULL));
  1255. #endif
  1256.  
  1257.   if (fw->unreadable)
  1258.     return;
  1259.  
  1260.   zzz();
  1261.  
  1262.   XtDestroyWidget(fw->icon_box);
  1263.  
  1264.   switch (fw->display_type) {
  1265.   case Tree:
  1266.     createTreeDisplay(fw);
  1267.     break;
  1268.   case Icons:
  1269.     createFileIcons(fw);
  1270.     break;
  1271.   case Text:
  1272.     createTextDisplay(fw);
  1273.     break;
  1274.   }
  1275.  
  1276.   updateStatus(fw);
  1277.   XtManageChild(fw->icon_box);
  1278.  
  1279.   wakeUp();
  1280.  
  1281. #ifdef DEBUG_MALLOC
  1282.   fprintf(stderr, "exiting redisplayFileWindow: %lu\n", malloc_inuse(NULL));
  1283. #endif
  1284. }
  1285.  
  1286. /*----------------------------------------------------------------------------
  1287.   Intelligent update - only update the windows needed.
  1288.   Use markForUpdate() to explicitly mark a directory for update.
  1289.   Call intUpdate to execute all the actions.
  1290. -----------------------------------------------------------------------------*/
  1291. void markForUpdate(String path)
  1292. {
  1293.   FileWindowRec *fw;
  1294.  
  1295.   for (fw = file_windows; fw; fw = fw->next)
  1296.     if (!strcmp(path, fw->directory))
  1297.       fw->update = True;
  1298. }
  1299.  
  1300. void intUpdate()
  1301. {
  1302.   FileWindowRec *fw;
  1303.   struct stat cur;
  1304.  
  1305.   for (fw = file_windows; fw; fw = fw->next) {
  1306.     if (fw->update ||
  1307.     stat(fw->directory, &cur) ||
  1308.     cur.st_ctime > fw->stats.st_ctime)
  1309.       updateFileDisplay(fw);
  1310.   }
  1311.  
  1312.   for (fw = file_windows; fw; fw = fw->next)
  1313.     fw->update = False;
  1314. }
  1315.  
  1316. /*-----------------------------------------------------------------------------
  1317.   Keep menus and status line consistent with the number of selections in each
  1318.   window. Currently this must be called manually, which is bad news.
  1319. -----------------------------------------------------------------------------*/
  1320. void updateStatus(FileWindowRec *fw)
  1321. {
  1322.   char s[1024];
  1323.   int n_files, n_selections;
  1324.   long n_bytes, n_bytes_selected;
  1325.  
  1326.   if (fw->n_selections >= 1) {
  1327.     fillIn(fw->file_items[2]);
  1328.     fillIn(fw->file_items[3]);
  1329.     fillIn(fw->file_items[6]);
  1330.     fillIn(fw->file_items[10]);
  1331.   }else {
  1332.     grayOut(fw->file_items[2]);
  1333.     grayOut(fw->file_items[3]);
  1334.     grayOut(fw->file_items[6]);
  1335.     grayOut(fw->file_items[10]);
  1336.   }
  1337.  
  1338.   if (fw->display_type == Tree) {
  1339.     grayOut(fw->view_items[8]);
  1340.     grayOut(fw->view_items[9]);
  1341.     noTick(fw->view_items[8]);
  1342.     noTick(fw->view_items[9]);
  1343.   }
  1344.   else {
  1345.     fillIn(fw->view_items[8]);
  1346.     if (fw->show_dirs) {
  1347.       fillIn(fw->view_items[9]);
  1348.       noTick(fw->view_items[8]);
  1349.       if (fw->dirs_first)
  1350.     noTick(fw->view_items[9]);
  1351.       else
  1352.     tick(fw->view_items[9]);
  1353.     }
  1354.     else {
  1355.       grayOut(fw->view_items[9]);
  1356.       tick(fw->view_items[8]);
  1357.       noTick(fw->view_items[9]);
  1358.     }
  1359.   }
  1360.  
  1361.   if (fw->show_hidden)
  1362.     tick(fw->view_items[10]);
  1363.   else
  1364.     noTick(fw->view_items[10]);
  1365.  
  1366.   noTick(fw->view_items[0]);
  1367.   noTick(fw->view_items[1]);
  1368.   noTick(fw->view_items[2]);
  1369.   noTick(fw->view_items[4]);
  1370.   noTick(fw->view_items[5]);
  1371.   noTick(fw->view_items[6]);
  1372.  
  1373.   switch (fw->display_type) {
  1374.   case Tree:
  1375.     tick(fw->view_items[0]);
  1376.     break;
  1377.   case Icons:
  1378.     tick(fw->view_items[1]);
  1379.     break;
  1380.   case Text:
  1381.     tick(fw->view_items[2]);
  1382.     break;
  1383.   }
  1384.  
  1385.   switch (fw->sort_type) {
  1386.   case SortByName:
  1387.     tick(fw->view_items[4]);
  1388.     break;
  1389.   case SortBySize:
  1390.     tick(fw->view_items[5]);
  1391.     break;
  1392.   case SortByMTime:
  1393.     tick(fw->view_items[6]);
  1394.     break;
  1395.   }
  1396.  
  1397.   /* update the status line */
  1398.  
  1399.   n_bytes = fw->n_bytes;
  1400.   n_files = fw->n_files;
  1401.   n_bytes_selected = fw->n_bytes_selected;
  1402.   n_selections = fw->n_selections;
  1403.  
  1404.   if (fw->display_type == Tree) {
  1405.     n_bytes -= fw->files[1]->stats.st_size;
  1406.     n_files--;
  1407.   }
  1408.  
  1409.   if (n_selections > 0)
  1410.     sprintf(s,
  1411.     "%ld byte%s in %d item%s, %ld byte%s in %d selected item%s",
  1412.     n_bytes, n_bytes==1?"":"s",
  1413.     n_files, n_files==1?"":"s",
  1414.     n_bytes_selected, n_bytes_selected==1?"":"s",
  1415.     n_selections, n_selections==1?"":"s");
  1416.   else
  1417.     sprintf(s, "%ld byte%s in %d item%s", n_bytes, n_bytes==1?"":"s",
  1418.     n_files, n_files==1?"":"s");
  1419.  
  1420.   XtVaSetValues(fw->status, XtNlabel, (XtArgVal) s, NULL);
  1421. }
  1422.