cdesktopenv/cde/programs/dtfile/ChangeDirP.c

1393 lines
42 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: ChangeDirP.c /main/8 1998/04/01 15:05:07 rafi $ */
/************************************<+>*************************************
****************************************************************************
*
* FILE: ChangeDirP.c
*
* COMPONENT_NAME: Desktop File Manager (dtfile)
*
* Description: Processing functions for the change directory display
* line and the current directory dialog.
*
* FUNCTIONS: ABS
* CheckCurrentDirectorySelect
* CurrentDirChange
* CurrentDirClose
* CurrentDirDropCallback
* CurrentDirExposed
* CurrentDirIconCallback
* CurrentDirSelected
* CurrentDirectoryIconMotion
* DrawCurrentDirectory
* GetStatusMsg
* ResizeFastText
* ShowChangeDirDialog
* ShowFastChangeDir
* TimerEvent
* draw_imagestring
* get_text_pieces
* get_textwidth
*
* (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
* (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
* (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
* (c) Copyright 1993, 1994, 1995 Novell, Inc.
*
****************************************************************************
************************************<+>*************************************/
#include <limits.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#include <Xm/DrawP.h>
#undef USE_XFT
#include <Xm/TextFP.h>
#include <Xm/PushBG.h>
#include <Xm/DragDrop.h>
#include <Xm/RowColumn.h>
#include <Dt/Icon.h>
#include <Dt/IconP.h>
#include <Dt/DtNlUtils.h>
#include <Dt/Connect.h>
#include <Dt/FileM.h>
#include "Encaps.h"
#include "SharedProcs.h"
#include "Desktop.h"
#include "FileMgr.h"
#include "Main.h"
#include "ChangeDir.h"
#include "Prefs.h"
/******** Static Function Declarations ********/
static void CurrentDirChange(
XtPointer client_data,
DialogData *old_dialog_data,
DialogData *new_dialog_data,
XtPointer call_data) ;
static void CurrentDirClose(
XtPointer client_data,
DialogData *old_dialog_data,
DialogData *new_dialog_data) ;
static void CheckCurrentDirectorySelect(
FileMgrData *file_mgr_data ) ;
static void TimerEvent(
XtPointer client_data,
XtIntervalId *id );
static void ResizeFastText(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
short columns) ;
static int get_textwidth(
FileMgrData *fmd,
char *str,
int len);
static void draw_imagestring(
Display *display,
Drawable d,
FileMgrData *fmd,
GC gc,
int x, int y,
char *text,
int bytes);
/******** End Static Function Declarations ********/
/* absolute value macro */
#ifndef ABS
#define ABS(x) (((x) > 0) ? (x) : (-(x)))
#endif
/* layout constants */
#define CUR_DIR_SPACING 5
/* local global varible to determine whether the user has double clicked
or not */
static Boolean doubleClick = False;
/*--------------------------------------------------------------------
* get_text_pieces:
*
* Given a width available for the current directory text,
* determines the text to be drawn in one of three formats:
*
* /path (non-restricted directory)
* /.../path (restricted directory)
* .../subpath (if the full path wouldn't fit)
*
* Returns the length (in chars) and width (in pixels) of each of
* the two components of the text:
* (1) prefix "/..." or "...", and (2) path or subpath.
* Returns True if the path was chopped because it wouldn't fit.
*
*------------------------------------------------------------------*/
static Boolean
get_text_pieces(
FileMgrData *file_mgr_data,
int width,
char buf[],
int *host_len_p,
int *host_pixels_p,
int *prefix_len_p,
int *prefix_pixels_p,
int *path_len_p,
int *path_pixels_p)
{
Boolean chopped = False;
int prefix_len;
int prefix_pixels;
int path_len;
int path_pixels;
char *path_begin;
char *next_part = NULL;
*host_len_p = *host_pixels_p = 0;
/* if restricted directory, path prefix is "/..." */
if (file_mgr_data->restricted_directory)
{
strcpy(buf, "/...");
prefix_len = strlen("/...");
prefix_pixels = get_textwidth (file_mgr_data, "/...", prefix_len);
path_begin = file_mgr_data->current_directory +
strlen(file_mgr_data->restricted_directory);
if (*path_begin == '\0')
path_begin = "/";
else if (*path_begin != '/')
-- path_begin;
}
else
{
prefix_len = 0;
prefix_pixels = 0;
path_begin = file_mgr_data->current_directory;
}
/* calculate path length & width */
path_len = strlen(path_begin);
path_pixels = get_textwidth (file_mgr_data, path_begin, path_len);
/* if whole path doesn't fit, we need to chop off pieces until it does */
if (prefix_pixels + path_pixels > width)
{
chopped = True;
/* change the path prefix */
strcpy(buf, "...");
prefix_len = strlen("...");
prefix_pixels = get_textwidth (file_mgr_data, "...", prefix_len);
do
{
/* chop off the next piece (everything up to the next '/') */
next_part = NULL;
next_part = DtStrchr(path_begin + 1, '/');
if (next_part == NULL)
{
/* Got here only when the last directory is still too
long to display
*/
break;
}
/* calculate new path length */
path_begin = next_part;
path_len = strlen(path_begin);
path_pixels = get_textwidth (file_mgr_data, path_begin, path_len);
/* keep going until it fits */
} while (prefix_pixels + path_pixels > width);
}
/* add the path to the buffer */
if( NULL == next_part )
{
/* Got here only when the last directory is still too
long to display
*/
int len = path_len;
char saved_char;
while( 0 != len )
{
/* Going back one character at a time to see if it fit
*/
path_pixels = get_textwidth( file_mgr_data, path_begin, len );
if( prefix_pixels + path_pixels < width )
{
break;
}
--len;
}
if( 0 == len )
{
buf[prefix_len] = 0x0;
*path_len_p = 0;
*path_pixels_p = 0;
}
else
{
strncpy (buf + prefix_len, path_begin, len);
*path_len_p = len;
*path_pixels_p = path_pixels;
}
}
else
{
strcpy (buf + prefix_len, path_begin);
*path_len_p = path_len;
*path_pixels_p = path_pixels;
}
/* return values */
*prefix_len_p = prefix_len;
*prefix_pixels_p = prefix_pixels;
return chopped;
}
/************************************************************************
*
* ShowChangeDirDialog
* Callback functions invoked from the Change Directory... menu
* item. This function displays the change directory dialog.
*
************************************************************************/
/*ARGSUSED*/
void
ShowChangeDirDialog(
Widget w,
XtPointer client_data,
XtPointer callback )
{
FileMgrRec * file_mgr_rec;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
ChangeDirData * change_dir_data;
ChangeDirRec * change_dir_rec;
Arg args[1];
Widget mbar;
char *tempStr, *tmpStr;
/* Set the menu item to insensitive to prevent multiple */
/* dialogs from being posted and get the area under the */
/* menu pane redrawn. */
if (w)
{
if((XtArgVal)client_data == FM_POPUP)
mbar = XtParent(w);
else
mbar = (Widget) XmGetPostedFromWidget(XtParent(w));
XmUpdateDisplay (w);
XtSetArg(args[0], XmNuserData, &file_mgr_rec);
XtGetValues(mbar, args, 1);
/* Ignore accelerators when we're insensitive */
if ((file_mgr_rec->menuStates & CHANGEDIR) == 0)
{
XSetInputFocus(XtDisplay(w),
XtWindow(file_mgr_rec->change_directoryBtn_child),
RevertToParent, CurrentTime);
return;
}
}
else
{
/* Done only during a restore session */
file_mgr_rec = (FileMgrRec *)client_data;
}
/* Got an accelerator after we were unposted */
if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
return;
file_mgr_data = (FileMgrData *) dialog_data->data;
change_dir_data = (ChangeDirData *) file_mgr_data->change_dir->data;
change_dir_data->file_mgr_rec = (XtPointer) file_mgr_rec;
file_mgr_rec->menuStates &= ~CHANGEDIR;
_DtShowDialog (file_mgr_rec->shell, (Widget)NULL, (XtPointer)file_mgr_rec,
file_mgr_data->change_dir,
CurrentDirChange, (XtPointer)file_mgr_rec,
CurrentDirClose, (XtPointer)file_mgr_rec, (char *)NULL,
False, False, (char *)NULL, (XClassHint *)NULL);
/* Save a ptr to file_mgr_rec in the find dialogs structure */
change_dir_rec = (ChangeDirRec *)_DtGetDialogInstance(
file_mgr_data->change_dir);
if(file_mgr_data->title != NULL &&
strcmp(file_mgr_data->helpVol, DTFILE_HELP_NAME) != 0)
{
tmpStr = GETMESSAGE(2,15, "Go To");
tempStr = (char *)XtMalloc(strlen(tmpStr) +
strlen(file_mgr_data->title) + 5);
sprintf(tempStr, "%s - %s", file_mgr_data->title, tmpStr);
}
else
{
tmpStr = (GETMESSAGE(2,17, "File Manager - Go To"));
tempStr = XtNewString(tmpStr);
}
XtSetArg (args[0], XmNtitle, tempStr);
XtSetValues (XtParent (change_dir_rec->change_dir), args, 1);
XtFree(tempStr);
file_mgr_rec->change_directoryBtn_child=XtParent (change_dir_rec->change_dir);
}
/************************************************************************
*
* CurrentDirSelected
* When a Button1 selection occurs on the current directory line,
* see if it occurred within the directory path, highlight the
* selected sub-path, or if the sub-path was already highlighted,
* set the current directory to the path and dehighlight.
*
************************************************************************/
void
CurrentDirSelected(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
FileMgrRec *file_mgr_rec = (FileMgrRec *) client_data;
DialogData *dialog_data;
FileMgrData *file_mgr_data;
char buf[2*MAX_PATH];
char host_name[MAX_PATH];
Boolean chopped;
int host_len;
int host_pixels;
int prefix_len;
int prefix_pixels;
int path_len;
int path_pixels;
XmDrawnButtonCallbackStruct *button_data;
XButtonEvent *event;
Dimension width, highlight, shadow, margin;
Arg args[4];
int left_margin;
int begin_x;
int end_x;
int len;
int i;
char *ptr;
char *new_select;
int swidth;
static XtIntervalId TimerId;
/* if doubleClick is true than we have a double click so we want
* to change to the new directory that the user double clicked on
*/
if (doubleClick)
XtRemoveTimeOut(TimerId);
button_data = (XmDrawnButtonCallbackStruct *) call_data;
event = (XButtonEvent *) button_data->event;
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
file_mgr_data = (FileMgrData *) dialog_data->data;
/* Get layout values */
XtSetArg (args[0], XmNwidth, &width);
XtSetArg (args[1], XmNhighlightThickness, &highlight);
XtGetValues (w, args, 2);
XtSetArg (args[0], XmNshadowThickness, &shadow);
XtSetArg (args[1], XmNmarginWidth, &margin);
XtGetValues (file_mgr_rec->current_directory_text, args, 2);
left_margin = highlight + shadow + margin;
/* Get the starting and ending locations of the current */
/* directory text. */
chopped = get_text_pieces(file_mgr_data, width - 2*left_margin,
buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
&path_len, &path_pixels);
begin_x = left_margin;
end_x = begin_x + host_pixels + prefix_pixels + path_pixels;
/* Get the selected path */
if (event->x < begin_x || event->x >= end_x)
{
/* click outside the directory text: nothing selected */
new_select = NULL;
}
else if (event->x < begin_x + host_pixels ||
event->x < begin_x + host_pixels + prefix_pixels && !chopped)
{
/* click on host name or "/..." prefix: root selected */
if (file_mgr_data->restricted_directory)
new_select = XtNewString(file_mgr_data->restricted_directory);
else
new_select = XtNewString("/");
}
else if (event->x < begin_x + host_pixels + prefix_pixels && chopped)
{
/* click on "..." prefix: directory above the visible piece selected */
len = strlen(file_mgr_data->current_directory) - path_len;
new_select = (char *) XtMalloc(len + 1);
memcpy(new_select, file_mgr_data->current_directory, len);
new_select[len] = 0;
}
else /* event->x >= begin_x + host_pixels + prefix_pixels */
{
/* click on the path: determine which subdirectory selected */
begin_x += host_pixels + prefix_pixels;
i = host_len + prefix_len;
swidth = get_textwidth(file_mgr_data, "/", strlen("/")) / 2;
while (begin_x - swidth < event->x)
{
/* find next '/' in path */
ptr = DtStrchr(buf + i, '/');
if (ptr == NULL)
{
i = host_len + prefix_len + path_len + 1;
break;
}
/* get x-position of next path component */
len = ((ptr + 1) - buf) - i;
begin_x += get_textwidth(file_mgr_data, buf + i, len);
i += len;
}
/* if we have a restricted diretory and i == 5 ("/.../") then we want
the len to be the restricted directory */
if (file_mgr_data->restricted_directory && i == 5)
len = strlen(file_mgr_data->restricted_directory);
else
len = strlen(file_mgr_data->current_directory)
- (host_len + prefix_len + path_len - i) - 1;
new_select = (char *) XtMalloc(len + 1);
if (len == 0)
strcpy(new_select, "/");
else
{
memcpy(new_select, file_mgr_data->current_directory, len);
new_select[len] = 0;
}
}
/* in restricted mode, don't allow going above the user's home dir */
if (new_select != NULL && restrictMode)
{
/* check if new_select is the same as or a subdirectory of $HOME */
len = strlen(users_home_dir);
if (strncmp(new_select, users_home_dir, len) != 0
|| new_select[len] != '\0' && new_select[len] != '/')
{
/* change new_select to $HOME */
XtFree(new_select);
new_select = XtNewString(users_home_dir);
}
}
/* If the path is the same as what is already selected, */
/* free cd_select, set the directory to the selected */
/* directory, redraw the directory display. */
/* If the path was different, set cd_select to the */
/* selected directory and redraw the directory. */
if (new_select != NULL && file_mgr_data->cd_select != NULL &&
strcmp(new_select, file_mgr_data->cd_select) == 0)
{
XtFree (file_mgr_data->cd_select);
file_mgr_data->cd_select = NULL;
strcpy(buf, new_select);
strcpy(host_name, file_mgr_data->host);
if (strcmp (buf, file_mgr_data->current_directory) == 0)
FileMgrReread (file_mgr_rec);
else
ShowNewDirectory (file_mgr_data, host_name, buf);
XtFree (new_select);
}
else
{
XtFree (file_mgr_data->cd_select);
file_mgr_data->cd_select = new_select;
}
if (doubleClick)
{
doubleClick = False;
DrawCurrentDirectory (w, file_mgr_rec, file_mgr_data);
}
else
{
doubleClick = True;
TimerId = XtAppAddTimeOut (XtWidgetToApplicationContext (w),
XtGetMultiClickTime(XtDisplay(w)),
(XtTimerCallbackProc) TimerEvent,
(XtPointer) file_mgr_rec);
}
}
/************************************************************************
*
* CurrentDirDropCallback
* Callback function invoked upon an action on the change view drop.
*
************************************************************************/
void
CurrentDirDropCallback(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
XmAnyCallbackStruct * callback;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
char host_name[MAX_PATH];
callback = (XmAnyCallbackStruct *) call_data;
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
file_mgr_data = (FileMgrData *) dialog_data->data;
if (callback->reason == XmCR_DEFAULT_ACTION)
{
strcpy(host_name, file_mgr_data->host);
ShowNewDirectory (file_mgr_data, host_name,
_DtPName (file_mgr_data->current_directory));
}
}
/************************************************************************
*
* CurrentDirIconCallback
* Callback function invoked upon an action occurring on an icon.
*
************************************************************************/
void
CurrentDirIconCallback(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
XmAnyCallbackStruct * callback;
XButtonEvent * event;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
callback = (XmAnyCallbackStruct *) call_data;
event = (XButtonEvent *) callback->event;
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
file_mgr_data = (FileMgrData *) dialog_data->data;
if (callback->reason == XmCR_DRAG)
{
/* Do nothing if a Button 1 drag is already ramping up */
if (B1DragPossible)
return;
/* Save starting X and Y, for threshold detection */
initialDragX = event->x;
initialDragY = event->y;
/* Flag that a Button 2 drag is ramping up */
B2DragPossible = True;
UnpostTextField(file_mgr_data);
}
else if (callback->reason == XmCR_ARM)
{
/* Do nothing if a Button 2 drag is already ramping up */
if (B2DragPossible)
return;
/* Save starting X and Y, for threshold detection */
initialDragX = event->x;
initialDragY = event->y;
/* Flag that a Button 1 drag is ramping up */
B1DragPossible = True;
/* but since we're in the current directory icon we don't want to
process on the button up */
ProcessBtnUpCD = False;
UnpostTextField(file_mgr_data);
}
else if (callback->reason == XmCR_DEFAULT_ACTION)
{
/* We now know that a drag operation won't be starting up */
B1DragPossible = False;
B2DragPossible = False;
UnpostTextField(file_mgr_data);
/* Default action is to reread the directory */
FileMgrReread (file_mgr_rec);
}
else if ((callback->reason == XmCR_SELECT) ||
(callback->reason == XmCR_DISARM) ||
(callback->reason == XmCR_DROP))
{
/* We now know that a drag operation won't be starting up */
B1DragPossible = False;
B2DragPossible = False;
}
}
/*
* This function processes motion events anytime a B1 or B2 drag operation
* has the potential of starting. When the drag threshold is surpassed,
* a drag operation will be started.
*/
void
CurrentDirectoryIconMotion(
Widget w,
XtPointer client_data,
XEvent *event)
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
Pixmap drag_pixmap;
char * type_set;
char * file_set;
int diffX, diffY;
Widget dirIcon;
DtIconGadget iconG;
if ((B1DragPossible && (event->xmotion.state & Button1Mask)) ||
(B2DragPossible && (event->xmotion.state & Button2Mask)))
{
/* Have we passed the drag threshold? */
diffX = initialDragX - event->xmotion.x;
diffY = initialDragY - event->xmotion.y;
if ((ABS(diffX) >= dragThreshold) || (ABS(diffY) >= dragThreshold))
{
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
file_mgr_data = (FileMgrData *) dialog_data->data;
initiating_view = (XtPointer) file_mgr_data;
dirIcon = file_mgr_rec->current_directory_icon;
StartDrag(dirIcon, NULL, event);
}
}
}
/************************************************************************
*
* CurrentDirExposed
* Callback functions invoked from the current directory display
* drawn button. This function extracts some structures and calls
* the directory display function.
*
************************************************************************/
void
CurrentDirExposed(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
/* Check to see if the view has been closed */
if (dialog_data == NULL) return;
file_mgr_data = (FileMgrData *) dialog_data->data;
if (file_mgr_data->cd_normal_gc != 0)
DrawCurrentDirectory (w, file_mgr_rec, file_mgr_data);
}
/************************************************************************
*
* GetStatusMsg
* Construct the status message (normally "x Items, y Hidden").
* Returns True if the message is deemed "important".
*
* @@@ Note 2/17/95: messages below containing "Item(s)" should really
* be just "Item", but the message catalog is frozen at this time, so
* we can't fix this now. (In practice, it doesn't matter, because
* the item count should always be > 1, since every directory shoule
* contain at least two files "." and "..")
*
************************************************************************/
Boolean
GetStatusMsg(
FileMgrData *file_mgr_data,
char *buf )
{
int n_files;
int n_hidden;
int i, j;
TreeShow ts;
FileViewData **file_view_data;
/*
* If we are currently busy reading a directory, display a progress
* message instead of the normal "x Items, y Hidden" message.
*/
if (file_mgr_data->busy_status == initiating_readdir ||
file_mgr_data->busy_status == busy_readdir)
{
if (file_mgr_data->busy_detail == 0)
sprintf (buf, "%s", (GETMESSAGE(3,5, "Reading ...")));
else if (file_mgr_data->busy_detail == 1)
sprintf (buf, (GETMESSAGE(3,11, "%d Item(s)...")),
file_mgr_data->busy_detail);
else
sprintf (buf, (GETMESSAGE(3,9, "%3d Items ...")),
file_mgr_data->busy_detail);
return True; /* this message deemed important! */
}
else if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
{
/*
* In tree mode, we only show a count of the hidden files
* in branches that are currently expanded.
* The idea is we want to show how many additional files would
* show up if the user turned on the "Show Hidden" option.
*/
n_hidden = 0;
for (i = 0; i < file_mgr_data->directory_count; i++)
{
file_view_data = file_mgr_data->directory_set[i]->file_view_data;
if (file_view_data == NULL)
continue;
ts = file_mgr_data->directory_set[i]->sub_root->ts;
if (ts < tsDirs)
continue; /* this branch is not expanded */
for (j = 0; j < file_mgr_data->directory_set[i]->file_count; j++)
{
if (file_view_data[j]->filtered &&
(ts == tsAll || file_view_data[j]->file_data->is_subdir))
{
n_hidden++;
}
}
}
sprintf (buf, (GETMESSAGE(3,6, "%d Hidden")), n_hidden);
return False;
}
else
{
/*
* In flat mode, we only show a total count of all files
* and a count of hidden files.
*/
n_files = file_mgr_data->directory_set[0]->file_count;
if( n_files == 0 )
sprintf( buf, (GETMESSAGE(11,31, "Error while reading %s")), file_mgr_data->current_directory );
else if( file_mgr_data == trashFileMgrData )
{
n_hidden = file_mgr_data->directory_set[0]->filtered_file_count;
sprintf (buf, (GETMESSAGE(3,10, "%d Item(s)")),
n_files - n_hidden);
}
else
{
n_files -= file_mgr_data->directory_set[0]->invisible_file_count;
n_hidden = file_mgr_data->directory_set[0]->filtered_file_count -
file_mgr_data->directory_set[0]->invisible_file_count;
if (n_files == 1)
sprintf (buf, (GETMESSAGE(3,12, "%d Item(s) %d Hidden")),
n_files, n_hidden);
else
sprintf (buf, (GETMESSAGE(3,7, "%d Items %d Hidden")),
n_files, n_hidden);
}
return False;
}
}
/************************************************************************
*
* DrawCurrentDirectory
* Draw the current directory display area, including the hostname,
* the current directory, any highlighted sub-path of the directory,
* the file count and the number of selected files.
*
************************************************************************/
void
DrawCurrentDirectory(
Widget w,
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data )
{
Arg args[8];
Dimension width, height, highlight, shadow, margin, twidth;
XFontSetExtents *extents;
int font_height;
int font_yoffset;
int top_margin;
int left_margin;
char buf[2*MAX_PATH];
char msg[21+MAX_PATH];
Boolean chopped;
int host_len;
int host_pixels;
int prefix_len;
int prefix_pixels;
int path_len;
int path_pixels;
int draw_x;
int draw_y;
int dir_width;
int msg_width = 0;
short columns;
Boolean msg_drawn;
/* Get layout values */
XtSetArg (args[0], XmNwidth, &width);
XtSetArg (args[1], XmNheight, &height);
XtSetArg (args[2], XmNhighlightThickness, &highlight);
XtGetValues (w, args, 3);
XtSetArg (args[0], XmNshadowThickness, &shadow);
XtSetArg (args[1], XmNmarginWidth, &margin);
XtGetValues (file_mgr_rec->current_directory_text, args, 2);
if(file_mgr_data->cd_fonttype == XmFONT_IS_FONTSET) {
extents = XExtentsOfFontSet(file_mgr_data->cd_fontset);
font_yoffset = -(extents->max_logical_extent.y);
font_height = extents->max_logical_extent.height;
}
else
{
font_yoffset = file_mgr_data->cd_font->ascent;
font_height = file_mgr_data->cd_font->ascent +
file_mgr_data->cd_font->descent;
}
top_margin = (height > (Dimension)font_height)? (Dimension)(height - font_height + 1)/(Dimension)2: 0;
left_margin = highlight + shadow + margin;
/* Ensure the area is cleared out. */
XClearArea (XtDisplay (w), XtWindow (w),
highlight, highlight,
width - 2*highlight, height - 2*highlight,
False);
/*
* If there is no status line and no iconic path,
* we will want yo draw the "x Files y Hidden" message here.
*/
if (!file_mgr_data->show_iconic_path && !file_mgr_data->show_status_line)
{
/*
* GetStatusMsg() returns True if the status msg is "important".
* In this case, make sure we leave room for it
*/
msg_drawn = GetStatusMsg(file_mgr_data, msg);
msg_width = get_textwidth (file_mgr_data, msg, strlen(msg));
}
else
msg_drawn = False;
draw_x = left_margin;
if( draw_x < 0 || (Dimension) draw_x > width ) /* Make sure that it's in bound */
draw_x = 0;
draw_y = top_margin + font_yoffset;
if( draw_y < 0 || (Dimension) draw_y > height ) /* Make sure that it's in bound */
{
draw_y = height-5;
}
/* get the text pieces */
dir_width = width - 2*left_margin;
if (msg_drawn)
dir_width -= CUR_DIR_SPACING + msg_width;
chopped = get_text_pieces(file_mgr_data, dir_width,
buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
&path_len, &path_pixels);
/*
* go check and change the file_mgr_data->cd_select, make sure its not
* longer than the file_mgr_data->current_directory.
*/
CheckCurrentDirectorySelect(file_mgr_data);
/* draw the host and paths */
if (!file_mgr_data->fast_cd_enabled)
{
draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
file_mgr_data->cd_normal_gc, draw_x, draw_y,
buf, host_len + prefix_len + path_len);
}
else if (file_mgr_data->restricted_directory)
{
draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
file_mgr_data->cd_normal_gc, draw_x, draw_y,
buf, host_len + prefix_len);
}
/*
* If there is no status line and no iconic path, and we have
* room left, draw the "x Files y Hidden" message here.
*/
if (!file_mgr_data->show_iconic_path && !file_mgr_data->show_status_line)
{
/* determine where the message could begin */
if (!file_mgr_data->fast_cd_enabled)
draw_x += host_pixels + prefix_pixels + path_pixels;
else
{
XtSetArg(args[0], XmNwidth, &twidth);
XtGetValues(file_mgr_rec->current_directory_text, args, 1);
if (file_mgr_data->restricted_directory && !chopped)
draw_x += host_pixels + prefix_pixels + twidth;
else
draw_x += host_pixels + twidth;
}
/* if there is enough space left, draw the message */
if ((Dimension)(draw_x + CUR_DIR_SPACING + msg_width + left_margin) <= width)
{
draw_x = width - left_margin - msg_width;
draw_imagestring (XtDisplay (w), XtWindow (w), file_mgr_data,
file_mgr_data->cd_normal_gc, draw_x, draw_y,
msg, strlen(msg));
draw_x -= shadow + CUR_DIR_SPACING; /* right edge of shadow */
msg_drawn = True;
}
else
msg_drawn = False;
}
if (!msg_drawn)
draw_x = width - (highlight + shadow);
/* draw the shadow */
if (!file_mgr_data->fast_cd_enabled)
{
int shadow_width = draw_x - highlight;
int shadow_height = height - 2*highlight;
XmTextFieldWidget tf =
(XmTextFieldWidget)file_mgr_rec->current_directory_text;
XmeDrawShadows(XtDisplay(w), XtWindow(w),
tf->primitive.top_shadow_GC,
tf->primitive.bottom_shadow_GC,
highlight, highlight, shadow_width, shadow_height,
shadow, XmSHADOW_IN);
}
}
/************************************************************************
*
* CurrentDirChange
* Callback functions invoked from the current directory dialog's
* apply button being pressed. This function updates and redisplays
* the current directory information.
*
************************************************************************/
static void
CurrentDirChange(
XtPointer client_data,
DialogData *old_dialog_data,
DialogData *new_dialog_data,
XtPointer call_data )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
ChangeDirData * new_change_dir_data;
ChangeDirData * old_change_dir_data;
char path[MAX_PATH];
char host_name[MAX_PATH];
char * ptr;
/* Get a pointer file manager's data structure, free up the */
/* old current directory and copy in a new one. Free up the */
/* old selected sub-path, update the file manager's internal */
/* data, and redraw the directory. */
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
file_mgr_data = (FileMgrData *) dialog_data->data;
if (file_mgr_data->cd_select != NULL)
{
XtFree (file_mgr_data->cd_select);
file_mgr_data->cd_select = NULL;
}
old_change_dir_data = (ChangeDirData *) file_mgr_data->change_dir->data;
new_change_dir_data = (ChangeDirData *) new_dialog_data->data;
new_change_dir_data->host_name = XtNewString(old_change_dir_data->host_name);
new_change_dir_data->file_mgr_rec = old_change_dir_data->file_mgr_rec;
_DtHideDialog(old_dialog_data, False);
new_change_dir_data->displayed = False;
file_mgr_data->change_dir->data = (XtPointer) new_change_dir_data;
new_dialog_data->data = (XtPointer) old_change_dir_data;
_DtFreeDialogData (new_dialog_data);
file_mgr_rec->menuStates |= CHANGEDIR;
/* Process call_data into a hostname and directory name. */
ShowNewDirectory (file_mgr_data,
((ChangeDirData *)file_mgr_data->change_dir->data)->host_name,
call_data);
}
/************************************************************************
*
* CurrentDirClose
* Callback functions invoked from the current directory dialog's
* close button being pressed. This function resensitizes the
* Change Directory... menu item.
*
************************************************************************/
/*ARGSUSED*/
static void
CurrentDirClose(
XtPointer client_data,
DialogData *old_dialog_data,
DialogData *new_dialog_data )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) client_data;
_DtFreeDialogData (new_dialog_data);
file_mgr_rec->menuStates |= CHANGEDIR;
}
/************************************************************************
*
* CheckCurrentDirectorySelect
* Before calling DrawCurrentDirectorySelect() this function
* makes sure that the fm->cd_select isn't longer than the
* fm->current_directory. If it is it reconfigures fm->cd_select
* to hold no more than what fm->current_directory is.
*
************************************************************************/
static void
CheckCurrentDirectorySelect(
FileMgrData *file_mgr_data )
{
int length_cd, length_cd_s;
char *str, *ptr;
if (file_mgr_data == NULL ||
file_mgr_data->cd_select == NULL ||
file_mgr_data->current_directory == NULL)
return;
/* get the true lengths of current_directory and current_directory_select */
length_cd = strlen(file_mgr_data->current_directory);
length_cd_s = strlen(file_mgr_data->cd_select);
/* if cd is larger than cd_select than we have now problem */
if(length_cd >= length_cd_s)
return;
/* we need to recalculate the cd_select */
str = XtNewString(file_mgr_data->cd_select);
while(1)
{
ptr = strrchr(str, '/');
*ptr = '\0';
length_cd_s = strlen(str);
if(length_cd > length_cd_s)
{
XtFree(file_mgr_data->cd_select);
file_mgr_data->cd_select = (char *)XtMalloc(strlen(str) + 1);
strcpy(file_mgr_data->cd_select, str);
XtFree(str);
return;
}
}
}
/************************************************************************
*
* ShowFastChangeDir
* Post the fast change to text widget.
*
***************************************************************************/
void
ShowFastChangeDir(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data )
{
char *textString;
Arg args[16];
Dimension width, height;
Dimension shadow, highlight, margin;
char buf[2*MAX_PATH];
Boolean chopped;
int host_len;
int host_pixels;
int prefix_len;
int prefix_pixels;
int path_len;
int path_pixels;
int begin_x;
int left_margin;
doubleClick = False;
XtRemoveAllCallbacks (file_mgr_rec->current_directory, XmNexposeCallback);
XtFree (file_mgr_data->cd_select);
file_mgr_data->cd_select = NULL;
file_mgr_data->fast_cd_enabled = True;
/* if not a toolbox, just put the current directory in text widget */
if (file_mgr_data->restricted_directory == NULL)
{
if (strcmp(file_mgr_data->host, home_host_name) == 0)
textString = XtNewString(file_mgr_data->current_directory);
else
textString = DtCreateContextString(file_mgr_data->host,
file_mgr_data->current_directory,
NULL);
}
else /* is a toolbox, so put the subset of what the toolbox is in the text*/
{
char *ptr;
ptr = file_mgr_data->current_directory +
strlen(file_mgr_data->restricted_directory);
if (strcmp(ptr, "") == 0)
textString = XtNewString("/");
else
textString = XtNewString(ptr);
}
begin_x = get_textwidth (file_mgr_data, textString, strlen (textString));
/* Get layout values */
XtSetArg (args[0], XmNwidth, &width);
XtSetArg (args[1], XmNhighlightThickness, &highlight);
XtGetValues (file_mgr_rec->current_directory, args, 2);
XtSetArg (args[0], XmNshadowThickness, &shadow);
XtSetArg (args[1], XmNmarginWidth, &margin);
XtGetValues (file_mgr_rec->current_directory_text, args, 2);
left_margin = highlight + shadow + margin;
if(file_mgr_data->restricted_directory == NULL)
XtSetArg (args[0], XmNleftOffset, 0);
else
{
XtSetArg (args[0], XmNshadowThickness, &shadow);
XtSetArg (args[1], XmNhighlightThickness, &highlight);
XtGetValues(file_mgr_rec->current_directory_text, args, 2);
chopped =
get_text_pieces(file_mgr_data, width - 2*left_margin,
buf, &host_len, &host_pixels, &prefix_len, &prefix_pixels,
&path_len, &path_pixels);
begin_x = left_margin + host_pixels - shadow - highlight;
if (!chopped)
begin_x += prefix_pixels;
XtSetArg (args[0], XmNleftOffset, begin_x);
}
XtSetArg (args[1], XmNvalue, textString);
XtSetValues(file_mgr_rec->current_directory_text, args, 2);
XtSetArg (args[0], XmNcursorPosition, strlen(textString));
XtSetValues(file_mgr_rec->current_directory_text, args, 1);
XtSetArg (args[0], XmNallowShellResize, False);
XtSetValues(file_mgr_rec->shell, args, 1);
XtManageChild(file_mgr_rec->current_directory_text);
XtSetArg (args[0], XmNallowShellResize, True);
XtSetValues(file_mgr_rec->shell, args, 1);
XRaiseWindow(XtDisplay(file_mgr_rec->current_directory_text),
XtWindow(file_mgr_rec->current_directory_text));
XmUpdateDisplay(file_mgr_rec->current_directory_text);
XmProcessTraversal(file_mgr_rec->current_directory_text,
XmTRAVERSE_CURRENT);
XtFree(textString);
XtAddCallback (file_mgr_rec->current_directory, XmNexposeCallback,
CurrentDirExposed, file_mgr_rec);
}
/************************************************************************
*
* TimerEvent - timeout for double click on current Directory line. If
* we get here we know it was a single click so lets post the
* fast change to text widget.
*
***************************************************************************/
static void
TimerEvent(
XtPointer client_data,
XtIntervalId *id )
{
FileMgrRec *file_mgr_rec = (FileMgrRec *)client_data;
DialogData * dialog_data;
FileMgrData *file_mgr_data;
doubleClick = False;
/* Got an accelerator after we were unposted */
if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
return;
file_mgr_data = (FileMgrData *) dialog_data->data;
ShowFastChangeDir(file_mgr_rec, file_mgr_data);
}
/************************************************************************
*
* ResizeFastText - resizes the fast change text widget due to changes
* in the size of the FileManager window.
*
*************************************************************************/
static void
ResizeFastText(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
short columns)
{
Arg args[2];
Dimension width;
int left_offset;
/* nothing to do if not managed */
if (!XtIsManaged(file_mgr_rec->current_directory_text))
return;
/* get width of current directory line */
XtSetArg (args[0], XmNwidth, &width);
XtGetValues (file_mgr_rec->current_directory, args, 1);
/* get offset of the text widget */
XtSetArg(args[0], XmNleftOffset, &left_offset);
XtGetValues(file_mgr_rec->current_directory_text, args, 1);
/* set text widget width = current_directory width minus left offset */
XtSetArg (args[0], XmNwidth, width - left_offset);
XtSetValues (file_mgr_rec->current_directory_text, args, 1);
}
/*--------------------------------------------------------------------
* get_textwidth
*------------------------------------------------------------------*/
/* use Xmb functions if XFontSet is used. */
static int
get_textwidth( FileMgrData *fmd,
char *str,
int len)
{
int w = 0;
switch(fmd->cd_fonttype)
{
case XmFONT_IS_FONTSET:
w = XmbTextEscapement(fmd->cd_fontset, str, len);
break;
case XmFONT_IS_FONT:
w = XTextWidth(fmd->cd_font, str, len);
default:
break;
}
return(w);
}
static void
draw_imagestring( Display *display,
Drawable d,
FileMgrData *fmd,
GC gc,
int x, int y,
char *text,
int bytes)
{
switch(fmd->cd_fonttype)
{
case XmFONT_IS_FONTSET:
XmbDrawImageString(display, d, fmd->cd_fontset, gc, x, y, text,
bytes);
break;
case XmFONT_IS_FONT:
XDrawImageString(display, d, gc, x, y, text, bytes);
default:
break;
}
}