1 /*
2  * Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore)
3  * Copyright(c) 1995-99 Andrew Lister
4  *                        All rights reserved
5  * Permission to use, copy, modify and distribute this material for
6  * any purpose and without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies, and that the name of Bellcore not be used in advertising
9  * or publicity pertaining to this material without the specific,
10  * prior written permission of an authorized representative of
11  * Bellcore.
12  *
13  * BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX-
14  * PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT
15  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN-
17  * FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS.  THE
18  * SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR
19  * ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY
20  * LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT-
21  * ING TO THE SOFTWARE.
22  *
23  * MatrixWidget Author: Andrew Wason, Bellcore, aw@bae.bellcore.com
24  *
25  * $Id: Create.c,v 1.1.2.3 2004/08/02 19:54:03 fnevgeny Exp $
26  */
27 
28 /*
29  * Create.c created by Andrew Lister (28 Jan, 1996)
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <stdlib.h>
37 
38 #include <Xm/Xm.h>
39 #include <Xbae/MatrixP.h>
40 #include <Xbae/Macros.h>
41 #include <Xbae/Utils.h>
42 #include <Xbae/Actions.h>
43 #include <Xm/ScrollBar.h>
44 #include <Xbae/Create.h>
45 
46 static Pixmap createInsensitivePixmap P((XbaeMatrixWidget mw));
47 
48 void
xbaeCopyBackground(widget,offset,value)49 xbaeCopyBackground(widget, offset, value)
50 Widget widget;
51 int offset;
52 XrmValue *value;
53 {
54     value->addr = (XtPointer)&(widget->core.background_pixel);
55 }
56 
57 
58 void
xbaeCopyForeground(widget,offset,value)59 xbaeCopyForeground(widget, offset, value)
60 Widget widget;
61 int offset;
62 XrmValue *value;
63 {
64     value->addr = (XtPointer)&(((XmManagerWidget)widget)->manager.foreground);
65 }
66 
67 void
xbaeCopyDoubleClick(widget,offset,value)68 xbaeCopyDoubleClick(widget, offset, value)
69 Widget widget;
70 int offset;
71 XrmValue *value;
72 {
73     static int interval;
74 
75     interval = XtGetMultiClickTime(XtDisplay(widget));
76     value->addr = (XtPointer)&interval;
77 }
78 
79 void
xbaeCopyCells(mw)80 xbaeCopyCells(mw)
81 XbaeMatrixWidget mw;
82 {
83     String **copy = NULL;
84     int i, j;
85     Boolean empty_row;
86 
87     if (mw->matrix.rows && mw->matrix.columns)
88     {
89 	/*
90 	 * Malloc an array of row pointers
91 	 */
92 	copy = (String **) XtMalloc(mw->matrix.rows * sizeof(String *));
93 
94 	/*
95 	 * Malloc an array of Strings for each row pointer
96 	 */
97 	for (i = 0; i < mw->matrix.rows; i++)
98 	    copy[i] = (String *) XtMalloc(mw->matrix.columns * sizeof(String));
99 
100 	/*
101 	 * Create a bunch of "" cells if cells was NULL
102 	 */
103 	if (!mw->matrix.cells)
104 	{
105 	    for (i = 0; i < mw->matrix.rows; i++)
106 		for (j = 0; j < mw->matrix.columns; j++)
107 		    copy[i][j] = XtNewString("");
108 	}
109 
110 	/*
111 	 * Otherwise copy the table passed in
112 	 */
113 	else
114 	{
115 	    for (i = 0, empty_row = False; i < mw->matrix.rows; i++)
116 	    {
117 		if (!empty_row && !mw->matrix.cells[i])
118 		    empty_row = True;
119 		for (j = 0; j < mw->matrix.columns; j++)
120 		{
121 		    if (empty_row || !mw->matrix.cells[i][j])
122 		    {
123 			XtAppWarningMsg(
124 			    XtWidgetToApplicationContext((Widget)mw),
125 			    "copyCells", "badValue", "XbaeMatrix",
126 			    "XbaeMatrix: NULL entry found in cell table",
127 			    NULL, 0);
128 			for (;j < mw->matrix.columns; j++)
129 			    copy[i][j] = XtNewString("");
130 		    }
131 		    else
132 			copy[i][j] = XtNewString(mw->matrix.cells[i][j]);
133 		}
134 	    }
135 	}
136     }
137     mw->matrix.cells = copy;
138 }
139 
140 #if CELL_WIDGETS
141 void
xbaeCopyCellWidgets(mw)142 xbaeCopyCellWidgets(mw)
143 XbaeMatrixWidget mw;
144 {
145     Widget **copy = NULL;
146     int i, j;
147 
148     /*
149      * Malloc an array of row pointers
150      */
151     if (mw->matrix.rows && mw->matrix.columns)
152     {
153 	copy = (Widget **) XtCalloc((Cardinal)mw->matrix.rows,
154 				    sizeof(Widget *));
155 
156 	for (i = 0; i < mw->matrix.rows; i++)
157 	{
158 	    copy[i] = (Widget *) XtCalloc((Cardinal)mw->matrix.columns,
159 					  sizeof(Widget));
160 	    if (mw->matrix.cell_widgets)
161 		for (j = 0; j < mw->matrix.columns; j++)
162 		    if (mw->matrix.cell_widgets[i][j])
163 			copy[i][j] = mw->matrix.cell_widgets[i][j];
164 	}
165     }
166     mw->matrix.cell_widgets = copy;
167 }
168 #endif
169 
170 void
xbaeCopyCellShadowTypes(mw)171 xbaeCopyCellShadowTypes(mw)
172 XbaeMatrixWidget mw;
173 {
174     unsigned char **copy = NULL;
175     int i, j;
176 
177     if (mw->matrix.rows && mw->matrix.columns)
178     {
179 	copy = (unsigned char **) XtMalloc(mw->matrix.rows *
180 					   sizeof(unsigned char*));
181 
182 	for (i = 0; i < mw->matrix.rows; i++)
183 	    copy[i] = (unsigned char*) XtMalloc(mw->matrix.columns *
184 						sizeof(unsigned char));
185 
186 	for (i = 0; i < mw->matrix.rows; i++)
187 	    for (j = 0; j < mw->matrix.columns; j++)
188 	    {
189 		if (!mw->matrix.cell_shadow_types[i][j])
190 
191 		{
192 		    XtAppWarningMsg(
193 			XtWidgetToApplicationContext((Widget) mw),
194 			"xbaeCopyCellShadowTypes", "badValue", "XbaeMatrix",
195 			"XbaeMatrix: NULL entry found in cellShadowTypes array",
196 			NULL, 0);
197 		    copy[i][j] = XmSHADOW_OUT;
198 		}
199 		else
200 		    copy[i][j] = mw->matrix.cell_shadow_types[i][j];
201 	    }
202     }
203     mw->matrix.cell_shadow_types = copy;
204 }
205 
206 void
xbaeCopyRowShadowTypes(mw)207 xbaeCopyRowShadowTypes(mw)
208 XbaeMatrixWidget mw;
209 {
210     unsigned char *copy = NULL;
211     int i;
212 
213     if (mw->matrix.rows)
214     {
215 	copy = (unsigned char *) XtMalloc(mw->matrix.rows *
216 					  sizeof(unsigned char));
217 
218 	for (i = 0; i < mw->matrix.rows; i++)
219 	    if (!mw->matrix.row_shadow_types[i])
220 	    {
221 		XtAppWarningMsg(
222 		    XtWidgetToApplicationContext((Widget) mw),
223 		    "xbaeCopyRowShadowTypes", "badValue", "XbaeMatrix",
224 		    "XbaeMatrix: NULL entry found in rowShadowTypes array",
225 		    NULL, 0);
226 		copy[i] = XmSHADOW_OUT;
227 	    }
228 	    else
229 		copy[i] = mw->matrix.row_shadow_types[i];
230     }
231     mw->matrix.row_shadow_types = copy;
232 }
233 
234 void
xbaeCopyColumnShadowTypes(mw)235 xbaeCopyColumnShadowTypes(mw)
236 XbaeMatrixWidget mw;
237 {
238     unsigned char *copy = NULL;
239     int i;
240 
241     if (mw->matrix.columns)
242     {
243 	copy = (unsigned char *) XtMalloc(mw->matrix.columns *
244 					  sizeof(unsigned char));
245 
246 	for (i = 0; i < mw->matrix.columns; i++)
247 	    if (!mw->matrix.column_shadow_types[i])
248 	    {
249 		XtAppWarningMsg(
250 		    XtWidgetToApplicationContext((Widget) mw),
251 		    "xbaeCopyColumnShadowTypes", "badValue", "XbaeMatrix",
252 		    "XbaeMatrix: NULL entry found in columnShadowTypes array",
253 		    NULL, 0);
254 		copy[i] = XmSHADOW_OUT;
255 	    }
256 	    else
257 		copy[i] = mw->matrix.column_shadow_types[i];
258     }
259     mw->matrix.column_shadow_types = copy;
260 }
261 
262 
263 void
xbaeCopyCellUserData(mw)264 xbaeCopyCellUserData(mw)
265 XbaeMatrixWidget mw;
266 {
267     XtPointer **copy = NULL;
268     int i, j;
269 
270     if (mw->matrix.rows && mw->matrix.columns)
271     {
272 	copy = (XtPointer **) XtMalloc(mw->matrix.rows * sizeof(XtPointer*));
273 
274 	for (i = 0; i < mw->matrix.rows; i++)
275 	    copy[i] = (XtPointer*) XtMalloc(mw->matrix.columns *
276 					    sizeof(XtPointer));
277 
278 	for (i = 0; i < mw->matrix.rows; i++)
279 	    for (j = 0; j < mw->matrix.columns; j++)
280 		copy[i][j] = mw->matrix.cell_user_data[i][j];
281     }
282     mw->matrix.cell_user_data = copy;
283 }
284 
285 void
xbaeCopyRowUserData(mw)286 xbaeCopyRowUserData(mw)
287 XbaeMatrixWidget mw;
288 {
289     XtPointer *copy = NULL;
290     int i;
291 
292     if (mw->matrix.rows)
293     {
294 	copy = (XtPointer *) XtMalloc(mw->matrix.rows * sizeof(XtPointer));
295 
296 	for (i = 0; i < mw->matrix.rows; i++)
297 	    copy[i] = mw->matrix.row_user_data[i];
298     }
299     mw->matrix.row_user_data = copy;
300 }
301 
302 void
xbaeCopyColumnUserData(mw)303 xbaeCopyColumnUserData(mw)
304 XbaeMatrixWidget mw;
305 {
306     XtPointer *copy = NULL;
307     int i;
308 
309     if (mw->matrix.columns)
310     {
311 	copy = (XtPointer *) XtMalloc(mw->matrix.columns * sizeof(XtPointer));
312 
313 	for (i = 0; i < mw->matrix.columns; i++)
314 	    copy[i] = mw->matrix.column_user_data[i];
315     }
316     mw->matrix.column_user_data = copy;
317 }
318 
319 void
xbaeCopyRowLabels(mw)320 xbaeCopyRowLabels(mw)
321 XbaeMatrixWidget mw;
322 {
323     String *copy = NULL;
324     int i;
325     Boolean empty_label;
326 
327     if (mw->matrix.rows)
328     {
329 	copy = (String *) XtMalloc(mw->matrix.rows * sizeof(String));
330 
331 	for (i = 0, empty_label = False; i < mw->matrix.rows; i++)
332 	    if (empty_label || !mw->matrix.row_labels[i])
333 	    {
334 		XtAppWarningMsg(
335 		    XtWidgetToApplicationContext((Widget) mw),
336 		    "copyRowLabels", "badValue", "XbaeMatrix",
337 		    "XbaeMatrix: NULL entry found in rowLabels array",
338 		    NULL, 0);
339 		copy[i] = XtNewString("");
340 		empty_label = True;
341 	    }
342 	    else
343 		copy[i] = XtNewString(mw->matrix.row_labels[i]);
344     }
345     mw->matrix.row_labels = copy;
346 }
347 
348 void
xbaeCopyColumnLabels(mw)349 xbaeCopyColumnLabels(mw)
350 XbaeMatrixWidget mw;
351 {
352     String *copy = NULL;
353     int i;
354     Boolean empty_column;
355 
356     if (mw->matrix.columns)
357     {
358 	copy = (String *) XtMalloc(mw->matrix.columns * sizeof(String));
359 
360 	mw->matrix.column_label_lines = (ColumnLabelLines)
361 	    XtMalloc(mw->matrix.columns * sizeof(ColumnLabelLinesRec));
362 
363 	for (i = 0, empty_column = False; i < mw->matrix.columns; i++)
364 	    if (empty_column || !mw->matrix.column_labels[i])
365 	    {
366 		XtAppWarningMsg(
367 		    XtWidgetToApplicationContext((Widget) mw),
368 		    "copyColumnLabels", "badValue", "XbaeMatrix",
369 		    "XbaeMatrix: NULL entry found in columnLabels array",
370 		    NULL, 0);
371 		copy[i] = XtNewString("");
372 		empty_column = True;
373 		xbaeParseColumnLabel(
374 		    copy[i], &mw->matrix.column_label_lines[i]);
375 	    }
376 	    else
377 	    {
378 		copy[i] = XtNewString(mw->matrix.column_labels[i]);
379 		xbaeParseColumnLabel(mw->matrix.column_labels[i],
380 				     &mw->matrix.column_label_lines[i]);
381 	    }
382 
383 	/*
384 	 * Determine max number of lines in column labels
385 	 */
386 	mw->matrix.column_label_maxlines =
387 	    mw->matrix.column_label_lines[0].lines;
388 
389 	for (i = 1; i < mw->matrix.columns; i++)
390 	    if (mw->matrix.column_label_lines[i].lines >
391 		mw->matrix.column_label_maxlines)
392 		mw->matrix.column_label_maxlines =
393 		    mw->matrix.column_label_lines[i].lines;
394     }
395     mw->matrix.column_labels = copy;
396 }
397 
398 void
xbaeCopyColumnWidths(mw)399 xbaeCopyColumnWidths(mw)
400 XbaeMatrixWidget mw;
401 {
402     short *copy = NULL;
403     int i;
404     Boolean bad = False;
405 
406     if (mw->matrix.columns)
407     {
408 	copy = (short *) XtMalloc(mw->matrix.columns * sizeof(short));
409 
410 	for (i = 0; i < mw->matrix.columns; i++)
411 	{
412 	    if (!bad && mw->matrix.column_widths[i] == BAD_WIDTH)
413 	    {
414 		bad = True;
415 		XtAppWarningMsg(
416 		    XtWidgetToApplicationContext((Widget) mw),
417 		    "copyColumnWidths", "tooShort", "XbaeMatrix",
418 		    "XbaeMatrix: Column widths array is too short",
419 		    NULL, 0);
420 		copy[i] = 1;
421 	    }
422 	    else if (bad)
423 		copy[i] = 1;
424 	    else
425 		copy[i] = mw->matrix.column_widths[i];
426 	}
427     }
428     mw->matrix.column_widths = copy;
429 }
430 
431 void
xbaeCopyColumnMaxLengths(mw)432 xbaeCopyColumnMaxLengths(mw)
433 XbaeMatrixWidget mw;
434 {
435     int *copy = NULL;
436     int i;
437     Boolean bad = False;
438 
439     if (mw->matrix.columns)
440     {
441 	copy = (int *) XtMalloc(mw->matrix.columns * sizeof(int));
442 
443 	for (i = 0; i < mw->matrix.columns; i++)
444 	{
445 	    if (!bad && mw->matrix.column_max_lengths[i] == BAD_MAXLENGTH)
446 	    {
447 		bad = True;
448 		XtAppWarningMsg(
449 		    XtWidgetToApplicationContext((Widget) mw),
450 		    "copyColumnMaxLengths", "tooShort", "XbaeMatrix",
451 		    "XbaeMatrix: Column max lengths array is too short",
452 		    NULL, 0);
453 		copy[i] = 1;
454 	    }
455 	    else if (bad)
456 		copy[i] = 1;
457 	    else
458 		copy[i] = mw->matrix.column_max_lengths[i];
459 	}
460     }
461     mw->matrix.column_max_lengths = copy;
462 }
463 
464 void
xbaeCopyColumnAlignments(mw)465 xbaeCopyColumnAlignments(mw)
466 XbaeMatrixWidget mw;
467 {
468     unsigned char *copy = NULL;
469     int i;
470     Boolean bad = False;
471 
472     if (mw->matrix.columns)
473     {
474 	copy = (unsigned char *) XtMalloc(mw->matrix.columns *
475 					  sizeof(unsigned char));
476 
477 	for (i = 0; i < mw->matrix.columns; i++)
478 	{
479 	    if (!bad && mw->matrix.column_alignments[i] == BAD_ALIGNMENT)
480 	    {
481 		bad = True;
482 		XtAppWarningMsg(
483 		    XtWidgetToApplicationContext((Widget) mw),
484 		    "copyColumnAlignments", "tooShort", "XbaeMatrix",
485 		    "XbaeMatrix: Column alignments array is too short",
486 		    NULL, 0);
487 		copy[i] = XmALIGNMENT_BEGINNING;
488 	    }
489 	    else if (bad)
490 		copy[i] = XmALIGNMENT_BEGINNING;
491 	    else
492 		copy[i] = mw->matrix.column_alignments[i];
493 	}
494     }
495     mw->matrix.column_alignments = copy;
496 }
497 
498 void
xbaeCopyColumnButtonLabels(mw)499 xbaeCopyColumnButtonLabels(mw)
500 XbaeMatrixWidget mw;
501 {
502     Boolean *copy = NULL;
503     int i;
504 
505     if (mw->matrix.columns)
506     {
507 	copy = (Boolean *) XtMalloc(mw->matrix.columns *
508 				    sizeof(Boolean));
509 
510 	for (i = 0; i < mw->matrix.columns; i++)
511 	{
512 	    copy[i] = mw->matrix.column_button_labels[i];
513 	}
514     }
515     mw->matrix.column_button_labels = copy;
516 }
517 
518 void
xbaeCopyRowButtonLabels(mw)519 xbaeCopyRowButtonLabels(mw)
520 XbaeMatrixWidget mw;
521 {
522     Boolean *copy = NULL;
523     int i;
524 
525     if (mw->matrix.rows)
526     {
527 	copy = (Boolean *) XtMalloc(mw->matrix.rows *
528 				    sizeof(Boolean));
529 
530 	for (i = 0; i < mw->matrix.rows; i++)
531 	{
532 	    copy[i] = mw->matrix.row_button_labels[i];
533 	}
534     }
535     mw->matrix.row_button_labels = copy;
536 }
537 
538 void
xbaeCopyColumnLabelAlignments(mw)539 xbaeCopyColumnLabelAlignments(mw)
540 XbaeMatrixWidget mw;
541 {
542     unsigned char *copy = NULL;
543     int i;
544     Boolean bad = False;
545 
546     if (mw->matrix.columns)
547     {
548 	copy = (unsigned char *) XtMalloc(mw->matrix.columns *
549 					  sizeof(unsigned char));
550 
551 	for (i = 0; i < mw->matrix.columns; i++)
552 	{
553 	    if (!bad &&
554 		mw->matrix.column_label_alignments[i] == BAD_ALIGNMENT)
555 	    {
556 		bad = True;
557 		XtAppWarningMsg(
558 		    XtWidgetToApplicationContext((Widget) mw),
559 		    "copyColumnLabelAlignments", "tooShort",
560 		    "XbaeMatrix",
561 		    "XbaeMatrix: Column label alignments array is too short",
562 		    NULL, 0);
563 		copy[i] = XmALIGNMENT_BEGINNING;
564 	    }
565 	    else if (bad)
566 		copy[i] = XmALIGNMENT_BEGINNING;
567 	    else
568 		copy[i] = mw->matrix.column_label_alignments[i];
569 	}
570     }
571     mw->matrix.column_label_alignments = copy;
572 }
573 
574 void
xbaeCopyColors(mw)575 xbaeCopyColors(mw)
576 XbaeMatrixWidget mw;
577 {
578     Pixel **copy = NULL;
579     int i, j;
580     Boolean badrow = False;
581     Boolean badcol;
582 
583 
584     if (mw->matrix.rows && mw->matrix.columns)
585     {
586 	/*
587 	 * Malloc an array of row pointers
588 	 */
589 	copy = (Pixel **) XtMalloc(mw->matrix.rows * sizeof(Pixel *));
590 
591 	/*
592 	 * Malloc an array of Pixels for each row pointer
593 	 */
594 	for (i = 0; i < mw->matrix.rows; i++)
595 	    copy[i] = (Pixel *) XtMalloc(mw->matrix.columns * sizeof(Pixel));
596 
597 	if (!mw->matrix.colors)
598 	{
599 	    for (i = 0; i < mw->matrix.rows; i++)
600 		for (j = 0; j < mw->matrix.columns; j++)
601 		    copy[i][j] = mw->manager.foreground;
602 	}
603 	else 	for (i = 0; i < mw->matrix.rows; i++)
604 	{
605 	    if (!badrow && !mw->matrix.colors[i]) {
606 		badrow = True;
607 		XtAppWarningMsg(
608 		    XtWidgetToApplicationContext((Widget)mw),
609 		    "copyCellColors", "tooShort",
610 		    "XbaeMatrix",
611 		    "XbaeMatrix: Cell ColorPixelTable is too short",
612 		    NULL, 0);
613 	    }
614 	    badcol = badrow;
615 	    for (j = 0; j < mw->matrix.columns; j++)
616 	    {
617 		if (badcol || mw->matrix.colors[i][j] == BAD_PIXEL)
618 		{
619 		    badcol = True;
620 		    if (j > 0)
621 			copy[i][j] = copy[i][j-1] ;
622 		    else if (i > 0)
623 			copy[i][j] = copy[i-1][j] ;
624 		    else
625 			copy[i][j] = mw->manager.foreground;
626 		}
627 		else
628 		{
629 		    copy[i][j] = mw->matrix.colors[i][j];
630 		}
631 	    }
632 	}
633     }
634     mw->matrix.colors = copy;
635 }
636 
637 void
xbaeCopyBackgrounds(mw)638 xbaeCopyBackgrounds(mw)
639 XbaeMatrixWidget mw;
640 {
641     Pixel **copy = NULL;
642     int i, j;
643     Boolean badrow = False;
644     Boolean badcol;
645 
646     if (mw->matrix.rows && mw->matrix.columns)
647     {
648 	/*
649 	 * Malloc an array of row pointers
650 	 */
651 	copy = (Pixel **) XtMalloc(mw->matrix.rows * sizeof(Pixel *));
652 
653 	/*
654 	 * Malloc an array of Pixels for each row pointer
655 	 */
656 	for (i = 0; i < mw->matrix.rows; i++)
657 	    copy[i] = (Pixel *) XtMalloc(mw->matrix.columns * sizeof(Pixel));
658 
659 	if (!mw->matrix.cell_background)
660 	{
661 	    for (i = 0; i < mw->matrix.rows; i++)
662 	    {
663 		Boolean alt = (mw->matrix.alt_row_count &&
664 			       i >= (int)mw->matrix.fixed_rows) ? (
665 				   ((i - (int)mw->matrix.fixed_rows) /
666 				    mw->matrix.alt_row_count) % 2) : False;
667 
668 		/*
669 		 * Assign the even and odd row colours appropriately.  These
670 		 * will be a copy of the core->background if they have not
671 		 * been explicitly set but if they have, we want to
672 		 * preserve the colours as they appear now
673 		 */
674 		for (j = 0; j < mw->matrix.columns; j++)
675 		    copy[i][j] = (alt ? mw->matrix.odd_row_background :
676 				  mw->matrix.even_row_background);
677 	    }
678 	}
679 	else for (i = 0; i < mw->matrix.rows; i++)
680 	{
681 	    if (!badrow && !mw->matrix.cell_background[i]) {
682 		badrow = True;
683 		XtAppWarningMsg(
684 		    XtWidgetToApplicationContext((Widget)mw),
685 		    "copyCellColors", "tooShort",
686 		    "XbaeMatrix",
687 		    "XbaeMatrix: Cell BackgroundPixelTable is too short",
688 		    NULL, 0);
689 	    }
690 	    badcol = badrow;
691 	    for (j = 0; j < mw->matrix.columns; j++)
692 	    {
693 		if (badcol || mw->matrix.cell_background[i][j] == BAD_PIXEL)
694 		{
695 		    badcol = True;
696 		    if (j > 0)
697 			copy[i][j] = copy[i][j-1] ;
698 		    else if (i > 0)
699 			copy[i][j] = copy[i-1][j] ;
700 		    else
701 			copy[i][j] = mw->core.background_pixel;
702 		}
703 		else
704 		{
705 		    copy[i][j] = mw->matrix.cell_background[i][j];
706 		}
707 	    }
708 	}
709     }
710     mw->matrix.cell_background = copy;
711 }
712 
713 /*
714  * Copy the selectedCells resource. Create a 2D array of Booleans to
715  * represent selected cells if it is NULL.
716  */
717 void
xbaeCopySelectedCells(mw)718 xbaeCopySelectedCells(mw)
719 XbaeMatrixWidget mw;
720 {
721     Boolean **copy = NULL;
722     int i, j;
723 
724     if (mw->matrix.rows && mw->matrix.columns)
725     {
726 	/*
727 	 * Malloc an array of row pointers
728 	 */
729 	mw->matrix.num_selected_cells = 0;
730 	copy = (Boolean **) XtMalloc(mw->matrix.rows * sizeof(Boolean *));
731 
732 	/*
733 	 * Malloc an array of Booleans for each row pointer
734 	 */
735 	for (i = 0; i < mw->matrix.rows; i++)
736 	    copy[i] = (Boolean *) XtCalloc(mw->matrix.columns,
737 					   sizeof(Boolean));
738 
739 	/*
740 	 * If selected_cells is not NULL, copy the table passed in
741 	 */
742 	if (mw->matrix.selected_cells)
743 	    for (i = 0; i < mw->matrix.rows; i++)
744 		for (j = 0; j < mw->matrix.columns; j++)
745 		{
746 		    copy[i][j] = mw->matrix.selected_cells[i][j];
747 		    if (mw->matrix.selected_cells[i][j])
748 			mw->matrix.num_selected_cells++;
749 		}
750     }
751     mw->matrix.selected_cells = copy;
752 }
753 
754 #if XmVersion >= 1002
755 /*
756  * Copy the highlightedCells resource. Create a 2D array of Booleans to
757  * represent highlighted cells if it is NULL.
758  */
759 void
xbaeCopyHighlightedCells(mw)760 xbaeCopyHighlightedCells(mw)
761 XbaeMatrixWidget mw;
762 {
763     unsigned char **copy = NULL;
764     int i, j;
765 
766     if (mw->matrix.rows && mw->matrix.columns)
767     {
768 	/*
769 	 * Malloc an array of row pointers
770 	 */
771 	copy = (unsigned char **) XtMalloc(mw->matrix.rows *
772 					   sizeof(Boolean *));
773 
774 	/*
775 	 * Malloc an array of Booleans for each row pointer
776 	 */
777 	for (i = 0; i < mw->matrix.rows; i++)
778 	    copy[i] = (unsigned char *) XtCalloc(mw->matrix.columns,
779 						 sizeof(Boolean));
780 
781 	/*
782 	 * If highlighted_cells is not NULL, copy the table passed in
783 	 */
784 	if (mw->matrix.highlighted_cells)
785 	    for (i = 0; i < mw->matrix.rows; i++)
786 		for (j = 0; j < mw->matrix.columns; j++)
787 		    copy[i][j] = mw->matrix.highlighted_cells[i][j];
788     }
789     mw->matrix.highlighted_cells = copy;
790 }
791 #endif
792 
793 /*
794  * Create a matrix of Pixels
795  */
796 void
xbaeCreateColors(mw)797 xbaeCreateColors(mw)
798 XbaeMatrixWidget mw;
799 {
800     int i;
801 
802     if (mw->matrix.rows && mw->matrix.columns)
803     {
804 	/*
805 	 * Malloc an array of row pointers
806 	 */
807 	mw->matrix.colors = (Pixel **) XtMalloc(mw->matrix.rows *
808 						sizeof(Pixel *));
809 
810 	/*
811 	 * Malloc an array of Pixels for each row pointer
812 	 */
813 	for (i = 0; i < mw->matrix.rows; i++)
814 	    mw->matrix.colors[i] = (Pixel *) XtMalloc(mw->matrix.columns *
815 						      sizeof(Pixel));
816     }
817     else
818 	mw->matrix.colors = NULL;
819 }
820 
821 /*
822  * Create a pixmap to be used for drawing the matrix contents when
823  * XmNsensitive is set to False
824  */
825 static Pixmap
createInsensitivePixmap(mw)826 createInsensitivePixmap(mw)
827 XbaeMatrixWidget mw;
828 {
829     static char stippleBits[] = { 0x01, 0x02 };
830     static Pixmap *stipple = NULL;
831     Display *dpy = XtDisplay(mw);
832     Screen *scr  = XtScreen (mw);
833     int i;
834     int maxScreens = ScreenCount(dpy);
835 
836     if (!stipple)
837     {
838 	stipple = (Pixmap *) XtMalloc(maxScreens*sizeof(Pixmap));
839         for (i = 0 ; i < maxScreens ; i++)
840 	    stipple[i] = XCreatePixmapFromBitmapData(
841 		dpy, RootWindow(dpy,i), stippleBits, 2, 2, 0, 1, 1);
842     }
843     for (i = 0; i < maxScreens; i++)
844     {
845 	if (ScreenOfDisplay(dpy, i) == scr)
846 	    return stipple[i];
847     }
848     return (Pixmap)NULL;
849 }
850 
851 void
xbaeCreateGridLineGC(mw)852 xbaeCreateGridLineGC(mw)
853 XbaeMatrixWidget mw;
854 {
855     XGCValues values;
856     XtGCMask mask = GCForeground | GCBackground;
857 
858     values.foreground = mw->matrix.grid_line_color;
859     values.background = mw->manager.foreground;
860 
861     /*
862      * GC for drawing grid lines
863      */
864     mw->matrix.grid_line_gc = XtGetGC((Widget) mw, mask, &values);
865 
866     /*
867      * GC for drawing grid lines with clipping
868      */
869     mw->matrix.cell_grid_line_gc = XCreateGC(XtDisplay(mw),
870 					     GC_PARENT_WINDOW(mw),
871 					     mask, &values);
872 }
873 
874 void
xbaeCreateDrawGC(mw)875 xbaeCreateDrawGC(mw)
876 XbaeMatrixWidget mw;
877 {
878     XGCValues values;
879     unsigned long mask = GCForeground | GCStipple;
880 
881     /*
882      * GC for drawing cells. We create it instead of using a cached one,
883      * since the foreground may change frequently.
884      */
885     values.foreground = mw->manager.foreground;
886     values.stipple = createInsensitivePixmap(mw);
887     /* font id isn't used for fontsets */
888     if (mw->matrix.font_struct) {
889         mask |= GCFont;
890         values.font = mw->matrix.fid;
891     }
892     mw->matrix.draw_gc = XCreateGC(XtDisplay(mw),
893 				   GC_PARENT_WINDOW(mw),
894 				   mask, &values);
895 }
896 
897 void
xbaeCreatePixmapGC(mw)898 xbaeCreatePixmapGC(mw)
899 XbaeMatrixWidget mw;
900 {
901     XGCValues values;
902     unsigned long mask = GCForeground | GCGraphicsExposures | GCStipple;
903 
904     values.foreground = mw->manager.foreground;
905     values.graphics_exposures = False;
906     values.stipple = createInsensitivePixmap(mw);
907 
908     mw->matrix.pixmap_gc = XCreateGC(XtDisplay(mw),
909 				     GC_PARENT_WINDOW(mw),
910 				     mask, &values);
911 }
912 
913 void
xbaeCreateLabelGC(mw)914 xbaeCreateLabelGC(mw)
915 XbaeMatrixWidget mw;
916 {
917     XGCValues values;
918     unsigned long mask = GCForeground | GCStipple;
919 
920     /*
921      * GC for drawing labels
922      */
923     values.foreground = mw->manager.foreground;
924     values.stipple = createInsensitivePixmap(mw);
925     /* font id isn't used for fontsets */
926     if (mw->matrix.label_font_struct) {
927         mask |= GCFont;
928         values.font = mw->matrix.label_fid;
929     }
930     mw->matrix.label_gc = XCreateGC(XtDisplay(mw),
931 				    GC_PARENT_WINDOW(mw),
932 				    mask, &values);
933 }
934 
935 void
xbaeCreateLabelClipGC(mw)936 xbaeCreateLabelClipGC(mw)
937 XbaeMatrixWidget mw;
938 {
939     XGCValues values;
940     unsigned long mask = GCForeground | GCStipple;
941 
942     /*
943      * GC for drawing labels with clipping.
944      */
945     values.foreground = mw->manager.foreground;
946     values.stipple = createInsensitivePixmap(mw);
947     /* font id isn't used for fontsets */
948     if (mw->matrix.label_font_struct) {
949         mask |= GCFont;
950         values.font = mw->matrix.label_fid;
951     }
952     mw->matrix.label_clip_gc = XCreateGC(XtDisplay(mw),
953 					 GC_PARENT_WINDOW(mw),
954 					 mask, &values);
955 }
956 
957 void
xbaeCreateTopShadowClipGC(mw)958 xbaeCreateTopShadowClipGC(mw)
959 XbaeMatrixWidget mw;
960 {
961     XGCValues values;
962     XtGCMask mask = GCForeground | GCBackground;
963 
964     /*
965      * GC for drawing top shadow inside cells with clipping.
966      */
967     values.foreground = mw->manager.top_shadow_color;
968     values.background = mw->manager.foreground;
969 
970     if (mw->manager.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
971     {
972 	mask |= GCFillStyle | GCTile;
973 	values.fill_style = FillTiled;
974 	values.tile = mw->manager.top_shadow_pixmap;
975     }
976     mw->matrix.cell_top_shadow_clip_gc = XCreateGC(
977 	XtDisplay(mw), GC_PARENT_WINDOW(mw), mask, &values);
978 
979     mask |= GCFunction;
980     values.function = GXxor;
981     mw->matrix.resize_top_shadow_gc = XtGetGC(
982 	(Widget) mw, mask, &values);
983 }
984 
985 void
xbaeCreateBottomShadowClipGC(mw)986 xbaeCreateBottomShadowClipGC(mw)
987 XbaeMatrixWidget mw;
988 {
989     XGCValues values;
990     XtGCMask mask = GCForeground | GCBackground;
991 
992     /*
993      * GC for drawing bottom shadow inside cells with clipping.
994      */
995     values.foreground = mw->manager.bottom_shadow_color;
996     values.background = mw->manager.foreground;
997 
998     if (mw->manager.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
999     {
1000 	mask |= GCFillStyle | GCTile;
1001 	values.fill_style = FillTiled;
1002 	values.tile = mw->manager.bottom_shadow_pixmap;
1003     }
1004     mw->matrix.cell_bottom_shadow_clip_gc = XCreateGC(
1005 	XtDisplay(mw), GC_PARENT_WINDOW(mw), mask, &values);
1006 
1007     mask |= GCFunction;
1008     values.function = GXxor;
1009     mw->matrix.resize_bottom_shadow_gc = XtGetGC(
1010 	(Widget) mw, mask, &values);
1011 }
1012 
1013 static short
xbaeGetFontWidth(font_struct)1014 xbaeGetFontWidth(font_struct)
1015 XFontStruct *font_struct;
1016 {
1017     short width;
1018     unsigned long fp;
1019     unsigned char char_idx;
1020 
1021     /*
1022      *  From the XmText man page: If the em-space value is
1023      *  available, it is used. If not, the width of the  numeral  "0"
1024      *  is used. If this is not available, the maximum width is used.
1025      */
1026     if (XGetFontProperty(font_struct, XA_QUAD_WIDTH, &fp) && fp != 0) {
1027         width = (short) fp;
1028     } else {
1029 	if (font_struct->min_char_or_byte2 <= '0' &&
1030 	    font_struct->max_char_or_byte2 >= '0' &&
1031             font_struct->per_char) {
1032 	    char_idx = '0' - font_struct->min_char_or_byte2;
1033             width = font_struct->per_char[char_idx].width;
1034 	} else {
1035 	    width = font_struct->max_bounds.width;
1036         }
1037     }
1038 
1039     /* last safety check */
1040     if (width <= 0) {
1041         width = 1;
1042     }
1043 
1044     return width;
1045 }
1046 
1047 void
xbaeNewFont(mw)1048 xbaeNewFont(mw)
1049 XbaeMatrixWidget mw;
1050 {
1051     XmFontContext context;
1052     XmFontListEntry font_list_entry;
1053     XmFontType type;
1054     XtPointer fontp;
1055 
1056     /*
1057      * Make a private copy of the FontList
1058      */
1059     mw->matrix.font_list = XmFontListCopy(mw->matrix.font_list);
1060 
1061     /*
1062      * Get XmFontListEntry from FontList
1063      */
1064     if (!XmFontListInitFontContext(&context, mw->matrix.font_list))
1065 	XtAppErrorMsg(
1066 	    XtWidgetToApplicationContext((Widget) mw),
1067 	    "newFont", "badFont", "XbaeMatrix",
1068 	    "XbaeMatrix: XmFontListInitFontContext failed, bad fontList",
1069 	    NULL, 0);
1070 
1071     if ((font_list_entry = XmFontListNextEntry(context)) == NULL)
1072 	XtAppErrorMsg(
1073 	    XtWidgetToApplicationContext((Widget) mw),
1074 	    "newFont", "badFont", "XbaeMatrix",
1075 	    "XbaeMatrix: XmFontListNextEntry failed, no next fontList",
1076 	    NULL, 0);
1077 
1078     fontp = XmFontListEntryGetFont(font_list_entry, &type);
1079 
1080 
1081     if (type == XmFONT_IS_FONTSET)
1082     {
1083         XFontSetExtents *extents;
1084 
1085         mw->matrix.font_set = (XFontSet)fontp;
1086 	mw->matrix.font_struct = (XFontStruct*)NULL;
1087 
1088         extents = XExtentsOfFontSet(mw->matrix.font_set);
1089 
1090         mw->matrix.font_width = extents->max_logical_extent.width;
1091         mw->matrix.font_height = extents->max_logical_extent.height;
1092         mw->matrix.font_y = extents->max_logical_extent.y;
1093         mw->matrix.fid  = 0; /* not used for fontsets */
1094     }
1095     else
1096     {
1097         XFontStruct *font_struct = (XFontStruct *)fontp;
1098 
1099         mw->matrix.font_set = (XFontSet)NULL;
1100 	mw->matrix.font_struct = font_struct;
1101 
1102         mw->matrix.font_width  = xbaeGetFontWidth(font_struct);
1103         mw->matrix.font_height = (font_struct->max_bounds.descent +
1104                                   font_struct->max_bounds.ascent);
1105         mw->matrix.font_y = -font_struct->max_bounds.ascent;
1106         mw->matrix.fid  = font_struct->fid;
1107     }
1108 
1109     XmFontListFreeFontContext(context);
1110 }
1111 
1112 void
xbaeNewLabelFont(mw)1113 xbaeNewLabelFont(mw)
1114 XbaeMatrixWidget mw;
1115 {
1116     XmFontContext context;
1117     XmFontListEntry font_list_entry;
1118     XmFontType type;
1119     XtPointer fontp;
1120 
1121     /*
1122      * Make a private copy of the FontList
1123      */
1124     mw->matrix.label_font_list = XmFontListCopy(mw->matrix.label_font_list);
1125 
1126     /*
1127      * Get XmFontListEntry from FontList
1128      */
1129     if (!XmFontListInitFontContext(&context, mw->matrix.label_font_list))
1130 	XtAppErrorMsg(
1131 	    XtWidgetToApplicationContext((Widget) mw),
1132 	    "newFont", "badLabelFont", "XbaeMatrix",
1133 	    "XbaeMatrix: XmFontListInitFontContext failed, bad labelFontList",
1134 	    NULL, 0);
1135 
1136     if ((font_list_entry = XmFontListNextEntry(context)) == NULL)
1137 	XtAppErrorMsg(
1138 	    XtWidgetToApplicationContext((Widget) mw),
1139 	    "newFont", "badLabelFont", "XbaeMatrix",
1140 	    "XbaeMatrix: XmFontListNextEntry failed, no next fontList",
1141 	    NULL, 0);
1142 
1143     fontp = XmFontListEntryGetFont(font_list_entry, &type);
1144 
1145     if (type == XmFONT_IS_FONTSET)
1146     {
1147         XFontSetExtents *extents;
1148 
1149         mw->matrix.label_font_set = (XFontSet)fontp;
1150 	mw->matrix.label_font_struct = (XFontStruct*)NULL;
1151 
1152         extents = XExtentsOfFontSet(mw->matrix.label_font_set);
1153 
1154         mw->matrix.label_font_width = extents->max_logical_extent.width;
1155         mw->matrix.label_font_height = extents->max_logical_extent.height;
1156         mw->matrix.label_font_y = extents->max_logical_extent.y;
1157         mw->matrix.label_fid  = 0; /* not used for fontsets */
1158     }
1159     else
1160     {
1161         XFontStruct *font_struct = (XFontStruct *)fontp;
1162 
1163         mw->matrix.label_font_set = (XFontSet)NULL;
1164 	mw->matrix.label_font_struct = font_struct;
1165 
1166         mw->matrix.label_font_width  = xbaeGetFontWidth(font_struct);
1167         mw->matrix.label_font_height = (font_struct->max_bounds.descent +
1168                                   font_struct->max_bounds.ascent);
1169         mw->matrix.label_font_y = -font_struct->max_bounds.ascent;
1170         mw->matrix.label_fid  = font_struct->fid;
1171     }
1172 
1173     XmFontListFreeFontContext(context);
1174 }
1175 
1176 void
xbaeFreeCells(mw)1177 xbaeFreeCells(mw)
1178 XbaeMatrixWidget mw;
1179 {
1180     int i, j;
1181 
1182     if (!mw->matrix.cells)
1183 	return;
1184 
1185     /*
1186      * Free each cell in a row, then free the row and go to the next one
1187      */
1188     for (i = 0; i < mw->matrix.rows; i++)
1189     {
1190 	for (j = 0; j < mw->matrix.columns; j++)
1191 	    XtFree((XtPointer) mw->matrix.cells[i][j]);
1192 	XtFree((XtPointer) mw->matrix.cells[i]);
1193     }
1194 
1195     /*
1196      * Free the array of row pointers
1197      */
1198     XtFree((XtPointer) mw->matrix.cells);
1199     mw->matrix.cells = NULL;
1200 }
1201 
1202 #if CELL_WIDGETS
1203 void
xbaeFreeCellWidgets(mw)1204 xbaeFreeCellWidgets(mw)
1205 XbaeMatrixWidget mw;
1206 {
1207     int i, j;
1208 
1209     if (!mw->matrix.cell_widgets)
1210 	return;
1211 
1212     /*
1213      * Free each cell in a row, then free the row and go to the next one
1214      */
1215     for (i = 0; i < mw->matrix.rows; i++)
1216     {
1217 	for (j = 0; j < mw->matrix.columns; j++)
1218 	    XtFree((XtPointer) mw->matrix.cell_widgets[i][j]);
1219 	XtFree((XtPointer) mw->matrix.cell_widgets[i]);
1220     }
1221 
1222     /*
1223      * Free the array of row pointers
1224      */
1225     XtFree((XtPointer) mw->matrix.cell_widgets);
1226     mw->matrix.cell_widgets = NULL;
1227 }
1228 #endif
1229 
1230 void
xbaeFreeRowLabels(mw)1231 xbaeFreeRowLabels(mw)
1232 XbaeMatrixWidget mw;
1233 {
1234     int i;
1235 
1236     if (!mw->matrix.row_labels)
1237 	return;
1238 
1239     for (i = 0; i < mw->matrix.rows; i++)
1240 	XtFree((XtPointer) mw->matrix.row_labels[i]);
1241 
1242     XtFree((XtPointer) mw->matrix.row_labels);
1243     mw->matrix.row_labels = NULL;
1244 }
1245 
1246 void
xbaeFreeColumnLabels(mw)1247 xbaeFreeColumnLabels(mw)
1248 XbaeMatrixWidget mw;
1249 {
1250     int i;
1251 
1252     if (!mw->matrix.column_labels)
1253 	return;
1254 
1255     for (i = 0; i < mw->matrix.columns; i++)
1256     {
1257 	XtFree((XtPointer) mw->matrix.column_labels[i]);
1258 	XtFree((XtPointer) mw->matrix.column_label_lines[i].lengths);
1259     }
1260 
1261     XtFree((XtPointer) mw->matrix.column_label_lines);
1262     XtFree((XtPointer) mw->matrix.column_labels);
1263     mw->matrix.column_labels = NULL;
1264 }
1265 
1266 
1267 void
xbaeFreeColors(mw)1268 xbaeFreeColors(mw)
1269 XbaeMatrixWidget mw;
1270 {
1271     int i;
1272 
1273     if (!mw->matrix.colors)
1274 	return;
1275 
1276     /*
1277      * Free each row of Pixels
1278      */
1279     for (i = 0; i < mw->matrix.rows; i++)
1280 	XtFree((XtPointer) mw->matrix.colors[i]);
1281 
1282     /*
1283      * Free the array of row pointers
1284      */
1285     XtFree((XtPointer) mw->matrix.colors);
1286     mw->matrix.colors = NULL;
1287 }
1288 
1289 void
xbaeFreeBackgrounds(mw)1290 xbaeFreeBackgrounds(mw)
1291 XbaeMatrixWidget mw;
1292 {
1293     int i;
1294 
1295     if (!mw->matrix.cell_background)
1296 	return;
1297 
1298     /*
1299      * Free each row of Pixels
1300      */
1301     for (i = 0; i < mw->matrix.rows; i++)
1302 	XtFree((XtPointer) mw->matrix.cell_background[i]);
1303 
1304     /*
1305      * Free the array of row pointers
1306      */
1307     XtFree((XtPointer) mw->matrix.cell_background);
1308     mw->matrix.cell_background = NULL;
1309 }
1310 
1311 void
xbaeFreeSelectedCells(mw)1312 xbaeFreeSelectedCells(mw)
1313 XbaeMatrixWidget mw;
1314 {
1315     int i;
1316 
1317     /*
1318      * Free each row of XtPointer pointers
1319      */
1320     if (!mw->matrix.selected_cells)
1321 	return;
1322 
1323     for (i = 0; i < mw->matrix.rows; i++)
1324 	XtFree((XtPointer) mw->matrix.selected_cells[i]);
1325 
1326     /*
1327      * Free the array of row pointers
1328      */
1329     XtFree((XtPointer) mw->matrix.selected_cells);
1330     mw->matrix.selected_cells = NULL;
1331 }
1332 
1333 #if XmVersion >= 1002
1334 void
xbaeFreeHighlightedCells(mw)1335 xbaeFreeHighlightedCells(mw)
1336 XbaeMatrixWidget mw;
1337 {
1338     int i;
1339 
1340     if (!mw->matrix.highlighted_cells)
1341 	return;
1342 
1343     /*
1344      * Free each row of XtPointer pointers
1345      */
1346     for (i = 0; i < mw->matrix.rows; i++)
1347 	XtFree((XtPointer) mw->matrix.highlighted_cells[i]);
1348 
1349     /*
1350      * Free the array of row pointers
1351      */
1352     XtFree((XtPointer) mw->matrix.highlighted_cells);
1353     mw->matrix.highlighted_cells = NULL;
1354 }
1355 #endif
1356 
1357 void
xbaeFreeCellUserData(mw)1358 xbaeFreeCellUserData(mw)
1359 XbaeMatrixWidget mw;
1360 {
1361     if (mw->matrix.cell_user_data)
1362     {
1363 	int i;
1364 
1365 	/*
1366 	 * Free each row of Booleans
1367 	 */
1368 	for (i = 0; i < mw->matrix.rows; i++)
1369 	    XtFree((XtPointer) mw->matrix.cell_user_data[i]);
1370 
1371 	/*
1372 	 * Free the array of row pointers
1373 	 */
1374 	XtFree((XtPointer) mw->matrix.cell_user_data);
1375     }
1376     mw->matrix.cell_user_data = NULL;
1377 }
1378 
1379 
1380 void
xbaeFreeCellShadowTypes(mw)1381 xbaeFreeCellShadowTypes(mw)
1382 XbaeMatrixWidget mw;
1383 {
1384     if (mw->matrix.cell_shadow_types)
1385     {
1386 	int i;
1387 
1388 	/*
1389 	 * Free each row of unsigned char pointers
1390 	 */
1391 	for (i = 0; i < mw->matrix.rows; i++)
1392 	    XtFree((XtPointer) mw->matrix.cell_shadow_types[i]);
1393 
1394 	/*
1395 	 * Free the array of row pointers
1396 	 */
1397 	XtFree((XtPointer) mw->matrix.cell_shadow_types);
1398     }
1399     mw->matrix.cell_shadow_types = NULL;
1400 }
1401 
1402