/***************************************************************************/ /***************************************************************************/ /* */ /* (c) 1995-1999. The Regents of the University of California. All */ /* rights reserved. */ /* */ /* This work was produced at the University of California, Lawrence */ /* Livermore National Laboratory (UC LLNL) under contract no. */ /* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */ /* (DOE) and The Regents of the University of California (University) */ /* for the operation of UC LLNL. Copyright is reserved to the */ /* University for purposes of controlled dissemination, */ /* commercialization through formal licensing, or other disposition */ /* under terms of Contract 48; DOE policies, regulations and orders; */ /* and U.S. statutes. The rights of the Federal Government are */ /* reserved under Contract 48 subject to the restrictions agreed upon */ /* by the DOE and University. */ /* */ /* */ /* DISCLAIMER */ /* */ /* This software was prepared as an account of work sponsored by an */ /* agency of the United States Government. Neither the United States */ /* Government nor the University of California nor any of their */ /* employees, makes any warranty, express or implied, or assumes any */ /* liability or responsibility for the accuracy, completeness, or */ /* usefulness of any information, apparatus, product, or process */ /* disclosed, or represents that its specific commercial products, */ /* process, or service by trade name, trademark, manufacturer, or */ /* otherwise, does not necessarily constitute or imply its */ /* endorsement, recommendation, or favoring by the United States */ /* Government or the University of California. The views and opinions */ /* of the authors expressed herein do not necessarily state or reflect */ /* those of the United States Government or the University of */ /* California, and shall not be used for advertising or product */ /* endorsement purposes. */ /* */ /* Permission to use, copy, modify and distribute this software and its */ /* documentation for any non-commercial purpose, without fee, is */ /* hereby granted, provided that the above copyright notice and this */ /* permission notice appear in all copies of the software and */ /* supporting documentation, and that all UC LLNL identification in */ /* the user interface remain unchanged. The title to copyright LLNL */ /* XDIR shall at all times remain with The Regents of the University */ /* of California and users agree to preserve same. Users seeking the */ /* right to make derivative works with LLNL XDIR for commercial */ /* purposes may obtain a license from the Lawrence Livermore National */ /* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */ /* Livermore, CA 94550. */ /* */ /***************************************************************************/ /***************************************************************************/ #include #include "xdir.h" #include "list.h" #define CONTROL 0 #define ICON_NAME 1 #define MIN_MOTION 5 static struct dirwin_st *src_dirwin; extern Display *display; extern Window root_window; extern int dir_area_enabled; extern int multiclick_interval; struct entry_info *xy_to_entry(); char *entry_to_full_path(); char *entry_to_rel_path(); struct sl_struct *create_null_array_list(); /* * HandleMouseEvents - Handle mouse events in drawing area of directory * window. */ void HandleMouseEvents(widget, client_data, event, continue_to_dispatch_return) Widget widget; XtPointer client_data; XEvent *event; Boolean *continue_to_dispatch_return; { static struct entry_info *prev_einfo = NULL; static struct entry_info *hilited_einfo; static Time prev_time; static int state = 0; static int button_press_x; static int button_press_y; struct dirwin_st *dirwin = (struct dirwin_st *)client_data; struct dirwin_st *temp_dirwin; struct entry_info *temp_einfo; char *path; char *rel_path; char *true_path; struct entry_info *einfo; int part; int x; int y; int delta_x; int delta_y; struct sl_struct *list; int retval; /* Is some important operation in progress? */ if (op_in_progress()) return; /* Process event */ switch (event->type) { case ButtonPress: if (event->xbutton.button == Button3) { XmMenuPosition(dirwin->w_popupLaunchMenu, (XButtonPressedEvent *)event); XtManageChild(dirwin->w_popupLaunchMenu); } if (event->xbutton.button != Button1) return; src_dirwin = dirwin; x = virtual_x(dirwin, event->xbutton.x); y = virtual_y(dirwin, event->xbutton.y); einfo = xy_to_entry(dirwin, x, y, &part); if (einfo == NULL) { init_toggle_rect(src_dirwin, x, y); state = 1; return; } if (part == CONTROL) { raise_okflag(); if (einfo->expanded) collapse_subtree(&einfo, True); else { if (!start_op(False)) return; if (dirwin->host != LOCAL) { show_stop_button(dirwin); retval = check_connection(dirwin->host, dirwin); if (retval < 0) { switch (retval) { case -6: record_abort("Expand Directory"); break; case -1: record_and_alert("Unable to expand directory.", dirwin->w_shell); } hide_stop_button(); end_op(); state = 0; return; } } path = entry_to_full_path(einfo); retval = determine_true_path(dirwin->host, path, True, dirwin->cache_mode, dirwin->cache_mode, &true_path); XtFree(path); if (retval < 0) { switch (retval) { case -6: record_abort("Expand Directory"); break; case -1: record_and_alert("Unable to go expand directory.", dirwin->w_shell); break; case -3: restore_lost_connection(dirwin->host, dirwin); } if (dirwin->host != LOCAL) hide_stop_button(); end_op(); state = 0; return; } if (is_dir_displayed(dirwin->host, true_path, &temp_dirwin, &temp_einfo)) { if (dirwin == temp_dirwin) { if (dirwin->host != LOCAL) hide_stop_button(); XtFree(true_path); end_op(); state = 0; return; } else { if (temp_einfo) /* Sanity check */ fatal_error("Bug in HandleMouseEvents()"); close_directory_window(temp_dirwin); } } XtFree(true_path); switch (expand_subtree(&einfo, dirwin->cache_mode, dirwin->cache_mode)) { case -6: record_abort("Expand Directory"); break; case -1: record_and_alert("Unable to go expand directory.", dirwin->w_shell); break; case -3: restore_lost_connection(dirwin->host, dirwin); break; case 1: report_cache_use(dirwin, True); } if (dirwin->host != LOCAL) hide_stop_button(); end_op(); } state = 0; return; } else if (einfo == prev_einfo && event->xbutton.time-prev_time < multiclick_interval) { clear_selected_entries(); update_dir_controls(); if ((einfo->type == FILE_TYPE) || (einfo->type == EXECUTABLE_TYPE)) { list = create_null_array_list(); rel_path = entry_to_rel_path(einfo); add_to_array_list(&list, rel_path); XtFree(rel_path); if (!start_op(True)) return; retval = init_view(dirwin, list); release_array_list(list); } else { if (!start_op(False)) return; if (dirwin->host != LOCAL) { show_stop_button(dirwin); retval = check_connection(dirwin->host, dirwin); if (retval < 0) { switch (retval) { case -6: record_abort("Go to Directory"); break; case -1: record_and_alert("Unable to go to directory.", dirwin->w_shell); } hide_stop_button(); end_op(); state = 0; return; } } path = entry_to_full_path(einfo); retval = display_dir(dirwin->host, dirwin, path, False, True, dirwin->cache_mode, dirwin->cache_mode); XtFree(path); switch (retval) { case -6: record_abort("Go to Directory"); break; case -1: record_and_alert("Unable to go to directory.", dirwin->w_shell); break; case -3: restore_lost_connection(dirwin->host, dirwin); } if (dirwin->host != LOCAL) hide_stop_button(); end_op(); } state = 0; } else { XtGrabPointer(dirwin->w_drawingArea, True, ButtonReleaseMask|Button1MotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); prev_einfo = einfo; prev_time = event->xbutton.time; button_press_x = x; button_press_y = y; if (einfo->state == UNSELECTED) { toggle_entry(einfo); state = 5; hilited_einfo = NULL; } else state = 3; } break; case ButtonRelease: if (event->xbutton.button != Button1) return; if (state > 0) XtUngrabPointer(src_dirwin->w_drawingArea, CurrentTime); x = virtual_x(dirwin, event->xbutton.x); y = virtual_y(dirwin, event->xbutton.y); einfo = xy_to_entry(dirwin, x, y, &part); switch (state) { case 1: move_toggle_rect(x, y); remove_toggle_rect(); break; case 2: if (hilited_einfo) { unhilite_entry(hilited_einfo); hilited_einfo = NULL; } restore_prev_cursor(); remove_move_outlines(); if (einfo && (einfo->type == DIRECTORY_TYPE) && (einfo->state == UNSELECTED)) { if (event->xbutton.state&ControlMask) init_move(src_dirwin, dirwin, einfo); else init_copy(src_dirwin, dirwin, einfo); } else if (dirwin != src_dirwin) { if (event->xbutton.state&ControlMask) init_move(src_dirwin, dirwin, NULL); else init_copy(src_dirwin, dirwin, NULL); } break; case 3: if ((einfo == prev_einfo) && (einfo->state == SELECTED)) toggle_entry(einfo); break; case 4: unset_toggle_rect_timer(); move_toggle_rect(x, y); remove_toggle_rect(); break; case 5: break; } state = 0; break; case MotionNotify: if (event->xbutton.root != root_window) break; x = virtual_x(dirwin, event->xbutton.x); y = virtual_y(dirwin, event->xbutton.y); einfo = xy_to_entry(dirwin, x, y, &part); switch (state) { case 1: case 4: move_toggle_rect(x, y); break; case 3: case 5: delta_x = x-button_press_x; delta_y = y-button_press_y; if (delta_x*delta_x+delta_y*delta_y < MIN_MOTION*MIN_MOTION) break; state = 2; init_outlines(src_dirwin, button_press_x, button_press_y); use_outlines_cursor(); case 2: move_outlines(dirwin->w_drawingArea, event->xbutton.x, event->xbutton.y); if (hilited_einfo && hilited_einfo != einfo) { unhilite_entry(hilited_einfo); hilited_einfo = NULL; } if (einfo && part == ICON_NAME && einfo->state == UNSELECTED && einfo->type == DIRECTORY_TYPE && einfo != hilited_einfo) { hilite_entry(einfo); hilited_einfo = einfo; } break; } break; case EnterNotify: if (state == 4) { state = 1; unset_toggle_rect_timer(); } break; case LeaveNotify: if (state == 1) { state = 4; set_toggle_rect_timer(); } } } /* * xy_to_entry - Determine the entry at coordinates (x, y). Returns NULL * if no entry at this position. If entry is found, part * is set to "CONTROL" if (x, y) falls in a tree view * control, or to "ICON_NAME" if (x, y) falls on the entry * icon or name. */ struct entry_info * xy_to_entry(dirwin, x, y, part) struct dirwin_st *dirwin; int x; int y; int *part; { int indx; int row; int col; struct entry_info *einfo; int x_offset; int y_offset; if (dirwin->nentries == 0) return NULL; if (x < HMARGIN || y < 0) return NULL; switch (dirwin->layout) { case TABULAR: case ICONIC: col = (x-HMARGIN)/(dirwin->max_entry_width+HSPACING); if (col >= dirwin->ncols) return NULL; row = y/(dirwin->entry_height+VSPACING); if (row >= dirwin->nrows || row >= dirwin->first_visible_row+dirwin->nrows_visible) return NULL; indx = col*dirwin->nrows+row; if (indx >= dirwin->nentries) return NULL; einfo = &dirwin->entries[indx]; x_offset = x-HMARGIN-col*(dirwin->max_entry_width+HSPACING); if (x_offset >= einfo->width) return NULL; y_offset = y-row*(dirwin->entry_height+VSPACING); if (y_offset >=dirwin->entry_height) return NULL; *part = ICON_NAME; return einfo; case TREE: row = y/(dirwin->entry_height+VSPACING); if (row >= dirwin->nentries || row >= dirwin->first_visible_row+dirwin->nrows_visible) return NULL; einfo = &dirwin->entries[row]; y_offset = y-row*(dirwin->entry_height+VSPACING); if (y_offset >=dirwin->entry_height) return NULL; x_offset = x-HMARGIN-einfo->level*INDENT; if (x_offset < 0 || x_offset >= CWIDTH+CMARGIN+einfo->width) return NULL; else if (x_offset >= CWIDTH+CMARGIN) { *part = ICON_NAME; return einfo; } else if (einfo->type == DIRECTORY_TYPE) { *part = CONTROL; return einfo; } else return NULL; case FULL_INFO: row = y/(dirwin->entry_height+VSPACING); if (row >= dirwin->nrows || row >= dirwin->first_visible_row+dirwin->nrows_visible) return NULL; einfo = &dirwin->entries[row]; if (x >= HMARGIN+einfo->width) return NULL; else { *part = ICON_NAME; return einfo; } } return NULL; /* Necessary to keep gcc compiler happy */ }