Link with C++ linker
[oweals/cde.git] / cde / programs / dtfile / ChangeDirP.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: ChangeDirP.c /main/8 1998/04/01 15:05:07 rafi $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           ChangeDirP.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    Processing functions for the change directory display
32  *                   line and the current directory dialog.
33  *
34  *   FUNCTIONS: ABS
35  *              CheckCurrentDirectorySelect
36  *              CurrentDirChange
37  *              CurrentDirClose
38  *              CurrentDirDropCallback
39  *              CurrentDirExposed
40  *              CurrentDirIconCallback
41  *              CurrentDirSelected
42  *              CurrentDirectoryIconMotion
43  *              DrawCurrentDirectory
44  *              GetStatusMsg
45  *              ResizeFastText
46  *              ShowChangeDirDialog
47  *              ShowFastChangeDir
48  *              TimerEvent
49  *              draw_imagestring
50  *              get_text_pieces
51  *              get_textwidth
52  *
53  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
54  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
55  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
56  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
57  *
58  ****************************************************************************
59  ************************************<+>*************************************/
60
61 #include <limits.h>
62 #include <Xm/Xm.h>
63 #include <Xm/XmP.h>
64 #include <Xm/TextFP.h>
65 #include <Xm/PushBG.h>
66 #include <Xm/DragDrop.h>
67 #include <Dt/Icon.h>
68 #include <Dt/IconP.h>
69 #include <Dt/DtNlUtils.h>
70 #include <Dt/Connect.h>
71 #include <Dt/FileM.h>
72 #include "Encaps.h"
73 #include "SharedProcs.h"
74
75 #include "Desktop.h"
76 #include "FileMgr.h"
77 #include "Main.h"
78 #include "ChangeDir.h"
79 #include "Prefs.h"
80
81
82 /********    Static Function Declarations    ********/
83
84 static void CurrentDirChange(
85                         XtPointer client_data,
86                         DialogData *old_dialog_data,
87                         DialogData *new_dialog_data,
88                         XtPointer call_data) ;
89 static void CurrentDirClose(
90                         XtPointer client_data,
91                         DialogData *old_dialog_data,
92                         DialogData *new_dialog_data) ;
93 static void CheckCurrentDirectorySelect(
94                         FileMgrData *file_mgr_data ) ;
95 static void TimerEvent(
96                         XtPointer client_data,
97                         XtIntervalId *id );
98 static void ResizeFastText(
99                         FileMgrRec *file_mgr_rec,
100                         FileMgrData *file_mgr_data,
101                         short columns) ;
102 static int get_textwidth(
103                         FileMgrData *fmd,
104                         char *str,
105                         int len);
106 static void draw_imagestring(
107                         Display *display,
108                         Drawable d,
109                         FileMgrData *fmd,
110                         GC gc,
111                         int x, int y,
112                         char *text,
113                         int bytes);
114
115 /********    End Static Function Declarations    ********/
116
117 /* absolute value macro */
118 #ifndef ABS
119 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
120 #endif
121
122 /* layout constants */
123 #define CUR_DIR_SPACING 5
124
125
126 /* local global varible to determine whether the user has double clicked
127    or not */
128 static Boolean doubleClick = False;
129
130 /*--------------------------------------------------------------------
131  * get_text_pieces:
132  *
133  *   Given a width available for the current directory text,
134  *   determines the text to be drawn in one of three formats:
135  *
136  *     /path         (non-restricted directory)
137  *     /.../path     (restricted directory)
138  *     .../subpath   (if the full path wouldn't fit)
139  *
140  *   Returns the length (in chars) and width (in pixels) of each of
141  *   the two components of the text: 
142  *   (1) prefix "/..." or "...", and (2) path or subpath.
143  *   Returns True if the path was chopped because it wouldn't fit.
144  *
145  *------------------------------------------------------------------*/
146
147 static Boolean
148 get_text_pieces(
149         FileMgrData *file_mgr_data,
150         int width,
151         char buf[],
152         int *host_len_p,
153         int *host_pixels_p,
154         int *prefix_len_p,
155         int *prefix_pixels_p,
156         int *path_len_p,
157         int *path_pixels_p)
158 {
159    Boolean chopped = False;
160    int prefix_len;
161    int prefix_pixels;
162    int path_len;
163    int path_pixels;
164    char *path_begin;
165    char *next_part = NULL;
166
167    *host_len_p = *host_pixels_p = 0;
168
169    /* if restricted directory, path prefix is "/..." */
170    if (file_mgr_data->restricted_directory)
171    {
172       strcpy(buf, "/...");
173       prefix_len = strlen("/...");
174       prefix_pixels = get_textwidth (file_mgr_data, "/...", prefix_len);
175       path_begin = file_mgr_data->current_directory +
176                        strlen(file_mgr_data->restricted_directory);
177       if (*path_begin == '\0')
178          path_begin = "/";
179       else if (*path_begin != '/')
180           -- path_begin;
181
182    }
183    else
184    {
185       prefix_len = 0;
186       prefix_pixels = 0;
187       path_begin = file_mgr_data->current_directory;
188    }
189
190    /* calculate path length & width */
191    path_len = strlen(path_begin);
192    path_pixels = get_textwidth (file_mgr_data, path_begin, path_len);
193
194    /* if whole path doesn't fit, we need to chop off pieces until it does */
195    if (prefix_pixels + path_pixels > width)
196    {
197       chopped = True;
198
199       /* change the path prefix */
200       strcpy(buf, "...");
201       prefix_len = strlen("...");
202       prefix_pixels = get_textwidth (file_mgr_data, "...", prefix_len);
203
204       do
205       {
206          /* chop off the next piece (everything up to the next '/') */
207          next_part = NULL;
208          next_part = DtStrchr(path_begin + 1, '/');
209          if (next_part == NULL)
210          {
211            /* Got here only when the last directory is still too
212               long to display
213            */
214            break;
215          }
216
217          /* calculate new path length */
218          path_begin = next_part;
219          path_len = strlen(path_begin);
220          path_pixels = get_textwidth (file_mgr_data, path_begin, path_len);
221
222          /* keep going until it fits */
223       } while (prefix_pixels + path_pixels > width);
224    }
225
226    /* add the path to the buffer */
227    if( NULL == next_part )
228    {
229      /* Got here only when the last directory is still too
230         long to display
231       */
232      int len = path_len;
233      char saved_char;
234
235      while( 0 != len )
236      {
237        /* Going back one character at a time to see if it fit
238        */
239        path_pixels = get_textwidth( file_mgr_data, path_begin, len );
240        if( prefix_pixels + path_pixels < width )
241        {
242          break;
243        }
244        --len;
245      }
246
247      if( 0 == len )
248      {
249        buf[prefix_len] = 0x0;
250        *path_len_p = 0;
251        *path_pixels_p = 0;
252      }
253      else
254      {
255        strncpy (buf + prefix_len, path_begin, len);
256        *path_len_p      = len;
257        *path_pixels_p   = path_pixels;
258      }
259    }
260    else
261    {
262      strcpy (buf + prefix_len, path_begin);
263      *path_len_p      = path_len;
264      *path_pixels_p   = path_pixels;
265    }
266
267    /* return values */
268    *prefix_len_p    = prefix_len;
269    *prefix_pixels_p = prefix_pixels;
270    return chopped;
271 }
272
273
274 /************************************************************************
275  *
276  *  ShowChangeDirDialog
277  *      Callback functions invoked from the Change Directory... menu
278  *      item.  This function displays the change directory dialog.
279  *
280  ************************************************************************/
281
282 /*ARGSUSED*/
283 void
284 ShowChangeDirDialog(
285         Widget w,
286         XtPointer client_data,
287         XtPointer callback )
288 {
289    FileMgrRec  * file_mgr_rec;
290    DialogData  * dialog_data;
291    FileMgrData * file_mgr_data;
292    ChangeDirData * change_dir_data;
293    ChangeDirRec * change_dir_rec;
294    Arg args[1];
295    Widget mbar;
296    char *tempStr, *tmpStr;
297
298
299    /*  Set the menu item to insensitive to prevent multiple  */
300    /*  dialogs from being posted and get the area under the  */
301    /*  menu pane redrawn.                                    */
302
303    if (w)
304    {
305       if((int)client_data == FM_POPUP)
306          mbar = XtParent(w);
307       else
308          mbar = (Widget) XmGetPostedFromWidget(XtParent(w));
309
310       XmUpdateDisplay (w);
311       XtSetArg(args[0], XmNuserData, &file_mgr_rec);
312       XtGetValues(mbar, args, 1);
313
314       /* Ignore accelerators when we're insensitive */
315       if ((file_mgr_rec->menuStates & CHANGEDIR) == 0)
316       {
317         XSetInputFocus(XtDisplay(w),
318                        XtWindow(file_mgr_rec->change_directoryBtn_child),
319                        RevertToParent, CurrentTime);
320         return;
321       }
322    }
323    else
324    {
325       /* Done only during a restore session */
326       file_mgr_rec = (FileMgrRec *)client_data;
327    }
328
329    /* Got an accelerator after we were unposted */
330    if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
331       return;
332
333    file_mgr_data = (FileMgrData *) dialog_data->data;
334    change_dir_data = (ChangeDirData *) file_mgr_data->change_dir->data;
335    change_dir_data->file_mgr_rec = (XtPointer) file_mgr_rec;
336
337    file_mgr_rec->menuStates &= ~CHANGEDIR;
338
339    _DtShowDialog (file_mgr_rec->shell, (Widget)NULL, (XtPointer)file_mgr_rec,
340                file_mgr_data->change_dir,
341                CurrentDirChange, (XtPointer)file_mgr_rec,
342                CurrentDirClose, (XtPointer)file_mgr_rec, (char *)NULL,
343                False, False, (char *)NULL, (XClassHint *)NULL);
344
345    /* Save a ptr to file_mgr_rec in the find dialogs structure */
346    change_dir_rec = (ChangeDirRec *)_DtGetDialogInstance(
347                                                    file_mgr_data->change_dir);
348
349    if(file_mgr_data->title != NULL &&
350                strcmp(file_mgr_data->helpVol, DTFILE_HELP_NAME) != 0)
351    {
352       tmpStr = GETMESSAGE(2,15, "Go To");
353       tempStr = (char *)XtMalloc(strlen(tmpStr) +
354                                  strlen(file_mgr_data->title) + 5);
355       sprintf(tempStr, "%s - %s", file_mgr_data->title, tmpStr);
356    }
357    else
358    {
359       tmpStr = (GETMESSAGE(2,17, "File Manager - Go To"));
360       tempStr = XtNewString(tmpStr);
361    }
362    XtSetArg (args[0], XmNtitle, tempStr);
363    XtSetValues (XtParent (change_dir_rec->change_dir), args, 1);
364    XtFree(tempStr);
365
366    file_mgr_rec->change_directoryBtn_child=XtParent (change_dir_rec->change_dir);
367 }
368
369
370
371
372 /************************************************************************
373  *
374  *  CurrentDirSelected
375  *      When a Button1 selection occurs on the current directory line,
376  *      see if it occurred within the directory path, highlight the
377  *      selected sub-path, or if the sub-path was already highlighted,
378  *      set the current directory to the path and dehighlight.
379  *
380  ************************************************************************/
381
382 void
383 CurrentDirSelected(
384         Widget w,
385         XtPointer client_data,
386         XtPointer call_data )
387 {
388    FileMgrRec  *file_mgr_rec = (FileMgrRec *) client_data;
389    DialogData  *dialog_data;
390    FileMgrData *file_mgr_data;
391    char buf[2*MAX_PATH];
392    char host_name[MAX_PATH];
393    Boolean chopped;
394    int host_len;
395    int host_pixels;
396    int prefix_len;
397    int prefix_pixels;
398    int path_len;
399    int path_pixels;
400
401    XmDrawnButtonCallbackStruct *button_data;
402    XButtonEvent *event;
403    Dimension width, highlight, shadow, margin;
404    Arg args[4];
405
406    int left_margin;
407    int begin_x;
408    int end_x;
409    int len;
410    int i;
411    char *ptr;
412    char *new_select;
413    int swidth;
414    static XtIntervalId TimerId;
415
416    /* if doubleClick is true than we have a double click so we want
417     * to change to the new directory that the user double clicked on
418     */
419    if (doubleClick)
420       XtRemoveTimeOut(TimerId);
421
422    button_data = (XmDrawnButtonCallbackStruct *) call_data;
423    event = (XButtonEvent *) button_data->event;
424
425    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
426    file_mgr_data = (FileMgrData *) dialog_data->data;
427
428    /* Get layout values */
429    XtSetArg (args[0], XmNwidth, &width);
430    XtSetArg (args[1], XmNhighlightThickness, &highlight);
431    XtGetValues (w, args, 2);
432    XtSetArg (args[0], XmNshadowThickness, &shadow);
433    XtSetArg (args[1], XmNmarginWidth, &margin);
434    XtGetValues (file_mgr_rec->current_directory_text, args, 2);
435    left_margin = highlight + shadow + margin;
436
437    /*  Get the starting and ending locations of the current  */
438    /*  directory text.                                       */
439    chopped = get_text_pieces(file_mgr_data, width - 2*left_margin,
440                buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
441                &path_len, &path_pixels);
442
443    begin_x = left_margin;
444    end_x = begin_x + host_pixels + prefix_pixels + path_pixels;
445
446    /*  Get the selected path  */
447    if (event->x < begin_x || event->x >= end_x)
448    {
449       /* click outside the directory text: nothing selected */
450       new_select = NULL;
451    }
452    else if (event->x < begin_x + host_pixels ||
453             event->x < begin_x + host_pixels + prefix_pixels && !chopped)
454    {
455       /* click on host name or "/..." prefix: root selected */
456       if (file_mgr_data->restricted_directory)
457          new_select = XtNewString(file_mgr_data->restricted_directory);
458       else
459          new_select = XtNewString("/");
460    }
461    else if (event->x < begin_x + host_pixels + prefix_pixels && chopped)
462    {
463       /* click on "..." prefix: directory above the visible piece selected */
464       len = strlen(file_mgr_data->current_directory) - path_len;
465       new_select = (char *) XtMalloc(len + 1);
466       memcpy(new_select, file_mgr_data->current_directory, len);
467       new_select[len] = 0;
468    }
469    else /* event->x >= begin_x + host_pixels + prefix_pixels */
470    {
471       /* click on the path: determine which subdirectory selected */
472       begin_x += host_pixels + prefix_pixels;
473       i = host_len + prefix_len;
474       swidth = get_textwidth(file_mgr_data, "/", strlen("/")) / 2;
475
476       while (begin_x - swidth < event->x)
477       {
478          /* find next '/' in path */
479          ptr = DtStrchr(buf + i, '/');
480          if (ptr == NULL)
481          {
482            i = host_len + prefix_len + path_len + 1;
483            break;
484          }
485
486          /* get x-position of next path component */
487          len = ((ptr + 1) - buf) - i;
488          begin_x += get_textwidth(file_mgr_data, buf + i, len);
489          i += len;
490       }
491
492          /* if we have a restricted diretory and i == 5 ("/.../") then we want
493             the len to be the restricted directory */
494       if (file_mgr_data->restricted_directory &&  i == 5)
495          len = strlen(file_mgr_data->restricted_directory);
496       else
497          len = strlen(file_mgr_data->current_directory)
498              - (host_len + prefix_len + path_len - i) - 1;
499       new_select = (char *) XtMalloc(len + 1);
500       if (len == 0)
501          strcpy(new_select, "/");
502       else
503       {
504          memcpy(new_select, file_mgr_data->current_directory, len);
505          new_select[len] = 0;
506       }
507    }
508
509    /* in restricted mode, don't allow going above the user's home dir */
510    if (new_select != NULL && restrictMode)
511    {
512       /* check if new_select is the same as or a subdirectory of $HOME */
513       len = strlen(users_home_dir);
514       if (strncmp(new_select, users_home_dir, len) != 0
515            || new_select[len] != '\0' && new_select[len] != '/')
516       {
517          /* change new_select to $HOME */
518          XtFree(new_select);
519          new_select = XtNewString(users_home_dir);
520       }
521    }
522
523
524    /*  If the path is the same as what is already selected,  */
525    /*  free cd_select, set the directory to the selected     */
526    /*  directory, redraw the directory display.              */
527
528    /*  If the path was different, set cd_select to the       */
529    /*  selected directory and redraw the directory.          */
530
531    if (new_select != NULL && file_mgr_data->cd_select != NULL &&
532        strcmp(new_select, file_mgr_data->cd_select) == 0)
533    {
534       XtFree (file_mgr_data->cd_select);
535       file_mgr_data->cd_select = NULL;
536
537       strcpy(buf, new_select);
538       strcpy(host_name, file_mgr_data->host);
539
540       if (strcmp (buf, file_mgr_data->current_directory) == 0)
541          FileMgrReread (file_mgr_rec);
542       else
543          ShowNewDirectory (file_mgr_data, host_name, buf);
544
545       XtFree (new_select);
546    }
547    else
548    {
549       XtFree (file_mgr_data->cd_select);
550       file_mgr_data->cd_select = new_select;
551    }
552
553    if (doubleClick)
554    {
555       doubleClick = False;
556       DrawCurrentDirectory (w, file_mgr_rec, file_mgr_data);
557    }
558    else
559    {
560       doubleClick = True;
561       TimerId = XtAppAddTimeOut (XtWidgetToApplicationContext (w), 
562                                  XtGetMultiClickTime(XtDisplay(w)),
563                                  (XtTimerCallbackProc) TimerEvent, 
564                                  (XtPointer) file_mgr_rec);
565    }
566 }
567
568
569
570 /************************************************************************
571  *
572  *  CurrentDirDropCallback
573  *      Callback function invoked upon an action on the change view drop.
574  *
575  ************************************************************************/
576
577 void
578 CurrentDirDropCallback(
579         Widget w,
580         XtPointer client_data,
581         XtPointer call_data )
582 {
583    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
584    XmAnyCallbackStruct * callback;
585    DialogData  * dialog_data;
586    FileMgrData * file_mgr_data;
587    char host_name[MAX_PATH];
588
589    callback = (XmAnyCallbackStruct *) call_data;
590    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
591    file_mgr_data = (FileMgrData *) dialog_data->data;
592
593    if (callback->reason == XmCR_DEFAULT_ACTION)
594    {
595       strcpy(host_name, file_mgr_data->host);
596       ShowNewDirectory (file_mgr_data, host_name,
597                         _DtPName (file_mgr_data->current_directory));
598    }
599 }
600
601
602 /************************************************************************
603  *
604  *  CurrentDirIconCallback
605  *      Callback function invoked upon an action occuring on an icon.
606  *
607  ************************************************************************/
608
609 void
610 CurrentDirIconCallback(
611         Widget w,
612         XtPointer client_data,
613         XtPointer call_data )
614 {
615    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
616    XmAnyCallbackStruct * callback;
617    XButtonEvent        * event;
618    DialogData  * dialog_data;
619    FileMgrData * file_mgr_data;
620
621    callback = (XmAnyCallbackStruct *) call_data;
622    event = (XButtonEvent *) callback->event;
623    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
624    file_mgr_data = (FileMgrData *) dialog_data->data;
625
626    if (callback->reason == XmCR_DRAG)
627    {
628       /* Do nothing if a Button 1 drag is already ramping up */
629       if (B1DragPossible)
630          return;
631
632       /* Save starting X and Y, for threshold detection */
633       initialDragX = event->x;
634       initialDragY = event->y;
635
636       /* Flag that a Button 2 drag is ramping up */
637       B2DragPossible = True;
638
639       UnpostTextField(file_mgr_data);
640    }
641    else if (callback->reason == XmCR_ARM)
642    {
643       /* Do nothing if a Button 2 drag is already ramping up */
644       if (B2DragPossible)
645          return;
646
647       /* Save starting X and Y, for threshold detection */
648       initialDragX = event->x;
649       initialDragY = event->y;
650
651       /* Flag that a Button 1 drag is ramping up */
652       B1DragPossible = True;
653       
654       /* but since we're in the current directory icon we don't want to
655          process on the button up */
656       ProcessBtnUpCD = False;
657
658       UnpostTextField(file_mgr_data);
659    }
660    else if (callback->reason == XmCR_DEFAULT_ACTION)
661    {
662       /* We now know that a drag operation won't be starting up */
663       B1DragPossible = False;
664       B2DragPossible = False;
665
666       UnpostTextField(file_mgr_data);
667
668       /* Default action is to reread the directory */
669       FileMgrReread (file_mgr_rec);
670    }
671    else if ((callback->reason == XmCR_SELECT) || 
672             (callback->reason == XmCR_DISARM) ||
673             (callback->reason == XmCR_DROP))
674    {
675       /* We now know that a drag operation won't be starting up */
676       B1DragPossible = False;
677       B2DragPossible = False;
678    }
679 }
680
681
682 /*
683  * This function processes motion events anytime a B1 or B2 drag operation
684  * has the potential of starting.  When the drag threshold is surpassed,
685  * a drag operation will be started.
686  */
687
688 void
689 CurrentDirectoryIconMotion(
690                         Widget w,
691                         XtPointer client_data,
692                         XEvent *event)
693 {
694
695    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
696    DialogData  * dialog_data;
697    FileMgrData * file_mgr_data;
698    Pixmap drag_pixmap;
699    char * type_set;
700    char * file_set;
701    int diffX, diffY;
702    Widget dirIcon;
703    DtIconGadget iconG;
704
705
706    if ((B1DragPossible && (event->xmotion.state & Button1Mask)) ||
707        (B2DragPossible && (event->xmotion.state & Button2Mask)))
708    {
709       /* Have we passed the drag threshold? */
710       diffX = initialDragX - event->xmotion.x;
711       diffY = initialDragY - event->xmotion.y;
712   
713       if ((ABS(diffX) >= dragThreshold) || (ABS(diffY) >= dragThreshold))
714       {
715          dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
716          file_mgr_data = (FileMgrData *) dialog_data->data;
717
718          initiating_view = (XtPointer) file_mgr_data;
719          dirIcon = file_mgr_rec->current_directory_icon;
720          StartDrag(dirIcon, NULL, event);
721       }
722    }
723 }
724
725
726 /************************************************************************
727  *
728  *  CurrentDirExposed
729  *      Callback functions invoked from the current directory display
730  *      drawn button.  This function extracts some structures and calls
731  *      the directory display function.
732  *
733  ************************************************************************/
734
735 void
736 CurrentDirExposed(
737         Widget w,
738         XtPointer client_data,
739         XtPointer call_data )
740 {
741    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
742    DialogData  * dialog_data;
743    FileMgrData * file_mgr_data;
744
745    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
746
747    /*  Check to see if the view has been closed  */
748
749    if (dialog_data == NULL) return;
750
751    file_mgr_data = (FileMgrData *) dialog_data->data;
752
753    if (file_mgr_data->cd_normal_gc != 0)
754       DrawCurrentDirectory (w, file_mgr_rec, file_mgr_data);
755 }
756
757
758
759
760 /************************************************************************
761  *
762  * GetStatusMsg
763  *   Construct the status message (normally "x Items, y Hidden").
764  *   Returns True if the message is deemed "important".
765  *
766  *   @@@ Note 2/17/95: messages below containing "Item(s)" should really
767  *   be just "Item", but the message catalog is frozen at this time, so
768  *   we can't fix this now.  (In practice, it doesn't matter, because
769  *   the item count should always be > 1, since every directory shoule
770  *   contain at least two files "." and "..")
771  *
772  ************************************************************************/
773
774 Boolean
775 GetStatusMsg(
776         FileMgrData *file_mgr_data,
777         char *buf )
778 {
779    int n_files;
780    int n_hidden;
781    int i, j;
782    TreeShow ts;
783    FileViewData **file_view_data;
784
785    /*
786     * If we are currently busy reading a directory, display a progress
787     * message instead of the normal "x Items, y Hidden" message.
788     */
789    if (file_mgr_data->busy_status == initiating_readdir ||
790        file_mgr_data->busy_status == busy_readdir)
791    {
792       if (file_mgr_data->busy_detail == 0)
793          sprintf (buf, (GETMESSAGE(3,5, "Reading ...")));
794       else if (file_mgr_data->busy_detail == 1)
795         sprintf (buf, (GETMESSAGE(3,11, "%d Item(s)...")),
796                  file_mgr_data->busy_detail);
797       else
798         sprintf (buf, (GETMESSAGE(3,9, "%3d Items ...")),
799                  file_mgr_data->busy_detail);
800
801       return True;  /* this message deemed important! */
802    }
803
804    else if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
805    {
806       /*
807        * In tree mode, we only show a count of the hidden files
808        * in branches that are currently expanded.
809        * The idea is we want to show how many additional files would
810        * show up if the user turned on the "Show Hidden" option.
811        */
812       n_hidden = 0;
813       for (i = 0; i < file_mgr_data->directory_count; i++)
814       {
815          file_view_data = file_mgr_data->directory_set[i]->file_view_data;
816          if (file_view_data == NULL)
817             continue;
818
819          ts = file_mgr_data->directory_set[i]->sub_root->ts;
820          if (ts < tsDirs)
821             continue;   /* this branch is not expanded */
822
823          for (j = 0; j < file_mgr_data->directory_set[i]->file_count; j++)
824          {
825             if (file_view_data[j]->filtered &&
826                 (ts == tsAll || file_view_data[j]->file_data->is_subdir))
827             {
828                n_hidden++;
829             }
830          }
831       }
832       sprintf (buf, (GETMESSAGE(3,6, "%d Hidden")), n_hidden);
833
834       return False;
835    }
836
837    else
838    {
839       /*
840        * In flat mode, we only show a total count of all files
841        * and a count of hidden files.
842        */
843       n_files = file_mgr_data->directory_set[0]->file_count;
844       if( n_files == 0 )
845         sprintf( buf, (GETMESSAGE(11,31, "Error while reading %s")), file_mgr_data->current_directory );
846       else if( file_mgr_data == trashFileMgrData )
847       {
848         n_hidden = file_mgr_data->directory_set[0]->filtered_file_count;
849         sprintf (buf, (GETMESSAGE(3,10, "%d Item(s)")),
850                  n_files - n_hidden);
851       }
852       else
853       {
854         n_files -= file_mgr_data->directory_set[0]->invisible_file_count;
855         n_hidden = file_mgr_data->directory_set[0]->filtered_file_count -
856           file_mgr_data->directory_set[0]->invisible_file_count;
857         if (n_files == 1)
858           sprintf (buf, (GETMESSAGE(3,12, "%d Item(s) %d Hidden")),
859                    n_files, n_hidden);
860         else
861           sprintf (buf, (GETMESSAGE(3,7, "%d Items %d Hidden")),
862                  n_files, n_hidden);
863       }
864
865       return False;
866    }
867 }
868
869
870 /************************************************************************
871  *
872  *  DrawCurrentDirectory
873  *      Draw the current directory display area, including the hostname,
874  *      the current directory, any highlighted sub-path of the directory,
875  *      the file count and the number of selected files.
876  *
877  ************************************************************************/
878
879 void
880 DrawCurrentDirectory(
881         Widget w,
882         FileMgrRec *file_mgr_rec,
883         FileMgrData *file_mgr_data )
884 {
885    Arg args[8];
886    Dimension width, height, highlight, shadow, margin, twidth;
887    XFontSetExtents *extents;
888    int font_height;
889    int font_yoffset;
890    int top_margin;
891    int left_margin;
892    char buf[2*MAX_PATH];
893    char msg[21+MAX_PATH];
894    Boolean chopped;
895    int host_len;
896    int host_pixels;
897    int prefix_len;
898    int prefix_pixels;
899    int path_len;
900    int path_pixels;
901    int draw_x;
902    int draw_y;
903    int dir_width;
904    int msg_width;
905    short columns;
906    Boolean msg_drawn;
907
908    /* Get layout values */
909    XtSetArg (args[0], XmNwidth, &width);
910    XtSetArg (args[1], XmNheight, &height);
911    XtSetArg (args[2], XmNhighlightThickness, &highlight);
912    XtGetValues (w, args, 3);
913    XtSetArg (args[0], XmNshadowThickness, &shadow);
914    XtSetArg (args[1], XmNmarginWidth, &margin);
915    XtGetValues (file_mgr_rec->current_directory_text, args, 2);
916
917    if(file_mgr_data->cd_fonttype == XmFONT_IS_FONTSET) {
918        extents = XExtentsOfFontSet(file_mgr_data->cd_fontset);
919        font_yoffset = -(extents->max_logical_extent.y);
920        font_height = extents->max_logical_extent.height;
921    }
922    else
923    {
924        font_yoffset = file_mgr_data->cd_font->ascent;
925        font_height = file_mgr_data->cd_font->ascent +
926                        file_mgr_data->cd_font->descent;
927    }
928    top_margin = (height > (Dimension)font_height)? (Dimension)(height - font_height + 1)/(Dimension)2: 0;
929    left_margin = highlight + shadow + margin;
930
931    /* Ensure the area is cleared out. */
932    XClearArea (XtDisplay (w), XtWindow (w),
933                highlight, highlight,
934                width - 2*highlight, height - 2*highlight,
935                False);
936
937    /*
938     * If there is no status line and no iconic path,
939     * we will want yo draw the "x Files y Hidden" message here.
940     */
941    if (!file_mgr_data->show_iconic_path && !file_mgr_data->show_status_line)
942    {
943       /*
944        * GetStatusMsg() returns True if the status msg is "important".
945        * In this case, make sure we leave room for it
946        */
947       msg_drawn = GetStatusMsg(file_mgr_data, msg);
948       msg_width = get_textwidth (file_mgr_data, msg, strlen(msg));
949    }
950    else
951       msg_drawn = False;
952
953    draw_x = left_margin;
954    if( draw_x < 0 || (Dimension) draw_x > width ) /* Make sure that it's in bound */
955      draw_x = 0;
956
957    draw_y = top_margin + font_yoffset;
958    if( draw_y < 0 || (Dimension) draw_y > height ) /* Make sure that it's in bound */
959    {
960      draw_y = height-5;
961    }
962
963    /* get the text pieces */
964    dir_width = width - 2*left_margin;
965    if (msg_drawn)
966       dir_width -= CUR_DIR_SPACING + msg_width;
967    chopped = get_text_pieces(file_mgr_data, dir_width,
968                buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
969                &path_len, &path_pixels);
970
971    /*
972     * go check and change the file_mgr_data->cd_select, make sure its not
973     * longer than the file_mgr_data->current_directory.
974     */
975    CheckCurrentDirectorySelect(file_mgr_data);
976
977    /* draw the host and paths */
978    if (!file_mgr_data->fast_cd_enabled)
979    {
980       draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
981                         file_mgr_data->cd_normal_gc, draw_x, draw_y,
982                         buf, host_len + prefix_len + path_len);
983    }
984    else if (file_mgr_data->restricted_directory)
985    {
986       draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
987                         file_mgr_data->cd_normal_gc, draw_x, draw_y,
988                         buf, host_len + prefix_len);
989    }
990
991    /*
992     * If there is no status line and no iconic path, and we have
993     * room left, draw the "x Files y Hidden" message here.
994     */
995    if (!file_mgr_data->show_iconic_path && !file_mgr_data->show_status_line)
996    {
997       /* determine where the message could begin */
998       if (!file_mgr_data->fast_cd_enabled)
999          draw_x += host_pixels + prefix_pixels + path_pixels;
1000       else
1001       {
1002          XtSetArg(args[0], XmNwidth, &twidth);
1003          XtGetValues(file_mgr_rec->current_directory_text, args, 1);
1004          if (file_mgr_data->restricted_directory && !chopped)
1005             draw_x += host_pixels + prefix_pixels + twidth;
1006          else
1007             draw_x += host_pixels + twidth;
1008       }
1009
1010       /* if there is enough space left, draw the message */
1011       if ((Dimension)(draw_x + CUR_DIR_SPACING + msg_width + left_margin) <= width)
1012       {
1013          draw_x = width - left_margin - msg_width;
1014          draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
1015                            file_mgr_data->cd_normal_gc, draw_x, draw_y,
1016                            msg, strlen(msg));
1017          draw_x -= shadow + CUR_DIR_SPACING;  /* right edge of shadow */
1018          msg_drawn = True;
1019       }
1020       else
1021          msg_drawn = False;
1022    }
1023
1024    if (!msg_drawn)
1025       draw_x = width - (highlight + shadow);
1026
1027    /* draw the shadow */
1028    if (!file_mgr_data->fast_cd_enabled)
1029    {
1030       int shadow_width = draw_x - highlight;
1031       int shadow_height = height - 2*highlight;
1032       XmTextFieldWidget tf =
1033              (XmTextFieldWidget)file_mgr_rec->current_directory_text;
1034
1035       XmeDrawShadows(XtDisplay(w), XtWindow(w),
1036                      tf->primitive.top_shadow_GC,
1037                      tf->primitive.bottom_shadow_GC,
1038                      highlight, highlight, shadow_width, shadow_height,
1039                      shadow, XmSHADOW_IN);
1040    }
1041 }
1042
1043
1044
1045 /************************************************************************
1046  *
1047  *  CurrentDirChange
1048  *      Callback functions invoked from the current directory dialog's
1049  *      apply button being pressed.  This function updates and redisplays
1050  *      the current directory information.
1051  *
1052  ************************************************************************/
1053
1054 static void
1055 CurrentDirChange(
1056         XtPointer client_data,
1057         DialogData *old_dialog_data,
1058         DialogData *new_dialog_data,
1059         XtPointer call_data )
1060 {
1061    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
1062    DialogData  * dialog_data;
1063    FileMgrData * file_mgr_data;
1064    ChangeDirData * new_change_dir_data;
1065    ChangeDirData * old_change_dir_data;
1066    char path[MAX_PATH];
1067    char host_name[MAX_PATH];
1068    char * ptr;
1069
1070
1071    /*  Get a pointer file manager's data structure, free up the   */
1072    /*  old current directory and copy in a new one.  Free up the  */
1073    /*  old selected sub-path, update the file manager's internal  */
1074    /*  data, and redraw the directory.                            */
1075
1076    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
1077    file_mgr_data = (FileMgrData *) dialog_data->data;
1078
1079    if (file_mgr_data->cd_select != NULL)
1080    {
1081       XtFree (file_mgr_data->cd_select);
1082       file_mgr_data->cd_select = NULL;
1083    }
1084
1085    old_change_dir_data = (ChangeDirData *) file_mgr_data->change_dir->data;
1086    new_change_dir_data = (ChangeDirData *) new_dialog_data->data;
1087    
1088    new_change_dir_data->host_name = XtNewString(old_change_dir_data->host_name);
1089    new_change_dir_data->file_mgr_rec = old_change_dir_data->file_mgr_rec;
1090
1091    _DtHideDialog(old_dialog_data, False);
1092
1093    new_change_dir_data->displayed = False;
1094
1095    file_mgr_data->change_dir->data = (XtPointer) new_change_dir_data;
1096    new_dialog_data->data = (XtPointer) old_change_dir_data;
1097    _DtFreeDialogData (new_dialog_data);
1098    file_mgr_rec->menuStates |= CHANGEDIR;
1099
1100
1101    /*  Process call_data into a hostname and directory name.  */
1102
1103    ShowNewDirectory (file_mgr_data,
1104                      ((ChangeDirData *)file_mgr_data->change_dir->data)->host_name,
1105                      call_data);
1106 }
1107
1108
1109
1110
1111 /************************************************************************
1112  *
1113  *  CurrentDirClose
1114  *      Callback functions invoked from the current directory dialog's
1115  *      close button being pressed.  This function resensitizes the
1116  *      Change Directory... menu item.
1117  *
1118  ************************************************************************/
1119
1120 /*ARGSUSED*/
1121 static void
1122 CurrentDirClose(
1123         XtPointer client_data,
1124         DialogData *old_dialog_data,
1125         DialogData *new_dialog_data )
1126 {
1127    FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
1128
1129    _DtFreeDialogData (new_dialog_data);
1130    file_mgr_rec->menuStates |= CHANGEDIR;
1131 }
1132
1133 /************************************************************************
1134  *
1135  *  CheckCurrentDirectorySelect
1136  *           Before calling DrawCurrentDirectorySelect() this function
1137  *           makes sure that the fm->cd_select isn't longer than the
1138  *           fm->current_directory.  If it is it reconfigures fm->cd_select
1139  *           to hold no more than what fm->current_directory is.
1140  *
1141  ************************************************************************/
1142 static void
1143 CheckCurrentDirectorySelect( 
1144          FileMgrData *file_mgr_data )
1145 {
1146    int length_cd, length_cd_s;
1147    char *str, *ptr;
1148
1149    if (file_mgr_data            == NULL ||
1150        file_mgr_data->cd_select == NULL ||
1151        file_mgr_data->current_directory == NULL)
1152        return;
1153
1154    /* get the true lengths of current_directory and current_directory_select */
1155    length_cd = strlen(file_mgr_data->current_directory);
1156    length_cd_s = strlen(file_mgr_data->cd_select);
1157    
1158    /* if cd is larger than cd_select than we have now problem */
1159    if(length_cd >= length_cd_s)
1160       return;
1161
1162    /* we need to recalculate the cd_select */
1163    str = XtNewString(file_mgr_data->cd_select);
1164    while(1)
1165    {
1166       ptr = strrchr(str, '/');
1167       *ptr = '\0';
1168       length_cd_s = strlen(str);
1169       if(length_cd > length_cd_s)
1170       {
1171          XtFree(file_mgr_data->cd_select);
1172          file_mgr_data->cd_select = (char *)XtMalloc(strlen(str) + 1);
1173          strcpy(file_mgr_data->cd_select, str);
1174          XtFree(str);
1175          return;
1176       }
1177    }
1178 }
1179
1180 /************************************************************************
1181  *
1182  *  ShowFastChangeDir
1183  *      Post the fast change to text widget.
1184  *
1185  ***************************************************************************/
1186 void
1187 ShowFastChangeDir(
1188         FileMgrRec *file_mgr_rec,
1189         FileMgrData *file_mgr_data )
1190 {
1191    char *textString;
1192    Arg args[16];
1193    Dimension width, height;
1194    Dimension shadow, highlight, margin;
1195    char buf[2*MAX_PATH];
1196    Boolean chopped;
1197    int host_len;
1198    int host_pixels;
1199    int prefix_len;
1200    int prefix_pixels;
1201    int path_len;
1202    int path_pixels;
1203    int begin_x;
1204    int left_margin;
1205
1206    doubleClick = False;
1207
1208    XtRemoveAllCallbacks (file_mgr_rec->current_directory, XmNexposeCallback);
1209
1210    XtFree (file_mgr_data->cd_select);
1211    file_mgr_data->cd_select = NULL;
1212
1213    file_mgr_data->fast_cd_enabled = True;
1214
1215    /* if not a toolbox, just put the current directory in text widget */
1216    if (file_mgr_data->restricted_directory == NULL)
1217    {
1218       if (strcmp(file_mgr_data->host, home_host_name) == 0)
1219          textString = XtNewString(file_mgr_data->current_directory);
1220       else
1221          textString = DtCreateContextString(file_mgr_data->host,
1222                                             file_mgr_data->current_directory,
1223                                             NULL);
1224    }
1225    else  /* is a toolbox, so put the subset of what the toolbox is in the text*/
1226    {
1227       char *ptr;
1228
1229       ptr = file_mgr_data->current_directory +
1230                         strlen(file_mgr_data->restricted_directory);
1231       if (strcmp(ptr, "") == 0)
1232          textString = XtNewString("/");
1233       else
1234          textString = XtNewString(ptr);
1235    }
1236    begin_x = get_textwidth (file_mgr_data, textString, strlen (textString));
1237
1238    /* Get layout values */
1239    XtSetArg (args[0], XmNwidth, &width);
1240    XtSetArg (args[1], XmNhighlightThickness, &highlight);
1241    XtGetValues (file_mgr_rec->current_directory, args, 2);
1242    XtSetArg (args[0], XmNshadowThickness, &shadow);
1243    XtSetArg (args[1], XmNmarginWidth, &margin);
1244    XtGetValues (file_mgr_rec->current_directory_text, args, 2);
1245    left_margin = highlight + shadow + margin;
1246
1247    if(file_mgr_data->restricted_directory == NULL)
1248       XtSetArg (args[0], XmNleftOffset, 0);
1249    else
1250    {
1251       XtSetArg (args[0], XmNshadowThickness, &shadow);
1252       XtSetArg (args[1], XmNhighlightThickness, &highlight);
1253       XtGetValues(file_mgr_rec->current_directory_text, args, 2);
1254       chopped =
1255         get_text_pieces(file_mgr_data, width - 2*left_margin,
1256                   buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
1257                   &path_len, &path_pixels);
1258       begin_x = left_margin + host_pixels - shadow - highlight;
1259       if (!chopped)
1260         begin_x += prefix_pixels;
1261       XtSetArg (args[0], XmNleftOffset, begin_x);
1262    }
1263    XtSetArg (args[1], XmNvalue, textString);
1264    XtSetValues(file_mgr_rec->current_directory_text, args, 2);
1265    XtSetArg (args[0], XmNcursorPosition, strlen(textString));
1266    XtSetValues(file_mgr_rec->current_directory_text, args, 1);
1267
1268    XtSetArg (args[0], XmNallowShellResize, False);
1269    XtSetValues(file_mgr_rec->shell, args, 1);
1270    XtManageChild(file_mgr_rec->current_directory_text);
1271    XtSetArg (args[0], XmNallowShellResize, True);
1272    XtSetValues(file_mgr_rec->shell, args, 1);
1273    XRaiseWindow(XtDisplay(file_mgr_rec->current_directory_text),
1274                 XtWindow(file_mgr_rec->current_directory_text));
1275    XmUpdateDisplay(file_mgr_rec->current_directory_text);
1276    XmProcessTraversal(file_mgr_rec->current_directory_text,
1277                          XmTRAVERSE_CURRENT);
1278    XtFree(textString);
1279    XtAddCallback (file_mgr_rec->current_directory, XmNexposeCallback,
1280                                           CurrentDirExposed, file_mgr_rec);
1281 }
1282
1283 /************************************************************************
1284  *
1285  *  TimerEvent - timeout for double click on current Directory line.  If
1286  *      we get here we know it was a single click so lets post the
1287  *      fast change to text widget.
1288  *
1289  ***************************************************************************/
1290 static void
1291 TimerEvent(
1292         XtPointer client_data,
1293         XtIntervalId *id )
1294 {
1295    FileMgrRec *file_mgr_rec = (FileMgrRec *)client_data;
1296    DialogData  * dialog_data;
1297    FileMgrData *file_mgr_data;
1298
1299    doubleClick = False;
1300
1301    /* Got an accelerator after we were unposted */
1302    if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
1303       return;
1304    file_mgr_data = (FileMgrData *) dialog_data->data;
1305
1306    ShowFastChangeDir(file_mgr_rec, file_mgr_data);
1307 }
1308
1309 /************************************************************************
1310  *
1311  *  ResizeFastText - resizes the fast change text widget due to changes
1312  *       in the size of the FileManager window.
1313  *
1314  *************************************************************************/
1315 static void
1316 ResizeFastText(
1317         FileMgrRec *file_mgr_rec,
1318         FileMgrData *file_mgr_data,
1319         short columns)
1320 {
1321    Arg args[2];
1322    Dimension width;
1323    int left_offset;
1324
1325    /* nothing to do if not managed */
1326    if (!XtIsManaged(file_mgr_rec->current_directory_text))
1327       return;
1328
1329    /* get width of current directory line */
1330    XtSetArg (args[0], XmNwidth, &width);
1331    XtGetValues (file_mgr_rec->current_directory, args, 1);
1332
1333    /* get offset of the text widget */
1334    XtSetArg(args[0], XmNleftOffset, &left_offset);
1335    XtGetValues(file_mgr_rec->current_directory_text, args, 1);
1336
1337    /* set text widget width = current_directory width minus left offset */
1338    XtSetArg (args[0], XmNwidth, width - left_offset);
1339    XtSetValues (file_mgr_rec->current_directory_text, args, 1);
1340 }
1341
1342
1343 /*--------------------------------------------------------------------
1344  * get_textwidth
1345  *------------------------------------------------------------------*/
1346
1347 /* use Xmb functions if XFontSet is used. */
1348 static int
1349 get_textwidth( FileMgrData *fmd,
1350                char *str,
1351                int len)
1352 {
1353     int w = 0;
1354
1355     switch(fmd->cd_fonttype)
1356     {
1357         case XmFONT_IS_FONTSET:
1358             w = XmbTextEscapement(fmd->cd_fontset, str, len);
1359             break;
1360         case XmFONT_IS_FONT:
1361             w = XTextWidth(fmd->cd_font, str, len);
1362         default:
1363             break;
1364     }
1365     return(w);
1366 }
1367
1368 static void
1369 draw_imagestring( Display *display,
1370                   Drawable d,
1371                   FileMgrData *fmd,
1372                   GC gc,
1373                   int x, int y,
1374                   char *text,
1375                   int bytes)
1376 {
1377     switch(fmd->cd_fonttype)
1378     {
1379         case XmFONT_IS_FONTSET:
1380             XmbDrawImageString(display, d, fmd->cd_fontset, gc, x, y, text,
1381                                bytes);
1382             break;
1383         case XmFONT_IS_FONT:
1384             XDrawImageString(display, d, gc, x, y, text, bytes);
1385         default:
1386             break;
1387     }
1388 }
1389