home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / xview / guidexv / gfm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  19.4 KB  |  762 lines

  1. /*
  2.  * This file is a product of Sun Microsystems, Inc. and is provided for
  3.  * unrestricted use provided that this legend is included on all tape
  4.  * media and as a part of the software program in whole or part.  Users
  5.  * may copy or modify this file without charge, but are not authorized to
  6.  * license or distribute it to anyone else except as part of a product
  7.  * or program developed by the user.
  8.  *
  9.  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12.  *
  13.  * This file is provided with no support and without any obligation on the
  14.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  15.  * modification or enhancement.
  16.  *
  17.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
  19.  * OR ANY PART THEREOF.
  20.  *
  21.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22.  * or profits or other special, indirect and consequential damages, even
  23.  * if Sun has been advised of the possibility of such damages.
  24.  *
  25.  * Sun Microsystems, Inc.
  26.  * 2550 Garcia Avenue
  27.  * Mountain View, California  94043
  28.  */
  29.  
  30. #ifndef lint
  31. static char    sccsid[] = "@(#)gfm.c    2.30 91/10/15 Copyright 1990 Sun Microsystems";
  32. #endif
  33.  
  34. /*
  35.  * gfm.c - Notify and event callback function stubs.
  36.  * This file was generated by `gxv' from `gfm.G'.
  37.  */
  38.  
  39. #include <stdio.h>
  40. #include <fcntl.h>
  41. #include <errno.h>
  42. #include <string.h>
  43. #include <malloc.h>
  44. #include <sys/param.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include <sys/time.h>
  48. #include <xview/xview.h>
  49. #include <xview/font.h>
  50. #include <xview/defaults.h>
  51. #include <xview/frame.h>
  52. #include <xview/panel.h>
  53. #include <xview/notify.h>
  54. #include <X11/Xutil.h>
  55. #include <group.h>
  56. #include "gfm.h"
  57.  
  58. #ifdef __STDC__
  59. extern char        *getcwd();
  60. #else
  61. extern char        *getwd();
  62. #endif
  63. extern void        expand_path();
  64. extern Server_image    Gfm_document_glyph;
  65.  
  66. extern void        gfm_load_dir();
  67. extern void        gfm_initialize_glyphs();
  68.  
  69. static int        Gfm_multiclick_timeout;
  70. static void        gfm_notify_client();
  71. static int        double_click();
  72.  
  73. #define    STRCMP(s1, s2)    (strcmp(s1 ? s1 : "", s2 ? s2 : ""))
  74.  
  75. /*
  76.  * Initialize the gfm popup window with a title.
  77.  *
  78.  * Arguments:
  79.  *    ip        An instance pointer to a file chooser, NULL means
  80.  *            create a new one from scratch
  81.  *    owner        The XView window to parent the file chooser off of
  82.  *    title        String containing initial frame title
  83.  *
  84.  * Returns:
  85.  *    NULL if okay
  86.  *    String containing error if error occurred
  87.  */
  88. gfm_popup_objects *
  89. #ifdef __STDC__
  90. gfm_initialize(gfm_popup_objects *ip, Xv_opaque owner, char *title)
  91. #else
  92. gfm_initialize(ip, owner, title)
  93.     gfm_popup_objects    *ip;
  94.     Xv_opaque        owner;
  95.     char            *title;
  96. #endif
  97. {
  98.     int        char_width;
  99.     int        row_height;
  100.     int        excess;
  101.     int        min_width;
  102.     int        min_height;
  103.     long        supplied;
  104.     Rect        *screen_rect;
  105.     XSizeHints    wmhints;
  106.     GFM_PRIVATE    *gfm_private;
  107.  
  108.     if (!ip && !(ip = gfm_popup_objects_initialize(ip, owner)))
  109.         return NULL;
  110.  
  111.     /*
  112.      * Set up glyphs
  113.      */
  114.     gfm_initialize_glyphs();
  115.  
  116.     xv_set(ip->controls, PANEL_DEFAULT_ITEM, ip->load, NULL);
  117.  
  118.     /*
  119.      * Allocate space for our private stash of data, fill it
  120.      * in with all the necessary information, then store it away
  121.      * in key data under the window.
  122.      */
  123.     gfm_private = (GFM_PRIVATE *) calloc(1, sizeof(GFM_PRIVATE));
  124.     gfm_private->height = (int)xv_get(ip->popup, XV_HEIGHT);
  125.     gfm_private->width = (int)xv_get(ip->popup, XV_WIDTH);
  126.     gfm_private->initial_win_height = gfm_private->height;
  127.     gfm_private->initial_list_height = (int)xv_get(ip->list, XV_HEIGHT);
  128.     gfm_private->initial_list_excess = gfm_private->initial_list_height -
  129.         (xv_get(ip->list, PANEL_LIST_ROW_HEIGHT) *
  130.          xv_get(ip->list, PANEL_LIST_DISPLAY_ROWS));
  131.     xv_set(ip->popup, XV_KEY_DATA, GFM_KEY, gfm_private, NULL);
  132.  
  133.     Gfm_multiclick_timeout =
  134.         defaults_get_integer("openwindows.multiclicktimeout",
  135.                      "OpenWindows.MultiClickTimeout", 4);
  136.  
  137.     /*
  138.      * Set the minimum allowable size for the window.  The minimum
  139.      * size for the list determines the overall minimum.  The smallest
  140.      * size is around 8 characters wide by 5 rows.  For the width we must
  141.      * take into account the width of the glyph and the border spacing.
  142.      */
  143.     XGetWMNormalHints((Display *)xv_get(ip->popup, XV_DISPLAY),
  144.               (Window) xv_get(ip->popup, XV_XID),
  145.               &wmhints, &supplied);
  146.  
  147.     row_height = (int)xv_get(ip->list, PANEL_LIST_ROW_HEIGHT);
  148.     excess = gfm_private->initial_list_height - 
  149.         (xv_get(ip->list, PANEL_LIST_DISPLAY_ROWS) * row_height);
  150.     min_height = xv_get(ip->controls, XV_HEIGHT) -
  151.         gfm_private->initial_list_height +
  152.             ((6 * row_height) + excess);
  153.  
  154.     char_width = xv_get(xv_get(ip->controls, XV_FONT), FONT_DEFAULT_CHAR_WIDTH );
  155.     excess = xv_get(xv_get(ip->list, PANEL_LIST_SCROLLBAR), XV_WIDTH);
  156.     min_width = 56 + (8 * char_width) + excess;
  157.  
  158.     wmhints.flags |= PMinSize;
  159.     wmhints.min_width = min_width;
  160.     wmhints.min_height = min_height;
  161.     XSetWMNormalHints((Display *)xv_get(ip->popup, XV_DISPLAY),
  162.               (Window) xv_get(ip->popup, XV_XID), &wmhints);
  163.  
  164.     /*
  165.      * Set the initial title, directory, and file
  166.      */
  167.     xv_set(ip->popup, XV_LABEL, title, NULL);
  168.     xv_set(ip->directory, PANEL_VALUE, "", NULL);
  169.     xv_set(ip->file, PANEL_VALUE, "", NULL);
  170.  
  171.     /*
  172.      * Initially position in center of screen
  173.      * XXX - need to use new window positioning functions here!
  174.      */
  175.     screen_rect = (Rect *)xv_get(ip->popup, WIN_SCREEN_RECT);
  176.     xv_set(ip->popup,
  177.            XV_X, screen_rect->r_width/2 - gfm_private->width/2,
  178.            XV_Y, screen_rect->r_height/2 - gfm_private->height/2,
  179.            NULL);
  180.  
  181.     return ip;
  182. }
  183.  
  184. /*
  185.  * Show/don't show "." files
  186.  */
  187. void
  188. #ifdef __STDC__
  189. gfm_show_dotfiles(gfm_popup_objects *ip, int flag)
  190. #else
  191. gfm_show_dotfiles(ip, flag)
  192.     gfm_popup_objects *ip;
  193.     int          flag;
  194. #endif
  195. {
  196.     GFM_PRIVATE      *gfm_private;
  197.  
  198.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  199.     gfm_private->show_dotfiles = flag;
  200. }
  201.  
  202. /*
  203.  * Change the label on the action button
  204.  */
  205. void
  206. #ifdef __STDC__
  207. gfm_set_action(gfm_popup_objects *ip, char *label)
  208. #else
  209. gfm_set_action(ip, label)
  210.     gfm_popup_objects *ip;
  211.     char    *label;
  212. #endif
  213. {
  214.     xv_set(ip->load, PANEL_LABEL_STRING, label, NULL);
  215.     xv_set(ip->props_group, GROUP_LAYOUT, TRUE, NULL);
  216.     panel_paint(ip->controls, PANEL_NO_CLEAR);
  217. }
  218.  
  219. /*
  220.  * Activate the file chooser
  221.  *
  222.  * gfm_activate is called from within a callback procedure written by the
  223.  * client.  For example, the application might have a "Load..." button.
  224.  * This button's notify handler would call gfm_activate to have the file
  225.  * chooser appear when that button is pushed.
  226.  *
  227.  * Arguments:
  228.  *
  229.  *    ip        is an instance pointer to the particular file
  230.  *            chooser that you would like to activate.  This
  231.  *            is returned from gfm_initialize().
  232.  *
  233.  *    directory    is a string containing the directory that the client
  234.  *            would like gfm to start up in.  If NULL is passed in
  235.  *            the current working directory is used.  The current
  236.  *            working directory is never changed even when the user
  237.  *             changes directories.
  238.  *
  239.  *    filter_pat    is a string containing a regular expression that will
  240.  *            match the files the client program would like to show
  241.  *            the user.  If NULL is passed int then all files are
  242.  *            considered for the next test- the magic number stuff.
  243.  *            Otherwise only those files that matched the regular
  244.  *            expression will be considered to match the magic number
  245.  *            test.
  246.  *
  247.  *    filter_callback    is a pointer to a function that will be called back
  248.  *            for every file in a directory.  If the callbacks
  249.  *            returns TRUE then the file will be included in 
  250.  *            the list, return FALSE and the file will not be
  251.  *            in the scrollng list.  If filter_pat is also
  252.  *            specified, gfm will filter files against the filter
  253.  *            pattern first, then call filter_callback for any
  254.  *            remaining files.
  255.  *
  256.  *    callback    is a pointer to the procedure that should be called
  257.  *            when the user pushes select or doubleclicks on the file
  258.  *            that they wish to choose. callback is passed the file
  259.  *            and directory that were selected.
  260.  *            If no callback is passed in then NOTHING HAPPENS;
  261.  *            gfm_activate will just return.
  262.  *
  263.  *    glyph        is a pointer to a Server_image.  This is only used in
  264.  *            conjunction with the filters.  If there is a filter
  265.  *            then all non-directories that match the tests will
  266.  *            be shown with this glyph.  If no glyph is specified, the
  267.  *            default is Gfm_document_glyph.
  268.  *
  269.  *    mode        is a flag to tell gfm what label it should use for its
  270.  *            action button.
  271.  *                GFM_LOAD sets the label to "Load"
  272.  *                GFM_SAVE set the label to "Save"
  273.  *                GFM_CREATE set the label to "Create"
  274.  *                GFM_DEFAULT leaves the label alone
  275.  */
  276. void
  277. #ifdef __STDC__
  278. gfm_activate(gfm_popup_objects *ip, char *directory, char *filter_pat,
  279.          int (*filter_callback)(), int (*callback)(),
  280.          Xv_opaque glyph, GFM_MODE mode)
  281. #else
  282. gfm_activate(ip, directory, filter_pat, filter_callback, callback, glyph, mode)
  283.     gfm_popup_objects    *ip;
  284.     char            *directory;
  285.     char            *filter_pat;
  286.     int            (*filter_callback)();
  287.     int            (*callback)();
  288.     Xv_opaque        glyph;
  289.     GFM_MODE        mode;
  290. #endif
  291. {
  292.     char        *current_dir;
  293.     char        new_dir[MAXPATHLEN + 1];
  294.     GFM_PRIVATE    *gfm_private;
  295.  
  296.     /*
  297.      * Check to see if this is a valid file chooser
  298.      */
  299.     if (!ip)
  300.     {
  301.         fprintf(stderr, dgettext("libguidexv",
  302.                      "gfm: No file chooser to activate\n"));
  303.         return;
  304.     }
  305.  
  306.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  307.  
  308.     current_dir = (char *)xv_get(ip->directory, PANEL_VALUE);
  309.  
  310.     if (directory && *directory)
  311.         strcpy(new_dir, directory);
  312.     else if (current_dir && *current_dir)
  313.         strcpy(new_dir, current_dir);
  314.     else
  315. #ifdef __STDC__
  316.         if (!getcwd(new_dir, MAXPATHLEN+1))
  317. #else
  318.         if (!getwd(new_dir))
  319. #endif
  320.         {
  321.             fprintf(stderr, dgettext("libguidexv",
  322.                  "gfm: Could not read current directory; using \"/\" instead\n"));
  323.             strcpy(new_dir, "/");
  324.         }
  325.  
  326.  
  327.     /*
  328.      * Check to see if filter pattern has changed.  If so,
  329.      * store it away and mark the directory listing invalid.
  330.      */
  331.     if (STRCMP(filter_pat, gfm_private->filter_pattern) != 0)
  332.     {
  333.         if (gfm_private->filter_pattern)
  334.             free(gfm_private->filter_pattern);
  335.  
  336.         gfm_private->dir_mtime = 0;
  337.  
  338.         if (filter_pat && *filter_pat)
  339.             gfm_private->filter_pattern = strdup(filter_pat);
  340.         else
  341.             gfm_private->filter_pattern = NULL;
  342.     }
  343.  
  344.     gfm_private->filter_callback = filter_callback;
  345.  
  346.     /*
  347.      * Must specify callback, otherwise file choose is worthless
  348.      */
  349.     if (!callback)
  350.     {
  351.         fprintf(stderr, dgettext("libguidexv",
  352.                      "gfm: No callback procedure specified - file chooser not activated\n"));
  353.         return;
  354.     } else
  355.         gfm_private->callback = callback;
  356.  
  357.     /*
  358.      * If no glyph was specified, use the default (Gfm_document_glyph)
  359.      */
  360.     gfm_private->user_glyph = glyph ? glyph : Gfm_document_glyph;
  361.     gfm_private->mode = mode;
  362.  
  363.     switch (mode)
  364.     {
  365.     case GFM_LOAD:
  366.         gfm_set_action(ip, dgettext("libguidexv", "Load"));
  367.         break;
  368.     case GFM_SAVE:
  369.         gfm_set_action(ip, dgettext("libguidexv", "Save"));
  370.         break;
  371.     case GFM_CREATE:
  372.         gfm_set_action(ip, dgettext("libguidexv", "Create"));
  373.         break;
  374.     case GFM_DEFAULT:
  375.     default:
  376.         break;
  377.     }
  378.  
  379.     xv_set(ip->popup, XV_SHOW, TRUE, NULL);
  380.     XFlush(XV_DISPLAY_FROM_WINDOW(ip->popup));
  381.  
  382.     gfm_load_dir(ip, new_dir);
  383. }
  384.  
  385. /*
  386.  * Notify callback function for `list'.
  387.  */
  388. int
  389. #ifdef __STDC__
  390. gfm_list_proc(Panel_item item, char *string, Xv_opaque client_data,
  391.           Panel_list_op op, Event *event)
  392. #else
  393. gfm_list_proc(item, string, client_data, op, event)
  394.     Panel_item    item;
  395.     char        *string;
  396.     Xv_opaque    client_data;
  397.     Panel_list_op    op;
  398.     Event        *event;
  399. #endif
  400. {
  401.     static Xv_opaque    last_sel = NULL;
  402.     static struct timeval    then = {0, 0};
  403.     static struct timeval    now = {0, 0};
  404.     gfm_popup_objects *ip = (gfm_popup_objects *) xv_get(item, XV_KEY_DATA,
  405.                                  INSTANCE);
  406.  
  407.     switch (op)
  408.     {
  409.     case PANEL_LIST_OP_SELECT:
  410.         xv_set(ip->list,
  411.                PANEL_PAINT, PANEL_NONE,
  412.                PANEL_CLIENT_DATA, client_data,
  413.                NULL);
  414.  
  415.         if (strcmp(GFM_DOTDOT_STR, string) == 0)
  416.             xv_set(ip->file, PANEL_VALUE, "..", NULL);
  417.         else
  418.             xv_set(ip->file, PANEL_VALUE, string, NULL);
  419.         now = event_time(event);
  420.  
  421.         /*
  422.          * Check for double click, open directory or file
  423.          */
  424.         if (double_click(last_sel, &then, client_data, &now))
  425.         {
  426.             if ((client_data & GFM_TYPE_MASK) == GFM_FOLDER)
  427.             {
  428.                 if (strcmp(string, GFM_DOTDOT_STR) == 0)
  429.                     gfm_load_dir(ip, "..");
  430.                 else
  431.                     gfm_load_dir(ip, string);
  432.             }
  433.             else
  434.             {
  435.                 xv_set(ip->file, PANEL_VALUE, string, NULL);
  436.                 gfm_notify_client(ip);
  437.             }
  438.         }
  439.         last_sel = client_data;
  440.         then = now;
  441.         break;
  442.  
  443.     case PANEL_LIST_OP_DESELECT:
  444.         break;
  445.  
  446.     case PANEL_LIST_OP_VALIDATE:
  447.         return XV_ERROR;
  448.  
  449.     case PANEL_LIST_OP_DELETE:
  450.         break;
  451.     }
  452.  
  453.     return XV_OK;
  454. }
  455.  
  456. /*
  457.  * Notify callback function for `file'.
  458.  */
  459. Panel_setting
  460. #ifdef __STDC__
  461. gfm_file_notify(Panel_item item, Event *event)
  462. #else
  463. gfm_file_notify(item, event)
  464.     Panel_item    item;
  465.     Event        *event;
  466. #endif
  467. {
  468.     char            *file;
  469.     gfm_popup_objects *ip = (gfm_popup_objects *) xv_get(item, XV_KEY_DATA,
  470.                                  INSTANCE);
  471.  
  472.     file = (char *)xv_get(ip->file, PANEL_VALUE);
  473.  
  474.     if (!file || !*file)
  475.         return panel_text_notify(item, event);
  476.  
  477.     gfm_load_dir(ip, file);
  478.  
  479.     file = (char *)xv_get(ip->file, PANEL_VALUE);
  480.  
  481.     if (file && *file)
  482.     {
  483.         gfm_notify_client(ip);
  484.         return PANEL_NONE;
  485.     }
  486.  
  487.     return PANEL_NONE;
  488.     /*
  489.      * return panel_text_notify(item, event);
  490.      */
  491. }
  492.  
  493. /*
  494.  * Notify callback function for `open'.
  495.  */
  496. void
  497. /* ARGSUSED */
  498. #ifdef __STDC__
  499. gfm_open(Panel_item item, Event *event)
  500. #else
  501. gfm_open(item, event)
  502.     Panel_item    item;
  503.     Event        *event;
  504. #endif
  505. {
  506.     int          i;
  507.     char          *file;
  508.     gfm_popup_objects *ip = (gfm_popup_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  509.  
  510.     xv_set(item, PANEL_NOTIFY_STATUS, XV_ERROR, NULL);
  511.     file = (char *)xv_get(ip->file, PANEL_VALUE);
  512.  
  513.     if (!file || !*file)
  514.     {
  515.         for (i = 0; i < xv_get(ip->list, PANEL_LIST_NROWS); i++)
  516.             if (xv_get(ip->list, PANEL_LIST_SELECTED, i))
  517.                 break;
  518.  
  519.         file = (char *) xv_get(ip->list, PANEL_LIST_STRING,
  520.                        (int) xv_get(ip->list,
  521.                             PANEL_LIST_FIRST_SELECTED));
  522.  
  523.         if (strcmp(GFM_DOTDOT_STR, file) == 0)
  524.         {
  525.             file = "..";
  526.             xv_set(ip->file, PANEL_VALUE, file, NULL);
  527.         }
  528.         else
  529.             xv_set(ip->file, PANEL_VALUE, file, NULL);
  530.     }
  531.  
  532.     gfm_load_dir(ip, file);
  533.  
  534.     file = (char *)xv_get(ip->file, PANEL_VALUE);
  535.  
  536.     if (file && *file)
  537.         gfm_notify_client(ip);
  538. }
  539.  
  540. /*
  541.  * Event callback function for `popup'.
  542.  */
  543. Notify_value
  544. #ifdef __STDC__
  545. gfm_resize(Xv_window win, Event *event, Notify_arg arg, Notify_event_type type)
  546. #else
  547. gfm_resize(win, event, arg, type)
  548.     Xv_window    win;
  549.     Event        *event;
  550.     Notify_arg    arg;
  551.     Notify_event_type type;
  552. #endif
  553. {
  554.     int           win_width;
  555.     int           win_height;
  556.     gfm_popup_objects *ip;
  557.     GFM_PRIVATE      *gfm_private;
  558.     
  559.     ip = (gfm_popup_objects *) xv_get(win, XV_KEY_DATA, INSTANCE);
  560.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  561.  
  562.     if (event_action(event) == WIN_RESIZE)
  563.     {
  564.         win_width = (int)xv_get(win, XV_WIDTH);
  565.         win_height = (int)xv_get(win, XV_HEIGHT);
  566.  
  567.         /*
  568.          * Only do something if size has changed
  569.          */
  570.         if ((win_width != gfm_private->width) ||
  571.             (win_height != gfm_private->height))
  572.         {
  573.             set_new_sizes(ip, win_width, win_height);
  574.             xv_set(ip->file_list_group, GROUP_LAYOUT, TRUE, NULL);
  575.             panel_paint(ip->controls, PANEL_NO_CLEAR);
  576.             gfm_private->width = win_width;
  577.             gfm_private->height = win_height;
  578.         }
  579.     }
  580.  
  581.     return notify_next_event_func(win, (Notify_event) event, arg, type);
  582. }
  583.  
  584. /*
  585.  * Calculate a new size for the scrolling list.  The list behaves
  586.  * as a free space hog taking up any remaining vertical space.
  587.  */
  588. static int
  589. #ifdef __STDC__
  590. set_new_sizes(gfm_popup_objects *ip, int win_width, int win_height)
  591. #else
  592. set_new_sizes(ip, win_width, win_height)
  593.     gfm_popup_objects    *ip;
  594.     int            win_width;
  595.     int            win_height;
  596. #endif
  597. {
  598.     int        row_height = (int)xv_get(ip->list,
  599.                          PANEL_LIST_ROW_HEIGHT);
  600.     int        rem, height, nrows;
  601.     int        height_diff;
  602.     int        char_width;
  603.     int        new_length;
  604.     GFM_PRIVATE    *gfm_private;
  605.  
  606.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  607.  
  608.     height_diff = win_height - gfm_private->initial_win_height;
  609.     height = gfm_private->initial_list_height + height_diff;
  610.     nrows = (height - gfm_private->initial_list_excess) / row_height;
  611.     rem = (height - gfm_private->initial_list_excess) % row_height;
  612.  
  613.     if (rem > (row_height * 0.3))
  614.         nrows++;
  615.  
  616.     new_length = xv_get(ip->popup, WIN_COLUMNS) - 
  617.         strlen((char *)xv_get(ip->directory, PANEL_LABEL_STRING));
  618.  
  619.     char_width = xv_get(xv_get(ip->controls, XV_FONT),
  620.                 FONT_DEFAULT_CHAR_WIDTH );
  621.     new_length = xv_get(ip->popup, WIN_COLUMNS) -
  622.         ((xv_get(ip->directory, PANEL_VALUE_X) + 10) / char_width);
  623.     xv_set(ip->directory, PANEL_VALUE_DISPLAY_LENGTH, new_length, NULL);
  624.  
  625.     new_length = xv_get(ip->popup, WIN_COLUMNS) -
  626.         ((xv_get(ip->file, PANEL_VALUE_X) + 10)/ char_width);
  627.     xv_set(ip->file, PANEL_VALUE_DISPLAY_LENGTH, new_length, NULL);
  628.  
  629.     xv_set(ip->list,
  630.            PANEL_LIST_WIDTH,     win_width - 40,
  631.            PANEL_LIST_DISPLAY_ROWS, nrows,
  632.            NULL);
  633. }
  634.  
  635. /*
  636.  * This procedure notifies the client of the selected file and dismisses the
  637.  * window if the pushpin is out and the result was GFM_OK.
  638.  */
  639. static void
  640. #ifdef __STDC__
  641. gfm_notify_client(gfm_popup_objects *ip)
  642. #else
  643. gfm_notify_client(ip)
  644.     gfm_popup_objects    *ip;
  645. #endif
  646. {
  647.     int        result;
  648.     int        pin_in = xv_get(ip->popup, FRAME_CMD_PUSHPIN_IN);
  649.     char        *dir = (char *)xv_get(ip->directory, PANEL_VALUE);
  650.     char        *file = (char *)xv_get(ip->file, PANEL_VALUE);
  651.     struct stat    buf;
  652.     GFM_PRIVATE    *gfm_private;
  653.  
  654.     xv_set(ip->popup, FRAME_BUSY, TRUE, NULL);
  655.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  656.     result = (gfm_private->callback)(ip, dir, file);
  657.     xv_set(ip->popup, FRAME_BUSY, FALSE, NULL);
  658.  
  659.     /*
  660.      * If the client callback returned okay we need to check
  661.      * a few things.  If the directory has been modified, we mark
  662.      * it as invalid.  It the file chooser is pinned then we go ahead
  663.      * an reload it before returning to the client.  If it is unpinned
  664.      * we dismiss it, it will be reloaded the next time it is activated.
  665.      */
  666.     if (result == GFM_OK)
  667.     {
  668.         if (stat(dir, &buf) < 0)
  669.         {
  670.             buf.st_mtime = 0;
  671.             fprintf(stderr, dgettext("libguidexv",
  672.                  "gfm: Could not \"stat\" directory %s\n"),dir);
  673.         }
  674.  
  675.  
  676.         if (buf.st_mtime != gfm_private->dir_mtime)
  677.             gfm_private->dir_mtime = 0;
  678.  
  679.         if (xv_get(ip->popup, FRAME_CMD_PUSHPIN_IN))
  680.         {
  681.             if (gfm_private->dir_mtime == 0)
  682.                 gfm_load_dir(ip, dir);
  683.         }
  684.         else
  685.             xv_set(ip->popup, XV_SHOW, FALSE, NULL);
  686.     }
  687. }
  688.  
  689. /*
  690.  * double_click --check for double click
  691.  */
  692. static int
  693. #ifdef __STDC__
  694. double_click(Xv_opaque last_sel, struct timeval *then,
  695.          Xv_opaque this_sel, struct timeval *now)
  696. #else
  697. double_click(last_sel, then, this_sel, now)
  698.     Xv_opaque    last_sel;
  699.     struct timeval    *then;
  700.     Xv_opaque    this_sel;
  701.     struct timeval    *now;
  702. #endif
  703. {
  704.     struct timeval    delta;
  705.  
  706.     if (this_sel != last_sel)
  707.         return 0;
  708.  
  709.     delta.tv_sec = now->tv_sec - then->tv_sec;
  710.     if ((delta.tv_usec = now->tv_usec - then->tv_usec) < 0)
  711.     {
  712.         delta.tv_usec += 1000000;
  713.         delta.tv_sec -= 1;
  714.     }
  715.  
  716.     /*
  717.      * Compare delta against multiclick timeout.
  718.      */
  719.     return (delta.tv_sec*10 + delta.tv_usec/100000) <= Gfm_multiclick_timeout;
  720. }
  721.  
  722. /*
  723.  * Front end to regexp(3).  Usage:
  724.  *
  725.  *    gfm_compile_regex(regular_expression);
  726.  *    ...
  727.  *    matched = gfm_match_regex(string);
  728.  *
  729.  */
  730. #define INIT        register char *sp = instring;
  731. #define GETC()        (*sp++)
  732. #define PEEKC()        (*sp)
  733. #define UNGETC(c)    (--sp)
  734. #define RETURN(c)    return;
  735. #define ERROR(c)    fprintf(stderr, dgettext("libguidexv", "gfm: Error %d compiling regular expression (regexp)\n"), c)
  736.  
  737. #include <regexp.h>
  738.  
  739. static char    regex_buf[MAXPATHLEN];
  740.  
  741. void
  742. #ifdef __STDC__
  743. gfm_compile_regex(char *regex_str)
  744. #else
  745. gfm_compile_regex(regex_str)
  746.     char    *regex_str;
  747. #endif
  748. {
  749.     (void)compile(regex_str, regex_buf, ®ex_buf[MAXPATHLEN], '\0');
  750. }
  751.  
  752. int
  753. #ifdef __STDC__
  754. gfm_match_regex(char *s)
  755. #else
  756. gfm_match_regex(s)
  757.     char    *s;
  758. #endif
  759. {
  760.     return step(s, regex_buf);
  761. }
  762.