Files
cdesktop/cde/programs/dtfile/File.c
Jon Trulson c936a8c065 dtfile/File.c: implement a hack to fix Ticket #19, tree icons are black
The real issue seems to be a bug in Motif.  The background color for
these tree icons is always black.  Depending on what Palette you have
selected, it's possible for the foreground color to be black.  When
this happens, you will see a black square since both fg and bg are now
black.

You can select another Palette that works (ie: foreground is white)
and the problem goes away.  So, for now, we always force a white
foreground color so the actual symbols are visible in tree mode.
2018-04-29 20:01:43 -06:00

9082 lines
269 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: File.c /main/22 1999/12/09 13:05:50 mgreess $ */
/************************************<+>*************************************
****************************************************************************
*
* FILE: File.c
*
* COMPONENT_NAME: Desktop File Manager (dtfile)
*
* Description: File processing functions.
*
* FUNCTIONS: ABS
* AddFileIcons
* BuildObjectPositions
* CommitWorkProcUpdates
* CompressObjectList
* CopyOrderedEntries
* CreateNameChangeDialog
* CreateTreeIcons
* DeselectAllFiles
* DeselectFile
* DestroyIconName
* DisplaySomeIcons
* DisplayWorkProc
* DragFinishCB
* DrawingAreaRedisplay
* DropOnRootCB
* EraseTreeLines
* EstimateIconSize
* FileConvertCB
* FileDateAscending
* FileDateDescending
* FileIconMotion
* FileIsSelected
* FileNameAscending
* FileNameDescending
* FileSizeAscending
* FileSizeDescending
* FileTypeAscending
* FileTypeDescending
* FilterFiles
* FindCurrentPosition
* FlattenTree
* FmPopup
* FreeLayoutData
* GetAncestorInfo
* GetBottomOfStack
* GetDirName
* GetDragIcon
* GetDragIconMask
* GetExtraHeight
* GetFullName
* GetIconLayoutParms
* GetInsertPosition
* GetLevel
* GetPositionalData
* GetSelectedCount
* GetStrcollProc
* GetTopOfStack
* GetTreebtnPixmap
* HorizontalScrollbarIsVisible
* IconCallback
* InMultipleObjectRegion
* InitiateIconDrag
* IntersectRects
* IsButtonOrMotion
* IsDesktopPtr
* LayoutDesktopIcons
* LayoutFileIcons
* MakeReuseList
* NewConvertDelete
* NewConvertFileName
* OrderChildrenList
* OrderFiles
* PositionDesktopIcon
* PositionFileView
* RedisplayUsingStackingOrder
* RedrawOneGadget
* RedrawTreeLines
* RegisterDesktopHotspots
* RelocateDesktopIcon
* ReorderChildrenList
* RepaintDesktop
* RepairFileWindow
* RepairStackingPointers
* RepositionIcons
* RepositionUpInStack
* RestorePositionalData
* SavePositionalData
* SelectAllFiles
* SelectFile
* SetFileSelected
* SetFileUnselected
* SetHotRects
* SetToNormalColors
* SetToSelectColors
* SpecialCases
* StartDrag
* StrCaseCmp
* ToBeManaged
* TreeBtnCallback
* TreeLX
* TreeOneWd
* TreeWd
* TypeToAction
* TypeToDropOperations
* UnmanageFileIcons
* UnpostTextField
* UnpostTextPath
* UpdateFileIcons
* UpdateOneFileIcon
* UpdateOneIconLabel
* VerticalScrollbarIsVisible
* WidgetCmp
* YSPACING
* _UpdateFileIcons
* InputForGadget
* InputInGadget
*
* (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 <string.h>
#include <locale.h>
#include <ctype.h>
#include <fnmatch.h>
#include <Xm/XmP.h>
#include <Xm/Xm.h>
#include <Xm/BulletinB.h>
#include <Xm/MwmUtil.h>
#include <X11/ShellP.h>
#include <X11/Shell.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifndef XK_MISCELLANY
#define XK_MISCELLANY
#endif
#include <X11/keysymdef.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#include <Xm/DrawingA.h>
#include <Xm/DrawingAP.h>
#include <Xm/RowColumn.h>
#include <Xm/LabelG.h>
#include <Xm/PushBG.h>
#include <Xm/ToggleBG.h>
#include <Xm/SeparatoG.h>
#include <Xm/ScrollBar.h>
#include <Xm/ScrolledW.h>
#include <Xm/TextF.h>
#include <Xm/Frame.h>
#include <Xm/Screen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <Dt/Icon.h>
#include <Dt/IconP.h>
#include <Dt/IconFile.h>
#include <Xm/DragIcon.h>
#include <Xm/DragC.h>
#include <Dt/Dnd.h>
#include <time.h>
#include <utime.h>
#include <Dt/Action.h>
#include <Dt/Connect.h>
#include <Dt/Wsm.h>
#include <Dt/DtNlUtils.h>
#include <Dt/HourGlass.h>
#include <Dt/Dts.h>
#include <Dt/UserMsg.h>
#include <Dt/SharedProcs.h>
#include <Tt/tttk.h>
#include <Xm/XmPrivate.h> /* _XmIsEventUnique _XmSetInDragMode _XmRecordEvent */
#include "Encaps.h"
#include "SharedProcs.h"
#include "FileMgr.h"
#include "Desktop.h"
#include "Main.h"
#include "Prefs.h"
#include "Common.h"
#include "Filter.h"
#include "Help.h"
#include "SharedMsgs.h"
extern Widget _DtDuplicateIcon ( Widget, Widget, XmString, String, XtPointer, Boolean );
/* absolute value macro */
#ifndef ABS
#define ABS(x) (((x) > 0) ? (x) : (-(x)))
#endif
#define INIT_VALUE 5
/*
* MAXWINSIZE: maximum width of the file window
*
* Note: the file window width and height can't exceed the maximum value
* for a short (32767), because x and y coords of the icon gadgets placed
* in the file window are stored as short's by the Xt library (the
* Position type is a short).
* Furthermore, somewhere in the code for registering icon drop sites
* in libDt or libXm calculations are done that overflow if the window
* size is too close to the maximum of 32767. The symptom is observed
* most easily in tree mode on a directory large enough for icons to
* overflow into a second column: for values of MAXWINSIZE of 32767,
* none of the icons are sensitive as drop sites any more. The value
* for MAXWINSIZE defined below has been found to be "safe" by experiment.
*/
#define MAXWINSIZE 32600
/******** Static Function Declarations ********/
static int FileNameAscending(
FileViewData **t1,
FileViewData **t2) ;
static int FileNameDescending(
FileViewData **t1,
FileViewData **t2) ;
static int FileTypeAscending(
FileViewData **t1,
FileViewData **t2) ;
static int FileTypeDescending(
FileViewData **t1,
FileViewData **t2) ;
static int FileSizeAscending(
FileViewData **t1,
FileViewData **t2) ;
static int FileSizeDescending(
FileViewData **t1,
FileViewData **t2) ;
static int FileDateAscending(
FileViewData **t1,
FileViewData **t2) ;
static int FileDateDescending(
FileViewData **t1,
FileViewData **t2) ;
static void CompressObjectList (
ObjectPosition ** object_positions,
int num_objects,
int starting_index) ;
static ObjectPosition *GetPositionalData (
FileMgrData * file_mgr_data,
FileViewData * object,
Dimension max_width,
Boolean create) ;
static void RedisplayUsingStackingOrder (
FileMgrData * file_mgr_data,
Widget w,
register XEvent *event,
Region region) ;
static void ReorderChildrenList (
XmManagerWidget file_window,
Widget * manage,
int manageCount,
Widget * unmanage,
int unmanageCount) ;
static Boolean IsDesktopPtr (
FileViewData * fileViewData,
FileMgrData ** fileMgrData,
DesktopRec ** desktopRec) ;
static Boolean IntersectRects(
Position x1,
Position y1,
Dimension w1,
Dimension h1,
Position x2,
Position y2,
Dimension w2,
Dimension h2 ) ;
static void InitiateIconDrag(
FileViewData * fileViewData,
int rootX,
int rootY,
XEvent * event );
static void RelocateDesktopIcon(
DesktopRec * desktopRec,
int root_x,
int root_y);
static void BuildObjectPositions(
FileMgrData *file_mgr_data);
static void moveCopyLinkCancel(
Widget w,
XtPointer client_data,
XtPointer call_data );
static void moveCopyLinkOK(
Widget w,
XtPointer client_data,
XtPointer call_data );
static void DropOnRootCB (
Widget w,
XtPointer client_data,
XtPointer call_data);
static void _UpdateFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
Boolean new_directory,
DirectorySet * add_dir_set );
static void CreateTreeIcons(
Widget w);
static void TreeBtnCallback(
Widget w,
XtPointer clientData,
XmAnyCallbackStruct * callData );
static void LayoutDesktopIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
FileViewData ** order_list,
int order_count,
Boolean turn_off_hourglass);
static XmGadget InputInGadget (
Widget w,
register int x,
register int y);
static XmGadget InputForGadget (
Widget cw,
int x,
int y);
/******** End Static Function Declarations ********/
/* cursor for double-click-drag (@@@ should be a resource) */
static Cursor loc_cursor1 = None;
static Cursor loc_cursor2 = None;
#define DBLCLICK_DRAG_THRESHOLD 20
/* layout constants (@@@ could be made resources) */
#define MARGIN 5
#define XSPACING 5
#define YSPACING(fmd) \
(fmd->layout_data? \
(fmd->view != BY_NAME? - ((IconLayoutData *)fmd->layout_data)->highlight: \
- ((IconLayoutData *)fmd->layout_data)->highlight + 2): \
0)
#define TreeSep 5
#define TreeOffset 15
#define TreeOneWd(sz) (TreeOffset + TreeBtnWd[sz]/2)
#define TreeLX(level,sz) (TreeBtnWd[sz]/2 + ((level) - 1)*TreeOneWd(sz))
#define TreeWd(level,sz) \
(TreeLX(level,sz) + TreeOffset + TreeBtnWd[sz] + TreeSep)
/* maximum size of the small, medium, and large tree buttons */
static int TreeBtnWd[3] = { 0, 0, 0 };
static int TreeBtnHt[3] = { 0, 0, 0 };
static int TreeNilWd[3] = { 0, 0, 0 };
static int TreeNilHt[3] = { 0, 0, 0 };
/* tree expansion circle pixmap indices */
typedef enum {
tpxNotRead, /* dotted circle */
tpxError, /* crossed circle */
tpxMore, /* "+" circle */
tpxLess, /* "-" circle */
tpxBoth, /* "+/-" circle */
tpxEmpty, /* empty circle */
tpxNil, /* empty-set symbol */
tpxN
} TreePxId;
/* pixmaps for expand circles in tree mode */
static struct TreePx {
char *name; /* name of pixmap file */
Pixmap px[3]; /* small, medium, and large pixmap */
} TreePxTab[tpxN] =
{
{ "Dttvnor", 0 },
{ "Dttverr", 0 },
{ "Dttvmor", 0 },
{ "Dttvlss", 0 },
{ "Dttvbth", 0 },
{ "Dttvemp", 0 },
{ "Dttvnil", 0 },
};
static char *TreePxSuffix[3] = { ".s", ".m", ".l" };
/* value need to to convert drop position to icon placement */
static int dragIconPixmapOffsetX;
static int dragIconPixmapOffsetY;
/* Local defines */
#define FILE_MOVE 0
#define FILE_COPY 1
#define FILE_INVALID 2
FileMgrPopup fileMgrPopup = {NULL};
/* Obsolete Motif highlighting and unhighlighting routines */
extern void _XmHighlightBorder(Widget w);
extern void _XmUnhighlightBorder(Widget w);
extern void SelectDTFile (DesktopRec *desktopWindow);
/************************************************************************
************************************************************************
*
* Comparison functions used for sorting the files
*
************************************************************************
************************************************************************/
/* only use when LANG=C on platforms that don't
provide strcasecmp(). Otherwise, use strcoll() */
static int
StrCaseCmp (
const char *s1,
const char *s2)
{
/* Note: This is not really a string case insensitive compare. So don't
even think of replacing it with any other library routines.
*/
char *s1a = (char *)s1, *s2a = (char *)s2;
if (s1 == s2) return 0;
for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) {
if (*s1 == '\0' )
{
/* File Manager depends heavily on this routine to position the
icons in its window.
We want case INSENSITIVE comparision, however when we have
2 same size and case equivalent strings i.e. "A" and "a", we
need this routine to behave like a case SENSITIVE comparision, so
the position of the icon is constant so "A" is always
before "a".
*/
if (*s2 == 0x0)
{
for (; *s1a == *s2a; ++s1a, ++s2a) {
if (*s1 == '\0' )
return 0;
}
return *s1a - *s2a;
}
else
return 0;
}
}
return tolower(*s1) - tolower(*s2);
}
StrcollProc FMStrcoll = NULL;
StrcollProc
GetStrcollProc(void)
{
int Clang = 0;
#if defined(__hpux)
struct locale_data * li;
#else
char * locale;
#endif
#define C_LANG "C"
/* if locale is C, use the explicit case insensitive compare */
#if defined(__hpux)
li = getlocale(LOCALE_STATUS);
if ( NULL == li->LC_COLLATE_D || strcmp(C_LANG,li->LC_COLLATE_D) == 0 )
Clang = 1;
#else
locale = setlocale(LC_COLLATE,NULL); /* put locale in buf */
if (strcmp(locale,C_LANG) == 0)
Clang = 1;
#endif
if (Clang)
return StrCaseCmp;
return ((StrcollProc)strcoll);
}
static Boolean
SpecialCases(
FileViewData **t1,
FileViewData **t2,
int *rc )
{
/* Tree mode */
if (((FileMgrData *)((DirectorySet *)((*t1)->directory_set))->file_mgr_data)
->show_type == MULTIPLE_DIRECTORY)
{
if (!(*t1)->file_data->is_subdir && (*t2)->file_data->is_subdir)
*rc = -1;
else if ((*t1)->file_data->is_subdir && !(*t2)->file_data->is_subdir)
*rc = 1;
else
return False;
return True;
}
/* Special files */
if (FMStrcoll ((*t1)->file_data->file_name, "." ) == 0 )
{
*rc = -1;
return True;
}
if (FMStrcoll ((*t1)->file_data->file_name, "..") == 0 )
{
if ( FMStrcoll ((*t2)->file_data->file_name, ".") == 0 )
*rc = 1;
else
*rc = -1;
return True;
}
if (FMStrcoll ((*t2)->file_data->file_name, ".") == 0 || FMStrcoll ((*t2)->file_data->file_name, "..") == 0)
{
*rc = 1;
return True;
}
/* Directories */
if (!(*t1)->file_data->is_subdir && (*t2)->file_data->is_subdir)
{
*rc = 1;
return True;
}
if ((*t1)->file_data->is_subdir && !(*t2)->file_data->is_subdir)
{
*rc = -1;
return True;
}
return False;
}
static int
FileNameAscending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if((*t1)->file_data->action_name == NULL)
{
if((*t2)->file_data->action_name == NULL)
rc = FMStrcoll((*t1)->file_data->file_name,
(*t2)->file_data->file_name);
else
rc = FMStrcoll((*t1)->file_data->file_name,
(*t2)->file_data->action_name);
}
else
{
if((*t2)->file_data->action_name != NULL)
rc = FMStrcoll((*t1)->file_data->action_name,
(*t2)->file_data->action_name);
else
rc = FMStrcoll((*t1)->file_data->action_name,
(*t2)->file_data->file_name);
}
return rc;
}
static int
FileNameDescending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if((*t1)->file_data->action_name == NULL)
{
if((*t2)->file_data->action_name == NULL)
rc = FMStrcoll((*t1)->file_data->file_name,
(*t2)->file_data->file_name);
else
rc = FMStrcoll((*t1)->file_data->file_name,
(*t2)->file_data->action_name);
}
else
{
if((*t2)->file_data->action_name != NULL)
rc = FMStrcoll((*t1)->file_data->action_name,
(*t2)->file_data->action_name);
else
rc = FMStrcoll((*t1)->file_data->action_name,
(*t2)->file_data->file_name);
}
if (rc <= -1)
return 1;
if (rc >= 1)
return -1;
return 0;
}
static int
FileTypeAscending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
rc = strcoll( (*t1)->file_data->logical_type, (*t2)->file_data->logical_type );
if( rc == 0 )
rc = FileNameAscending( t1, t2 );
return rc;
}
static int
FileTypeDescending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
rc = strcoll( (*t1)->file_data->logical_type, (*t2)->file_data->logical_type );
if (rc <= -1)
return 1;
if (rc >= 1)
return -1;
rc = FileNameDescending( t1, t2 );
return rc;
}
static int
FileSizeAscending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if ((*t1)->file_data->stat.st_size < (*t2)->file_data->stat.st_size)
return -1;
else if ((*t1)->file_data->stat.st_size > (*t2)->file_data->stat.st_size)
return 1;
return 0;
}
static int
FileSizeDescending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if ((*t1)->file_data->stat.st_size < (*t2)->file_data->stat.st_size)
return 1;
if ((*t1)->file_data->stat.st_size > (*t2)->file_data->stat.st_size)
return -1;
return 0;
}
static int
FileDateAscending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if ((*t1)->file_data->stat.st_mtime < (*t2)->file_data->stat.st_mtime)
return -1;
if ((*t1)->file_data->stat.st_mtime > (*t2)->file_data->stat.st_mtime)
return 1;
return 0;
}
static int
FileDateDescending(
FileViewData **t1,
FileViewData **t2 )
{
int rc;
if( SpecialCases( t1, t2, &rc ) )
return rc;
if ((*t1)->file_data->stat.st_mtime < (*t2)->file_data->stat.st_mtime)
return 1;
if ((*t1)->file_data->stat.st_mtime > (*t2)->file_data->stat.st_mtime)
return -1;
return 0;
}
/************************************************************************
*
* OrderFiles
* Sort the file display list according to the ordering data.
*
************************************************************************/
void
OrderFiles(
FileMgrData *file_mgr_data,
DirectorySet *directory_set )
{
FileViewData ** file_view_data;
int file_count;
FileViewData ** order_list;
int * sort;
int * sub_sort;
register int i;
register int start;
file_view_data = directory_set->file_view_data;
file_count = directory_set->file_count;
/* Allocate an ordering list */
if (directory_set->order_list != NULL)
{
XtFree ((char *) directory_set->order_list);
directory_set->order_list = NULL;
}
if (file_count > 0)
directory_set->order_list = order_list =
(FileViewData **) XtMalloc (sizeof (FileViewData **) * file_count);
else
directory_set->order_list = order_list = NULL;
/* Get pointers to all of the file data into the order list */
for (i = 0; i < file_count; i++)
order_list[i] = file_view_data[i];
/* Set up the sorting functions according to the order and direction. */
sub_sort = NULL;
if (file_mgr_data->order == ORDER_BY_FILE_TYPE)
{
if (file_mgr_data->direction == DIRECTION_ASCENDING)
{
sort = (int *) FileTypeAscending;
sub_sort = (int *) FileNameAscending;
}
else
{
sort = (int *) FileTypeDescending;
sub_sort = (int *) FileNameDescending;
}
}
else if (file_mgr_data->order == ORDER_BY_ALPHABETICAL)
{
if (file_mgr_data->direction == DIRECTION_ASCENDING)
sort = (int *) FileNameAscending;
else
sort = (int *) FileNameDescending;
}
else if (file_mgr_data->order == ORDER_BY_DATE)
{
if (file_mgr_data->direction == DIRECTION_ASCENDING)
sort = (int *) FileDateAscending;
else
sort = (int *) FileDateDescending;
}
else if (file_mgr_data->order == ORDER_BY_SIZE)
{
if (file_mgr_data->direction == DIRECTION_ASCENDING)
sort = (int *) FileSizeAscending;
else
sort = (int *) FileSizeDescending;
}
/* Sort the files and if the sub_sort function is non-null, */
/* sort sets of the files broken according to file type. */
qsort (order_list, file_count, sizeof (FileViewData *), (int (*)())sort);
if (sub_sort != NULL)
{
start = 0;
i = 0;
while (i < file_count)
{
if (order_list[start]->file_data->logical_type !=
order_list[i]->file_data->logical_type)
{
qsort (order_list + start, i - start,
sizeof (FileViewData *), (int (*)())sub_sort);
start = i;
}
i++;
}
qsort (order_list + start, i - start, sizeof (FileViewData *),
(int (*)())sub_sort);
}
}
/************************************************************************
*
* FilterFiles
* Filter out the files which do not match the filtering criteria.
*
* The `mustMatch' flag is used to determine whether the user has
* requested that the files which match the specification are to
* be displayed, or instead, filtered out.
*
************************************************************************/
void
FilterFiles(
FileMgrData *file_mgr_data,
DirectorySet *directory_set )
{
FileViewData **file_view_data;
FilterData * filter_data;
register int i, j, k;
Boolean show_hidden;
String filter;
Boolean mustMatch, matches;
int filterCount = 0;
int invisibleCount = 0;
FileViewData *sub_root;
#ifdef DT_PERFORMANCE
struct timeval update_time_s;
struct timeval update_time_f;
printf(" Begin FilterFiles\n");
gettimeofday(&update_time_s, NULL);
/* added by Rafi */
_DtPerfChkpntMsgSend("Begin Filtering Files");
#endif
file_view_data = directory_set->file_view_data;
filter_data = (FilterData *)(file_mgr_data->filter_active->data);
show_hidden = filter_data->show_hidden;
filter = filter_data->filter;
mustMatch = filter_data->match_flag;
/* set the show hidden boolean depending on the filter specification */
if (show_hidden)
file_mgr_data->show_hid_enabled = True;
else
file_mgr_data->show_hid_enabled = False;
/* Filter out all files not matching the specifications */
for (i = 0; i < directory_set->file_count; i++)
{
/* Initially assume the file is not filtered out */
file_view_data[i]->filtered = False;
/* If in tree mode, explicitly filter out . and .. */
if (file_mgr_data->show_type == MULTIPLE_DIRECTORY &&
(strcmp(file_view_data[i]->file_data->file_name, ".") == 0 ||
strcmp(file_view_data[i]->file_data->file_name, "..") == 0))
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
/* filter out any files that have their attributes "invisible" */
/* field set to false */
if((_DtCheckForDataTypeProperty(
file_view_data[i]->file_data->logical_type,
"invisible")) &&
(file_mgr_data != trashFileMgrData))
{
filterCount++;
file_view_data[i]->filtered = True;
++invisibleCount;
continue;
}
/* Filter hidden files, according to the user setting */
if (file_view_data[i]->file_data->file_name[0] == '.')
{
if(strcmp(file_mgr_data->current_directory, "/") == 0 &&
strcmp(file_view_data[i]->file_data->file_name, "..") == 0)
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
if(file_mgr_data->restricted_directory != NULL)
{
if((strcmp(file_mgr_data->restricted_directory,
file_mgr_data->current_directory) == 0 &&
(strcmp(file_view_data[i]->file_data->file_name, ".") == 0 || strcmp(file_view_data[i]->file_data->file_name, "..") == 0 )) ||
(strncmp(file_mgr_data->restricted_directory,file_mgr_data->current_directory, strlen(file_mgr_data->restricted_directory)) == 0 &&
strcmp(file_view_data[i]->file_data->file_name, ".") == 0 ))
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
}
}
if( restrictMode &&
(strcmp(file_view_data[i]->file_data->file_name, "..") == 0 ||
strcmp(file_view_data[i]->file_data->file_name, ".") == 0))
{
char *tempName;
tempName = (char *)XtMalloc( strlen(file_mgr_data->current_directory) + 3);
sprintf( tempName, "%s/", file_mgr_data->current_directory );
if( strcmp(users_home_dir, tempName) == 0 ||
strcmp(users_home_dir, file_mgr_data->current_directory) == 0)
{
filterCount++;
file_view_data[i]->filtered = True;
XtFree(tempName);
continue;
}
XtFree(tempName);
}
/* if we want to show the hidden files no more should be filtered out */
if(show_hidden)
continue;
/* don't show .trashinfo in the trash directory */
if(trashFileMgrData == file_mgr_data &&
(strcmp(file_view_data[i]->file_data->file_name, ".trashinfo") == 0))
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
/* Check for a match against the filter expression string, except for
* files in the trash directory and sub directories in tree mode. */
matches = False;
if (strcmp(filter, "") != 0 &&
file_mgr_data != trashFileMgrData &&
!(file_mgr_data->show_type == MULTIPLE_DIRECTORY &&
file_view_data[i]->file_data->is_subdir))
{
/* Special case for ".." that need not be filtered */
if( !strcmp( file_view_data[i]->file_data->file_name, ".." )
|| !strcmp( file_view_data[i]->file_data->file_name, "." ) )
{
}
else if (file_view_data[i]->file_data->action_name)
{
if(fnmatch((const char *)filter,
(const char *)file_view_data[i]->file_data->action_name,
0) == 0)
{
if ( mustMatch )
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
else
matches = True;
}
}
else if (fnmatch((const char *)filter,
(const char *)file_view_data[i]->file_data->file_name, 0) == 0)
{
if ( mustMatch )
{
filterCount++;
file_view_data[i]->filtered = True;
continue;
}
else
matches = True;
}
}
/* now lets check through the filter filetypes and if the file is */
/* filtered, filter it out */
if(file_mgr_data != trashFileMgrData)
{
/* This is for the case of files likes 'action' files which
do not have a logical_type */
if(strcmp(file_view_data[i]->file_data->file_name,file_view_data[i]->
file_data->logical_type) == 0)
{
if(!filter_data->match_flag)
{
if(!matches)
{
filterCount++;
file_view_data[i]->filtered = True;
}
}
}
else
for(j = 0; j < filter_data->count; j++)
{
if(strcmp(filter_data->user_data[j]->filetype,
file_view_data[i]->file_data->logical_type) == 0)
{
if((filter_data->user_data[j]->selected == True &&
filter_data->match_flag) ||
(filter_data->user_data[j]->selected == False &&
!filter_data->match_flag))
{
if(!matches)
{
filterCount++;
file_view_data[i]->filtered = True;
}
}
break;
}
}
}
}
/* update ndir, nfile counts for this sub directory */
directory_set->filtered_file_count = filterCount;
directory_set->invisible_file_count = invisibleCount;
sub_root = directory_set->sub_root;
sub_root->ndir = sub_root->nfile = 0;
sub_root->nnew = 0;
for (i = 0; i < directory_set->file_count; i++)
{
if (!file_view_data[i]->filtered)
{
if (file_view_data[i]->file_data->is_subdir)
sub_root->ndir++;
else
sub_root->nfile++;
}
}
UpdateBranchState(file_mgr_data, sub_root, BRANCH_UPDATE, False);
#ifdef DT_PERFORMANCE
gettimeofday(&update_time_f, NULL);
if (update_time_s.tv_usec > update_time_f.tv_usec) {
update_time_f.tv_usec += 1000000;
update_time_f.tv_sec--;
}
printf(" done FilterFiles, time: %ld.%ld\n\n", update_time_f.tv_sec - update_time_s.tv_sec, update_time_f.tv_usec - update_time_s.tv_usec);
/* added by Rafi */
_DtPerfChkpntMsgSend("Done Filtering Files");
#endif
}
/************************************************************************
*
* GetAncestorInfo, GetLevel, GetFullName
*
************************************************************************/
void
GetAncestorInfo(
FileMgrData *file_mgr_data,
FileViewData *ip,
int *levelp,
char *path,
Bool *morep)
/*
* Get information related to the ancestory of an entry:
* - tree depth level
* - full path name
* - for each level: flag indicating whether there are additional siblings
* to be diplayed after this entry
*/
{
FileViewData *pp, *pa[256];
int i, l, level;
char *p;
/* determine tree depth level of this entry */
level = 0;
for (pp = ip->parent; pp; pp = pp->parent)
level++;
if (levelp)
*levelp = level;
/* get a list of all ancestors (including ip) in top down order */
l = level;
for (pp = ip; pp; pp = pp->parent)
pa[l--] = pp;
/* construct path name of this entry */
if (path) {
strcpy(path, file_mgr_data->current_directory);
p = path + strlen(path);
for (l = 1; l <= level; l++) {
if (p[-1] != '/')
*p++ = '/';
strcpy(p, pa[l]->file_data->file_name);
p += strlen(p);
}
}
/* compile more array */
if (morep) {
for (l = 0; l <= level; l++) {
DirectorySet *ds = (DirectorySet *)pa[l]->directory_set;
morep[l] = False;
if (ds->order_list == NULL)
continue;
for (i = 0; i < ds->file_count; i++)
if (ds->order_list[i] == pa[l])
break;
for (i = i + 1; i < ds->file_count; i++) {
if (ds->order_list[i]->displayed) {
morep[l] = True;
break;
}
}
}
}
}
void
GetFullName(
FileMgrData *file_mgr_data,
FileViewData *ip,
char *path)
{
GetAncestorInfo(file_mgr_data, ip, NULL, path, NULL);
}
void
GetDirName(
FileMgrData *file_mgr_data,
FileViewData *ip,
char *path)
{
char *p;
GetAncestorInfo(file_mgr_data, ip, NULL, path, NULL);
p = strrchr(path, '/');
*p = 0;
}
void
GetLevel(
FileViewData *ip,
int *levelp)
{
int level = 0;
for (ip = ip->parent; ip; ip = ip->parent)
level++;
*levelp = level;
}
/************************************************************************
*
* FlattenTree
*
************************************************************************/
static void
CopyOrderedEntries(
FileViewData *ip,
FileViewData *fvd_array[],
int *index)
/*
* Copy all entries from the tree to an array
*/
{
DirectorySet *directory_set;
int i;
fvd_array[*index] = ip;
(*index)++;
if (ip->desc)
{
directory_set = (DirectorySet *)ip->desc->directory_set;
for (i = 0; i < directory_set->file_count; i++)
CopyOrderedEntries(directory_set->order_list[i], fvd_array, index);
}
}
void
FlattenTree(
FileMgrData *file_mgr_data,
FileViewData ***file_view_data,
int *file_count)
{
int i;
*file_count = 1;
for (i = 0; i < file_mgr_data->directory_count; i++)
*file_count += file_mgr_data->directory_set[i]->file_count;
*file_view_data =
(FileViewData **) XtMalloc (*file_count * sizeof(FileViewData *));
i = 0;
CopyOrderedEntries(file_mgr_data->tree_root, *file_view_data, &i);
}
/************************************************************************
*
* IconCallback
* Callback function invoked upon an action occurring on an icon.
*
************************************************************************/
static Bool
IsButtonOrMotion(
Display *disp,
XEvent *ep,
char *arg)
{
return (ep->type == MotionNotify || ep->type == ButtonRelease);
}
void
IconCallback(
Widget w,
XtPointer clientData,
XtPointer callData )
{
XmAnyCallbackStruct * callback;
XButtonEvent * event;
FileViewData * fileViewData;
FileMgrData * fileMgrData;
static Boolean highlightType = INIT_VALUE;
static Widget highlightWidget = NULL;
char * logicalType;
char * command;
DesktopRec * desktopRec;
Boolean dragged;
Window root;
XEvent bevent;
int dx, dy;
WindowPosition position;
static int adjustState=-1;
XrmValue value_return;
char *str_type_return;
if( adjustState == -1)
{
if (XrmGetResource(XrmGetDatabase(XtDisplay(w)), "*enableBtn1Transfer", "*EnableBtn1Transfer",&str_type_return, &value_return) && !strcmp(value_return.addr,"True") )
{
adjustState=True;
}
else
adjustState=False;
}
callback = (XmAnyCallbackStruct *) callData;
fileViewData = (FileViewData *) clientData;
event = (XButtonEvent *) callback->event;
if (callback->reason == XmCR_DRAG && event->button == bMenuButton)
callback->reason = XmCR_POPUP;
if(callback->reason != XmCR_UNHIGHLIGHT)
{
/* Get the directory data and the file manager data */
(void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
}
/* Process the different callback types */
if ((callback->reason == XmCR_ARM) || (callback->reason == XmCR_SELECT))
{
/*
* Both ARM and SELECT are generated using Button1. We pass on these
* requests to the code responsible for processing button 1 selects
* and drags.
*/
FileMgrRec * fileMgrRec;
DtIconGadget new = (DtIconGadget)w;
if( event->type == KeyPress )
{
/* if a keypress we only want to select on an SELECT */
if( callback->reason == XmCR_ARM )
return;
else
{
XKeyEvent *kevent;
KeySym keysym;
int offset;
kevent = (XKeyEvent *)event;
if (kevent->state & ShiftMask)
offset = 1;
else
offset = 0;
keysym = XLookupKeysym((XKeyEvent *)kevent, offset);
if( keysym == XK_Return )
goto run_default_action;
}
}
if (callback->reason == XmCR_ARM)
new->icon.armed = False;
if (desktopRec)
{
B1DragPossible = False;
B2DragPossible = False;
XtCallCallbacks(desktopRec->drawA, XmNinputCallback, callData);
}
else
{
B1DragPossible = False;
B2DragPossible = False;
fileMgrRec = (FileMgrRec *)fileMgrData->file_mgr_rec;
XtCallCallbacks(fileMgrRec->file_window, XmNinputCallback, callData);
}
if (callback->reason == XmCR_ARM)
new->icon.armed = True;
}
else if (callback->reason==XmCR_DISARM)
{
/*
* DISARM is generated as the result of a button 1 up event.
* If we are in the middle of a button 2 drag, then we'll ignore this;
* otherwise, we now know a drag will not start, so clear all state flags.
*/
if (B2DragPossible)
return;
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
}
else if (callback->reason == XmCR_DROP)
{
/*
* DROP is generated as the result of a button 2 up event.
* If we are in the middle of a button 1 drag, then we'll ignore this;
* otherwise, we now know a drag will not start, so clear all state flags.
*/
if (B1DragPossible)
return;
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
}
else if (callback->reason == XmCR_DEFAULT_ACTION)
{
Boolean Error;
if(event->type == KeyPress)
{
XKeyEvent *kevent;
KeySym keysym;
int offset;
kevent = (XKeyEvent *)event;
if (kevent->state & ShiftMask)
offset = 1;
else
offset = 0;
keysym = XLookupKeysym((XKeyEvent *)kevent, offset);
if (keysym == XK_Escape)
{
/* an escape unposts the name change text widget */
if(desktopRec)
UnpostDTTextField();
else
UnpostTextField(fileMgrData);
return;
}
else
{
KeySym SpaceKeySym = XStringToKeysym( "space" );
if( keysym == SpaceKeySym )
return;
}
}
run_default_action:
Error = False;
/*
* If DEFAULT_ACTION was generated by button press,
* wait for the button release
*/
dragged = False;
if(event->type == ButtonPress)
{
if (loc_cursor1 == None)
loc_cursor1 = XCreateFontCursor(XtDisplay(w), 40);
if (loc_cursor2 == None)
loc_cursor2 = XCreateFontCursor(XtDisplay(w), 34);
root = RootWindowOfScreen(XtScreen(w));
XGrabPointer(XtDisplay(w), root,
False, ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
None, loc_cursor1, CurrentTime);
do {
XIfEvent(XtDisplay(w), &bevent, IsButtonOrMotion, NULL);
if (!dragged && bevent.type == MotionNotify) {
dx = event->x_root - bevent.xmotion.x_root; if (dx < 0) dx = -dx;
dy = event->y_root - bevent.xmotion.y_root; if (dy < 0) dy = -dy;
if (dx > DBLCLICK_DRAG_THRESHOLD || dy > DBLCLICK_DRAG_THRESHOLD) {
DPRINTF(("dragged!\n"));
XGrabPointer(XtDisplay(w), root,
False, ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
None, loc_cursor2, CurrentTime);
dragged = True;
}
}
} while (bevent.type != ButtonRelease);
XUngrabPointer(XtDisplay(w), CurrentTime);
XFlush(XtDisplay(w));
position.x = bevent.xbutton.x_root;
position.y = bevent.xbutton.y_root;
}
/*
* DEFAULT_ACTION is generated by a double-click of button 1.
* We now know a drag will not start, so clear all state flags.
*/
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
logicalType = fileViewData->file_data->logical_type;
command = _DtRetrieveDefaultAction(logicalType);
if (desktopRec)
{
/* Any button event unposts the text field */
UnpostDTTextField();
if(command)
RunDTCommand(command, desktopRec, NULL);
else
Error = True;
}
else
{
/* Any button event unposts the text field */
UnpostTextField(fileMgrData);
if((openDirType == NEW && strcmp(command, openInPlace) == 0) ||
(openDirType != NEW && strcmp(command, openNewView) == 0))
{
unsigned int modifiers = event->state;
RunCommand (openNewView, fileMgrData, fileViewData,
dragged? &position: NULL, NULL, NULL);
if((modifiers != 0) && ((modifiers & ControlMask) != 0))
{
DialogData *dialog_data;
dialog_data = _DtGetInstanceData(fileMgrData->file_mgr_rec);
CloseView(dialog_data);
}
}
else
{
if(command)
{
if ((fileMgrData->show_type == MULTIPLE_DIRECTORY || dragged) &&
strcmp(command, openInPlace) == 0)
{
RunCommand (openNewView, fileMgrData, fileViewData,
dragged? &position: NULL, NULL, NULL);
}
else
RunCommand (command, fileMgrData, fileViewData,
NULL, NULL, NULL);
}
else
Error = True;
}
}
XtFree(command);
if(Error)
{
char * title;
char msg[512];
char * tmpStr;
tmpStr = (GETMESSAGE(9,6, "Action Error"));
title = (char *)XtMalloc(strlen(tmpStr) + 1);
strcpy(title, tmpStr);
(void) sprintf (msg,
(GETMESSAGE(9,7, "There are no actions defined for %s\n")),
logicalType);
if(desktopRec)
_DtMessage (desktopRec->shell, title, msg, NULL, HelpRequestCB);
else
_DtMessage (fileViewData->widget, title, msg, NULL, HelpRequestCB);
XtFree(title);
}
}
else if (callback->reason == XmCR_DRAG)
{
/*
* DRAG is generated by a button 2 down event. It flags that
* the user may possible be initiating a drag; we won't know
* for sure until the drag threshold is surpassed.
* Ignore this if a Button 1 drag is ramping up.
*/
if (B1DragPossible)
return;
/* Any button event unposts the text field */
if (desktopRec)
{
UnpostDTTextField();
if(!DTFileIsSelected(desktopRec, fileViewData) && adjustState)
SelectDTFile(desktopRec);
}
else
{
if( fileMgrData && !FileIsSelected(fileMgrData,fileViewData) &&
adjustState
)
{
SelectFile(fileMgrData, fileViewData);
}
UnpostTextField(fileMgrData);
}
/* Save starting X & Y, in case a drag really starts */
initialDragX = event->x;
initialDragY = event->y;
B2DragPossible = True;
memcpy((char *) &desktop_data->event, (char *) event,
(int) sizeof(XButtonEvent));
}
else if (callback->reason == XmCR_POPUP)
{
if(!desktopRec)
{
FmPopup (w, clientData, (XEvent *)event, fileMgrData);
}
}
else if (callback->reason == XmCR_HIGHLIGHT)
{
DtIconGadget g = (DtIconGadget)w;
if (dragActive)
{
if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
_XmUnhighlightBorder(w);
B1DragPossible = False;
B2DragPossible = False;
return;
}
if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
return;
if ((highlightType != INIT_VALUE) && (highlightWidget))
{
if (desktopRec)
{
if (highlightType == NOT_DESKTOP)
DrawUnhighlight(highlightWidget, NOT_DESKTOP);
else if (highlightWidget != w)
DrawUnhighlight(highlightWidget, DESKTOP);
}
else
{
if (highlightType == DESKTOP)
DrawUnhighlight(highlightWidget, DESKTOP);
else if (highlightWidget != w)
DrawUnhighlight(highlightWidget, NOT_DESKTOP);
}
}
if (desktopRec)
{
DrawHighlight(w, NULL, NULL, DESKTOP);
highlightType = DESKTOP;
}
else
{
DrawHighlight(w, fileViewData, fileMgrData, NOT_DESKTOP);
highlightType = NOT_DESKTOP;
}
highlightWidget = w;
}
else if (callback->reason == XmCR_UNHIGHLIGHT)
{
DtIconGadget g = (DtIconGadget)w;
if (dragActive)
{
if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
_XmHighlightBorder(w);
B1DragPossible = False;
B2DragPossible = False;
return;
}
if ((g->icon.border_type == DtRECTANGLE) || (!g->icon.pixmap))
return;
if (w == highlightWidget)
{
if (highlightType == DESKTOP)
DrawUnhighlight(w, DESKTOP);
else
DrawUnhighlight(w, NOT_DESKTOP);
highlightType = INIT_VALUE;
highlightWidget = NULL;
}
}
else if (callback->reason == XmCR_SHADOW)
DrawShadowTh(w, NULL, DESKTOP);
}
static int
GetSelectedCount(
FileViewData * fileViewData,
FileMgrData * fileMgrData,
DesktopRec * desktopRec,
int * dt)
{
int selectedCount = 0;
char * wsName;
Atom pCurrent;
/* If the initiation of the drag occurred upon an */
/* already selected icon, check for a multiple drag. */
if ((desktopRec == NULL) && FileIsSelected(fileMgrData, fileViewData))
selectedCount = fileMgrData->selected_file_count;
else if (desktopRec == NULL)
selectedCount = 1;
else
{
if (DTFileIsSelected(desktopRec, fileViewData))
{
if(DtWsmGetCurrentWorkspace(XtDisplay(desktopRec->shell),
RootWindowOfScreen(XtScreen(desktopRec->shell)),
&pCurrent) == Success)
{
wsName = XGetAtomName(XtDisplay(desktopRec->shell), pCurrent);
CleanUpWSName(wsName);
}
else
wsName = XtNewString("One");
for(*dt = 0; *dt < desktop_data->numWorkspaces; (*dt)++)
{
if(strcmp(wsName, desktop_data->workspaceData[*dt]->name) == 0)
{
selectedCount = desktop_data->workspaceData[*dt]->files_selected;
break;
}
}
XtFree(wsName);
}
else
selectedCount = 1;
}
return(selectedCount);
}
static Pixmap
GetDragIconMask(
Widget w,
unsigned int wid,
unsigned int hei)
{
Pixmap dragMask;
Display *dpy = XtDisplay(w);
unsigned char flags;
XRectangle pRect, lRect;
GC fillGC;
XGCValues values;
Arg args[8];
Dimension shadowThickness;
Dimension marginWidth, marginHeight;
int minX, minY;
Boolean minXUndefined, minYUndefined;
dragMask = XCreatePixmap(dpy, RootWindowOfScreen (XtScreenOfObject(w)),
wid, hei, 1);
/* Create a GC for drawing 0's into the pixmap */
fillGC = XCreateGC(dpy, dragMask, 0, (XGCValues *) NULL);
XFillRectangle(dpy, dragMask, fillGC, 0, 0, wid, hei);
values.foreground = 1;
XChangeGC(dpy, fillGC, GCForeground, &values);
/* Create the drag pixmap, and the associated mask bitmap */
_DtIconGetIconRects((DtIconGadget)w, &flags, &pRect, &lRect);
minX= 0;
minY= 0;
minXUndefined = minYUndefined = True;
if (flags & XmPIXMAP_RECT)
{
minX = pRect.x;
minY = pRect.y;
minXUndefined = minYUndefined = False;
}
if (flags & XmLABEL_RECT)
{
if ((lRect.x < minX) || minXUndefined)
minX = lRect.x;
if ((lRect.y < minY) || minYUndefined)
minY = lRect.y;
}
XtSetArg (args[0], XmNshadowThickness, &shadowThickness);
XtSetArg (args[1], XmNmarginWidth, &marginWidth);
XtSetArg (args[2], XmNmarginHeight, &marginHeight);
XtGetValues (w, args, 3);
if (flags & XmPIXMAP_RECT)
XFillRectangle(dpy, dragMask, fillGC,
pRect.x - minX + shadowThickness + marginWidth,
pRect.y - minY + shadowThickness + marginHeight,
pRect.width - 2*marginWidth,
pRect.height - 2*marginHeight);
if (flags & XmLABEL_RECT)
{
XFillRectangle(dpy, dragMask, fillGC,
lRect.x - minX + shadowThickness + marginWidth,
lRect.y - minY + shadowThickness + marginHeight,
lRect.width - 2*marginWidth,
lRect.height - 2*marginHeight);
}
XFreeGC(dpy, fillGC);
return (dragMask);
}
static Widget
GetDragIcon(
Widget w,
FileViewData * fileViewData )
{
XmManagerWidget mw = (XmManagerWidget) XtParent(w);
Widget screen_object = (Widget) XmGetXmScreen(XtScreenOfObject(w));
Arg args[11];
register int n;
unsigned int wid, hei, d, junk;
Widget dragIcon;
Pixmap dragPixmap;
Pixmap dragMask;
dragPixmap = _DtIconDraw (w, 0, 0, 0, False);
XGetGeometry (XtDisplay(w), dragPixmap,
(Window *) &junk, /* returned root window */
(int *) &junk, (int *) &junk, /* x, y of pixmap */
&wid, &hei, /* width, height of pixmap */
&junk, /* border width */
&d); /* depth */
if (initiating_view
&& ((FileMgrData *)initiating_view)->view == BY_ATTRIBUTES)
{
XmFontList fontList;
XmString fileNameString;
DtIconGadget g = (DtIconGadget)w;
XtSetArg( args[0], XmNfontList, &fontList );
XtGetValues( fileViewData->widget, args, 1 );
fileNameString = XmStringCreateLocalized( fileViewData->file_data->file_name );
wid = XmStringWidth( fontList, fileNameString )
+ g->icon.pixmap_width
+ g->icon.cache->margin_width
+ g->icon.cache->spacing
+ G_ShadowThickness(g)
+ G_HighlightThickness(g);
XmStringFree( fileNameString );
}
dragMask = GetDragIconMask(w, wid, hei);
n = 0 ;
XtSetArg(args[n], XmNhotX, 0); n++;
XtSetArg(args[n], XmNhotY, 0); n++;
XtSetArg(args[n], XmNwidth, wid); n++;
XtSetArg(args[n], XmNheight, hei); n++;
XtSetArg(args[n], XmNmaxWidth, wid); n++;
XtSetArg(args[n], XmNmaxHeight, hei); n++;
XtSetArg(args[n], XmNdepth, d); n++;
XtSetArg(args[n], XmNpixmap, dragPixmap); n++;
XtSetArg(args[n], XmNmask, dragMask); n++;
XtSetArg(args[n], XmNforeground, mw->core.background_pixel); n++;
XtSetArg(args[n], XmNbackground, mw->manager.foreground); n++;
dragIcon = XtCreateWidget("drag_icon", xmDragIconObjectClass,
screen_object, args, n);
return(dragIcon);
}
/* The following function is called if the completeMove flag is */
/* set to TRUE. Internally, dtfile sets this to FALSE; thus, only */
/* receiving clients that set this to true will get this function */
/* called for them. */
/* This function will delete the files/dirs that were dropped */
/* on the receiving client. */
static void
NewConvertDelete(
Widget w,
FileViewData * fileViewData,
char ** fileList,
int numFiles)
{
static char *pname = "NewConvertDelete";
int i;
int child_pid = 0;
DPRINTF(("%s: Entering function\n", pname));
/* fork a background child process to honor the Move Completion */
child_pid = fork();
if (child_pid == -1)
{
char *msg, *tmpStr, *title;
DBGFORK(("%s: Cannot create child process\n", pname));
tmpStr = GETMESSAGE(11,59,
"Cannot create a child process to delete the dropped files.");
msg = XtNewString(tmpStr);
title = XtNewString((GETMESSAGE(11,58,"Process Create Error")));
/* Display Error message */
_DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
XtFree(msg);
XtFree(title);
return;
}
/* In the Child Process, we simply erase the files */
/* and directories that were dropped on the receiver */
if (child_pid == 0)
{
DBGFORK(("%s: child forked\n", pname));
for (i = 0; i < numFiles; i++)
{
DPRINTF(("%s: Erasing file %s\n", pname, fileList[i]));
EraseObject(fileList[i]);
}
DBGFORK(("%s: child exiting\n", pname));
exit(0);
}
DBGFORK(("%s: forked child<%d>\n", pname, child_pid));
}
static void
NewConvertFileName(
Widget w,
FileViewData * fileViewData,
char ** fileList,
Cardinal *numFiles)
{
FileMgrData * fileMgrData;
DesktopRec * desktopRec;
int selectedCount;
int dt, i, count;
char * directoryName;
char * fileName;
char * path;
if(fileViewData != NULL)
{
(void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
selectedCount = GetSelectedCount(fileViewData, fileMgrData, desktopRec, &dt);
}
else
{
/* If fileViewData is NULL, then the file no long exists */
fileMgrData = (FileMgrData *)initiating_view;
desktopRec = NULL;
if(fileMgrData)
selectedCount = fileMgrData->selected_file_count;
else
selectedCount = 0;
}
if (selectedCount > 1)
{
for (i = (selectedCount-1); i >= 0; i--)
{
if (desktopRec)
{
fileViewData = desktop_data->workspaceData[dt]->
selectedDTWindows[i]->file_view_data;
directoryName = desktop_data->workspaceData[dt]->
selectedDTWindows[i]->dir_linked_to;
fileName = fileViewData->file_data->file_name;
}
else
{
fileViewData = fileMgrData->selection_list[i];
directoryName = ((DirectorySet *)fileViewData->directory_set)->name;
fileName = fileViewData->file_data->file_name;
}
path = (char *)XtMalloc(strlen(directoryName) + strlen(fileName) + 2);
sprintf(path,"%s/%s", directoryName, fileName);
if ((!desktopRec) && (fileMgrData->toolbox))
path = _DtResolveAppManPath(path,
fileMgrData->restricted_directory);
fileList[i] = DtEliminateDots(path);
}
*numFiles = selectedCount;
}
else
{
if (desktopRec)
{
directoryName = desktopRec->dir_linked_to;
fileName = fileViewData->file_data->file_name;
}
else if(fileViewData)
{
directoryName = ((DirectorySet *)fileViewData->directory_set)->name;
fileName = fileViewData->file_data->file_name;
}
else
{
directoryName = fileMgrData->current_directory;
fileName = NULL;
}
path = (char *)XtMalloc(strlen(directoryName) + strlen(fileName) + 2);
sprintf(path,"%s/%s", directoryName, fileName);
if ((!desktopRec) && (fileMgrData->toolbox))
path = _DtResolveAppManPath(path, fileMgrData->restricted_directory);
fileList[0] = DtEliminateDots( path );
*numFiles = 1;
}
#ifdef DEBUG
if (debug)
{
printf("NewConvertFileName: returns %d files\n", selectedCount);
for (i = 0; i < selectedCount; i++) {
printf("\t\"%s\"\n", fileList[i]);
}
if (selectedCount == 0)
printf("\t\"%s\"\n", fileList[0]);
}
#endif
}
/* ARGSUSED */
static void
FileConvertCB(
Widget w,
XtPointer client,
XtPointer call)
{
FileViewData * fileViewData = (FileViewData *) client;
DtDndConvertCallback cb = (DtDndConvertCallback) call;
FileMgrData *fmd = (FileMgrData *)initiating_view;
if(fmd)
{
fileViewData = fmd->drag_file_view_data;
fmd->drag_file_view_data = NULL;
}
if (cb->reason == DtCR_DND_CONVERT_DATA)
{
if(fmd && !fmd->selected_file_count && fileViewData == NULL)
{
cb->status = DtDND_FAILURE;
cb->dragData->numItems = 0; /* Just to be on safe side */
return;
}
NewConvertFileName(w, fileViewData,
cb->dragData->data.files, &cb->dragData->numItems);
} else if (cb->reason == DtCR_DND_CONVERT_DELETE)
{
NewConvertDelete(w, fileViewData,
cb->dragData->data.files, cb->dragData->numItems);
}
}
/* This callback procedure removes the icons when the drop is complete */
/* ARGSUSED */
static void
DragFinishCB(Widget w, XtPointer client, XtPointer call)
{
DtDndDragFinishCallback cb = (DtDndDragFinishCallback) call;
int i;
static Window root = 0;
DPRINTF(("DragFinishCB: dragActive -> False\n"));
dragActive = False;
initialDragX = -1;
initialDragY = -1;
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
if (cb->sourceIcon)
XtDestroyWidget(cb->sourceIcon);
DPRINTF (("DragFinishCB: Number of items being freed are %d\n",
cb->dragData->numItems));
for (i = 0; i < cb->dragData->numItems; i++) {
DPRINTF(("DragFinishCB: Freeing %s\n", cb->dragData->data.files[i]));
XtFree(cb->dragData->data.files[i]);
cb->dragData->data.files[i] = NULL;
}
}
/* ARGSUSED */
void
StartDrag(
Widget w,
FileViewData * fileViewData,
XEvent * event)
{
static XtCallbackRec fileConvertCB[] = { {FileConvertCB, NULL},
{NULL, NULL} };
static XtCallbackRec dragFinishCB[] = { {DragFinishCB, NULL},
{NULL, NULL} };
static XtCallbackRec dropOnRootCB[] = { {DropOnRootCB, NULL},
{NULL, NULL} };
Widget drag_icon;
Arg args[2];
int numArgs;
FileMgrData * fileMgrData = NULL;
DesktopRec * desktopRec = NULL;
int selectedCount;
int dt;
Boolean desktopObj;
unsigned char operations;
if (event->type == INVALID_TYPE) return;
if (fileViewData == NULL) return;
fileConvertCB[0].closure = (XtPointer)fileViewData;
dropOnRootCB[0].closure = (XtPointer)fileViewData;
desktopObj = IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
selectedCount = GetSelectedCount(fileViewData, fileMgrData,
desktopRec, &dt);
if (selectedCount > 1)
drag_icon = NULL;
else
drag_icon = GetDragIcon(w, fileViewData);
numArgs = 0;
XtSetArg(args[numArgs], DtNsourceIcon, drag_icon); numArgs++;
XtSetArg(args[numArgs], DtNdropOnRootCallback, dropOnRootCB); numArgs++;
if ((desktopObj && desktopRec->toolbox) ||
(!desktopObj && fileMgrData->toolbox))
operations = XmDROP_COPY;
else
operations = XmDROP_MOVE | XmDROP_COPY | XmDROP_LINK;
if (DtDndDragStart(w, event, DtDND_FILENAME_TRANSFER, selectedCount,
operations,
fileConvertCB, dragFinishCB, args, numArgs) == NULL) {
DPRINTF(("StartDrag: dragActive -> False\n"));
dragActive = False;
initialDragX = -1;
initialDragY = -1;
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
}
}
/*
* This function is capable of initiating either a button 1 or button 2
* drag operation; which one gets started is dependent upon which of the
* two state flags (B1DragPossible or B2DragPossible) is set.
*/
static void
InitiateIconDrag(
FileViewData * fileViewData,
int rootX,
int rootY,
XEvent * event )
{
FileMgrData * fileMgrData;
DtIconGadget iconG;
Widget dragIcon;
char * typeSet;
char * fileSet;
char * directoryName;
Pixmap dragPixmap;
XRectangle dragMask[2];
Pixel bg;
XRectangle pRect, lRect;
unsigned char flags;
int stringSize;
register int i;
Arg args[10];
Boolean allowDropInInitiatingWindow;
int rectCount;
int minX, minY;
Boolean minXUndefined, minYUndefined;
DesktopRec * desktopRec;
int btn;
char * hostName;
Boolean spaces = False;
Boolean trash = False;
char *tmpStr, *link_path, *ptr;
/* Don't allow multi-drags to start */
if (dragActive)
{
initialDragX = -1;
initialDragY = -1;
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
return;
}
else
dragActive = True;
DPRINTF(("InitiateIconDrag: dragActive -> True\n"));
dragIcon = fileViewData->widget;
(void)IsDesktopPtr(fileViewData, &fileMgrData, &desktopRec);
/* if what we are dragging is a trash item, we want the objects to be
* real objects, not their links
*/
if(fileMgrData == trashFileMgrData && trashFileMgrData != NULL)
trash = True;
/*
* We need to mark the icon which initiated the drag as no longer
* being 'armed', since it will not receive the button up event,
* because we will have release the drag.
*/
iconG = (DtIconGadget)dragIcon;
iconG->icon.armed = False;
/*
* Remember the posistion of the icon pixmap within the drag icon.
*/
dragIconPixmapOffsetX = G_ShadowThickness(iconG) + G_MarginWidth(iconG);
dragIconPixmapOffsetY = G_ShadowThickness(iconG) + G_MarginHeight(iconG);
if(desktopRec)
{
initiating_view = (XtPointer) NULL;
widget_dragged = dragIcon;
}
else
{
initiating_view = (XtPointer) fileMgrData;
widget_dragged = NULL;
}
StartDrag(dragIcon, fileViewData, event);
}
/*
* These are replacements for the corresponding libXm functions. They allow
* us to treat icon gadgets as non-rectangular, so that input processing
* is handled correctly.
*/
static XmGadget
InputInGadget (
Widget w,
register int x,
register int y)
{
CompositeWidget cw = (CompositeWidget)w;
static Region r = NULL;
FileMgrData * file_mgr_data;
Boolean simpleCheck = False;
register int i;
unsigned char flags;
XRectangle pRect, lRect;
register Widget widget;
file_mgr_data = ReturnDesktopPtr((Widget)cw);
/*
* Tree views and attribute views do not have the non-rectangular
* hotspots, so we can resort to the standard checking algorithm.
*/
if ((file_mgr_data == NULL) ||
(file_mgr_data->show_type != SINGLE_DIRECTORY) ||
(file_mgr_data->view == BY_ATTRIBUTES))
{
simpleCheck = True;
}
for (i = 0; i < cw->composite.num_children; i++)
{
widget = cw->composite.children[i];
if (XmIsGadget(widget) && XtIsManaged(widget))
{
if (simpleCheck)
{
if (x >= widget->core.x && y >= widget->core.y &&
(Position) x < (Position) (widget->core.x + widget->core.width) &&
(Position) y < (Position) (widget->core.y + widget->core.height))
{
return ((XmGadget) widget);
}
}
else
{
/* Initialize the region to be empty */
if (r == NULL)
r = XCreateRegion();
else
XSubtractRegion(r, r, r);
_DtIconGetIconRects((DtIconGadget)widget, &flags, &pRect, &lRect);
if (flags & XmPIXMAP_RECT)
XUnionRectWithRegion(&pRect, r, r);
if (flags & XmLABEL_RECT)
XUnionRectWithRegion(&lRect, r, r);
if (XPointInRegion(r, x, y))
return ((XmGadget) widget);
}
}
}
return(NULL);
}
/*
* This function is identical to the libXm version; it needs to be here
* so that it will call our InputInGadget() instead of the libXm
* version, which was bundled together with it in GadgetUtil.c
*/
static XmGadget
InputForGadget (
Widget cw,
int x,
int y)
{
XmGadget gadget;
gadget = InputInGadget (cw, x, y);
if (!gadget || !XtIsSensitive ((Widget)gadget))
{
return ((XmGadget) NULL);
}
return (gadget);
}
/*
* This function processes motion events anytime a B1 or B2 drag operation
* has the potential of starting for a file icon. When the drag threshold
* is surpassed, a drag operation will be started.
*/
void
FileIconMotion(
Widget w,
XtPointer clientData,
XEvent *event)
{
int diffX, diffY;
FileViewData * fileViewData = NULL;
Position rootX, rootY;
DirectorySet * directoryData = NULL;
Arg args[10];
int i;
Widget dragIcon;
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))
{
/* Map the original (x,y) into a gadget Id */
if (dragIcon =(Widget)InputForGadget(w, initialDragX, initialDragY))
{
/* Map the icon into its fileViewData structure */
/* Check for desktop icon first */
for (i = 0, fileViewData = NULL; i<desktop_data->numIconsUsed; i++)
{
if (desktop_data->desktopWindows[i]->iconGadget == dragIcon)
{
fileViewData = desktop_data->desktopWindows[i]->file_view_data;
break;
}
}
if (fileViewData == NULL)
{
/* Not a desktop icon */
XtSetArg(args[0], XmNuserData, (XtPointer) &directoryData);
XtGetValues(dragIcon, args, 1);
for (i = 0; i < directoryData->file_count; i++)
{
if (directoryData->file_view_data[i]->widget == dragIcon &&
directoryData->file_view_data[i]->displayed)
{
fileViewData = directoryData->file_view_data[i];
break;
}
}
}
/* Map to root coordinates */
XtTranslateCoords(w, (Position)initialDragX, (Position)initialDragY,
&rootX, &rootY);
if(directoryData)
{
FileMgrData *fmd;
fmd = (FileMgrData *)(directoryData->file_mgr_data);
if(fmd)
fmd->drag_file_view_data = fileViewData;
}
InitiateIconDrag(fileViewData, (int)rootX, (int)rootY, event);
}
else
{
/*
* The file manager view must have changed between the time
* the user did the button down, and the time they moved
* enough to pass the drag threshold, because there is now
* no icon located where the drag initiated. Therefore,
* we'll just clean up, because there is much else we can do.
*/
B1DragPossible = False;
B2DragPossible = False;
ProcessBtnUp = False;
}
/* Force the button up to be ignored */
initialDragX = -1;
initialDragY = -1;
}
}
}
/* Compute position of desktop icon shell for given a drop position */
static void
PositionDesktopIcon(
int drop_x,
int drop_y,
int *root_x,
int *root_y)
{
int pixmap_offset_x;
int pixmap_offset_y;
DtIconGadget g;
/*
* We want to position the shell, so that the icon pixmap in the icon
* gadget will appear at the same spot that the icon pixmap of the drag
* cursor was when the drop occurred.
*/
/* First we caculate the top left corner of the drag pixmap by adding
* the offset of the pixmap within the drag icon to the drop position. */
drop_x += dragIconPixmapOffsetX;
drop_y += dragIconPixmapOffsetY;
/* In order to calculate the correct position of the dektop icon shell
* such that the pixmap within the icon gadget will end up at the desired
* position, we need to know the offset of the gadget's icon pixmap relative
* to the desktop icon shell.
* Since a desktop icon consists a frame widget, a drawing area and an
* icon gadget (all within a popup shell), this offset is computed by adding
* the frame width and and drawing area margins to the icon gadget's
* highlight thickness.
* The frame width is 3 and and and the drawing area margin width is 1
* (both hardcoded in Desktop.c). We determine the remaining components
* by looking at one of the existing desktop icon gadgets. */
if (desktop_data != NULL &&
desktop_data->numIconsUsed + desktop_data->numCachedIcons > 0)
{
g = (DtIconGadget) desktop_data->desktopWindows[0]->iconGadget;
pixmap_offset_x =
pixmap_offset_y = 3 + 1 + G_HighlightThickness(g) + G_ShadowThickness(g);
pixmap_offset_x += G_MarginWidth(g);
pixmap_offset_y += G_MarginHeight(g);
}
else
{
/* don't have an icon gadget; assume default values */
pixmap_offset_x = pixmap_offset_y = 3 + 1 + 2 + 2 + 2;
}
/* Finally, calculate the position of the dektop icon shell by
* subtracting the offset of the gadget's icon pixmap from the
* desired pixmap position */
*root_x = drop_x - pixmap_offset_x;
*root_y = drop_y - pixmap_offset_y;
}
/* Code to reposition a desktop icon after a drag */
static void
RelocateDesktopIcon(
DesktopRec * desktopRec,
int root_x,
int root_y)
{
Widget pu_shell;
Dimension width, height;
Arg args[10];
XSizeHints wmSizeHints;
pu_shell = desktopRec->shell;
XtSetArg (args[0], XmNwidth, &width);
XtSetArg (args[1], XmNheight, &height);
XtGetValues(pu_shell, args, 2);
RegisterInGrid((int)width, (int)height,
desktopRec->root_x,
desktopRec->root_y,
desktopRec->workspace_num,
False);
XtSetArg (args[0], XmNx, root_x);
XtSetArg (args[1], XmNy, root_y);
XtSetValues (pu_shell, args, 2);
XRaiseWindow(XtDisplay(pu_shell), XtWindow(pu_shell));
XSync(XtDisplay(pu_shell), False);
RegisterInGrid((int)width, (int)height, root_x, root_y,
desktopRec->workspace_num, True);
desktopRec->root_x = root_x;
desktopRec->root_y = root_y;
SaveDesktopInfo(NORMAL_RESTORE);
}
/************************************************************************
*
* FileIsSelected
* Loop through the file selection list to see if the specified
* file is selected.
*
************************************************************************/
Boolean
FileIsSelected(
FileMgrData *file_mgr_data,
FileViewData *file_view_data )
{
return file_view_data->selected;
}
/************************************************************************
*
* SetFileSelected
* Display the icon representing file_data as selected.
*
************************************************************************/
static void
SetFileSelected(
FileMgrData *file_mgr_data,
FileViewData *file_view_data )
{
/* mark selected */
file_view_data->selected = True;
/* if this file has an up-to-date gadget, change its colors */
if (!file_view_data->need_update)
{
if (file_view_data->file_data->link == NULL)
SetToSelectColors (file_view_data->widget,
(Widget)((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
0);
else
SetToSelectColors (file_view_data->widget,
(Widget)((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
LINK_FILE);
if (PositioningEnabledInView(file_mgr_data))
RedrawOneGadget(file_view_data->widget, NULL, NULL);
}
}
/************************************************************************
*
* SetFileUnselected
* Display the icon representing file_data as not selected.
*
************************************************************************/
static void
SetFileUnselected(
FileMgrData *file_mgr_data,
FileViewData *file_view_data )
{
/* mark selected */
file_view_data->selected = False;
/* if this file has an up-to-date gadget, change its colors */
if (!file_view_data->need_update)
{
if (file_view_data->file_data->link != NULL)
SetToNormalColors (file_view_data->widget,
((FileMgrRec *)(file_mgr_data->file_mgr_rec))->file_window,
((FileMgrRec *)(file_mgr_data->file_mgr_rec))->main,
LINK_FILE);
else
SetToNormalColors (file_view_data->widget,
((FileMgrRec *)(file_mgr_data->file_mgr_rec))->file_window,
((FileMgrRec *)(file_mgr_data->file_mgr_rec))->main,
0);
if (PositioningEnabledInView(file_mgr_data))
RedrawOneGadget(file_view_data->widget, NULL, NULL);
}
}
/************************************************************************
*
* SelectFile
* Add the file to the selection list.
*
************************************************************************/
void
SelectFile(
FileMgrData *file_mgr_data,
FileViewData *file_view_data )
{
int selection_count;
int i;
/* Add to the front of the selection list */
selection_count = file_mgr_data->selected_file_count;
file_mgr_data->selected_file_count++;
file_mgr_data->selection_list = (FileViewData **)
XtRealloc ((char *) file_mgr_data->selection_list,
sizeof(FileViewData *) * (selection_count + 2));
for (i = file_mgr_data->selected_file_count; i > 0; i--)
file_mgr_data->selection_list[i] = file_mgr_data->selection_list[i-1];
file_mgr_data->selection_list[0] = file_view_data;
/* mark selected */
SetFileSelected(file_mgr_data, file_view_data);
}
/************************************************************************
*
* DeselectFile
* Remove the file from the selection list.
*
************************************************************************/
void
DeselectFile(
FileMgrData *file_mgr_data,
FileViewData *file_view_data,
Boolean valid)
{
int selection_count;
register int i;
register int j;
selection_count = file_mgr_data->selected_file_count;
file_mgr_data->selected_file_count--;
for (i = 0; i < selection_count; i++)
if (file_mgr_data->selection_list[i] == file_view_data)
break;
for (j = i; j < selection_count - 1; j++)
file_mgr_data->selection_list[j] = file_mgr_data->selection_list[j + 1];
file_mgr_data->selection_list = (FileViewData **)
XtRealloc ((char *) file_mgr_data->selection_list,
sizeof(FileViewData *) * selection_count);
file_mgr_data->selection_list[selection_count - 1] = NULL;
if (valid)
SetFileUnselected(file_mgr_data, file_view_data);
else
file_view_data->selected = False;
}
/************************************************************************
*
* DeselectAllFiles
* Unselect all of the selected icons within the file manager data
*
************************************************************************/
void
DeselectAllFiles(
FileMgrData *file_mgr_data )
{
FileViewData * file_view_data;
register int i, j, k;
ObjectPtr bottom;
FileViewData ** repaint_list;
/* Get the color to reset the icons. */
/* Loop through the selection set, resetting the visuals for */
/* each selected icon. */
if (!PositioningEnabledInView(file_mgr_data))
{
for (i = 0; i < file_mgr_data->selected_file_count; i++)
{
file_view_data = file_mgr_data->selection_list[i];
SetFileUnselected(file_mgr_data, file_view_data);
}
}
else if (file_mgr_data->selected_file_count > 0)
{
/*
* We can't simply redraw the selected files; we must also redraw
* any unselected files which are higher on the stacking order.
*/
repaint_list = (FileViewData **)XtMalloc(sizeof(FileViewData *) *
file_mgr_data->selected_file_count);
/* Order the objects to be unselected */
for (i = 0; i < file_mgr_data->selected_file_count; i++)
{
file_view_data = file_mgr_data->selection_list[i];
for (j = 0; j < i; j++)
{
if (file_view_data->position_info->stacking_order <
repaint_list[j]->position_info->stacking_order)
{
/* Insert here, pushing down all lower entries */
for (k = file_mgr_data->selected_file_count - 1; k > j; k--)
repaint_list[k] = repaint_list[k-1];
repaint_list[j] = file_view_data;
break;
}
}
/* Insert at end, if necessary */
if (j >= i)
repaint_list[i] = file_view_data;
}
/* Start the redraw process */
i = file_mgr_data->selected_file_count - 1;
bottom = repaint_list[i]->position_info;
while(bottom)
{
if ((i >= 0) && (bottom == repaint_list[i]->position_info))
{
/* Unselect this object */
SetFileUnselected(file_mgr_data, bottom->file_view_data);
i--;
}
if(bottom->file_view_data != NULL &&
!bottom->file_view_data->need_update)
{
RedrawOneGadget(bottom->file_view_data->widget, NULL, NULL);
}
bottom = bottom->prev;
}
XtFree((char *)repaint_list);
repaint_list = NULL;
}
if (file_mgr_data->selection_list != NULL)
{
XtFree ((char *) file_mgr_data->selection_list);
file_mgr_data->selection_list = NULL;
}
file_mgr_data->selection_list =
(FileViewData **) XtMalloc (sizeof (FileViewData *));
file_mgr_data->selection_list[0] = NULL;
file_mgr_data->selected_file_count = 0;
}
/************************************************************************
*
* SelectAllFiles
* Select all of the files within the file manager data.
*
************************************************************************/
void
SelectAllFiles(
FileMgrData *file_mgr_data )
{
DirectorySet * directory_data;
FileViewData ** order_list;
int directory_count;
int selection_count;
register int i;
register int j;
ObjectPtr top;
FileViewData ** selection_list;
if (PositioningEnabledInView(file_mgr_data))
{
/* Force selection list order to match stacking order */
selection_list = (FileViewData **)XtMalloc(sizeof(FileViewData *) *
(file_mgr_data->num_objects));
top = GetTopOfStack(file_mgr_data);
selection_count = 0;
for (i = 0; i < file_mgr_data->num_objects; i++)
{
/* If the there isn't file_view_data for it
Or if it's a parent folder (..go up)
Don't bother to select them
*/
if( top->file_view_data != NULL
&& strcmp( top->name, ".." ) != 0 )
{
selection_list[selection_count] = top->file_view_data;
++selection_count;
}
top = top->next;
}
selection_list[selection_count] = NULL;
/* Force redraw in bottom to top order */
for (i = selection_count - 1; i >= 0; i--)
{
if (!FileIsSelected(file_mgr_data, selection_list[i]))
SetFileSelected(file_mgr_data, selection_list[i]);
}
/* Free old selection list, and save new one */
XtFree ((char *) file_mgr_data->selection_list);
file_mgr_data->selection_list = selection_list;
}
else
{
/* Free up any current selection and get the selection color. */
if (file_mgr_data->selection_list != NULL)
{
DeselectAllFiles( file_mgr_data );
}
if (file_mgr_data->show_type == SINGLE_DIRECTORY)
directory_count = 1;
else
directory_count = file_mgr_data->directory_count;
/* Loop through the set of directories checking each file view */
/* structure to see if the icon is filtered. If not, select it */
/* and increment the selection count. */
selection_count = 0;
/* For tree mode the index has to be -1 */
i = (file_mgr_data->show_type == MULTIPLE_DIRECTORY)?-1:0;
for (; i < directory_count; i++)
{
directory_data = file_mgr_data->directory_set[i];
order_list = directory_data->order_list;
for (j = 0; j < directory_data->file_count; j++)
{
/* If the file is being filtered out
Or if it's a parent folder (..go up)
Don't bother to select them
*/
if (order_list[j]->filtered == True
|| strcmp( order_list[j]->file_data->file_name, ".." ) == 0 )
continue;
selection_count++;
file_mgr_data->selection_list = (FileViewData **)
XtRealloc ((char *) file_mgr_data->selection_list,
sizeof(FileViewData *) * (selection_count + 1));
file_mgr_data->selection_list[selection_count] = NULL;
file_mgr_data->selection_list[selection_count - 1] = order_list[j];
SetFileSelected(file_mgr_data, order_list[j]);
}
}
}
file_mgr_data->selected_file_count = selection_count;
if(file_mgr_data != trashFileMgrData)
{
if (selection_count == 0)
ActivateNoSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec);
else if (selection_count == 1)
{
ActivateSingleSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec,
file_mgr_data->selection_list[0]->file_data->logical_type);
}
else
ActivateMultipleSelect ((FileMgrRec *)file_mgr_data->file_mgr_rec);
}
}
/************************************************************************
*
* SetToSelectColors
* Set a single icon widget to selected colors.
*
************************************************************************/
void
SetToSelectColors(
Widget widget,
Widget file_window,
int type)
{
int j;
Pixel background_color;
Arg args[3];
/* Get the select color to be used as the background of */
/* the icon gadgets. */
j = 0;
XtSetArg (args[j], XmNbackground, &background_color); j++;
XtGetValues (file_window, args, j);
j = 0;
if (background_color == white_pixel)
{
XtSetArg (args[j], XmNbackground, black_pixel); j++;
XtSetArg (args[j], XmNforeground, white_pixel); j++;
}
else if (background_color == black_pixel)
{
XtSetArg (args[j], XmNbackground, white_pixel); j++;
XtSetArg (args[j], XmNforeground, black_pixel); j++;
}
else
{
XtSetArg (args[j], XmNbackground, white_pixel); j++;
XtSetArg (args[j], XmNforeground, black_pixel); j++;
}
XtSetValues (widget, args, j);
}
/************************************************************************
*
* SetToNormalColors
* Set a single icon widget to normal colors.
*
************************************************************************/
void
SetToNormalColors(
Widget widget,
Widget bg_fg_colors,
Widget top_shadow_colors,
int type)
{
int j;
Pixel background_color;
Pixel foreground_color;
Pixel pixmap_background;
DtIconGadget new = (DtIconGadget)widget;
Arg args[5];
/* Get the colors to be used for drawing the icons */
j = 0;
XtSetArg (args[j], XmNbackground, &background_color); j++;
XtSetArg (args[j], XmNforeground, &foreground_color); j++;
XtGetValues (bg_fg_colors, args, j);
j = 0;
XtSetArg (args[j], XmNtopShadowColor, &pixmap_background); j++;
XtGetValues (top_shadow_colors, args, j);
j = 0;
#ifdef _SHOW_LINK
if(type == LINK_FILE)
XtSetArg (args[j], XmNforeground, pixmap_background); j++;
else
#endif
XtSetArg (args[j], XmNforeground, foreground_color); j++;
if (background_color == white_pixel)
{
XtSetArg (args[j], XmNbackground, white_pixel); j++;
}
else if (background_color == black_pixel)
{
XtSetArg (args[j], XmNbackground, black_pixel); j++;
}
else
{
XtSetArg (args[j], XmNbackground, background_color); j++;
}
/* we want to make sure the armed value is off so that it will get
the correct GC */
if(new->icon.armed == True)
{
new->icon.armed = False;
}
XtSetValues (widget, args, j);
}
/*
* When a text widget is destroyed, we need to free up the string we
* attached as userData.
*/
void
DestroyIconName (
Widget w,
XtPointer client_data,
XtPointer call_data)
{
char * str;
Arg args[1];
XtSetArg(args[0], XmNuserData, &str);
XtGetValues(w, args, 1);
XtFree(str);
}
int
#ifdef _NO_PROTO
GetInsertPosition( x1, x2, fontList, name )
int x1;
int x2;
XmFontList fontList;
char * name;
#else
GetInsertPosition( int x1, int x2, XmFontList fontList, char * name )
#endif
{
int i, width, stringWidth;
char * tmp;
char savedChar;
#ifdef MULTIBYTE
int len;
#endif /* MULTIBYTE */
width = x2 - x1;
#ifdef MULTIBYTE
i = 0;
tmp = name;
while ((len = mblen(tmp, MB_CUR_MAX)) > 0)
#else /* MULTIBYTE */
for( tmp = name + 1, i = 0;
*tmp != 0x0;
++tmp, ++i )
#endif /* MULTIBYTE */
{
XmString string;
#ifdef MULTIBYTE
tmp += len;
#endif /* MULTIBYTE */
savedChar = *tmp;
*tmp = 0x0;
string = XmStringCreateLocalized( name );
stringWidth = XmStringWidth( fontList, string );
XmStringFree( string );
*tmp = savedChar;
if( stringWidth > width )
break;
#ifdef MULTIBYTE
else
i++;
#endif /* MULTIBYTE */
}
return( i );
}
void
CreateNameChangeDialog (
Widget w,
FileViewData *file_view_data,
XtPointer client_data,
int type)
{
XRectangle textExtent;
FileMgrData * file_mgr_data;
DesktopRec * desktopWindow;
Widget parent = XtParent(w);
Widget text;
Arg args[8];
int n;
Position x, y;
Widget frame, shell;
Dimension fHeight, sHeight;
#ifdef SHAPE
Dimension tWidth, tHeight;
#endif
char * name;
XtTranslations trans_table;
XmFontList fontList;
Dimension stringWidth;
XmString fileNameString;
char tmpBuf[MAX_PATH];
_DtIconGetTextExtent_r(w, &textExtent);
if(type == DESKTOP)
{
char buf[MAXPATHLEN];
desktopWindow = (DesktopRec *)client_data;
if(desktopWindow->text != NULL)
return;
sprintf( buf, "%s:%s", home_host_name, root_title );
/*
* If the object is on the DESKTOP and its name is root_title, then
* the user can't rename it.
*/
if( strcmp( buf, desktopWindow->title ) == 0
&& strcmp( desktopWindow->dir_linked_to, "/" ) == 0
&& strcmp( desktopWindow->file_name, "." ) == 0 )
return;
}
else
file_mgr_data = (FileMgrData *)client_data;
/* if the object is in the trash, can't rename it */
if( type != DESKTOP
&& file_mgr_data == trashFileMgrData )
return;
/* if the object is an action, can't rename it */
if( DtDtsDataTypeIsAction( file_view_data->file_data->logical_type ) )
{
char *tmpStr, *title, *msg;
tmpStr = GETMESSAGE(10, 39, "Rename error");
title = XtNewString(tmpStr);
tmpStr = GETMESSAGE(10, 40, "This object is an Action.\nAction icon labels cannot be directly renamed." );
msg = XtNewString(tmpStr);
_DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
XtFree(title);
XtFree(msg);
return;
}
else if(file_view_data->file_data->action_name)
{
char *tmpStr, *title, *msg;
tmpStr = GETMESSAGE(10, 39, "Rename error");
title = XtNewString(tmpStr);
tmpStr = GETMESSAGE(11, 32, "Cannot rename %s");
msg = XtMalloc(strlen(tmpStr)+strlen(file_view_data->file_data->
action_name) +1);
sprintf(msg,tmpStr,file_view_data->file_data->action_name);
_DtMessage(toplevel, title, msg, NULL, HelpRequestCB);
XtFree(title);
XtFree(msg);
return;
}
/*
* The selected objects name is attached as 'userData' to text field,
* to aid us in mapping back to the original object later.
*/
if( type == DESKTOP &&
( (strcmp(".", file_view_data->file_data->file_name) == 0)
|| strcmp("..", file_view_data->file_data->file_name) == 0) )
{
name = XtNewString(desktopWindow->file_name);
}
else if ( strcmp(".", file_view_data->file_data->file_name) == 0 ||
strcmp("..", file_view_data->file_data->file_name) == 0 )
{
return;
}
else
name = XtNewString(file_view_data->file_data->file_name);
/* set up translations in main edit widget */
trans_table = XtParseTranslationTable(translations_escape);
/* We need to set the width of the text widget.
Can't use XmNcolumns because of the double-byte.
*/
{
XtSetArg( args[0], XmNfontList, &fontList );
XtGetValues( file_view_data->widget, args, 1 );
sprintf( tmpBuf, "%s ", file_view_data->file_data->file_name );
fileNameString = XmStringCreateLocalized( tmpBuf );
stringWidth = XmStringWidth( fontList, fileNameString );
XmStringFree( fileNameString );
n = 0;
XtSetArg(args[n], XmNuserData, name); n++;
XtSetArg(args[n], XmNmarginHeight, 0); n++;
XtSetArg(args[n], XmNmarginWidth, 0); n++;
XtSetArg(args[n], XmNvalue, name); n++;
XtSetArg(args[n], XmNwidth, stringWidth); n++;
}
if(type == DESKTOP)
{
text = XmCreateTextField(parent, "nameChangeT_DT", args, n);
XtAddCallback (text, XmNactivateCallback, ChangeIconNameDT,
(XtPointer)desktopWindow);
XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)DTHelpRequestCB,
HELP_NAMECHANGE_DIALOG_STR);
desktopWindow->text = text;
frame = XtParent(parent);
shell = XtParent(frame);
XtSetArg(args[0], XmNheight, &fHeight);
XtGetValues(frame, args, 1);
XtSetArg(args[0], XmNheight, &sHeight);
XtGetValues(shell, args, 1);
}
else
{
text = XmCreateTextField(parent, "nameChangeT", args, n);
file_mgr_data->renaming = file_view_data;
XtAddCallback (text, XmNmotionVerifyCallback,
(XtCallbackProc)ChangeIconName,
(XtPointer)file_mgr_data);
XtAddCallback (text, XmNmodifyVerifyCallback,
(XtCallbackProc)ChangeIconName,
(XtPointer)file_mgr_data);
XtAddCallback (text, XmNactivateCallback,
(XtCallbackProc)ChangeIconName,
(XtPointer)file_mgr_data);
XtAddCallback(text, XmNhelpCallback, (XtCallbackProc)HelpRequestCB,
HELP_NAMECHANGE_DIALOG_STR);
}
XtAddCallback (text, XmNdestroyCallback, DestroyIconName, (XtPointer)NULL);
/* set up translations in main edit widget */
XtOverrideTranslations(text, trans_table);
if(type == DESKTOP && sHeight > fHeight) {
/* status area has been attached in multi-byte case */
x = 0;
y = textExtent.y;
}
else {
x = textExtent.x;
y = textExtent.y - (Dimension)(text->core.height - textExtent.height);
}
{
Window rootWindow, childWindow;
int pX, pY, rootX, rootY, insertPosition;
unsigned int mask;
XQueryPointer( XtDisplay( parent ), XtWindow( file_view_data->widget ),
&rootWindow, &childWindow, &rootX, &rootY, &pX, &pY,
&mask );
if( pX == 0 )
insertPosition = strlen( name );
else
{
if( type != DESKTOP )
{
if( pX > (int) x && pX < (int) x + (int) stringWidth )
insertPosition = GetInsertPosition( x, pX, fontList, name );
else
insertPosition = strlen( name );
}
else
insertPosition = GetInsertPosition( x, x + pX, fontList, name );
}
n = 0;
XtSetArg( args[n], XmNcursorPosition, insertPosition); n++;
XtSetArg( args[n], XmNx, x); n++;
XtSetArg( args[n], XmNy, y); n++;
XtSetValues (text, args, n);
}
#ifdef SHAPE
if(shapeExtension)
if(type == DESKTOP)
{
Dimension shadowThickness;
XRectangle rect[2];
unsigned char flags;
XtSetArg (args[0], XmNwidth, &tWidth);
XtSetArg (args[1], XmNheight, &tHeight);
XtGetValues (text, args, 2);
XtSetArg (args[0], XmNshadowThickness, &shadowThickness);
XtGetValues (desktopWindow->iconGadget, args, 1);
_DtIconGetIconRects((DtIconGadget)desktopWindow->iconGadget,
&flags, &rect[0], &rect[1]);
/* 1 */
rect[0].x += 1;
rect[0].y += 1;
rect[0].width += 2*shadowThickness;
rect[0].height += 2*shadowThickness;
/* 2 */
if(type == DESKTOP && sHeight > fHeight) {
/* status area has been attached in multi-byte case */
rect[1].x = x + 1;
rect[1].y = y + 1;
rect[1].width = 2*shadowThickness + tWidth;
rect[1].height = sHeight - y - 1;
}
else {
rect[1].x += 1;
rect[1].y += 1;
rect[1].width = shadowThickness + tWidth;
rect[1].height = tHeight;
}
if(rect[0].width > rect[1].width)
rect[1].width = rect[0].width;
XShapeCombineRectangles(XtDisplay(desktopWindow->shell),
XtWindow(desktopWindow->shell),
ShapeBounding, 0, 0, &rect[0], 2,
ShapeSet, Unsorted);
}
#endif
XtManageChild(text);
XmProcessTraversal(text, XmTRAVERSE_CURRENT);
if(type != DESKTOP)
{
FileMgrRec *file_mgr_rec;
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
file_mgr_rec->menuStates &= ~RENAME;
}
}
/************************************************************************
*
* SavePositionalData
* Save the desktop icon positional data.
*
************************************************************************/
void
SavePositionalData (
int fd,
FileMgrData * file_mgr_data,
char ** name_list,
char * name)
{
int i;
FILE * fd_stream = fdopen(fd, "w");
ObjectPosition * ptr;
if (!fd_stream)
return;
if(file_mgr_data->positionEnabled == RANDOM_ON &&
file_mgr_data->object_positions &&
file_mgr_data->show_type == SINGLE_DIRECTORY &&
file_mgr_data->host != NULL)
{
/* Number of object positions */
fprintf(fd_stream, "*%s.%s.%s.%s: %d\n#\n", name_list[0], name_list[1],
name, "num_positions", file_mgr_data->num_objects);
for (i = 0; i < file_mgr_data->num_objects; i++)
{
ptr = file_mgr_data->object_positions[i];
fprintf(fd_stream, "*%s.%s.%s.%s%d: %s %d %d %d\n",
name_list[0], name_list[1], name, "object", i,
ptr->name,
ptr->x,
ptr->y,
ptr->stacking_order);
}
}
else
{
/* Number of object positions */
fprintf(fd_stream, "*%s.%s.%s.%s: %d\n#\n", name_list[0], name_list[1],
name, "num_positions", 0);
}
fclose(fd_stream);
}
/************************************************************************
*
* RestorePositionalData
* Restore the desktop icon positional data.
*
************************************************************************/
void
RestorePositionalData (
XrmDatabase db,
char ** name_list,
FileMgrData * file_mgr_data,
char * name)
{
XrmName xrm_name[10];
int i = 0;
int j;
char objectName[20];
XrmRepresentation rep_type;
XrmValue value;
int num_objects;
char * str;
char * obj_name;
ObjectPosition * ptr;
int x, y;
int s_order;
while (name_list[i])
{
xrm_name[i] = XrmStringToQuark(name_list[i]);
i++;
}
xrm_name[i++] = XrmStringToQuark(name);
xrm_name[i] = XrmStringToQuark("num_positions");
xrm_name[i+1] = '\0';
/* Find out how many objects there are to be loaded */
file_mgr_data->object_positions = NULL;
num_objects = 0;
if (XrmQGetResource (db, xrm_name, NULL, &rep_type, &value))
{
if ((num_objects = atoi (value.addr)) <= 0)
num_objects = 0;
else
{
file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
sizeof(ObjectPosition *) * num_objects);
}
}
file_mgr_data->num_objects = num_objects;
for (j = 0; j < num_objects; j++)
{
sprintf(objectName, "object%d", j);
xrm_name[i] = XrmStringToQuark(objectName);
ptr = file_mgr_data->object_positions[j] = (ObjectPosition *)
XtMalloc(sizeof(ObjectPosition));
XrmQGetResource (db, xrm_name, NULL, &rep_type, &value);
str = (char *)value.addr;
obj_name = XtMalloc(strlen(str) + 1);
sscanf((char *)value.addr, "%s %d %d %d", obj_name, &x, &y, &s_order);
ptr->name = obj_name;
ptr->x = x;
ptr->y = y;
ptr->stacking_order = s_order;
ptr->in_use = False;
ptr->late_bind = False;
ptr->file_view_data = NULL;
ptr->next = NULL;
ptr->prev = NULL;
}
/* Repair all of the next and prev pointers */
RepairStackingPointers(file_mgr_data);
}
void
UnpostTextField (
FileMgrData * file_mgr_data)
{
XmManagerWidget file_window;
int i;
FileMgrRec * file_mgr_rec;
file_mgr_data->renaming = NULL;
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
for (i = 0; i < file_window->composite.num_children; i++)
{
if (XmIsTextField(file_window->composite.children[i]) &&
!file_window->composite.children[i]->core.being_destroyed)
{
XtUnmanageChild(file_window->composite.children[i]);
XtDestroyWidget(file_window->composite.children[i]);
return;
}
}
}
void
UnpostTextPath (
FileMgrData * file_mgr_data)
{
FileMgrRec * file_mgr_rec;
Arg args[2];
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
XtSetArg (args[0], XmNallowShellResize, False);
XtSetValues(file_mgr_rec->shell, args, 1);
XtUnmanageChild(file_mgr_rec->current_directory_text);
XtSetArg (args[0], XmNallowShellResize, True);
XtSetValues(file_mgr_rec->shell, args, 1);
file_mgr_data->fast_cd_enabled = False;
}
/*
* Function to force a redraw of a single gadget.
*/
void
RedrawOneGadget (
Widget child,
XEvent * event,
Region region)
{
if (child->core.widget_class->core_class.expose)
(*(child->core.widget_class->core_class.expose))(child, event, region);
}
/*
* Given a region describing the area to be repainted, repaint all icons,
* in bottom to top order, which fall into this region.
*/
void
RepaintDesktop (
FileMgrData * file_mgr_data,
XEvent * event,
Region region)
{
Widget child;
ObjectPosition * bottom = GetBottomOfStack(file_mgr_data);
/* Redraw all affected gadgets */
while(bottom)
{
if (!bottom->late_bind)
{
if (bottom->file_view_data != NULL &&
!bottom->file_view_data->need_update)
{
child = bottom->file_view_data->widget;
if (XRectInRegion(region, child->core.x, child->core.y,
child->core.width, child->core.height))
{
RedrawOneGadget(child, event, region);
}
}
}
bottom = bottom->prev;
}
}
/*
* This function will extract all exposure events intended for this file
* window, combine them into a single region, and then determine which of
* the file icons need to be redrawn. It is a two step process, as
* described by the comments in the code.
*/
static void
RedisplayUsingStackingOrder (
FileMgrData * file_mgr_data,
Widget w,
register XEvent *event,
Region region)
{
register Widget child;
FileViewData * file_view_data;
ObjectPosition * bottom;
ObjectPosition * top;
Region redrawRegion = XCreateRegion();
XRectangle rect;
XEvent expEvent;
int numChildren = 0;
Widget * children = NULL;
Region widget_region;
Region tmp_region;
/* Get the initial region to redraw */
if (region)
XUnionRegion(redrawRegion, region, redrawRegion);
else if (event)
{
rect.x = event->xexpose.x;
rect.y = event->xexpose.y;
rect.height = event->xexpose.height;
rect.width = event->xexpose.width;
XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
}
/*
* Capture and encompass any other exposure events which are destined for
* us, but are waiting in the wings.
*/
while (XCheckWindowEvent(XtDisplay(w), XtWindow(w), ExposureMask, &expEvent))
{
rect.x = expEvent.xexpose.x;
rect.y = expEvent.xexpose.y;
rect.height = expEvent.xexpose.height;
rect.width = expEvent.xexpose.width;
XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
}
/* Nothing to do if the redraw region is empty */
if (XEmptyRegion(redrawRegion))
{
XDestroyRegion(redrawRegion);
return;
}
/*
* Starting at the top of the stack, find any items which fall into
* the redraw region. As items are found which need to be redrawn,
* subtract them from the redraw region, so that any items lower on the
* stack which might be under these gadgets, but are within the region,
* are not redrawn.
*
* The second phase is to start at the bottom of the stack, and start
* redrawing the gadgets which fell into the region, along with any
* other gadgets on top of these (since they too now need to be redrawn.
*/
top = GetTopOfStack(file_mgr_data);
children = NULL;
numChildren = 0;
while (top)
{
if (!top->late_bind)
{
file_view_data = top->file_view_data;
if(file_view_data != NULL)
{
child = file_view_data->widget;
if (child && XmIsGadget(child) && XtIsManaged(child))
{
widget_region = XCreateRegion();
WidgetRectToRegion(file_mgr_data, child, widget_region);
XIntersectRegion(redrawRegion, widget_region, widget_region);
if (!XEmptyRegion(widget_region))
{
XSubtractRegion(redrawRegion, widget_region, redrawRegion);
children = (Widget *)XtRealloc((char *)children,
(numChildren + 1) * sizeof(Widget));
children[numChildren] = child;
numChildren++;
}
XDestroyRegion(widget_region);
}
}
}
top = (ObjectPosition *)top->next;
}
/* Now, start redrawing, in bottom to top order */
bottom = GetBottomOfStack(file_mgr_data);
numChildren--;
while (bottom)
{
if (!bottom->late_bind)
{
file_view_data = bottom->file_view_data;
if(file_view_data != NULL)
{
child = file_view_data->widget;
if (child && XmIsGadget(child) && XtIsManaged(child))
{
widget_region = XCreateRegion();
WidgetRectToRegion(file_mgr_data, child, widget_region);
if ((numChildren >= 0) && (children[numChildren] == child))
{
XUnionRegion(redrawRegion, widget_region, redrawRegion);
RedrawOneGadget(child, event, redrawRegion);
numChildren--;
}
else
{
/* Do we overlap something which was previously redrawn? */
tmp_region = XCreateRegion();
XIntersectRegion(redrawRegion, widget_region, tmp_region);
if (!XEmptyRegion(tmp_region))
{
XUnionRegion(redrawRegion, widget_region, redrawRegion);
RedrawOneGadget(child, event, redrawRegion);
}
XDestroyRegion(tmp_region);
}
XDestroyRegion(widget_region);
}
}
}
bottom = (ObjectPosition *)bottom->prev;
}
XDestroyRegion(redrawRegion);
XtFree((char *)children);
children = NULL;
}
/*
* This is the function which we use to override the class expose function
* for the drawing area widget. It allows us to catch exposure events
* intended for the desktop, so that we can force the redrawing of the
* gadgets to occur occording to the stacking order.
*/
void
DrawingAreaRedisplay (
Widget wid,
XEvent *event,
Region region)
{
XmDrawingAreaWidget da = (XmDrawingAreaWidget) wid;
XmDrawingAreaCallbackStruct cb;
FileMgrData * file_mgr_data;
cb.reason = XmCR_EXPOSE;
cb.event = event;
cb.window = XtWindow (da);
DPRINTF2(("DrawingAreaRedisplay: event %d, x/y %d/%d, wd/ht %d/%d\n",
event->xany.type,
event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height));
file_mgr_data = ReturnDesktopPtr(wid);
if (file_mgr_data && PositioningEnabledInView(file_mgr_data))
RedisplayUsingStackingOrder(file_mgr_data, (Widget)da, event, region);
else
XmeRedisplayGadgets((Widget)da, event, region);
XtCallCallbackList ((Widget)da, da->drawing_area.expose_callback, &cb);
}
/*
* Return the bottom of the stacking order list.
*/
ObjectPtr
GetBottomOfStack (
FileMgrData * file_mgr_data)
{
int i;
ObjectPtr bottom;
for (i = 0, bottom = NULL; i < file_mgr_data->num_objects; i++)
{
if (file_mgr_data->object_positions[i]->next == NULL)
{
bottom = file_mgr_data->object_positions[i];
break;
}
}
return(bottom);
}
/*
* Return the top of the stacking order list.
*/
ObjectPtr
GetTopOfStack (
FileMgrData * file_mgr_data)
{
int i;
ObjectPtr top;
for (i = 0, top = NULL; i < file_mgr_data->num_objects; i++)
{
if (file_mgr_data->object_positions[i]->prev == NULL)
{
top = file_mgr_data->object_positions[i];
break;
}
}
return(top);
}
/*
* Move an object up in the stacking order. Will not work for moving an
* object further down in the stacking order, but we currently have no
* need for doing that.
*
* NOTE: The top of the stack is '1', not '0'!!
*/
void
RepositionUpInStack (
FileMgrData * file_mgr_data,
int oldPos,
int newPos)
{
ObjectPtr ptr, ptr2, savePtr;
int i, j;
XmManagerWidget file_window;
if (oldPos == newPos)
return;
ptr = GetTopOfStack(file_mgr_data);
/* Find where item is to be inserted */
while (ptr->stacking_order != newPos)
ptr = ptr->next;
/* Find where item currently is */
ptr2 = ptr;
while (ptr2->stacking_order != oldPos)
ptr2 = ptr2->next;
savePtr = ptr2;
if(savePtr->file_view_data == NULL)
return;
/* Remove from its current location */
if (ptr2->prev)
ptr2->prev->next = ptr2->next;
if (ptr2->next)
ptr2->next->prev = ptr2->prev;
/* Link into new position */
ptr2->prev = ptr->prev;
ptr2->next = ptr;
if (ptr->prev)
ptr2->prev->next = ptr2;
ptr->prev = ptr2;
/* Update the stacking order value */
for (i = newPos; i <= oldPos; i++)
{
ptr2->stacking_order = i;
ptr2 = ptr2->next;
}
/* Update the children's list for the file window */
file_window = (XmManagerWidget)
(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
/* Find the affect child */
for (i = 0; (i < file_window->composite.num_children) &&
(file_window->composite.children[i] != savePtr->file_view_data->widget);
i++);
/* Push intervening entries down */
for (j = i; j >= newPos; j--)
file_window->composite.children[j] = file_window->composite.children[j-1];
/* Insert into new position in children list */
file_window->composite.children[newPos-1] = savePtr->file_view_data->widget;
}
/*
* Reorder the file window's children list so that it matches the stacking
* order.
*/
static void
ReorderChildrenList (
XmManagerWidget file_window,
Widget * manage,
int manageCount,
Widget * unmanage,
int unmanageCount)
{
Widget * children = file_window->composite.children;
register int i, j;
for (i = 0; i < manageCount; i++)
children[i] = manage[i];
for (j = 0; j < unmanageCount; j++)
children[i++] = unmanage[j];
}
/*
* If positional information is available for the indicated file, then
* return it; if not, then return NULL.
*/
ObjectPtr
FindCurrentPosition (
FileMgrData * file_mgr_data,
char * file_name)
{
int i;
for (i = 0; i < file_mgr_data->num_objects; i++)
{
if (strcmp(file_name, file_mgr_data->object_positions[i]->name) == 0)
{
/* Found a match */
file_mgr_data->object_positions[i]->in_use = True;
return(file_mgr_data->object_positions[i]);
}
}
return(NULL);
}
void
RepairStackingPointers (
FileMgrData * file_mgr_data)
{
int i;
int j;
ObjectPosition * ptr;
ObjectPosition * prev;
for (i = 1, prev = NULL; i <= file_mgr_data->num_objects; i++)
{
for (j = 0; j < file_mgr_data->num_objects; j++)
{
ptr = file_mgr_data->object_positions[j];
if (ptr->stacking_order == i)
{
if (prev)
{
ptr->prev = prev;
prev->next = ptr;
}
prev = ptr;
break;
}
}
}
}
/*
* Reorder the children's list for the file_window, so that it matches
* the stacking order. Also, set up all next and previous pointers.
*/
void
OrderChildrenList (
FileMgrData * file_mgr_data)
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
XmManagerWidget file_window;
Widget * managed;
Widget * unmanaged;
int num_managed;
int num_unmanaged;
ObjectPosition * top;
int i, j;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
managed = (Widget *)XtMalloc(sizeof(Widget *) *
file_window->composite.num_children);
unmanaged = (Widget *)XtMalloc(sizeof(Widget *) *
file_window->composite.num_children);
num_managed = num_unmanaged = 0;
top = GetTopOfStack(file_mgr_data);
while(top)
{
if (top->file_view_data != NULL && top->file_view_data->widget != NULL)
managed[num_managed++] = top->file_view_data->widget;
top = top->next;
}
/* All the rest get put at the end of the children's list */
for (i = 0; i < file_window->composite.num_children; i++)
{
for (j = 0; j < num_managed; j++)
{
if (managed[j] == file_window->composite.children[i])
break;
}
if (j >= num_managed)
unmanaged[num_unmanaged++] = file_window->composite.children[i];
}
ReorderChildrenList(file_window, managed, num_managed, unmanaged,
num_unmanaged);
XtFree( (char *)managed );
XtFree( (char *)unmanaged );
}
/*
* SetHotRects
*/
void
SetHotRects (
FileViewData * file_view_data,
XtCallbackProc callback,
XtPointer callback_data)
{
Arg args[3];
if (file_view_data->displayed)
{
/*************************/
/* icon gadget displayed */
/*************************/
DtIconGadget g = (DtIconGadget) file_view_data->widget;
unsigned char operations;
/* find defined operations (M/C/L) for file type */
operations = TypeToDropOperations(
file_view_data->file_data->logical_type);
/* if icon gadget not yet registered as a drop site, do so now */
if (!file_view_data->registered)
{
/* register drop site for MCL but make drop site inactive */
XtSetArg (args[0], XmNdropSiteOperations,
XmDROP_COPY | XmDROP_MOVE | XmDROP_LINK);
XtSetValues (file_view_data->widget, args, 1);
file_view_data->registered = True;
}
if (operations)
{
/***********************************/
/* file has associated MCL actions */
/***********************************/
XRectangle rects[2];
unsigned char flags;
int numRects = 0;
Cardinal n = 0;
Dimension s_t, adj_xy, adj_size;
/* ensure drop site operations and drop area are correct */
_DtIconGetIconRects(g, &flags, &rects[0], &rects[1]);
/*
* Compute adjustments to the drop area:
*
* - Add shadowThickness to the drop area:
* The icon gadget leaves space of width shadowThickness around
* the pixmap and label; use this space to make the drop zone
* larger.
*
* - Compensate for bug in drop zone registration/drawing:
* For some reason the drop zone displayed on the screen is
* actually smaller than the rectangle we register:
* The drag&drop library seems to reduce the size of the drop
* area by the value of highlightThickness at the top and left
* border and by highlightThickness-1 at the bottom and right.
* Is this a Motif drag&drop bug?
* We compensate by registering a larger rectangle.
*/
s_t = G_ShadowThickness(g);
adj_xy = s_t + G_HighlightThickness(g);
adj_size = adj_xy + s_t + G_HighlightThickness(g) - 1;
if (flags & XmPIXMAP_RECT)
{
rects[0].x -= g->rectangle.x + adj_xy;
rects[0].y -= g->rectangle.y + adj_xy;
rects[0].width += adj_size;
rects[0].height += adj_size;
numRects++;
}
if (flags & XmLABEL_RECT)
{
rects[1].x -= g->rectangle.x + adj_xy;
rects[1].y -= g->rectangle.y + adj_xy;
rects[1].width += adj_size;
rects[1].height += adj_size;
if (!numRects) rects[0] = rects[1];
numRects++;
}
if (numRects)
{
XtSetArg(args[n], XmNdropRectangles, rects); n++;
XtSetArg(args[n], XmNnumDropRectangles, numRects); n++;
}
XtSetArg (args[n], XmNdropSiteOperations, operations); n++;
XmDropSiteUpdate (file_view_data->widget, args, n);
g->icon.operations = operations;
/* add client data */
XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
XtAddCallback(file_view_data->widget, XmNdropCallback,
callback, callback_data);
}
else
{
/*********************************************/
/* file does not have associated MCL actions */
/*********************************************/
/* make drop site inactive */
XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
XmDropSiteUpdate (file_view_data->widget, args, 1);
XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
}
}
else
{
/*****************************/
/* icon gadget not displayed */
/*****************************/
if (file_view_data->registered)
{
/***************************************/
/* icon gadget registered as drop site */
/***************************************/
/* make drop site inactive */
XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
XmDropSiteUpdate (file_view_data->widget, args, 1);
XtRemoveAllCallbacks(file_view_data->widget, XmNdropCallback);
}
}
}
/*
* TypeToDropOperations
*/
unsigned char
TypeToDropOperations (
char * file_type)
{
unsigned char operations = 0L;
char *action;
/* does object have MOVE, COPY, and/or LINK actions */
/* -- or no actions at all */
if (action = DtDtsDataTypeToAttributeValue(file_type,
DtDTS_DA_MOVE_TO_ACTION,
NULL))
{
operations = operations | XmDROP_MOVE;
DtDtsFreeAttributeValue(action);
}
if (action = DtDtsDataTypeToAttributeValue(file_type,
DtDTS_DA_COPY_TO_ACTION,
NULL))
{
operations = operations | XmDROP_COPY;
DtDtsFreeAttributeValue(action);
}
if (action = DtDtsDataTypeToAttributeValue(file_type,
DtDTS_DA_LINK_TO_ACTION,
NULL))
{
operations = operations | XmDROP_LINK;
DtDtsFreeAttributeValue(action);
}
return(operations);
}
/*
* TypeToAction
*/
char *
TypeToAction (
unsigned char dropOperation,
char * logical_type)
{
char * action;
/* retrieve action from database based on dropOperation */
switch(dropOperation)
{
case XmDROP_MOVE:
action = DtDtsDataTypeToAttributeValue(logical_type,
DtDTS_DA_MOVE_TO_ACTION,
NULL);
break;
case XmDROP_COPY:
action = DtDtsDataTypeToAttributeValue(logical_type,
DtDTS_DA_COPY_TO_ACTION,
NULL);
break;
case XmDROP_LINK:
action = DtDtsDataTypeToAttributeValue(logical_type,
DtDTS_DA_LINK_TO_ACTION,
NULL);
break;
default:
action = NULL;
break;
}
return(action);
}
/*
* Given a fileViewData pointer, determine if it is part of a FileMgrData,
* or a DesktopRec; return the appropriate pointer.
*/
static
Boolean
IsDesktopPtr (
FileViewData * fileViewData,
FileMgrData ** fileMgrData,
DesktopRec ** desktopRec)
{
int i;
*desktopRec = NULL;
*fileMgrData = NULL;
for (i = 0; i < desktop_data->numIconsUsed; i++)
{
if (desktop_data->desktopWindows[i]->file_view_data == fileViewData)
{
*desktopRec = desktop_data->desktopWindows[i];
return(True);
}
}
*fileMgrData = (FileMgrData *)
((DirectorySet *)fileViewData->directory_set)->file_mgr_data;
return(False);
}
/******************************************************************
*
* PositionFileView -
* Given a particular file, position the file view that file
* is in on that particular file.
*
********************************************************************/
void
PositionFileView(
FileViewData *file_view_data,
FileMgrData *file_mgr_data)
{
Position x, y;
Arg args[1];
int value, size, increment, page, max;
FileMgrRec * file_mgr_rec = (FileMgrRec *)(file_mgr_data->file_mgr_rec);
Widget p;
/* if the file is filtered we can't highlight it! */
if(!file_view_data->displayed)
return;
/* Get the y location of the icon_gadget */
y = file_view_data->y - file_mgr_data->grid_height;
/* Two things:
*
* 1) not sure exactly how slow this is, but there seems to be no other
* way to do this. (CDExc23427)
* 2) XmScrollVisible does not work if the work window is not managed...
* so, we call it, and then get the appropriate x,y back from the
* scroll bars and set them (CDExc23428) */
p = XtVaCreateManagedWidget("positionicon", xmGadgetClass,
file_mgr_rec->file_window,
XmNmappedWhenManaged, False,
XmNx, file_view_data->x,
XmNy, y,
XmNwidth, file_mgr_data->grid_width,
XmNheight, file_mgr_data->grid_height,
NULL);
XmScrollVisible(file_mgr_rec->scroll_window, p,
XSPACING, YSPACING(file_mgr_data));
XtDestroyWidget(p);
XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
&value, &size, &increment, &page);
x = -((Position) value);
XmScrollBarGetValues(file_mgr_rec->vertical_scroll_bar,
&value, &size, &increment, &page);
y = -((Position) value);
XtVaSetValues(file_mgr_rec->file_window, XmNx, x, XmNy, y, NULL);
}
static Boolean
InMultipleObjectRegion (FileMgrData * file_mgr_data, FileViewData * fileViewData)
{
register int i;
for( i = 0; i < file_mgr_data->selected_file_count; ++i )
if( strcmp( file_mgr_data->selection_list[i]->file_data->file_name, fileViewData->file_data->file_name ) == 0 )
return True;
return False;
}
void
FmPopup (
Widget w,
XtPointer client_data,
XEvent *event,
FileMgrData *file_mgr_data)
{
FileMgrRec *file_mgr_rec;
Arg args[2];
FileViewData *fileViewData = NULL;
int i, num_of_children, obj_btns;
XmManagerWidget action_pane;
XmString label_string;
/* set number of popup children based on annotation */
num_of_children = FM_POPUP_CHILDREN_NA;
obj_btns = OBJ_BTNS_NA;
/* attach the popup widget info to the menu */
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
XtSetArg(args[0], XmNuserData, file_mgr_rec);
XtSetValues(fileMgrPopup.menu, args, 1);
if(file_mgr_data)
file_mgr_data->popup_menu_icon = NULL;
/* we are dealing with a white space popup */
if((w == NULL)
&& (client_data == NULL)
/*
&& (file_mgr_data->selected_file_count == 0)
*/
)
{
DirectorySet *directory_set;
/* retrieve the fileViewData for the current directory */
directory_set = file_mgr_data->directory_set[0];
for (i = 0; i < directory_set->file_count; i++)
{
if(strcmp(directory_set->order_list[i]->file_data->file_name, ".")
== 0)
{
fileViewData = directory_set->order_list[i];
break;
}
}
/* manage the white space buttons and unmanage the object buttons */
XtManageChildren(fileMgrPopup.wsPopup, WS_BTNS);
XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
XtUnmanageChild(fileMgrPopup.wsPopup[BTN_UNSELECTALL]);
if(file_mgr_data == trashFileMgrData)
{
/* Set popup menu label */
label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
XtSetArg (args[0], XmNlabelString, label_string);
XtSetValues (fileMgrPopup.title, args, 1);
XtManageChild(fileMgrPopup.title);
XmStringFree (label_string);
/* trash white space popup -- unmanage the properties and show */
/* hidden files buttons */
XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
XtUnmanageChild(fileMgrPopup.wsPopup[BTN_FIND]);
XtUnmanageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
/* align the remaining buttons */
XtSetArg(args[0], XmNmarginLeft, 0);
if( PositioningEnabledInView( file_mgr_data ) )
{
file_mgr_rec->menuStates |= CLEAN_UP;
XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
}
else
{
file_mgr_rec->menuStates &= ~(CLEAN_UP);
XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
}
XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
/* unmanage the action portion of the popup menu */
XtUnmanageChild(fileMgrPopup.action_separator);
action_pane = (XmManagerWidget) fileMgrPopup.menu;
for(i=num_of_children; i<action_pane->composite.num_children; i++)
XtUnmanageChild(action_pane->composite.children[i]);
}
else
{
Dimension margin;
/* manage the properties and show hidden files buttons */
if( file_mgr_data->toolbox )
XtUnmanageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
else
XtManageChild(fileMgrPopup.wsPopup[BTN_PROPERTIES]);
XtManageChild(fileMgrPopup.wsPopup[BTN_FIND]);
XtManageChild(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN]);
/* Set popup menu label */
label_string = XmStringCreateLocalized ((GETMESSAGE(33, 2, "Current Folder")));
XtSetArg (args[0], XmNlabelString, label_string);
XtSetValues (fileMgrPopup.title, args, 1);
XtManageChild(fileMgrPopup.title);
XmStringFree (label_string);
/* align the menu buttons */
action_pane = (XmManagerWidget) fileMgrPopup.menu;
XtSetArg(args[0], XmNmarginLeft, &margin);
XtGetValues(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], args, 1);
XtSetArg(args[0], XmNmarginLeft, margin);
if( PositioningEnabledInView( file_mgr_data ) )
{
file_mgr_rec->menuStates |= CLEAN_UP;
XtSetValues(fileMgrPopup.wsPopup[BTN_CLEANUP], args, 1);
}
else
{
file_mgr_rec->menuStates &= ~(CLEAN_UP);
XtUnmanageChild( fileMgrPopup.wsPopup[BTN_CLEANUP] );
}
XtSetValues(fileMgrPopup.wsPopup[BTN_SELECTALL], args, 1);
if(showFilesystem )
{
if (file_mgr_data->show_hid_enabled)
XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], True, False);
else
XmToggleButtonGadgetSetState(fileMgrPopup.wsPopup[BTN_SHOWHIDDEN], False, False);
}
/* ensure that there was fileViewData for the current directory */
if(fileViewData != NULL)
{
/* attach the current fileViewData to the 'Properties' button */
if( ! file_mgr_data->toolbox )
{
XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
XmNactivateCallback);
XtAddCallback (fileMgrPopup.wsPopup[BTN_PROPERTIES],
XmNactivateCallback,
ShowModAttrDialog, (XtPointer) fileViewData);
/* sensitize the 'Properties' option */
XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], True);
}
/* update the actions portion of the popup menu */
XtManageChild(fileMgrPopup.action_separator);
XtFree(fileMgrPopup.action_pane_file_type);
fileMgrPopup.action_pane_file_type =
XtNewString(fileViewData->file_data->logical_type);
UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
fileViewData->file_data->logical_type,
FM_POPUP, num_of_children,
fileMgrPopup.menu,
fileViewData->file_data->physical_type);
/* align actions portion of the popup menu */
for(i=num_of_children; i<action_pane->composite.num_children; i++)
XtSetValues(action_pane->composite.children[i], args, 1);
}
else
{
if( ! file_mgr_data->toolbox )
{
/* remove callback from 'Properties' button */
XtRemoveAllCallbacks(fileMgrPopup.wsPopup[BTN_PROPERTIES],
XmNactivateCallback);
/* desensitize the 'Properties' button */
XtSetSensitive(fileMgrPopup.wsPopup[BTN_PROPERTIES], False);
}
/* unmanage the action portion of the popup menu */
XtUnmanageChild(fileMgrPopup.action_separator);
for(i=num_of_children; i<action_pane->composite.num_children; i++)
XtUnmanageChild(action_pane->composite.children[i]);
}
}
}
/* we are dealing with an object popup */
else
{
char label[MAX_PATH];
/* retrieve the fileViewData for the selected icon */
if (client_data)
fileViewData = (FileViewData *) client_data;
else if (file_mgr_data->selected_file_count != 0)
fileViewData = file_mgr_data->selection_list[0];
/* unmanage the white space buttons */
XtUnmanageChildren(fileMgrPopup.wsPopup, WS_BTNS);
if(file_mgr_data == trashFileMgrData)
{
file_mgr_data->popup_menu_icon = fileViewData;
/* Set popup menu label */
if( file_mgr_data->selected_file_count > 1
&& InMultipleObjectRegion(file_mgr_data, fileViewData))
{
label_string = XmStringCreateLocalized ((GETMESSAGE(33,1, "Multiple Objects")));
}
else
{
char *tmp_label;
if (fileViewData->file_data->action_name)
tmp_label = fileViewData->file_data->action_name;
else
tmp_label = fileViewData->file_data->file_name;
if( strlen( tmp_label ) > 20 )
sprintf( label, "%-20.20s...", tmp_label );
else
sprintf( label, "%s", tmp_label );
label_string = XmStringCreateLocalized (label);
}
XtSetArg (args[0], XmNlabelString, label_string);
XtSetValues (fileMgrPopup.title, args, 1);
XtManageChild(fileMgrPopup.title);
XmStringFree (label_string);
/* trash popup--unmanage the non-trash buttons, manage the trash */
XtUnmanageChildren(fileMgrPopup.objPopup, obj_btns);
XtManageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
/* adjust callbacks */
XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_RESTORE],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.trash_objPopup[BTN_RESTORE],
XmNactivateCallback, Restore, (XtPointer) fileViewData);
XtRemoveAllCallbacks(fileMgrPopup.trash_objPopup[BTN_REMOVE],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.trash_objPopup[BTN_REMOVE],
XmNactivateCallback, ConfirmRemove,
(XtPointer) fileViewData);
/* unmanage the action portion of the popup menu */
XtUnmanageChild(fileMgrPopup.action_separator);
action_pane = (XmManagerWidget) fileMgrPopup.menu;
for(i=num_of_children; i<action_pane->composite.num_children; i++)
XtUnmanageChild(action_pane->composite.children[i]);
}
else
{
/* non-trash popup--manage the non-trash buttons, unmanage the trash */
XtManageChildren(fileMgrPopup.objPopup, obj_btns);
XtUnmanageChildren(fileMgrPopup.trash_objPopup, TRASH_OBJ_BTNS);
if( file_mgr_data->toolbox )
XtUnmanageChild(fileMgrPopup.objPopup[BTN_PROPERTIES]);
if(file_mgr_data->selected_file_count > 1
&& InMultipleObjectRegion(file_mgr_data, fileViewData))
{
/* we have many files selected; remove callbacks from the */
/* 'Properties', 'Put on Desktop', and 'Review' buttons */
/* and attach the selection list to the remaining buttons; */
/* desensitize the 3 buttons listed above; unmanage the */
/* actions part of the popup menu */
/* adjust callbacks */
if( ! file_mgr_data->toolbox )
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
XmNactivateCallback);
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON], XmNactivateCallback,
PutOnDTCB, (XtPointer) fileViewData);
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH], XmNactivateCallback,
TrashFiles, (XtPointer) fileViewData);
if( file_mgr_data->toolbox && geteuid() != root_user &&
access(file_mgr_data->current_directory,W_OK|X_OK) != 0)
XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
/* sensitize buttons */
if( !file_mgr_data->toolbox )
XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], False);
XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], False);
/* Set popup menu label */
label_string = XmStringCreateLocalized ((GETMESSAGE(33, 1, "Multiple Objects")));
XtSetArg (args[0], XmNlabelString, label_string);
XtSetValues (fileMgrPopup.title, args, 1);
XtManageChild(fileMgrPopup.title);
XmStringFree (label_string);
/* unmanage actions */
XtUnmanageChild(fileMgrPopup.action_separator);
action_pane = (XmManagerWidget) fileMgrPopup.menu;
for(i = num_of_children;
i < action_pane->composite.num_children;
i++)
XtUnmanageChild(action_pane->composite.children[i]);
}
else
{
char *tmp_label;
/* we have one file selected; attach fileViewData to buttons; */
/* sensitize any desensitized buttons; update the actions */
/* part of the popup menu */
/* adjust callbacks */
if( ! file_mgr_data->toolbox )
{
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PROPERTIES],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_PROPERTIES],
XmNactivateCallback, ShowModAttrDialog, (XtPointer) fileViewData);
}
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_PUTON],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_PUTON],
XmNactivateCallback, PutOnDTCB, (XtPointer) fileViewData);
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_TRASH],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_TRASH],
XmNactivateCallback, TrashFiles, (XtPointer) fileViewData);
if ( file_mgr_data->toolbox && geteuid() != root_user &&
access(file_mgr_data->current_directory,W_OK|X_OK) != 0 )
XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], False);
else
XtSetSensitive(fileMgrPopup.objPopup[BTN_TRASH], True);
XtRemoveAllCallbacks(fileMgrPopup.objPopup[BTN_HELP],
XmNactivateCallback);
XtAddCallback(fileMgrPopup.objPopup[BTN_HELP],
XmNactivateCallback, ObjectHelp, (XtPointer) fileViewData->widget);
/* sensitize buttons */
if( ! file_mgr_data->toolbox )
XtSetSensitive(fileMgrPopup.objPopup[BTN_PROPERTIES], True);
XtSetSensitive(fileMgrPopup.objPopup[BTN_PUTON], True);
XtSetSensitive(fileMgrPopup.objPopup[BTN_HELP], True);
if (fileViewData->file_data->action_name)
tmp_label = fileViewData->file_data->action_name;
else
tmp_label = fileViewData->file_data->file_name;
if( strlen( tmp_label ) > 20 )
sprintf( label, "%-20.20s...", tmp_label );
else
sprintf( label, "%s", tmp_label );
/* Set popup menu label */
label_string = XmStringCreateLocalized (label);
XtSetArg (args[0], XmNlabelString, label_string);
XtSetValues (fileMgrPopup.title, args, 1);
XtManageChild(fileMgrPopup.title);
XmStringFree (label_string);
/* update actions */
XtManageChild(fileMgrPopup.action_separator);
XtFree(fileMgrPopup.action_pane_file_type);
fileMgrPopup.action_pane_file_type =
XtNewString(fileViewData->file_data->logical_type);
UpdateActionMenuPane ((XtPointer)fileViewData, file_mgr_rec,
fileViewData->file_data->logical_type,
FM_POPUP, num_of_children,
fileMgrPopup.menu,
fileViewData->file_data->physical_type);
/* align actions */
action_pane = (XmManagerWidget) fileMgrPopup.menu;
XtSetArg(args[0], XmNmarginLeft, 0);
for(i = num_of_children; i < action_pane->composite.num_children; i++)
XtSetValues(action_pane->composite.children[i], args, 1);
}
}
}
/* position and manage popup menu */
if(event == NULL)
{
Position x, y;
Dimension width, height;
Dimension gWidth, gHeight;
int displayWidth, displayHeight;
DtIconGadget g = (DtIconGadget)w;
XtSetArg (args[0], XmNwidth, &width);
XtSetArg (args[1], XmNheight, &height);
XtGetValues(XtParent(fileMgrPopup.menu), args, 2);
gWidth = g->icon.pixmap_width;
gHeight = g->icon.pixmap_height;
displayWidth = DisplayWidth(XtDisplay(w), DefaultScreen(XtDisplay(w)));
displayHeight =DisplayHeight(XtDisplay(w), DefaultScreen(XtDisplay(w)));
x = file_mgr_rec->shell->core.x +
file_mgr_rec->scroll_window->core.x +
w->core.x + gWidth/2;;
y = file_mgr_rec->shell->core.y +
file_mgr_rec->header_frame->core.y +
file_mgr_rec->header_frame->core.height +
file_mgr_rec->scroll_window->core.y +
w->core.y + gHeight/2;;
if((Dimension)(x + width) > (Dimension)displayWidth)
x = displayWidth - width - 4;
if((Dimension)(y + height) > (Dimension)displayHeight)
y = displayHeight - height - 4;
XtSetArg (args[0], XmNx, x);
XtSetArg (args[1], XmNy, y);
XtSetValues(XtParent(fileMgrPopup.menu), args, 2);
}
else
{
if(( event->type == ButtonPress || event->type == ButtonRelease) ||
( ( event->type == KeyPress || event->type == KeyRelease) &&
_XmIsEventUnique(event) ) )
{
XmMenuPosition(fileMgrPopup.menu, (XButtonPressedEvent *)event);
}
}
XtManageChild(fileMgrPopup.menu);
if( event->type == KeyPress || event->type == KeyRelease )
{
/* Specify that the focus is being moved by key, NOT mouse
*/
_XmSetInDragMode(fileMgrPopup.menu,False);
XmProcessTraversal(fileMgrPopup.menu,XmTRAVERSE_CURRENT);
/* This function is being called twice.
Record this event so the above check _XmIsEventUnique will work
*/
_XmRecordEvent(event);
}
}
static void
DropOnRootCB (
Widget w,
XtPointer client_data,
XtPointer call_data)
{
DtDndDropCallbackStruct *fileList = (DtDndDropCallbackStruct *)call_data;
char * ptr;
char ** file_set = NULL;
char ** host_set = NULL;
FileMgrRec * file_mgr_rec;
FileMgrData * file_mgr_data;
char *next;
int i, j;
int wsNum;
String end;
String tmpStr;
int numFiles;
int effScreenWidth = 0;
int effScreenHeight = 0;
int start_x = 0, start_y = 0;
int root_x, root_y;
int step = 0, dstep = 0;
/* Check the protocol, set to failure if not the */
/* File Transfer protocol */
if (fileList->dropData->protocol != DtDND_FILENAME_TRANSFER)
{
fileList->status = DtDND_FAILURE;
return;
}
numFiles = fileList->dropData->numItems;
DPRINTF (("DropOnRoot: Number of files dropped are %d\n", numFiles));
if(fileList->reason != DtCR_DND_DROP_ANIMATE)
{
/* set the complete move flag to False since it is not required to be called */
/* In case when the drag is from non File manager client */
if(!dragActive)
initiating_view = NULL;
fileList->completeMove = False;
_DtSetDroppedFileInfo(fileList, &file_set, &host_set);
if(initiating_view != NULL)
{
file_mgr_rec = (FileMgrRec *)
(((FileMgrData *) initiating_view)->file_mgr_rec);
file_mgr_data = (FileMgrData *) initiating_view;
}
else
file_mgr_data = NULL;
/* get the correct position for the desktop icon shell */
PositionDesktopIcon(fileList->x, fileList->y, &root_x, &root_y);
if (numFiles > 1)
{
/*
* We will place the icons by marching down a diagonal starting
* at the drop point. But we don't want to march off-screen
* if there are too many icons. So ...
* - We choose a step width of 20, 10, 5, or 2 depending
* on the number of icons dropped.
* - When we run into the edge of the screen, we start a new
* diagonal shifted one step to the right.
* - If all icons still won't fit, we move the starting point
* closer to the top left corner of the screen.
*/
/* compute effective screen size (largest x,y where an icon
* can be placed without going off-screen) */
effScreenWidth = WidthOfScreen(XtScreen(w)) - (4 + 4+48+4 + 5);
effScreenHeight = HeightOfScreen(XtScreen(w)) - (4 + 4+48+3+15+4 + 5);
/* chosee step depending on number of icons */
if (numFiles <= 200)
step = 20;
else if (numFiles <= 400)
step = 10;
else if (numFiles <= 1000)
step = 5;
else
step = 2;
dstep = 40 + 4+48+4 + 5;
/* choose starting point so at least two icons will fit */
if (root_x <= effScreenWidth - step)
start_x = root_x;
else
start_x = effScreenWidth - step;
if (root_y <= effScreenWidth - step)
start_y = root_y;
else
start_y = effScreenWidth - step;
DPRINTF(("DropOnRootCB: numFiles %d, root_x %d, root_y %d, step %d\n",
numFiles, root_x, root_y, step));
/* check if all icons will fit */
for (;;)
{
/* cacluclate how many will fit (add up icons on all diagonals) */
int n = 0, nd = 0;
for (root_x = start_x; root_x <= effScreenWidth; root_x += dstep)
{
int nx = (effScreenWidth - root_x)/step + 1;
int ny = (effScreenHeight - start_y)/step + 1;
n += (nx <= ny)? nx: ny;
nd++;
}
DPRINTF(("start_x %d, start_y %d, nd %d, n %d\n",
start_x, start_y, nd, n));
/* if everything fits - great! */
if (n >= numFiles)
break;
/* move the start point closer to the top left corner */
if (effScreenWidth - start_x < effScreenHeight - start_y &&
start_x >= step)
{
/* move left so more icons will fit */
start_x -= step;
}
else if (effScreenWidth - start_x > effScreenHeight - start_y &&
start_y >= step)
{
/* move up so one more icon will fit in each diagonal */
start_y -= step;
}
else if (start_x > 0 || start_y > 0)
{
/* move left and up */
if (start_x >= step)
start_x -= step;
else
start_x = 0;
if (start_y >= step)
start_y -= step;
else
start_y = 0;
}
else
/* ran out of space - too bad! */
break;
}
root_x = start_x;
root_y = start_y;
}
/* the icon that was dropped on the root window was an
icon that was already on the root window */
if (file_mgr_data == NULL)
{
DPRINTF(("DropOnRoot: Object already on Desktop\n"));
/* loop through the existing desktop icons to determine which
ones are being dragged, then change their location */
for(i=0; i < desktop_data->numIconsUsed; i++)
{
if((Widget)desktop_data->desktopWindows[i]->iconGadget ==
(Widget)widget_dragged)
{
if (DTFileIsSelected(desktop_data->desktopWindows[i],
desktop_data->desktopWindows[i]->file_view_data))
{
for(j=0;j< desktop_data->numWorkspaces;j++)
if(desktop_data->workspaceData[j]->number ==
desktop_data->desktopWindows[i]->workspace_num)
break;
wsNum = j;
for (j = 0;
j < desktop_data->workspaceData[wsNum]->files_selected;
j++)
{
RelocateDesktopIcon(desktop_data->workspaceData[wsNum]->
selectedDTWindows[j],
root_x, root_y);
root_x += step;
root_y += step;
if (root_x > effScreenWidth || root_y > effScreenHeight)
{
start_x += dstep;
if (start_x > effScreenWidth)
start_x = 0;
root_x = start_x;
root_y = start_y;
}
}
}
else
{
RelocateDesktopIcon(desktop_data->desktopWindows[i],
root_x, root_y);
break;
}
}
}
}
else if( file_mgr_data == trashFileMgrData )
{
/* if the file manager data is the trash, we want to tell the
user that they can't drop trash on the desktop
*/
char * msg;
char * tmpStr;
DPRINTF(("DropOnRoot: Attempting to Drag Trash Object to Desktop\n"));
file_mgr_rec = (FileMgrRec *)trashFileMgrData->file_mgr_rec;
tmpStr = (GETMESSAGE(11,37, "You can't drop files from\nthe Trash Can on to the Workspace.\nTo remove an object from Trash,\n -Select the object, and\n -Choose 'Put Back'\nfrom the File menu or the object's popup menu.\nYou can then drag the object out of File Manager and drop it on\nthe Workspace backdrop."));
msg = XtNewString(tmpStr);
FileOperationError (file_mgr_rec->main, msg, NULL);
XtFree(msg);
return;
}
else /* it was dropped on the root window so lets process it */
{
int EndIndex = desktop_data->numIconsUsed;
for(i = 0; i < numFiles; i++)
{
ptr = strrchr(file_set[i], '/');
if( strcmp(file_mgr_data->current_directory, file_set[i]) == 0)
{
SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
file_mgr_data, file_mgr_rec,
".", host_set[i], file_set[i],
root_x, root_y,
NULL,EndIndex);
}
else if(strncmp(file_mgr_data->current_directory, file_set[i], strlen(file_set[i]) ) == 0 )
{
SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
file_mgr_data, file_mgr_rec,
"..", host_set[i],file_mgr_data->current_directory,
root_x, root_y,
NULL,EndIndex);
}
else
{
*ptr = '\0';
if(*(file_set[i]) == 0)
{
SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
file_mgr_data, file_mgr_rec,
ptr + 1, host_set[i], "/",
root_x, root_y,
NULL,EndIndex);
}
else
{
SetupDesktopWindow(XtDisplay(file_mgr_rec->shell),
file_mgr_data, file_mgr_rec,
ptr + 1, host_set[i], file_set[i],
root_x, root_y,
NULL,EndIndex);
}
}
root_x += step;
root_y += step;
if (root_x > effScreenWidth || root_y > effScreenHeight)
{
start_x += dstep;
if (start_x > effScreenWidth)
start_x = 0;
root_x = start_x;
root_y = start_y;
}
}
initiating_view = (XtPointer)NULL;
}
_DtFreeDroppedFileInfo(numFiles, file_set, host_set);
return;
}
}
/************************************************************************
*
* FreeLayoutData
*
************************************************************************/
void
FreeLayoutData(XtPointer p)
{
IconLayoutData *layout_data;
if (p == NULL)
return;
layout_data = (IconLayoutData *)p;
if (layout_data->work_id != 0)
{
DPRINTF(("FreeLayoutData: removing workproc\n"));
XtRemoveWorkProc(layout_data->work_id);
XmDropSiteEndUpdate(layout_data->drop_site_w);
}
XtFree((char *)layout_data->order_list);
layout_data->order_list = NULL;
XtFree((char *)layout_data->reuse_icons);
layout_data->reuse_icons = NULL;
XtFree((char *)layout_data->reuse_btns);
layout_data->reuse_btns = NULL;
XtFree((char *)layout_data->manage);
layout_data->manage = NULL;
XtFree((char *)layout_data);
layout_data = NULL;
}
/************************************************************************
*
* UnmanageFileIcons
* Unmanage a subset of the file icons.
*
************************************************************************/
void UnmanageFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
FileViewData *file_view_data)
{
XmManagerWidget file_window;
FileViewData **order_list;
int order_count;
int i, n;
Widget *unmanage;
Widget child;
Arg args[20];
/* Set the size of the file window BIG so that it does not */
/* try to force positioning on its children. */
file_window = (XmManagerWidget) file_mgr_rec->file_window;
XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
/* Set the scrolled window and file window appropriately */
/* to prevent a lot of gyrations. */
XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
XtSetValues (file_mgr_rec->scroll_window, args, 1);
order_list = ((IconLayoutData *)file_mgr_data->layout_data)->order_list;
order_count = ((IconLayoutData *)file_mgr_data->layout_data)->order_count;
unmanage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
n = 0;
for (i = 0; i < order_count; i++)
{
if (order_list[i]->filtered)
continue;
if ((n > 0 || order_list[i] == file_view_data) &&
!order_list[i]->need_update)
{
unmanage[n++] = order_list[i]->widget;
if (order_list[i]->treebtn)
unmanage[n++] = order_list[i]->treebtn;
}
}
/* remember which icon currently has the focus */
if (XtIsManaged(file_mgr_rec->file_window))
{
/* see if the focus is inside the file window */
child = XmGetFocusWidget(file_mgr_rec->file_window);
if (child != NULL && XtParent(child) == file_mgr_rec->file_window)
file_mgr_rec->focus_widget = child;
}
/* unmanage the selected children */
if (n > 0)
XtUnmanageChildren(unmanage, n);
XtFree((char *)unmanage);
}
/************************************************************************
*
* UpdateFileIcons
* Create or reuse a set of file icons used to get the files
* displayed. This is never called for the desktop.
*
************************************************************************/
void
UpdateFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
Boolean new_directory)
{
_UpdateFileIcons(file_mgr_rec, file_mgr_data, new_directory, NULL);
}
void
AddFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
DirectorySet * add_dir_set)
{
_UpdateFileIcons(file_mgr_rec, file_mgr_data, False, add_dir_set);
}
/*--------------------------------------------------------------------
* MakeReuseList
*
* Background information:
* After a refresh on a directory we want to reuse old icon and tree
* button widgets instead of destroying the old widgets and creating
* new ones. Fourthermore, we want to reuse the same widgets for the
* same files, so that if the icon and/or label didn't change, less
* work needs to be done in _UpdateFileIcons().
* For this reason, after a refresh the GetFileData() routine copies
* Widgets from the old FileViewData list to the new FileViewData list
* for files that are both on the old and new list (i.e., files that
* already existed before the refresh and are still there after the
* refresh). This allows _UpdateFileIcons() to reuse the old
* widget.
*
* The purpose of MakeReuseList() is to find widgets that are no
* longer found in the new FileViewData list. These are widgets
* from files that disappeared after the refresh (either because the
* file was deleted or because file is now filtered out). These
* widgets can then be reused by _UpdateFileIcons()for new files that
* just appeared after the refresh.
*
*------------------------------------------------------------------*/
/* compare function for qsort and bsearch */
static int
WidgetCmp(Widget *w1, Widget *w2)
{
return *w1 - *w2;
}
static void
MakeReuseList(
Widget *children,
int num_children,
FileViewData **order_list,
int order_count,
Widget **reuse_icons,
Widget **reuse_btns)
{
#ifdef DEBUG
int n_old, n_filtered, del_icon, del_btn;
#endif
Widget *sorted_chilren = NULL;
Boolean *reuse = NULL;
int icon_count;
int btn_count;
int i;
Widget *p;
Widget w;
/* allocate widget arrays */
*reuse_icons = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
*reuse_btns = (Widget *)XtMalloc((num_children + 1)*sizeof(Widget));
icon_count = btn_count = 0;
/* only figure things out if we already have children */
if (num_children > 0) {
/* create a sorted list of children */
sorted_chilren = (Widget *)XtMalloc(num_children * sizeof(Widget));
memcpy(sorted_chilren, children, num_children * sizeof(Widget));
qsort(sorted_chilren, num_children, sizeof(Widget), (int (*)())WidgetCmp);
/* create reuse flags; initially assume all children can be reused */
reuse = (Boolean *)XtMalloc(num_children * sizeof(Boolean));
for (i = 0; i < num_children; i++)
reuse[i] = True;
/* reset reuse flag for all widgets found in order_list */
#ifdef DEBUG
n_old = n_filtered = del_icon = del_btn = 0;
#endif
for (i = 0; i < order_count; i++)
{
if (order_list[i]->filtered &&
strcmp(order_list[i]->file_data->file_name, ".") != 0)
{
/* don't reuse this widget later */
#ifdef DEBUG
n_filtered++;
if (order_list[i]->widget)
del_icon++;
if (order_list[i]->treebtn)
del_btn++;
#endif
order_list[i]->widget =
order_list[i]->treebtn = NULL;
}
else
{
if (order_list[i]->widget)
{
p = bsearch(&order_list[i]->widget,
sorted_chilren, num_children, sizeof(Widget),
(int (*)())WidgetCmp);
if (p)
{
/* don't reuse this widget for any other file */
reuse[p - sorted_chilren] = False;
#ifdef DEBUG
n_old++;
#endif
}
else
{
/* don't reuse this widget later */
order_list[i]->widget = NULL;
#ifdef DEBUG
del_icon++;
#endif
}
}
if (order_list[i]->treebtn)
{
p = bsearch(&order_list[i]->treebtn,
sorted_chilren, num_children, sizeof(Widget),
(int (*)())WidgetCmp);
if (p)
{
/* don't reuse this widget for any other file */
reuse[p - sorted_chilren] = False;
}
else
{
/* don't reuse this widget later */
order_list[i]->treebtn = NULL;
#ifdef DEBUG
del_btn++;
#endif
}
}
}
}
/* copy reusable widgets into widget arrays */
for (i = 0; i < num_children; i++)
{
if (reuse[i])
{
/* this widget can be reused for new files */
w = sorted_chilren[i];
if (XtClass(w) == dtIconGadgetClass)
{
#ifndef DELAYED_UNREGISTER
Arg args[1];
XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
XtRemoveAllCallbacks(w, XmNdropCallback);
XtSetValues (w, args, 1);
#endif
(*reuse_icons)[icon_count++] = w;
}
else if (XtClass(w) == xmPushButtonGadgetClass)
(*reuse_btns)[btn_count++] = w;
}
}
}
/* null-terminate the arrays */
(*reuse_icons)[icon_count] = NULL;
(*reuse_btns)[btn_count] = NULL;
/* free storage */
XtFree((char *)sorted_chilren);
XtFree((char *)reuse);
DPRINTF(("MakeReuseList: count %d (%d new, %d old, %d filtered)\n",
order_count, order_count - n_filtered - n_old, n_old, n_filtered));
DPRINTF((" reuse %d + %d, del %d + %d\n",
icon_count, btn_count, del_icon, del_btn));
}
/*--------------------------------------------------------------------
* UpdateOneIconLabel
*------------------------------------------------------------------*/
static void
UpdateOneIconLabel(
FileMgrData *file_mgr_data,
FileViewData *file_view_data)
{
char *label;
char *s;
/* Get the label and icon to be used for the widget */
if (file_mgr_data->view != BY_ATTRIBUTES)
{
if (strcmp(file_view_data->file_data->file_name, "..") == 0)
{
/* label = ".. (go up)" */
s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
label = (char *)XtMalloc(2 + strlen(s) + 1);
strcpy(label, "..");
strcat(label, s);
}
else if (file_mgr_data->view == BY_NAME &&
file_view_data->file_data->physical_type == DtDIRECTORY &&
file_mgr_data->show_type != MULTIPLE_DIRECTORY)
{
/* label = "name/" */
label = (char *)XtMalloc(
strlen(file_view_data->file_data->file_name) + 2);
strcpy(label, file_view_data->file_data->file_name);
strcat(label, "/");
}
else if (file_mgr_data->view == BY_NAME &&
file_view_data->file_data->physical_type == DtEXECUTABLE)
{
/* label = "name*" */
label = (char *)XtMalloc(
strlen(file_view_data->file_data->file_name) + 2);
strcpy(label, file_view_data->file_data->file_name);
strcat(label, "*");
}
else if(file_view_data->file_data->action_name != NULL)
/* label = action name */
label = XtNewString(file_view_data->file_data->action_name);
else
/* label = file name */
label = XtNewString(file_view_data->file_data->file_name);
}
else /* file_mgr_data->view == BY_ATTRIBUTES */
{
/* label = file name + attributes */
label = GetLongName(file_view_data->file_data);
if (strcmp(file_view_data->file_data->file_name, "..") == 0)
{
s = GetSharedMessage(UP_ONE_LEVEL_LABEL);
label = (char *)XtRealloc(label, strlen(label) + strlen(s) + 1);
strcat(label, s);
}
}
/* store new label */
XtFree(file_view_data->label);
file_view_data->label = label;
}
/*--------------------------------------------------------------------
* UpdateOneFileIcon
*------------------------------------------------------------------*/
static void
UpdateOneFileIcon(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
FileViewData *file_view_data)
{
XmString icon_label;
char *logical_type;
PixmapData *pixmapData;
Widget icon_widget;
Widget btn_widget;
Boolean is_instance_icon;
Boolean instance_icon_changed;
Arg args[35];
int n_color_args;
int argi_imageName;
int n;
XmManagerWidget file_window = (XmManagerWidget) file_mgr_rec->file_window;
DirectorySet *directory_set = (DirectorySet *)file_view_data->directory_set;
IconLayoutData *layout_data = (IconLayoutData *)file_mgr_data->layout_data;
/* Get the label and icon to be used for the widget */
if (!file_view_data->label)
UpdateOneIconLabel(file_mgr_data, file_view_data);
icon_label = XmStringCreateLocalized(file_view_data->label);
/* Get the icon name based on the file type */
logical_type = file_view_data->file_data->logical_type;
if (file_mgr_data->view == BY_NAME)
pixmapData = NULL;
else if (openDirType == NEW &&
file_view_data->file_data->physical_type == DtDIRECTORY)
{
pixmapData = CheckForOpenDirectory(file_view_data,
directory_set,
file_mgr_data,
logical_type);
}
else
{
if (file_mgr_data->view == BY_NAME_AND_ICON)
pixmapData = _DtRetrievePixmapData(
logical_type,
file_view_data->file_data->file_name,
directory_set->name,
(Widget) file_window,
LARGE);
else
pixmapData = _DtRetrievePixmapData(
logical_type,
file_view_data->file_data->file_name,
directory_set->name,
(Widget) file_window,
SMALL);
}
/* check if this is an instance icon */
is_instance_icon = False;
if (pixmapData != NULL)
{
char tmp[1024];
strcpy(tmp, directory_set->name);
strcat(tmp, "/");
strcat(tmp, file_view_data->file_data->file_name);
if (strcmp(pixmapData->iconFileName, tmp) == 0)
is_instance_icon = True;
}
/* check if instance icon was modified */
instance_icon_changed = False;
if (is_instance_icon)
{
if (file_view_data->icon_mtime != file_view_data->file_data->stat.st_mtime)
{
if (file_view_data->icon_mtime != 0)
instance_icon_changed = True;
file_view_data->icon_mtime = file_view_data->file_data->stat.st_mtime;
}
}
else
file_view_data->icon_mtime = 0;
/* Build the arg list for color resources. */
n = 0;
XtSetArg (args[n], XmNarmColor, white_pixel); n++;
if (layout_data->background == white_pixel)
{
if (file_view_data->selected)
{
XtSetArg (args[n], XmNbackground, black_pixel); n++;
XtSetArg (args[n], XmNforeground, white_pixel); n++;
}
else
{
XtSetArg (args[n], XmNbackground, white_pixel); n++;
XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
}
XtSetArg (args[n], XmNpixmapBackground, white_pixel); n++;
XtSetArg (args[n], XmNpixmapForeground, black_pixel); n++;
}
else if (layout_data->background == black_pixel)
{
if (file_view_data->selected)
{
XtSetArg (args[n], XmNbackground, white_pixel); n++;
XtSetArg (args[n], XmNforeground, black_pixel); n++;
}
else
{
XtSetArg (args[n], XmNbackground, black_pixel); n++;
XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
}
XtSetArg (args[n], XmNpixmapBackground, white_pixel); n++;
XtSetArg (args[n], XmNpixmapForeground, black_pixel); n++;
}
else
{
if (file_view_data->selected)
{
XtSetArg (args[n], XmNbackground, white_pixel); n++;
XtSetArg (args[n], XmNforeground, black_pixel); n++;
XtSetArg (args[n], XmNpixmapBackground, white_pixel); n++;
XtSetArg (args[n], XmNpixmapForeground, black_pixel); n++;
}
else
{
XtSetArg (args[n], XmNbackground, layout_data->background); n++;
XtSetArg (args[n], XmNforeground, layout_data->foreground); n++;
XtSetArg (args[n], XmNpixmapBackground, layout_data->pixmap_back); n++;
XtSetArg (args[n], XmNpixmapForeground, layout_data->pixmap_fore); n++;
}
}
n_color_args = n;
/* Build the rest of the arg list and either create or reuse the widget. */
XtSetArg (args[n], XmNstring, icon_label); n++;
argi_imageName = n;
if (pixmapData)
XtSetArg (args[n], XmNimageName, pixmapData->iconFileName);
else
XtSetArg (args[n], XmNimageName, NULL);
n++;
XtSetArg (args[n], XmNmaxPixmapWidth, layout_data->pixmap_width); n++;
XtSetArg (args[n], XmNmaxPixmapHeight, layout_data->pixmap_height); n++;
XtSetArg (args[n], XmNuserData, directory_set); n++;
XtSetArg (args[n], XmNunderline, False); n++;
XtSetArg (args[n], XmNfillMode, XmFILL_TRANSPARENT); n++;
if (file_mgr_data->view == BY_NAME_AND_ICON &&
file_mgr_data->show_type != MULTIPLE_DIRECTORY)
XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_TOP);
else
XtSetArg (args[n], XmNpixmapPosition, XmPIXMAP_LEFT); n++;
/* See if we can re-use the same or some other icon gadget */
if (file_view_data->widget)
icon_widget = file_view_data->widget;
else if (*layout_data->next_icon_to_use)
icon_widget = *layout_data->next_icon_to_use++;
else
icon_widget = NULL;
/* See if we found an available icon gadget */
if (icon_widget)
{
/* reuse the icon gadget */
if (icon_widget != file_view_data->widget || file_mgr_data->newSize)
{
XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
XtRemoveAllCallbacks(icon_widget, XmNdropCallback);
file_view_data->registered = False;
}
XtRemoveAllCallbacks (icon_widget, XmNcallback);
/* if instance_icon_changed, force destroy of old pixmap */
if (instance_icon_changed)
XtSetArg (args[argi_imageName], XmNimageName, NULL);
/*
* Move the gadget off the visible area; this avoids unnecessary
* redraw events at the old position when the gadget is moved to
* the correct position once it is determined in LayoutFileIcons.
*/
icon_widget->core.x = -999;
icon_widget->core.y = -999;
XtSetValues (icon_widget, args, n);
if (instance_icon_changed && pixmapData)
{
XtSetArg (args[0], XmNimageName, pixmapData->iconFileName);
XtSetValues (icon_widget, args, 1);
}
}
else
{
/* create a new or duplicate an existing widget */
XtSetArg (args[n], XmNshadowThickness, 2); n++;
XtSetArg (args[n], XmNdropSiteOperations, XmDROP_NOOP);n++;
XtSetArg (args[n], XmNfontList, user_font); n++;
if( keybdFocusPolicy == XmEXPLICIT)
{
XtSetArg (args[n], XmNtraversalOn, True); n++;
}
else
{
XtSetArg (args[n], XmNtraversalOn, False); n++;
XtSetArg (args[n], XmNhighlightThickness, 0); n++;
}
XtSetArg (args[n], XmNborderType, DtNON_RECTANGLE); n++;
if (layout_data->dup_icon_widget == NULL)
{
#ifdef HARDCODED_ICON_MARGINS
XtSetArg (args[n], XmNmarginWidth, 0); n++;
XtSetArg (args[n], XmNmarginHeight, 0); n++;
#endif
XtSetArg (args[n], XmNx, -999); n++;
XtSetArg (args[n], XmNy, -999); n++;
icon_widget = layout_data->dup_icon_widget =
_DtCreateIcon ((Widget)file_window, "icon", args, n);
}
else
{
DtIconGadget g;
int i = n_color_args;
icon_widget = _DtDuplicateIcon ((Widget)file_window,
layout_data->dup_icon_widget,
icon_label,
(pixmapData? pixmapData->iconFileName: NULL),
(XtPointer)directory_set, /* userData */
False); /* underline */
g = (DtIconGadget)icon_widget;
g->gadget.highlighted = False;
g->gadget.highlight_drawn = False;
/*
* Move the gadget off the visible area; this avoids unnecessary
* redraw events at the old position when the gadget is moved to
* the correct position once it is determined in LayoutFileIcons.
*/
icon_widget->core.x = -999;
icon_widget->core.y = -999;
/* make sure colors, drop operations, and clipping are right */
XtSetArg(args[i], XmNdropSiteOperations, XmDROP_NOOP); i++;
XtSetArg(args[i], XmNmaxPixmapWidth, layout_data->pixmap_width); i++;
XtSetArg(args[i], XmNmaxPixmapHeight, layout_data->pixmap_height); i++;
XtSetValues (icon_widget, args, i);
}
XtAddCallback(icon_widget, XmNhelpCallback,
(XtCallbackProc)HelpRequestCB, NULL);
file_view_data->registered = False;
}
if (file_mgr_data->view != BY_NAME)
_DtCheckAndFreePixmapData(logical_type,
(Widget) file_window,
(DtIconGadget) icon_widget,
pixmapData);
#ifdef _SHOW_LINK
if (file_view_data->file_data->link != 0)
{
XtSetArg (args[0], XmNforeground, layout_data->topshadow);
XtSetValues (icon_widget, args, 1);
}
#endif
/*
* If viewing by attributes, adjust spacing between the icon pixmap and
* the file name so that all file names are aligned.
*/
if (file_mgr_data->view != BY_NAME_AND_ICON ||
file_mgr_data->show_type == MULTIPLE_DIRECTORY)
{
Dimension pixmap_width = ((DtIconGadget)icon_widget)->icon.pixmap_width;
if (pixmap_width < layout_data->pixmap_width)
{
XtSetArg (args[0], XmNspacing,
layout_data->spacing + layout_data->pixmap_width - pixmap_width);
XtSetValues (icon_widget, args, 1);
}
}
file_view_data->file_data->is_broken = False;
file_view_data->widget = icon_widget;
XtAddCallback (icon_widget, XmNcallback, (XtCallbackProc)IconCallback,
file_view_data);
XmStringFree (icon_label);
/* Check if we need a button for tree branch expand */
if (file_mgr_data->show_type != MULTIPLE_DIRECTORY ||
!file_view_data->file_data->is_subdir)
{
/* no tree branch expand button needed */
file_view_data->treebtn = NULL;
}
else
{
/* create a tree branch expand button */
Pixmap px = GetTreebtnPixmap(file_mgr_data, file_view_data);
n = 0;
XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
XtSetArg(args[n], XmNlabelPixmap, px); n++;
XtSetArg(args[n], XmNbackground, layout_data->background); n++;
XtSetArg(args[n], XmNtraversalOn, False); n++;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
XtSetArg(args[n], XmNshadowThickness, 0); n++;
XtSetArg(args[n], XmNmarginWidth, 0); n++;
XtSetArg(args[n], XmNmarginHeight, 0); n++;
XtSetArg(args[n], XmNuserData, file_mgr_data); n++;
XtSetArg(args[n], XmNx, -999); n++;
XtSetArg(args[n], XmNy, -999); n++;
/* See if we can re-use the same or some other button gadget */
if (file_view_data->treebtn)
btn_widget = file_view_data->treebtn;
else if (*layout_data->next_btn_to_use)
btn_widget = *(layout_data->next_btn_to_use)++;
else
btn_widget = NULL;
/* See if we found an available button gadget */
if (btn_widget) {
XtRemoveAllCallbacks (btn_widget, XmNactivateCallback);
XtSetValues (btn_widget, args, n);
}
else
{
btn_widget = XmCreatePushButtonGadget((Widget)file_window,
"tree_button", args, n);
}
XtAddCallback(btn_widget, XmNactivateCallback,
(XtCallbackProc)TreeBtnCallback, file_view_data);
file_view_data->treebtn = btn_widget;
}
/* this entry is now up-to-date */
file_view_data->need_update = False;
}
/*--------------------------------------------------------------------
* _UpdateFileIcons
*------------------------------------------------------------------*/
static void
_UpdateFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
Boolean new_directory,
DirectorySet * add_dir_set)
{
XmManagerWidget file_window;
FileViewData **order_list;
int order_count;
Widget child;
Arg args[5];
IconLayoutData *layout_data;
int i;
#ifdef DT_PERFORMANCE
struct timeval update_time_s;
struct timeval update_time_f;
#endif
DPRINTF(("_UpdateFileIcons(\"%s\", new_dir %c, add_dir_set %p) ...\n",
file_mgr_data->current_directory,
new_directory? 'T': 'F', add_dir_set));
/* Set the size of the file window BIG so that it does not */
/* try to force positioning on its children. */
file_window = (XmManagerWidget) file_mgr_rec->file_window;
XtResizeWidget ((Widget)file_window, 32767, 32767, 0);
/* Set the scrolled window and file window appropriately */
/* to prevent a lot of gyrations. */
XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmSTATIC);
XtSetValues (file_mgr_rec->scroll_window, args, 1);
/* For faster updates, unmanage all the icons */
if (XtIsManaged(file_mgr_rec->file_window))
{
/* see if the focus is inside the file window */
child = XmGetFocusWidget(file_mgr_rec->file_window);
if (child != NULL)
{
if (new_directory)
{
file_mgr_rec->focus_widget = file_mgr_rec->file_window;
}
else if( XtParent(child) == file_mgr_rec->file_window )
{
/* remember which widget had the focus */
file_mgr_rec->focus_widget = child;
}
}
DPRINTF((" focus_widget = %p (%s)\n",
file_mgr_rec->focus_widget,
file_mgr_rec->focus_widget?
XtName(file_mgr_rec->focus_widget): "nil"));
XtUnmanageChild(file_mgr_rec->file_window);
}
XtUnmanageChildren(file_window->composite.children,
file_window->composite.num_children);
/* if this is a new directory, scroll to the top */
if (new_directory)
{
XtSetArg (args[0], XmNx, 0);
XtSetArg (args[1], XmNy, 0);
XtSetValues ((Widget)file_window, args, 2);
}
/*
* Don't leave the view in a munged state for too long.
* Only do if we are not creating a new view. This is because the
* view is not yet in the 'view_list', and so the redisplay code
* may not use the correct redisplay function.
*/
if (ReturnDesktopPtr(file_mgr_rec->file_window))
{
UpdateHeaders(file_mgr_rec, file_mgr_data, False);
XFlush (XtDisplay (file_window));
XmUpdateDisplay ((Widget)file_window);
}
/* free any old layout data */
FreeLayoutData(file_mgr_data->layout_data);
file_mgr_data->layout_data = NULL;
/* if directory-read still in progress, don't do anything more now */
if (file_mgr_data->busy_status != not_busy)
{
DPRINTF(("done (busy)\n"));
return;
}
#ifdef DT_PERFORMANCE
printf(" Beginning UpdateFileIcons\n");
gettimeofday(&update_time_s, NULL);
/* added by Rafi */
_DtPerfChkpntMsgSend("Begin Update Icons");
#endif
/* set up new layout data */
layout_data = (IconLayoutData *)XtCalloc(1, sizeof(IconLayoutData));
file_mgr_data->layout_data = (XtPointer)layout_data;
FlattenTree(file_mgr_data, &order_list, &order_count);
layout_data->order_list = order_list;
layout_data->order_count = order_count;
MakeReuseList(file_window->composite.children,
file_window->composite.num_children,
order_list, order_count,
&layout_data->reuse_icons,
&layout_data->reuse_btns);
layout_data->next_icon_to_use = layout_data->reuse_icons;
layout_data->next_btn_to_use = layout_data->reuse_btns;
layout_data->manage = (Widget *)XtMalloc(2*order_count*sizeof(Widget));
layout_data->manage_count = 0;
layout_data->i_do_next_vis = 0;
layout_data->i_do_next_all = 0;
/*
* Iterate through the file list and mark all entries to be in
* need of update. We also construct icon labels at this time,
* since they are need by LayoutFileIcons to estimate icon gadget
* sizes.
*/
if (add_dir_set)
{
/* only need to iterate throught the new entries */;
order_list = add_dir_set->order_list;
order_count = add_dir_set->file_count;
}
for (i = 0; i < order_count; i++)
{
order_list[i]->need_update = True;
order_list[i]->selected = False;
UpdateOneIconLabel(file_mgr_data, order_list[i]);
}
/* set selected flag on all files in selection_list */
for (i = 0; i < file_mgr_data->selected_file_count; i++)
file_mgr_data->selection_list[i]->selected = True;
#ifdef DT_PERFORMANCE
gettimeofday(&update_time_f, NULL);
if (update_time_s.tv_usec > update_time_f.tv_usec) {
update_time_f.tv_usec += 1000000;
update_time_f.tv_sec--;
}
printf(" done UpdateFileIcons, time: %ld.%ld\n\n", update_time_f.tv_sec - update_time_s.tv_sec, update_time_f.tv_usec - update_time_s.tv_usec);
/* added by Rafi */
_DtPerfChkpntMsgSend("Done Update Icons");
#endif
DPRINTF(("done\n"));
}
/************************************************************************
*
* CreateTreeIcons
* Create icons for tree-branch-expand buttons.
*
************************************************************************/
static void
CreateTreeIcons(Widget w)
{
Arg args[20];
Pixel background_color = 0;
Pixel foreground_color = 0;
int i, j;
TreePxId px;
char pxname[128];
unsigned int width, height, dummy;
XtSetArg (args[0], XmNbackground, &background_color);
XtSetArg (args[1], XmNforeground, &foreground_color);
XtGetValues (w, args, 2);
/* JET - 4/29/18, It seems for some reason that no matter what
* background is specified for these pixmaps, it will always be
* black when drawn. This seems like a Motif issue. The problem
* arises when earlier on, depending on what Palette has been
* selected for the user, the foreground can also be black. In
* those cases, instead of seeing the pixmap, you see a black square
* since both the fg and bg colors are black now. We "fix" this by
* always forcing the foreground to be white. This is a
* "workaround" - the real problem still needs to be located and
* fixed. in motif.
*/
foreground_color = 0x00ffffff;
for (i = 0; i < 3; i++)
{
TreeBtnWd[i] = 5;
TreeBtnHt[i] = 5;
for (j = 0; j < tpxN; j++)
{
strcpy(pxname, TreePxTab[j].name);
strcat(pxname, TreePxSuffix[i]);
TreePxTab[j].px[i] = _DtGetPixmap(XtScreen(w), pxname,
foreground_color, background_color);
width = height = 0;
XGetGeometry(XtDisplay(w), TreePxTab[j].px[i],
(Window *) &dummy, /* returned root window */
(int *) &dummy, (int *) &dummy, /* x, y of pixmap */
&width, &height, /* pixmap width, height */
&dummy, &dummy); /* border width, depth */
if (j == tpxNil)
{
TreeNilWd[i] = width;
TreeNilHt[i] = height;
}
else
{
if (width > TreeBtnWd[i])
TreeBtnWd[i] = width;
if (height > TreeBtnHt[i])
TreeBtnHt[i] = height;
}
}
}
}
/************************************************************************
*
* GetTreebtnPixmap
* Get icon for tree-branch-expand buttons.
*
************************************************************************/
Pixmap GetTreebtnPixmap(
FileMgrData *file_mgr_data,
FileViewData *file_view_data)
{
TreePxId pxid = tpxNil;
/* if not yet done, create tree button icons */
/* @@@ do this earlier from main? */
if (TreeBtnWd[0] == 0)
CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
if (file_view_data->ts == tsNotRead)
pxid = tpxNotRead;
else if (file_view_data->ts == tsError)
pxid = tpxError;
else if (file_view_data->ndir == 0 &&
(file_view_data->nfile == 0 ||
file_mgr_data->tree_files == TREE_FILES_NEVER)
&& (file_view_data->ts == tsNone || !showEmptySet))
pxid = tpxEmpty;
else if (file_view_data->ts == tsNone)
pxid = tpxMore;
else if (file_view_data->ts == tsDirs)
pxid = (file_view_data->nfile == 0 ||
file_mgr_data->tree_files == TREE_FILES_NEVER)? tpxLess:
(file_view_data->ndir == 0)? tpxMore:
tpxBoth;
else if (file_view_data->ts == tsAll)
pxid = tpxLess;
if (file_mgr_data->view == BY_NAME)
return TreePxTab[pxid].px[0]; /* small pixmap */
else if (file_mgr_data->view == BY_NAME_AND_ICON)
return TreePxTab[pxid].px[2]; /* large pixmap */
else
return TreePxTab[pxid].px[1]; /* medium pixmap */
}
/************************************************************************
*
* GetIconSize
* Compute maximum icon size.
*
************************************************************************/
static void
GetIconLayoutParms(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
IconLayoutData *ld)
{
DirectorySet *directory_set;
int file_count;
FileViewData **file_list;
int i;
DtIconGadget g;
Arg args[10];
Dimension shadowThickness;
Dimension marginWidth;
Dimension maxWidth = ld->pixmap_width;
Dimension gadgetWidth;
/* determine pixmap size */
if (file_mgr_data->view == BY_NAME)
{
/* no pixmap */
ld->pixmap_width = 0;
ld->pixmap_height = 0;
}
else if (file_mgr_data->view == BY_NAME_AND_ICON)
{
/* large pixmap */
ld->pixmap_width = largeIconWidth;
ld->pixmap_height = largeIconHeight;
}
else
{
/* small pixmap */
ld->pixmap_width = smallIconWidth;
ld->pixmap_height = smallIconHeight;
}
/* find the icon gadget for "." */
directory_set = file_mgr_data->directory_set[0];
file_count = directory_set->file_count;
file_list = directory_set->file_view_data;
g = NULL;
for (i = 0; i < file_count; i++)
{
if (strcmp(file_list[i]->file_data->file_name, ".") == 0)
{
g = (DtIconGadget)file_list[i]->widget;
break;
}
}
/* get layout parameters from "." */
if (g)
{
XtSetArg(args[0], XmNhighlightThickness, &ld->highlight);
XtSetArg(args[1], XmNshadowThickness, &shadowThickness);
XtSetArg(args[2], XmNmarginWidth, &marginWidth);
XtSetArg(args[3], XmNspacing, &ld->spacing);
XtSetArg(args[4], XmNalignment, &ld->alignment);
XtSetArg(args[5], XmNpixmapPosition, &ld->pixmap_position);
XtGetValues((Widget)g, args, 6);
if (g->icon.pixmap_width < maxWidth)
ld->spacing = ld->spacing - (maxWidth - g->icon.pixmap_width);
ld->width = ((Widget)g)->core.width +
ld->pixmap_width - g->icon.pixmap_width;
ld->height = ((Widget)g)->core.height +
ld->pixmap_height - g->icon.pixmap_height;
ld->char_width = (g->icon.string_width)/strlen(file_list[i]->label);
if (ld->pixmap_position != XmPIXMAP_TOP)
ld->width -= g->icon.string_width;
ld->margin = ld->highlight + shadowThickness + marginWidth;
}
else
{
/* No icon gadget for "." found: strange! Guess some defaults. */
ld->char_width = 8;
ld->margin = 2 + 1 + 1;
ld->spacing = 2;
ld->highlight = (keybdFocusPolicy == XmEXPLICIT)? 2: 0;
ld->alignment = XmALIGNMENT_END;
if (file_mgr_data->view == BY_NAME_AND_ICON &&
file_mgr_data->show_type != MULTIPLE_DIRECTORY)
{
ld->pixmap_position = XmPIXMAP_TOP;
ld->width = 2*ld->margin + ld->pixmap_width;
ld->height = 2*ld->margin + ld->pixmap_height + ld->spacing + 14;
}
else
{
ld->pixmap_position = XmPIXMAP_LEFT;
ld->width = 2*ld->margin + ld->pixmap_width +
ld->spacing + ld->char_width;
ld->height = 2*ld->margin + ld->pixmap_height;
}
}
/* determine which size tree buttons to use */
if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
ld->treebtn_size = 0; /* no tree buttons needed */
else if (file_mgr_data->view == BY_NAME)
ld->treebtn_size = 0; /* small size */
else if (file_mgr_data->view == BY_NAME_AND_ICON)
ld->treebtn_size = 2; /* large size */
else
ld->treebtn_size = 1; /* medium size */
}
static void
EstimateIconSize(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
IconLayoutData *layout_data,
FileViewData *file_view_data,
Dimension *width,
Dimension *height)
{
int label_len;
int label_width;
if (file_view_data == NULL) {
label_len = 1;
} else {
#ifdef MULTIBYTE
label_len = DtCharCount(file_view_data->label == NULL ?
file_view_data->file_data->file_name : file_view_data->label);
#else
label_len = strlen(file_view_data->label == NULL ?
file_view_data->file_data->file_name : file_view_data->label);
#endif
}
if (layout_data->pixmap_position == XmPIXMAP_TOP)
{
label_width = 2*layout_data->margin + label_len*layout_data->char_width;
if ((Dimension)label_width > layout_data->width)
*width = label_width;
else
*width = layout_data->width;
}
else
*width = layout_data->width + (label_len) * layout_data->char_width;
*height = layout_data->height;
}
/************************************************************************
*
* GetExtraHeight
* Compute extra height for drawing nil symbol for empty tree branches.
*
************************************************************************/
static Dimension
GetExtraHeight(
FileMgrData *file_mgr_data,
FileViewData *file_view_data,
int treebtn_size)
{
if (showEmptySet &&
file_view_data->file_data->is_subdir &&
file_view_data->ts >= tsDirs &&
file_view_data->ndir == 0 &&
(file_view_data->nfile == 0 ||
file_mgr_data->tree_files == TREE_FILES_NEVER))
{
return YSPACING(file_mgr_data) + TreeNilHt[treebtn_size];
}
else
return 0;
}
/************************************************************************
*
* EraseTreeLines
* Erase connecting lines in tree mode from a specified icon widget
* on down; called when a tree branch is expanded or collapsed to
* erase previous tree lines before drawing new icons and tree lines.
*
************************************************************************/
void
EraseTreeLines(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
FileViewData *file_view_data)
{
XmManagerWidget file_window;
Dimension fw_width, fw_height;
Position x, y;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
if (!XtIsManaged((Widget)file_window))
return;
/* get upper left corner of grid space for the icon widget */
x = file_view_data->x;
y = file_view_data->y - file_mgr_data->grid_height;
/* Get file window width and height */
fw_width = file_window->core.width;
fw_height = file_window->core.height;
DPRINTF2(("EraseTreeLines(\"%s\"): x/y %d/%d (widget %d/%d)\n",
file_view_data->file_data->file_name, x, y,
file_view_data->widget->core.x,
file_view_data->widget->core.y));
/* clear area from icon widget to bottom of file window */
XClearArea(XtDisplay(file_window), XtWindow(file_window),
x, y, fw_width - x, fw_height - y, False);
/*
* clear area to the right and above the icon widget
* (necessary if there are multiple columns, which happens if
* there are more icons than fit into a single column of
* maximum height 32767)
*/
if (y > 0 && (Dimension)(x + file_mgr_data->grid_width) < fw_width)
{
x += file_mgr_data->grid_width;
XClearArea(XtDisplay(file_window), XtWindow(file_window),
x, 0, fw_width - x, y, False);
}
}
/************************************************************************
*
* RedrawTreeLines
* Redraw connecting lines in tree mode.
*
************************************************************************/
void
RedrawTreeLines(
Widget w,
int ex, int ey, int ewidth, int eheight, int ecount,
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data)
{
static char *empty_msg = NULL;
FileViewData *file_view_data;
IconLayoutData *layout_data;
Dimension grid_width, grid_height;
Dimension extra_height, e_height;
int sz;
FileViewData **order_list;
int order_count;
GC solid_gc, dash_gc;
int i, k;
Position x, xl;
Position y, y0, y1;
int level;
Bool more[256];
XFontSetExtents *extents;
int font_height;
int font_yoffset;
int tmp;
if (!XtIsManaged(w))
return;
/* get layout parameters */
layout_data = (IconLayoutData *)file_mgr_data->layout_data;
order_list = layout_data->order_list;
order_count = layout_data->order_count;
grid_width = file_mgr_data->grid_width;
grid_height = file_mgr_data->grid_height;
sz = layout_data->treebtn_size;
DPRINTF2(("RedrawTreeLines(x %d, y %d, wd %d, ht %d, count %d)\n",
ex, ey, ewidth, eheight, ecount));
if (grid_width == 0 || grid_height == 0)
/* layout probably not yet done */
return;
/* if not yet done, create tree button icons */
/* @@@ do this earlier from main? */
if (TreeBtnWd[0] == 0)
CreateTreeIcons(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window);
/* select line styles */
if (file_mgr_data->view == BY_NAME) {
solid_gc = file_mgr_data->tree_solid_thin_gc;
dash_gc = file_mgr_data->tree_dash_thin_gc;
} else {
solid_gc = file_mgr_data->tree_solid_thick_gc;
dash_gc = file_mgr_data->tree_dash_thick_gc;
}
x = MARGIN;
y = MARGIN;
for (k = 0; k < order_count; k++)
{
if (!order_list[k]->displayed)
continue;
/* determine the height of this item */
file_view_data = order_list[k];
extra_height = GetExtraHeight(file_mgr_data, file_view_data, sz);
GetLevel(file_view_data, &level);
/* check if we need to go to the next column */
tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
if (tmp + MARGIN > MAXWINSIZE)
{
/* window would exceed height limit; go to the next column */
x += grid_width + XSPACING;
y = MARGIN;
tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
}
/* check if current item intersects the exposed region */
y0 = y - YSPACING(file_mgr_data)
- grid_height
+ (Dimension)(grid_height - TreeBtnHt[sz])/(Dimension)2
+ TreeBtnHt[sz];
y1 = y + grid_height + extra_height + YSPACING(file_mgr_data);
if (x <= ex + ewidth && x + TreeWd(level, sz) > ex &&
y0 <= ey + eheight && y1 > ey)
{
GetAncestorInfo(file_mgr_data, file_view_data, NULL, NULL, more);
/* draw vertical connecting lines for upper tree levels */
for (i = 0; i < level; i++) {
if (more[i])
XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
x + TreeLX(i, sz), y0,
x + TreeLX(i, sz), y1);
}
/* draw vertical connecting line for this tree level */
xl = x + TreeLX(level, sz);
if (level > 0) {
XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
xl, y0,
xl, more[level]? y1: y + grid_height/2);
if (file_view_data->file_data->is_subdir || !more[level]) {
/* draw horizontal line */
XDrawLine(XtDisplay(w), XtWindow(w),
(file_view_data->file_data->is_subdir &&
file_view_data->ts == tsNotRead)? dash_gc: solid_gc,
xl, y + grid_height/2,
xl + TreeOffset, y + grid_height/2);
}
}
/* draw nil symbol for empty subdirs */
if (extra_height)
{
xl += TreeOneWd(sz);
y0 += grid_height + YSPACING(file_mgr_data);
y1 = y + grid_height + YSPACING(file_mgr_data);
e_height = extra_height - YSPACING(file_mgr_data);
XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
xl, y0,
xl, y1 + e_height/2);
XDrawLine(XtDisplay(w), XtWindow(w), solid_gc,
xl, y1 + e_height/2,
xl + TreeOffset, y1 + e_height/2);
xl = x + TreeWd(level, sz) + TreeBtnWd[sz];
XCopyArea(XtDisplay(w), TreePxTab[tpxNil].px[sz],
XtWindow(w), solid_gc,
0, 0, TreeNilWd[sz], TreeNilHt[sz],
xl, y1);
/*
if (empty_msg == NULL)
empty_msg = XtNewString("(empty)");
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;
}
XDrawImageString(XtDisplay(w), XtWindow(w), solid_gc,
xl + TreeNilWd[sz] + 2,
y1 + (TreeNilHt[sz] - font_height)/2 + font_yoffset,
empty_msg, strlen(empty_msg));
*/
}
}
/* goto next item */
y = (Position)tmp;
}
}
/************************************************************************
*
* DisplaySomeIcons
* Check if any incons or widgets in the area given by ex, ey, ewd,
* and eht need to be updated.
*
************************************************************************/
#ifdef DEBUG
static int g_workCount1 = 0;
static int g_workCount2 = 0;
static int g_callCount = 0;
#endif
static Boolean
ToBeManaged(
IconLayoutData *layout_data,
FileViewData *file_view_data)
{
int i;
for (i = 0; i < layout_data->manage_count; i++)
if (layout_data->manage[i] == file_view_data->widget)
return True;
return False;
}
static int
DisplaySomeIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
int ex, int ey, int ewd, int eht,
int workLimit,
Boolean doAll)
{
#ifdef DT_PERFORMANCE
struct timeval update_time_s;
struct timeval update_time_f;
#endif
XmManagerWidget file_window;
FileViewData **order_list;
int order_count;
Arg args[10];
Arg args_dso_get[1];
Arg args_dso_set[1];
IconLayoutData *layout_data;
FileViewData **change;
int changeCount;
Widget *manage;
int manageCount;
int workCount1;
int workCount2;
Dimension grid_width, grid_height;
Dimension icon_width, icon_height;
Dimension extra_height;
int i, k;
Position x, y;
FileViewData *file_view_data;
Boolean changed;
Widget child;
DtIconGadget g;
int level;
unsigned char operations;
Widget *wp;
ObjectPosition *position_data;
XRectangle textExtent;
/* Get a list of icon and button widgets we can re-use */
file_window = (XmManagerWidget) file_mgr_rec->file_window;
layout_data = (IconLayoutData *)file_mgr_data->layout_data;
order_list = layout_data->order_list;
order_count = layout_data->order_count;
manage = layout_data->manage + layout_data->manage_count;
/* allocate storage for list of changed icons */
change = (FileViewData **)XtMalloc(order_count * sizeof(FileViewData *));
/* Find the maximum values for the icon heights and widths */
grid_width = file_mgr_data->grid_width;
grid_height = file_mgr_data->grid_height;
#ifdef DT_PERFORMANCE
printf(" Begin Part 1, DisplaySomeIcons (update icons)\n");
gettimeofday(&update_time_s, NULL);
/* added by Rafi */
_DtPerfChkpntMsgSend("Begin Display Icons");
#endif
DPRINTF2((
"DisplaySomeIcons(\"%s\", x/y %d/%d, wd/ht %d/%d, i %d:%d) ...\n",
file_mgr_data->current_directory, ex, ey, ewd, eht,
layout_data->i_do_next_vis,
layout_data->i_do_next_all));
/* set up args for querying/unregistering drop sites */
XtSetArg (args_dso_get[0], XmNdropSiteOperations, &operations);
XtSetArg (args_dso_set[0], XmNdropSiteOperations, XmDROP_NOOP);
/*
* Iterate through the list of files and create/update and position
* all visible icon gadgets for which this work hasn't been done yet
* (need_update flag set).
*/
changeCount = 0;
manageCount = 0;
workCount1 = 0;
if (doAll)
k = layout_data->i_do_next_all;
else
k = layout_data->i_do_next_vis;
for ( ; k < order_count && workCount1 < workLimit; k++)
{
/*
* Process focus widget before everything else so that we can restore
* the focus when we manage the file_window again. If a file was
* being renamed, we do that one first.
*/
if (!layout_data->focus_done)
{
/* search for focus widget in order_list and see if still displayed */
file_view_data = NULL;
if (file_mgr_rec->focus_widget != NULL)
{
if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
{
for (i = 0; i < order_count; i++)
if (order_list[i]->displayed)
{
file_view_data = order_list[i];
break;
}
}
else
{
for (i = 0; i < order_count; i++)
if (order_list[i]->widget == file_mgr_rec->focus_widget)
{
if (order_list[i]->displayed)
file_view_data = order_list[i];
break;
}
}
}
/* if not found, focus could be on a rename text widget */
if (file_view_data == NULL)
file_view_data = file_mgr_data->renaming;
layout_data->focus_done = True;
if (file_view_data)
{
k--;
/* decrement loop index, so that the entry that was supposed to be
processed here will be looked at again in the next iteration
*/
goto do_this_entry;
}
}
/* ignore files that are filtered */
file_view_data = order_list[k];
if (file_view_data->filtered &&
strcmp(file_view_data->file_data->file_name, ".") != 0)
{
continue;
}
/*
* If the file is not currenly displayed (collapsed tree branch) or
* is currenly scrolled out of view, we don't need to do anything
* at this time. Except ...
*/
if (!file_view_data->displayed ||
((int)file_view_data->x + (int)grid_width) < ex ||
file_view_data->x >= ex + ewd ||
file_view_data->y < ey ||
((int)file_view_data->y - (int)grid_height) >= (ey + eht))
{
/*
* ... if this file still has an old icon widget, AND if the
* old icon position is visible, AND if the icon was registered
* as a drop site, we will have a "ghost drop zone" showing up where
* the icon used to be. The old icon gadget is unmanaged and will
* remain unmanaged until later when we update it and move it to the
* correct positon (happens only when the user scrolls to the new
* position). In the meantime, even though the gadget is unmanged,
* its old position still remains registered as a drop site,
* so we have to either unregister it or move the gadget to
* its new position now.
*/
child = file_view_data->widget;
if (child != NULL &&
(Position)(child->core.x + child->core.width) >= (Position)ex &&
child->core.x < ex + ewd &&
(Position)(child->core.y + child->core.height) >= (Position)ey &&
child->core.y < ey + eht)
{
if (!file_view_data->displayed)
{
XtGetValues (child, args_dso_get, 1);
if (operations != XmDROP_NOOP)
{
XtSetValues (child, args_dso_set, 1);
workCount1++;
file_view_data->registered = False;
}
continue;
}
} else
continue;
}
do_this_entry:
/*
* If not yet done, create/update the icon gadget for this file
*/
if (file_view_data->need_update)
{
UpdateOneFileIcon(file_mgr_rec, file_mgr_data, file_view_data);
child = file_view_data->widget;
/*
* We may need to adjust the icon position based on the difference
* between estimated size and actual size.
*/
if (layout_data->alignment == XmALIGNMENT_CENTER &&
file_mgr_data->view == BY_NAME_AND_ICON)
{
EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
file_view_data, &icon_width, &icon_height);
if (child->core.width != icon_width)
{
file_view_data->x = file_view_data->x
- (Dimension)(grid_width - icon_width)/(Dimension)2
+ (Dimension)(grid_width - child->core.width)/(Dimension)2;
}
}
if (PositioningEnabledInView(file_mgr_data))
{
position_data = file_view_data->position_info;
if (position_data->late_bind)
{
/*
* When new objects are dropped on the random placement window,
* they do not yet have a widget, so the drop_y could not be
* adjusted to take into account the height of the icon;
* this must be done now, after the object has an icon.
*/
/*
position_data->y -= child->core.height/2;
*/
position_data->late_bind = False;
file_view_data->y = position_data->y + child->core.height;
}
else if (child->core.height != grid_height)
{
/* @@@ ??? @@@
* Not quite right: have to distinguish two cases:
* (1) position_data->y read from .!xxx file
* file_view_data->y computed by adding grid_height
* (2) file_view_data->y from layout
* position_data->y computed by subtracting grid_height
* In case (1) have to recompute file_view_data->y; in case
* (2) have to recompute position_data->y. Code below only
* works for case (2).
*/
/*
position_data->y = file_view_data->y - child->core.height;
*/
}
}
changed = True;
}
else
changed = False;
/* if focus is supposed to be in the file window, focus on this widget */
if (file_mgr_rec->focus_widget == file_mgr_rec->file_window)
file_mgr_rec->focus_widget = file_view_data->widget;
/* determine desired icon postition */
child = file_view_data->widget;
if (PositioningEnabledInView(file_mgr_data))
{
x = file_view_data->position_info->x;
y = file_view_data->position_info->y;
}
else if (file_mgr_data->show_type != MULTIPLE_DIRECTORY)
{
x = file_view_data->x;
y = file_view_data->y - child->core.height;
}
else /* file_mgr_data->show_type == MULTIPLE_DIRECTORY */
{
GetLevel(file_view_data, &level);
extra_height = GetExtraHeight(file_mgr_data, file_view_data,
layout_data->treebtn_size);
/* check position of tree button, if any */
if (file_view_data->treebtn)
{
child = file_view_data->treebtn;
x = file_view_data->x
+ TreeLX(level, layout_data->treebtn_size) + TreeOffset;
y = file_view_data->y
- grid_height
+ (Dimension)(grid_height - child->core.height)/(Dimension)2;
if (child->core.x != x || child->core.y != y)
XmeConfigureObject(child, x, y, child->core.width,
child->core.height, child->core.border_width);
child = file_view_data->widget;
}
if (child->core.height < grid_height)
{
x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
y = file_view_data->y
- grid_height
+(Dimension)(grid_height - child->core.height)/(Dimension)2;
}
else
{
x = file_view_data->x + TreeWd(level, layout_data->treebtn_size);
y = file_view_data->y - grid_height;
}
}
if (child->core.x != x || child->core.y != y)
{
XmeConfigureObject(child, x, y, child->core.width,
child->core.height, child->core.border_width);
changed = True;
}
/* make sure the icon gadget and tree button, if any, are managed */
if (!XtIsManaged(child) && !ToBeManaged(layout_data, file_view_data))
{
manage[manageCount++] = child;
if (file_view_data->treebtn)
manage[manageCount++] = file_view_data->treebtn;
changed = True;
}
if (changed)
{
/* remember which icons were changed */
change[changeCount++] = file_view_data;
workCount1++;
/*
* If the icon we just changed was being renamed, make sure
* the corresponding text widget is positioned correctly.
*/
if (file_view_data == file_mgr_data->renaming)
{
for (i = 0; i < file_window->composite.num_children; i++)
{
child = file_window->composite.children[i];
if (XmIsTextField(child))
{
/* Check if the text field is still needed */
if (!child->core.being_destroyed)
{
/* move to the correct position */
_DtIconGetTextExtent_r(file_view_data->widget,
&textExtent);
x = textExtent.x;
y = textExtent.y -
(Dimension)(child->core.height - textExtent.height)/(Dimension)2;
XmeConfigureObject(child, x, y, child->core.width,
child->core.height,
child->core.border_width);
/* manage it */
manage[manageCount++] = child;
}
break;
}
}
}
}
}
/* remember where we left off ... */
if (doAll)
layout_data->i_do_next_all = k;
else
layout_data->i_do_next_vis = k;
#ifdef DT_PERFORMANCE
gettimeofday(&update_time_f, NULL);
if (update_time_s.tv_usec > update_time_f.tv_usec) {
update_time_f.tv_usec += 1000000;
update_time_f.tv_sec--;
}
printf(" done Part 1, DisplaySomeIcons, time: %ld.%ld\n\n",
update_time_f.tv_sec - update_time_s.tv_sec,
update_time_f.tv_usec - update_time_s.tv_usec);
/* the following message send call added by Rafi */
_DtPerfChkpntMsgSend("Done Display Icons");
#endif
#ifdef DT_PERFORMANCE
printf(" Begin Part 2, DisplaySomeIcons (register drop sites)\n");
gettimeofday(&update_time_s, NULL);
/* added by Rafi */
_DtPerfChkpntMsgSend("Begin Register drop sites");
#endif
/* unregister drop sites of unused icon gadgets */
workCount2 = 0;
#ifdef DELAYED_UNREGISTER
for (wp = layout_data->next_icon_to_use;
(child = *wp) != NULL;
wp++)
{
if ((Position)(child->core.x + child->core.width) >= (Position)ex &&
child->core.x < ex + ewd &&
(Position)(child->core.y + child->core.height) >= (Position)ey &&
child->core.y < ey + eht)
{
XtGetValues (child, args_dso_get, 1);
if (operations != XmDROP_NOOP)
{
XtSetValues (child, args_dso_set, 1);
workCount2++;
if (workCount2/2 >= workLimit)
break;
}
}
}
#endif
/*
* Register drop sites
*
* Note: in "as placed" mode, we defer this work and do it in
* CommitWorkProcUpdates instead. Reason: need to re-register
* all drop sites in top-to-bottom stacking order at that time.
*/
if (! PositioningEnabledInView(file_mgr_data) &&
file_mgr_data != trashFileMgrData)
{
for (k = 0; k < changeCount; k++)
{
SetHotRects(change[k],
(XtCallbackProc) DropOnObject,
(XtPointer) change[k]);
}
}
/* free storage */
XtFree((char *)change);
change = NULL;
/* update count of children to be managed */
layout_data->manage_count += manageCount;
#ifdef DT_PERFORMANCE
gettimeofday(&update_time_f, NULL);
if (update_time_s.tv_usec > update_time_f.tv_usec) {
update_time_f.tv_usec += 1000000;
update_time_f.tv_sec--;
}
printf(" done Part 2 DisplaySomeIcons, time: %ld.%ld\n\n",
update_time_f.tv_sec - update_time_s.tv_sec,
update_time_f.tv_usec - update_time_s.tv_usec);
/* the following message send call added by Rafi */
_DtPerfChkpntMsgSend("Done Register drop sites");
#endif
DPRINTF2((" ... %d+%d changed (%d managed)\n",
workCount1, workCount2, manageCount));
#ifdef DEBUG
g_workCount1 += workCount1;
g_workCount2 += workCount2;
g_callCount++;
#endif
return (workCount1 >= workCount2)? workCount1: workCount2;
}
/************************************************************************
*
* Display work procedure
*
************************************************************************/
static void
CommitWorkProcUpdates(
FileMgrRec *file_mgr_rec,
FileMgrData * file_mgr_data,
Boolean reset)
{
XmManagerWidget file_window;
IconLayoutData *layout_data;
Widget w;
int i;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
layout_data = (IconLayoutData *)file_mgr_data->layout_data;
if (layout_data == NULL)
return;
DPRINTF((
"CommitWorkProcUpdates: %d+%d updates (m %d, n %d, i %d:%d, reset %d)\n",
g_workCount1,
g_workCount2,
layout_data->manage_count,
g_callCount,
layout_data->i_do_next_vis,
layout_data->i_do_next_all,
reset));
#ifdef DEBUG
g_workCount1 = 0;
g_workCount2 = 0;
g_callCount = 0;
#endif
if (reset)
{
layout_data->i_do_next_vis = 0;
layout_data->i_do_next_all = 0;
}
/* if work proc no longer active, everything should already be commited */
if (layout_data->work_id == 0)
return;
/* manage new children */
if (layout_data->manage_count > 0)
{
if (PositioningEnabledInView(file_mgr_data))
OrderChildrenList(file_mgr_data);
XtManageChildren(layout_data->manage, layout_data->manage_count);
}
/*
* In "as placed" mode, need to register drop sites now.
* (If not "as placed" mode, this was already done in DisplaySomeIcons.)
*/
if (PositioningEnabledInView(file_mgr_data))
RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
/* commit drop site updates */
XmDropSiteEndUpdate(layout_data->drop_site_w);
/* If not managed yet, manage the file window again */
if (!XtIsManaged((Widget)file_window))
{
XtArgVal incr;
Arg args[2];
XtManageChild ((Widget)file_window);
XtVaGetValues(file_mgr_rec->vertical_scroll_bar,XmNuserData,&incr,NULL);
if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
file_mgr_rec->scroll_window)
&& incr > 0 )
{
XtSetArg (args[0], XmNincrement,incr);
XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
}
XmUpdateDisplay ((Widget)file_window);
}
/* Try to preserve the focus */
if (file_mgr_rec->focus_widget)
{
/* see if the widget that previously had the focus was just managed */
w = NULL;
for (i = 0; i < layout_data->manage_count; i++)
{
if (layout_data->manage[i] == file_mgr_rec->focus_widget)
{
w = file_mgr_rec->focus_widget;
break;
}
}
/* if focus widget not found, set focus on file_window */
if (w == NULL)
w = (Widget)file_window;
XmProcessTraversal(w, XmTRAVERSE_CURRENT);
file_mgr_rec->focus_widget = NULL;
}
layout_data->manage_count = 0;
/* start new update */
XmDropSiteStartUpdate(layout_data->drop_site_w);
}
static Boolean
DisplayWorkProc(
XtPointer client_data)
{
FileMgrRec *file_mgr_rec = (FileMgrRec *)client_data;
DialogData * dialog_data;
FileMgrData * file_mgr_data;
XmManagerWidget file_window;
IconLayoutData *layout_data;
int ex, ey, ewd, eht;
ObjectPosition *bottom;
Widget child;
int n;
Boolean commit_updates = False;
int n1 = 1;
int n2 = 1;
dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
if (dialog_data == NULL)
return False;
file_mgr_data = (FileMgrData *) dialog_data->data;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
layout_data = (IconLayoutData *)file_mgr_data->layout_data;
/* get the position and size of the currently visible area */
ex = -file_window->core.x;
ey = -file_window->core.y;
ewd = XtParent(file_window)->core.width;
eht = XtParent(file_window)->core.height;
/* check if the window scrolled */
if (ex != layout_data->ex || ey != layout_data->ey)
{
layout_data->i_do_next_vis = layout_data->i_do_next_all;
layout_data->visible_done = False;
}
/* first work on icons in the currently visible area */
if (layout_data->visible_done)
n = 0;
else
{
n = DisplaySomeIcons(file_mgr_rec, file_mgr_data, ex, ey, ewd, eht, n1, False);
if (n == 0)
{
/* we just finished updating all visible icons */
DPRINTF(("DisplayWorkProc: visible done.\n"));
layout_data->visible_done = True;
commit_updates = True;
}
}
/* if we still have some time left, work on other icons */
if (layout_data->visible_done && n < n2)
{
n = DisplaySomeIcons(file_mgr_rec, file_mgr_data,
0, 0, 32767, 32767, n2 - n, True);
/* check if we are done */
if (n == 0)
{
layout_data->all_done = True;
commit_updates = True;
}
else if (layout_data->manage_count >= 100)
commit_updates = True;
}
if (commit_updates)
{
/* manage new children and commit drop site updates */
CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, False);
/*
* In "as placed" mode, icons may overlap.
* Force redraw in bottom to top stacking order.
*/
if (PositioningEnabledInView(file_mgr_data))
{
for (bottom = GetBottomOfStack(file_mgr_data);
bottom;
bottom = (ObjectPosition *)bottom->prev)
{
if (bottom->file_view_data != NULL &&
bottom->file_view_data->displayed &&
!bottom->file_view_data->need_update)
{
child = bottom->file_view_data->widget;
if ((Position)(child->core.x + child->core.width) >= (Position)ex &&
child->core.x < ex + ewd &&
(Position)(child->core.y + child->core.height) >= (Position)ey &&
child->core.y < ey + eht)
{
RedrawOneGadget(child, NULL, NULL);
}
}
}
}
}
if (layout_data->all_done)
{
/* all work is done; all icons are up-to-date */
file_mgr_data->newSize = False;
layout_data->work_id = 0;
XmDropSiteEndUpdate(layout_data->drop_site_w);
DPRINTF(("DisplayWorkProc: all done.\n"));
/* returning True will end the work proc */
return True;
}
else
{
/* remember current scroll position */
layout_data->ex = ex;
layout_data->ey = ey;
return False;
}
}
/************************************************************************
*
* LayoutFileIcons
* Position and size the full set of icons for the file mgr data.
*
************************************************************************/
void
LayoutFileIcons(
FileMgrRec *file_mgr_rec,
FileMgrData *file_mgr_data,
Boolean update_scrolling_position,
Boolean turn_off_hourglass )
{
#ifdef DT_PERFORMANCE
struct timeval update_time_s;
struct timeval update_time_f;
#endif
XmManagerWidget file_window;
FileViewData ** order_list;
int order_count;
int total_icon_count;
IconLayoutData *layout_data;
Dimension file_window_width, file_window_height;
Dimension scrolled_window_width, scrolled_window_height;
Dimension vert_scrollbar_width, horiz_scrollbar_height;
Dimension grid_width, grid_height;
Dimension icon_width, icon_height;
Dimension extra_height;
Dimension sw_shadow_thickness, sb_highlight_thickness, space;
int len, max_len;
int level, max_level;
FileViewData *file_view_data;
Boolean overflow = False;
int i, j, k;
Position x, y;
int row_count;
int column_count;
int tmp;
Arg args[10];
char *fileType;
unsigned char operations = 0L;
static XtCallbackRec dropCB[] = { {DropOnFileWindow, NULL}, {NULL, NULL} };
/* if directory-read still in progress, don't do anything now */
if (file_mgr_data->busy_status != not_busy)
return;
DPRINTF(("LayoutFileIcons(\"%s\", u_s_p %c, t_o_h %c) ...\n",
file_mgr_data->current_directory,
update_scrolling_position? 'T': 'F',
turn_off_hourglass? 'T': 'F'));
#ifdef DT_PERFORMANCE
printf(" Begin LayoutFileIcons\n");
gettimeofday(&update_time_s, NULL);
/* added by Rafi */
_DtPerfChkpntMsgSend("Begin Layout Icons");
#endif
/*
* Just in case a previous update work proc is still active,
* we commit pending updates made by the work proc before we
* start making changes.
*/
CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
file_window = (XmManagerWidget) file_mgr_rec->file_window;
layout_data = (IconLayoutData *)file_mgr_data->layout_data;
fileType = GetDirectoryLogicalType(file_mgr_data,
file_mgr_data->current_directory);
operations = TypeToDropOperations(fileType);
if (!file_mgr_data->dropSite)
{
dropCB[0].closure = (XtPointer)file_mgr_data;
DtDndVaDropRegister((Widget)file_mgr_rec->file_window,
DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
operations,
dropCB,
DtNdropAnimateCallback, dropCB,
DtNregisterChildren, True,
DtNtextIsBuffer, True,
XmNanimationStyle, XmDRAG_UNDER_SHADOW_IN,
NULL);
file_mgr_data->dropSite = True;
if (!operations)
{
XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
}
}
else
{
if (operations)
XtSetArg (args[0], XmNdropSiteOperations, operations);
else
XtSetArg (args[0], XmNdropSiteOperations, XmDROP_NOOP);
XmDropSiteUpdate((Widget)file_mgr_rec->file_window, args, 1);
}
/* Get the count of the total icon to be displayed. */
order_list = layout_data->order_list;
order_count = layout_data->order_count;
total_icon_count = 0;
for (i = 0; i < order_count; i++)
{
if (order_list[i]->displayed)
total_icon_count++;
}
/* Get the colors to be used for drawing the icons */
XtSetArg (args[0], XmNbackground, &layout_data->background);
XtSetArg (args[1], XmNforeground, &layout_data->foreground);
#ifdef _SHOW_LINK
XtSetArg (args[2], XmNtopShadowColor, &layout_data->topshadow);
XtGetValues (file_mgr_rec->file_window, args, 3);
#else
XtGetValues (file_mgr_rec->file_window, args, 2);
#endif
XtSetArg (args[0], XmNtopShadowColor, &layout_data->pixmap_back);
XtSetArg (args[1], XmNbottomShadowColor, &layout_data->pixmap_fore);
XtGetValues (file_mgr_rec->main, args, 2);
/*
* Create/update icon gadget for ".".
* This gadget may not actually be displayed (depends of filter settings;
* by default it is filtered out), but we need at least one gadget
* created here so we can figure out fonts and margins used by icon
* gadgets. This is necessary to compute the grid spacing.
*/
for (i = 0; i < order_count; i++)
if (strcmp(order_list[i]->file_data->file_name, ".") == 0)
{
UpdateOneFileIcon(file_mgr_rec, file_mgr_data, order_list[i]);
order_list[i]->need_update = True;
break;
}
/* Find the icon with the longest label */
max_len = 0;
file_view_data = NULL;
for (i = 0; i < order_count; i++)
{
if (!order_list[i]->filtered &&
(len = strlen(order_list[i]->label)) > max_len)
{
file_view_data = order_list[i];
max_len = len;
}
}
/* get the size of the icon with the longest label */
GetIconLayoutParms(file_mgr_rec, file_mgr_data, layout_data);
EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data, file_view_data,
&grid_width, &grid_height);
/* for tree view add space for tree lines and buttons */
max_level = 0;
if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
{
for (i = 0; i < order_count; i++)
{
if (order_list[i]->displayed)
{
GetLevel(order_list[i], &level);
if (level > max_level)
max_level = level;
}
}
grid_width += TreeWd(max_level, layout_data->treebtn_size);
}
file_mgr_data->grid_height = grid_height;
file_mgr_data->grid_width = grid_width;
/*
* If positioning is enabled in this view, then we need to use the other
* layout function, which is capable of handling overlapping icons and
* stacking order.
*/
if (PositioningEnabledInView(file_mgr_data))
{
if (file_mgr_data->object_positions)
{
LayoutDesktopIcons(file_mgr_rec, file_mgr_data,
order_list, order_count, turn_off_hourglass);
/* RepairFileWindow(file_mgr_data); *OBSOLETE* */
goto layout_done;
}
}
/*
* Position and size the icons according to the show and view types.
*/
scrolled_window_width = file_mgr_rec->scroll_window->core.width;
scrolled_window_height = file_mgr_rec->scroll_window->core.height;
vert_scrollbar_width = file_mgr_rec->vertical_scroll_bar->core.width;
horiz_scrollbar_height = file_mgr_rec->horizontal_scroll_bar->core.height;
if (file_mgr_data->show_type == MULTIPLE_DIRECTORY)
{
/* if not yet done, create tree button icons */
if (TreeBtnWd[0] == 0)
CreateTreeIcons(file_mgr_rec->file_window);
/* layout for tree mode */
x = MARGIN;
y = MARGIN;
file_window_width = MARGIN + grid_width - TreeOffset + XSPACING;
for (k = 0; k < order_count; k++)
{
if (!order_list[k]->displayed)
continue;
/* make sure window height won't exceed limit */
extra_height = GetExtraHeight(file_mgr_data, order_list[k],
layout_data->treebtn_size);
tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
if (tmp + MARGIN > MAXWINSIZE)
{
/* window would exceed height limit; start a new column */
x += grid_width + XSPACING;
y = MARGIN;
file_window_width += grid_width + XSPACING;
tmp = (int)y + grid_height + extra_height + YSPACING(file_mgr_data);
overflow = True;
}
order_list[k]->x = x;
order_list[k]->y = y + grid_height;
/* update y */
y = (Position)tmp;
}
if (overflow)
file_window_height = MAXWINSIZE;
else
file_window_height = y + MARGIN;
}
else if (file_mgr_data->view == BY_ATTRIBUTES)
{
/* layout for details view, no tree mode */
x = MARGIN;
y = MARGIN;
file_window_width = 2*MARGIN + grid_width;
for (k = 0; k < order_count; k++)
{
if (!order_list[k]->displayed)
continue;
/* make sure window height won't exceed limit */
tmp = (int)y + grid_height + YSPACING(file_mgr_data);
if (tmp + MARGIN > MAXWINSIZE)
{
/* window would exceed height limit; start a new column */
x += grid_width + XSPACING;
y = MARGIN;
file_window_width += grid_width + XSPACING;
tmp = (int)y + grid_height + YSPACING(file_mgr_data);
overflow = True;
}
order_list[k]->x = x;
order_list[k]->y = y + grid_height;
/* update y */
y = (Position)tmp;
}
if (overflow)
file_window_height = MAXWINSIZE;
else
file_window_height = y + MARGIN;
}
else /* show_type == SINGLE_DIRECTORY, view != BY_ATTRIBUTES */
{
/* layout for "normal" views (no tree mode, no details) */
/* calculate how many columns fit in the window width */
column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING) /
((int)grid_width + XSPACING);
if (column_count == 0)
column_count = 1; /* need at least one column */
/*
* Calculate the window height. Need to do calculation in int's
* rather than short (Dimension) because of possible overflow.
*/
row_count = (total_icon_count + column_count - 1) / column_count;
tmp = 2*MARGIN - YSPACING(file_mgr_data) +
row_count * ((int)grid_height + YSPACING(file_mgr_data));
/* check if the height is larger than the scrolled window */
if (tmp >= (int)scrolled_window_height - 2*MARGIN)
{
/* need to recompute everything because of space for vert scrollbar */
column_count = ((int)scrolled_window_width - 4 - 2*MARGIN + XSPACING
- (int)vert_scrollbar_width)
/ ((int)grid_width + XSPACING);
if (column_count == 0)
column_count = 1;
row_count = (total_icon_count + column_count - 1) / column_count;
tmp = 2*MARGIN - YSPACING(file_mgr_data) +
row_count * ((int)grid_height + YSPACING(file_mgr_data));
}
/* check if the window height is within the limit */
if (tmp <= MAXWINSIZE)
file_window_height = (Dimension)tmp;
else
{
/* window height too large; use more columns */
overflow = True;
row_count = (int)(MAXWINSIZE - 2*MARGIN + YSPACING(file_mgr_data)) /
(int)((int)grid_height + YSPACING(file_mgr_data));
column_count = (total_icon_count + row_count - 1) / row_count;
row_count = (total_icon_count + column_count - 1) / column_count;
file_window_height = (Dimension) (2*MARGIN - YSPACING(file_mgr_data) +
row_count * ((int)grid_height + YSPACING(file_mgr_data)));
}
DPRINTF((" %d columns, %d rows (scroll_window width %d)\n",
column_count, row_count,
scrolled_window_width));
/* assign positions to all icons */
y = MARGIN;
file_window_width = (Dimension)
(2*MARGIN - XSPACING + column_count*((int)grid_width + XSPACING));
k = 0;
for (i = 0; i < row_count; i++)
{
x = MARGIN;
for (j = 0; j < column_count && k < order_count;)
{
/* find the next icon to display */
while (k < order_count && !order_list[k]->displayed)
k++;
if (k == order_count)
break;
if (layout_data->alignment == XmALIGNMENT_CENTER &&
file_mgr_data->view == BY_NAME_AND_ICON)
{
EstimateIconSize(file_mgr_rec, file_mgr_data, layout_data,
order_list[k], &icon_width, &icon_height);
order_list[k]->x = x +
(Dimension)(grid_width - icon_width)/(Dimension)2;
}
else
order_list[k]->x = x;
order_list[k]->y = y + grid_height;
x += grid_width + XSPACING;
j++;
k++;
}
y += grid_height + YSPACING(file_mgr_data);
}
}
DPRINTF((" file_window size: width %d, height %d\n",
file_window_width, file_window_height));
/* Manage/unmanage the scrollbars as needed. */
XtSetArg (args[0], XmNwidth, file_window_width);
XtSetArg (args[1], XmNheight, file_window_height);
XtSetValues ((Widget)file_window, args, 2);
XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
XtSetValues (file_mgr_rec->scroll_window, args, 1);
/* Unmanage the horizontal scrollbar if it is not needed */
if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
file_mgr_rec->scroll_window))
{
if (file_window_width >= (Dimension)(scrolled_window_width - 4 -
vert_scrollbar_width))
XtManageChild (file_mgr_rec->horizontal_scroll_bar);
else
{
XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
XtSetArg (args[0], XmNx, 0);
XtSetValues ((Widget)file_window, args, 1);
}
}
else if (file_window_width >= (Dimension)(scrolled_window_width - 4))
XtManageChild (file_mgr_rec->horizontal_scroll_bar);
else
{
XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
XtSetArg (args[0], XmNx, 0);
XtSetValues ((Widget)file_window, args, 1);
}
XSync (XtDisplay (file_window), False);
/* Set the file window width and height to be at least */
/* the size of the scrolled window. */
if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
file_mgr_rec->scroll_window))
{
if(file_window_width <= (Dimension)(scrolled_window_width -
(vert_scrollbar_width + 4)))
file_window_width = scrolled_window_width -
(vert_scrollbar_width + 4);
}
else
{
if(file_window_width < (Dimension)(scrolled_window_width - 4))
file_window_width = scrolled_window_width - 4;
}
if (HorizontalScrollbarIsVisible(file_mgr_rec->horizontal_scroll_bar,
file_mgr_rec->scroll_window))
{
int pad;
XtSetArg (args[0], XmNhighlightThickness, &sb_highlight_thickness);
XtGetValues ((Widget)file_mgr_rec->horizontal_scroll_bar, args, 1);
XtSetArg (args[0], XmNshadowThickness, &sw_shadow_thickness);
XtSetArg (args[1], XmNspacing, &space);
XtGetValues ((Widget)file_mgr_rec->scroll_window, args, 2);
pad = (int)(((sb_highlight_thickness + sw_shadow_thickness) * 2) + space);
if(file_window_height < (Dimension)(scrolled_window_height -
(horiz_scrollbar_height + pad)))
file_window_height = scrolled_window_height -
(horiz_scrollbar_height + pad);
}
else
{
if (file_window_height < (Dimension)(scrolled_window_height - 4))
file_window_height = scrolled_window_height - 4;
}
XtSetArg (args[0], XmNwidth, file_window_width);
XtSetArg (args[1], XmNheight, file_window_height);
XtSetValues ((Widget)file_window, args, 2);
if( file_mgr_data->scrollToThisFile == NULL )
{
if (update_scrolling_position)
{
XtSetArg (args[0], XmNx, 0);
XtSetArg (args[1], XmNy, 0);
XtSetValues ((Widget)file_window, args, 2);
}
/* Set the vertical scrollbar's increment to icon height */
XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
}
if (PositioningEnabledInView(file_mgr_data))
{
BuildObjectPositions(file_mgr_data);
/* RepairFileWindow(file_mgr_data); *OBSOLETE* */
}
/*
* Don't keep up the hourglass; this helps the user to get the impression
* that all of the work is done.
*/
if (turn_off_hourglass && !overflow)
_DtTurnOffHourGlass(file_mgr_rec->shell);
layout_done:
/*
* Start up a work proc that will update the display.
*/
layout_data->visible_done = False;
layout_data->all_done = False;
if (layout_data->work_id == 0)
{
XtAppContext app_context =
XtWidgetToApplicationContext(file_mgr_rec->shell);
DPRINTF(("LayoutFileIcons: starting workproc\n"));
layout_data->drop_site_w = (Widget)file_mgr_rec->shell;
XmDropSiteStartUpdate(layout_data->drop_site_w);
layout_data->work_id =
XtAppAddWorkProc(app_context, DisplayWorkProc, file_mgr_rec);
}
if( file_mgr_data->scrollToThisFile )
{
int i;
DirectorySet * directory_set = NULL;
file_view_data = NULL;
for( i = 0; i < file_mgr_data->directory_count; ++i)
{
if( strcmp( ((DirectorySet *)file_mgr_data->directory_set[i])->name, file_mgr_data->scrollToThisDirectory ) == 0 )
{
directory_set = (DirectorySet *)file_mgr_data->directory_set[i];
break;
}
}
if( directory_set )
{
for( i = 0; i < directory_set->file_count; ++i )
{
if( strcmp( directory_set->order_list[i]->file_data->file_name,
file_mgr_data->scrollToThisFile ) == 0 )
{
file_view_data = directory_set->order_list[i];
break;
}
}
}
if( file_view_data
&& file_view_data->filtered == False )
{
FileMgrRec * file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
DeselectAllFiles( file_mgr_data );
SelectFile( file_mgr_data, file_view_data );
ActivateSingleSelect( file_mgr_rec,
file_mgr_data->selection_list[0]->file_data->logical_type );
PositionFileView(file_view_data, file_mgr_data);
}
else
{
if (update_scrolling_position)
{
XtSetArg (args[0], XmNx, 0);
XtSetArg (args[1], XmNy, 0);
XtSetValues ((Widget)file_window, args, 2);
}
/* Set the vertical scrollbar's increment to icon height */
XtSetArg (args[0], XmNincrement, grid_height + YSPACING(file_mgr_data));
XtSetArg (args[1], XmNuserData, grid_height + YSPACING(file_mgr_data));
XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 2);
}
XtFree( file_mgr_data->scrollToThisFile );
file_mgr_data->scrollToThisFile = NULL;
XtFree( file_mgr_data->scrollToThisDirectory );
file_mgr_data->scrollToThisDirectory = NULL;
}
#ifdef DT_PERFORMANCE
gettimeofday(&update_time_f, NULL);
if (update_time_s.tv_usec > update_time_f.tv_usec) {
update_time_f.tv_usec += 1000000;
update_time_f.tv_sec--;
}
printf(" done LayoutFileIcons, time: %ld.%ld\n\n",
update_time_f.tv_sec - update_time_s.tv_sec,
update_time_f.tv_usec - update_time_s.tv_usec);
/* the following message send call added by Rafi */
_DtPerfChkpntMsgSend("Done LayoutFileIcons");
#endif
DPRINTF(("... done\n"));
}
/************************************************************************
*
* TreeBtnCallback
* Callback function invoked upon clicking the tree-branch-expand button.
*
************************************************************************/
static void
TreeBtnCallback(
Widget w,
XtPointer clientData,
XmAnyCallbackStruct *callData )
{
FileMgrRec *file_mgr_rec;
FileMgrData *file_mgr_data;
FileViewData *file_view_data = (FileViewData *)clientData;
Arg args[20];
Bool expand;
/* check which mouse button was pressed */
if ((callData->event->type == ButtonPress ||
callData->event->type == ButtonRelease) &&
((XButtonEvent *)callData->event)->button != Button1)
{
return;
}
expand = True;
/* get file mgr data and record */
XtSetArg (args[0], XmNuserData, &file_mgr_data);
XtGetValues (w, args, 1);
file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
XmDropSiteStartUpdate(file_mgr_rec->file_window);
CommitWorkProcUpdates(file_mgr_rec, file_mgr_data, True);
DirTreeExpand(file_mgr_data, file_view_data, expand);
DrawCurrentDirectory (file_mgr_rec->current_directory,
file_mgr_rec, file_mgr_data);
LayoutFileIcons(file_mgr_rec, file_mgr_data, False, True);
XmDropSiteEndUpdate(file_mgr_rec->file_window);
RedrawTreeLines(file_mgr_rec->file_window,
-file_mgr_rec->file_window->core.x,
-file_mgr_rec->file_window->core.y,
XtParent(file_mgr_rec->file_window)->core.width,
XtParent(file_mgr_rec->file_window)->core.height,
0, file_mgr_rec, file_mgr_data);
}
/*
* When a drop occurs on a File Manger window, which now
* support random placement, what is dropped may not ultimately be what
* is displayed. Since the dissolve transition effect has been disabled
* for drops on the desktop, we can sometimes end up with garbage left on
* the desktop. This function will attempt to clear up the leftover garbage,
* by resetting all areas of the desktop which are not covered by an icon
* to the background color for the file window.
*
* This function is OBSOLETE (?).
*/
void
RepairFileWindow (
FileMgrData * file_mgr_data)
{
FileMgrRec * file_mgr_rec;
Region clipList;
Region hotspot;
Region redrawRegion;
int i;
XRectangle rect;
int num_children;
Widget * children;
XmManagerWidget file_window;
GC gc;
unsigned long mask;
XGCValues values;
file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
file_window = (XmManagerWidget)file_mgr_rec->file_window;
/* Initialize the clip region to that of the file window */
rect.x = 0;
rect.y = 0;
rect.height = file_window->core.height;
rect.width = file_window->core.width;
clipList = XCreateRegion();
XUnionRectWithRegion(&rect, clipList, clipList);
/* Subtract out the hotspots associated with each icon */
num_children = file_window->composite.num_children;
children = file_window->composite.children;
hotspot = XCreateRegion();
for (i = 0; i < num_children; i++)
{
if (XtIsManaged(children[i]) &&
XtIsSubclass(children[i], dtIconGadgetClass))
{
WidgetRectToRegion(file_mgr_data, children[i], hotspot);
XSubtractRegion(clipList, hotspot, clipList);
}
}
/* Create a GC for doing our drawing */
mask = GCForeground;
values.foreground = file_window->core.background_pixel;
gc = XCreateGC(XtDisplay(file_window), XtWindow(file_window), mask, &values);
XSetRegion(XtDisplay(file_window), gc, clipList);
/* Restore the window */
XFillRectangle(XtDisplay(file_window), XtWindow(file_window), gc, 0, 0,
file_window->core.width, file_window->core.height);
/*
* Force all icons to redraw, since we are only able to repair the
* areas where icons are not; the drop image may have extended onto
* some of the icons.
*/
rect.x = 0;
rect.y = 0;
rect.height = file_window->core.height;
rect.width = file_window->core.width;
redrawRegion = XCreateRegion();
XUnionRectWithRegion(&rect, redrawRegion, redrawRegion);
(*file_window->core.widget_class->core_class.expose)
((Widget)file_window, NULL, redrawRegion);
/* Clean up */
XFreeGC(XtDisplay(file_window), gc);
XDestroyRegion(clipList);
XDestroyRegion(hotspot);
XDestroyRegion(redrawRegion);
}
/*
* Compress the stacking order values, anytime an item is removed.
*/
static void
CompressObjectList (
ObjectPosition ** object_positions,
int num_objects,
int starting_index)
{
int i;
for (i = 0; i < num_objects; i++)
{
if (object_positions[i]->stacking_order > starting_index)
object_positions[i]->stacking_order--;
}
}
/************************************************************************
*
* LayoutDesktopIcons
* Position and size the full set of icons for the file mgr data.
*
************************************************************************/
static void
LayoutDesktopIcons (
FileMgrRec * file_mgr_rec,
FileMgrData * file_mgr_data,
FileViewData ** order_list,
int order_count,
Boolean turn_off_hourglass )
{
XmManagerWidget file_window;
int directory_count, largest_x, largest_y;
int value = 0, size, increment, page;
Dimension current_wd;
Dimension current_ht;
Dimension file_window_width;
Dimension grid_height;
Dimension grid_width;
FileViewData * object;
ObjectPosition * position_data;
ObjectPosition * bottom;
ObjectPtr top;
int i, j, k;
Boolean set_size = False;
char * edit_name;
Arg args[2];
int sorder;
/* Get the grid block size */
file_window = (XmManagerWidget) file_mgr_rec->file_window;
grid_height = file_mgr_data->grid_height;
grid_width = file_mgr_data->grid_width;
file_window_width = file_mgr_rec->scroll_window->core.width - 4;
current_ht = file_mgr_rec->file_window->core.height;
current_wd = file_mgr_rec->file_window->core.width;
/* Before positioning, mark all position entries as 'not used' */
for (i = 0; i < file_mgr_data->num_objects; i++)
{
file_mgr_data->object_positions[i]->in_use = False;
file_mgr_data->object_positions[i]->file_view_data = NULL;
}
/*
* Before attempting to place new icons, we need to make sure that
* all of the existing object_positions entries have had their
* file_view_data field filled in. This is so that during placement,
* we can get the height and width of the associated icons, to help
* prevent overlap.
*/
for (i = 0; i < order_count; i++)
{
object = order_list[i];
if (object->displayed)
{
if (position_data = GetPositionalData(file_mgr_data, object, 0, False))
{
/* Save; used later during redraw */
position_data->file_view_data = object;
object->position_info = (ObjectPtr)position_data;
}
}
else if (position_data = GetPositionalData(file_mgr_data, object, 0,
False))
{
/*
* If an object has position information, but is currently
* filtered, don't discard its position info; mark it as in-use.
*/
position_data->file_view_data = object;
object->position_info = (ObjectPtr)position_data;
}
}
/* Remove any unused position data entries */
for (i = 0; i < file_mgr_data->num_objects; )
{
if (!file_mgr_data->object_positions[i]->in_use)
{
/* If this object had a text field, delete it */
for (k = 0; k < file_window->composite.num_children; k++)
{
if (XmIsTextField(file_window->composite.children[k]) &&
!file_window->composite.children[k]->core.being_destroyed)
{
XtSetArg(args[0], XmNuserData, &edit_name);
XtGetValues(file_window->composite.children[k], args, 1);
if (strcmp(edit_name,file_mgr_data->object_positions[i]->name)
== 0)
{
/* Match */
XtUnmanageChild(file_window->composite.children[k]);
XtDestroyWidget(file_window->composite.children[k]);
break;
}
}
}
/* Free up the entry; bump up the other array entries */
/* Update the linked list */
if (file_mgr_data->object_positions[i]->prev)
{
file_mgr_data->object_positions[i]->prev->next = (ObjectPtr)
file_mgr_data->object_positions[i]->next;
}
if (file_mgr_data->object_positions[i]->next)
{
file_mgr_data->object_positions[i]->next->prev = (ObjectPtr)
file_mgr_data->object_positions[i]->prev;
}
sorder = file_mgr_data->object_positions[i]->stacking_order;
XtFree(file_mgr_data->object_positions[i]->name);
file_mgr_data->object_positions[i]->name = NULL;
XtFree((char *)file_mgr_data->object_positions[i]);
file_mgr_data->object_positions[i] = NULL;
for (j = i; j < file_mgr_data->num_objects - 1; j++)
{
file_mgr_data->object_positions[j] =
file_mgr_data->object_positions[j+1];
}
file_mgr_data->num_objects--;
file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
(char *)file_mgr_data->object_positions,
sizeof(ObjectPosition *) * file_mgr_data->num_objects);
CompressObjectList(file_mgr_data->object_positions,
file_mgr_data->num_objects, sorder);
}
else
i++;
}
/* Now, it is safe to position any unplaced objects */
for (i = 0; i < order_count; i++)
{
object = order_list[i];
if (object->displayed)
{
position_data = GetPositionalData(file_mgr_data, object,
file_window_width, True);
/* Save; used later during redraw */
position_data->file_view_data = object;
object->position_info = (ObjectPtr)position_data;
/* record position of bottom left corner for DisplaySomeIcons */
object->x = position_data->x;
object->y = position_data->y +
(object->need_update? grid_height: object->widget->core.height);
}
}
/* Get largest x value */
largest_x = 0;
largest_y = 0;
bottom = GetBottomOfStack(file_mgr_data);
while (bottom)
{
if (bottom->file_view_data != NULL && bottom->file_view_data->displayed)
{
if (bottom->file_view_data->position_info->x > largest_x)
largest_x = bottom->file_view_data->position_info->x;
if (bottom->file_view_data->position_info->y > largest_y)
largest_y = bottom->file_view_data->position_info->y;
}
bottom = (ObjectPosition *)bottom->prev;
}
largest_x += grid_width;
largest_y += grid_height;
/* if necessary, shrink the width & height to what we need */
if (current_wd == 32767)
{
current_wd = largest_x;
set_size = True;
}
if (current_ht == 32767)
{
current_ht = largest_y;
set_size = True;
}
/* Get the horizontal and vertical scrollbars. */
XtSetArg (args[0], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
XtSetValues (file_mgr_rec->scroll_window, args, 1);
/*
* Typically, dtfile does everything possible to prevent a horizontal
* scrollbar from being displayed. However, when random placement is
* enabled, we don't mind having a horizontal scrollbar, when needed.
* We need to manually manage this, since the normal dtfile layout
* code may have forcably unmanaged the scrollbar earlier.
*/
if (XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
{
/* get scroll bar values */
(void)XmScrollBarGetValues(file_mgr_rec->horizontal_scroll_bar,
&value, &size, &increment, &page);
}
if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
file_mgr_rec->scroll_window))
{
if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width -
(file_mgr_rec->vertical_scroll_bar->core.width + 4)))
{
XtManageChild(file_mgr_rec->horizontal_scroll_bar);
}
else
{
/* set scroll bar values changing its position */
if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
XtManageChild(file_mgr_rec->horizontal_scroll_bar);
else
{
XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
XtSetArg (args[0], XmNx, 0);
XtSetValues ((Widget)file_window, args, 1);
}
}
}
else if ((Dimension)largest_x >= (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
XtManageChild(file_mgr_rec->horizontal_scroll_bar);
else
{
/* set scroll bar values changing its position */
if(value != 0 && XtIsManaged(file_mgr_rec->horizontal_scroll_bar))
XtManageChild(file_mgr_rec->horizontal_scroll_bar);
else
{
XtUnmanageChild (file_mgr_rec->horizontal_scroll_bar);
XtSetArg (args[0], XmNx, 0);
XtSetValues ((Widget)file_window, args, 1);
}
}
/* Set the file window width and height to be at least */
/* the size of the scrolled window. */
if ((Dimension)(current_wd) < (Dimension)(file_mgr_rec->scroll_window->core.width - 4))
{
if (VerticalScrollbarIsVisible(file_mgr_rec->vertical_scroll_bar,
file_mgr_rec->scroll_window))
current_wd = file_mgr_rec->scroll_window->core.width -
(file_mgr_rec->vertical_scroll_bar->core.width + 4);
else
current_wd = file_mgr_rec->scroll_window->core.width - 4;
set_size = True;
}
if ((Dimension)(current_ht) < (Dimension)(file_mgr_rec->scroll_window->core.height - 4))
{
current_ht = file_mgr_rec->scroll_window->core.height - 4;
set_size = True;
}
if (set_size)
{
XtSetArg (args[0], XmNwidth, current_wd);
XtSetArg (args[1], XmNheight, current_ht);
XtSetValues (file_mgr_rec->file_window, args, 2);
}
/* Set the vertical scrollbar's increment to icon height */
XtSetArg (args[0], XmNincrement, file_mgr_data->grid_height + 2);
XtSetValues (file_mgr_rec->vertical_scroll_bar, args, 1);
/*
* Don't keep up the hourglass; this helps the user to get the impression
* that all of the work is done.
*/
if (turn_off_hourglass)
_DtTurnOffHourGlass(file_mgr_rec->shell);
}
/***************************************************
*
* Given a desktop object, see if it has already been assigned a position;
* if not, then try to fit it into the next available grid position.
*
**************************************************/
static Boolean
IntersectRects(
Position x1,
Position y1,
Dimension w1,
Dimension h1,
Position x2,
Position y2,
Dimension w2,
Dimension h2 )
{
int srcABot, srcBBot;
int srcARight, srcBRight;
int dw, dh;
int dx, dy;
srcABot = y1 + h1 - 1;
srcBBot = y2 + h2 - 1;
srcARight = x1 + w1 - 1;
srcBRight = x2 + w2 - 1;
if (x1 >= x2)
dx = x1;
else
dx = x2;
if (y1 > y2)
dy = y1;
else
dy = y2;
if (srcARight >= srcBRight)
dw = srcBRight - dx + 1;
else
dw = srcARight - dx + 1;
if (srcABot > srcBBot)
dh = srcBBot - dy + 1;
else
dh = srcABot - dy + 1;
if (dw <= 0 || dh <= 0)
return(FALSE);
return(TRUE);
}
static ObjectPosition *
GetPositionalData (
FileMgrData * file_mgr_data,
FileViewData * object,
Dimension max_width,
Boolean create)
{
int i;
int k;
ObjectPosition *entry, *top;
Position x;
Position y;
Dimension grid_height;
Dimension grid_width;
Boolean hit;
ObjectPosition * oP;
Dimension objWidth, objHeight;
Dimension oWidth, oHeight;
/* If object already has positional data, then use it */
for (i = 0; i < file_mgr_data->num_objects; i++)
{
if (strcmp(object->file_data->file_name,
file_mgr_data->object_positions[i]->name) == 0)
{
/* Found a match */
file_mgr_data->object_positions[i]->in_use = True;
return(file_mgr_data->object_positions[i]);
}
}
if (!create)
return(NULL);
/* Create a new entry, and place into the grid on the top of the stack */
entry = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
entry->name = XtNewString(object->file_data->file_name);
entry->in_use = True;
entry->late_bind = False;
entry->stacking_order = 2;
entry->prev = NULL;
entry->next = NULL;
entry->file_view_data = NULL;
if(file_mgr_data->num_objects == 1)
{
top = file_mgr_data->object_positions[0];
top->next = (ObjectPtr)entry;
entry->prev = (ObjectPtr)top;
}
else
{
top = NULL;
/* Push all other objects down in the stack */
for (i = 0; i < file_mgr_data->num_objects; i++)
{
/* Find the previous top of the stack */
if (file_mgr_data->object_positions[i]->stacking_order == 1)
{
top = file_mgr_data->object_positions[i];
continue;
}
else if (file_mgr_data->object_positions[i]->stacking_order == 2)
{
if(top == NULL)
top = GetTopOfStack(file_mgr_data);
top->next = (ObjectPtr)entry;
entry->next = (ObjectPtr)file_mgr_data->object_positions[i];
entry->prev = (ObjectPtr)top;
file_mgr_data->object_positions[i]->prev = (ObjectPtr)entry;
}
file_mgr_data->object_positions[i]->stacking_order++;
}
}
grid_height = file_mgr_data->grid_height;
grid_width = file_mgr_data->grid_width;
x = MARGIN;
y = MARGIN;
if (object->widget && !object->need_update)
{
objWidth = object->widget->core.width;
objHeight = object->widget->core.height;
}
else
{
objWidth = grid_width;
objHeight = grid_height;
}
/* Find the first open spot, which will not cause any overlap */
do
{
hit = False;
for (i = 0; i < file_mgr_data->num_objects; i++)
{
oP = file_mgr_data->object_positions[i];
if (oP->file_view_data->widget && !oP->file_view_data->need_update)
{
oWidth = oP->file_view_data->widget->core.width;
oHeight = oP->file_view_data->widget->core.height;
}
else
{
oWidth = grid_width;
oHeight = grid_height;
}
if (oP->file_view_data->displayed &&
IntersectRects(x, y, objWidth, objHeight,
oP->x, oP->y, oWidth, oHeight))
{
/* Try next grid spot */
x += grid_width + XSPACING;
if ((Dimension)(x + objWidth) >= max_width)
{
/* Go to next row */
y += grid_height + YSPACING(file_mgr_data);
x = MARGIN;
}
hit = True;
break;
}
}
} while (hit);
/* Add to the end of the list */
entry->x = x;
entry->y = y;
file_mgr_data->num_objects++;
file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
(char *)file_mgr_data->object_positions,
sizeof(ObjectPosition *) * file_mgr_data->num_objects);
/* Force the ordered list to be maintained */
for (i = 0; i < file_mgr_data->num_objects - 1; i++)
{
if ((entry->y < file_mgr_data->object_positions[i]->y) ||
((entry->y == file_mgr_data->object_positions[i]->y) &&
(entry->x < file_mgr_data->object_positions[i]->x)))
{
/* Fits here; slide later entries down */
for (k = file_mgr_data->num_objects - 1; k > i; k--)
{
file_mgr_data->object_positions[k] =
file_mgr_data->object_positions[k-1];
}
break;
}
}
file_mgr_data->object_positions[i] = entry;
return(file_mgr_data->object_positions[i]);
}
/*******************************************************************
*
* BuildObjectPositons - builds up the object positions for directories
* which have now object position information.
*
*********************************************************************/
static void
BuildObjectPositions(
FileMgrData *file_mgr_data)
{
int i, j, k, l;
FileViewData * file_view_data;
ObjectPosition * ptr;
file_mgr_data->object_positions = (ObjectPosition **)XtMalloc(
sizeof(ObjectPosition *) *
file_mgr_data->directory_set[0]->file_count);
for (i = 0, j = 0; i < file_mgr_data->directory_set[0]->file_count; i++)
{
file_view_data = file_mgr_data->directory_set[0]->order_list[i];
if (file_view_data->filtered)
continue;
ptr = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
ptr->name = XtNewString(file_view_data->file_data->file_name);
ptr->x = file_view_data->x;
ptr->y = file_view_data->y -
(file_view_data->need_update? file_mgr_data->grid_height:
file_view_data->widget->core.height);
ptr->in_use = True;
ptr->late_bind = False;
ptr->stacking_order = j+1;
ptr->file_view_data = file_view_data;
file_view_data->position_info = (ObjectPtr)ptr;
ptr->next = NULL;
ptr->prev = NULL;
/* Sort according to left-to-right, top-to-bottom */
for (k = 0; k < j; k++)
{
if ((ptr->y < file_mgr_data->object_positions[k]->y) ||
((ptr->y == file_mgr_data->object_positions[k]->y) &&
(ptr->x < file_mgr_data->object_positions[k]->x)))
{
/* Shift others down, to open up a spot */
for (l = j; l > k; l--)
{
file_mgr_data->object_positions[l] =
file_mgr_data->object_positions[l - 1];
}
break;
}
}
file_mgr_data->object_positions[k] = ptr;
j++;
}
file_mgr_data->num_objects = j;
/* Repair all of the next and prev pointers */
RepairStackingPointers(file_mgr_data);
OrderChildrenList(file_mgr_data);
}
/***********************************
*
* When items are dragged around on a random placement window, they will be
* repositioned at the point where they were dropped. Multiple drop items
* will be positioned 'around' where the drop occurred.
*
**********************************/
void
RepositionIcons (
FileMgrData * file_mgr_data,
char ** file_list,
int file_count,
Position drop_x,
Position drop_y,
Boolean late_binding_needed)
{
Position x;
Position y;
int i, i2, j, k, l;
int adj;
Position orig_x;
Position orig_y;
ObjectPosition * save_object;
char * name;
FileMgrRec * file_mgr_rec;
XmManagerWidget file_window;
Widget textWidget;
char * edit_name;
Arg args[10];
Boolean newEntry;
int newEntryCount = 0;
char dot_dir[3] = ".";
char dotdot_dir[3] = "..";
/* if random placement is not enabled, positioning doesn't matter */
if(file_mgr_data->positionEnabled == RANDOM_OFF)
return;
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
/*
* For directory views, no positional data may be present if positioning
* was disabled for this view. So ... we must create some now.
*/
if ((file_mgr_data->num_objects == 0) &&
(file_mgr_data->directory_set[0]->file_count > 0))
{
BuildObjectPositions(file_mgr_data);
}
/*
* Update to the new position.
* The position needs to be adjusted so that the icon actually ends
* up where the user dropped it. This is because the drag icon includes
* margins and shadow area, but not the highlight area of the icon gadget
* that was dragged. Coordinates drop_x, drop_y are the upper left corner
* of the drag icon when it was dropped. To convert to icon gadget
* coordinates we need to subtract the highlight thickness.
*/
if (file_mgr_data->layout_data != NULL)
adj = ((IconLayoutData *)file_mgr_data->layout_data)->highlight;
else
adj = 0;
x = drop_x - adj;
y = drop_y - adj;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
/* Process each of the dropped files */
/* Go from bottom to top, to retain stacking order */
for (i = file_count - 1; i >= 0; i--)
{
textWidget = NULL;
/*
* The names typically come in as complete paths; we only want
* the filename portion.
* fdt: this check will break for root (/)
*/
if( strcmp(file_mgr_data->current_directory, file_list[i]) == 0)
name = dot_dir;
else if(strncmp(file_mgr_data->current_directory, file_list[i], strlen(file_list[i]) ) == 0 )
name = dotdot_dir;
else
{
if ((name = strrchr(file_list[i], '/')) == NULL)
name = file_list[i];
else
{
name++;
/* Try to gracefully handle root (/) */
if (*name == '\0')
name--;
}
}
newEntry = True;
/* Find the positional data for this object, if any */
for (j = 0; j < file_mgr_data->num_objects; j++)
{
if (strcmp(name, file_mgr_data->object_positions[j]->name) == 0)
{
/* Find the associated widget */
for (k = 0; strcmp(name,
file_mgr_data->directory_set[0]->file_view_data[k]->file_data-> file_name); k++);
newEntry = False;
/* If this object has a text field, then move it also */
for (l = 0; l < file_window->composite.num_children; l++)
{
if (XmIsTextField(file_window->composite.children[l]) &&
!file_window->composite.children[l]->core.being_destroyed)
{
XtSetArg(args[0], XmNuserData, &edit_name);
XtGetValues(file_window->composite.children[l], args, 1);
if (strcmp(edit_name, name) == 0)
{
textWidget = file_window->composite.children[l];
break;
}
}
}
break;
}
}
if (newEntry)
{
ObjectPosition * data;
/* Create positional data at the top of the ordered array */
newEntryCount++;
j = 0;
data = (ObjectPosition *) XtMalloc(sizeof(ObjectPosition));
data->name = XtNewString(name);
data->x = 0;
data->y = 0;
data->in_use = True;
data->late_bind = True;
data->stacking_order = 1;
data->file_view_data = NULL;
data->prev = NULL;
data->next = NULL;
/* Push all other objects down in the stack */
for (i2 = 0; i2 < file_mgr_data->num_objects; i2++)
{
/* Find the previous top of the stack */
if (file_mgr_data->object_positions[i2]->stacking_order == 1)
{
data->next = (ObjectPtr)file_mgr_data->object_positions[i2];
file_mgr_data->object_positions[i2]->prev = (ObjectPtr)data;
}
file_mgr_data->object_positions[i2]->stacking_order++;
}
file_mgr_data->num_objects++;
file_mgr_data->object_positions = (ObjectPosition **) XtRealloc(
(char *)file_mgr_data->object_positions,
sizeof(ObjectPosition *) * file_mgr_data->num_objects);
/* Add entry to the top of the ordered array */
for (j = file_mgr_data->num_objects - 1; j > 0; j--)
{
file_mgr_data->object_positions[j] =
file_mgr_data->object_positions[j - 1];
}
file_mgr_data->object_positions[0] = data;
}
else
{
/* Move item upto top of the stack */
RepositionUpInStack(file_mgr_data,
file_mgr_data->object_positions[j]->stacking_order, 1);
}
orig_x = file_mgr_data->object_positions[j]->x;
orig_y = file_mgr_data->object_positions[j]->y;
file_mgr_data->object_positions[j]->x = x;
file_mgr_data->object_positions[j]->y = y;
save_object = file_mgr_data->object_positions[j];
/* Move the object */
if (!newEntry)
{
/* We need to force a geometry request */
XtSetArg(args[0], XmNx, x);
XtSetArg(args[1], XmNy, y);
XtSetValues(file_mgr_data->directory_set[0]->file_view_data[k]->widget,
args, 2);
/* Move associated text widget, if there is one */
if (textWidget)
{
Position t_x, t_y;
t_x = textWidget->core.x + x - orig_x;
t_y = textWidget->core.y + y - orig_y;
/* We need to force a geometry request */
XtSetArg(args[0], XmNx, t_x);
XtSetArg(args[1], XmNy, t_y);
XtSetValues(textWidget, args, 2);
}
}
/*
* Reorder the positional array, so that it remains ordered.
* Bubble down toward the end of the list if the object has moved
* farther from the origin; bubble up if it has moved closer to
* the origin.
*/
if ((y > orig_y) || ((y == orig_y) && (x > orig_x)))
{
/* Bubble down */
for (k = j + 1; k < file_mgr_data->num_objects; k++)
{
if ((y < file_mgr_data->object_positions[k]->y) ||
((y == file_mgr_data->object_positions[k]->y) &&
(x < file_mgr_data->object_positions[k]->x)))
{
/* We fit right here */
file_mgr_data->object_positions[k - 1] = save_object;
break;
}
else
{
/* Bubble */
file_mgr_data->object_positions[k - 1] =
file_mgr_data->object_positions[k];
}
}
/* See if it goes at the end */
if (k == file_mgr_data->num_objects)
file_mgr_data->object_positions[k - 1] = save_object;
}
else
{
/* Bubble up */
for (k = j - 1; k >= 0; k--)
{
if ((y > file_mgr_data->object_positions[k]->y) ||
((y == file_mgr_data->object_positions[k]->y) &&
(x > file_mgr_data->object_positions[k]->x)))
{
/* We fit right here */
file_mgr_data->object_positions[k + 1] = save_object;
break;
}
else
{
/* Bubble */
file_mgr_data->object_positions[k + 1] =
file_mgr_data->object_positions[k];
}
}
/* See if it goes at the end */
if (k < 0)
file_mgr_data->object_positions[0] = save_object;
}
/* Create position for the next file to be processed */
x += 20;
y += 20;
}
/*
* Reregister the desktop hotspots.
* Even if the caller told us that late binding was needed, if no new
* objects were specified, then we need to register hotspots now, because
* the layout function will never be called because the directory never
* really changed. This situation can occur when an icon is dropped on
* the desktop from a regular dtfile view, but that icon is already on
* the desktop (it thus is just a reposition).
*/
if (!late_binding_needed ||
(late_binding_needed && (newEntryCount == 0)))
{
RegisterDesktopHotspots(file_mgr_data, file_mgr_rec);
}
}
void
RegisterDesktopHotspots (
FileMgrData * file_mgr_data,
FileMgrRec * file_mgr_rec)
{
XmManagerWidget file_window;
FileViewData * file_view_data;
int ex, ey, ewd, eht;
ObjectPtr top;
Widget icon;
file_window = (XmManagerWidget) file_mgr_rec->file_window;
ex = -file_window->core.x;
ey = -file_window->core.y;
ewd = XtParent(file_window)->core.width;
eht = XtParent(file_window)->core.height;
/* Set up the icon location information with the drag handler */
/* Register in top to bottom stacking order */
top = GetTopOfStack(file_mgr_data);
while (top)
{
file_view_data = top->file_view_data;
if (file_view_data != NULL &&
file_view_data->displayed &&
!file_view_data->need_update)
{
icon = file_view_data->widget;
if ((Position)(icon->core.x + icon->core.width) >= (Position)ex &&
icon->core.x < ex + ewd &&
(Position)(icon->core.y + icon->core.height) >= (Position)ey &&
icon->core.y < ey + eht)
{
SetHotRects(file_view_data,
(XtCallbackProc) DropOnObject,
(XtPointer) file_view_data);
}
}
top = top->next;
}
}
/*
* Dtfile used to try to determine if the vertical scrollbar was visible
* by checking to see if it was managed; the assumption here was that the
* scrolled window widget unmanaged the scrollbar, when it was not needed.
* Unfortunately, it turns out that instead of unmanaging the scrollbar,
* the scrolled window simply moves the scrollbar out of sight; it is moved
* such that the X for the scrollbar is the same as the width of the
* scrolled window. So ... in order for us to really determine if the
* scrollbar is visible, we need to see whether or not its X falls within
* the visible area of the scrolled window.
*/
Boolean
VerticalScrollbarIsVisible(
Widget vertSB,
Widget scrolledWin)
{
if (vertSB && XtIsManaged(vertSB) &&
(vertSB->core.x < (Position)scrolledWin->core.width))
{
return(True);
}
return(False);
}
Boolean
HorizontalScrollbarIsVisible(
Widget hortSB,
Widget scrolledWin)
{
if (hortSB && XtIsManaged(hortSB) &&
(hortSB->core.y <= (Position)scrolledWin->core.height))
{
return(True);
}
return(False);
}