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