9062 lines
268 KiB
C
9062 lines
268 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 librararies 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 occuring 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;
|
|
char * wsName;
|
|
Atom pCurrent;
|
|
|
|
/* If the initiation of the drag occured 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(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);
|
|
}
|
|
|
|
fflush(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;
|
|
register 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;
|
|
int effScreenHeight;
|
|
int start_x, start_y;
|
|
int root_x, root_y;
|
|
int step, dstep;
|
|
|
|
/* 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);
|
|
|
|
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;
|
|
|
|
/* 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 if (file_view_data->label == NULL)
|
|
label_len = strlen(file_view_data->file_data->file_name);
|
|
else
|
|
label_len = strlen(file_view_data->label);
|
|
|
|
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, 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);
|
|
}
|