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: Matrix.c,v 1.1.2.2 2004/07/02 21:53:02 fnevgeny Exp $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <X11/StringDefs.h>
36 #include <X11/Xlib.h>
37 #include <Xm/XmP.h>
38 #include <Xm/AtomMgr.h>
39 #include <Xm/ScrollBar.h>
40 #include <Xm/TextF.h>
41 #if XmVersion > 1001
42 #include <Xm/DrawP.h>
43 #include <Xm/DragIcon.h>
44 #include <Xm/DragC.h>
45 #endif
46 #include <Xbae/Clip.h>
47 #include <Xbae/MatrixP.h>
48 #include <Xbae/Converters.h>
49 #include <Xbae/ScrollMgr.h>
50 #include <Xbae/Actions.h>
51 #include <Xbae/Create.h>
52 #include <Xbae/Methods.h>
53 #include <Xbae/Utils.h>
54 #include <Xbae/Shadow.h>
55 
56 #ifndef XlibSpecificationRelease
57 #define XrmPermStringToQuark XrmStringToQuark
58 #endif
59 
60 /*
61  * Translations for Matrix (these will also be used by the Clip child).
62  */
63 static char defaultTranslations[] =
64 "<Btn1Up>			:	DefaultAction()\n\
65 <Btn1Down>			:	DefaultAction() EditCell(Pointer)\n\
66 Shift<Btn2Down>			:	ResizeColumns()\n\
67 <Btn2Down>			:	ProcessDrag()\n\
68 <Btn1Motion>			:	HandleMotion()";
69 
70 /*
71  * Default translations for XmNtextTranslations resource
72  */
73 static char default_text_translations[] =
74 "#override\n\
75 Shift ~Ctrl ~Meta ~Alt <Key>Tab	:	EditCell(Left)\n\
76 ~Ctrl ~Meta ~Alt <Key>Tab	:	EditCell(Right)\n\
77 <Key>osfUp			:	EditCell(Up)\n\
78 <Key>osfDown			:	EditCell(Down)\n\
79 <Key>osfActivate		:	CommitEdit(False)\n\
80 ~Shift ~Meta ~Alt <Key>Return	:   	CommitEdit(False)\n\
81 Ctrl <Key>osfCancel		:	CancelEdit(False)\n\
82 Shift Ctrl ~Meta ~Alt <Key>Tab	:	TraversePrev()\n\
83 Ctrl ~Meta ~Alt <Key>Tab	:	TraverseNext()\n\
84 <Key>osfPageDown		:	PageDown()\n\
85 <Key>osfPageUp			:	PageUp()";
86 
87 
88 #define offset(field)	XtOffsetOf(XbaeMatrixRec, field)
89 
90 static XtResource resources[] =
91 {
92 #ifdef ALLOW_COLUMN_RESIZE
93     {XmNallowColumnResize, XmCColumnResize, XmRBoolean, sizeof(Boolean),
94      offset(matrix.allow_column_resize), XmRImmediate, (XtPointer) True},
95 #else
96     {XmNallowColumnResize, XmCColumnResize, XmRBoolean, sizeof(Boolean),
97      offset(matrix.allow_column_resize), XmRImmediate, (XtPointer) False},
98 #endif
99     {XmNaltRowCount, XmCAltRowCount, XmRInt, sizeof(int),
100      offset(matrix.alt_row_count), XmRImmediate, (XtPointer) 1},
101 
102     {XmNboldLabels, XmCBoldLabels, XmRBoolean, sizeof(Boolean),
103      offset(matrix.bold_labels), XmRImmediate, (XtPointer) False},
104 
105     {XmNbuttonLabels, XmCButtonLabels, XmRBoolean, sizeof(Boolean),
106      offset(matrix.button_labels), XmRImmediate, (XtPointer) False},
107 
108     {XmNbuttonLabelBackground, XmCColor, XmRPixel, sizeof(Pixel),
109      offset(matrix.button_label_background), XmRCallProc,
110      (XtPointer)xbaeCopyBackground},
111 
112     {XmNcalcCursorPosition, XmCCalcCursorPosition, XmRBoolean, sizeof(Boolean),
113      offset(matrix.calc_cursor_position), XmRImmediate, (XtPointer) False},
114 
115     {XmNcellBackgrounds, XmCColors, XmRPixelTable, sizeof(Pixel **),
116      offset(matrix.cell_background), XmRImmediate, (XtPointer) NULL},
117 
118     {XmNcellHighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
119      sizeof(Dimension), offset(matrix.cell_highlight_thickness),
120      XmRImmediate, (XtPointer) 2},
121 
122     {XmNcellMarginHeight, XmCMarginHeight, XmRVerticalDimension,
123      sizeof(Dimension), offset(matrix.cell_margin_height),
124      XmRImmediate, (XtPointer) 3},
125 
126     {XmNcellMarginWidth, XmCMarginWidth, XmRHorizontalDimension,
127      sizeof(Dimension), offset(matrix.cell_margin_width),
128      XmRImmediate, (XtPointer) 3},
129 
130     {XmNcellShadowThickness, XmCShadowThickness, XmRDimension,
131      sizeof(Dimension), offset(matrix.cell_shadow_thickness),
132      XmRImmediate, (XtPointer) 1},
133 
134     {XmNcellShadowType, XmCShadowType, XmRShadowType,
135      sizeof(unsigned char), offset(matrix.cell_shadow_type), XmRImmediate,
136      (XtPointer) XmSHADOW_OUT},
137 
138     {XmNcellShadowTypes, XmCCellShadowTypes, XmRShadowTypeTable,
139      sizeof(unsigned char**), offset(matrix.cell_shadow_types), XmRImmediate,
140      (XtPointer) NULL},
141 
142     {XmNcellUserData, XmCCellUserData, XmRUserDataTable,
143       sizeof(XtPointer**), offset(matrix.cell_user_data), XmRImmediate,
144       (XtPointer) NULL},
145 #if CELL_WIDGETS
146     {XmNcellWidgets, XmCCellWidgets, XmRWidgetTable,
147       sizeof(Widget **), offset(matrix.cell_widgets), XmRImmediate,
148       (XtPointer) NULL},
149 #endif
150     {XmNcells, XmCCells, XmRCellTable, sizeof(String **),
151      offset(matrix.cells), XmRImmediate, NULL},
152 
153     {XmNclipWindow, XmCClipWindow, XmRWidget, sizeof(Widget),
154      offset(matrix.clip_window), XmRImmediate, NULL},
155 
156     {XmNcolors, XmCColors, XmRPixelTable, sizeof(Pixel **),
157      offset(matrix.colors), XmRImmediate, (XtPointer) NULL},
158 
159     {XmNcolumnAlignments, XmCAlignments, XmRAlignmentArray,
160      sizeof(unsigned char *), offset(matrix.column_alignments),
161      XmRImmediate, (XtPointer) NULL},
162 
163     {XmNcolumnButtonLabels, XmCButtonLabels, XmRBooleanArray,
164      sizeof(Boolean*), offset(matrix.column_button_labels),
165      XmRImmediate, (XtPointer) NULL},
166 
167     {XmNcolumnLabelAlignments, XmCAlignments, XmRAlignmentArray,
168      sizeof(unsigned char *), offset(matrix.column_label_alignments),
169      XmRImmediate, (XtPointer) NULL},
170 
171     {XmNcolumnLabelColor, XmCColor, XmRPixel, sizeof(Pixel),
172      offset(matrix.column_label_color), XmRCallProc,
173      (XtPointer)xbaeCopyForeground},
174 
175     {XmNcolumnLabels, XmCLabels, XmRStringArray, sizeof(String *),
176      offset(matrix.column_labels), XmRImmediate, NULL},
177 
178     {XmNcolumnMaxLengths, XmCColumnMaxLengths, XmRMaxLengthArray,
179      sizeof(int *), offset(matrix.column_max_lengths),
180      XmRImmediate, NULL},
181 
182     {XmNcolumnShadowTypes, XmCShadowTypes, XmRShadowTypeArray,
183       sizeof(unsigned char*), offset(matrix.column_shadow_types), XmRImmediate,
184       (XtPointer) NULL},
185 
186     {XmNcolumnUserData, XmCUserDatas, XmRUserDataArray,
187       sizeof(XtPointer*), offset(matrix.column_user_data), XmRImmediate,
188       (XtPointer) NULL},
189 
190     {XmNcolumnWidths, XmCColumnWidths, XmRWidthArray, sizeof(short *),
191      offset(matrix.column_widths), XmRImmediate, NULL},
192 
193     {XmNcolumns, XmCColumns, XmRInt, sizeof(int),
194      offset(matrix.columns), XmRImmediate, (XtPointer) 1},
195 
196     {XmNdefaultActionCallback,XmCCallback,XmRCallback,sizeof(XtCallbackList),
197      offset(matrix.default_action_callback),XmRCallback,NULL },
198 
199     {XmNdoubleClickInterval, XmCDoubleClickInterval, XmRInt, sizeof(int),
200      offset(matrix.double_click_interval), XmRCallProc,
201      (XtPointer)xbaeCopyDoubleClick },
202 
203     {XmNdrawCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
204      offset(matrix.draw_cell_callback), XmRCallback, NULL},
205 
206     {XmNenterCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
207      offset(matrix.enter_cell_callback), XmRCallback, NULL},
208 
209     {XmNevenRowBackground, XmCBackground, XmRPixel, sizeof(Pixel),
210      offset(matrix.even_row_background), XmRCallProc,
211      (XtPointer)xbaeCopyBackground},
212 
213     {XmNfill, XmCFill, XmRBoolean, sizeof(Boolean),
214      offset(matrix.fill), XmRImmediate, (XtPointer) False},
215 
216     {XmNfixedColumns, XmCFixedColumns, XmRDimension, sizeof(Dimension),
217      offset(matrix.fixed_columns), XmRImmediate, (XtPointer) 0},
218 
219     {XmNfixedRows, XmCFixedRows, XmRDimension, sizeof(Dimension),
220      offset(matrix.fixed_rows), XmRImmediate, (XtPointer) 0},
221 
222     {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
223      offset(matrix.font_list), XmRString, (XtPointer) "fixed"},
224 
225     {XmNgridLineColor, XmCColor, XmRPixel, sizeof(Pixel),
226      offset(matrix.grid_line_color), XmRCallProc,
227      (XtPointer)xbaeCopyForeground},
228 
229     {XmNgridType, XmCGridType, XmRGridType,
230      sizeof(unsigned char), offset(matrix.grid_type),
231      XmRImmediate, (XtPointer)XmGRID_CELL_LINE},
232 
233 #if XmVersion >= 1002
234     {XmNhighlightedCells, XmCHighlightedCells, XmRHighlightTable,
235      sizeof(unsigned char **), offset(matrix.highlighted_cells),
236      XmRImmediate, (XtPointer) NULL},
237 #endif
238 
239     {XmNhorizontalScrollBar, XmCHorizontalScrollBar, XmRWidget, sizeof(Widget),
240      offset(matrix.horizontal_sb), XmRImmediate, NULL},
241 
242     {XmNhorizontalScrollBarDisplayPolicy, XmCMatrixScrollBarDisplayPolicy,
243      XmRMatrixScrollBarDisplayPolicy, sizeof(unsigned char),
244      offset(matrix.hsb_display_policy), XmRImmediate,
245      (XtPointer) XmDISPLAY_AS_NEEDED},
246 
247     {XmNlabelActivateCallback, XmCCallback, XmRCallback,
248      sizeof(XtCallbackList), offset(matrix.label_activate_callback),
249      XmRCallback, NULL},
250 
251     {XmNlabelFont, XmCFontList, XmRFontList, sizeof(XmFontList),
252      offset(matrix.label_font_list), XmRString, (XtPointer)NULL },
253 
254     {XmNleaveCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
255      offset(matrix.leave_cell_callback), XmRCallback, NULL},
256 
257     {XmNleftColumn, XmCLeftColumn, XmRInt, sizeof(int),
258      offset(matrix.left_column), XmRImmediate, (XtPointer) 0 },
259 
260     {XmNmodifyVerifyCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
261      offset(matrix.modify_verify_callback), XmRCallback, NULL},
262 
263     {XmNoddRowBackground, XmCBackground, XmRPixel, sizeof(Pixel),
264      offset(matrix.odd_row_background), XmRCallProc,
265      (XtPointer)xbaeCopyBackground},
266 
267 #if XmVersion > 1001
268     {XmNprocessDragCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
269      offset(matrix.process_drag_callback), XmRCallback, NULL},
270 #endif
271 
272     /* Resize callback resource. Added by mjs */
273     {XmNresizeCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
274      offset(matrix.resize_callback), XmRCallback, NULL},
275 
276     {XmNresizeColumnCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
277      offset(matrix.resize_column_callback), XmRCallback, NULL},
278 
279     {XmNreverseSelect, XmCReverseSelect, XmRBoolean, sizeof(Boolean),
280      offset(matrix.reverse_select), XmRImmediate, (XtPointer) False},
281 
282     {XmNrowButtonLabels, XmCButtonLabels, XmRBooleanArray,
283      sizeof(Boolean*), offset(matrix.row_button_labels),
284      XmRImmediate, (XtPointer) NULL},
285 
286     {XmNrowLabelAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
287      offset(matrix.row_label_alignment),
288      XmRImmediate, (XtPointer) XmALIGNMENT_END},
289 
290     {XmNrowLabelColor, XmCColor, XmRPixel, sizeof(Pixel),
291      offset(matrix.row_label_color), XmRCallProc,
292      (XtPointer)xbaeCopyForeground },
293 
294     {XmNrowLabelWidth, XmCRowLabelWidth, XmRShort, sizeof(short),
295      offset(matrix.row_label_width), XmRImmediate, (XtPointer) 0},
296 
297     {XmNrowLabels, XmCLabels, XmRStringArray, sizeof(String *),
298      offset(matrix.row_labels), XmRImmediate, NULL},
299 
300     {XmNrowShadowTypes, XmCShadowTypes, XmRShadowTypeArray,
301       sizeof(unsigned char*), offset(matrix.row_shadow_types), XmRImmediate,
302       (XtPointer) NULL},
303 
304     {XmNrowUserData, XmCUserDatas, XmRUserDataArray,
305       sizeof(XtPointer*), offset(matrix.row_user_data), XmRImmediate,
306       (XtPointer) NULL},
307 
308     {XmNrows, XmCRows, XmRInt, sizeof(int),
309      offset(matrix.rows), XmRImmediate, (XtPointer) 1},
310 
311     {XmNscrollBarPlacement, XmCScrollBarPlacement, XmRScrollBarPlacement,
312      sizeof(unsigned char), offset(matrix.scrollbar_placement), XmRImmediate,
313      (XtPointer) XmBOTTOM_RIGHT },
314 
315     {XmNselectCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
316      offset(matrix.select_cell_callback), XmRCallback, NULL},
317 
318     {XmNselectScrollVisible, XmCSelectScrollVisible, XmRBoolean,
319      sizeof(Boolean), offset(matrix.scroll_select), XmRImmediate,
320      (XtPointer) True},
321 
322     {XmNselectedBackground, XmCColor, XmRPixel, sizeof(Pixel),
323      offset(matrix.selected_background), XmRCallProc,
324      (XtPointer)xbaeCopyForeground},
325 
326     {XmNselectedCells, XmCSelectedCells, XmRBooleanTable, sizeof(Boolean **),
327      offset(matrix.selected_cells), XmRImmediate, (XtPointer) NULL},
328 
329     {XmNselectedForeground, XmCColor, XmRPixel, sizeof(Pixel),
330      offset(matrix.selected_foreground), XmRCallProc,
331      (XtPointer)xbaeCopyBackground},
332 
333     {XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy,
334      sizeof(unsigned char), offset(matrix.selection_policy), XmRImmediate,
335      XmSINGLE_SELECT},
336 
337     /* Override Manager default */
338     {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
339      sizeof(Dimension), XtOffsetOf(XmManagerRec, manager.shadow_thickness),
340      XmRImmediate, (XtPointer) 2},
341 
342     {XmNshadowType, XmCShadowType, XmRShadowType,
343      sizeof(unsigned char), offset(matrix.shadow_type), XmRImmediate,
344      (XtPointer) XmSHADOW_IN},
345 
346     {XmNshowArrows, XmCShowArrows, XmRBoolean, sizeof(Boolean),
347      offset(matrix.show_arrows), XmRImmediate, (XtPointer) False},
348 
349     {XmNspace, XmCSpace, XmRHorizontalDimension, sizeof(Dimension),
350      offset(matrix.space), XmRImmediate, (XtPointer) 4},
351 
352     {XmNtextBackground, XmCTextBackground, XmRPixel, sizeof(Pixel),
353      offset(matrix.text_background), XmRCallProc,
354      (XtPointer)xbaeCopyBackground},
355 
356     {XmNtextField, XmCTextField, XmRWidget, sizeof(Widget),
357      offset(matrix.text_field), XmRImmediate, NULL},
358 
359     {XmNtextShadowThickness, XmCTextShadowThickness, XmRDimension,
360      sizeof(Dimension), offset(matrix.text_shadow_thickness), XmRImmediate,
361      (XtPointer) 0},
362 
363     {XmNtextTranslations, XmCTranslations, XmRTranslationTable,
364      sizeof(XtTranslations), offset(matrix.text_translations),
365      XmRString, (XtPointer) default_text_translations},
366 
367     {XmNtopRow, XmCTopRow, XmRInt, sizeof(int),
368      offset(matrix.top_row), XmRImmediate, (XtPointer) 0},
369 
370     {XmNtrailingAttachedBottom, XmCTrailingAttachedBottom, XmRBoolean, sizeof(Boolean),
371      offset(matrix.trailing_attached_bottom), XmRImmediate, (XtPointer) False},
372 
373     {XmNtrailingAttachedRight, XmCTrailingAttachedRight, XmRBoolean, sizeof(Boolean),
374      offset(matrix.trailing_attached_right), XmRImmediate, (XtPointer) False},
375 
376     {XmNtrailingFixedColumns, XmCTrailingFixedColumns, XmRDimension,
377      sizeof(Dimension), offset(matrix.trailing_fixed_columns),
378      XmRImmediate, (XtPointer) 0},
379 
380     {XmNtrailingFixedRows, XmCTrailingFixedRows, XmRDimension,
381      sizeof(Dimension), offset(matrix.trailing_fixed_rows),
382      XmRImmediate, (XtPointer) 0},
383 
384     {XmNtraverseCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
385      offset(matrix.traverse_cell_callback), XmRCallback, NULL},
386 
387     {XmNtraverseFixedCells, XmCTraverseFixedCells, XmRBoolean, sizeof(Boolean),
388      offset(matrix.traverse_fixed), XmRImmediate, (XtPointer) False},
389 
390     {XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget),
391      offset(matrix.vertical_sb), XmRImmediate, NULL},
392 
393     {XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget),
394      offset(matrix.vertical_sb), XmRImmediate, NULL},
395 
396     {XmNverticalScrollBarDisplayPolicy, XmCMatrixScrollBarDisplayPolicy,
397      XmRMatrixScrollBarDisplayPolicy, sizeof(unsigned char),
398      offset(matrix.vsb_display_policy), XmRImmediate,
399      (XtPointer) XmDISPLAY_AS_NEEDED},
400 
401     {XmNvisibleColumns, XmCVisibleColumns, XmRDimension, sizeof(Dimension),
402      offset(matrix.visible_columns), XmRImmediate, (XtPointer) 0},
403 
404     {XmNvisibleRows, XmCVisibleRows, XmRDimension, sizeof(Dimension),
405      offset(matrix.visible_rows), XmRImmediate, (XtPointer) 0},
406 
407     {XmNwriteCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
408      offset(matrix.write_cell_callback), XmRCallback, NULL},
409 
410 };
411 
412 static XmSyntheticResource syn_resources[] =
413 {
414     {XmNcellHighlightThickness, sizeof(Dimension),
415      offset(matrix.cell_highlight_thickness), _XmFromHorizontalPixels,
416      _XmToHorizontalPixels},
417 
418     {XmNcellMarginHeight, sizeof(Dimension), offset(matrix.cell_margin_height),
419      _XmFromVerticalPixels, _XmToVerticalPixels},
420 
421     {XmNcellMarginWidth, sizeof(Dimension), offset(matrix.cell_margin_width),
422      _XmFromHorizontalPixels, _XmToHorizontalPixels},
423 
424     {XmNcellShadowThickness, sizeof(Dimension),
425      offset(matrix.cell_shadow_thickness), _XmFromHorizontalPixels,
426      _XmToHorizontalPixels},
427 
428     {XmNspace, sizeof(Dimension), offset(matrix.space),
429      _XmFromHorizontalPixels, _XmToHorizontalPixels},
430 };
431 
432 #if XmVersion >= 1002
433 static XtIntervalId TraverseID = 0;
434 #endif
435 
436 /*
437  * Declaration of methods
438  */
439 static void ClassInitialize P((void));
440 static void xbaeRegisterConverters P((void));
441 static void ClassPartInitialize P((XbaeMatrixWidgetClass));
442 static void Initialize P((XbaeMatrixWidget, XbaeMatrixWidget, ArgList,
443 			  Cardinal *));
444 static void Realize P((XbaeMatrixWidget, XtValueMask *,
445 		       XSetWindowAttributes *));
446 static void InsertChild P((Widget));
447 static void Redisplay P((Widget, XEvent *, Region));
448 static Boolean SetValues P((XbaeMatrixWidget, XbaeMatrixWidget,
449 			    XbaeMatrixWidget, ArgList, Cardinal *));
450 static void SetValuesAlmost P((XbaeMatrixWidget, XbaeMatrixWidget,
451 			       XtWidgetGeometry *, XtWidgetGeometry *));
452 static void Destroy P((XbaeMatrixWidget));
453 static XtGeometryResult GeometryManager P((Widget, XtWidgetGeometry *,
454 					   XtWidgetGeometry *));
455 static XtGeometryResult QueryGeometry P((XbaeMatrixWidget, XtWidgetGeometry *,
456 					 XtWidgetGeometry *));
457 
458 /*
459  * Redraw function for clip widget
460  */
461 static void ClipRedisplay P((Widget, XEvent *, Region));
462 
463 /*
464  * Private functions unique to Matrix
465  */
466 static void ResizeCells P((XbaeMatrixWidget, XbaeMatrixWidget));
467 static void ResizeSelectedCells P((XbaeMatrixWidget, XbaeMatrixWidget));
468 #if XmVersion >= 1002
469 static void ResizeHighlightedCells P((XbaeMatrixWidget, XbaeMatrixWidget));
470 #endif
471 static void ResizeColors P((XbaeMatrixWidget, XbaeMatrixWidget, Boolean));
472 static void TraverseIn P((XbaeMatrixWidget));
473 
474 #if XmVersion >= 1002
475 static void TraverseInTimeOut P((XtPointer, XtIntervalId *));
476 #endif /* XmVersion >= 1002 */
477 
478 /*
479  * Clip widget focusCallback
480  */
481 static void TraverseInCB P((Widget, XbaeMatrixWidget, XtPointer));
482 
483 /*
484  * Matrix actions
485  */
486 static XtActionsRec actions[] =
487 {
488     {"EditCell",	xbaeEditCellACT},
489     {"CancelEdit",	xbaeCancelEditACT},
490     {"DefaultAction",	xbaeDefaultActionACT},
491     {"CommitEdit",	xbaeCommitEditACT},
492     {"ResizeColumns",	xbaeResizeColumnsACT},
493     {"SelectCell",	xbaeSelectCellACT},
494     {"TraverseNext",	xbaeTraverseNextACT},
495     {"TraversePrev",	xbaeTraversePrevACT},
496     {"ProcessDrag",	xbaeProcessDragACT},
497     {"HandleMotion",	xbaeHandleMotionACT},
498     {"PageDown",	xbaePageDownACT},
499     {"PageUp",		xbaePageUpACT}
500 };
501 
502 
503 static XmBaseClassExtRec BaseClassExtRec = {
504     NULL,					/* next_extension	*/
505     NULLQUARK,					/* record_type		*/
506     XmBaseClassExtVersion,			/* version		*/
507     sizeof(XmBaseClassExtRec),			/* record_size		*/
508     NULL,					/* InitializePrehook	*/
509     NULL,					/* SetValuesPrehook	*/
510     NULL,					/* InitializePosthook	*/
511     NULL,					/* SetValuesPosthook	*/
512     NULL,					/* secondaryObjectClass	*/
513     NULL,					/* secondaryCreate	*/
514     NULL,					/* getSecRes data	*/
515     { 0 },					/* fastSubclass flags	*/
516     NULL,					/* get_values_prehook	*/
517     NULL,					/* get_values_posthook	*/
518     NULL,					/* classPartInitPrehook */
519     NULL,					/* classPartInitPosthook*/
520     NULL,					/* ext_resources	*/
521     NULL,					/* compiled_ext_resources*/
522     0,						/* num_ext_resources	*/
523     FALSE,					/* use_sub_resources	*/
524     XmInheritWidgetNavigable,			/* widgetNavigable	*/
525     XmInheritFocusChange,			/* focusChange		*/
526 };
527 
528 
529 externaldef(xbaematrixclassrec)
530 XbaeMatrixClassRec xbaeMatrixClassRec =
531 {
532     {
533 	/* core_class fields	*/
534 	(WidgetClass) & xmManagerClassRec,	/* superclass		*/
535 	"XbaeMatrix",				/* class_name		*/
536 	sizeof(XbaeMatrixRec),			/* widget_size		*/
537 	ClassInitialize,			/* class_initialize	*/
538 	(XtWidgetClassProc)ClassPartInitialize,	/* class_part_initialize*/
539 	False,					/* class_inited		*/
540 	(XtInitProc)Initialize,			/* initialize		*/
541 	NULL,					/* initialize_hook	*/
542 	(XtRealizeProc)Realize,			/* realize		*/
543 	actions,				/* actions		*/
544 	XtNumber(actions),			/* num_actions		*/
545 	resources,				/* resources		*/
546 	XtNumber(resources),			/* num_resources	*/
547 	NULLQUARK,				/* xrm_class		*/
548 	True,					/* compress_motion	*/
549 	XtExposeCompressMultiple |		/* compress_exposure	*/
550 	XtExposeGraphicsExpose |
551 	XtExposeNoExpose,
552 	True,					/* compress_enterleave	*/
553 	False,					/* visible_interest	*/
554 	(XtWidgetProc)Destroy,			/* destroy		*/
555 	(XtWidgetProc)xbaeResize,		/* resize		*/
556 	(XtExposeProc)Redisplay,		/* expose		*/
557 	(XtSetValuesFunc)SetValues,		/* set_values		*/
558 	NULL,					/* set_values_hook	*/
559 	(XtAlmostProc)SetValuesAlmost,		/* set_values_almost	*/
560 	NULL,					/* get_values_hook	*/
561 	NULL,					/* accept_focus		*/
562 	XtVersionDontCheck,			/* version		*/
563 	NULL,					/* callback_private	*/
564 	defaultTranslations,			/* tm_table		*/
565 	(XtGeometryHandler)QueryGeometry,	/* query_geometry	*/
566 	NULL,					/* display_accelerator	*/
567 	(XtPointer) &BaseClassExtRec		/* extension		*/
568     },
569 
570     {
571 	/* composite_class fields */
572 	GeometryManager,			/* geometry_manager	*/
573 	NULL,					/* change_managed	*/
574 	InsertChild,				/* insert_child		*/
575 	XtInheritDeleteChild,			/* delete_child		*/
576 	NULL,					/* extension		*/
577     },
578     {
579 	/* constraint_class fields */
580 	NULL,					/* resources		*/
581 	0,					/* num_resources	*/
582 	0,					/* constraint_size	*/
583 	NULL,					/* initialize		*/
584 	NULL,					/* destroy		*/
585 	NULL,					/* set_values		*/
586 	NULL					/* extension		*/
587     },
588     {
589 	/* manager_class fields */
590 	XtInheritTranslations,			/* translations		*/
591 	syn_resources,				/* syn_resources	*/
592 	XtNumber(syn_resources),		/* num_syn_resources	*/
593 	NULL,				    /* syn_constraint_resources	*/
594 	0,				    /* num_syn_constraint_resources */
595 	XmInheritParentProcess,			/* parent_process	*/
596 	NULL					/* extension		*/
597     },
598     {
599 	/* matrix_class fields */
600 	xbaeSetCell,				/* set_cell		*/
601 	xbaeGetCell,				/* get_cell		*/
602 	xbaeEditCell,				/* edit_cell		*/
603 	xbaeSelectCell,				/* select_cell		*/
604 	xbaeSelectRow,				/* select_row		*/
605 	xbaeSelectColumn,			/* select_column	*/
606 	xbaeDeselectAll,			/* deselect_all		*/
607 	xbaeSelectAll,				/* select_all		*/
608 	xbaeDeselectCell,			/* deselect_cell	*/
609 	xbaeDeselectRow,			/* deselect_row		*/
610 	xbaeDeselectColumn,			/* deselect_column	*/
611 	xbaeCommitEdit,				/* commit_edit		*/
612 	xbaeCancelEdit,				/* cancel_edit		*/
613 	xbaeAddRows,				/* add_rows		*/
614 	xbaeDeleteRows,				/* delete_rows		*/
615 	xbaeAddColumns,				/* add_columns		*/
616 	xbaeDeleteColumns,			/* delete_columns	*/
617 	xbaeSetRowColors,			/* set_row_colors	*/
618 	xbaeSetColumnColors,			/* set_column_colors	*/
619 	xbaeSetCellColor,			/* set_cell_color	*/
620 	NULL,					/* extension		*/
621     }
622 };
623 
624 externaldef(xbaematrixwidgetclass)
625 WidgetClass xbaeMatrixWidgetClass = (WidgetClass) & xbaeMatrixClassRec;
626 
627 static XtConvertArgRec convertArg[] = {
628     {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.screen),
629      sizeof(Screen *)},
630     {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.colormap),
631      sizeof(Colormap)}
632 };
633 
634 static void
xbaeRegisterConverters()635 xbaeRegisterConverters()
636 {
637     /*
638      * String to StringArray is used for XmNrowLabels and XmNcolumnLabels
639      * We make a private copy of this table
640      */
641     XtSetTypeConverter(XmRString, XmRStringArray,
642 		       CvtStringToStringArray, NULL, 0,
643 		       XtCacheAll | XtCacheRefCount,
644 		       StringArrayDestructor);
645 
646     /*
647      * String to String2DArray is used for XmNcells resource
648      * We make a private copy of this table
649      */
650     XtSetTypeConverter(XmRString, XmRCellTable,
651 		       CvtStringToCellTable, NULL, 0,
652 		       XtCacheNone,
653 		       StringCellDestructor);
654 
655     /*
656      * String to ShortArray is used for XmNcolumnWidths resource.
657      * We make a private copy of this table
658      */
659     XtSetTypeConverter(XmRString, XmRWidthArray,
660 		       CvtStringToWidthArray, NULL, 0,
661 		       XtCacheAll | XtCacheRefCount,
662 		       WidthArrayDestructor);
663 
664     /*
665      * String to IntArray is used for XmNcolumnMaxLengths resource.
666      * We make a private copy of this table
667      */
668     XtSetTypeConverter(XmRString, XmRMaxLengthArray,
669 		       CvtStringToMaxLengthArray, NULL, 0,
670 		       XtCacheAll | XtCacheRefCount,
671 		       MaxLengthArrayDestructor);
672 
673     /*
674      * String to PixelTable is used for XmNcolors
675      * and XmNcellBackgrounds resources.
676      */
677     XtSetTypeConverter(XmRString, XmRPixelTable,
678 		       CvtStringToPixelTable,convertArg, XtNumber(convertArg),
679 		       XtCacheNone,
680 		       PixelTableDestructor);
681     /*
682      * String to BooleanArray is used for XmNcolumnButtonLabels and
683      * XmNrowButtonLabels resources.
684      */
685     XtSetTypeConverter(XmRString, XmRBooleanArray,
686 		       CvtStringToBooleanArray, NULL, 0,
687 		       XtCacheAll | XtCacheRefCount,
688 		       BooleanArrayDestructor);
689 
690     /*
691      * String to AlignmentArray is used for XmNcolumnAlignments
692      * and XmNcolumnLabelAlignments resources.
693      */
694     XtSetTypeConverter(XmRString, XmRAlignmentArray,
695 		       CvtStringToAlignmentArray, NULL, 0,
696 		       XtCacheAll | XtCacheRefCount,
697 		       AlignmentArrayDestructor);
698 
699     /*
700      * String to grid type is used for XmNgridType
701      */
702     XtSetTypeConverter(XmRString, XmRGridType,
703 		       CvtStringToGridType, NULL, 0,
704 		       XtCacheAll, NULL);
705 
706     /*
707      * String to matrix display policy is used for
708      * XmN{vertical,horizontal}ScrollBarDisplayPolicy
709      */
710     XtSetTypeConverter(XmRString, XmRMatrixScrollBarDisplayPolicy,
711 #ifdef __VMS
712 		       CvtStringToMatrixScrollBarDisp,
713 #else
714 		       CvtStringToMatrixScrollBarDisplayPolicy,
715 #endif
716 		       NULL, 0, XtCacheAll, NULL);
717 }
718 
719 static void
ClassInitialize()720 ClassInitialize()
721 {
722     xbaeRegisterConverters();
723 }
724 
725 static void
ClassPartInitialize(mwc)726 ClassPartInitialize(mwc)
727 XbaeMatrixWidgetClass mwc;
728 {
729     register XbaeMatrixWidgetClass super =
730 	(XbaeMatrixWidgetClass) mwc->core_class.superclass;
731 
732     /*
733      * Allow subclasses to inherit new Matrix methods
734      */
735     if (mwc->matrix_class.set_cell == XbaeInheritSetCell)
736 	mwc->matrix_class.set_cell = super->matrix_class.set_cell;
737     if (mwc->matrix_class.get_cell == XbaeInheritGetCell)
738 	mwc->matrix_class.get_cell = super->matrix_class.get_cell;
739     if (mwc->matrix_class.edit_cell == XbaeInheritEditCell)
740 	mwc->matrix_class.edit_cell = super->matrix_class.edit_cell;
741     if (mwc->matrix_class.select_cell == XbaeInheritSelectCell)
742 	mwc->matrix_class.select_cell = super->matrix_class.select_cell;
743     if (mwc->matrix_class.select_row == XbaeInheritSelectRow)
744 	mwc->matrix_class.select_row = super->matrix_class.select_row;
745     if (mwc->matrix_class.select_column == XbaeInheritSelectColumn)
746 	mwc->matrix_class.select_column = super->matrix_class.select_column;
747     if (mwc->matrix_class.deselect_all == XbaeInheritDeselectAll)
748 	mwc->matrix_class.deselect_all = super->matrix_class.deselect_all;
749     if (mwc->matrix_class.select_all == XbaeInheritSelectAll)
750 	mwc->matrix_class.select_all = super->matrix_class.select_all;
751     if (mwc->matrix_class.deselect_cell == XbaeInheritDeselectCell)
752 	mwc->matrix_class.deselect_cell = super->matrix_class.deselect_cell;
753     if (mwc->matrix_class.deselect_row == XbaeInheritDeselectRow)
754 	mwc->matrix_class.deselect_row = super->matrix_class.deselect_row;
755     if (mwc->matrix_class.deselect_column == XbaeInheritDeselectColumn)
756 	mwc->matrix_class.deselect_column =
757 	    super->matrix_class.deselect_column;
758     if (mwc->matrix_class.commit_edit == XbaeInheritCommitEdit)
759 	mwc->matrix_class.commit_edit = super->matrix_class.commit_edit;
760     if (mwc->matrix_class.cancel_edit == XbaeInheritCancelEdit)
761 	mwc->matrix_class.cancel_edit = super->matrix_class.cancel_edit;
762     if (mwc->matrix_class.add_rows == XbaeInheritAddRows)
763 	mwc->matrix_class.add_rows = super->matrix_class.add_rows;
764     if (mwc->matrix_class.delete_rows == XbaeInheritDeleteRows)
765 	mwc->matrix_class.delete_rows = super->matrix_class.delete_rows;
766     if (mwc->matrix_class.add_columns == XbaeInheritAddColumns)
767 	mwc->matrix_class.add_columns = super->matrix_class.add_columns;
768     if (mwc->matrix_class.delete_columns == XbaeInheritDeleteColumns)
769 	mwc->matrix_class.delete_columns = super->matrix_class.delete_columns;
770     if (mwc->matrix_class.set_row_colors == XbaeInheritSetRowColors)
771 	mwc->matrix_class.set_row_colors = super->matrix_class.set_row_colors;
772     if (mwc->matrix_class.set_column_colors == XbaeInheritSetColumnColors)
773 	mwc->matrix_class.set_column_colors =
774 	    super->matrix_class.set_column_colors;
775     if (mwc->matrix_class.set_cell_color == XbaeInheritSetCellColor)
776 	mwc->matrix_class.set_cell_color = super->matrix_class.set_cell_color;
777 }
778 
779 
780 #ifdef NEED_24BIT_VISUAL
781 static Widget
get_shell_ancestor(w)782 get_shell_ancestor(w)
783 Widget w;
784 {
785     Widget sh;
786 
787     for (sh=w ; !XtIsShell(sh) ; sh=XtParent(sh))
788 	;
789 }
790 #endif
791 
792 /*
793  * Callbacks for our scrollbars.
794  */
795 static XtCallbackRec VSCallback[] =
796 {
797     {(XtCallbackProc) xbaeScrollVertCB, (XtPointer) NULL},
798     {(XtCallbackProc) NULL, NULL}
799 };
800 static XtCallbackRec HSCallback[] =
801 {
802     {(XtCallbackProc) xbaeScrollHorizCB, (XtPointer) NULL},
803     {(XtCallbackProc) NULL, NULL}
804 };
805 
806 /* ARGSUSED */
807 static void
Initialize(request,new,args,num_args)808 Initialize(request, new, args, num_args)
809 XbaeMatrixWidget request, new;
810 ArgList args;
811 Cardinal *num_args;
812 {
813     Dimension marginHeight;
814 
815     /*
816      * Initialize redisplay counters
817      */
818     new->matrix.disable_redisplay = 0;
819     new->matrix.first_row_offset = 0;
820 
821 #if XmVersion >= 1002
822     /*
823      * Initialize highlight location
824      */
825     new->matrix.highlight_location = HighlightNone;
826 #endif
827 
828     /*
829      * Check rows/cols set by resources for consistency/validity
830      */
831     if (new->matrix.rows < 0 || new->matrix.columns < 0)
832     {
833 	XtAppWarningMsg(
834 	    XtWidgetToApplicationContext((Widget) new),
835 	    "initialize", "badSize", "XbaeMatrix",
836 	    "XbaeMatrix: Number of rows or columns is less than zero",
837 	    (String *) NULL, (Cardinal *) NULL);
838 	if (new->matrix.rows < 0)
839 	    new->matrix.rows = 0;
840 	if (new->matrix.columns < 0)
841 	    new->matrix.columns = 0;
842     }
843 
844     /*
845      * Make sure column_widths were specified.  If not, use a default value.
846      * This should keep the XDesigner users happy....
847      */
848     if (new->matrix.columns && (new->matrix.column_widths == NULL))
849     {
850 	int i;
851 
852 	new->matrix.column_widths = (short*)XtMalloc(new->matrix.columns *
853 						     sizeof(short));
854 	for (i = 0; i < new->matrix.columns; i++)
855 	    new->matrix.column_widths[i] = 5;
856 
857     }
858 
859     /* If no label font is specified, copy the default fontList, but if
860        we do then override the bold_labels resource */
861     if (!new->matrix.label_font_list)
862 	new->matrix.label_font_list = XmFontListCopy(new->matrix.font_list);
863     else
864 	new->matrix.bold_labels = False;
865 
866     /*
867      * We must have at least one non-fixed row/column. Only complain if there
868      * are some to complain about, though. We may have none at all (yet).
869      */
870     if ((int)(new->matrix.fixed_rows +
871 	      new->matrix.trailing_fixed_rows) > 0 &&
872        	(int)(new->matrix.fixed_rows +
873 	      new->matrix.trailing_fixed_rows) >= new->matrix.rows)
874     {
875         XtAppWarningMsg(XtWidgetToApplicationContext((Widget) new),
876 			 "initialize", "tooManyFixed", "XbaeMatrix",
877 			 "XbaeMatrix: At least one row must not be fixed",
878 			 NULL, 0);
879         new->matrix.fixed_rows = 0;
880         new->matrix.trailing_fixed_rows = 0;
881     }
882     if ((int)(new->matrix.fixed_columns +
883 	      new->matrix.trailing_fixed_columns) > 0 &&
884 	(int)(new->matrix.fixed_columns +
885 	      new->matrix.trailing_fixed_columns) >= new->matrix.columns)
886     {
887         XtAppWarningMsg(XtWidgetToApplicationContext((Widget) new),
888 			 "initialize", "tooManyFixed", "XbaeMatrix",
889 			 "XbaeMatrix: At least one column must not be fixed",
890 			 NULL, 0);
891         new->matrix.fixed_columns = 0;
892         new->matrix.trailing_fixed_columns = 0;
893     }
894     /*
895      * We can't have too many visible columns
896      */
897     if (new->matrix.columns && ((int)new->matrix.visible_columns >
898 	(new->matrix.columns - (int)new->matrix.fixed_columns -
899 	(int)new->matrix.trailing_fixed_columns)))
900     {
901 	XtAppWarningMsg(
902 	    XtWidgetToApplicationContext((Widget) new),
903 	    "initialize", "tooManyVisibleColumns", "XbaeMatrix",
904 	    "XbaeMatrix: visibleColumns must not be greater than\n            (columns - fixedColumns - trailingFixedColumns)",
905 	    (String *) NULL, (Cardinal *) NULL);
906 	new->matrix.visible_columns = 0;
907     }
908 
909     if (new->matrix.grid_type >= XmGRID_LINE)
910 	/* Deprecated types. To be removed in next version. */
911 	XtAppWarningMsg(
912 	    XtWidgetToApplicationContext((Widget) new),
913 	    "cvtStringToGridType", "deprecatedType",
914 	    "XbaeMatrix",
915 	    "Value for GridType is deprecated and will be removed in next release",
916 	    NULL, NULL);
917 
918     /*
919      * Copy the pointed to resources.
920      * If cells is NULL, we create an array of "" strings.
921      */
922     if (new->matrix.cells)
923 	xbaeCopyCells(new);
924     if (new->matrix.row_labels)
925 	xbaeCopyRowLabels(new);
926     if (new->matrix.column_labels)
927 	xbaeCopyColumnLabels(new);
928     else
929     {
930 	new->matrix.column_label_lines = NULL;
931 	new->matrix.column_label_maxlines = 0;
932     }
933 
934     xbaeCopyColumnWidths(new);
935 
936     if (new->matrix.cell_shadow_types)
937 	xbaeCopyCellShadowTypes(new);
938     if (new->matrix.row_shadow_types)
939 	xbaeCopyRowShadowTypes(new);
940     if (new->matrix.column_shadow_types)
941 	xbaeCopyColumnShadowTypes(new);
942 
943     if (new->matrix.cell_user_data)
944 	xbaeCopyCellUserData(new);
945     if (new->matrix.row_user_data)
946 	xbaeCopyRowUserData(new);
947     if (new->matrix.column_user_data)
948 	xbaeCopyColumnUserData(new);
949 
950 #if CELL_WIDGETS
951     if (new->matrix.cell_widgets)
952 	xbaeCopyCellWidgets(new);
953 #endif
954 
955     if (new->matrix.column_max_lengths)
956 	xbaeCopyColumnMaxLengths(new);
957 
958     if (new->matrix.column_alignments)
959 	xbaeCopyColumnAlignments(new);
960 
961     if (new->matrix.column_button_labels)
962 	xbaeCopyColumnButtonLabels(new);
963 
964     if (new->matrix.column_label_alignments)
965 	xbaeCopyColumnLabelAlignments(new);
966 
967     if (new->matrix.colors)
968 	xbaeCopyColors(new);
969 
970     if (new->matrix.cell_background)
971   	xbaeCopyBackgrounds(new);
972 
973     if (new->matrix.selected_cells)
974 	xbaeCopySelectedCells(new);
975 
976 #if XmVersion >= 1002
977     if (new->matrix.highlighted_cells)
978 	xbaeCopyHighlightedCells(new);
979 #endif
980 
981     if (new->matrix.row_button_labels)
982 	xbaeCopyRowButtonLabels(new);
983 
984     /*
985      * If user didn't specify a rowLabelWidth, then calculate one based on
986      * the widest label
987      */
988     if (new->matrix.row_label_width == 0 && new->matrix.row_labels)
989 	new->matrix.row_label_width = xbaeMaxRowLabel(new);
990 
991     /*
992      * Copy the fontList. Get fontStruct from fontList.
993      */
994     xbaeNewFont(new);
995     xbaeNewLabelFont(new);
996 
997     /*
998      * Create our 4 children (SBs and textField are unmanaged for now)
999      * they must be created in this order so our macros work
1000      * (horiz scroll, vert scroll and then clip and textField).
1001      * We scroll horizontally by pixels, vertically by rows.
1002      */
1003     new->matrix.horizontal_sb = XtVaCreateWidget(
1004 	"horizScroll", xmScrollBarWidgetClass, (Widget) new,
1005 	XmNorientation, XmHORIZONTAL,
1006 	XmNdragCallback, HSCallback,
1007 	XmNvalueChangedCallback, HSCallback,
1008 	XmNincrement, FONT_WIDTH(new),
1009 	XmNsliderSize, 1,
1010 	XmNminimum, 0,
1011 	XmNmaximum, 1,
1012 	XmNbackground, new->core.background_pixel,
1013 	XmNforeground, new->manager.foreground,
1014 	XmNbottomShadowColor, new->manager.bottom_shadow_color,
1015 	XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap,
1016 	XmNhighlightColor, new->manager.highlight_color,
1017 	XmNhighlightPixmap, new->manager.highlight_pixmap,
1018 	XmNtopShadowColor, new->manager.top_shadow_color,
1019 	XmNtopShadowPixmap, new->manager.top_shadow_pixmap,
1020 	NULL);
1021 
1022     HORIZ_ORIGIN(new) = 0;
1023 
1024     new->matrix.vertical_sb = XtVaCreateWidget(
1025 	"vertScroll", xmScrollBarWidgetClass, (Widget) new,
1026 	XmNorientation, XmVERTICAL,
1027 	XmNdragCallback, VSCallback,
1028 	XmNvalueChangedCallback, VSCallback,
1029 	XmNincrement, 1,
1030 	XmNminimum, 0,
1031 	XmNmaximum, new->matrix.rows ?
1032 		(new->matrix.rows - (int) new->matrix.fixed_rows -
1033 		(int) new->matrix.trailing_fixed_rows) : 1,
1034 	XmNsliderSize, 1,
1035 	XmNbackground, new->core.background_pixel,
1036 	XmNforeground, new->manager.foreground,
1037 	XmNbottomShadowColor, new->manager.bottom_shadow_color,
1038 	XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap,
1039 	XmNhighlightColor, new->manager.highlight_color,
1040 	XmNhighlightPixmap, new->manager.highlight_pixmap,
1041 	XmNtopShadowColor, new->manager.top_shadow_color,
1042 	XmNtopShadowPixmap, new->manager.top_shadow_pixmap,
1043 	NULL);
1044 
1045     /*
1046      * Create the Clip widget managed so we can use it for traversal
1047      */
1048     new->matrix.clip_window = XtVaCreateManagedWidget(
1049 	"clip", xbaeClipWidgetClass, (Widget) new,
1050 	XmNexposeProc, ClipRedisplay,
1051 	XmNtraversalOn, new->manager.traversal_on,
1052 	XmNbackground, new->core.background_pixel,
1053 	NULL);
1054 
1055     /*
1056      * Add a callback to the Clip widget so we know when it gets the focus
1057      * and can use it in traversal.
1058      */
1059     XtAddCallback(ClipChild(new), XmNfocusCallback,
1060 		  (XtCallbackProc)TraverseInCB, (XtPointer) new);
1061 
1062     /*
1063      * Calculate an imaginary cellMarginHeight based on the largest of
1064      * the label and cell font.  If the font for the labels is bigger,
1065      * the cellMarginHeight needs to be increased to allow the cell font
1066      * to still appear centrally placed
1067      */
1068     if (LABEL_HEIGHT(new) > FONT_HEIGHT(new))
1069 	marginHeight = (int)(LABEL_HEIGHT(new) +
1070 			     (new->matrix.cell_margin_height *
1071 			      2) - FONT_HEIGHT(new)) / 2;
1072     else
1073 	marginHeight = new->matrix.cell_margin_height;
1074 
1075     /*
1076      * Create text field (unmanaged for now) - its window will be reparented
1077      * in Realize to be a subwindow of Clip
1078      *
1079      * Set the shadow thickness to 0 to prevent a shadow drawn inside the
1080      * highlight region.  The shadow thickness is used to draw the shadows
1081      * *around* the highlight
1082      */
1083 
1084     new->matrix.text_field = XtVaCreateWidget(
1085 	"textField", xmTextFieldWidgetClass, (Widget) new,
1086 	XmNmarginWidth, new->matrix.cell_margin_width,
1087 	XmNmarginHeight, marginHeight,
1088 	XmNtranslations, new->matrix.text_translations,
1089 	XmNfontList, new->matrix.font_list,
1090 	XmNshadowThickness, new->matrix.text_shadow_thickness,
1091 	XmNbackground, new->matrix.text_background,
1092 	XmNforeground, new->manager.foreground,
1093 	XmNbottomShadowColor, new->manager.bottom_shadow_color,
1094 	XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap,
1095 	XmNhighlightThickness, new->matrix.cell_highlight_thickness,
1096 	XmNhighlightColor, new->manager.highlight_color,
1097 	XmNhighlightPixmap, new->manager.highlight_pixmap,
1098 	XmNeditMode, XmSINGLE_LINE_EDIT,
1099 	NULL);
1100 
1101     XtAddCallback(TextChild(new), XmNmodifyVerifyCallback, xbaeModifyVerifyCB,
1102 		  (XtPointer) new);
1103 
1104     /* Add a handler on top of the text field to handle clicks on it */
1105     XtAddEventHandler(TextChild(new), ButtonPressMask | ButtonReleaseMask,
1106 		      True, (XtEventHandler)xbaeHandleClick, (XtPointer)new);
1107     XtAddEventHandler((Widget)new, ButtonPressMask | ButtonReleaseMask,
1108 		      True, (XtEventHandler)xbaeHandleClick, (XtPointer)new);
1109 
1110     /*
1111      * Compute cell text baseline based on TextField widget
1112      */
1113     new->matrix.text_baseline = XmTextGetBaseline(TextChild(new)) +
1114 	new->matrix.cell_shadow_thickness;
1115 
1116     /*
1117      * Adjust the label_baseline according to the larger of the two fonts
1118      */
1119     if (LABEL_HEIGHT(new) == FONT_HEIGHT(new))
1120 	new->matrix.label_baseline = new->matrix.text_baseline;
1121     else
1122     {
1123 	if (LABEL_HEIGHT(new) < FONT_HEIGHT(new))
1124 	    marginHeight = (int)(FONT_HEIGHT(new) +
1125 				 new->matrix.text_shadow_thickness * 2 +
1126 				 new->matrix.cell_margin_height * 2 -
1127 				 LABEL_HEIGHT(new)) / 2;
1128 	else
1129 	    marginHeight = new->matrix.cell_margin_height +
1130 		new->matrix.text_shadow_thickness;
1131 
1132 	new->matrix.label_baseline = marginHeight +
1133 	    new->matrix.cell_shadow_thickness -
1134 	    new->matrix.label_font_y;
1135     }
1136     /*
1137      * Calculate total pixel width of cell area
1138      */
1139     xbaeGetCellTotalWidth(new);
1140 
1141     /*
1142      * Make the clips for the fixed cells which are scrollable (i.e. the
1143      * fixed rows that can scroll horizontally, and the fixed columns which
1144      * can scroll vertically. This makes 4 scrollable fixed-cell areas.
1145      */
1146     new->matrix.left_clip = XtVaCreateWidget(
1147 	"leftclip", xbaeClipWidgetClass, (Widget) new,
1148 	XmNexposeProc, Redisplay,
1149 	XmNtraversalOn, new->manager.traversal_on,
1150 	XmNbackground, new->core.background_pixel,
1151 	NULL);
1152     new->matrix.right_clip = XtVaCreateWidget(
1153 	"rightclip", xbaeClipWidgetClass, (Widget) new,
1154 	XmNexposeProc, Redisplay,
1155 	XmNtraversalOn, new->manager.traversal_on,
1156 	XmNbackground, new->core.background_pixel,
1157 	NULL);
1158     new->matrix.top_clip = XtVaCreateWidget(
1159 	"topclip", xbaeClipWidgetClass, (Widget) new,
1160 	XmNexposeProc, Redisplay,
1161 	XmNtraversalOn, new->manager.traversal_on,
1162 	XmNbackground, new->core.background_pixel,
1163 	NULL);
1164     new->matrix.bottom_clip = XtVaCreateWidget(
1165 	"bottomclip", xbaeClipWidgetClass, (Widget) new,
1166 	XmNexposeProc, Redisplay,
1167 	XmNtraversalOn, new->manager.traversal_on,
1168 	XmNbackground, new->core.background_pixel,
1169 	NULL);
1170     /*
1171      * Cache the pixel position of each column
1172      */
1173     new->matrix.column_positions = CreateColumnPositions(new);
1174     xbaeGetColumnPositions(new);
1175 
1176     /*
1177      * Now we can set the VSB maximum (relies on data from
1178      * GetCellTotalWidth above)
1179      */
1180     XtVaSetValues(HorizScrollChild(new),
1181 		  XmNmaximum, NON_FIXED_TOTAL_WIDTH(new) ?
1182 		  NON_FIXED_TOTAL_WIDTH(new) : 1,
1183 		  NULL);
1184 
1185     /*
1186      * Current position starts at the top left editable cell.
1187      */
1188     new->matrix.current_row = new->matrix.fixed_rows;
1189     new->matrix.current_column = new->matrix.fixed_columns;
1190 
1191     new->matrix.current_clip = CLIP_NONE;
1192 
1193     /*
1194      * We aren't trying to traverse out
1195      */
1196     new->matrix.traversing = NOT_TRAVERSING;
1197 
1198 #ifndef NEED_24BIT_VISUAL
1199     /*
1200      * Get/create our GCs
1201      */
1202     xbaeCreateDrawGC(new);
1203     xbaeCreatePixmapGC(new);
1204     xbaeCreateLabelGC(new);
1205     xbaeCreateLabelClipGC(new);
1206     xbaeCreateGridLineGC(new);
1207     xbaeCreateTopShadowClipGC(new);
1208     xbaeCreateBottomShadowClipGC(new);
1209 #endif
1210 
1211     /*
1212      * Now we have created our GCs, check if the widget is sensitive
1213      */
1214     if (!new->core.sensitive)
1215     {
1216 	XGCValues values;
1217 	unsigned long valuemask = GCFillStyle;
1218 	Display *dpy = XtDisplay(new);
1219 
1220 	if (!new->core.sensitive)
1221 	{
1222 	    int i;
1223 
1224 	    values.fill_style = FillStippled;
1225 
1226 	    /*
1227 	     * Change our drawing GC's to the stipple effect to indicate
1228 	     * the widget is insensitive and redraw
1229 	     */
1230 	    XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values);
1231 	    XChangeGC(dpy, new->matrix.label_gc, valuemask, &values);
1232 	    XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values);
1233 	    XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values);
1234 	    /*
1235 	     * Propogate the insensitive feel to our children
1236 	     */
1237 	    for (i = 0; i < XbaeNumChildren; i++)
1238 		XtSetSensitive(new->composite.children[i], False);
1239 	}
1240     }
1241 
1242     /*
1243      * Create ScrollMgrs to manage scrolling events
1244      */
1245     new->matrix.matrix_scroll_mgr = xbaeSmCreateScrollMgr();
1246     new->matrix.clip_scroll_mgr = xbaeSmCreateScrollMgr();
1247 
1248     /*
1249      * Set the last row and column to an impossible value
1250      */
1251     new->matrix.last_row = -1;
1252     new->matrix.last_column = -1;
1253     new->matrix.last_click_time = (Time)0;
1254 
1255     /*
1256      * Compute our size.  If either dimension was explicitly set to 0,
1257      * then that dimension is computed.
1258      * Use request because superclasses modify width/height.
1259      */
1260     if (request->core.width == 0 || request->core.height == 0)
1261 	xbaeComputeSize(new, request->core.width == 0,
1262 			request->core.height == 0);
1263 
1264     /*
1265      * Make sure top_row is sensible before we call Resize
1266      */
1267     if (VERT_ORIGIN(new) < 0)
1268 	VERT_ORIGIN(new) = 0;
1269     else if (VERT_ORIGIN(new) > new->matrix.rows)
1270 	VERT_ORIGIN(new) = new->matrix.rows;
1271 
1272     /*
1273      * Tweak top_row to make sure it is valid before calling Resize
1274      */
1275     if (VERT_ORIGIN(new))
1276 	xbaeAdjustTopRow(new);
1277 
1278     if (new->matrix.left_column)
1279 	xbaeAdjustLeftColumn(new);
1280 
1281     /*
1282      * Layout the scrollbars and clip widget based on our size
1283      */
1284     xbaeResize(new);
1285 }
1286 
1287 static void
Realize(mw,valueMask,attributes)1288 Realize(mw, valueMask, attributes)
1289 XbaeMatrixWidget mw;
1290 XtValueMask *valueMask;
1291 XSetWindowAttributes *attributes;
1292 {
1293     *valueMask |= CWDontPropagate;
1294     attributes->do_not_propagate_mask =
1295 	ButtonPressMask | ButtonReleaseMask |
1296 	KeyPressMask | KeyReleaseMask | PointerMotionMask;
1297 
1298     /*
1299      * Don't call our superclasses realize method, because Manager sets
1300      * bit_gravity
1301      */
1302     XtCreateWindow((Widget) mw, InputOutput, CopyFromParent,
1303 		   *valueMask, attributes);
1304 
1305 #ifdef NEED_24BIT_VISUAL
1306     /*
1307      * Now that we have a window...
1308      * Get/create our GCs
1309      */
1310     xbaeCreateDrawGC(mw);
1311     xbaeCreatePixmapGC(mw);
1312     xbaeCreateLabelGC(mw);
1313     xbaeCreateLabelClipGC(mw);
1314     xbaeCreateTopShadowClipGC(mw);
1315     xbaeCreateBottomShadowClipGC(mw);
1316 #endif
1317 
1318     /*
1319      * Reparent the textFields window to be a subwindow of Clip widget
1320      * (we need to realize them first)
1321      */
1322     XtRealizeWidget(TextChild(mw));
1323     XtRealizeWidget(ClipChild(mw));
1324     XtRealizeWidget(LeftClip(mw));
1325     XtRealizeWidget(RightClip(mw));
1326     XtRealizeWidget(TopClip(mw));
1327     XtRealizeWidget(BottomClip(mw));
1328     XReparentWindow(XtDisplay(mw), XtWindow(TextChild(mw)),
1329 		    XtWindow(ClipChild(mw)),
1330 		    TextChild(mw)->core.x, TextChild(mw)->core.y);
1331     mw->matrix.current_parent = ClipChild(mw);
1332     /*
1333      * Set the clip_mask in our clipping GCs.
1334      */
1335     xbaeSetClipMask(mw, CLIP_NONE);
1336 }
1337 
1338 static void
InsertChild(w)1339 InsertChild(w)
1340 Widget w;
1341 {
1342 #if 0
1343     if (((CompositeWidget) XtParent(w))->composite.num_children > 7)
1344     {
1345 #if XmVersion > 1001
1346 	/* Hah! Cannot use XmIsDragIconObjectClass because it is defined
1347 	 * using XtIsSubclass() (at least in the 1.2 and 2.0 headers I have
1348 	 * available to me). Nothing like a little QA, huh.
1349 	 *
1350 	 * Anyways, since the drag icon & context are created as widget
1351 	 * children of the matrix, we need to allow just those extra types
1352 	 * to be created as our kids.
1353 	 */
1354 	if ((!XmIsDragContext(w)) && (!XtIsSubclass(w, xmDragIconObjectClass)))
1355 	{
1356 #endif
1357 	    String params[1];
1358 	    Cardinal num_params = 1;
1359 
1360 	    params[0] = XtClass(XtParent(w))->core_class.class_name;
1361 	    XtAppWarningMsg(
1362 		XtWidgetToApplicationContext(w),
1363 		"insertChild", "badChild", "XbaeMatrix",
1364 		"XbaeMatrix: Applications cannot add children to %s widgets",
1365 		params, &num_params);
1366 #if XmVersion > 1001
1367 	}
1368 #endif
1369 	return;
1370     }
1371 #endif
1372 #if XmVersion > 1001
1373     (*((XmManagerWidgetClass)
1374        (xbaeMatrixWidgetClass->core_class.superclass))->composite_class.insert_child) (w);
1375 #endif
1376 }
1377 
1378 /*
1379  * This is the expose method for the Matrix widget.
1380  * It redraws the row and column labels, the cells in fixed rows and columns
1381  * and the clip window shadow.
1382  */
1383 /* ARGSUSED */
1384 static void
Redisplay(w,event,region)1385 Redisplay(w, event, region)
1386 Widget w;
1387 XEvent *event;
1388 Region region;
1389 {
1390     Rectangle expose;
1391     XbaeMatrixWidget mw;
1392 
1393     if (XtIsSubclass(w, xbaeMatrixWidgetClass))
1394 	mw = (XbaeMatrixWidget) w;
1395     else	/* must be one of the clips */
1396     {
1397 	int *x = NULL, *y = NULL;
1398 
1399 	mw = (XbaeMatrixWidget) XtParent(w);
1400 	/* point at the correct x,y pair */
1401 	switch (event->type)
1402 	{
1403 	    case Expose:
1404 		x = &event->xexpose.x;
1405 		y = &event->xexpose.y;
1406 		break;
1407 
1408 	    case GraphicsExpose:
1409 		x = &event->xgraphicsexpose.x;
1410 		y = &event->xgraphicsexpose.y;
1411 		break;
1412 
1413 	    case NoExpose:
1414 		break;
1415 
1416 	    default:
1417 		return;
1418 	}
1419 
1420 	/* NoExpose event can't be translated so make sure x is set */
1421 	if (x)
1422 	{
1423 	    /*
1424 	     * Translate expose event coords into matrix coords if it occured
1425 	     * on a clip. xbaeRedrawLabelsAndFixed needs to check intersections
1426 	     * in matrix coords, even though the xbaeDraw* routines will
1427 	     * correctly retranslate these onto the correct windows for drawing.
1428 	     */
1429 	    if (w == LeftClip(mw))
1430 	    {
1431 		*x += ROW_LABEL_WIDTH(mw) + mw->manager.shadow_thickness;
1432 		*y += FIXED_ROW_LABEL_OFFSET(mw);
1433 	    }
1434 	    else if (w == RightClip(mw))
1435 	    {
1436 		*x += TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw);
1437 		*y += FIXED_ROW_LABEL_OFFSET(mw);
1438 	    }
1439 	    else if (w == TopClip(mw))
1440 	    {
1441 		*x += FIXED_COLUMN_LABEL_OFFSET(mw);
1442 		*y += (COLUMN_LABEL_HEIGHT(mw) + mw->manager.shadow_thickness);
1443 	    }
1444 	    else if (w == BottomClip(mw))
1445 	    {
1446 		*x += FIXED_COLUMN_LABEL_OFFSET(mw);
1447 		*y += TRAILING_FIXED_ROW_LABEL_OFFSET(mw);
1448 	    }
1449 	    else
1450 		return;	/* eek! Run away quickly */
1451 	}
1452     }
1453 
1454     if (mw->matrix.disable_redisplay)
1455 	return;
1456 
1457     /*
1458      * Send our events to the mw ScrollMgr to be adjusted.
1459      */
1460     switch (event->type)
1461     {
1462 
1463     case Expose:
1464 	/*
1465 	 * The Expose event will be translated into our scrolled
1466 	 * coordinate system.  Then it is put in a Rectangle.
1467 	 */
1468 	xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event);
1469 	SETRECT(expose,
1470 		event->xexpose.x, event->xexpose.y,
1471 		event->xexpose.x + event->xexpose.width,
1472 		event->xexpose.y + event->xexpose.height);
1473 	break;
1474 
1475     case GraphicsExpose:
1476 	/*
1477 	 * The GraphicsExpose event will cause a scroll to be removed
1478 	 * from the managers queue, then the event will be translated
1479 	 * into our scrolled coordinate system.	 Then it is put in a Rectangle.
1480 	 */
1481 	xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event);
1482 	SETRECT(expose,
1483 		event->xgraphicsexpose.x, event->xgraphicsexpose.y,
1484 		event->xgraphicsexpose.x + event->xgraphicsexpose.width,
1485 		event->xgraphicsexpose.y + event->xgraphicsexpose.height);
1486 	break;
1487 
1488     case NoExpose:
1489 	/*
1490 	 * The NoExpose event means we won't be getting any GraphicsExpose
1491 	 * events, so the scroll will be removed from the queue and
1492 	 * we are done.
1493 	 */
1494 	xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event);
1495 	return;
1496 
1497     default:	/* maybe handled above already */
1498 	return;
1499     }
1500 
1501     /*
1502      * Redraw the row/column labels and fixed rows/columns which are
1503      * overlapped by the expose Rectangle.
1504      */
1505     if ((! mw->matrix.trailing_fixed_columns) &&
1506 	 IN_GRID_ROW_MODE(mw) && NEED_HORIZ_FILL(mw))
1507     {
1508 	Rectangle nonfixed;
1509 
1510 	/*
1511 	 * We need to ensure that the last column of cells gets
1512 	 * redrawn so that the fill is properly redrawn.
1513 	 */
1514 	SETRECT(nonfixed,
1515 		COLUMN_POSITION(mw, mw->matrix.columns-1), 0,
1516 		COLUMN_POSITION(mw, mw->matrix.columns-1)+1,
1517 		ClipChild(mw)->core.height-1);
1518 
1519 	xbaeRedrawCells(mw, &nonfixed);
1520     }
1521     else if ((! mw->matrix.trailing_fixed_rows) &&
1522 	      IN_GRID_COLUMN_MODE(mw) && NEED_VERT_FILL(mw))
1523     {
1524 	Rectangle nonfixed;
1525 
1526 	/*
1527 	 * We need to ensure that the last row of cells gets
1528 	 * redrawn so that the fill is properly redrawn.
1529 	 */
1530 	SETRECT(nonfixed,
1531 		0, ROW_HEIGHT(mw) * (mw->matrix.rows - 1),
1532 		ClipChild(mw)->core.width-1,
1533 		ROW_HEIGHT(mw) * mw->matrix.rows);
1534 
1535 	xbaeRedrawCells(mw, &nonfixed);
1536     }
1537 
1538     xbaeRedrawLabelsAndFixed(mw, &expose);
1539 }
1540 
1541 /*
1542  * This is the exposeProc function for the Clip widget.
1543  * It handles expose events for the Clip widget by redrawing those
1544  * non-fixed cells which were damaged.
1545  * It receives Expose, GraphicsExpose and NoExpose events.
1546  */
1547 /* ARGSUSED */
1548 static void
ClipRedisplay(w,event,region)1549 ClipRedisplay(w, event, region)
1550 Widget w;
1551 XEvent *event;
1552 Region region;
1553 {
1554     XbaeMatrixWidget mw = (XbaeMatrixWidget) XtParent(w);
1555     Rectangle expose, clip, intersect;
1556 
1557     if (mw->matrix.disable_redisplay)
1558 	return;
1559 
1560     /*
1561      * Send our events to the clip ScrollMgr to be adjusted.
1562      */
1563     switch (event->type)
1564     {
1565 
1566     case Expose:
1567 	/*
1568 	 * The Expose event will be translated into our scrolled
1569 	 * coordinate system.  Then it is put in a Rectangle.
1570 	 */
1571 	xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event);
1572 	SETRECT(expose,
1573 		event->xexpose.x, event->xexpose.y,
1574 		event->xexpose.x + event->xexpose.width - 1,
1575 		event->xexpose.y + event->xexpose.height - 1);
1576 	break;
1577 
1578     case GraphicsExpose:
1579 	/*
1580 	 * The GraphicsExpose event will cause a scroll to be removed
1581 	 * from the managers queue, then the event will be translated
1582 	 * into our scrolled coordinate system.	 Then it is put in a Rectangle.
1583 	 */
1584 	xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event);
1585 	SETRECT(expose,
1586 		event->xgraphicsexpose.x, event->xgraphicsexpose.y,
1587 		event->xgraphicsexpose.x + event->xgraphicsexpose.width - 1,
1588 		event->xgraphicsexpose.y + event->xgraphicsexpose.height - 1);
1589 	break;
1590 
1591     case NoExpose:
1592 	/*
1593 	 * The NoExpose event means we won't be getting any GraphicsExpose
1594 	 * events, so the scroll well be removed from the queue and
1595 	 * we are done.
1596 	 */
1597 	xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event);
1598 	return;
1599 
1600     default:
1601 	return;
1602     }
1603 
1604     /*
1605      * We may get an expose event larger than the size of the Clip widget.
1606      * This is because in set_values we may clear the Clip widget
1607      * before it gets resized smaller (maybe in set_values_almost).
1608      * So here we intersect the expose event with the clip widget
1609      * to ensure the expose Rectangle is not larger than the Clip widget.
1610      */
1611     SETRECT(clip,
1612 	    0, 0,
1613 	    w->core.width - 1, w->core.height - 1);
1614     INTERSECT(clip, expose, intersect);
1615 
1616     /*
1617      * Redraw those cells which overlap the intersect Rectangle.
1618      */
1619     xbaeRedrawCells(mw, &intersect);
1620 }
1621 
1622 
1623 /* ARGSUSED */
1624 static Boolean
SetValues(current,request,new,args,num_args)1625 SetValues(current, request, new, args, num_args)
1626 XbaeMatrixWidget current, request, new;
1627 ArgList args;
1628 Cardinal *num_args;
1629 {
1630     Boolean redisplay = False;	/* need to redraw */
1631     Boolean relayout = False;	/* need to layout, but same size */
1632     Boolean new_column_widths = False;	/* column widths changed */
1633     Boolean new_cells = False;	/* cells changed */
1634     Boolean do_top_row = False;	/* reset top_row */
1635     Boolean do_left_column = False;     /* reset left_column */
1636     int n;
1637     Arg wargs[9];
1638 
1639 #define NE(field)	(current->field != new->field)
1640 #define EQ(field)	(current->field == new->field)
1641 
1642     /*
1643      * We cannot re-set either of the scrollbars, the textField or
1644      * clip window.
1645      */
1646     if (NE(matrix.vertical_sb) || NE(matrix.horizontal_sb) ||
1647 	NE(matrix.clip_window) || NE(matrix.text_field))
1648     {
1649 	XtAppWarningMsg(
1650 	    XtWidgetToApplicationContext((Widget) new),
1651 	    "setValues", "set matrix children", "XbaeMatrix",
1652 	    "XbaeMatrix: Cannot set matrix widget children",
1653 	    NULL, 0);
1654 	new->matrix.vertical_sb = current->matrix.vertical_sb;
1655 	new->matrix.horizontal_sb = current->matrix.horizontal_sb;
1656 	new->matrix.clip_window = current->matrix.clip_window;
1657 	new->matrix.text_field = current->matrix.text_field;
1658     }
1659 
1660     /*
1661      * If rows changed, then:
1662      *	row_labels must change or be NULL
1663      *	row_button_labels must change or be NULL
1664      */
1665     if ((NE(matrix.rows) && (new->matrix.row_labels &&
1666 			     EQ(matrix.row_labels))) ||
1667 	(new->matrix.row_button_labels &&
1668 	 EQ(matrix.row_button_labels)))
1669     {
1670 	XtAppWarningMsg(
1671 	    XtWidgetToApplicationContext((Widget) new),
1672 	    "setValues", "rows", "XbaeMatrix",
1673 	    "XbaeMatrix: Number of rows changed but dependent resources did not",
1674 	    NULL, 0);
1675 	new->matrix.rows = current->matrix.rows;
1676 	new->matrix.row_labels = current->matrix.row_labels;
1677 	new->matrix.row_button_labels = current->matrix.row_button_labels;
1678     }
1679 
1680     /*
1681      * If columns changed, then:
1682      *	column_widths must change
1683      *	column_max_lengths must change or be NULL
1684      *	column_labels must change or be NULL
1685      *	column_alignments must change or be NULL
1686      *	column_button_labels must change or be NULL
1687      *	column_label_alignments must change or be NULL
1688      */
1689     if (NE(matrix.columns) &&
1690 	((new->matrix.column_labels && EQ(matrix.column_labels)) ||
1691 	 (new->matrix.column_max_lengths && EQ(matrix.column_max_lengths)) ||
1692 	 (new->matrix.column_alignments && EQ(matrix.column_alignments)) ||
1693 	 (new->matrix.column_button_labels &&
1694 	  EQ(matrix.column_button_labels)) ||
1695 	 (new->matrix.column_label_alignments &&
1696 	  EQ(matrix.column_label_alignments)) ||
1697 	 EQ(matrix.column_widths)))
1698     {
1699 	XtAppWarningMsg(
1700 	    XtWidgetToApplicationContext((Widget) new),
1701 	    "setValues", "columns", "XbaeMatrix",
1702 	    "XbaeMatrix: Number of columns changed but dependent resources did not",
1703 	    NULL, 0);
1704 	new->matrix.columns = current->matrix.columns;
1705 	new->matrix.column_widths = current->matrix.column_widths;
1706 	new->matrix.column_max_lengths = current->matrix.column_max_lengths;
1707 	new->matrix.column_labels = current->matrix.column_labels;
1708 	new->matrix.column_alignments = current->matrix.column_alignments;
1709 	new->matrix.column_button_labels =
1710 	    current->matrix.column_button_labels;
1711 	new->matrix.column_label_alignments =
1712 	    current->matrix.column_label_alignments;
1713     }
1714 
1715     /*
1716      * Make sure we have at least one row/column.
1717      */
1718     if (new->matrix.columns < 0 || new->matrix.rows < 0)
1719     {
1720 	XtAppWarningMsg(
1721 	    XtWidgetToApplicationContext((Widget) new),
1722 	    "setValues", "size", "XbaeMatrix",
1723 	    "XbaeMatrix: Must have at least one row and column",
1724 	    NULL, 0);
1725 	if (new->matrix.columns < 0)
1726 	    new->matrix.columns = current->matrix.columns;
1727 	if (new->matrix.rows < 0)
1728 	    new->matrix.rows = current->matrix.rows;
1729     }
1730 
1731 
1732     /*
1733      * We must have at least one non-fixed row/column.
1734      * This could be caused by (trailing) fixed_rows/columns or
1735      * rows/columns changing.
1736      */
1737     if ((int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) > 0 &&
1738 	(int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) >=
1739         new->matrix.rows)
1740     {
1741         XtAppWarningMsg(
1742             XtWidgetToApplicationContext((Widget) new),
1743             "setValues", "tooManyFixed", "XbaeMatrix",
1744             "XbaeMatrix: At least one row must not be fixed",
1745             NULL, 0);
1746 
1747         if (NE(matrix.fixed_rows))
1748             new->matrix.fixed_rows = current->matrix.fixed_rows;
1749         if (NE(matrix.trailing_fixed_rows))
1750             new->matrix.trailing_fixed_rows =
1751 		current->matrix.trailing_fixed_rows;
1752         if (NE(matrix.rows))
1753             new->matrix.rows = current->matrix.rows;
1754     }
1755     if ((int)(new->matrix.fixed_columns +
1756 	      new->matrix.trailing_fixed_columns) > 0 &&
1757 	(int)(new->matrix.fixed_columns +
1758 	      new->matrix.trailing_fixed_columns) >= new->matrix.columns)
1759     {
1760         XtAppWarningMsg(
1761             XtWidgetToApplicationContext((Widget) new),
1762             "setValues", "tooManyFixed", "XbaeMatrix",
1763             "XbaeMatrix: At least one column must not be fixed",
1764             NULL, 0);
1765 
1766         if (NE(matrix.fixed_columns))
1767             new->matrix.fixed_columns = current->matrix.fixed_columns;
1768         if (NE(matrix.trailing_fixed_columns))
1769             new->matrix.trailing_fixed_columns =
1770 		current->matrix.trailing_fixed_columns;
1771         if (NE(matrix.columns))
1772             new->matrix.columns = current->matrix.columns;
1773     }
1774 
1775     /*
1776      * We can't have too many visible columns.
1777      * This could be caused by visible_columns or columns or fixed_columns
1778      * changing.
1779      */
1780     if (new->matrix.columns && ((int)new->matrix.visible_columns >
1781 	(new->matrix.columns - (int)new->matrix.fixed_columns -
1782 	 (int)new->matrix.trailing_fixed_columns)))
1783     {
1784 	XtAppWarningMsg(
1785 	    XtWidgetToApplicationContext((Widget) new),
1786 	    "setValues", "tooManyVisibleColumns", "XbaeMatrix",
1787 	    "XbaeMatrix: visibleColumns must not be greater than\n            (columns - fixedColumns - trailingFixedColumns)",
1788 	    (String *) NULL, (Cardinal *) NULL);
1789 	if (NE(matrix.visible_columns))
1790 	    new->matrix.visible_columns = current->matrix.visible_columns;
1791 	if (NE(matrix.columns))
1792 	    new->matrix.columns = current->matrix.columns;
1793 	if (NE(matrix.fixed_columns))
1794 	    new->matrix.fixed_columns = current->matrix.fixed_columns;
1795 	if (NE(matrix.trailing_fixed_columns))
1796 	    new->matrix.trailing_fixed_columns =
1797 		current->matrix.trailing_fixed_columns;
1798     }
1799 
1800     /*
1801      * Make sure we have column_widths
1802      */
1803     if (new->matrix.columns && (new->matrix.column_widths == NULL))
1804     {
1805 	XtAppWarningMsg(
1806 	    XtWidgetToApplicationContext((Widget) new),
1807 	    "setValues", "columnWidths", "XbaeMatrix",
1808 	    "XbaeMatrix: Must specify columnWidths",
1809 	    NULL, 0);
1810 	new->matrix.column_widths = current->matrix.column_widths;
1811     }
1812 
1813 
1814     /*
1815      * If rows or columns or fixed rows/columns changed,
1816      * then we need to relayout.
1817      */
1818     if (NE(matrix.rows) || NE(matrix.fixed_rows) ||
1819 	NE(matrix.trailing_fixed_rows))
1820     {
1821 	/*
1822 	 * Reset VSB maximum. sliderSize will be reset later in Resize.
1823 	 */
1824 	XtVaSetValues(VertScrollChild(new),
1825 		      XmNmaximum, (new->matrix.rows -
1826 				   (int) new->matrix.fixed_rows -
1827 				   (int) new->matrix.trailing_fixed_rows),
1828 		      XmNsliderSize, 1,
1829 		      NULL);
1830 	do_top_row = True;
1831 	relayout = True;
1832     }
1833 
1834     if (NE(matrix.columns) || NE(matrix.fixed_columns) ||
1835 	NE(matrix.trailing_fixed_columns))
1836 	relayout = True;
1837 
1838     /*
1839      * Copy any pointed to resources if they changed
1840      */
1841 
1842 #if CELL_WIDGETS
1843     if (NE(matrix.cell_widgets))
1844     {
1845 	xbaeFreeCellWidgets(current);
1846 	xbaeCopyCellWidgets(current);
1847 	redisplay = True;
1848     }
1849 #endif
1850 
1851     if (NE(matrix.cells))
1852     {
1853 	xbaeFreeCells(current);
1854 	xbaeCopyCells(new);
1855 	redisplay = True;
1856 	new_cells = True;
1857     }
1858     else if (NE(matrix.rows) || NE(matrix.columns))
1859 	ResizeCells(current, new);
1860 
1861     if (NE(matrix.cell_user_data))
1862     {
1863 	xbaeFreeCellUserData(current);
1864 	if (new->matrix.cell_user_data)
1865 	    xbaeCopyCellUserData(new);
1866     }
1867     if (NE(matrix.row_user_data))
1868     {
1869 	xbaeFreeRowUserData(current);
1870 	if (new->matrix.row_user_data)
1871 	    xbaeCopyRowUserData(new);
1872     }
1873     if (NE(matrix.column_user_data))
1874     {
1875 	xbaeFreeColumnUserData(current);
1876 	if (new->matrix.column_user_data)
1877 	    xbaeCopyColumnUserData(new);
1878     }
1879     if (NE(matrix.cell_shadow_types))
1880     {
1881 	xbaeFreeCellShadowTypes(current);
1882 	if (new->matrix.cell_shadow_types)
1883 	    xbaeCopyCellShadowTypes(new);
1884     }
1885     if (NE(matrix.row_shadow_types))
1886     {
1887 	xbaeFreeRowShadowTypes(current);
1888 	if (new->matrix.row_shadow_types)
1889 	    xbaeCopyRowShadowTypes(new);
1890     }
1891     if (NE(matrix.column_shadow_types))
1892     {
1893 	xbaeFreeColumnShadowTypes(current);
1894 	if (new->matrix.column_shadow_types)
1895 	    xbaeCopyColumnShadowTypes(new);
1896     }
1897 
1898     if (NE(matrix.row_labels))
1899     {
1900 	/*
1901 	 * If we added or deleted row_labels, we need to layout.
1902 	 */
1903 	if (!current->matrix.row_labels || !new->matrix.row_labels)
1904 	    relayout = True;
1905 	else
1906 	    redisplay = True;
1907 
1908 	xbaeFreeRowLabels(current);
1909 	if (new->matrix.row_labels)
1910 	    xbaeCopyRowLabels(new);
1911     }
1912     if (NE(matrix.column_labels))
1913     {
1914 	xbaeFreeColumnLabels(current);
1915 	if (new->matrix.column_labels)
1916 	    xbaeCopyColumnLabels(new);
1917 	else
1918 	{
1919 	    new->matrix.column_label_lines = NULL;
1920 	    new->matrix.column_label_maxlines = 0;
1921 	}
1922 
1923 	/*
1924 	 * If the number of lines in column labels changed, we need to relayout
1925 	 */
1926 	if (current->matrix.column_label_maxlines !=
1927 	    new->matrix.column_label_maxlines)
1928 	    relayout = True;
1929 	else
1930 	    redisplay = True;
1931     }
1932     if (NE(matrix.column_max_lengths))
1933     {
1934 	xbaeFreeColumnMaxLengths(current);
1935 	if (new->matrix.column_max_lengths)
1936 	    xbaeCopyColumnMaxLengths(new);
1937 	redisplay = True;
1938     }
1939     if (NE(matrix.column_alignments))
1940     {
1941 	xbaeFreeColumnAlignments(current);
1942 	if (new->matrix.column_alignments)
1943 	    xbaeCopyColumnAlignments(new);
1944 	redisplay = True;
1945     }
1946     if (NE(matrix.column_button_labels))
1947     {
1948 	xbaeFreeColumnButtonLabels(current);
1949 	if (new->matrix.column_button_labels)
1950 	    xbaeCopyColumnButtonLabels(new);
1951 	redisplay = True;
1952     }
1953     if (NE(matrix.row_button_labels))
1954     {
1955 	xbaeFreeRowButtonLabels(current);
1956 	if (new->matrix.row_button_labels)
1957 	    xbaeCopyRowButtonLabels(new);
1958 	redisplay = True;
1959     }
1960     if (NE(matrix.column_label_alignments))
1961     {
1962 	xbaeFreeColumnLabelAlignments(current);
1963 	if (new->matrix.column_label_alignments)
1964 	    xbaeCopyColumnLabelAlignments(new);
1965 	redisplay = True;
1966     }
1967     if (NE(matrix.row_label_alignment))
1968 	redisplay = True;
1969     if (NE(matrix.row_label_color) || NE(matrix.column_label_color) ||
1970 	NE(matrix.button_label_background))
1971 	redisplay = True;
1972 
1973     if (NE(matrix.colors))
1974     {
1975 	xbaeFreeColors(current);
1976 	if (new->matrix.colors)
1977 	    xbaeCopyColors(new);
1978 	redisplay = True;
1979     }
1980     if (NE(matrix.cell_background))
1981     {
1982 	xbaeFreeBackgrounds(current);
1983 	if (new->matrix.cell_background)
1984 	    xbaeCopyBackgrounds(new);
1985 	redisplay = True;
1986     }
1987     if (NE(matrix.grid_line_color))
1988     {
1989 	XtReleaseGC((Widget)new, new->matrix.grid_line_gc);
1990 	XFreeGC(XtDisplay(new), new->matrix.cell_grid_line_gc);
1991 	xbaeCreateGridLineGC(new);
1992 	if ((new->matrix.grid_type == XmGRID_CELL_LINE) ||
1993 	    (new->matrix.grid_type == XmGRID_ROW_LINE) ||
1994 	    (new->matrix.grid_type == XmGRID_COLUMN_LINE))
1995 	    redisplay = True;
1996     }
1997 
1998     if (NE(matrix.alt_row_count) &&
1999        (new->matrix.even_row_background != current->core.background_pixel ||
2000        new->matrix.odd_row_background != current->core.background_pixel))
2001 	redisplay = True;
2002 
2003     if (NE(matrix.even_row_background) || NE(matrix.odd_row_background) ||
2004 	NE(matrix.grid_type) || NE(matrix.selected_foreground) ||
2005 	NE(matrix.selected_background))
2006         redisplay = True;
2007 
2008     if (NE(matrix.grid_type) && (new->matrix.grid_type >= XmGRID_LINE))
2009 	/* Deprecated types. To be removed in next version. */
2010 	XtAppWarningMsg(
2011 	    XtWidgetToApplicationContext((Widget) new),
2012 	    "cvtStringToGridType", "deprecatedType",
2013 	    "XbaeMatrix",
2014 	    "Value for GridType is deprecated and will be removed in next release",
2015 	    NULL, NULL);
2016 
2017     if (new->matrix.colors && EQ(matrix.colors)
2018 	&& (NE(matrix.rows) || NE(matrix.columns)))
2019     {
2020 	ResizeColors(current, new, False);
2021 	redisplay = True;
2022     }
2023 
2024     if (new->matrix.cell_background && EQ(matrix.cell_background) &&
2025 	(NE(matrix.rows) || NE(matrix.columns)))
2026     {
2027 	ResizeColors(current, new, True);
2028 	redisplay = True;
2029     }
2030 
2031     if (NE(matrix.cell_shadow_type) || NE(matrix.shadow_type) ||
2032 	NE(matrix.reverse_select))
2033 	redisplay = True;
2034 
2035     if (NE(matrix.column_widths))
2036     {
2037 	xbaeFreeColumnWidths(current);
2038 	xbaeCopyColumnWidths(new);
2039 	relayout = True;
2040 	new_column_widths = True;
2041     }
2042 
2043     if (NE(matrix.selected_cells))
2044     {
2045 	xbaeFreeSelectedCells(current);
2046 	xbaeCopySelectedCells(new);
2047 	redisplay = True;
2048     }
2049     else if (NE(matrix.rows) || NE(matrix.columns))
2050 	ResizeSelectedCells(current, new);
2051 
2052 #if XmVersion >= 1002
2053     if (NE(matrix.highlighted_cells))
2054     {
2055 	xbaeFreeHighlightedCells(current);
2056 	xbaeCopyHighlightedCells(new);
2057 	redisplay = True;
2058     }
2059     else if (NE(matrix.rows) || NE(matrix.columns))
2060 	ResizeHighlightedCells(current, new);
2061 #endif
2062 
2063     /*
2064      * If traversal changes, pass through to Clip and textField children.
2065      */
2066     if (NE(manager.traversal_on))
2067     {
2068 	XtVaSetValues(ClipChild(new),
2069 		      XmNtraversalOn, new->manager.traversal_on,
2070 		      NULL);
2071     }
2072     if (NE(matrix.even_row_background) || NE(matrix.odd_row_background))
2073 	redisplay = True;
2074 
2075     /*
2076      * Pass through primitive/manager resources to our children
2077      */
2078     n = 0;
2079     if (NE(core.background_pixel))
2080     {
2081 	/*
2082 	 * Set all clip widgets to the new background (thanks Daiji)
2083 	 */
2084 	XtVaSetValues(ClipChild(new),
2085 		      XmNbackground, new->core.background_pixel,
2086 		      NULL);
2087 	XtVaSetValues(LeftClip(new),
2088 		      XmNbackground, new->core.background_pixel,
2089 		      NULL);
2090 	XtVaSetValues(RightClip(new),
2091 		      XmNbackground, new->core.background_pixel,
2092 		      NULL);
2093 	XtVaSetValues(TopClip(new),
2094 		      XmNbackground, new->core.background_pixel,
2095 		      NULL);
2096 	XtVaSetValues(BottomClip(new),
2097 		      XmNbackground, new->core.background_pixel,
2098 		      NULL);
2099 	XtSetArg(wargs[n], XmNbackground, new->core.background_pixel); n++;
2100     }
2101     if (NE(manager.foreground))
2102     {
2103 	XtSetArg(wargs[n], XmNforeground, new->manager.foreground); n++;
2104     }
2105     if (NE(manager.bottom_shadow_color))
2106     {
2107 	XtSetArg(wargs[n], XmNbottomShadowColor,
2108 		 new->manager.bottom_shadow_color); n++;
2109     }
2110     if (NE(manager.bottom_shadow_pixmap))
2111     {
2112 	XtSetArg(wargs[n], XmNbottomShadowPixmap,
2113 		 new->manager.bottom_shadow_pixmap); n++;
2114     }
2115     if (NE(manager.highlight_color))
2116     {
2117 	XtSetArg(wargs[n], XmNhighlightColor,
2118 		 new->manager.highlight_color); n++;
2119     }
2120     if (NE(manager.highlight_pixmap))
2121     {
2122 	XtSetArg(wargs[n], XmNhighlightPixmap,
2123 		 new->manager.highlight_pixmap); n++;
2124     }
2125     if (NE(manager.top_shadow_color))
2126     {
2127 	XtSetArg(wargs[n], XmNtopShadowColor,
2128 		 new->manager.top_shadow_color); n++;
2129     }
2130     if (NE(manager.top_shadow_pixmap))
2131     {
2132 	XtSetArg(wargs[n], XmNtopShadowPixmap,
2133 		 new->manager.top_shadow_pixmap); n++;
2134     }
2135     if (n)
2136     {
2137 	XtSetValues(VertScrollChild(new), wargs, n);
2138 	XtSetValues(HorizScrollChild(new), wargs, n);
2139 	XtSetValues(TextChild(new), wargs, n);
2140     }
2141 
2142     /*
2143      * Would really like to do this in the above,
2144      * but we need to override background_pixel.
2145      */
2146     if (EQ(matrix.text_background) &&
2147 	(current->matrix.text_background == current->core.background_pixel))
2148 	new->matrix.text_background = new->core.background_pixel;
2149     if (NE(matrix.text_background) || NE(core.background_pixel))
2150     {
2151 	XtVaSetValues(TextChild(new),
2152 		      XmNbackground, new->matrix.text_background,
2153 		      NULL);
2154 	if (XtIsManaged(TextChild(new)))
2155 	    redisplay = True;
2156     }
2157     /*
2158      * Get a new XFontStruct and copy the fontList if it changed
2159      * and pass it to the textField.
2160      * Reset the HSB increment.
2161      * redisplay and relayout will be set below.
2162      */
2163     if (NE(matrix.font_list))
2164     {
2165 	XmFontListFree(current->matrix.font_list);
2166 	xbaeNewFont(new);
2167 	XtVaSetValues(TextChild(new),
2168 		      XmNfontList, new->matrix.font_list,
2169 		      NULL);
2170 	XtVaSetValues(HorizScrollChild(new),
2171 		      XmNincrement, FONT_WIDTH(new),
2172 		      NULL);
2173     }
2174 
2175     if (NE(matrix.label_font_list))
2176     {
2177 	XmFontListFree(current->matrix.label_font_list);
2178 	xbaeNewLabelFont(new);
2179 	XtVaSetValues(HorizScrollChild(new),
2180 		      XmNincrement, FONT_WIDTH(new),
2181 		      NULL);
2182     }
2183 
2184     /*
2185      * Pass the cell resources on to the textField.
2186      * Both redisplay and relayout will be set below.
2187      *
2188      * If anything changed to affect cell total width or column positions,
2189      * recalc them
2190      */
2191     if (new_cells || NE(matrix.fid) || NE(matrix.label_fid) ||
2192 	NE(matrix.cell_margin_width) || NE(matrix.cell_margin_height) ||
2193 	NE(matrix.cell_shadow_thickness) || NE(matrix.fixed_columns) ||
2194 	NE(matrix.trailing_fixed_columns) ||
2195 	NE(matrix.cell_highlight_thickness) || new_column_widths ||
2196 	NE(matrix.text_shadow_thickness))
2197     {
2198 	/*
2199 	 * Recalculate the margin height, based on the larger of the
2200 	 * label and general fonts.
2201 	 */
2202 	int marginHeight = new->matrix.cell_margin_height; /* by default */
2203 
2204 	if (LABEL_HEIGHT(new) > FONT_HEIGHT(new))
2205 	    marginHeight = (int)(LABEL_HEIGHT(new) +
2206 				 (new->matrix.cell_margin_height *
2207 				  2) - FONT_HEIGHT(new)) / 2;
2208 	/*
2209 	 * Cancel the edit -> If I think of a better way of doing this
2210 	 * I'll do it, AL.
2211 	 */
2212 	(*((XbaeMatrixWidgetClass) XtClass(new))->matrix_class.cancel_edit)
2213 	    (new, True);
2214 
2215 	XtVaSetValues(
2216 	    TextChild(new),
2217 	    XmNmarginWidth, new->matrix.cell_margin_width,
2218 	    XmNhighlightThickness, new->matrix.cell_highlight_thickness,
2219 	    XmNshadowThickness, new->matrix.text_shadow_thickness,
2220 	    XmNmarginHeight, marginHeight,
2221 	    NULL);
2222 
2223 	xbaeGetCellTotalWidth(new);
2224 
2225 	/*
2226 	 * Reset the HSB maximum.  sliderSize will be reset later in Resize.
2227 	 */
2228 	XtVaSetValues(HorizScrollChild(new),
2229 		      XmNmaximum, NON_FIXED_TOTAL_WIDTH(new) ?
2230 		      NON_FIXED_TOTAL_WIDTH(new) : 1,
2231 		      XmNsliderSize, 1,
2232 		      NULL);
2233 
2234 	/*
2235 	 * If the number of columns changed, we need to allocate a new array.
2236 	 */
2237 	if (NE(matrix.columns))
2238 	{
2239 	    xbaeFreeColumnPositions(current);
2240 	    new->matrix.column_positions = CreateColumnPositions(new);
2241 	}
2242 
2243 	/*
2244 	 * If anything but (trailing_)fixed_columns or the highlight color
2245 	 * changed, we need to recalc column positions.
2246 	 */
2247 	if (new_cells || NE(matrix.fid) || NE(matrix.label_fid) ||
2248 	    NE(matrix.cell_margin_width) || NE(matrix.cell_margin_height) ||
2249 	    NE(matrix.cell_shadow_thickness) ||
2250 	    NE(matrix.cell_highlight_thickness) || new_column_widths ||
2251 	    NE(matrix.text_shadow_thickness))
2252 
2253 	    xbaeGetColumnPositions(new);
2254 
2255 	/*
2256 	 * Recalculate the baselines
2257 	 */
2258 	new->matrix.text_baseline = XmTextGetBaseline(TextChild(new)) +
2259 	    new->matrix.cell_shadow_thickness /*+
2260 	    new->matrix.text_shadow_thickness*/;
2261 
2262 	/*
2263 	 * Adjust the label_baseline according to the larger of the two fonts
2264 	 */
2265 	if (LABEL_HEIGHT(new) == FONT_HEIGHT(new))
2266 	    new->matrix.label_baseline = new->matrix.text_baseline;
2267 	else
2268 	{
2269 	    if (LABEL_HEIGHT(new) < FONT_HEIGHT(new))
2270 		marginHeight = (FONT_HEIGHT(new) +
2271 				 new->matrix.text_shadow_thickness * 2 +
2272 				 new->matrix.cell_margin_height * 2 -
2273 				 (int)LABEL_HEIGHT(new)) / 2;
2274 	    else
2275 		marginHeight = new->matrix.cell_margin_height +
2276 		    new->matrix.text_shadow_thickness;
2277 
2278 	    new->matrix.label_baseline = marginHeight +
2279 		new->matrix.cell_shadow_thickness -
2280 		new->matrix.label_font_y;
2281 	}
2282 
2283 	/* JDS: The comment above this section says both redisplay and
2284 	 * relayout get set, but only relayout was being set.  I noticed
2285 	 * this because the resizeColumns action was setting the
2286 	 * columnWidths, but the clip widget wasn't properly redrawing
2287 	 * its cells when they were resized. This was in conjunction with
2288 	 * calling clipRedisplay only when the matrix redisplayed instead
2289 	 * of also when it relayedout :) (see the comment below).
2290 	 *
2291 	 * However, I'm not sure what else this might impact. But, I'm in
2292 	 * favor of the change I made to only redisplay when the matrix
2293 	 * redisplays since that's more efficient, I think, and it eliminated
2294 	 * some ugly redraws that I at least encountered. So there :).
2295 	 */
2296 	redisplay = relayout = True;
2297     }
2298 
2299     /*
2300      * Install text_translations on textField
2301      */
2302     if (NE(matrix.text_translations))
2303 	XtVaSetValues(TextChild(new),
2304 		      XmNtranslations, new->matrix.text_translations,
2305 		      NULL);
2306 
2307     /*
2308      * If row_label_width was set to 0, calculate it.
2309      * Otherwise if it was changed, set flags.
2310      */
2311     if (new->matrix.row_label_width == 0 && new->matrix.row_labels)
2312     {
2313 	new->matrix.row_label_width = xbaeMaxRowLabel(new);
2314 	relayout = True;
2315     }
2316     else if (NE(matrix.row_label_width))
2317 	relayout = True;
2318 
2319     /*
2320      * Check whether the widget is sensitive has changed and set our GC's
2321      * appropriately
2322      */
2323     if (XtIsSensitive((Widget)current) != XtIsSensitive((Widget)new))
2324     {
2325 	XGCValues values;
2326 	int i;
2327 	unsigned long valuemask = GCFillStyle;
2328 	Display *dpy = XtDisplay(new);
2329 
2330 	if (!XtIsSensitive((Widget)new))
2331 	{
2332 	    values.fill_style = FillStippled;
2333 
2334 	    /*
2335 	     * Change our drawing GC's to the stipple effect to indicate
2336 	     * the widget is insensitive and redraw
2337 	     */
2338 	    XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values);
2339 	    XChangeGC(dpy, new->matrix.label_gc, valuemask, &values);
2340 	    XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values);
2341 	    XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values);
2342 	    /*
2343 	     * Propogate the insensitive feel to our children
2344 	     */
2345 	    for (i = 0; i < XbaeNumChildren; i++)
2346 		XtSetSensitive(new->composite.children[i], False);
2347 	}
2348 	else
2349 	{
2350 	    values.fill_style = FillSolid;
2351 
2352 	    XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values);
2353 	    XChangeGC(dpy, new->matrix.label_gc, valuemask, &values);
2354 	    XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values);
2355 	    XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values);
2356 
2357 	    for (i = 0; i < XbaeNumChildren; i++)
2358 		XtSetSensitive(new->composite.children[i], True);
2359 	}
2360 	redisplay = True;
2361     }
2362 
2363     /*
2364      * If our fill policy changed or our bottom attachment,
2365      * we must redisplay and relayout.
2366      */
2367     if (NE(matrix.fill) || NE(matrix.trailing_attached_bottom))
2368     {
2369 	redisplay = True;
2370 	relayout = True;
2371     }
2372 
2373     /*
2374      * If either of the scrollbar display policies changed,
2375      * we need to redisplay and relayout.
2376      */
2377     if (NE(matrix.vsb_display_policy) ||
2378 	NE(matrix.hsb_display_policy))
2379 	relayout = True;
2380 
2381     /*
2382      * If the place of the scrollbars changes, we must redisplay
2383      */
2384     if (NE(matrix.scrollbar_placement))
2385 	relayout = True;
2386 
2387     /*
2388      * Change created GCs if needed
2389      */
2390 
2391     if (NE(manager.foreground))
2392     {
2393 	/*
2394 	 * We don't need to put the new foreground in draw_gc or
2395 	 * draw_clip_gc because they get a new foreground when they are used.
2396 	 */
2397 	XSetForeground(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc,
2398 		       new->manager.foreground);
2399 	XSetBackground(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc,
2400 		       new->manager.foreground);
2401 	redisplay = True;
2402     }
2403     if (NE(manager.top_shadow_color))
2404     {
2405 	XSetForeground(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc,
2406 		       new->manager.top_shadow_color);
2407 	XSetForeground(XtDisplay(new), new->matrix.resize_top_shadow_gc,
2408 		       new->manager.top_shadow_color);
2409 	redisplay = True;
2410     }
2411     if (NE(manager.top_shadow_pixmap))
2412     {
2413 	XSetTile(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc,
2414 		 new->manager.top_shadow_pixmap);
2415 	XSetTile(XtDisplay(new), new->matrix.resize_top_shadow_gc,
2416 		 new->manager.top_shadow_pixmap);
2417 	redisplay = True;
2418     }
2419     if (NE(manager.bottom_shadow_color))
2420     {
2421 	XSetForeground(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc,
2422 		       new->manager.bottom_shadow_color);
2423 	XSetForeground(XtDisplay(new), new->matrix.resize_bottom_shadow_gc,
2424 		       new->manager.bottom_shadow_color);
2425 	redisplay = True;
2426     }
2427     if (NE(manager.bottom_shadow_pixmap))
2428     {
2429 	XSetTile(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc,
2430 		 new->manager.bottom_shadow_pixmap);
2431 	XSetTile(XtDisplay(new), new->matrix.resize_bottom_shadow_gc,
2432 		 new->manager.bottom_shadow_pixmap);
2433 	redisplay = True;
2434     }
2435     if (NE(matrix.fid))
2436     {
2437 	XSetFont(XtDisplay(new), new->matrix.draw_gc, new->matrix.fid);
2438 	redisplay = True;
2439     }
2440 
2441     if (NE(matrix.label_fid))
2442     {
2443 	XSetFont(XtDisplay(new), new->matrix.label_gc,
2444 		 new->matrix.label_fid);
2445 	XSetFont(XtDisplay(new), new->matrix.label_clip_gc,
2446 		 new->matrix.label_fid);
2447 	redisplay = True;
2448     }
2449     /*
2450      * See if any other resources changed which will require a relayout
2451      */
2452     if (NE(matrix.space) || NE(matrix.cell_shadow_thickness) ||
2453 	NE(manager.shadow_thickness))
2454 	relayout = True;
2455 
2456     /*
2457      * If bold_labels or button labels changed, and we have labels,
2458      * we must redisplay
2459      */
2460     if ((NE(matrix.bold_labels) || NE(matrix.button_labels)) &&
2461 	 (new->matrix.row_labels || new->matrix.column_labels))
2462 	 redisplay = True;
2463 
2464     /*
2465      * If showArrows is changed, redisplay to get rid of existing arrows
2466      */
2467     if (NE(matrix.show_arrows))
2468 	redisplay = True;
2469 
2470     /*
2471      * Compute a new size if:
2472      *	 visible_rows or visible_columns changed.
2473      *	 user set our width or height to zero.
2474      */
2475     if (NE(matrix.visible_rows) || NE(matrix.visible_columns) ||
2476 	request->core.height == 0 || request->core.width == 0)
2477 	xbaeComputeSize(new, request->core.width == 0,
2478 			request->core.height == 0);
2479 
2480     /*
2481      * If our size didn't change, but we need to layout, call Resize.
2482      * If our size did change, then Xt will call our Resize method for us.
2483      * If our size did change, but the new size is later refused,
2484      *	 then SetValuesAlmost will call Resize to layout.
2485      */
2486     if (EQ(core.width) && EQ(core.height) && relayout)
2487 	xbaeResize(new);
2488 
2489     /*
2490      * The user forced a new top_row or something changed to force
2491      * us to recheck the current top_row.
2492      */
2493     if (NE(matrix.top_row) || do_top_row)
2494     {
2495 	XmScrollBarCallbackStruct call_data;
2496 
2497 	xbaeAdjustTopRow(new);
2498  	call_data.value = VERT_ORIGIN(new);
2499 	/*
2500 	 * Trick xbaeScrollVertCB() into believing it needs to scroll
2501 	 */
2502 	VERT_ORIGIN(new) = VERT_ORIGIN(current);
2503 	xbaeScrollVertCB((Widget)VertScrollChild(new), NULL, &call_data);
2504 	VERT_ORIGIN(new) = call_data.value; /* and reset VERT_ORIGIN */
2505 
2506 	XtVaSetValues(VertScrollChild(new),
2507 		      XmNvalue, VERT_ORIGIN(new),
2508 		      NULL);
2509     }
2510 
2511     if (NE(matrix.left_column) || do_left_column)
2512     {
2513 	XmScrollBarCallbackStruct call_data;
2514 
2515 	xbaeAdjustLeftColumn(new);
2516 	call_data.value = HORIZ_ORIGIN(new);
2517 	HORIZ_ORIGIN(new) = HORIZ_ORIGIN(current);
2518 	xbaeScrollHorizCB((Widget)HorizScrollChild(new), NULL, &call_data);
2519 	HORIZ_ORIGIN(new) = call_data.value;
2520 	XtVaSetValues(HorizScrollChild(new),
2521 		      XmNvalue, HORIZ_ORIGIN(new),
2522 		      NULL);
2523     }
2524 
2525     /*
2526      * Force the Clip widget to redisplay.  Note: this may generate an
2527      * expose event for the current size of the Clip widget, and the Clip
2528      * widget may be sized smaller in set_values_almost.  The ClipRedisplay
2529      * function can handle this case.
2530      *
2531      * JDS: Don't need to force a redisplay on a relayout, since the Clip
2532      * widget's resize method (now non-NULL) will be called and Xt will
2533      * automatically do an expose after that occurs. Seems to work, anyways :).
2534      */
2535     if (redisplay)
2536 	XbaeMatrixRefresh((Widget)new);
2537 
2538     /*
2539      * We want to return True when we need to redisplay or relayout.
2540      */
2541     return redisplay || relayout;
2542 
2543 #undef NE
2544 #undef EQ
2545 }
2546 
2547 /* ARGSUSED */
2548 static void
SetValuesAlmost(old,new,request,reply)2549 SetValuesAlmost(old, new, request, reply)
2550 XbaeMatrixWidget old;
2551 XbaeMatrixWidget new;
2552 XtWidgetGeometry *request;
2553 XtWidgetGeometry *reply;
2554 {
2555     /*
2556      * If XtGeometryAlmost, accept compromize - Resize will take care of it
2557      */
2558     if (reply->request_mode)
2559     {
2560 	*request = *reply;
2561 
2562 #if XtSpecificationRelease > 4
2563 	/*
2564 	 * In R5, XtSetValues changed so that when a widgets parent
2565 	 * returns XtGeometryAlmost, Xt will only call the widgets resize
2566 	 * method if the widgets size actually changed.  It turns out that
2567 	 * some manager widgets (old Wcl XmpTable and 1.1.x XmForm) return
2568 	 * XtGeometryAlmost with a compromise size which is the widgets
2569 	 * original size (not much of a compromise)!  This means as of R5,
2570 	 * Matrix's resize method won't get called in that case.
2571 	 *
2572 	 * So, for R5 we explicitly call our resize method here for the
2573 	 * case of XtGeometryAlmost where our size did not change.
2574 	 */
2575 	if ((reply->request_mode & CWWidth ||
2576 	     reply->request_mode & CWHeight)
2577 	    &&
2578 	    (old->core.width == new->core.width &&
2579 	     old->core.height == new->core.height))
2580 	    xbaeResize(new);
2581 #endif
2582     }
2583 
2584     /*
2585      * If XtGeometryNo, call Resize to relayout if it was a size change
2586      * that was denied.
2587      * Accept the original geometry.
2588      * (we need to call Resize even though the size
2589      * didn't change to force a relayout - set_values relies on this)
2590      */
2591     else
2592     {
2593 	if ((request->request_mode & CWWidth ||
2594 	     request->request_mode & CWHeight))
2595 	    xbaeResize(new);
2596 
2597 	request->request_mode = 0;
2598     }
2599 }
2600 
2601 static void
Destroy(mw)2602 Destroy(mw)
2603 XbaeMatrixWidget mw;
2604 {
2605 #if XmVersion >= 1002
2606     if (TraverseID)
2607 	XtRemoveTimeOut(TraverseID);
2608 #endif
2609 
2610     XtReleaseGC((Widget) mw, mw->matrix.grid_line_gc);
2611     XFreeGC(XtDisplay(mw), mw->matrix.cell_grid_line_gc);
2612 
2613     XFreeGC(XtDisplay(mw), mw->matrix.label_gc);
2614     XFreeGC(XtDisplay(mw), mw->matrix.label_clip_gc);
2615     XFreeGC(XtDisplay(mw), mw->matrix.draw_gc);
2616     XFreeGC(XtDisplay(mw), mw->matrix.pixmap_gc);
2617     XFreeGC(XtDisplay(mw), mw->matrix.cell_top_shadow_clip_gc);
2618     XFreeGC(XtDisplay(mw), mw->matrix.cell_bottom_shadow_clip_gc);
2619     XtReleaseGC((Widget) mw, mw->matrix.resize_top_shadow_gc);
2620     XtReleaseGC((Widget) mw, mw->matrix.resize_bottom_shadow_gc);
2621 
2622     xbaeFreeCells(mw);
2623 #if CELL_WIDGETS
2624     xbaeFreeCellWidgets(mw);
2625 #endif
2626     xbaeFreeRowLabels(mw);
2627     xbaeFreeColumnLabels(mw);
2628     xbaeFreeColumnWidths(mw);
2629     xbaeFreeColumnMaxLengths(mw);
2630     xbaeFreeColumnPositions(mw);
2631     xbaeFreeColumnAlignments(mw);
2632     xbaeFreeColumnButtonLabels(mw);
2633     xbaeFreeRowButtonLabels(mw);
2634     xbaeFreeColumnLabelAlignments(mw);
2635     xbaeFreeCellUserData(mw);
2636     xbaeFreeRowUserData(mw);
2637     xbaeFreeColumnUserData(mw);
2638     xbaeFreeCellShadowTypes(mw);
2639     xbaeFreeRowShadowTypes(mw);
2640     xbaeFreeColumnShadowTypes(mw);
2641     xbaeFreeColors(mw);
2642     xbaeFreeBackgrounds(mw);
2643     xbaeFreeSelectedCells(mw);
2644 #if XmVersion >= 1002
2645     xbaeFreeHighlightedCells(mw);
2646 #endif
2647 
2648     XmFontListFree(mw->matrix.font_list);
2649     XmFontListFree(mw->matrix.label_font_list);
2650 
2651     xbaeSmDestroyScrollMgr(mw->matrix.matrix_scroll_mgr);
2652     xbaeSmDestroyScrollMgr(mw->matrix.clip_scroll_mgr);
2653 }
2654 
2655 /*
2656  * Since we totally control our childrens geometry, allow anything.
2657  */
2658 /* ARGSUSED */
2659 static XtGeometryResult
GeometryManager(w,desired,allowed)2660 GeometryManager(w, desired, allowed)
2661 Widget w;
2662 XtWidgetGeometry *desired, *allowed;
2663 {
2664 #define Wants(flag) (desired->request_mode & flag)
2665 
2666     if (Wants(XtCWQueryOnly))
2667 	return (XtGeometryYes);
2668 
2669     if (Wants(CWWidth))
2670 	w->core.width = desired->width;
2671     if (Wants(CWHeight))
2672 	w->core.height = desired->height;
2673     if (Wants(CWX))
2674 	w->core.x = desired->x;
2675     if (Wants(CWY))
2676 	w->core.y = desired->y;
2677     if (Wants(CWBorderWidth))
2678 	w->core.border_width = desired->border_width;
2679 
2680     return (XtGeometryYes);
2681 
2682 #undef Wants
2683 }
2684 
2685 /*
2686  * We would prefer to be the size calculated in ComputeSize and saved in
2687  * desired_width/height
2688  */
2689 static XtGeometryResult
QueryGeometry(mw,proposed,desired)2690 QueryGeometry(mw, proposed, desired)
2691 XbaeMatrixWidget mw;
2692 XtWidgetGeometry *proposed, *desired;
2693 {
2694 #define Set(bit) (proposed->request_mode & bit)
2695 
2696     desired->width = mw->matrix.desired_width;
2697     desired->height = mw->matrix.desired_height;
2698     desired->request_mode = CWWidth | CWHeight;
2699 
2700     if (Set(CWWidth) && proposed->width == desired->width &&
2701 	Set(CWHeight) && proposed->height == desired->height)
2702 	return (XtGeometryYes);
2703 
2704     if (desired->width == mw->core.width && desired->height == mw->core.height)
2705 	return (XtGeometryNo);
2706 
2707     return (XtGeometryAlmost);
2708 
2709 #undef Set
2710 }
2711 
2712 /*
2713  * This function is called from either the Clip focus CB or a timeout proc.
2714  * It is called as a result of the Clip getting the focus. We want to give
2715  * the focus to the textField if a cell is being edited.  If no cells are
2716  * being edited, force an edit on the top left most visible cell.
2717  */
2718 static void
TraverseIn(mw)2719 TraverseIn(mw)
2720 XbaeMatrixWidget mw;
2721 {
2722     /*
2723      * If the traversing flag is set, then Clip got the focus because
2724      * textField was trying to traverse out of mw.  We'll help it along.
2725      * Sickening.
2726      */
2727     if (mw->matrix.traversing != NOT_TRAVERSING)
2728     {
2729 	XmProcessTraversal(ClipChild(mw), mw->matrix.traversing);
2730 	return;
2731     }
2732 
2733     /*
2734      * If the textField is managed and not visible, scroll it onto the screen
2735      * and traverse to it.
2736      */
2737     if (XtIsManaged(TextChild(mw)))
2738     {
2739 	if (mw->matrix.scroll_select)
2740 	    xbaeMakeCellVisible(mw, mw->matrix.current_row,
2741 				 mw->matrix.current_column);
2742 	XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT);
2743     }
2744 
2745     /*
2746      * Otherwise, no cell is being edited.  Force an edit on the top-left
2747      * most visible cell.
2748      */
2749     else
2750     {
2751 	int column = xbaeXtoCol(mw, FIXED_COLUMN_WIDTH(mw) + HORIZ_ORIGIN(mw));
2752 	int row = VERT_ORIGIN(mw) + mw->matrix.fixed_rows;
2753 
2754 	/*
2755 	 * Call the traverseCellCallback to allow the application to
2756 	 * perform custom traversal.
2757 	 */
2758 	if (mw->matrix.traverse_cell_callback)
2759 	{
2760 	    XbaeMatrixTraverseCellCallbackStruct call_data;
2761 
2762 	    call_data.reason = XbaeTraverseCellReason;
2763 	    call_data.event = (XEvent *)NULL;
2764 	    call_data.row = 0;
2765 	    call_data.column = 0;
2766 	    call_data.next_row = row;
2767 	    call_data.next_column = column;
2768 	    call_data.fixed_rows = mw->matrix.fixed_rows;
2769 	    call_data.fixed_columns = mw->matrix.fixed_columns;
2770 	    call_data.trailing_fixed_rows = mw->matrix.trailing_fixed_rows;
2771 	    call_data.trailing_fixed_columns =
2772 		mw->matrix.trailing_fixed_columns;
2773 	    call_data.num_rows = mw->matrix.rows;
2774 	    call_data.num_columns = mw->matrix.columns;
2775 	    call_data.param = NULL;
2776 	    call_data.qparam = NULLQUARK;
2777 
2778 	    XtCallCallbackList((Widget) mw, mw->matrix.traverse_cell_callback,
2779 			       (XtPointer) & call_data);
2780 
2781 	    row = call_data.next_row;
2782 	    column = call_data.next_column;
2783 	}
2784 
2785 	(*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.edit_cell)
2786 	    (mw, NULL, row, column, NULL, 0);
2787 
2788 	XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT);
2789     }
2790 }
2791 
2792 #if XmVersion >= 1002
2793 /*
2794  * Under Motif 1.2, TraverseInCB can't call TraverseIn directly, so it
2795  * adds a zero length timeout and we call it from here.
2796  */
2797 /* ARGSUSED */
2798 static void
TraverseInTimeOut(mw,timer)2799 TraverseInTimeOut(mw, timer)
2800 XtPointer mw;
2801 XtIntervalId *timer;
2802 {
2803     TraverseIn((XbaeMatrixWidget)mw);
2804 }
2805 
2806 #endif /* XmVersion >= 1002 */
2807 
2808 /*
2809  * This is the Clip widgets focusCallback. We want to give the focus to
2810  * the textField if a cell is being edited.  If no cells are being edited,
2811  * force an edit on the top left most visible cell.
2812  */
2813 /* ARGSUSED */
2814 static void
TraverseInCB(w,mw,call_data)2815 TraverseInCB(w, mw, call_data)
2816 Widget w;
2817 XbaeMatrixWidget mw;
2818 XtPointer call_data;
2819 {
2820 #if XmVersion < 1002
2821     TraverseIn(mw);
2822 #else
2823     /*
2824      * Under Motif 1.2, we can't call TraverseIn directly because it
2825      * calls XmProcessTraversal and recursive calls to XmProcessTraversal
2826      * are disallowed in 1.2 (we may be in this CB as a result of someone
2827      * calling XmProcessTraversal).  So we add a zero length timeout
2828      * and call TraverseIn from there.
2829      */
2830     TraverseID = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w), 0L,
2831 				 TraverseInTimeOut, (XtPointer) mw);
2832 #endif
2833 }
2834 
2835 /*
2836  * Add rows/columns of cells when set_values changes our rows/columns
2837  */
2838 static void
ResizeCells(current,new)2839 ResizeCells(current, new)
2840 XbaeMatrixWidget current;
2841 XbaeMatrixWidget new;
2842 {
2843     int i, j;
2844     int safe_rows = 0;
2845 
2846     /*
2847      * If there is a draw cell callback, we don't need to allocate any
2848      * memory for the cells so get outta here.  If there is a draw cell
2849      * callback, no memory should have been allocated when this point is
2850      * reached.
2851      */
2852     if (!new->matrix.cells)
2853 	return;
2854 
2855     if (new->matrix.rows == current->matrix.rows)
2856 	safe_rows = new->matrix.rows;
2857 
2858     /*
2859      * Adding rows
2860      */
2861     if (new->matrix.rows > current->matrix.rows)
2862     {
2863 	/*
2864 	 * Realloc a larger array of row pointers
2865 	 */
2866 	new->matrix.cells =
2867 	    (String **) XtRealloc((char *) new->matrix.cells,
2868 				  new->matrix.rows * sizeof(String *));
2869 
2870 	/*
2871 	 * Malloc a new row array for each row. Initialize it with
2872 	 * NULL Strings. Use the new column size.
2873 	 */
2874 	for (i = current->matrix.rows; i < new->matrix.rows; i++)
2875 	{
2876 	    new->matrix.cells[i] =
2877 		(String *) XtMalloc(new->matrix.columns * sizeof(String));
2878 	    for (j = 0; j < new->matrix.columns; j++)
2879 		new->matrix.cells[i][j] = XtNewString("");
2880 	}
2881 
2882 	safe_rows = current->matrix.rows;
2883     }
2884 
2885     /*
2886      * Deleting rows
2887      */
2888     if (new->matrix.rows < current->matrix.rows)
2889     {
2890 	/*
2891 	 * Free the cells in the rows being deleted and the rows themselves
2892 	 */
2893 	for (i = new->matrix.rows; i < current->matrix.rows; i++)
2894 	{
2895 	    for (j = 0; j < current->matrix.columns; j++)
2896 		XtFree((XtPointer) new->matrix.cells[i][j]);
2897 	    XtFree((XtPointer) new->matrix.cells[i]);
2898 	}
2899 
2900 	safe_rows = new->matrix.rows;
2901     }
2902 
2903     /*
2904      * Adding columns
2905      */
2906     if (new->matrix.columns > current->matrix.columns)
2907     {
2908 	/*
2909 	 * Realloc each row array. Do not touch any rows added/deleted above
2910 	 * (use safe_rows)
2911 	 */
2912 	for (i = 0; i < safe_rows; i++)
2913 	{
2914 	    new->matrix.cells[i] =
2915 		(String *) XtRealloc((char *) new->matrix.cells[i],
2916 				     new->matrix.columns * sizeof(String));
2917 	    for (j = current->matrix.columns; j < new->matrix.columns; j++)
2918 		new->matrix.cells[i][j] = XtNewString("");
2919 	}
2920     }
2921 
2922     /*
2923      * Deleting columns
2924      */
2925     if (new->matrix.columns < current->matrix.columns)
2926     {
2927 	/*
2928 	 * Free all the cells in the deleted columns. Do not touch any
2929 	 * rows added/deleted above (use safe_rows).
2930 	 * We don't bother to realloc each row, just leave some wasted space.
2931 	 * XXX is this a problem?
2932 	 */
2933 	for (i = 0; i < safe_rows; i++)
2934 	    for (j = new->matrix.columns; j < current->matrix.columns; j++)
2935 		XtFree((XtPointer) new->matrix.cells[i][j]);
2936     }
2937 }
2938 
2939 /*
2940  * Add rows/columns of selected flags when set_values changes our rows/columns
2941  */
2942 static void
ResizeSelectedCells(current,new)2943 ResizeSelectedCells(current, new)
2944 XbaeMatrixWidget current;
2945 XbaeMatrixWidget new;
2946 {
2947     int i;
2948     int safe_rows = 0;
2949 
2950     /*
2951      * selectedCells is allocated when the first cell is selected.  If it
2952      * is still NULL, no cells have been selected up to this point.
2953      */
2954     if (!new->matrix.selected_cells)
2955 	return;
2956 
2957     if (new->matrix.rows == current->matrix.rows)
2958 	safe_rows = new->matrix.rows;
2959 
2960     /*
2961      * Adding rows
2962      */
2963     if (new->matrix.rows > current->matrix.rows)
2964     {
2965 	/*
2966 	 * Realloc a larger array of row pointers
2967 	 */
2968 	new->matrix.selected_cells =
2969 	    (Boolean **) XtRealloc((char *) new->matrix.selected_cells,
2970 				   new->matrix.rows * sizeof(Boolean *));
2971 
2972 	/*
2973 	 * Calloc a new row array for each row. Use the new column size.
2974 	 */
2975 	for (i = current->matrix.rows; i < new->matrix.rows; i++)
2976 	    new->matrix.selected_cells[i] =
2977 		(Boolean *) XtCalloc(new->matrix.columns, sizeof(Boolean));
2978 
2979 	safe_rows = current->matrix.rows;
2980     }
2981 
2982     /*
2983      * Deleting rows
2984      */
2985     if (new->matrix.rows < current->matrix.rows)
2986     {
2987 	for (i = new->matrix.rows; i < current->matrix.rows; i++)
2988 	    XtFree((XtPointer) new->matrix.selected_cells[i]);
2989 	safe_rows = new->matrix.rows;
2990     }
2991 
2992     /*
2993      * Adding columns
2994      */
2995     if (new->matrix.columns > current->matrix.columns)
2996     {
2997 	/*
2998 	 * Realloc each row array. Do not touch any rows added/deleted above
2999 	 * (use safe_rows)
3000 	 */
3001 	for (i = 0; i < safe_rows; i++)
3002 	{
3003 	    int j;
3004 
3005 	    new->matrix.selected_cells[i] =
3006 		(Boolean *) XtRealloc((char *) new->matrix.selected_cells[i],
3007 				      new->matrix.columns * sizeof(Boolean));
3008 	    for (j = current->matrix.columns; j < new->matrix.columns; j++)
3009 		new->matrix.selected_cells[i][j] = False;
3010 	}
3011     }
3012 
3013     /*
3014      * Deleting columns
3015      *   if (new->matrix.columns < current->matrix.columns)
3016      * We don't bother to realloc, just leave some wasted space.
3017      * XXX is this a problem?
3018      */
3019 }
3020 
3021 #if XmVersion >= 1002
3022 /*
3023  * Add rows/columns of highlighted flags when set_values changes our rows/columns
3024  */
3025 static void
ResizeHighlightedCells(current,new)3026 ResizeHighlightedCells(current, new)
3027 XbaeMatrixWidget current;
3028 XbaeMatrixWidget new;
3029 {
3030     int i;
3031     int safe_rows = 0;
3032 
3033     if (!new->matrix.highlighted_cells)
3034 	return;
3035 
3036     if (new->matrix.rows == current->matrix.rows)
3037 	safe_rows = new->matrix.rows;
3038 
3039     /*
3040      * Adding rows
3041      */
3042     if (new->matrix.rows > current->matrix.rows)
3043     {
3044 	/*
3045 	 * Realloc a larger array of row pointers
3046 	 */
3047 	new->matrix.highlighted_cells =
3048 	    (unsigned char **) XtRealloc(
3049 		(char *) new->matrix.highlighted_cells,
3050 		new->matrix.rows * sizeof(unsigned char *));
3051 
3052 	/*
3053 	 * Calloc a new row array for each row. Use the new column size.
3054 	 */
3055 	for (i = current->matrix.rows; i < new->matrix.rows; i++)
3056 	    new->matrix.highlighted_cells[i] =
3057 		(unsigned char *) XtCalloc(new->matrix.columns,
3058 					   sizeof(unsigned char));
3059 
3060 	safe_rows = current->matrix.rows;
3061     }
3062 
3063     /*
3064      * Deleting rows
3065      */
3066     if (new->matrix.rows < current->matrix.rows)
3067     {
3068 	for (i = new->matrix.rows; i < current->matrix.rows; i++)
3069 	    XtFree((XtPointer) new->matrix.highlighted_cells[i]);
3070 	safe_rows = new->matrix.rows;
3071     }
3072 
3073     /*
3074      * Adding columns
3075      */
3076     if (new->matrix.columns > current->matrix.columns)
3077     {
3078 	/*
3079 	 * Realloc each row array. Do not touch any rows added/deleted above
3080 	 * (use safe_rows)
3081 	 */
3082 	for (i = 0; i < safe_rows; i++)
3083 	{
3084 	    int j;
3085 
3086 	    new->matrix.highlighted_cells[i] =
3087 		(unsigned char *) XtRealloc(
3088 		    (char *) new->matrix.highlighted_cells[i],
3089 		    new->matrix.columns * sizeof(unsigned char));
3090 	    for (j = current->matrix.columns; j < new->matrix.columns; j++)
3091 		new->matrix.highlighted_cells[i][j] = HighlightNone;
3092 	}
3093     }
3094 
3095     /*
3096      * Deleting columns
3097      *   if (new->matrix.columns < current->matrix.columns)
3098      * We don't bother to realloc, just leave some wasted space.
3099      * XXX is this a problem?
3100      */
3101 }
3102 #endif
3103 
3104 /*
3105  * Add rows/columns of colors when set_values changes our rows/columns
3106  */
3107 static void
3108 #if NeedFunctionPrototypes
ResizeColors(XbaeMatrixWidget current,XbaeMatrixWidget new,Boolean bg)3109 ResizeColors(XbaeMatrixWidget current, XbaeMatrixWidget new, Boolean bg)
3110 #else
3111 ResizeColors(current, new, bg)
3112 XbaeMatrixWidget current;
3113 XbaeMatrixWidget new;
3114 Boolean bg;
3115 #endif
3116 {
3117     int i, j;
3118     int safe_rows = 0;
3119 
3120     if (! new->matrix.rows)
3121 	return;
3122 
3123     if (new->matrix.rows == current->matrix.rows)
3124 	safe_rows = new->matrix.rows;
3125 
3126     /*
3127      * Adding rows
3128      */
3129     if (new->matrix.rows > current->matrix.rows)
3130     {
3131 	/*
3132 	 * Realloc a larger array of row pointers
3133 	 */
3134 	if (bg)
3135 	{
3136 	    new->matrix.cell_background =
3137 		(Pixel **) XtRealloc((char *) new->matrix.cell_background,
3138 				     new->matrix.rows * sizeof(Pixel *));
3139 	    for (i = current->matrix.rows; i < new->matrix.rows; i++)
3140 	    {
3141 		new->matrix.cell_background[i] =
3142 		    (Pixel *) XtMalloc(new->matrix.columns * sizeof(Pixel));
3143 
3144 		for (j = 0; j < new->matrix.columns; j++)
3145 		    new->matrix.cell_background[i][j] =
3146 			new->core.background_pixel;
3147 	    }
3148 	}
3149 	else
3150 	{
3151 	    new->matrix.colors =
3152 		(Pixel **) XtRealloc((char *) new->matrix.colors,
3153 				     new->matrix.rows * sizeof(Pixel *));
3154 	    for (i = current->matrix.rows; i < new->matrix.rows; i++)
3155 	    {
3156 		new->matrix.colors[i] =
3157 		    (Pixel *) XtMalloc(new->matrix.columns * sizeof(Pixel));
3158 
3159 		for (j = 0; j < new->matrix.columns; j++)
3160 		    new->matrix.colors[i][j] = new->manager.foreground;
3161 	    }
3162 	}
3163 	/*
3164 	 * Malloc a new row array for each row. Initialize it with foreground.
3165 	 * Use the new column size.
3166 	 */
3167 	safe_rows = current->matrix.rows;
3168     }
3169 
3170     /*
3171      * Deleting rows
3172      */
3173     if (new->matrix.rows < current->matrix.rows)
3174     {
3175 	if (bg)
3176 	    for (i = new->matrix.rows; i < current->matrix.rows; i++)
3177 		XtFree((XtPointer) new->matrix.cell_background[i]);
3178 	else
3179 	    for (i = new->matrix.rows; i < current->matrix.rows; i++)
3180 		XtFree((XtPointer) new->matrix.colors[i]);
3181 
3182 	safe_rows = new->matrix.rows;
3183     }
3184 
3185     /*
3186      * Adding columns
3187      */
3188     if (new->matrix.columns > current->matrix.columns)
3189     {
3190 	/*
3191 	 * Realloc each row array. Do not touch any rows added/deleted above
3192 	 * (use safe_rows)
3193 	 */
3194 	if (bg)
3195 	{
3196 	    for (i = 0; i < safe_rows; i++)
3197 	    {
3198 		int k;
3199 
3200 		new->matrix.cell_background[i] =
3201 		    (Pixel *) XtRealloc(
3202 			(char *) new->matrix.cell_background[i],
3203 			new->matrix.columns * sizeof(Pixel));
3204 
3205 		for (k = current->matrix.columns; k < new->matrix.columns;
3206 		     k++)
3207 		    new->matrix.cell_background[i][k] =
3208 			new->core.background_pixel;
3209 	    }
3210 	}
3211 	else
3212 	{
3213 	    for (i = 0; i < safe_rows; i++)
3214 	    {
3215 		int k;
3216 
3217 		new->matrix.colors[i] =
3218 		    (Pixel *) XtRealloc(
3219 			(char *) new->matrix.colors[i],
3220 			new->matrix.columns * sizeof(Pixel));
3221 
3222 		for (k = current->matrix.columns; k < new->matrix.columns;
3223 		     k++)
3224 		    new->matrix.colors[i][k] = new->manager.foreground;
3225 	    }
3226 	}
3227     }
3228 
3229     /*
3230      * Deleting columns
3231      *   if (new->matrix.columns < current->matrix.columns)
3232      * We don't bother to realloc, just leave some wasted space.
3233      * XXX is this a problem?  AL: Probably! If you are deleting enough
3234      * columns, it would be nice to make the memory available again.
3235      * I'll get to it later.
3236      */
3237 }
3238 
3239