/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (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 <Xm/Xm.h>
#include <limits.h>
#include <sys/param.h>
#include "xdir.h"

static XRectangle *orig_outlines;
static XRectangle *outlines;
static int num_outlines;
static int outlines_drawn;
static int orig_move_x;
static int orig_move_y;
static Window main_input_window;
static int x_leftmost_range;
static int x_rightmost_range;
static int y_topmost_range;
static int y_bottommost_range;

extern Display *display;
extern Window root_window;
extern GC gc_move;
extern struct dirwin_st *dirwin_head;
extern Widget w_toplev;

void create_invisible_windows();
void destroy_invisible_windows();

void
hilite_entry(einfo)
struct entry_info *einfo;
{
	XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
		outlines, num_outlines);
	einfo->state = SELECTED;
	draw_entry(einfo);
	XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
		outlines, num_outlines);
}


void
unhilite_entry(einfo)
struct entry_info *einfo;
{
	XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
		outlines, num_outlines);
	einfo->state = UNSELECTED;
	draw_entry(einfo);
	XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
		outlines, num_outlines);
}


void
init_outlines(dirwin, x, y)
struct dirwin_st *dirwin;
int x;
int y;
{
	int start_row;
	int end_row;
	int start_col;
	int end_col;
	int col;
	int row;
	int nrows;
	int indx;
	Dimension drawing_area_width;
	Dimension drawing_area_height;
	Position drawing_area_x;
	Position drawing_area_y;
	int x_offset_virtual_to_global;
	int y_offset_virtual_to_global;
	int x_root;
	int y_root;
	Window child;
	int min_x = INT_MAX;
	int max_x = 0;
	int min_y = INT_MAX;
	int max_y = 0;
	Window rr;
	int xr;
	int yr;
	unsigned int wr;
	unsigned int hr;
	unsigned int bwr;
	unsigned int dr;
	int i;

	/* Calculate offsets for virtual to global coordinate translations */
	XTranslateCoordinates(display, XtWindow(dirwin->w_drawingArea),
		root_window, 0, 0, &x_root, &y_root, &child);
	x_offset_virtual_to_global = actual_x(dirwin, 0)+x_root;
	y_offset_virtual_to_global = actual_y(dirwin, 0)+y_root;

	/* Remember original cursor global coordinates */
	orig_move_x = x+x_offset_virtual_to_global;
	orig_move_y = y+y_offset_virtual_to_global;

	/* Get drawing area geometry */
	XtVaGetValues(dirwin->w_drawingArea,
		XmNwidth,	&drawing_area_width,
		XmNheight,	&drawing_area_height,
		XmNx,		&drawing_area_x,
		XmNy,		&drawing_area_y,
		NULL
	);

	/* Create rectangles to be used to draw outlines of entries being moved */
	outlines_drawn = False;
	num_outlines = 0;
    start_row = dirwin->first_visible_row;
	end_row = start_row+dirwin->nrows_visible-1;
	end_row = MIN(end_row, dirwin->nrows-1);
	nrows = dirwin->nrows;
	switch (dirwin->layout) {
	case TABULAR:
	case ICONIC:
		start_col = virtual_x(dirwin, 0)
			/(dirwin->max_entry_width+HSPACING);
		start_col = MAX(start_col, 0);
		end_col = virtual_x(dirwin, drawing_area_width)
			/(dirwin->max_entry_width+HSPACING);
		end_col = MIN(end_col, dirwin->ncols-1);
		orig_outlines = 
			(XRectangle *)XtMalloc((end_col-start_col+1)*(end_row-start_row+1)
			*sizeof(XRectangle));
		for (col=start_col; col<=end_col; col++)
			for (row=start_row; row<=end_row; row++) {
				indx = col*nrows+row;
				if (indx >= dirwin->nentries)
					break;
				if (dirwin->entries[indx].state == SELECTED) {
					orig_outlines[num_outlines].x = HMARGIN
						+col*(dirwin->max_entry_width+HSPACING);
					orig_outlines[num_outlines].y =
						row*(dirwin->entry_height+VSPACING);
					orig_outlines[num_outlines].width =
						dirwin->entries[indx].width;
					orig_outlines[num_outlines].height =
						dirwin->entry_height;
					num_outlines++;
				}
			}
		break;
	case TREE:
		orig_outlines = (XRectangle *)XtMalloc((end_row-start_row+1)
			*sizeof(XRectangle));
	    for (row=start_row; row<=end_row; row++) {
			if (dirwin->entries[row].state == SELECTED) {
				orig_outlines[num_outlines].x = 
					dirwin->entries[row].level*INDENT+HMARGIN+CWIDTH+CMARGIN;
				orig_outlines[num_outlines].y =
					row*(dirwin->entry_height+VSPACING);
				orig_outlines[num_outlines].width = dirwin->entries[row].width;
				orig_outlines[num_outlines].height = dirwin->entry_height;
				num_outlines++;
			}
		}
		break;
	case FULL_INFO:
		orig_outlines = 
			(XRectangle *)XtMalloc((end_row-start_row+1)*sizeof(XRectangle));
		for (row=start_row; row<=end_row; row++)
			if (dirwin->entries[row].state == SELECTED) {
				orig_outlines[num_outlines].x = HMARGIN;
				orig_outlines[num_outlines].y =
					row*(dirwin->entry_height+VSPACING);
				orig_outlines[num_outlines].width =
					dirwin->entries[row].width;
				orig_outlines[num_outlines].height =
					dirwin->entry_height;
				num_outlines++;
			}
		break;
	}
	outlines = (XRectangle *)XtMalloc(num_outlines*sizeof(XRectangle));
	bcopy(orig_outlines, outlines, num_outlines*sizeof(XRectangle));

	/* Install event handlers on Xdir's widgets that absorb motion events */
	create_invisible_windows();

	/* Convert rectangles from virtual to global coordinated */
	for (i=0; i<num_outlines; i++) {
		orig_outlines[i].x += x_offset_virtual_to_global;
		orig_outlines[i].y += y_offset_virtual_to_global;
	}

	/* Determine bounds for moving outlines */
	for (i=0; i<num_outlines; i++) {
		min_x = MIN(min_x, orig_outlines[i].x);
		max_x = MAX(max_x, (int)(orig_outlines[i].x+orig_outlines[i].width));
		min_y = MIN(min_y, orig_outlines[i].y);
		max_y = MAX(max_y, (int)(orig_outlines[i].y+orig_outlines[i].height));
	}
	XGetGeometry(display, root_window, &rr, &xr, &yr, &wr, &hr, &bwr, &dr);
	x_leftmost_range = orig_move_x-min_x;
	x_rightmost_range = wr-(max_x-orig_move_x)-1;
	y_topmost_range = orig_move_y-min_y;
	y_bottommost_range = hr-(max_y-orig_move_y)-1;
}


void
move_outlines(widget, x, y)
Widget widget;
int x;
int y;
{
	int i;
	int x_offset;
	int y_offset;
	int x_global;
	int y_global;
	Window child;

	/* Erase previous outlines */
	if (outlines_drawn)
		XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
			outlines, num_outlines);

	/* Adjust coordinates of outline rectangles */
	XTranslateCoordinates(display, XtWindow(widget), root_window, x, y,
		&x_global, &y_global, &child);
	if (x_global <= x_leftmost_range)
		x_global = x_leftmost_range;
	else if (x_global >= x_rightmost_range)
		x_global = x_rightmost_range;
	x_offset = x_global-orig_move_x;
	if (y_global <= y_topmost_range)
		y_global = y_topmost_range;
	else if (y_global >= y_bottommost_range)
		y_global = y_bottommost_range;
	y_offset = y_global-orig_move_y;
	for (i=0; i<num_outlines; i++) {
		outlines[i].x = orig_outlines[i].x+x_offset;
		outlines[i].y = orig_outlines[i].y+y_offset;
	}

	XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
		outlines, num_outlines);
	outlines_drawn = True;
}


void
remove_move_outlines()
{
	/* Erase previous outlines */
	if (outlines_drawn)
		XDrawRectangles(display, XDefaultRootWindow(display), gc_move,
			outlines, num_outlines);

	/* Free up memory */
	XtFree((char *)outlines);
	XtFree((char *)orig_outlines);

	/* Remove event handlers on Xdir's widgets that absorb motion events */
	destroy_invisible_windows();
}


/*
 * create_invisible_windows - Creates invisible input-only windows to
 *                            overlay the non-drawingArea portions of
 *                            the application.  This is done so that
 *                            none of the application's widgets will
 *                            get the motion events intended for
 *                            moving the outlines of selected entries.
 */
void
create_invisible_windows()
{
	struct dirwin_st *dirwin;
	Dimension w1;
	Dimension h1;
	int x2;
	int y2;
	Dimension w2;
	Dimension h2;
	XSetWindowAttributes xswa;
	unsigned long valuemask;
	Window child;
	Window shell_window;

	/* Specify the window attributes */
	xswa.override_redirect = True;
	valuemask = CWOverrideRedirect;

	/* Overlay input windows over non-drawingArea parts of directory displays */
	dirwin = dirwin_head;
	while(dirwin) {
		XtVaGetValues(dirwin->w_form,
			XmNwidth,	&w1,
			XmNheight,	&h1,
			NULL
		);
		XtVaGetValues(dirwin->w_drawingArea,
			XmNwidth,	&w2,
			XmNheight,	&h2,
			NULL
		);
		shell_window = XtWindow(XtParent(dirwin->w_form));
		XTranslateCoordinates(display, XtWindow(dirwin->w_drawingArea),
			shell_window, 0, 0, &x2, &y2, &child);
		dirwin->input_windows[0] = XCreateWindow(display, shell_window,
			 0, 0, (int)w1, y2,
			0, 0, InputOnly, CopyFromParent, valuemask, &xswa);
		XMapWindow(display, dirwin->input_windows[0]);
		dirwin->input_windows[1] = XCreateWindow(display, shell_window,
			(int)(x2+w2), y2, (int)(w1-(x2+w2)), (int)h2,
			0, 0, InputOnly, CopyFromParent, valuemask, &xswa);
		XMapWindow(display, dirwin->input_windows[1]);
		dirwin->input_windows[2] = XCreateWindow(display, shell_window,
			0, (int)(y2+h2), w1, (int)(h1-(y2+h2)),
			0, 0, InputOnly, CopyFromParent, valuemask, &xswa);
		XMapWindow(display, dirwin->input_windows[2]);
		dirwin->input_windows[3] = XCreateWindow(display, shell_window,
			0, y2, x2, (int)h2,
			0, 0, InputOnly, CopyFromParent, valuemask, &xswa);
		XMapWindow(display, dirwin->input_windows[3]);
		dirwin = dirwin->next;
	}

	/* Overlay invisible window over main window to deflect input events */
	XtVaGetValues(w_toplev,
		XmNwidth,	&w1,
		XmNheight,	&h1,
		NULL
	);
	main_input_window = XCreateWindow(display, XtWindow(w_toplev), 0, 0,
		(int)w1, (int)h1, 0, 0, InputOnly, CopyFromParent,
		valuemask, &xswa);
	XMapWindow(display, main_input_window);

	/***************  How about help, preferences, and about windows? ********/
}


/*
 * destroy_invisible_windows - Destroys the invisible windows that overlay
 *                             the non-drawingArea portions of the
 *                             application.
 */
void
destroy_invisible_windows()
{
	struct dirwin_st *dirwin;
	int i;

	/* Destroy invisible windows overlaying portions of directory displays */
	dirwin = dirwin_head;
	while(dirwin) {
		for (i=0; i<4; i++)
			XDestroyWindow(display, dirwin->input_windows[i]);
		dirwin = dirwin->next;
	}

	/* Destroy invisible window overlaying main window */
	XDestroyWindow(display, main_input_window);
}



syntax highlighted by Code2HTML, v. 0.9.1