/* * 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 #include #include #include #include #include #include #include #include #include #include #include #ifndef XK_MISCELLANY #define XK_MISCELLANY #endif #include #ifdef SHAPE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
#include
#include
#include #include #include
#include #include #include
#include
#include
#include
#include
#include
#include
#include
#include #include /* _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; inumIconsUsed; 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; icomposite.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; icomposite.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; icomposite.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; icomposite.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); }