1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12 #ifdef OS2
13 #include <stdlib.h>
14 #include <types.h>
15 #endif
16 #include <stdio.h> /* for sprintf */
17 #include <ctype.h> /* define isupper() */
18 #include <X11/Xlib.h>
19 #include <X11/StringDefs.h>
20 #include <X11/cursorfont.h>
21 #include <X11/IntrinsicP.h>
22 #include <X11/Intrinsic.h>
23 #include <X11/CoreP.h>
24 #include <X11/CompositeP.h>
25 #include <X11/Composite.h>
26 #include <X11/Constraint.h>
27 #include <Xm/XmP.h>
28 #include <Xm/Xm.h>
29 #include "WorkspaceW.h"
30 #include "WorkspaceP.h"
31 #include "WorkspaceCallback.h"
32 #include <string.h>
33 #include <X11/keysym.h>
34
35 #if !defined(XK_MISCELLANY)
36 #define XK_MISCELLANY 1
37 #endif
38
39
40 /* External functions */
41 extern void ChangeWidgetInCollideList(); /* From Findroute.c */
42
43 extern void _XmManagerEnter();
44 extern void _XmManagerFocusIn();
45
46 #define STRCMP(a,b) ((a) ? ((b) ? strcmp(a,b) : strcmp(a,"")) : \
47 ((b) ? strcmp("",b) : 0))
48
49 /*
50 * Explanation of default Actions in response to mouse pressing and motion:
51 *
52 * Action started on background:
53 *
54 * ~SHIFT Button1Down: Start rubberband
55 * Unhighlight previously selected children
56 *
57 * SHIFT Button1Down: Start rubberband
58 *
59 * (~SHIFT)Button1Move: Stretch rubberband
60 * (A) Highlight children as included
61 * (A) Unhighlight children as unincluded
62 *
63 * (SHIFT)Button1Move: Stretch rubberband
64 * (A) Toggle highlight of children as included
65 * (A) Toggle highlight of children as unincluded
66 *
67 * (~SHIFT)Button1Up: Hide rubberband
68 * (B) Highlight new included children
69 * Callback w/ unselect new excluded children
70 * Callback w/ select new included children
71 *
72 * (SHIFT)Button1Up: Hide rubberband
73 * (B) Toggle highlight of all included children
74 * Callback w/ unselect new unhighlighted children
75 * Callback w/ select new highlighted children
76 *
77 * Action started in child:
78 *
79 * If child was not already selected:
80 * ~SHIFT Button1Down: Unhighlight prior highlighted children
81 * Highlight child
82 * Callback w/ unselect to prior selected children
83 * Callback w/ select to child
84 * enable move
85 *
86 * SHIFT Button1Down: Highlight child
87 * Callback w/ select to child
88 * enable move
89 *
90 * If child was already selected:
91 * ~SHIFT Button1Down: enable move
92 *
93 * SHIFT Button1Down: Unhighlight child
94 * Callback w/ unselect to child
95 * disable move
96 *
97 * Button1Move: if move enabled:
98 * (A) Move outline of each selected child
99 * (B) Move bounding box of selected children extremes
100 * (C) (B) plus outline of grabbed child
101 *
102 * Button1Up: if move enabled:
103 * Hide rubberband(s)
104 * Move selected children
105 * (?) Action to update graphics
106 *
107 */
108
109
110 /*
111 * Explanation of Automated widget movement applied when widget overlap is
112 * not allowed:
113 *
114 * Space wars rules:
115 *
116 * 1. No moved widget may overlap any other.
117 * 2. Movement to clear overlaps is to the right only
118 * 3. Any widget moved, whether by user or by space wars, will be placed
119 * according to all existing gridding rules.
120 * 4. All adjustment to avoid overlap is done by moving widgets to the right.
121 *
122 * Option Rules:
123 * (Option 2 is the default)
124 * (Option 0 may be a bit more efficient if only 1 child can be moved at
125 * a time).
126 * 0. Automated movement for space wars does not change horizontal widget
127 * ordering (established at time selected children are dropped).
128 * 1. a. The left-most selected child maintains its horizontal order as
129 * placed.
130 * b. All other selected children maintain their position relative to
131 * that left-most child
132 * 2. a. Selected widgets are placed (and snapped-to-grid if called for) with
133 * no consideration of other widgets.
134 * b. All other widgets move right to accomodate new placement.
135 * c. Movement of non-selected widgets does not alter the horizontal
136 * ordering among those non-selected widgets (e.g. a small child to
137 * the right of a large one will NOT be moved ahead of it to fill a
138 * convenient hole too small for the larger one).
139 *
140 * Rules of Horizontal Ordering
141 * 1. Horizontal ordering is based on the x coordinate of each widget's
142 * left edge, center, or right edge as per alignment_policy.
143 * 2. a. When two widgets have the same x coordinate for alignment, the
144 * selected widget is ordered before one that is not selected.
145 * b. When both widgets have the same x coordinate and selection status,
146 * the ordering will be based on the y coordinates as per alignment.
147 */
148
149
150 /* Define structure of link elements in a sort list of child widgets */
151 struct SortRec {
152 struct SortRec* next;
153 Widget child;
154 XmWorkspaceConstraints constraints;
155 short x_left, x_right;
156 short y_upper, y_lower;
157 int x_index;
158 Boolean is_selected;
159 Boolean is_displaced;
160 };
161
162 /* Parameter to control size of arms of alignment hash marks: ray+1+ray */
163 #define HASH_RAY 4
164 #define GRID_DASH_MIN 10
165
166 /* Codes and indexes for rubberbanding cursor */
167 #define SZ_NONE 4
168 #define SZ_LEFT 0
169 #define SZ_RIGHT 1
170 #define SZ_UPPER 0
171 #define SZ_LOWER 2
172 #define SZ_UL 0
173 #define SZ_UR 1
174 #define SZ_LL 2
175 #define SZ_LR 3
176
177 #define FC_LEFT 0
178 #define FC_RIGHT 1
179 #define FC_TOP 2
180 #define FC_BOTTOM 3
181
182 #define superclass (&xmFormClassRec)
183
184 LineElement *Manhattan(XmWorkspaceWidget ww, int srcx, int srcy,
185 int dstx, int dsty,
186 int level, int *cost,
187 Widget source, Widget destination,
188 XmWorkspaceLine new, int *failnum);
189 void CopyPointsToLine(XmWorkspaceWidget ww,LineElement *list,
190 XmWorkspaceLine line);
191 extern void AddWidgetToCollideList(Widget child);
192 extern void HideWidgetInCollideList(XmWorkspaceWidget ww, Widget child);
193 extern void DeleteWidgetFromCollideList(Widget child);
194 extern void RemoveLineFromCollideList(XmWorkspaceWidget ww,
195 XmWorkspaceLine line);
196 extern void AddLineToCollideList(XmWorkspaceWidget ww, XmWorkspaceLine line);
197
198 static void ClassInitialize ();
199 static void Initialize (XmWorkspaceWidget request,
200 XmWorkspaceWidget new);
201 static void Realize (XmWorkspaceWidget ww,
202 Mask* p_valueMask,
203 XSetWindowAttributes *attributes);
204 static void Destroy (XmWorkspaceWidget ww);
205 static void Redisplay (XmWorkspaceWidget ww,
206 XExposeEvent* event,
207 Region region);
208 static void Resize (XmWorkspaceWidget ww);
209 static Boolean RedisplayRectangle (XmWorkspaceWidget ww,
210 XRectangle* rect,
211 Region region,
212 Boolean clip_region_set);
213 static Boolean SetValues (XmWorkspaceWidget current,
214 XmWorkspaceWidget request,
215 XmWorkspaceWidget new);
216 static void ChangeManaged (XmWorkspaceWidget ww);
217 static XtGeometryResult
218 _GeometryManager (Widget w,
219 XtWidgetGeometry *request,
220 XtWidgetGeometry *reply,
221 Boolean adjust_constraints);
222 static XtGeometryResult
223 GeometryManager (Widget w,
224 XtWidgetGeometry *request,
225 XtWidgetGeometry *reply);
226 static void Arm (XmWorkspaceWidget ww,
227 XEvent* event);
228 static void Drag (XmWorkspaceWidget ww,
229 XEvent* event);
230 static void Disarm (XmWorkspaceWidget ww,
231 XEvent* event);
232 static void KeyboardNavigation (XmWorkspaceWidget ww,
233 XEvent* event);
234 static void ConstraintInitialize (Widget req,
235 Widget new);
236 static Boolean ConstraintSetValues (Widget current,
237 Widget request,
238 Widget new);
239 static void ConstraintDestroy (Widget w);
240 static void GetRubberbandGC (XmWorkspaceWidget ww);
241 static void DrawRubberband (XmWorkspaceWidget ww);
242 static void GrabSelections (Widget w,
243 XEvent* event,
244 String* params,
245 Cardinal* num_params);
246 static void MoveResizeSelections (Widget w,
247 XEvent* event,
248 String* params,
249 Cardinal* num_params);
250 static void ChildNavigation (Widget w,
251 XEvent* event,
252 String* params,
253 Cardinal* num_params);
254 #if RESIZE_HANDLES
255 static void ResizeNE (Widget w,
256 XEvent* event,
257 String* params,
258 Cardinal* num_params);
259 static void ResizeNW (Widget w,
260 XEvent* event,
261 String* params,
262 Cardinal* num_params);
263 static void ResizeSE (Widget w,
264 XEvent* event,
265 String* params,
266 Cardinal* num_params);
267 static void ResizeSW (Widget w,
268 XEvent* event,
269 String* params,
270 Cardinal* num_params);
271 static void NewDrop (Widget w,
272 XEvent* event,
273 String* params,
274 Cardinal* num_params);
275 #endif
276 static void DropSelections (Widget w,
277 XEvent* event,
278 String* params,
279 Cardinal* num_params);
280 static void RaiseSelections (Widget w,
281 XEvent* event,
282 String* params,
283 Cardinal* num_params);
284 static void MoveChild (XmWorkspaceWidget ww,
285 Widget child,
286 XmWorkspaceConstraints constraints);
287 static void ResetChild (XmWorkspaceWidget ww,
288 XmWorkspaceConstraints constraints);
289 static void SnapToGrid (XmWorkspaceWidget ww,
290 Widget child,
291 XmWorkspaceConstraints constraints,
292 Boolean increase);
293 static void Align1D (int* x,
294 int width,
295 int grid,
296 unsigned char alignment,
297 Boolean increase_only);
298 static void UpdateRubberbandSelections
299 (XmWorkspaceWidget ww,
300 XEvent* event);
301 static void UnselectAll (XmWorkspaceWidget ww,
302 XEvent* event);
303 static void SelectChild (XmWorkspaceWidget ww,
304 Widget child,
305 XmWorkspaceConstraints constraints,
306 XEvent* event);
307 static void UnselectChild (XmWorkspaceWidget ww,
308 Widget child,
309 XmWorkspaceConstraints constraints,
310 XEvent* event);
311 static void StartRubberband (XmWorkspaceWidget ww,
312 XEvent* event);
313 static void StretchRubberband (XmWorkspaceWidget ww,
314 XEvent* event);
315 static void EndRubberband (XmWorkspaceWidget ww,
316 XEvent* event);
317 static void AccentChild (XmWorkspaceWidget ww,
318 Widget child,
319 XmWorkspaceConstraints constraints,
320 XEvent* event);
321 static void UnaccentChild (XmWorkspaceWidget ww,
322 Widget child,
323 XmWorkspaceConstraints constraints,
324 XEvent* event);
325 static void UnaccentAll (XmWorkspaceWidget ww,
326 XEvent* event);
327 static void RestackSelectedChildren (XmWorkspaceWidget ww);
328 static Boolean ChildWindowIsSelected (XmWorkspaceWidget ww,
329 Window child);
330 static void SetGridBackground (XmWorkspaceWidget ww, Boolean change);
331 static void DrawGridMarks (XmWorkspaceWidget ww,
332 GC gc,
333 Pixmap pixmap);
334 static void OutlineChild (XRectangle* surrogate,
335 XmWorkspaceConstraints constraints);
336 static void SaveOutline (XmWorkspaceWidget ww,
337 Widget grab_child);
338 static void SaveOutlines (XmWorkspaceWidget ww);
339 static void DiscardSurrogate (XmWorkspaceWidget ww);
340 static void CreateSurrogate (XmWorkspaceWidget ww,
341 Widget grab_child);
342 static void DrawSurrogate (XmWorkspaceWidget ww);
343 static void MoveSurrogate (XmWorkspaceWidget ww,
344 int delta_x,
345 int delta_y);
346 static void ResizeSurrogate (XmWorkspaceWidget ww,
347 int width,
348 int height);
349 static Boolean PerformSpaceWars (XmWorkspaceWidget ww,
350 Boolean change_managed,
351 XEvent* event);
352 static Boolean ResolveOverlaps (XmWorkspaceWidget ww,
353 struct SortRec* sortlist,
354 Boolean* first_selected,
355 XEvent* event);
356 static Boolean MoveIfDisplaced (XmWorkspaceWidget ww,
357 struct SortRec *list,
358 int max_x,
359 int max_y);
360 static int MoveAToRightOfB (XmWorkspaceWidget ww,
361 struct SortRec* movee,
362 struct SortRec *mover,
363 XEvent* event);
364 static void RepositionSelectedChildren (struct SortRec* current,
365 short delta_x);
366 static struct SortRec* GetSortList (XmWorkspaceWidget ww,
367 Boolean change_managed,
368 struct SortRec** sortmem);
369 void RerouteLines (XmWorkspaceWidget ww,
370 Boolean reroute_all);
371 static void SetLineRoute (XmWorkspaceWidget ww,
372 XmWorkspaceLine new);
373 static Boolean DestroyLine (XmWorkspaceWidget ww,
374 XmWorkspaceLine old);
375 void AugmentExposureAreaForLine (XmWorkspaceWidget ww,
376 XmWorkspaceLine line);
377 static void UnsetExposureArea (XmWorkspaceWidget ww);
378 void RefreshLines (XmWorkspaceWidget ww);
379 static void InitLineGC (XmWorkspaceWidget ww,
380 int color);
381 static void CvtStringToWorkspaceType(XrmValue* args,
382 Cardinal num_args,
383 XrmValue* from_val,
384 XrmValue* to_val);
385 static Boolean StringsAreEqual (register char * in_str,
386 register char * test_str);
387 static void childRelative (XmWorkspaceWidget ww,
388 XEvent *xev, int *x, int *y);
389 static Boolean Overlapping( XmWorkspaceWidget , int , int );
390
391 void ReallocCollideLists(XmWorkspaceWidget ww);
392 static void MyInsertChild( Widget w);
393 static void MyDeleteChild( Widget w);
394 extern void MarkCommonLines(XmWorkspaceWidget ww);
395 static void dropResizedSurrogates (XmWorkspaceWidget ww, int delta_x, int delta_y, XEvent* event);
396
397 #if (OLD_LESSTIF == 1)
398 #define GetFormConstraint(w) (&((XmFormConstraints) (w)->core.constraints)->form)
399 #else
400 #define GetFormConstraint(w) (&((XmFormConstraintPtr) (w)->core.constraints)->form)
401 #endif
402
403 static XtResource defaultResources[] =
404 {
405 { XmNforceRoute, XmCForceRoute, XmRBoolean, sizeof(Boolean),
406 XtOffset(XmWorkspaceWidget, workspace.force_route),
407 XmRImmediate, (XtPointer) FALSE
408 },
409 {
410 XmNcollisionSpacing, XmCCollisionSpacing, XmRInt, sizeof(int),
411 XtOffset(XmWorkspaceWidget, workspace.collision_spacing),
412 XmRImmediate, (XtPointer) 20
413 },
414 {
415 XmNhaloThickness, XmCHaloThickness, XmRInt, sizeof(int),
416 XtOffset(XmWorkspaceWidget, workspace.halo_thickness),
417 XmRImmediate, (XtPointer) 2
418 },
419 {
420 XmNpositionChangeCallback, XmCPositionChangeCallback, XmRCallback, sizeof(XtPointer),
421 XtOffset(XmWorkspaceWidget, workspace.position_change_callback),
422 XmRCallback, NULL
423 },
424 {
425 XmNerrorCallback, XmCErrorCallback, XmRCallback, sizeof(XtPointer),
426 XtOffset(XmWorkspaceWidget, workspace.error_callback),
427 XmRCallback, NULL
428 },
429 {
430 XmNbackgroundCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
431 XtOffset(XmWorkspaceWidget, workspace.background_callback),
432 XmRPointer, (XtPointer) NULL
433 },
434 {
435 XmNdefaultActionCallback, XmCCallback, XmRCallback,
436 sizeof(XtCallbackList),
437 XtOffset(XmWorkspaceWidget, workspace.action_callback),
438 XmRPointer, (XtPointer) NULL
439 },
440 {
441 XmNselectionCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
442 XtOffset(XmWorkspaceWidget, workspace.selection_change_callback),
443 XmRPointer, (XtPointer) NULL
444 },
445 {
446 XmNresizeCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
447 XtOffset(XmWorkspaceWidget, workspace.resize_callback),
448 XmRPointer, (XtPointer) NULL
449 },
450 { XmNaccentColor, XmCAccentColor, XmRPixel, sizeof(Pixel),
451 XtOffset(XmWorkspaceWidget, workspace.accent_color),
452 XmRImmediate, (XtPointer) -1
453 },
454 { XmNaccentPolicy, XmCAccentPolicy,
455 XmRWorkspaceType, sizeof(unsigned char),
456 XtOffset(XmWorkspaceWidget, workspace.accent_policy),
457 XmRImmediate, (XtPointer) XmACCENT_BACKGROUND
458 },
459 { XmNallowMovement, XmCAllowMovement, XmRBoolean, sizeof(Boolean),
460 XtOffset(XmWorkspaceWidget, workspace.movement_is_allowed),
461 XmRImmediate, (XtPointer) TRUE
462 },
463 { XmNmanhattanRoute, XmCManhattanRoute, XmRBoolean, sizeof(Boolean),
464 XtOffset(XmWorkspaceWidget, workspace.manhattan_route),
465 XmRImmediate, (XtPointer) FALSE
466 },
467 { XmNgridWidth, XmCGridWidth, XmRShort, sizeof(short),
468 XtOffset(XmWorkspaceWidget, workspace.grid_width),
469 XmRImmediate, (XtPointer) 1
470 },
471 { XmNgridHeight, XmCGridHeight, XmRShort, sizeof(short),
472 XtOffset(XmWorkspaceWidget, workspace.grid_height),
473 XmRImmediate, (XtPointer) 1
474 },
475 { XmNhorizontalAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
476 XtOffset(XmWorkspaceWidget, workspace.horizontal_alignment),
477 XmRImmediate, (XtPointer) XmALIGNMENT_CENTER
478 },
479 { XmNhorizontalDrawGrid, XmCDrawGrid,
480 XmRWorkspaceType, sizeof(unsigned char),
481 XtOffset(XmWorkspaceWidget, workspace.horizontal_draw_grid),
482 XmRImmediate, (XtPointer) XmDRAW_NONE
483 },
484 { XmNverticalAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
485 XtOffset(XmWorkspaceWidget, workspace.vertical_alignment),
486 XmRImmediate, (XtPointer) XmALIGNMENT_CENTER
487 },
488 { XmNverticalDrawGrid, XmCDrawGrid,
489 XmRWorkspaceType, sizeof(unsigned char),
490 XtOffset(XmWorkspaceWidget, workspace.vertical_draw_grid),
491 XmRImmediate, (XtPointer) XmDRAW_NONE
492 },
493 { XmNsortPolicy, XmCAlignment, XmRAlignment, sizeof(unsigned char),
494 XtOffset(XmWorkspaceWidget, workspace.sort_policy),
495 XmRImmediate, (XtPointer) XmALIGNMENT_CENTER
496 },
497 { XmNsnapToGrid, XmCSnapToGrid, XmRBoolean, sizeof(Boolean),
498 XtOffset(XmWorkspaceWidget, workspace.snap_to_grid),
499 XmRImmediate, (XtPointer) FALSE
500 },
501 { XmNlineThickness, XmCLineThickness, XmRShort, sizeof(short),
502 XtOffset(XmWorkspaceWidget, workspace.line_thickness),
503 XmRImmediate, (XtPointer) 0
504 },
505 { XmNdoubleClickInterval, XmCDoubleClickInterval, XmRInt, sizeof(int),
506 XtOffset(XmWorkspaceWidget, workspace.double_click_interval),
507 XmRImmediate, (XtPointer) 500
508 },
509 { XmNinclusionPolicy, XmCInclusionPolicy,
510 XmRWorkspaceType, sizeof(unsigned char),
511 XtOffset(XmWorkspaceWidget, workspace.inclusion_policy),
512 XmRImmediate, (XtPointer) XmINCLUDE_ALL
513 },
514 { XmNselectionPolicy, XmCSelectionPolicy,
515 XmRSelectionPolicy, sizeof(unsigned char),
516 XtOffset(XmWorkspaceWidget, workspace.selection_policy),
517 XmRImmediate, (XtPointer) XmEXTENDED_SELECT
518 },
519 { XmNoutlineType, XmCOutlineType,
520 XmRWorkspaceType, sizeof(unsigned char),
521 XtOffset(XmWorkspaceWidget, workspace.surrogate_type),
522 XmRImmediate, (XtPointer) XmOUTLINE_EACH
523 },
524 { XmNplacementPolicy, XmCPlacementPolicy, XmRChar, sizeof(unsigned char),
525 XtOffset(XmWorkspaceWidget, workspace.placement_policy),
526 XmRImmediate, (XtPointer) XmSPACE_WARS_SELECTED_STAYS
527 },
528 { XmNbutton1PressMode, XmCButton1PressMode, XmRBoolean, sizeof(Boolean),
529 XtOffset(XmWorkspaceWidget, workspace.button1_press_mode),
530 XmRImmediate, (XtPointer) True
531 },
532 { XmNlineTolerance, XmCLineTolerance, XmRInt, sizeof(int),
533 XtOffset(XmWorkspaceWidget, workspace.ltol),
534 XmRImmediate, (XtPointer) 2
535 },
536 { XmNwidgetTolerance, XmCWidgetTolerance, XmRInt, sizeof(int),
537 XtOffset(XmWorkspaceWidget, workspace.wtol),
538 XmRImmediate, (XtPointer) 1
539 },
540 { XmNlineDrawingEnabled, XmCLineDrawingEnabled, XmRBoolean, sizeof(Boolean),
541 XtOffset(XmWorkspaceWidget, workspace.line_drawing_enabled),
542 XmRImmediate, (XtPointer) True
543 },
544 { XmNselectable, XmCSelectable, XmRBoolean, sizeof(Boolean),
545 XtOffset(XmWorkspaceWidget, workspace.is_selectable),
546 XmRImmediate, (XtPointer) TRUE
547 },
548 { XmNpreventOverlap, XmCAllowOverlap, XmRBoolean, sizeof(Boolean),
549 XtOffset(XmWorkspaceWidget, workspace.check_overlap),
550 XmRImmediate, (XtPointer) FALSE
551 },
552 { XmNautoArrange, XmCAutoArrange, XmRBoolean, sizeof(Boolean),
553 XtOffset(XmWorkspaceWidget, workspace.auto_arrange),
554 XmRImmediate, (XtPointer) FALSE
555 }
556 };
557
558 #define OFFSET_DEFAULT -1
559 static XtResource constraintResources[] = {
560 { XmNselectionCallback, XmCSelectionCallback,
561 XmRCallback, sizeof(WsCallbackList),
562 XtOffset(XmWorkspaceConstraints, workspace.select_callbacks),
563 XmRImmediate, (XtPointer) NULL
564 },
565 { XmNresizingCallback, XmCResizingCallback,
566 XmRCallback, sizeof(WsCallbackList),
567 XtOffset(XmWorkspaceConstraints, workspace.resizing_callbacks),
568 XmRImmediate, (XtPointer) NULL
569 },
570 { XmNaccentCallback, XmCAccentCallback, XmRCallback,sizeof(WsCallbackList),
571 XtOffset(XmWorkspaceConstraints, workspace.accent_callbacks),
572 XmRImmediate, (XtPointer) NULL
573 },
574 { XmNselectable, XmCSelectable, XmRBoolean, sizeof(Boolean),
575 XtOffset(XmWorkspaceConstraints, workspace.is_selectable),
576 XmRImmediate, (XtPointer) TRUE
577 },
578 { XmNselected, XmCSelected, XmRBoolean, sizeof(Boolean),
579 XtOffset(XmWorkspaceConstraints, workspace.is_selected),
580 XmRImmediate, (XtPointer) FALSE
581 },
582 { XmNid, XmCId, XmRChar, sizeof(char),
583 XtOffset(XmWorkspaceConstraints, workspace.id), XmRImmediate, (XtPointer) 0
584 },
585 { XmNallowVerticalResizing, XmCAllowResizing, XmRBoolean, sizeof(Boolean),
586 XtOffset(XmWorkspaceConstraints, workspace.is_v_resizable),
587 XmRImmediate, (XtPointer) FALSE
588 },
589 { XmNallowHorizontalResizing, XmCAllowResizing, XmRBoolean, sizeof(Boolean),
590 XtOffset(XmWorkspaceConstraints, workspace.is_h_resizable),
591 XmRImmediate, (XtPointer) FALSE
592 },
593 { XmNpinLeftRight, XmCPinSides, XmRBoolean, sizeof(Boolean),
594 XtOffset(XmWorkspaceConstraints, workspace.pin_to_sides_lr),
595 XmRImmediate, (XtPointer) FALSE
596 },
597 { XmNpinTopBottom, XmCPinSides, XmRBoolean, sizeof(Boolean),
598 XtOffset(XmWorkspaceConstraints, workspace.pin_to_sides_tb),
599 XmRImmediate, (XtPointer) FALSE
600 },
601 {
602 XmNwwTopAttachment, XmCAttachment, XmRAttachment, sizeof(unsigned char),
603 XtOffset(XmWorkspaceConstraints, workspace.att[FC_TOP].type),
604 XmRImmediate, (XtPointer) XmATTACH_NONE
605 },
606 {
607 XmNwwBottomAttachment, XmCAttachment, XmRAttachment, sizeof(unsigned char),
608 XtOffset(XmWorkspaceConstraints, workspace.att[FC_BOTTOM].type),
609 XmRImmediate, (XtPointer) XmATTACH_NONE
610 },
611 {
612 XmNwwLeftAttachment, XmCAttachment, XmRAttachment, sizeof(unsigned char),
613 XtOffset(XmWorkspaceConstraints, workspace.att[FC_LEFT].type),
614 XmRImmediate, (XtPointer) XmATTACH_NONE
615 },
616 {
617 XmNwwRightAttachment, XmCAttachment, XmRAttachment, sizeof(unsigned char),
618 XtOffset(XmWorkspaceConstraints, workspace.att[FC_RIGHT].type),
619 XmRImmediate, (XtPointer) XmATTACH_NONE
620 },
621 {
622 XmNwwTopWidget, XmCWidget, XmRWindow, sizeof(Widget),
623 XtOffset(XmWorkspaceConstraints, workspace.att[FC_TOP].w),
624 XmRWindow, (XtPointer) NULL
625 },
626 {
627 XmNwwBottomWidget, XmCWidget, XmRWindow, sizeof(Widget),
628 XtOffset(XmWorkspaceConstraints, workspace.att[FC_BOTTOM].w),
629 XmRWindow, (XtPointer) NULL
630 },
631 {
632 XmNwwLeftWidget, XmCWidget, XmRWindow, sizeof(Widget),
633 XtOffset(XmWorkspaceConstraints, workspace.att[FC_LEFT].w),
634 XmRWindow, (XtPointer) NULL
635 },
636 {
637 XmNwwRightWidget, XmCWidget, XmRWindow, sizeof(Widget),
638 XtOffset(XmWorkspaceConstraints, workspace.att[FC_RIGHT].w),
639 XmRWindow, (XtPointer) NULL
640 },
641 {
642 XmNwwTopPosition, XmCAttachment, XmRInt, sizeof(int),
643 XtOffset(XmWorkspaceConstraints, workspace.att[FC_TOP].percent),
644 XmRImmediate, (XtPointer) 0
645 },
646 {
647 XmNwwBottomPosition, XmCAttachment, XmRInt, sizeof(int),
648 XtOffset(XmWorkspaceConstraints, workspace.att[FC_BOTTOM].percent),
649 XmRImmediate, (XtPointer) 0
650 },
651 {
652 XmNwwLeftPosition, XmCAttachment, XmRInt, sizeof(int),
653 XtOffset(XmWorkspaceConstraints, workspace.att[FC_LEFT].percent),
654 XmRImmediate, (XtPointer) 0
655 },
656 {
657 XmNwwRightPosition, XmCAttachment, XmRInt, sizeof(int),
658 XtOffset(XmWorkspaceConstraints, workspace.att[FC_RIGHT].percent),
659 XmRImmediate, (XtPointer) 0
660 },
661 {
662 XmNwwTopOffset, XmCOffset, XmRInt, sizeof(int),
663 XtOffset(XmWorkspaceConstraints, workspace.att[FC_TOP].offset),
664 XmRImmediate, (XtPointer) (Dimension) OFFSET_DEFAULT
665 },
666 {
667 XmNwwBottomOffset, XmCOffset, XmRInt, sizeof(int),
668 XtOffset(XmWorkspaceConstraints, workspace.att[FC_BOTTOM].offset),
669 XmRImmediate, (XtPointer) (Dimension) OFFSET_DEFAULT
670 },
671 {
672 XmNwwLeftOffset, XmCOffset, XmRInt, sizeof(int),
673 XtOffset(XmWorkspaceConstraints, workspace.att[FC_LEFT].offset),
674 XmRImmediate, (XtPointer) (Dimension) OFFSET_DEFAULT
675 },
676
677 {
678 XmNwwRightOffset, XmCOffset, XmRInt, sizeof(int),
679 XtOffset(XmWorkspaceConstraints, workspace.att[FC_RIGHT].offset),
680 XmRImmediate, (XtPointer) (Dimension) OFFSET_DEFAULT
681 },
682 {
683 XmNlineInvisibility, XmCLineInvisibility, XmRBoolean, sizeof(Boolean),
684 XtOffset(XmWorkspaceConstraints, workspace.line_invisibility),
685 XmRImmediate, (XtPointer) FALSE
686 },
687 };
688
689
690
691 /* This translation table maps to rubberbanding actions */
692 static char defaultTranslations[] =
693 "<Btn1Down>: arm() \n\
694 <Btn1Motion>: drag()\n\
695 <Key>osfHelp: ManagerGadgetHelp()\n\
696 <Key>: kbd_nav()\n\
697 <Btn1Up>: disarm()";
698
699 /* Translation table to be installed on the children for selection actions */
700 static char acceleratorTranslations[] = "#override\n\
701 <Btn1Motion>: move_w()\n\
702 <Btn1Down>: select_w()\n\
703 <Btn1Up>(2+): select_w() release_w() select_w() release_w()\n\
704 <Key>osfUp: child_nav()\n\
705 <Key>osfDown: child_nav()\n\
706 <Key>osfLeft: child_nav()\n\
707 <Key>osfRight: child_nav()\n\
708 <Btn1Up>: release_w()";
709
710 static char traversalTranslations[] =
711 "<EnterWindow>: ManagerEnter()\n\
712 <LeaveWindow>: ManagerLeave()\n\
713 <FocusOut>: ManagerFocusOut()\n\
714 <FocusIn>: ManagerFocusIn()";
715
716
717 XtActionsRec defaultActions[] = {
718 {"arm", (XtActionProc)Arm},
719 {"drag", (XtActionProc)Drag},
720 {"disarm", (XtActionProc)Disarm},
721 {"kbd_nav", (XtActionProc)KeyboardNavigation},
722 {"select_w", (XtActionProc)GrabSelections },
723 {"move_w", (XtActionProc)MoveResizeSelections },
724 {"child_nav", (XtActionProc)ChildNavigation},
725 #if RESIZE_HANDLES
726 {"grow_ne", (XtActionProc)ResizeNE },
727 {"grow_nw", (XtActionProc)ResizeNW },
728 {"grow_se", (XtActionProc)ResizeSE },
729 {"grow_sw", (XtActionProc)ResizeSW },
730 {"new_release", (XtActionProc)NewDrop },
731 #endif
732 {"release_w", (XtActionProc)DropSelections },
733 {"raise", (XtActionProc)RaiseSelections },
734 { "Enter", (XtActionProc) _XmManagerEnter }, /* Motif 1.0 */
735 { "FocusIn", (XtActionProc) _XmManagerFocusIn }, /* Motif 1.0 */
736 };
737
738
739 /*
740 * Workspace class record definition:
741 */
742 XmWorkspaceClassRec xmWorkspaceClassRec = {
743 /*
744 * CoreClassPart:
745 */
746 {
747 (WidgetClass)&xmFormClassRec,/* superclass */
748 "XmWorkspace", /* class_name */
749 sizeof(XmWorkspaceRec), /* widget_size */
750 ClassInitialize, /* class_initialize */
751 (XtWidgetClassProc) NULL, /* class_part_initialize */
752 FALSE, /* class_inited */
753 (XtInitProc)Initialize, /* initialize */
754 (XtArgsProc) NULL, /* initialize_hook */
755 (XtRealizeProc)Realize, /* realize */
756 defaultActions, /* actions */
757 XtNumber(defaultActions), /* num_actions */
758 defaultResources, /* resources */
759 XtNumber(defaultResources), /* num_resources */
760 NULLQUARK, /* xrm_class */
761 TRUE, /* compress_motion */
762 TRUE, /* compress_exposure */
763 TRUE, /* compress_enterleave */
764 TRUE, /* visible_interest */
765 (XtWidgetProc)Destroy, /* destroy */
766 (XtWidgetProc) Resize, /* resize */
767 (XtExposeProc)Redisplay, /* expose */
768 (XtSetValuesFunc)SetValues, /* set_values */
769 (XtArgsFunc) NULL, /* set_values_hook */
770 XtInheritSetValuesAlmost, /* set_values_almost */
771 (XtArgsProc) NULL, /* get_values_hook */
772 XtInheritAcceptFocus, /* accept_focus */
773 XtVersion, /* version */
774 NULL, /* callback private */
775 defaultTranslations, /* tm_table */
776 XtInheritQueryGeometry, /* query_geometry */
777 XtInheritDisplayAccelerator, /* display_accelerator */
778 (void *) NULL, /* extension */
779 },
780 /*
781 * CompositeClassPart: composite_class
782 */
783 {
784 GeometryManager, /* geometry_manager */
785 (XtWidgetProc)ChangeManaged, /* change_managed */
786 MyInsertChild, /* insert_child */
787 MyDeleteChild, /* delete_child */
788 (void *) NULL, /* extension */
789 },
790 /*
791 * ConstraintClassPart: constraint_class
792 */
793 {
794 constraintResources, /* resource list */
795 XtNumber(constraintResources), /* num resources */
796 sizeof(XmWorkspaceConstraintRec), /* constraint size */
797 (XtInitProc)ConstraintInitialize, /* init proc */
798 ConstraintDestroy, /* destroy proc */
799 (XtSetValuesFunc)ConstraintSetValues, /* set values proc */
800 (void *) NULL, /* extension */
801 },
802 /*
803 * XmManagerClassPart: manager_class
804 */
805 {
806 traversalTranslations, /* translations */
807 NULL, /* get resources */
808 0, /* num get_resources */
809 NULL, /* get_cont_resources */
810 0, /* num_get_cont_resources */
811 (XmParentProcessProc)NULL, /* parent_process */
812 NULL, /* extension */
813 },
814 { /* bulletin_board_class fields */
815 FALSE, /* always_install_accelerators */
816 NULL, /* geo_matrix_create */
817 XmInheritFocusMovedProc, /* focus_moved_proc */
818 NULL, /* extension */
819 },
820
821 { /* form_class fields */
822 NULL, /* extension */
823 },
824
825 /*
826 * XmWorkspaceClassPart: workspace_class
827 */
828 {
829 NULL, /* lineGC */
830 NULL, /* lineGC2 */
831 None, /* hour_glass */
832 None, /* move_cursor */
833 { None, None, None, None }, /* size_cursor[4] */
834 NULL,
835 }
836 };
837
838 WidgetClass xmWorkspaceWidgetClass = (WidgetClass)&xmWorkspaceClassRec;
839
840 /* Subroutine: MyDeleteChild
841 * Purpose: Add a child and populate the collision array
842 */
MyDeleteChild(Widget w)843 static void MyDeleteChild(Widget w)
844 {
845 XmWorkspaceConstraints nc;
846 nc = WORKSPACE_CONSTRAINT(w);
847 if (!nc->workspace.line_invisibility)
848 DeleteWidgetFromCollideList(w);
849 (*superclass->composite_class.delete_child) (w);
850 }
851
852 /* Subroutine: MyInsertChild
853 * Purpose: Add a child and populate the collision array
854 */
MyInsertChild(Widget w)855 static void MyInsertChild( Widget w)
856 {
857 Dimension new_width, new_height;
858 Dimension old_width, old_height;
859 XmWorkspaceWidget ww;
860 XtWidgetGeometry request, reply;
861 XtGeometryResult result;
862 XmWorkspaceConstraints nc;
863
864 (*superclass->composite_class.insert_child) (w);
865 ww = (XmWorkspaceWidget)w->core.parent;
866 /* The folloing code will dynamically resize the workspace widget if a
867 a child is inserted beyond the current width and height. If the
868 parent does not allow the resize, punt with an XtWarning. The
869 size of the collision lists are then resized.
870 */
871 new_width = w->core.x + w->core.width;
872 old_width = XtWidth(ww);
873 new_width = MAX(new_width, old_width);
874
875 new_height = w->core.y + w->core.height;
876 old_height = XtHeight(ww);
877 new_height = MAX(new_height, old_height);
878
879 if ( (new_width > old_width) || (new_height > old_height) )
880 {
881 request.width = new_width + 2*(ww->workspace.grid_width);
882 request.height = new_height + 2*(ww->workspace.grid_width);
883 request.request_mode = CWWidth | CWHeight;
884 result = XtMakeGeometryRequest((Widget)ww, &request, &reply);
885 if(result != XtGeometryYes)
886 {
887 XtWarning("Geometry Request failed in Workspace.InsertChild.");
888 return;
889 }
890 ReallocCollideLists(ww);
891 }
892 nc = WORKSPACE_CONSTRAINT(w);
893 if (!nc->workspace.line_invisibility)
894 AddWidgetToCollideList(w);
895 }
896
897 /* Subroutine: ClassInitialize
898 * Purpose: Install non-standard type converters needed by this widget class
899 */
ClassInitialize()900 static void ClassInitialize( )
901 {
902 /* Install resource converter to parse strings in Xdefaults file */
903 XtAddConverter(XmRString, XmRWorkspaceType,
904 (XtConverter)CvtStringToWorkspaceType, NULL, 0);
905 }
906
907
908 /* Subroutine: Initialize
909 * Purpose: Initialize the workspace widget instance
910 */
Initialize(XmWorkspaceWidget request,XmWorkspaceWidget new)911 static void Initialize( XmWorkspaceWidget request, XmWorkspaceWidget new )
912 {
913 XtTranslations trans_table;
914 Arg warg;
915
916 /* Contrary to what is promised, record is not initially cleared */
917 new->workspace.suppress_callbacks = False;
918 new->workspace.num_selected = 0;
919 new->workspace.is_rubberbanding = FALSE;
920 new->workspace.is_moving = FALSE;
921 new->workspace.is_resizing = FALSE;
922 new->workspace.band_is_visible = FALSE;
923 new->workspace.surrogate_is_visible = FALSE;
924 new->workspace.bandGC = NULL;
925 new->workspace.badBandGC = NULL;
926 new->workspace.gridGC = NULL;
927 new->workspace.num_surrogates = 0;
928 new->workspace.lines = NULL;
929 new->workspace.num_lines = 0;
930 new->workspace.button_tracker = NULL;
931 new->workspace.time = 0;
932 new->workspace.move_cursor_installed = 0;
933 new->workspace.size_xx_installed = SZ_NONE;
934 new->workspace.auto_arrange = FALSE;
935
936 GetRubberbandGC(new);
937 if( xmWorkspaceClassRec.workspace_class.move_cursor == None )
938 xmWorkspaceClassRec.workspace_class.move_cursor =
939 XCreateFontCursor(XtDisplay(new), XC_fleur);
940 if( xmWorkspaceClassRec.workspace_class.hour_glass == None )
941 xmWorkspaceClassRec.workspace_class.hour_glass =
942 XCreateFontCursor(XtDisplay(new), XC_watch);
943 if( xmWorkspaceClassRec.workspace_class.size_cursor[SZ_UL] == None )
944 xmWorkspaceClassRec.workspace_class.size_cursor[SZ_UL] =
945 XCreateFontCursor(XtDisplay(new), XC_ul_angle);
946 if( xmWorkspaceClassRec.workspace_class.size_cursor[SZ_UR] == None )
947 xmWorkspaceClassRec.workspace_class.size_cursor[SZ_UR] =
948 XCreateFontCursor(XtDisplay(new), XC_ur_angle);
949 if( xmWorkspaceClassRec.workspace_class.size_cursor[SZ_LL] == None )
950 xmWorkspaceClassRec.workspace_class.size_cursor[SZ_LL] =
951 XCreateFontCursor(XtDisplay(new), XC_ll_angle);
952 if( xmWorkspaceClassRec.workspace_class.size_cursor[SZ_LR] == None )
953 xmWorkspaceClassRec.workspace_class.size_cursor[SZ_LR] =
954 XCreateFontCursor(XtDisplay(new), XC_lr_angle);
955 new->workspace.collide_width = new->core.width;
956 new->workspace.collide_height = new->core.height;
957 new->workspace.collide_list_x =
958 (CollideList **)XtCalloc(new->core.width, sizeof(new->workspace.collide_list_x));
959 new->workspace.collide_list_y =
960 (CollideList **)XtCalloc(new->core.height, sizeof(new->workspace.collide_list_y));
961 new->workspace.widget_list = NULL;
962
963 /* Adjust wtol and ltol to be a multiple of the line thickness */
964 new->workspace.wtol = (new->workspace.wtol*new->workspace.line_thickness)/2;
965 new->workspace.ltol = new->workspace.ltol * new->workspace.line_thickness;
966
967 UnsetExposureArea(new);
968
969 /*
970 * calling XtSetValues inside the Initialize method is a bad
971 * thing since the SetValues method will then be called on a widget
972 * whose initialization process hasn't completed.
973 *
974 */
975
976 trans_table = XtParseTranslationTable (defaultTranslations);
977 XtSetArg (warg, XmNtranslations, trans_table);
978 #if 0
979 // Don't check this in -MST
980 //XtSetValues ((Widget)new, &warg, 1);
981 #endif
982 }
983
984
985 /* Subroutine: Realize
986 */
Realize(XmWorkspaceWidget ww,Mask * p_valueMask,XSetWindowAttributes * attributes)987 static void Realize( XmWorkspaceWidget ww, Mask* p_valueMask,
988 XSetWindowAttributes *attributes )
989 {
990 XmWorkspaceConstraints constraints;
991 Mask valueMask;
992 int i;
993 Widget child;
994 XMapEvent event;
995
996 if( ww->workspace.accent_color == ((Pixel)(-1)) )
997 {
998 Display *display = XtDisplay(ww);
999 ww->workspace.accent_color =
1000 WhitePixel(display, XScreenNumberOfScreen(XtScreen(ww)));
1001 }
1002 valueMask = *p_valueMask | CWBitGravity | CWDontPropagate;
1003 attributes->bit_gravity = NorthWestGravity;
1004
1005 attributes->do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask
1006 | KeyPressMask | KeyReleaseMask | PointerMotionMask;
1007 XtCreateWindow((Widget)ww, InputOutput, CopyFromParent, valueMask, attributes);
1008 /* Create a background pixmap with grid lines, if warranted */
1009 SetGridBackground(ww, FALSE);
1010 /* Accents pre-selected children and then perform selection */
1011 /* Fake a map event to pass in the callback */
1012 event.type = MapNotify;
1013 event.event = XtWindow(ww);
1014 event.send_event = TRUE;
1015 event.display = XtDisplay(ww);
1016 event.override_redirect = FALSE;
1017 for( i=0; i<ww->composite.num_children; i++ ) {
1018 child = ww->composite.children[i];
1019 constraints = WORKSPACE_CONSTRAINT(child);
1020 if( constraints->workspace.is_selected )
1021 {
1022 constraints->workspace.is_selected = FALSE;
1023 /* SelectChild will include call to AccentChild */
1024 event.window = XtWindow(child);
1025 SelectChild(ww, child, constraints, (XEvent *)&event);
1026 }
1027 }
1028 }
1029
1030
1031 /* Subroutine: Destroy
1032 * Purpose: Clean up allocated resources when the widget is destroyed.
1033 */
Destroy(XmWorkspaceWidget ww)1034 static void Destroy( XmWorkspaceWidget ww )
1035 {
1036 CollideList **cl_ptr;
1037 CollideList *ce_ptr;
1038 CollideList *n_ce_ptr;
1039 int i;
1040 MyWidgetList *wl_ptr, *rove;
1041
1042 if( ww->workspace.gridGC )
1043 XtReleaseGC((Widget)ww, ww->workspace.gridGC);
1044 if( ww->workspace.bandGC )
1045 XtReleaseGC((Widget)ww, ww->workspace.bandGC);
1046 if( ww->workspace.badBandGC )
1047 XtReleaseGC((Widget)ww, ww->workspace.badBandGC);
1048 XtRemoveAllCallbacks((Widget)ww, XmNbackgroundCallback);
1049 XtRemoveAllCallbacks((Widget)ww, XmNdefaultActionCallback);
1050 XtRemoveAllCallbacks((Widget)ww, XmNerrorCallback);
1051 XtRemoveAllCallbacks((Widget)ww, XmNpositionChangeCallback);
1052
1053
1054 /* Free the collision lists */
1055 cl_ptr = ww->workspace.collide_list_x;
1056 for (i = 0; i < ww->workspace.collide_width; ++i)
1057 {
1058 for (ce_ptr = cl_ptr[i]; ce_ptr; ce_ptr = n_ce_ptr)
1059 {
1060 n_ce_ptr = ce_ptr->next;
1061 XtFree((char*)ce_ptr);
1062 }
1063 }
1064 XtFree((char*)cl_ptr);
1065
1066 cl_ptr = ww->workspace.collide_list_y;
1067 for (i = 0; i < ww->workspace.collide_height; ++i)
1068 {
1069 for (ce_ptr = cl_ptr[i]; ce_ptr; ce_ptr = n_ce_ptr)
1070 {
1071 n_ce_ptr = ce_ptr->next;
1072 XtFree((char*)ce_ptr);
1073 }
1074 }
1075 XtFree((char*)cl_ptr);
1076
1077 /*
1078 * Free the widget list
1079 */
1080 wl_ptr = ww->workspace.widget_list;
1081 while (wl_ptr) {
1082 rove = wl_ptr->next;
1083 XtFree((char*)wl_ptr);
1084 wl_ptr = rove;
1085 }
1086 }
1087
1088 #if STRETCH_SEPARATORS
1089 static void unobstructedHoriz (XmWorkspaceWidget , Widget , int *, int*);
1090 #endif
1091
Resize(XmWorkspaceWidget ww)1092 static void Resize( XmWorkspaceWidget ww)
1093 {
1094 XmWorkspaceCallbackStruct cb;
1095
1096 if (ww->workspace.auto_arrange)
1097 (*superclass->core_class.resize) ((Widget)ww);
1098 if (!XtIsRealized((Widget)ww))
1099 return;
1100
1101 #if STRETCH_SEPARATORS
1102 {
1103 XtWidgetGeometry req;
1104 int i, bw;
1105 Widget child;
1106 XmWorkspaceConstraints cons;
1107
1108 /*
1109 * if !auto_arrange_mode then see if there are widgets who want
1110 * want to be pinned top/bottom or left/right. Separator widgets
1111 * in ControlPanels want this.
1112 */
1113 if (!ww->workspace.auto_arrange) {
1114 int smallx, bigx, bigy;
1115 XmWorkspaceGetMaxWidthHeight ((Widget)ww, &bigx, &bigy);
1116 for (i=0; i<ww->composite.num_children; i++) {
1117 child = ww->composite.children[i];
1118 cons = WORKSPACE_CONSTRAINT(child);
1119 if ((cons->workspace.pin_to_sides_lr == False) &&
1120 (cons->workspace.pin_to_sides_tb == False)) continue;
1121 req.x = child->core.x;
1122 req.y = child->core.y;
1123 req.width = child->core.width;
1124 req.height = child->core.height;
1125 bw = child->core.border_width;
1126 req.request_mode = 0;
1127 /* refuse to pin left,right and top.bottom */
1128 if (cons->workspace.pin_to_sides_lr) {
1129 smallx = 0;
1130 unobstructedHoriz (ww, child, &smallx, &bigx);
1131 req.x = smallx;
1132 req.width = bigx - smallx;
1133 if (child->core.x > req.x) req.request_mode|= CWX;
1134 if (child->core.width != req.width) req.request_mode|= CWWidth;
1135 } else if (cons->workspace.pin_to_sides_tb) {
1136 }
1137 XtConfigureWidget (child, req.x, req.y, req.width, req.height, bw);
1138 _GeometryManager (child, &req, NULL, False);
1139 }
1140 }
1141 }
1142 #endif
1143
1144 ReallocCollideLists(ww);
1145
1146 cb.reason = XmCR_RESIZE;
1147 cb.event = NULL;
1148 cb.window = XtWindow(ww);
1149 cb.selected_widget = NULL;
1150 XtCallCallbackList ((Widget)ww, ww->workspace.resize_callback, &cb);
1151 }
1152
1153 #if STRETCH_SEPARATORS
1154 /*
1155 * assumes the outputs are initialized by the caller.
1156 */
1157 static void
unobstructedHoriz(XmWorkspaceWidget ww,Widget cw,int * lx,int * rx)1158 unobstructedHoriz (XmWorkspaceWidget ww, Widget cw, int *lx, int *rx)
1159 {
1160 int i, minx, maxx, cw_bottom, cw_right, this_bottom, this_right;
1161 Boolean overlap;
1162 Widget child;
1163 XmWorkspaceConstraints cons;
1164
1165 minx = *lx;
1166 maxx = *rx;
1167
1168 cw_bottom = cw->core.y + cw->core.height;
1169 cw_right = maxx;
1170
1171 for (i=0; i<ww->composite.num_children; i++) {
1172 child = ww->composite.children[i];
1173 if (child == cw) continue;
1174 cons = WORKSPACE_CONSTRAINT(child);
1175
1176 this_bottom = child->core.y + child->core.height;
1177 this_right = child->core.x + child->core.width;
1178 if ((child->core.y > cw_bottom)||
1179 (cw->core.y > this_bottom)) overlap = False;
1180 else if (child->core.x > cw_right) overlap = False;
1181 else overlap = True;
1182
1183 if (overlap) {
1184 minx = MAX(minx, this_right+1);
1185 }
1186
1187 if ((child->core.y > cw_bottom)||
1188 (cw->core.y > this_bottom)) overlap = False;
1189 else if (child->core.x < cw->core.x) overlap = False;
1190 else overlap = True;
1191
1192 if (overlap) {
1193 maxx = MIN(maxx, child->core.x-1);
1194 }
1195
1196 }
1197
1198 *lx = minx;
1199 *rx = maxx;
1200 }
1201 #endif
1202
1203
1204 /* Subroutine: Expose
1205 * Effect: Redraw portion of the window exposed by movement of other
1206 * windows
1207 * Note: Redrawing of xor'd features must be precisely fit to
1208 * regions newly exposed.
1209 */
1210 #define IF_MORE(a,b) if((a)>(b))(b)=(a)
1211 #define IF_LESS(a,b) if((a)<(b))(b)=(a)
Redisplay(XmWorkspaceWidget ww,XExposeEvent * event,Region region)1212 static void Redisplay( XmWorkspaceWidget ww, XExposeEvent* event,
1213 Region region )
1214 {
1215 int i;
1216 Boolean clip_region_set = FALSE;
1217 short line_excess;
1218
1219 if (ww->workspace.auto_arrange)
1220 (*superclass->core_class.expose) ((Widget)ww, (XEvent *)event, region);
1221
1222 if( !XtIsRealized((Widget)ww) )
1223 return;
1224 /* The user can enter events while the application is in the process of *
1225 * rearranging its windows. Since the server may be slow to make all of *
1226 * the changes, events can be entered during meaningless intermediate *
1227 * states. */
1228 /* Discard or suppress all events that represent user input. Do not let *
1229 * these events get queued up for later processing. Expose events must *
1230 * still be accepted as they are used to synchronize changes and *
1231 * redrawing. */
1232 line_excess = ww->workspace.line_thickness / 2;
1233 /* Augment exposure rectangle (in case it's already being augmented) */
1234 IF_LESS(event->x - line_excess, ww->workspace.expose_left);
1235 IF_MORE(line_excess + event->width + event->x - 1,
1236 ww->workspace.expose_right);
1237 IF_LESS(event->y - line_excess, ww->workspace.expose_upper);
1238 IF_MORE(line_excess + event->y + event->height - 1,
1239 ww->workspace.expose_lower);
1240 /* Redraw application lines if needed (uses exposure rectangle) */
1241 if( ww->workspace.lines )
1242 RefreshLines(ww);
1243 /* Grid lines are handled by server as background pixmap so do nothing */
1244 /* Redraw rubberband bounding box, if visible */
1245 if( ww->workspace.band_is_visible )
1246 {
1247 if( RedisplayRectangle(ww, ww->workspace.rubberband, region,
1248 clip_region_set) )
1249 XSetClipMask(XtDisplay(ww), ww->workspace.bandGC, None);
1250 }
1251 /* Redraw surrogate outline(s), if visible */
1252 else if( ww->workspace.surrogate_is_visible )
1253 {
1254 for( i=0; i<ww->workspace.num_surrogates; i++ )
1255 clip_region_set =
1256 RedisplayRectangle(ww, &ww->workspace.surrogates[i], region,
1257 clip_region_set);
1258 /* Restore Clipping mask to None */
1259 if( clip_region_set )
1260 XSetClipMask(XtDisplay(ww), ww->workspace.bandGC, None);
1261 }
1262 UnsetExposureArea(ww);
1263 }
1264 #undef IF_MORE
1265 #undef IF_LESS
1266
1267
RedisplayRectangle(XmWorkspaceWidget ww,XRectangle * rect,Region region,Boolean clip_region_set)1268 static Boolean RedisplayRectangle( XmWorkspaceWidget ww, XRectangle* rect,
1269 Region region, Boolean clip_region_set )
1270 {
1271 if( XRectInRegion(region, rect->x, rect->y, rect->width, rect->height) )
1272 {
1273 if( region && (clip_region_set == FALSE) )
1274 XSetRegion(XtDisplay(ww), ww->workspace.bandGC, region);
1275 XDrawRectangles(XtDisplay(ww), XtWindow(ww), ww->workspace.bandGC,
1276 rect, 1);
1277 if( region )
1278 return TRUE;
1279 else
1280 return FALSE;
1281 }
1282 else
1283 return FALSE;
1284 }
1285
1286 typedef struct {
1287 char *type;
1288 char *w;
1289 char *offset;
1290 char *percent;
1291 } ResNamePlaceHolder;
1292
1293 static ResNamePlaceHolder rname[] = {
1294 { XmNleftAttachment, XmNleftWidget, XmNleftOffset, XmNleftPosition },
1295 { XmNrightAttachment, XmNrightWidget, XmNrightOffset, XmNrightPosition },
1296 { XmNtopAttachment, XmNtopWidget, XmNtopOffset, XmNtopPosition },
1297 { XmNbottomAttachment, XmNbottomWidget, XmNbottomOffset, XmNbottomPosition }
1298 };
1299
1300
1301 /********************************************************************************/
1302 /* return True if this child widget can scoot over to the left edge of the */
1303 /* Workspace without bumping into anyone. Used when switching into XmForm mode. */
1304 /* Had been assuming that coords within a few pixels of the edge guaranteed */
1305 /* we could stretch, but then Rich S. started making vertical separators along */
1306 /* the edges of his control panels. */
1307 /********************************************************************************/
1308 static Boolean
safe2StretchLeft(XRectangle rangle[],int nkids,int kid)1309 safe2StretchLeft (XRectangle rangle[], int nkids, int kid)
1310 {
1311 int i;
1312
1313 for (i=0; i<nkids; i++) {
1314 if (i == kid) continue;
1315 if (rangle[i].y > (rangle[kid].y + rangle[kid].height)) continue;
1316 if ((rangle[i].y + rangle[i].height) < rangle[kid].y) continue;
1317 if (rangle[i].x < rangle[kid].x) return False;
1318 }
1319 return True;
1320 }
1321 static Boolean
safe2StretchRight(XRectangle rangle[],int nkids,int kid)1322 safe2StretchRight (XRectangle rangle[], int nkids, int kid)
1323 {
1324 int i;
1325
1326 for (i=0; i<nkids; i++) {
1327 if (i == kid) continue;
1328 if (rangle[i].y > (rangle[kid].y + rangle[kid].height)) continue;
1329 if ((rangle[i].y + rangle[i].height) < rangle[kid].y) continue;
1330 if (rangle[i].x > rangle[kid].x) return False;
1331 }
1332 return True;
1333 }
1334
1335
1336
1337 /* Subroutine: SetValues
1338 * Purpose: Check for changes that require other action to bring all things
1339 * into consistency.
1340 */
SetValues(XmWorkspaceWidget current,XmWorkspaceWidget request,XmWorkspaceWidget new)1341 static Boolean SetValues( XmWorkspaceWidget current,
1342 XmWorkspaceWidget request,
1343 XmWorkspaceWidget new )
1344 {
1345 Boolean clear_window = FALSE;
1346 XmWorkspaceLine line;
1347 int i;
1348 XmWorkspaceConstraints nc;
1349 Widget child;
1350 XEvent event;
1351 Boolean reroute = False, refresh = False, redraw = False;
1352 Boolean *was_selected;
1353
1354 #if 0
1355 /*
1356 * this is how you make lines disappear when the value of the resource changes
1357 */
1358 if ((new->workspace.line_drawing_enabled != current->workspace.line_drawing_enabled)&&
1359 (new->workspace.line_drawing_enabled == False)) redraw = True;
1360 #endif
1361
1362 if (new->workspace.button1_press_mode !=
1363 current->workspace.button1_press_mode)
1364 {
1365 return FALSE;
1366 }
1367
1368 /* If grid visibility changes or grid is visible and its form changes */
1369 if( (new->workspace.snap_to_grid != current->workspace.snap_to_grid)
1370 || ( new->workspace.horizontal_draw_grid
1371 != current->workspace.horizontal_draw_grid)
1372 || ( new->workspace.vertical_draw_grid
1373 != current->workspace.vertical_draw_grid)
1374 || ( ( current->workspace.snap_to_grid
1375 && ( (current->workspace.horizontal_draw_grid != XmDRAW_NONE)
1376 || (current->workspace.vertical_draw_grid != XmDRAW_NONE)))
1377 && ( ( new->workspace.horizontal_alignment
1378 != current->workspace.horizontal_alignment)
1379 || ( new->workspace.vertical_alignment
1380 != current->workspace.vertical_alignment)
1381 || (new->workspace.grid_width != current->workspace.grid_width)
1382 || ( new->workspace.grid_height
1383 != current->workspace.grid_height))
1384 )
1385 )
1386 {
1387 /* Create the new gridding situation */
1388 SetGridBackground(new, TRUE);
1389 clear_window = TRUE;
1390 }
1391
1392 /* if line routing changed */
1393 if (new->workspace.manhattan_route !=
1394 current->workspace.manhattan_route)
1395 {
1396 #if 11
1397 reroute = True;
1398 #else
1399 RerouteLines(new, TRUE);
1400 #endif
1401 clear_window = TRUE;
1402 }
1403 if ((new->workspace.line_drawing_enabled == TRUE) &&
1404 (current->workspace.line_drawing_enabled == FALSE))
1405 {
1406 if (XtIsRealized ((Widget)new))
1407 XClearWindow(XtDisplay(new), XtWindow(new));
1408 #if 11
1409 reroute = True;
1410 refresh = True;
1411 #else
1412 RerouteLines(new, TRUE);
1413 RefreshLines(new);
1414 #endif
1415 }
1416 if( (new->core.width >= current->core.width) ||
1417 (new->core.height >= current->core.height) )
1418 {
1419 ReallocCollideLists(new);
1420 }
1421
1422 /* Replace the old with the new */
1423 if (clear_window)
1424 {
1425 if ( (new->workspace.snap_to_grid == TRUE) &&
1426 (current->workspace.snap_to_grid == FALSE) )
1427 {
1428 new->workspace.suppress_callbacks = True;
1429 was_selected = (Boolean *)
1430 XtMalloc(new->composite.num_children*sizeof(Boolean));
1431 for(i=0; i<new->composite.num_children; i++)
1432 {
1433 child = new->composite.children[i];
1434 nc = WORKSPACE_CONSTRAINT(child);
1435 was_selected[i] = nc->workspace.is_selected;
1436 if(!was_selected[i])
1437 SelectChild(new, child, nc, (XEvent *)NULL);
1438 }
1439 if(new->composite.num_children > 0)
1440 {
1441 child = new->composite.children[0];
1442 event.xbutton.x = child->core.x+1;
1443 event.xbutton.y = child->core.y+1;
1444 event.xbutton.window = new->composite.children[0]->core.window;
1445 event.xbutton.time = new->workspace.time -
1446 2*new->workspace.double_click_interval;
1447 event.xbutton.state = 0;
1448 GrabSelections((Widget)new, &event, NULL, NULL);
1449 event.xbutton.x = child->core.x;
1450 event.xbutton.y = child->core.y;
1451 DropSelections((Widget)new, &event, NULL, NULL);
1452 }
1453 for(i=0; i<new->composite.num_children; i++)
1454 {
1455 child = new->composite.children[i];
1456 nc = WORKSPACE_CONSTRAINT(child);
1457 if(was_selected[i])
1458 SelectChild(new, child, nc, (XEvent *)NULL);
1459 else
1460 UnselectChild(new, child, nc, (XEvent *)NULL);
1461 }
1462 if(new->composite.num_children > 0)
1463 XtFree(was_selected);
1464 new->workspace.suppress_callbacks = False;
1465 }
1466 if (XtWindow(new))
1467 XClearWindow(XtDisplay(new), XtWindow(new));
1468 if(new->workspace.lines)
1469 {
1470 line = new->workspace.lines;
1471 while(line)
1472 {
1473 line->is_to_be_drawn = TRUE;
1474 line = line->next;
1475 }
1476 }
1477 redraw = TRUE;
1478 }
1479 if ((new->bulletin_board.allow_overlap !=
1480 current->bulletin_board.allow_overlap) &&
1481 !new->bulletin_board.allow_overlap)
1482 {
1483 /*
1484 * Pretend like all are newly managed so space wars works
1485 */
1486 Boolean moved;
1487 for( i=0; i<new->composite.num_children; i++ )
1488 {
1489 child = new->composite.children[i];
1490 nc = WORKSPACE_CONSTRAINT(child);
1491 nc->workspace.is_newly_managed = True;
1492 }
1493 moved = PerformSpaceWars(new, TRUE, NULL);
1494 for( i=0; i<new->composite.num_children; i++ )
1495 {
1496 child = new->composite.children[i];
1497 nc = WORKSPACE_CONSTRAINT(child);
1498 nc->workspace.is_newly_managed = False;
1499 }
1500 /*
1501 * If we move anything, be sure to reroute the lines
1502 */
1503 if( moved && new->workspace.lines )
1504 {
1505 if (XtWindow(new))
1506 XClearWindow(XtDisplay(new), XtWindow(new));
1507 #if 11
1508 reroute = True;
1509 refresh = True;
1510 #else
1511 RerouteLines(new, FALSE);
1512 RefreshLines(new);
1513 #endif
1514 }
1515 }
1516
1517 /*
1518 * form attachments will be set all at once when XmNautoArrange is set to
1519 * True. Any settings which have been put into XmNwwTopAttachment etc will
1520 * be used first. Any settings == XmATTACH_NONE will be calculated and set
1521 * to XmATTACH_POSITION. It would be nice to have a real way to specify
1522 * the attachments. One possibility would be sorting the edges.
1523 */
1524 if (current->workspace.auto_arrange != new->workspace.auto_arrange) {
1525 int n, wwidth, wheight, bw;
1526 int bottomp, rightp, leftp, topp, fbase;
1527 XmFormAttachmentRec *att;
1528 Arg args[20];
1529
1530 /*
1531 * We're switching into XmForm mode... do attachment calculations.
1532 */
1533 if (new->workspace.auto_arrange) {
1534
1535 int maxw, maxh;
1536 XRectangle *rangle;
1537 int nkids = current->composite.num_children;
1538 wwidth = new->core.width;
1539 wheight = new->core.height;
1540 rangle = (XRectangle *)malloc((1+nkids) * sizeof(XRectangle));
1541
1542 /*
1543 * must hang on to dimensions before superclass get its hands on them
1544 * must also inform the form widget of the child's preferred dimensions.
1545 * Ordinarily a form widget would have this info, but the form side of
1546 * personality has been asleep and needs to be roused carefully.
1547 */
1548 for (i=0; i<current->composite.num_children; i++) {
1549 #if (OLD_LESSTIF == 1)
1550 XmFormConstraintPart* formcons;
1551 #else
1552 XmFormConstraint formcons;
1553 #endif
1554 rangle[i].x = current->composite.children[i]->core.x;
1555 rangle[i].y = current->composite.children[i]->core.y;
1556 rangle[i].width = current->composite.children[i]->core.width;
1557 rangle[i].height = current->composite.children[i]->core.height;
1558
1559 formcons = GetFormConstraint(current->composite.children[i]);
1560 formcons->preferred_width = rangle[i].width;
1561 formcons->preferred_height = rangle[i].height;
1562 }
1563 (*superclass->composite_class.change_managed) ((Widget)current);
1564
1565
1566 /*
1567 * From this point on, must not use core.{x,y,width,height} because
1568 * the superclass might have touched these values. Can only use
1569 * values in rangle.
1570 */
1571 XtVaGetValues ((Widget)current, XmNfractionBase, &fbase, NULL);
1572 XmWorkspaceGetMaxWidthHeight ((Widget)current, &maxw, &maxh);
1573 for (i=0; i<current->composite.num_children; i++) {
1574 int j;
1575 int x2use, y2use, w2use, h2use;
1576 float posfl, wfactor, hfactor;
1577 struct {
1578 int top,left,right,bottom;
1579 } limits;
1580
1581 posfl = fbase * 0.05;
1582 limits.top = limits.left = (int)posfl;
1583 posfl = fbase * 0.95;
1584 limits.right = limits.bottom = (int)posfl;
1585
1586 child = current->composite.children[i];
1587 nc = WORKSPACE_CONSTRAINT(child);
1588 att = nc->workspace.att;
1589
1590 x2use = rangle[i].x;
1591 y2use = rangle[i].y;
1592 w2use = rangle[i].width;
1593 h2use = rangle[i].height;
1594
1595 nc->workspace.orig_base.x = x2use;
1596 nc->workspace.orig_base.y = y2use;
1597 nc->workspace.orig_base.width = w2use;
1598 nc->workspace.orig_base.height = h2use;
1599
1600 /*
1601 * perform accurate rounding
1602 */
1603 if (wwidth <= 0) wwidth = 1;
1604 if (wheight <= 0) wheight = 1;
1605 wfactor = (float)fbase/(float)wwidth;
1606 hfactor = (float)fbase/(float)wheight;
1607
1608 posfl = (float)x2use * wfactor;
1609 leftp = (int)posfl;
1610 if ((posfl - (float)leftp) >= 0.5) leftp++;
1611
1612 posfl = (float)y2use * hfactor;
1613 topp = (int)posfl;
1614 if ((posfl - (float)topp) >= 0.5) topp++;
1615
1616 posfl = (float)(x2use+w2use) * wfactor;
1617 rightp = (int)posfl;
1618 if ((posfl - (float)rightp) >= 0.5) rightp++;
1619
1620 posfl = (float)(y2use+h2use) * hfactor;
1621 bottomp = (int)posfl;
1622 if ((posfl - (float)bottomp) >= 0.5) bottomp++;
1623
1624 /*
1625 * ASSERT (rightp >= (leftp+1))
1626 * ASSERT (bottomp >= (topp+1))
1627 * You would expect not to have to do this but because of
1628 * an old bug it might be possible to find a dimension set to
1629 * something like 0 or 1 in the .cfg file. So this prevents
1630 * pages and pages of motif warnings from XmForm.
1631 */
1632 if (rightp < (leftp+1)) rightp = leftp+1;
1633 if (bottomp < (topp+1)) bottomp = topp+1;
1634
1635
1636
1637 n = 0;
1638
1639 /*
1640 * separator decorators have this resource set so that they will
1641 * be stretched on a window resize.
1642 */
1643 if ((nc->workspace.pin_to_sides_lr) && (!nc->workspace.pin_to_sides_tb)) {
1644
1645 /*
1646 * The separator is currently going all the way across
1647 */
1648 if ((leftp<=limits.left)&&(safe2StretchLeft(rangle, nkids, i)) &&
1649 (rightp>=limits.right)&&(safe2StretchRight(rangle, nkids, i))) {
1650 for (j=0; j<4; j++) {
1651 if (att[j].offset != OFFSET_DEFAULT) {
1652 XtSetArg (args[n], rname[j].offset, att[j].offset); n++;
1653 } else {
1654 XtSetArg (args[n], rname[j].offset, 0); n++;
1655 }
1656 if (att[j].type != XmATTACH_NONE) {
1657 XtSetArg (args[n], rname[j].type, att[j].type); n++;
1658 XtSetArg (args[n], rname[j].w, att[j].w); n++;
1659 XtSetArg (args[n], rname[j].percent, att[j].percent); n++;
1660 } else {
1661 switch (j) {
1662 case FC_LEFT:
1663 XtSetArg (args[n],
1664 XmNleftAttachment, XmATTACH_FORM); n++;
1665 break;
1666 case FC_RIGHT:
1667 XtSetArg (args[n],
1668 XmNrightAttachment, XmATTACH_FORM); n++;
1669 break;
1670 case FC_TOP:
1671 XtSetArg (args[n],
1672 XmNtopAttachment, XmATTACH_POSITION); n++;
1673 XtSetArg (args[n], XmNtopPosition, topp); n++;
1674 break;
1675 case FC_BOTTOM:
1676 break;
1677 }
1678 }
1679 }
1680 } else if ((leftp<=limits.left)&&(safe2StretchLeft(rangle, nkids, i))) {
1681 /*
1682 * The separator goes from the left side, part way across.
1683 */
1684 for (j=0; j<4; j++) {
1685 if (att[j].offset != OFFSET_DEFAULT) {
1686 XtSetArg (args[n], rname[j].offset, att[j].offset); n++;
1687 } else {
1688 XtSetArg (args[n], rname[j].offset, 0); n++;
1689 }
1690 if (att[j].type != XmATTACH_NONE) {
1691 XtSetArg (args[n], rname[j].type, att[j].type); n++;
1692 XtSetArg (args[n], rname[j].w, att[j].w); n++;
1693 XtSetArg (args[n], rname[j].percent, att[j].percent); n++;
1694 } else {
1695 switch (j) {
1696 case FC_LEFT:
1697 XtSetArg (args[n],
1698 XmNleftAttachment, XmATTACH_FORM); n++;
1699 break;
1700 case FC_RIGHT:
1701 XtSetArg (args[n],
1702 XmNrightAttachment, XmATTACH_POSITION); n++;
1703 XtSetArg (args[n], XmNrightPosition, rightp); n++;
1704 break;
1705 case FC_TOP:
1706 XtSetArg (args[n],
1707 XmNtopAttachment, XmATTACH_POSITION); n++;
1708 XtSetArg (args[n], XmNtopPosition, topp); n++;
1709 break;
1710 case FC_BOTTOM:
1711 break;
1712 }
1713 }
1714 }
1715 } else if ((rightp>=limits.right)&&(safe2StretchRight(rangle, nkids, i))) {
1716 /*
1717 * The separator goes from somewhere in the middle all the
1718 * way to the right side.
1719 */
1720 for (j=0; j<4; j++) {
1721 if (att[j].offset != OFFSET_DEFAULT) {
1722 XtSetArg (args[n], rname[j].offset, att[j].offset); n++;
1723 } else {
1724 XtSetArg (args[n], rname[j].offset, 0); n++;
1725 }
1726 if (att[j].type != XmATTACH_NONE) {
1727 XtSetArg (args[n], rname[j].type, att[j].type); n++;
1728 XtSetArg (args[n], rname[j].w, att[j].w); n++;
1729 XtSetArg (args[n], rname[j].percent, att[j].percent); n++;
1730 } else {
1731 switch (j) {
1732 case FC_LEFT:
1733 XtSetArg (args[n],
1734 XmNleftAttachment, XmATTACH_POSITION); n++;
1735 XtSetArg (args[n], XmNleftPosition, leftp); n++;
1736 break;
1737 case FC_RIGHT:
1738 XtSetArg (args[n],
1739 XmNrightAttachment, XmATTACH_FORM); n++;
1740 break;
1741 case FC_TOP:
1742 XtSetArg (args[n],
1743 XmNtopAttachment, XmATTACH_POSITION); n++;
1744 XtSetArg (args[n], XmNtopPosition, topp); n++;
1745 break;
1746 case FC_BOTTOM:
1747 break;
1748 }
1749 }
1750 }
1751 } else {
1752 /*
1753 * The separator starts somewhere in the middle and ends
1754 * somewhere in the middle
1755 */
1756 for (j=0; j<4; j++) {
1757 if (att[j].offset != OFFSET_DEFAULT) {
1758 XtSetArg (args[n], rname[j].offset, att[j].offset); n++;
1759 } else {
1760 XtSetArg (args[n], rname[j].offset, 0); n++;
1761 }
1762 if (att[j].type != XmATTACH_NONE) {
1763 XtSetArg (args[n], rname[j].type, att[j].type); n++;
1764 XtSetArg (args[n], rname[j].w, att[j].w); n++;
1765 XtSetArg (args[n], rname[j].percent, att[j].percent); n++;
1766 } else {
1767 switch (j) {
1768 case FC_LEFT:
1769 XtSetArg (args[n],
1770 XmNleftAttachment, XmATTACH_POSITION); n++;
1771 XtSetArg (args[n], XmNleftPosition, leftp); n++;
1772 break;
1773 case FC_RIGHT:
1774 XtSetArg (args[n],
1775 XmNrightAttachment, XmATTACH_POSITION); n++;
1776 XtSetArg (args[n], XmNrightPosition, rightp); n++;
1777 break;
1778 case FC_TOP:
1779 XtSetArg (args[n],
1780 XmNtopAttachment, XmATTACH_POSITION); n++;
1781 XtSetArg (args[n], XmNtopPosition, topp); n++;
1782 break;
1783 case FC_BOTTOM:
1784 break;
1785 }
1786 }
1787 }
1788 }
1789 } else {
1790 /*
1791 * handle everything except separator decorators.
1792 */
1793 for (j=0; j<4; j++) {
1794 if (att[j].offset != OFFSET_DEFAULT) {
1795 XtSetArg (args[n], rname[j].offset, att[j].offset); n++;
1796 } else {
1797 XtSetArg (args[n], rname[j].offset, 0); n++;
1798 }
1799 if (att[j].type != XmATTACH_NONE) {
1800 XtSetArg (args[n], rname[j].type, att[j].type); n++;
1801 XtSetArg (args[n], rname[j].w, att[j].w); n++;
1802 XtSetArg (args[n], rname[j].percent, att[j].percent); n++;
1803 } else {
1804 switch (j) {
1805 case FC_LEFT:
1806 XtSetArg (args[n],
1807 XmNleftAttachment, XmATTACH_POSITION); n++;
1808 XtSetArg (args[n], XmNleftPosition, leftp); n++;
1809 break;
1810 case FC_TOP:
1811 XtSetArg (args[n],
1812 XmNtopAttachment, XmATTACH_POSITION); n++;
1813 XtSetArg (args[n], XmNtopPosition, topp); n++;
1814 break;
1815 case FC_RIGHT:
1816 if (nc->workspace.pin_to_sides_lr) {
1817 XtSetArg (args[n],
1818 XmNrightAttachment, XmATTACH_POSITION); n++;
1819 XtSetArg (args[n],
1820 XmNrightPosition, rightp); n++;
1821 } else {
1822 XtSetArg (args[n],
1823 XmNrightAttachment, XmATTACH_NONE); n++;
1824 }
1825 break;
1826 case FC_BOTTOM:
1827 if (nc->workspace.pin_to_sides_tb) {
1828 XtSetArg (args[n],
1829 XmNbottomAttachment, XmATTACH_POSITION); n++;
1830 XtSetArg (args[n],
1831 XmNbottomPosition, bottomp); n++;
1832 } else {
1833 XtSetArg (args[n],
1834 XmNbottomAttachment, XmATTACH_NONE); n++;
1835 }
1836 break;
1837 }
1838 }
1839 }
1840 }
1841
1842 XtSetValues (child, args, n);
1843
1844 bw = child->core.border_width;
1845 XtResizeWidget (child, rangle[i].width, rangle[i].height, bw);
1846 if (nc->workspace.is_selected) {
1847 UnselectChild(new, child, nc, (XEvent *)NULL);
1848 }
1849
1850 }
1851 free(rangle);
1852 } else {
1853 /*
1854 * We're switching from XmForm mode to Workspace mode.
1855 */
1856 Boolean tmp;
1857 XtWidgetGeometry req;
1858 tmp = current->bulletin_board.allow_overlap;
1859 current->bulletin_board.allow_overlap = True;
1860 for (i=0; i<current->composite.num_children; i++) {
1861 child = current->composite.children[i];
1862 XtVaSetValues (child, XmNtopAttachment, XmATTACH_NONE,
1863 XmNleftAttachment, XmATTACH_NONE, XmNbottomAttachment,
1864 XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL);
1865 }
1866 for (i=0; i<current->composite.num_children; i++) {
1867 child = current->composite.children[i];
1868 nc = WORKSPACE_CONSTRAINT(child);
1869 req.request_mode = CWX|CWY|CWWidth|CWHeight;
1870 req.x = nc->workspace.orig_base.x;
1871 req.y = nc->workspace.orig_base.y;
1872 req.width = nc->workspace.orig_base.width;
1873 req.height = nc->workspace.orig_base.height;
1874 bw = child->core.border_width;
1875 XtResizeWidget (child, req.width, req.height, bw);
1876 XtMoveWidget (child, req.x, req.y);
1877 /*XtConfigureWidget (child, req.x, req.y, req.width, req.height, bw);*/
1878 _GeometryManager (child, &req, NULL, False);
1879 }
1880 current->workspace.orig_width = 0;
1881 current->workspace.orig_height = 0;
1882 current->bulletin_board.allow_overlap = tmp;
1883 }
1884 }
1885
1886 #if 11
1887 if (reroute)
1888 RerouteLines(new, TRUE);
1889 if (refresh)
1890 RefreshLines(new);
1891 #endif
1892 /* Watch out for line management %% */
1893 return redraw;
1894 }
1895
1896
1897 /* Subroutine: ChangeManaged
1898 * Effect: Makes sure everyone is in their places before the curtain opens
1899 */
ChangeManaged(XmWorkspaceWidget ww)1900 static void ChangeManaged( XmWorkspaceWidget ww )
1901 {
1902 XmWorkspaceConstraints nc=0;
1903 Widget child=0;
1904 int i;
1905 Boolean resolve_overlap = FALSE;
1906 Boolean new_node = FALSE;
1907 #if (OLD_LESSTIF == 1)
1908 XmFormConstraintPart *formcon;
1909 #else
1910 XmFormConstraint formcon;
1911 #endif
1912
1913 if (ww->workspace.auto_arrange)
1914 (*superclass->composite_class.change_managed) ((Widget)ww);
1915 for( i=0; i<ww->composite.num_children; i++ )
1916 {
1917 child = ww->composite.children[i];
1918 nc = WORKSPACE_CONSTRAINT(child);
1919 if (((child->core.managed) && (!nc->workspace.is_managed)) &&
1920 (!ww->workspace.auto_arrange))
1921 {
1922
1923 /*
1924 * Certainly don't want to do this if auto_arrange==True
1925 */
1926 formcon = GetFormConstraint(child);
1927 #if (OLD_LESSTIF == 1)
1928 formcon->atta[0].type = XmATTACH_NONE;
1929 formcon->atta[1].type = XmATTACH_NONE;
1930 formcon->atta[2].type = XmATTACH_NONE;
1931 formcon->atta[3].type = XmATTACH_NONE;
1932 #else
1933 formcon->att[0].type = XmATTACH_NONE;
1934 formcon->att[1].type = XmATTACH_NONE;
1935 formcon->att[2].type = XmATTACH_NONE;
1936 formcon->att[3].type = XmATTACH_NONE;
1937 #endif
1938
1939 new_node = True;
1940 #if 1
1941 /*
1942 * grow the workspace if the child won't fit
1943 */
1944 {
1945 XtWidgetGeometry compromise,req; int newdim;
1946 XtGeometryResult result;
1947 newdim = child->core.x + child->core.width;
1948 req.request_mode = 0;
1949 if (newdim > ww->core.width) {
1950 req.request_mode|= CWWidth;
1951 req.width = newdim + 100;
1952 }
1953 newdim = child->core.y + child->core.height;
1954 if (newdim > ww->core.height) {
1955 req.request_mode = CWHeight;
1956 req.height = newdim + 100;
1957 }
1958 if (req.request_mode) {
1959 result = XtMakeGeometryRequest ((Widget)ww, &req, &compromise);
1960 if (result != XtGeometryNo) {
1961 if (result == XtGeometryAlmost) {
1962 XtMakeGeometryRequest ((Widget)ww, &compromise, NULL);
1963 }
1964 ReallocCollideLists(ww);
1965 }
1966 }
1967 }
1968 #endif
1969 ChangeWidgetInCollideList(ww, child);
1970
1971
1972
1973 nc->workspace.x_left = child->core.x;
1974 nc->workspace.x_right = child->core.x + child->core.width - 1;
1975 nc->workspace.y_upper = child->core.y;
1976 nc->workspace.y_lower = child->core.y + child->core.height - 1;
1977 nc->workspace.x_delta = nc->workspace.y_delta = 0;
1978 nc->workspace.x_center = child->core.x + (child->core.width / 2);
1979 nc->workspace.y_center = child->core.y + (child->core.height / 2);
1980 /* Register initial sort position (before any adjustment) */
1981 if( ww->workspace.sort_policy == XmALIGNMENT_BEGINNING )
1982 nc->workspace.x_index = nc->workspace.x_left;
1983 else if( ww->workspace.sort_policy == XmALIGNMENT_CENTER )
1984 nc->workspace.x_index = nc->workspace.x_center;
1985 else
1986 nc->workspace.x_index = nc->workspace.x_right;
1987 /* Adjust position to constraint-grid location */
1988 if( ww->workspace.snap_to_grid )
1989 {
1990 /* Move into closest grid position (any direction) */
1991 SnapToGrid(ww, child, nc, FALSE);
1992 /* If no other adjustments will be made, move it now */
1993 if( ww->bulletin_board.allow_overlap )
1994 MoveChild(ww, child, nc);
1995 }
1996 if( ww->bulletin_board.allow_overlap )
1997 nc->workspace.is_newly_managed = FALSE;
1998 else
1999 {
2000 nc->workspace.is_newly_managed = TRUE;
2001 resolve_overlap = TRUE;
2002 }
2003 }
2004 nc->workspace.is_managed = child->core.managed;
2005 }
2006
2007 /* If a child has been added, make sure it doesn't add any overlaps */
2008 if ((resolve_overlap) && (!ww->workspace.auto_arrange))
2009 (void)PerformSpaceWars(ww, TRUE, NULL);
2010 /* %% Check window size and extents for need to resize */
2011 if( ww->workspace.lines )
2012 {
2013 if ( (!(nc->workspace.is_managed && child->core.managed)) ||
2014 new_node )
2015 {
2016 /* Establish new routes for lines that were moved */
2017 RerouteLines(ww, FALSE);
2018 if( ww->workspace.expose_left < ww->workspace.expose_right )
2019 {
2020 if (XtWindow(ww))
2021 XClearArea(XtDisplay(ww), XtWindow(ww),
2022 ww->workspace.expose_left,
2023 ww->workspace.expose_upper,
2024 ww->workspace.expose_right -
2025 ww->workspace.expose_left,
2026 ww->workspace.expose_lower -
2027 ww->workspace.expose_upper, False);
2028 }
2029 RefreshLines(ww);
2030 }
2031 }
2032 }
2033
2034 /*
2035 * Subroutine: XtGeometryResult
2036 * Purpose: Get informed of a change in a child widget's geometry.
2037 */
2038 static XtGeometryResult
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)2039 GeometryManager( Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply )
2040 {
2041 return _GeometryManager (w, request, reply, True);
2042 }
2043
2044 /*
2045 * Expose the ability to move standins programatically. Using
2046 * XtSetValues() doesn't work for this because our GeometryManager
2047 * is never called. Using XtMakeGeometryRequest() almost does the job
2048 * but that function is doc'ed as being only for widget writers
2049 * to use and not for application programmers. In addition to
2050 * changing x,y location of standins, we need to ensure that
2051 * line routing is handled at the same time.
2052 */
XmWorkspaceSetLocation(Widget w,Dimension x,Dimension y)2053 Boolean XmWorkspaceSetLocation (Widget w, Dimension x, Dimension y)
2054 {
2055 XmWorkspaceWidget ww;
2056 XtWidgetGeometry req;
2057 XtGeometryResult result;
2058
2059 ww = (XmWorkspaceWidget)XtParent(w);
2060 req.request_mode = 0;
2061
2062
2063 /* Using 32767 is a hack. I just happen to know that that it's
2064 * what we use elsewhere in dxui to indicate no-change.
2065 */
2066 if (x != 32767) {
2067 req.request_mode|= CWX;
2068 req.x = x;
2069 }
2070 if (y != 32767) {
2071 req.request_mode|= CWY;
2072 req.y = y;
2073 }
2074
2075 if (req.request_mode == 0) return TRUE;
2076 result = XtMakeGeometryRequest (w, &req, NULL);
2077 return (result == XtGeometryYes);
2078 }
2079
2080 static XtGeometryResult
_GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply,Boolean adjust_constraints)2081 _GeometryManager( Widget w, XtWidgetGeometry *request,
2082 XtWidgetGeometry *reply, Boolean adjust_constraints )
2083 {
2084 XmWorkspaceWidget ww;
2085 XmWorkspaceConstraints constraints = WORKSPACE_CONSTRAINT(w);
2086 Boolean resolve_overlap = False;
2087 XtGeometryResult retval;
2088
2089 ww = (XmWorkspaceWidget)XtParent(w);
2090
2091 if ((adjust_constraints) && (ww->workspace.auto_arrange))
2092 retval = (*superclass->composite_class.geometry_manager) (w, request, reply);
2093 else
2094 retval = XtGeometryYes;
2095
2096 if ((retval == XtGeometryYes)||(retval == XtGeometryDone)) {
2097 if (request->request_mode & CWWidth)
2098 w->core.width = request->width;
2099 if (request->request_mode & CWHeight)
2100 w->core.height = request->height;
2101 if (request->request_mode & CWBorderWidth)
2102 w->core.border_width = request->border_width;
2103 if (request->request_mode & CWX)
2104 w->core.x = request->x;
2105 if (request->request_mode & CWY)
2106 w->core.y = request->y;
2107 }
2108
2109 /*if ((retval == XtGeometryNo) || (retval == XtGeometryAlmost)) return retval;*/
2110
2111 #if 1
2112 /*
2113 * grow the workspace if the child won't fit
2114 */
2115 {
2116 XtWidgetGeometry compromise,req; int newdim;
2117 XtGeometryResult result;
2118 newdim = w->core.x + w->core.width;
2119 req.request_mode = 0;
2120 if (newdim > ww->core.width) {
2121 req.request_mode|= CWWidth;
2122 req.width = newdim + 10;
2123 }
2124 newdim = w->core.y + w->core.height;
2125 if (newdim > ww->core.height) {
2126 req.request_mode = CWHeight;
2127 req.height = newdim + 10;
2128 }
2129 if (req.request_mode) {
2130 result = XtMakeGeometryRequest ((Widget)ww, &req, &compromise);
2131 if (result != XtGeometryNo) {
2132 if (result == XtGeometryAlmost) {
2133 XtMakeGeometryRequest ((Widget)ww, &compromise, NULL);
2134 }
2135 ReallocCollideLists(ww);
2136 }
2137 }
2138 }
2139 #endif
2140
2141 constraints->workspace.x_left = w->core.x;
2142 constraints->workspace.x_right = w->core.x + w->core.width - 1;
2143 constraints->workspace.y_upper = w->core.y;
2144 constraints->workspace.y_lower = w->core.y + w->core.height - 1;
2145 constraints->workspace.x_center = w->core.x + (w->core.width/2);
2146 constraints->workspace.y_center = w->core.y + (w->core.height/2);
2147 constraints->workspace.x_delta = 0;
2148 constraints->workspace.y_delta = 0;
2149 constraints->workspace.x_center = w->core.x + (w->core.width / 2);
2150 constraints->workspace.y_center = w->core.y + (w->core.height / 2);
2151
2152 /* Register initial sort position (before any adjustment) */
2153 if( ww->workspace.sort_policy == XmALIGNMENT_BEGINNING )
2154 constraints->workspace.x_index = constraints->workspace.x_left;
2155 else if( ww->workspace.sort_policy == XmALIGNMENT_CENTER )
2156 constraints->workspace.x_index = constraints->workspace.x_center;
2157 else
2158 constraints->workspace.x_index = constraints->workspace.x_right;
2159 /* Adjust position to constraint-grid location */
2160 if( ww->workspace.snap_to_grid )
2161 {
2162 /* Move into closest grid position (any direction) */
2163 SnapToGrid(ww, w, constraints, FALSE);
2164 /* If no other adjustments will be made, move it now */
2165 if( ww->bulletin_board.allow_overlap )
2166 MoveChild(ww, w, constraints);
2167 }
2168 if( ww->bulletin_board.allow_overlap )
2169 constraints->workspace.is_newly_managed = FALSE;
2170 else
2171 {
2172 constraints->workspace.is_newly_managed = TRUE;
2173 resolve_overlap = TRUE;
2174 }
2175 if ((resolve_overlap) && (!ww->workspace.auto_arrange))
2176 {
2177 (void)PerformSpaceWars(ww, TRUE, NULL);
2178 }
2179
2180 if (!constraints->workspace.line_invisibility)
2181 ChangeWidgetInCollideList(ww, w);
2182
2183 return retval;
2184 }
2185
2186
2187 /* Subroutine: ConstraintInitialize
2188 * Purpose: Update parameters in a child widget's constraints (except
2189 * those pertaining to size) and install the accerators.
2190 */
ConstraintInitialize(Widget req,Widget new)2191 static void ConstraintInitialize( Widget req, Widget new )
2192 {
2193 XtTranslations acc_table;
2194
2195 /* Unitialized fields are not automatically cleared! */
2196 XmWorkspaceConstraints constraints = WORKSPACE_CONSTRAINT(new);
2197 constraints->workspace.source_lines = NULL;
2198 constraints->workspace.destination_lines = NULL;
2199 constraints->workspace.will_be_selected = FALSE;
2200 constraints->workspace.is_accented = FALSE;
2201 constraints->workspace.is_managed = FALSE;
2202
2203 /* Accelerators are per-instance and must be installed at runtime */
2204 /*
2205 * on behalf of vpe pages... don't put accelerators on the child
2206 * if the child is another workspace.
2207 */
2208 if (XtClass(new) != xmWorkspaceWidgetClass) {
2209 acc_table = XtParseTranslationTable(acceleratorTranslations);
2210 XtOverrideTranslations (new, acc_table);
2211 } else {
2212
2213 /*
2214 * FIXME: there are 2 resources with the same name: XmNselectable (of the
2215 * workspace itself) and XmNselectable (a constraint provided by the workspace
2216 * to its children). That means there is no way to set the resource on
2217 * workspace whose parent is also a workspace.
2218 */
2219 constraints->workspace.is_selectable = False;
2220 }
2221 }
2222
2223
2224 /* Subroutine: ConstraintDestroy
2225 * Purpose: Free space allocated for use in the child's constraints
2226 */
ConstraintDestroy(Widget w)2227 static void ConstraintDestroy( Widget w )
2228 {
2229 XmWorkspaceWidget ww = (XmWorkspaceWidget)XtParent(w);
2230 XmWorkspaceConstraints constraints = WORKSPACE_CONSTRAINT(w);
2231
2232 /* Make sure child is no longer counted among the select */
2233 if( constraints->workspace.is_selected )
2234 ww->workspace.num_selected--;
2235 if( constraints->workspace.select_callbacks )
2236 RemoveConstraintCallbacks(&constraints->workspace.select_callbacks);
2237 if( constraints->workspace.accent_callbacks )
2238 RemoveConstraintCallbacks(&constraints->workspace.accent_callbacks);
2239 if( constraints->workspace.resizing_callbacks )
2240 RemoveConstraintCallbacks(&constraints->workspace.resizing_callbacks);
2241 }
2242
2243
2244 /* Subroutine: ConstraintSetValues
2245 * Purpose: Check for application changes to constraint parameters and
2246 * take actions indicated.
2247 */
ConstraintSetValues(Widget current,Widget request,Widget new)2248 static Boolean ConstraintSetValues( Widget current, Widget request, Widget new )
2249 {
2250 Boolean retval;
2251 Cardinal zero = 0;
2252 XmWorkspaceConstraints new_constraints = WORKSPACE_CONSTRAINT(new);
2253 XmWorkspaceConstraints old_constraints = WORKSPACE_CONSTRAINT(current);
2254
2255 retval = (*superclass->constraint_class.set_values)(current,request,new,NULL,&zero);
2256
2257 new->core.x = current->core.x;
2258 new->core.y = current->core.y;
2259 if( new_constraints->workspace.is_selected !=
2260 old_constraints->workspace.is_selected )
2261 {
2262 if( new_constraints->workspace.is_selected )
2263 {
2264 if( new_constraints->workspace.is_selectable
2265 && new_constraints->workspace.is_managed ) {
2266 new_constraints->workspace.is_selected = FALSE;
2267 SelectChild((XmWorkspaceWidget)XtParent(new), new, new_constraints,
2268 (XEvent *)NULL);
2269 }
2270 }
2271 else {
2272 new_constraints->workspace.is_selected = TRUE;
2273 UnselectChild((XmWorkspaceWidget)XtParent(new), new, new_constraints, NULL);
2274 }
2275 }
2276 if( new_constraints->workspace.is_selectable !=
2277 old_constraints->workspace.is_selectable )
2278 {
2279 if( (new_constraints->workspace.is_selectable == FALSE)
2280 && new_constraints->workspace.is_selected )
2281 UnselectChild((XmWorkspaceWidget)XtParent(new), new, new_constraints, NULL);
2282 }
2283
2284 if (new_constraints->workspace.line_invisibility !=
2285 old_constraints->workspace.line_invisibility) {
2286 if (new_constraints->workspace.line_invisibility) {
2287 DeleteWidgetFromCollideList(new);
2288 } else {
2289 AddWidgetToCollideList(new);
2290 }
2291 RerouteLines ((XmWorkspaceWidget)XtParent(new), FALSE);
2292 }
2293
2294 return retval;
2295 }
2296
2297
2298 /* Subroutine: Arm
2299 * Purpose: Action for when button1 is pressed
2300 */
Arm(XmWorkspaceWidget ww,XEvent * event)2301 static void Arm( XmWorkspaceWidget ww, XEvent* event )
2302 {
2303
2304 if (ww->workspace.auto_arrange) return ;
2305
2306 /* Check for the second click of a double click */
2307 if (ww->workspace.button1_press_mode == False)
2308 {
2309 StartRubberband(ww, event);
2310 }
2311 else
2312 {
2313 if( (event->xbutton.time - ww->workspace.time) /* Double click */
2314 <= ww->workspace.double_click_interval )
2315 {
2316 ; /* Nada */
2317 }
2318 else /* Single Click */
2319 {
2320 XmWorkspaceCallbackStruct call_value;
2321
2322 call_value.reason = XmCR_BACKGROUND;
2323 call_value.event = event;
2324 call_value.window = event->xbutton.window;
2325 call_value.selected_widget = NULL;
2326 XtCallCallbacks((Widget)ww, XmNbackgroundCallback, &call_value);
2327 }
2328 }
2329 /* Third click will not put us back here
2330 ww->workspace.time = 0;
2331 return; */
2332
2333 ww->workspace.time = event->xbutton.time;
2334 }
2335
2336 /* Subroutine: Disarm
2337 * Purpose: Action for when button1 is released
2338 */
Disarm(XmWorkspaceWidget ww,XEvent * event)2339 static void Disarm( XmWorkspaceWidget ww, XEvent* event )
2340 {
2341 Boolean bool = True;
2342
2343 if( ww->workspace.button_tracker != NULL )
2344 {
2345 event->xbutton.x += ww->workspace.track_x;
2346 event->xbutton.y += ww->workspace.track_y;
2347 ww->workspace.button_tracker(ww->workspace.track_widget,
2348 ww->workspace.track_client_data,
2349 event
2350 ,&bool
2351 );
2352 }
2353 else if( ww->workspace.is_rubberbanding )
2354 EndRubberband(ww, event);
2355 }
2356
2357 /*
2358 * Action for using the keyboard in the empty canvas
2359 * Should move selected children if any
2360 * Handling keysyms should not be done here. The proper way is to write a
2361 * translation table that ties specific key events to their operations. This
2362 * isn't working on my computer however. The keyboard's arrow keys never
2363 * percolate this far if the translation table specifies them.
2364 */
KeyboardNavigation(XmWorkspaceWidget ww,XEvent * event)2365 static void KeyboardNavigation( XmWorkspaceWidget ww, XEvent* event )
2366 {
2367 KeySym keysym;
2368 int delta_x, delta_y;
2369 int dx=1, dy=1;
2370 int i;
2371 int minx=0, miny=0;
2372 short first = True;
2373 XmWorkspaceConstraints constraints;
2374 switch (event->type) {
2375 case KeyPress:
2376 keysym = XLookupKeysym (&event->xkey, 0);
2377 if ((keysym == XK_Left) || (keysym == XK_Right) ||
2378 (keysym == XK_Up) || (keysym == XK_Down)) {
2379 if( ww->workspace.movement_is_allowed && (!ww->workspace.is_moving) &&
2380 !(event->xbutton.state & ControlMask) )
2381 {
2382 /* Prepare to move */
2383 ww->workspace.grab_x = 0;
2384 ww->workspace.grab_y = 0;
2385 ww->workspace.is_moving = TRUE;
2386 ww->workspace.is_resizing = FALSE;
2387 /* Use base variables to keep track of move applied so far */
2388 ww->workspace.base_x = 0;
2389 ww->workspace.base_y = 0;
2390 /* loop over all selected */
2391 /* set min_x, min_y so that we know when to stop sliding left,up */
2392 for(i=0; i<ww->composite.num_children; i++)
2393 {
2394 Widget child = ww->composite.children[i];
2395 constraints = WORKSPACE_CONSTRAINT(child);
2396 if(constraints->workspace.is_selected)
2397 {
2398 if (first) {
2399 minx = child->core.x;
2400 miny = child->core.y;
2401 first = 0;
2402 } else {
2403 minx = MIN(minx, child->core.x);
2404 miny = MIN(miny, child->core.y);
2405 }
2406 }
2407 }
2408 }
2409 }
2410 if (first) ww->workspace.is_moving = FALSE;
2411 delta_x = delta_y = 0;
2412 if (ww->workspace.snap_to_grid) {
2413 if (ww->workspace.horizontal_alignment != XmALIGNMENT_NONE)
2414 dx = ww->workspace.grid_width;
2415 if (ww->workspace.vertical_alignment != XmALIGNMENT_NONE)
2416 dy = ww->workspace.grid_height;
2417 }
2418 switch (keysym) {
2419 case XK_Left:
2420 if ((minx-dx)<0) ww->workspace.is_moving = FALSE;
2421 delta_x = -dx;
2422 break;
2423 case XK_Right:
2424 delta_x = dx;
2425 break;
2426 case XK_Up:
2427 if ((miny-dy)<0) ww->workspace.is_moving = FALSE;
2428 delta_y = -dy;
2429 break;
2430 case XK_Down:
2431 delta_y = dy;
2432 break;
2433 default:
2434 break;
2435 }
2436 /*
2437 * If check_overlap is turned on then we set up the surrogates
2438 * and run the check for overlapping before allow the move to
2439 * go ahead.
2440 */
2441 if ((ww->workspace.check_overlap) && (ww->workspace.is_moving)) {
2442 SaveOutlines (ww);
2443 if (Overlapping (ww, delta_x, delta_y ))
2444 ww->workspace.is_moving = FALSE;
2445 DiscardSurrogate (ww);
2446 }
2447 if (ww->workspace.is_moving) {
2448 dropResizedSurrogates (ww, delta_x, delta_y, event);
2449 }
2450 break;
2451 default:
2452 break;
2453 }
2454 }
2455 /* Subroutine: Drag
2456 * Purpose: Action for when the mouse is dragged with button1 down
2457 */
Drag(XmWorkspaceWidget ww,XEvent * event)2458 static void Drag( XmWorkspaceWidget ww, XEvent* event )
2459 {
2460 Boolean bool = True;
2461
2462 if (ww->workspace.auto_arrange) return ;
2463
2464 if( ww->workspace.button_tracker != NULL )
2465 {
2466 event->xbutton.x += ww->workspace.track_x;
2467 event->xbutton.y += ww->workspace.track_y;
2468 ww->workspace.button_tracker(ww->workspace.track_widget,
2469 ww->workspace.track_client_data,
2470 event
2471 ,&bool
2472 );
2473 }
2474 else if( ww->workspace.is_rubberbanding )
2475 StretchRubberband(ww, event);
2476 }
2477
2478
2479 /* Subroutine: GetRubberbandGC
2480 * Purpose: Get a GC with the right resources for drawing the bounding box
2481 */
GetRubberbandGC(XmWorkspaceWidget ww)2482 static void GetRubberbandGC( XmWorkspaceWidget ww )
2483 {
2484 XGCValues values;
2485 XtGCMask valueMask;
2486
2487 values.graphics_exposures = False;
2488 values.foreground = ww->manager.foreground ^ ww->core.background_pixel;
2489 values.background = 0;
2490 values.function = GXxor;
2491 values.line_style = LineOnOffDash;
2492 values.subwindow_mode = IncludeInferiors;
2493 valueMask = GCForeground | GCBackground | GCGraphicsExposures
2494 | GCFunction | GCSubwindowMode | GCLineStyle;
2495 ww->workspace.bandGC = XtGetGC((Widget)ww, valueMask, &values);
2496 values.line_style = LineSolid;
2497 /*values.foreground = WhitePixel(XtDisplay(ww), XScreenNumberOfScreen(XtScreen(ww)));*/
2498 ww->workspace.badBandGC = XtGetGC((Widget)ww, valueMask, &values);
2499 }
2500
2501
2502 /* Subroutine: DrawRubberband
2503 * Purpose: Draw or undraw the rubberband bounding box
2504 */
DrawRubberband(XmWorkspaceWidget ww)2505 static void DrawRubberband( XmWorkspaceWidget ww )
2506 {
2507 XDrawRectangles(XtDisplay(ww), XtWindow(ww), ww->workspace.bandGC,
2508 ww->workspace.rubberband, 1);
2509 ww->workspace.band_is_visible = !ww->workspace.band_is_visible;
2510 }
2511
2512 static Boolean
inHierarchy(Widget child,XmWorkspaceWidget ww,int i)2513 inHierarchy (Widget child, XmWorkspaceWidget ww, int i)
2514 {
2515 Widget parent;
2516
2517 parent = child;
2518 while ((parent) && (parent!=ww->composite.children[i]) && (parent != (Widget)ww))
2519 parent = XtParent(parent);
2520
2521 if (parent == ww->composite.children[i]) return True;
2522 return False;
2523 }
2524
2525 static XmWorkspaceWidget
WorkspaceOfWidget(Widget w)2526 WorkspaceOfWidget (Widget w)
2527 {
2528 XmWorkspaceWidget ww;
2529
2530 /*
2531 * Make the routine less restrictive in that it can cope with being invoked
2532 * by any descendant, not just the immediate children.
2533 */
2534 ww = (XmWorkspaceWidget)w;
2535
2536 while ((ww) && (!XtIsSubclass ((Widget)ww, xmWorkspaceWidgetClass)))
2537 ww = (XmWorkspaceWidget)XtParent((Widget)ww);
2538 if (!ww) return 0;
2539 if (!XtIsSubclass ((Widget)ww, xmWorkspaceWidgetClass)) return 0;
2540 return ww;
2541 }
2542
2543
ChildNavigation(Widget w,XEvent * event,String * ignore,Cardinal * ignore2)2544 static void ChildNavigation (Widget w, XEvent* event, String* ignore, Cardinal* ignore2)
2545 {
2546 XmWorkspaceWidget ww;
2547
2548 if (!(ww = WorkspaceOfWidget(w))) return ;
2549
2550 KeyboardNavigation (ww, event);
2551 }
2552
2553
2554 /* Subroutine: GrabSelections
2555 * Purpose: Action for Button1Down in child widget (accelerator translation)
2556 */
2557 /* ARGSUSED */
GrabSelections(Widget w,XEvent * event,String * params,Cardinal * num_params)2558 static void GrabSelections( Widget w, XEvent* event,
2559 String* params, Cardinal* num_params )
2560 {
2561 XmWorkspaceWidget ww;
2562 Widget grab_child;
2563 XmWorkspaceConstraints constraints;
2564 int i;
2565
2566 if (!(ww = WorkspaceOfWidget(w))) return ;
2567 ww->workspace.overlaps = FALSE;
2568
2569 if (ww->workspace.auto_arrange) return ;
2570
2571 /*
2572 * Determine which child was grabbed, but use a less restricitve method.
2573 * Don't assume that the window of the event is the window of a child
2574 * widget. Assume only the the window is descendant of a child widget.
2575 */
2576 for (i=0; i<ww->composite.num_children; i++)
2577 if (inHierarchy(XtWindowToWidget(XtDisplay(ww), event->xany.window), ww, i))
2578 break;
2579 /* This call comes from the accelerator so it should have a child */
2580 if( i >= ww->composite.num_children )
2581 return;
2582 grab_child = ww->composite.children[i];
2583 constraints = WORKSPACE_CONSTRAINT(grab_child);
2584 /* Check if child is sensitive */
2585 if( (constraints->workspace.is_selectable == FALSE ) ||
2586 (ww->workspace.is_selectable == FALSE ) )
2587 return;
2588 /* Check for the second click of a double click */
2589 if( (event->xbutton.time - ww->workspace.time)
2590 <= XtGetMultiClickTime(XtDisplay((Widget)ww)) )
2591 {
2592 XmWorkspaceCallbackStruct call_value;
2593
2594 call_value.reason = XmCR_DEFAULT_ACTION;
2595 call_value.event = event;
2596 call_value.window = event->xbutton.window;
2597 call_value.selected_widget = grab_child;
2598 XtCallCallbacks((Widget)ww, XmNdefaultActionCallback, &call_value);
2599
2600 /* Third click will not put us back here */
2601 ww->workspace.time = 0;
2602 return;
2603 }
2604 ww->workspace.time = event->xbutton.time;
2605 /* Handle change of selection status */
2606 if( constraints->workspace.is_selected == FALSE )
2607 {
2608 if( ( ((event->xbutton.state & ShiftMask) == 0)
2609 || (ww->workspace.selection_policy == XmSINGLE_SELECT))
2610 && (ww->workspace.num_selected > 0) )
2611 UnselectAll(ww, event);
2612 SelectChild(ww, grab_child, constraints, (XEvent *)event);
2613 }
2614 /* If this is a deselect, there should be no move */
2615 else if( event->xbutton.state & ShiftMask )
2616 {
2617 UnselectChild(ww, grab_child, constraints, event);
2618 return;
2619 }
2620 if( ww->workspace.movement_is_allowed &&
2621 !(event->xbutton.state & ControlMask) )
2622 {
2623 /* Prepare to move */
2624 CreateSurrogate(ww, grab_child);
2625 ww->workspace.grab_x = event->xbutton.x;
2626 ww->workspace.grab_y = event->xbutton.y;
2627 ww->workspace.is_moving = TRUE;
2628 ww->workspace.is_resizing = FALSE;
2629 /* Use base variables to keep track of move applied so far */
2630 ww->workspace.base_x = 0;
2631 ww->workspace.base_y = 0;
2632 }
2633 if( (constraints->workspace.is_v_resizable ||
2634 constraints->workspace.is_h_resizable) &&
2635 (event->xbutton.state & ControlMask) )
2636 {
2637 for(i=0; i<ww->composite.num_children; i++)
2638 {
2639 Widget child = ww->composite.children[i];
2640 constraints = WORKSPACE_CONSTRAINT(child);
2641 if(!(constraints->workspace.is_v_resizable ||
2642 constraints->workspace.is_h_resizable) &&
2643 constraints->workspace.is_selected)
2644 UnselectChild(ww, child, constraints, event);
2645 }
2646
2647 /* Prepare to resize */
2648 CreateSurrogate(ww, grab_child);
2649 ww->workspace.grab_x = grab_child->core.width;
2650 ww->workspace.grab_y = grab_child->core.height;
2651 ww->workspace.is_resizing = TRUE;
2652 ww->workspace.is_moving = FALSE;
2653 /* Use base variables to keep track of move applied so far */
2654 ww->workspace.base_x = grab_child->core.x;
2655 ww->workspace.base_y = grab_child->core.y;
2656 XWarpPointer(XtDisplay(ww), None, XtWindow(grab_child),
2657 0,0,0,0, grab_child->core.width-1, grab_child->core.height-1);
2658 }
2659 }
2660
2661
2662 /* Subroutine: MoveResizeSelections
2663 * Purpose: Action during move of selected children
2664 */
2665 /* ARGSUSED */
MoveResizeSelections(Widget w,XEvent * event,String * params,Cardinal * num_params)2666 static void MoveResizeSelections( Widget w, XEvent* event,
2667 String* params, Cardinal* num_params )
2668 {
2669 XmWorkspaceWidget ww;
2670
2671 if (!(ww = WorkspaceOfWidget(w))) return ;
2672
2673 if (ww->workspace.auto_arrange) return ;
2674
2675 if( ww->workspace.is_moving )
2676 {
2677 int delta_x, delta_y;
2678 if( ww->workspace.move_cursor_installed == FALSE )
2679 {
2680 XDefineCursor(XtDisplay(ww), XtWindow(ww),
2681 xmWorkspaceClassRec.workspace_class.move_cursor);
2682 ww->workspace.move_cursor_installed = TRUE;
2683 }
2684 delta_x = event->xbutton.x - ww->workspace.grab_x;
2685 delta_y = event->xbutton.y - ww->workspace.grab_y;
2686 if( delta_x < ww->workspace.min_x )
2687 delta_x = ww->workspace.min_x;
2688 if( delta_y < ww->workspace.min_y )
2689 delta_y = ww->workspace.min_y;
2690 delta_x -= ww->workspace.base_x;
2691 delta_y -= ww->workspace.base_y;
2692 MoveSurrogate(ww, delta_x, delta_y);
2693 }
2694 else if( ww->workspace.is_resizing)
2695 {
2696 int width, height, tx,ty;
2697 tx = event->xbutton.x;
2698 ty = event->xbutton.y;
2699 childRelative (ww, event, &tx, &ty);
2700
2701 width = MAX(10, tx);
2702 height = MAX(10, ty);
2703 ResizeSurrogate(ww, width, height);
2704 }
2705 }
2706
2707 /*
2708 * The coords in event refer to the widget of the event which might
2709 * not be an immediate child of the workspace. So, find the immediate
2710 * child, then translate coords in event to that widget.
2711 */
2712 static void
childRelative(XmWorkspaceWidget ww,XEvent * xev,int * x,int * y)2713 childRelative (XmWorkspaceWidget ww, XEvent *xev, int *x, int *y)
2714 {
2715 Widget parent;
2716 int tx, ty, i;
2717 Widget woe = XtWindowToWidget(XtDisplay(ww), xev->xany.window);
2718
2719 *x = tx = xev->xbutton.x; *y = ty = xev->xbutton.y;
2720
2721 for (i=0; i<ww->composite.num_children; i++)
2722 if (inHierarchy(woe, ww, i)) break;
2723 if (i==ww->composite.num_children) return ;
2724
2725 parent = woe;
2726 while (XtParent(parent) != (Widget)ww) {
2727 tx+= parent->core.x;
2728 ty+= parent->core.y;
2729 parent = XtParent(parent);
2730 }
2731 *x = tx; *y = ty;
2732 }
2733
2734
2735
2736 /* Subroutine: DropSelections
2737 * Purpose: Action at end of move selected children
2738 */
2739 /* ARGSUSED */
DropSelections(Widget w,XEvent * event,String * params,Cardinal * num_params)2740 static void DropSelections( Widget w, XEvent* event,
2741 String* params, Cardinal* num_params )
2742 {
2743 XmWorkspaceChildCallbackStruct cb;
2744 XmWorkspaceConstraints constraints;
2745 XmWorkspaceWidget ww;
2746 Widget child;
2747 int i;
2748 short delta_x, delta_y;
2749 short resize_x = 0;
2750 short resize_y = 0;
2751 Dimension width, height;
2752 XtWidgetGeometry request, reply;
2753 XtGeometryResult result;
2754 int n;
2755
2756 if (!(ww = WorkspaceOfWidget(w))) return ;
2757
2758 if (ww->workspace.auto_arrange) return ;
2759
2760 if( ww->workspace.is_moving )
2761 {
2762 /* We're done, so get rid of surrogate box(es) */
2763 if( ww->workspace.surrogate_is_visible )
2764 DrawSurrogate(ww);
2765 XSync(XtDisplay(ww), 0);
2766 /* Determine the move, and clip to limits */
2767 #if RESIZE_HANDLES
2768 if ((num_params) && (*num_params==1) && (!strcmp(params[0], "NE"))) delta_x = 0;
2769 else
2770 #endif
2771 delta_x = (event->xbutton.x - ww->workspace.grab_x);
2772 if( delta_x < ww->workspace.min_x )
2773 delta_x = ww->workspace.min_x;
2774 else if( delta_x > ww->workspace.max_x )
2775 resize_x = delta_x - ww->workspace.max_x;
2776 #if RESIZE_HANDLES
2777 if ((num_params) && (*num_params==1) && (!strcmp(params[0], "SW"))) delta_y = 0;
2778 else
2779 #endif
2780 delta_y = (event->xbutton.y - ww->workspace.grab_y);
2781 if( delta_y < ww->workspace.min_y )
2782 delta_y = ww->workspace.min_y;
2783 else if( delta_y > ww->workspace.max_y )
2784 resize_y = delta_y - ww->workspace.max_y;
2785 if(Overlapping (ww, delta_x-ww->workspace.base_x, delta_y-ww->workspace.base_y)) {
2786 delta_x = delta_y = 0;
2787 resize_x = resize_y = 0;
2788 }
2789 if( (resize_x > 0) || (resize_y > 0) )
2790 {
2791 /*old_width = ww->core.width;*/
2792 /*old_height = ww->core.height;*/
2793 if(resize_x > 0)
2794 request.width = ww->core.width + resize_x +
2795 ww->workspace.grid_width;
2796 else
2797 request.width = ww->core.width;
2798 if(resize_y > 0)
2799 request.height = ww->core.height + resize_y +
2800 ww->workspace.grid_height;
2801 else
2802 request.height = ww->core.height;
2803 request.request_mode = CWWidth | CWHeight;
2804 result = XtMakeGeometryRequest((Widget)ww, &request, &reply);
2805 if( result == XtGeometryAlmost )
2806 {
2807 short x_diff, y_diff;
2808 x_diff = request.width - reply.width;
2809 y_diff = request.height - reply.height;
2810 result = XtMakeGeometryRequest((Widget)ww, &reply, &request);
2811 if( x_diff > 0 )
2812 delta_x -= x_diff;
2813 if( y_diff > 0 )
2814 delta_y -= y_diff;
2815 }
2816 else if( result == XtGeometryNo )
2817 {
2818 if( resize_x > 0 )
2819 delta_x -= resize_x;
2820 if( resize_y > 0 )
2821 delta_y -= resize_y;
2822 }
2823 /* If the size of the workspace changed, reallocate the collision
2824 lists */
2825 if ( (result == XtGeometryAlmost) || (result == XtGeometryYes) )
2826 {
2827 ReallocCollideLists(ww);
2828 }
2829 }
2830 dropResizedSurrogates (ww, delta_x, delta_y, event);
2831 }
2832 if( ww->workspace.is_resizing)
2833 {
2834 int tx, ty;
2835 if( ww->workspace.surrogate_is_visible )
2836 DrawSurrogate(ww);
2837 XSync(XtDisplay(ww), 0);
2838
2839 /* Determine the size, and clip to limits */
2840 childRelative (ww, event, &tx, &ty);
2841 width = MAX(10, tx);
2842 height = MAX(10, ty);
2843 #if RESIZE_HANDLES
2844 if ((num_params) && (*num_params == 1)) {
2845 int i;
2846
2847 for (i=0; i<ww->composite.num_children; i++) {
2848 child = ww->composite.children[i];
2849 constraints = WORKSPACE_CONSTRAINT(child);
2850 if (constraints->workspace.is_selected) {
2851 if (!strcmp (params[0], "NW")) {
2852 width = child->core.width - event->xbutton.x;
2853 height = child->core.height - event->xbutton.y;
2854 } else if (!strcmp (params[0], "NE")) {
2855 height = child->core.height - event->xbutton.y;
2856 } else if (!strcmp (params[0], "SW")) {
2857 width = child->core.width - event->xbutton.x;
2858 }
2859 break;
2860 }
2861 }
2862 }
2863 #endif
2864 for( i=ww->composite.num_children-1; i>=0; i-- )
2865 {
2866 child = ww->composite.children[i];
2867 constraints = WORKSPACE_CONSTRAINT(child);
2868 if(constraints->workspace.is_selected)
2869 {
2870 n = 0;
2871 cb.height = 0;
2872 cb.width = 0;
2873 if(constraints->workspace.is_h_resizable)
2874 {
2875 /*XtSetArg(wargs[n], XmNwidth, width);*/ n++;
2876 cb.width = width;
2877 } else cb.width = child->core.width;
2878 if(constraints->workspace.is_v_resizable)
2879 {
2880 /*XtSetArg(wargs[n], XmNheight, height);*/ n++;
2881 cb.height = height;
2882 } else cb.height = child->core.height;
2883 if(n > 0)
2884 {
2885 /*XtSetValues(child, wargs, n);*/
2886 XtResizeWidget (child, cb.width, cb.height, child->core.border_width);
2887
2888 constraints->workspace.x_right = constraints->workspace.x_left +
2889 cb.width;
2890 constraints->workspace.y_lower = constraints->workspace.y_upper +
2891 cb.height;
2892 CallConstraintCallbacks(child,
2893 constraints->workspace.resizing_callbacks,
2894 (XmAnyCallbackStruct *)&cb);
2895 }
2896 }
2897 }
2898 ww->workspace.is_resizing = FALSE;
2899 /* Deal with overlaps by movement or stacking */
2900 if( ww->bulletin_board.allow_overlap )
2901 RestackSelectedChildren(ww);
2902 else
2903 PerformSpaceWars(ww, FALSE, event);
2904 }
2905 }
2906
2907 /*
2908 * Broken out of DropSelections so that the code can be called from a similar
2909 * operation performed using the keyboard instead of the mouse
2910 */
dropResizedSurrogates(XmWorkspaceWidget ww,int delta_x,int delta_y,XEvent * event)2911 static void dropResizedSurrogates (XmWorkspaceWidget ww, int delta_x, int delta_y, XEvent* event)
2912 {
2913 XmWorkspaceConstraints constraints;
2914 XmWorkspaceLine line;
2915 Widget child;
2916 int i;
2917 if( (delta_x != 0) || (delta_y != 0) ) {
2918 /* Go through all the children and see if they were selected. If
2919 * they were, "hide" them in the collide lists, so they do not
2920 * cause collisions with the ones that are moved first. For the
2921 * lines, simply remove them from the lists. They will be added
2922 * back in when they are re-reouted
2923 */
2924 for( i=ww->composite.num_children-1; i>=0; i-- )
2925 {
2926 child = ww->composite.children[i];
2927 constraints = WORKSPACE_CONSTRAINT(child);
2928 if( constraints->workspace.is_selected == TRUE )
2929 {
2930 constraints->workspace.x_delta = delta_x;
2931 constraints->workspace.y_delta = delta_y;
2932 if( ww->workspace.snap_to_grid )
2933 SnapToGrid(ww, child, constraints, FALSE);
2934 if ( (constraints->workspace.x_delta != 0 ) ||
2935 (constraints->workspace.y_delta != 0) )
2936 {
2937 if (!constraints->workspace.line_invisibility)
2938 HideWidgetInCollideList(ww, child);
2939 for( line = constraints->workspace.source_lines;
2940 line;
2941 line = line->src_next )
2942 {
2943 if( line->is_to_be_moved == FALSE )
2944 {
2945 RemoveLineFromCollideList(ww, line);
2946 line->is_to_be_moved = TRUE;
2947 AugmentExposureAreaForLine(ww, line);
2948 }
2949 }
2950 for( line = constraints->workspace.destination_lines;
2951 line;
2952 line = line->dst_next )
2953 {
2954 if( line->is_to_be_moved == FALSE )
2955 {
2956 RemoveLineFromCollideList(ww, line);
2957 line->is_to_be_moved = TRUE;
2958 AugmentExposureAreaForLine(ww, line);
2959 }
2960 }
2961 }
2962 }
2963 }
2964 for( i=ww->composite.num_children-1; i>=0; i-- )
2965 {
2966 child = ww->composite.children[i];
2967 constraints = WORKSPACE_CONSTRAINT(child);
2968 if( constraints->workspace.is_selected == TRUE )
2969 {
2970 constraints->workspace.x_delta = delta_x;
2971 constraints->workspace.y_delta = delta_y;
2972 if( ww->workspace.snap_to_grid )
2973 SnapToGrid(ww, child, constraints, FALSE);
2974 if ( ((constraints->workspace.x_delta != 0) ||
2975 (constraints->workspace.y_delta != 0)) &&
2976 !ww->workspace.suppress_callbacks )
2977 {
2978 XmWorkspacePositionChangeCallbackStruct call_data;
2979
2980 call_data.child = child;
2981 call_data.x = constraints->workspace.x_left +
2982 constraints->workspace.x_delta;
2983 call_data.y = constraints->workspace.y_upper +
2984 constraints->workspace.y_delta;
2985 call_data.event = event;
2986 XtCallCallbacks((Widget)
2987 ww, XmNpositionChangeCallback, &call_data);
2988 }
2989 if( ww->bulletin_board.allow_overlap )
2990 MoveChild(ww, child, constraints);
2991 else
2992 {
2993 if ((POLICY(ww) == XmSPACE_WARS_LEFT_MOST_STAYS)||
2994 (POLICY(ww) == XmSPACE_WARS_SELECTED_MIGRATE))
2995 /* Register position where widget was dropped */
2996 constraints->workspace.x_index += delta_x;
2997 else
2998 /* Register position post-snap_to_grid */
2999 constraints->workspace.x_index +=
3000 constraints->workspace.x_delta;
3001 }
3002 }
3003 }
3004 }
3005 /* Deal with overlaps by movement or stacking */
3006 if( ww->bulletin_board.allow_overlap )
3007 RestackSelectedChildren(ww);
3008 else
3009 (void)PerformSpaceWars(ww, FALSE, event);
3010 ww->workspace.is_moving = FALSE;
3011 /* Redraw any affected application lines */
3012 if( ww->workspace.lines )
3013 {
3014 /* Establish new routes for lines that were moved */
3015 RerouteLines(ww, FALSE);
3016 if ( (delta_x != 0) || (delta_y != 0) )
3017 {
3018 if( ww->workspace.expose_left < ww->workspace.expose_right )
3019 {
3020 if (XtWindow(ww))
3021 XClearArea(XtDisplay(ww), XtWindow(ww),
3022 ww->workspace.expose_left,
3023 ww->workspace.expose_upper,
3024 ww->workspace.expose_right -
3025 ww->workspace.expose_left,
3026 ww->workspace.expose_lower -
3027 ww->workspace.expose_upper, False);
3028 }
3029 }
3030 }
3031 if( ww->workspace.move_cursor_installed )
3032 {
3033 if (XtWindow(ww))
3034 XUndefineCursor(XtDisplay(ww), XtWindow(ww));
3035 ww->workspace.move_cursor_installed = FALSE;
3036 }
3037 }
3038
3039 /* Subroutine: MoveChild
3040 * Purpose: Move child widget by given offsets and update constraints notes
3041 */
MoveChild(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints)3042 static void MoveChild( XmWorkspaceWidget ww, Widget child,
3043 XmWorkspaceConstraints constraints )
3044 {
3045 XmWorkspaceLine line;
3046 register short x_delta, y_delta;
3047
3048 x_delta = constraints->workspace.x_delta;
3049 y_delta = constraints->workspace.y_delta;
3050 if( (x_delta == 0) && (y_delta == 0) )
3051 return;
3052 constraints->workspace.x_left += x_delta;
3053 constraints->workspace.x_center += x_delta;
3054 constraints->workspace.x_right += x_delta;
3055 constraints->workspace.y_upper += y_delta;
3056 constraints->workspace.y_center += y_delta;
3057 constraints->workspace.y_lower += y_delta;
3058 XtMoveWidget(child, constraints->workspace.x_left,
3059 constraints->workspace.y_upper);
3060 if (!constraints->workspace.line_invisibility)
3061 ChangeWidgetInCollideList(ww, child);
3062 ResetChild(ww, constraints);
3063 /* Note movement for managed lines */
3064 for( line = constraints->workspace.source_lines;
3065 line;
3066 line = line->src_next )
3067 {
3068 line->src_x += x_delta;
3069 line->src_y += y_delta;
3070 if( line->is_to_be_moved == FALSE )
3071 {
3072 line->is_to_be_moved = TRUE;
3073 AugmentExposureAreaForLine(ww, line);
3074 }
3075 }
3076 for( line = constraints->workspace.destination_lines;
3077 line;
3078 line = line->dst_next )
3079 {
3080 line->dst_x += x_delta;
3081 line->dst_y += y_delta;
3082 if( line->is_to_be_moved == FALSE )
3083 {
3084 line->is_to_be_moved = TRUE;
3085 AugmentExposureAreaForLine(ww, line);
3086 }
3087 }
3088 }
3089
3090
3091 /* Subroutine: ResetChild
3092 * Purpose: Reset parameters changed during transitional state to
3093 * their default or static state values.
3094 */
ResetChild(XmWorkspaceWidget ww,XmWorkspaceConstraints constraints)3095 static void ResetChild( XmWorkspaceWidget ww,
3096 XmWorkspaceConstraints constraints )
3097 {
3098 /* Unset move request */
3099 constraints->workspace.x_delta = 0;
3100 constraints->workspace.y_delta = 0;
3101 /* Register current sort position */
3102 if( ww->workspace.sort_policy == XmALIGNMENT_BEGINNING )
3103 constraints->workspace.x_index = constraints->workspace.x_left;
3104 else if( ww->workspace.sort_policy == XmALIGNMENT_CENTER )
3105 constraints->workspace.x_index = constraints->workspace.x_center;
3106 else
3107 constraints->workspace.x_index = constraints->workspace.x_right;
3108 }
3109
3110
3111 /* Subroutine: SnapToGrid
3112 * Purpose: Given a widget, choose the nearest grid position based
3113 * on the current policy;
3114 */
SnapToGrid(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints,Boolean increase)3115 static void SnapToGrid( XmWorkspaceWidget ww, Widget child,
3116 XmWorkspaceConstraints constraints, Boolean increase )
3117 {
3118 int x, width;
3119 int y, height;
3120
3121 if (XtClass(child) == xmWorkspaceWidgetClass) return ;
3122 x = constraints->workspace.x_left + constraints->workspace.x_delta;
3123 width = 1 + constraints->workspace.x_right - constraints->workspace.x_left;
3124 Align1D(&x, width, ww->workspace.grid_width,
3125 ww->workspace.horizontal_alignment, increase);
3126 constraints->workspace.x_delta = x - constraints->workspace.x_left;
3127 y = constraints->workspace.y_upper + constraints->workspace.y_delta;
3128 height =
3129 1 + constraints->workspace.y_lower - constraints->workspace.y_upper;
3130 Align1D(&y, height, ww->workspace.grid_height,
3131 ww->workspace.vertical_alignment, increase);
3132 constraints->workspace.y_delta = y - constraints->workspace.y_upper;
3133 }
3134
3135
3136 /* Subroutine: Align1D
3137 * Purpose: Set position on one axis according to rules of alignment
3138 * Note: If increase is set, only positive adjustments will be made
3139 */
Align1D(int * x,int width,int grid,unsigned char alignment,Boolean increase_only)3140 static void Align1D( int* x, int width, int grid, unsigned char alignment,
3141 Boolean increase_only )
3142 {
3143 int index, x_off, center;
3144 Boolean odd; /* Is (width / grid) an odd number? */
3145
3146 if( grid == 1 )
3147 return;
3148
3149 switch( alignment )
3150 {
3151 case XmALIGNMENT_NONE:
3152 break;
3153 case XmALIGNMENT_BEGINNING:
3154 if( increase_only )
3155 index = (*x + 1.5*grid - 1) / grid;
3156 else
3157 index = (*x + .5*grid) / grid;
3158 *x = index * grid;
3159 break;
3160 case XmALIGNMENT_CENTER:
3161 /* x_off is center in widget for first grid cell if 1 or more used */
3162 /* (-1 seems to work better, but I don't really know why) */
3163 x_off = (width % grid) / 2;
3164 odd = (width / grid) % 2;
3165 center = grid / 2;
3166
3167 if( increase_only )
3168 /* -1 prevents advancing if perfect fit */
3169 index = (*x + x_off + center - 1) / grid;
3170 else
3171 index = (*x + x_off + odd * center) / grid;
3172 *x = (grid * index) + !odd * center - x_off;
3173 while(*x < 0)
3174 *x += grid;
3175 break;
3176
3177 case XmALIGNMENT_END:
3178 index = (*x + width + 0.5*grid - 1) / grid;
3179 *x = (index * grid) - width;
3180 break;
3181 default:
3182 break;
3183 }
3184 if (*x < 0) *x = 0;
3185 }
3186
3187
3188 /* Subroutine: StartRubberband
3189 * Purpose: Initialize rubberbanding action
3190 */
StartRubberband(XmWorkspaceWidget ww,XEvent * event)3191 static void StartRubberband( XmWorkspaceWidget ww, XEvent* event )
3192 {
3193 if( ww->workspace.selection_policy != XmEXTENDED_SELECT )
3194 return;
3195 if( ww->workspace.bandGC == NULL )
3196 GetRubberbandGC(ww);
3197 /* Shift at this point means leave unboxed items alone */
3198 if( (event->xbutton.state & ShiftMask) == 0 )
3199 {
3200 UnaccentAll(ww, event);
3201 ww->workspace.shift_is_applied = FALSE;
3202 }
3203 else
3204 {
3205 register XmWorkspaceConstraints constraints;
3206 int i;
3207 /* Update looks at prior inclusion status in this case, so clean up */
3208 /* Clear all inclusion marks for a fresh start */
3209 for( i=0; i<ww->composite.num_children; i++ )
3210 {
3211 constraints = WORKSPACE_CONSTRAINT(ww->composite.children[i]);
3212 constraints->workspace.is_within_band = FALSE;
3213 }
3214 ww->workspace.shift_is_applied = TRUE;
3215 }
3216 ww->workspace.is_rubberbanding = TRUE;
3217 ww->workspace.base_x = ww->workspace.rubberband[0].x = event->xbutton.x;
3218 ww->workspace.base_y = ww->workspace.rubberband[0].y = event->xbutton.y;
3219 ww->workspace.rubberband[0].width = ww->workspace.rubberband[0].height = 1;
3220 /*
3221 DrawRubberband(ww);
3222 */
3223 }
3224
3225
3226 /* Subroutine: StretchRubberband
3227 * Purpose: Change the rubberband bounding box and do all that implies
3228 */
StretchRubberband(XmWorkspaceWidget ww,XEvent * event)3229 static void StretchRubberband( XmWorkspaceWidget ww, XEvent * event )
3230 {
3231 unsigned char direction;
3232
3233 if( ww->workspace.is_rubberbanding )
3234 {
3235 if( ww->workspace.band_is_visible )
3236 DrawRubberband(ww);
3237 if( event->xbutton.x > ww->workspace.base_x )
3238 {
3239 ww->workspace.rubberband[0].x = ww->workspace.base_x;
3240 ww->workspace.rubberband[0].width =
3241 1 + event->xbutton.x - ww->workspace.base_x;
3242 direction = SZ_RIGHT;
3243 }
3244 else
3245 {
3246 ww->workspace.rubberband[0].x = event->xbutton.x;
3247 ww->workspace.rubberband[0].width =
3248 1 + ww->workspace.base_x - event->xbutton.x;
3249 direction = SZ_LEFT;
3250 }
3251 if( event->xbutton.y > ww->workspace.base_y )
3252 {
3253 ww->workspace.rubberband[0].y = ww->workspace.base_y;
3254 ww->workspace.rubberband[0].height =
3255 1 + event->xbutton.y - ww->workspace.base_y;
3256 direction += SZ_LOWER;
3257 }
3258 else
3259 {
3260 ww->workspace.rubberband[0].y = event->xbutton.y;
3261 ww->workspace.rubberband[0].height =
3262 1 + ww->workspace.base_y - event->xbutton.y;
3263 direction += SZ_UPPER;
3264 }
3265 /* Make sure band is not present when/if widget changes appearance */
3266 XSync(XtDisplay(ww), False);
3267 if( ww->workspace.size_xx_installed != direction )
3268 {
3269 if (XtWindow(ww))
3270 XDefineCursor(XtDisplay(ww), XtWindow(ww),
3271 xmWorkspaceClassRec.workspace_class.size_cursor[direction]);
3272 ww->workspace.size_xx_installed = direction;
3273 }
3274 /* Check for selection changes */
3275 UpdateRubberbandSelections(ww, event);
3276 /* Make sure selection changes are done before drawing new band */
3277 XSync(XtDisplay(ww), False);
3278 DrawRubberband(ww);
3279 XSync(XtDisplay(ww), False);
3280 }
3281 }
3282
3283
3284 /* Subroutine: EndRubberband
3285 * Purpose: Terminate rubberbanding action
3286 */
EndRubberband(XmWorkspaceWidget ww,XEvent * event)3287 static void EndRubberband( XmWorkspaceWidget ww, XEvent* event )
3288 {
3289 Widget child;
3290 XmWorkspaceConstraints constraints;
3291 int i;
3292
3293 if( ww->workspace.is_rubberbanding )
3294 {
3295 ww->workspace.is_rubberbanding = FALSE;
3296 if( ww->workspace.band_is_visible )
3297 {
3298 DrawRubberband(ww);
3299 XSync(XtDisplay(ww), 0);
3300 }
3301 if( ww->workspace.size_xx_installed != SZ_NONE )
3302 {
3303 XUndefineCursor(XtDisplay(ww), XtWindow(ww));
3304 ww->workspace.size_xx_installed = SZ_NONE;
3305 }
3306 /* Send notification to children whose selection status has changed */
3307 for( i=0; i<ww->composite.num_children; i++ )
3308 {
3309 child = ww->composite.children[i];
3310 constraints = WORKSPACE_CONSTRAINT(child);
3311 if( constraints->workspace.will_be_selected !=
3312 constraints->workspace.is_selected )
3313 {
3314 if( constraints->workspace.will_be_selected )
3315 SelectChild(ww, ww->composite.children[i],
3316 constraints, (XEvent *)event);
3317 else
3318 UnselectChild(ww, ww->composite.children[i],
3319 constraints, event);
3320 }
3321 }
3322 /*
3323 RestackSelectedChildren(ww);
3324 */
3325 }
3326 }
3327
3328
3329 /* Subroutine: UpdateRubberbandSelections
3330 * Purpose: Update selections to reflect current bounding box
3331 * Note: is_within_band shows whether widget was previously counted in
3332 * will_be_selected shows whether has been marked for selection
3333 * is_accented shows if widget has visible sign of being marked
3334 * is_selected shows if last callback for widget was select true.
3335 */
UpdateRubberbandSelections(XmWorkspaceWidget ww,XEvent * event)3336 static void UpdateRubberbandSelections( XmWorkspaceWidget ww, XEvent* event )
3337 {
3338 XmWorkspaceConstraints constraints;
3339 register short x1, x2, y1, y2;
3340 int i;
3341 Boolean included;
3342
3343 if(!ww->workspace.is_selectable) return;
3344
3345 x1 = ww->workspace.rubberband[0].x;
3346 x2 = x1 + ww->workspace.rubberband[0].width - 1;
3347 y1 = ww->workspace.rubberband[0].y;
3348 y2 = y1 + ww->workspace.rubberband[0].height - 1;
3349 for( i=ww->composite.num_children-1; i>=0; i-- )
3350 {
3351 constraints = WORKSPACE_CONSTRAINT(ww->composite.children[i]);
3352 if( constraints->workspace.is_selectable )
3353 {
3354 if( ww->workspace.inclusion_policy == XmINCLUDE_ANY )
3355 {
3356 /* If any side beyond rubberband range, no part is included */
3357 if( (x2 < constraints->workspace.x_left)
3358 || (x1 > constraints->workspace.x_right)
3359 || (y2 < constraints->workspace.y_upper)
3360 || (y1 > constraints->workspace.y_lower) )
3361 included = FALSE;
3362 else
3363 included = TRUE;
3364 }
3365 else if( ww->workspace.inclusion_policy == XmINCLUDE_CENTER )
3366 {
3367 if( (x1 < constraints->workspace.x_center)
3368 && (x2 > constraints->workspace.x_center)
3369 && (y1 < constraints->workspace.y_center)
3370 && (y2 > constraints->workspace.y_center) )
3371 included = TRUE;
3372 else
3373 included = FALSE;
3374 }
3375 else /* XmINCLUDE_ALL */
3376 {
3377 if( (x1 < constraints->workspace.x_left)
3378 && (x2 > constraints->workspace.x_right)
3379 && (y1 < constraints->workspace.y_upper)
3380 && (y2 > constraints->workspace.y_lower) )
3381 included = TRUE;
3382 else
3383 included = FALSE;
3384 }
3385 /* With shift, we are toggling states */
3386 if( ww->workspace.shift_is_applied )
3387 {
3388 /* If inclusion status changed since last we checked */
3389 if( constraints->workspace.is_within_band != included )
3390 {
3391 if( constraints->workspace.will_be_selected )
3392 UnaccentChild(ww, ww->composite.children[i],
3393 constraints, event);
3394 else
3395 AccentChild(ww, ww->composite.children[i],
3396 constraints, event);
3397 constraints->workspace.is_within_band = included;
3398 }
3399 }
3400 else
3401 {
3402 if( included )
3403 {
3404 if( constraints->workspace.will_be_selected == FALSE )
3405 AccentChild(ww, ww->composite.children[i],
3406 constraints, event);
3407 }
3408 else
3409 {
3410 if( constraints->workspace.will_be_selected == TRUE )
3411 UnaccentChild(ww, ww->composite.children[i],
3412 constraints, event);
3413 }
3414 }
3415 }
3416 }
3417 }
3418
3419
3420 /* Subroutine: UnselectAll
3421 * Purpose: Unselect all selected children widgets
3422 */
UnselectAll(XmWorkspaceWidget ww,XEvent * event)3423 static void UnselectAll( XmWorkspaceWidget ww, XEvent* event )
3424 {
3425 XmWorkspaceConstraints constraints;
3426 Widget child;
3427 int i;
3428
3429 for( i=ww->composite.num_children-1; i>=0; i-- )
3430 {
3431 child = ww->composite.children[i];
3432 constraints = WORKSPACE_CONSTRAINT(child);
3433 if( constraints->workspace.is_selected == TRUE )
3434 UnselectChild(ww, child, constraints, event);
3435 }
3436 }
3437
3438
3439 /* Subroutine: SelectChild
3440 * Purpose: Perform selection on given child widget
3441 */
SelectChild(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints,XEvent * event)3442 static void SelectChild( XmWorkspaceWidget ww, Widget child,
3443 XmWorkspaceConstraints constraints, XEvent* event )
3444 {
3445 XmWorkspaceChildCallbackStruct cb;
3446
3447 /* Make sure selection is visually accented */
3448 if( constraints->workspace.will_be_selected == FALSE )
3449 AccentChild(ww, child, constraints, event);
3450 /* Select this widget */
3451 if (constraints->workspace.is_selected == FALSE)
3452 ++ww->workspace.num_selected;
3453 constraints->workspace.is_selected = TRUE;
3454 /* Tell the widget that it has been Selected */
3455 cb.reason = XmCR_SELECT;
3456 cb.event = event;
3457 cb.status = TRUE;
3458 /* Call the selection callback */
3459 if(!ww->workspace.suppress_callbacks)
3460 {
3461 CallConstraintCallbacks(child, constraints->workspace.select_callbacks,
3462 (XmAnyCallbackStruct *)&cb);
3463 }
3464 XtCallCallbacks((Widget)ww, XmNselectionCallback, &cb);
3465 }
3466
3467
3468 /* Subroutine: UnselectChild
3469 * Purpose: Unperform selection on given child widget
3470 */
UnselectChild(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints,XEvent * event)3471 static void UnselectChild( XmWorkspaceWidget ww, Widget child,
3472 XmWorkspaceConstraints constraints, XEvent* event )
3473 {
3474 XmWorkspaceChildCallbackStruct cb;
3475
3476 /* Make sure selection is visually unaccented */
3477 if( constraints->workspace.will_be_selected == TRUE )
3478 UnaccentChild(ww, child, constraints, event);
3479 /* Deselect this widget */
3480 if (constraints->workspace.is_selected == TRUE)
3481 --ww->workspace.num_selected;
3482 constraints->workspace.is_selected = FALSE;
3483
3484 if(ww->workspace.suppress_callbacks)
3485 return;
3486
3487 /* Tell the widget that it has been deselected */
3488 cb.reason = XmCR_SELECT;
3489 cb.event = event;
3490 cb.status = FALSE;
3491 /* Call the selection callback */
3492 CallConstraintCallbacks(child, constraints->workspace.select_callbacks,
3493 (XmAnyCallbackStruct *)&cb);
3494 XtCallCallbacks((Widget)ww, XmNselectionCallback, &cb);
3495 }
3496
3497
3498 /* Subroutine: UnaccentAll
3499 * Purpose: Remove accents from all accented children
3500 */
UnaccentAll(XmWorkspaceWidget ww,XEvent * event)3501 static void UnaccentAll( XmWorkspaceWidget ww, XEvent* event )
3502 {
3503 XmWorkspaceConstraints constraints;
3504 Widget child;
3505 int i;
3506
3507 for( i=ww->composite.num_children-1; i>=0; i-- )
3508 {
3509 child = ww->composite.children[i];
3510 constraints = WORKSPACE_CONSTRAINT(child);
3511 if( constraints->workspace.will_be_selected == TRUE )
3512 UnaccentChild(ww, child, constraints, event);
3513 }
3514 }
3515
3516
3517 /* Subroutine: AccentChild
3518 * Purpose: Apply any indicated visual accent and call accent callback
3519 */
AccentChild(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints,XEvent * event)3520 static void AccentChild( XmWorkspaceWidget ww, Widget child,
3521 XmWorkspaceConstraints constraints, XEvent* event )
3522 {
3523 XmWorkspaceChildCallbackStruct cb;
3524 Arg warg;
3525
3526 if( ww->workspace.accent_policy == XmACCENT_BACKGROUND )
3527 {
3528 constraints->workspace.accent_uncolor = child->core.background_pixel;
3529 if( XmIsPrimitive(child) || XmIsManager(child) )
3530 {
3531 register int thickness;
3532 if( XmIsPrimitive(child) )
3533 thickness =
3534 ((XmPrimitiveWidget)child)->primitive.shadow_thickness +
3535 ((XmPrimitiveWidget)child)->primitive.highlight_thickness;
3536 else
3537 thickness = ((XmManagerWidget)child)->manager.shadow_thickness;
3538 child->core.background_pixel = ww->workspace.accent_color;
3539 if (XtWindow(child)) {
3540 XSetWindowBackground(XtDisplay(child), XtWindow(child),
3541 child->core.background_pixel);
3542 XClearArea(XtDisplay(child), XtWindow(child), thickness, thickness,
3543 child->core.width - (thickness + thickness),
3544 child->core.height - (thickness + thickness), True);
3545 }
3546 }
3547 else
3548 {
3549 XtSetArg(warg, XmNbackground, ww->workspace.accent_color);
3550 XtSetValues((Widget)child, &warg, 1);
3551 }
3552 constraints->workspace.is_accented = TRUE;
3553 }
3554 else if( ww->workspace.accent_policy == XmACCENT_BORDER )
3555 {
3556 constraints->workspace.accent_uncolor = child->core.border_pixel;
3557 XtSetArg(warg, XmNborderColor, ww->workspace.accent_color);
3558 XtSetValues((Widget)child, &warg, 1);
3559 constraints->workspace.is_accented = TRUE;
3560 }
3561 cb.reason = XmCR_ACCENT;
3562 cb.event = event;
3563 cb.status = ON;
3564 CallConstraintCallbacks(child, constraints->workspace.accent_callbacks,
3565 (XmAnyCallbackStruct *)&cb);
3566 constraints->workspace.will_be_selected = TRUE;
3567 }
3568
3569
3570 /* Subroutine: UnaccentChild
3571 * Purpose: Remove any visual accents and call accent callback
3572 */
UnaccentChild(XmWorkspaceWidget ww,Widget child,XmWorkspaceConstraints constraints,XEvent * event)3573 static void UnaccentChild( XmWorkspaceWidget ww, Widget child,
3574 XmWorkspaceConstraints constraints, XEvent* event )
3575 {
3576 XmWorkspaceChildCallbackStruct cb;
3577 Arg warg;
3578
3579 if( constraints->workspace.is_accented == TRUE )
3580 {
3581 if( ww->workspace.accent_policy == XmACCENT_BACKGROUND )
3582 {
3583 if( XmIsPrimitive(child) || XmIsManager(child) )
3584 {
3585 register int thickness;
3586 if( XmIsPrimitive(child) )
3587 thickness =
3588 ((XmPrimitiveWidget)child)->primitive.shadow_thickness +
3589 ((XmPrimitiveWidget)child)->primitive.highlight_thickness;
3590 else
3591 thickness =
3592 ((XmManagerWidget)child)->manager.shadow_thickness;
3593 child->core.background_pixel =
3594 constraints->workspace.accent_uncolor;
3595 if (XtWindow(child)) {
3596 XSetWindowBackground(XtDisplay(child), XtWindow(child),
3597 child->core.background_pixel);
3598 XClearArea(XtDisplay(child), XtWindow(child),
3599 thickness, thickness,
3600 child->core.width - (thickness + thickness),
3601 child->core.height - (thickness + thickness), True);
3602 }
3603 }
3604 else
3605 {
3606 XtSetArg(warg, XmNbackground,
3607 constraints->workspace.accent_uncolor);
3608 XtSetValues((Widget)child, &warg, 1);
3609 }
3610 }
3611 else if( ww->workspace.accent_policy == XmACCENT_BORDER )
3612 {
3613 XtSetArg(warg, XmNborderColor,
3614 constraints->workspace.accent_uncolor);
3615 XtSetValues((Widget)child, &warg, 1);
3616 }
3617 constraints->workspace.is_accented = FALSE;
3618 }
3619 cb.reason = XmCR_ACCENT;
3620 cb.event = event;
3621 cb.status = OFF;
3622 CallConstraintCallbacks(child, constraints->workspace.accent_callbacks,
3623 (XmAnyCallbackStruct *)&cb);
3624 constraints->workspace.will_be_selected = FALSE;
3625 }
3626
RaiseSelections(Widget w,XEvent * event,String * params,Cardinal * num_params)3627 static void RaiseSelections( Widget w, XEvent* event,
3628 String* params, Cardinal* num_params )
3629 {
3630 XmWorkspaceWidget ww;
3631
3632 if (!(ww = WorkspaceOfWidget(w))) return ;
3633 if (ww->workspace.auto_arrange) return ;
3634 RestackSelectedChildren (ww);
3635 }
3636
3637 /* Subroutine: RestackSelectedChildren
3638 * Purpose: Change the stacking order such that all moved children appear
3639 * in front of all unmoved children.
3640 */
RestackSelectedChildren(XmWorkspaceWidget ww)3641 static void RestackSelectedChildren( XmWorkspaceWidget ww )
3642 {
3643 int i;
3644 if( ww->workspace.num_selected == 1 )
3645 {
3646 XmWorkspaceConstraints constraints;
3647 Widget child;
3648
3649 for( i=0; i<ww->composite.num_children; i++ )
3650 {
3651 child = ww->composite.children[i];
3652 constraints = WORKSPACE_CONSTRAINT(child);
3653 if( constraints->workspace.is_selected == TRUE )
3654 {
3655 if (XtWindow(ww->composite.children[i]))
3656 XRaiseWindow(XtDisplay(ww), XtWindow(ww->composite.children[i]));
3657 return;
3658 }
3659 }
3660 }
3661 else if (XtWindow(ww))
3662 {
3663 Window root, parent, *children, *new_order;
3664 int selCnt, under, over;
3665 unsigned int num_children;
3666
3667 /*
3668 * Problem: the number of widgets in ww->composite.num_children may
3669 * not be the same a num_children returned from XQueryTree.
3670 * That makes this a garbage-in garbage-out situation.
3671 */
3672
3673 /* Get current stacking order as bottom-first list */
3674 (void)XQueryTree(XtDisplay(ww), XtWindow(ww), &root, &parent,
3675 &children, &num_children);
3676 new_order = (Window *)XtCalloc(num_children, sizeof(Window));
3677 under = num_children - 1;
3678 selCnt = 0;
3679 for( i=0; i<num_children; i++ )
3680 if( ChildWindowIsSelected(ww, children[i]) ) selCnt++;
3681
3682 over = selCnt - 1;
3683 for( i=0; i<num_children; i++ )
3684 {
3685 if( ChildWindowIsSelected(ww, children[i]) )
3686 {
3687 new_order[over] = children[i];
3688 over--;
3689 }
3690 else
3691 {
3692 new_order[under] = children[i];
3693 under--;
3694 }
3695 }
3696 /* Stack according to the top-first list */
3697 XRestackWindows(XtDisplay(ww), new_order, num_children);
3698 XtFree((char*)new_order);
3699 XFree((void *)children);
3700 }
3701 }
3702
3703
3704 /* Subroutine: ChildWindowIsSelected
3705 * Purpose: Determine if passed window belongs to a child which is selected
3706 */
ChildWindowIsSelected(XmWorkspaceWidget ww,Window child)3707 static Boolean ChildWindowIsSelected( XmWorkspaceWidget ww, Window child )
3708 {
3709 int i;
3710 for( i=0; i<ww->composite.num_children; i++ )
3711 {
3712 if( XtWindow(ww->composite.children[i]) == child )
3713 {
3714 XmWorkspaceConstraints constraints =
3715 WORKSPACE_CONSTRAINT(ww->composite.children[i]);
3716 return constraints->workspace.is_selected;
3717 }
3718 }
3719 return FALSE;
3720 }
3721
3722
3723 /* Subroutine: SetGridBackground
3724 * Purpose: Install a background pixmap with grid marks
3725 */
SetGridBackground(XmWorkspaceWidget ww,Boolean change)3726 static void SetGridBackground( XmWorkspaceWidget ww, Boolean change )
3727 {
3728 Pixmap pixmap;
3729 XGCValues values;
3730 XtGCMask valueMask;
3731 GC gc;
3732 int width, height;
3733 Boolean draw_grid_marks;
3734 Screen* scrptr = ww->core.screen;
3735 Window rootw = RootWindowOfScreen(scrptr);
3736
3737 /* Check if drawing the grid marks is requested */
3738 if( ww->workspace.snap_to_grid
3739 && ( (ww->workspace.horizontal_draw_grid != XmDRAW_NONE)
3740 || (ww->workspace.vertical_draw_grid != XmDRAW_NONE)) )
3741 {
3742 width = ww->workspace.grid_width;
3743 height = ww->workspace.grid_height;
3744 draw_grid_marks = True;
3745 }
3746 else
3747 {
3748 #if DUPLICATE_XT_STUFF
3749 #else
3750 XtVaSetValues ((Widget)ww, XmNbackgroundPixmap, XtUnspecifiedPixmap, NULL);
3751 return ;
3752 #endif
3753 /* When window is created, it has a solid background by default */
3754 if( change == False )
3755 return;
3756 /* If pixmap is changed, we must manufacture a solid background */
3757 width = 16;
3758 height = 16;
3759 draw_grid_marks = False;
3760 }
3761
3762 if (!XtWindow(ww)) return ;
3763
3764 pixmap = XCreatePixmap(XtDisplay(ww), rootw,
3765 width, height, ww->core.depth);
3766 values.graphics_exposures = False;
3767 values.foreground = ww->core.background_pixel;
3768 values.background = ww->core.background_pixel;
3769 values.function = GXcopy;
3770 values.line_style = LineOnOffDash;
3771 values.dashes = 1;
3772 values.plane_mask = AllPlanes;
3773 valueMask = GCForeground | GCBackground | GCGraphicsExposures
3774 | GCFunction | GCLineStyle | GCDashList | GCPlaneMask;
3775 gc = XtGetGC((Widget)ww, valueMask, &values);
3776 XFillRectangle(XtDisplay(ww), pixmap, gc, 0, 0, width, height);
3777 if( draw_grid_marks )
3778 {
3779 XSetForeground(XtDisplay(ww), gc, ww->manager.foreground);
3780 DrawGridMarks(ww, gc, pixmap);
3781 }
3782 #if DUPLICATE_XT_STUFF
3783 XSetWindowBackgroundPixmap(XtDisplay(ww), XtWindow(ww), pixmap);
3784 #else
3785 XtVaSetValues ((Widget)ww, XmNbackgroundPixmap, pixmap, NULL);
3786 #endif
3787 XtReleaseGC((Widget)ww, gc);
3788 XFreePixmap(XtDisplay(ww), pixmap);
3789 }
3790
3791
3792 /* Subroutine: DrawGridMarks
3793 * Purpose: Draw the brid marks in the workspace background pixmap
3794 */
DrawGridMarks(XmWorkspaceWidget ww,GC gc,Pixmap pixmap)3795 static void DrawGridMarks( XmWorkspaceWidget ww, GC gc, Pixmap pixmap )
3796 {
3797 int x_h, y1_h, y2_h, x1_v, x2_v, y_v;
3798
3799 if( ww->workspace.horizontal_alignment == XmALIGNMENT_END )
3800 {
3801 x_h = ww->workspace.grid_width - 1;
3802 x1_v = ww->workspace.grid_width - (HASH_RAY + HASH_RAY);
3803 }
3804 else if((ww->workspace.horizontal_alignment == XmALIGNMENT_CENTER) ||
3805 (ww->workspace.horizontal_alignment == XmALIGNMENT_NONE))
3806 {
3807 x_h = ww->workspace.grid_width / 2;
3808 x1_v = (ww->workspace.grid_width / 2) - HASH_RAY;
3809 }
3810 else
3811 {
3812 x_h = 0;
3813 x1_v = 0;
3814 }
3815 if( ww->workspace.vertical_alignment == XmALIGNMENT_END )
3816 {
3817 y1_h = ww->workspace.grid_height - (HASH_RAY + HASH_RAY);
3818 y_v = ww->workspace.grid_height - 1;
3819 }
3820 else if((ww->workspace.vertical_alignment == XmALIGNMENT_CENTER) ||
3821 (ww->workspace.vertical_alignment == XmALIGNMENT_NONE))
3822 {
3823 y1_h = (ww->workspace.grid_height / 2) - HASH_RAY;
3824 y_v = ww->workspace.grid_height / 2;
3825 }
3826 else
3827 {
3828 y1_h = 0;
3829 y_v = 0;
3830 }
3831 /* There is a dash problem in that some PS2 servers don't draw the on .. *
3832 * part of a dash unless the off is also included! So we stretch to ... *
3833 * an even size. Worse, some old PS2 servers don't do dashes: they ... *
3834 * will draw these lines too long. Sigh! */
3835 if( ww->workspace.horizontal_draw_grid == XmDRAW_HASH )
3836 /* I don't know why -1 but OnOffDash comes out short without it */
3837 y2_h = y1_h + HASH_RAY + HASH_RAY + 1;
3838 else
3839 {
3840 if( ww->workspace.horizontal_draw_grid == XmDRAW_OUTLINE )
3841 x_h = 0;
3842 y1_h = 0;
3843 y2_h = ww->workspace.grid_height - 1;
3844 }
3845 if( ww->workspace.vertical_draw_grid == XmDRAW_HASH )
3846 x2_v = x1_v + HASH_RAY + HASH_RAY + 1;
3847 else
3848 {
3849 if( ww->workspace.vertical_draw_grid == XmDRAW_OUTLINE )
3850 y_v = 0;
3851 x1_v = 0;
3852 x2_v = ww->workspace.grid_width - 1;
3853 }
3854 /* If things are too tight in our direction, don't draw anything */
3855 if( ww->workspace.horizontal_draw_grid != XmDRAW_NONE )
3856 XDrawLine(XtDisplay(ww), pixmap, gc, x_h, y1_h, x_h, y2_h);
3857 if( ww->workspace.vertical_draw_grid != XmDRAW_NONE )
3858 XDrawLine(XtDisplay(ww), pixmap, gc, x1_v, y_v, x2_v, y_v);
3859 }
3860
3861
3862 /* Subroutine: OutlineChild
3863 * Purpose: Set a rectangle the outline of a single child widget
3864 */
OutlineChild(XRectangle * surrogate,XmWorkspaceConstraints constraints)3865 static void OutlineChild( XRectangle* surrogate,
3866 XmWorkspaceConstraints constraints )
3867 {
3868 surrogate->x = constraints->workspace.x_left;
3869 surrogate->y = constraints->workspace.y_upper;
3870 /* X draws box as x<->x+width instead of x<->x+width-1 as it should */
3871 surrogate->width =
3872 constraints->workspace.x_right - constraints->workspace.x_left;
3873 surrogate->height =
3874 constraints->workspace.y_lower - constraints->workspace.y_upper;
3875 }
3876
3877
3878 /* Subroutine: SaveOutline
3879 * Purpose: Make outline of grabbed widget and a box fit around all
3880 * selected widgets (if there are more than the one).
3881 */
SaveOutline(XmWorkspaceWidget ww,Widget grab_child)3882 static void SaveOutline( XmWorkspaceWidget ww, Widget grab_child )
3883 {
3884 XmWorkspaceConstraints constraints;
3885
3886 constraints = WORKSPACE_CONSTRAINT(grab_child);
3887 OutlineChild(ww->workspace.rubberband, constraints);
3888 if( constraints && (ww->workspace.num_selected > 1) )
3889 {
3890 ww->workspace.rubberband[1].x = ww->workspace.min_x - 1;
3891 ww->workspace.rubberband[1].width =
3892 3 + ww->workspace.max_x - ww->workspace.min_x;
3893 ww->workspace.rubberband[1].y = ww->workspace.min_y - 1;
3894 ww->workspace.rubberband[1].height =
3895 3 + ww->workspace.max_y - ww->workspace.min_y;
3896 ww->workspace.num_surrogates = 2;
3897 }
3898 else
3899 ww->workspace.num_surrogates = 1;
3900 ww->workspace.surrogates = ww->workspace.rubberband;
3901 }
3902
3903
3904 /* Subroutine: SaveOutlines
3905 * Purpose: Make array of outlines of each of the selected widgets
3906 */
SaveOutlines(XmWorkspaceWidget ww)3907 static void SaveOutlines( XmWorkspaceWidget ww )
3908 {
3909 XmWorkspaceConstraints constraints;
3910 Widget child;
3911 int i, j;
3912
3913 if ((ww->workspace.num_surrogates)&&(ww->workspace.surrogates))
3914 DiscardSurrogate (ww);
3915
3916 /*
3917 * Purify found an abw bug here. It appears as though num_selected
3918 * is less than the number of constraint parts which say they
3919 * are selected. I added the following loop and the MAX. Beware
3920 */
3921 j = 0;
3922 for (i=0; i<ww->composite.num_children; i++) {
3923 child = ww->composite.children[i];
3924 constraints = WORKSPACE_CONSTRAINT(child);
3925 if( constraints->workspace.is_selected == TRUE ) j++;
3926 }
3927 #if 0
3928 if (j!=ww->workspace.num_selected) {
3929 char msg[512];
3930 sprintf (msg,
3931 "Selection cnt (%d) != number of children who think they are selected (%d). [%s:%d]",
3932 ww->workspace.num_selected, j, __FILE__, __LINE__);
3933 XtWarning(msg);
3934 }
3935 #endif
3936
3937 ww->workspace.surrogates =
3938 (XRectangle *)XtMalloc(MAX(j,ww->workspace.num_selected) * sizeof(XRectangle));
3939
3940
3941 for( j=0, i=0; i<ww->composite.num_children; i++ )
3942 {
3943 child = ww->composite.children[i];
3944 constraints = WORKSPACE_CONSTRAINT(child);
3945 if( constraints->workspace.is_selected == TRUE )
3946 {
3947 OutlineChild(&(ww->workspace.surrogates[j]), constraints);
3948 ++j;
3949 }
3950 }
3951 ww->workspace.num_surrogates = j;
3952 }
3953
3954
3955 /* Subroutine: DiscardSurrogate
3956 * Purpose: Free up space occupied by array of surrogate outlines
3957 */
DiscardSurrogate(XmWorkspaceWidget ww)3958 static void DiscardSurrogate( XmWorkspaceWidget ww )
3959 {
3960 if( ww->workspace.surrogates != ww->workspace.rubberband )
3961 XtFree((char*)ww->workspace.surrogates);
3962 ww->workspace.surrogates = NULL;
3963 ww->workspace.num_surrogates = 0;
3964 }
3965
3966
3967 /* Subroutine: CreateSurrogate
3968 * Purpose: Create drawable outlines of some type to aid in interactive
3969 * placement of selected children.
3970 */
3971 #define IFMIN(a,b) if((b)<a)a=(b)
3972 #define IFMAX(a,b) if((b)>a)a=(b)
CreateSurrogate(XmWorkspaceWidget ww,Widget grab_child)3973 static void CreateSurrogate( XmWorkspaceWidget ww, Widget grab_child )
3974 {
3975 Widget child;
3976 XmWorkspaceConstraints constraints;
3977 int i, init;
3978
3979 if( ww->workspace.bandGC == NULL )
3980 GetRubberbandGC(ww);
3981 /* Determine the limits (used to prevent moving anything off the edge) */
3982 init = 1;
3983 for( i=0; i<ww->composite.num_children; i++ )
3984 {
3985 child = ww->composite.children[i];
3986 constraints = WORKSPACE_CONSTRAINT(child);
3987 if( constraints->workspace.is_selected == TRUE )
3988 {
3989 constraints->workspace.x_left = child->core.x;
3990 constraints->workspace.y_upper = child->core.y;
3991 constraints->workspace.x_right = child->core.x + child->core.width - 1;
3992 constraints->workspace.y_lower = child->core.y + child->core.height - 1;
3993 if( init )
3994 {
3995 ww->workspace.min_x = constraints->workspace.x_left;
3996 ww->workspace.max_x = constraints->workspace.x_right;
3997 ww->workspace.min_y = constraints->workspace.y_upper;
3998 ww->workspace.max_y = constraints->workspace.y_lower;
3999 init = 0;
4000 }
4001 else
4002 {
4003 IFMIN(ww->workspace.min_x,constraints->workspace.x_left);
4004 IFMAX(ww->workspace.max_x,constraints->workspace.x_right);
4005 IFMIN(ww->workspace.min_y,constraints->workspace.y_upper);
4006 IFMAX(ww->workspace.max_y,constraints->workspace.y_lower);
4007 }
4008 }
4009 }
4010 /* Draw the kind of visual feedback we will use */
4011 switch( ww->workspace.surrogate_type )
4012 {
4013 case XmOUTLINE_EACH:
4014 SaveOutlines(ww);
4015 break;
4016 case XmOUTLINE_PLUS:
4017 SaveOutline(ww, grab_child);
4018 break;
4019 case XmOUTLINE_ALL:
4020 default:
4021 SaveOutline(ww, NULL);
4022 break;
4023 }
4024 /* Reset limits to reflect limits of movement */
4025 ww->workspace.min_x = -ww->workspace.min_x;
4026 ww->workspace.max_x = ww->core.width - ww->workspace.max_x;
4027 ww->workspace.min_y = -ww->workspace.min_y;
4028 ww->workspace.max_y = ww->core.height - ww->workspace.max_y;
4029 }
4030 #undef IFMIN
4031 #undef IFMAX
4032
4033
4034 /* Subroutine: DrawSurrogate
4035 * Purpose: Put the surrogate outline(s) on the screen and note their state
4036 */
DrawSurrogate(XmWorkspaceWidget ww)4037 static void DrawSurrogate( XmWorkspaceWidget ww )
4038 {
4039 if (ww->workspace.overlaps)
4040 XDrawRectangles(XtDisplay(ww), XtWindow(ww), ww->workspace.badBandGC,
4041 ww->workspace.surrogates, ww->workspace.num_surrogates);
4042 else
4043 XDrawRectangles(XtDisplay(ww), XtWindow(ww), ww->workspace.bandGC,
4044 ww->workspace.surrogates, ww->workspace.num_surrogates);
4045 ww->workspace.surrogate_is_visible = !ww->workspace.surrogate_is_visible;
4046 }
4047
4048
4049 /* Subroutine: MoveSurrogate
4050 * Purpose: Move the position of the surrogates (to track pointer)
4051 */
MoveSurrogate(XmWorkspaceWidget ww,int delta_x,int delta_y)4052 static void MoveSurrogate( XmWorkspaceWidget ww, int delta_x, int delta_y )
4053 {
4054 int i;
4055 if( ww->workspace.surrogate_is_visible )
4056 DrawSurrogate(ww);
4057
4058 Overlapping (ww, delta_x, delta_y);
4059 for( i=0; i<ww->workspace.num_surrogates; i++ )
4060 {
4061 ww->workspace.surrogates[i].x += delta_x;
4062 ww->workspace.surrogates[i].y += delta_y;
4063 }
4064 ww->workspace.base_x += delta_x;
4065 ww->workspace.base_y += delta_y;
4066 DrawSurrogate(ww);
4067 }
4068
Overlapping(XmWorkspaceWidget ww,int delta_x,int delta_y)4069 static Boolean Overlapping( XmWorkspaceWidget ww, int delta_x, int delta_y )
4070 {
4071 int i;
4072 Boolean overlaps = False;
4073 Region r;
4074 XPoint p[4];
4075
4076 if (ww->workspace.check_overlap == False) return False;
4077
4078 /*
4079 * If the position of a surrogate overlaps the position of any
4080 * tool, then don't move any surrogates.
4081 */
4082 p[0].x = ww->workspace.surrogates[0].x + delta_x;
4083 p[0].y = ww->workspace.surrogates[0].y + delta_y;
4084 if (ww->workspace.snap_to_grid) {
4085 int x = p[0].x;
4086 int y = p[0].y;
4087 Align1D(&x, ww->workspace.surrogates[0].width + 1, ww->workspace.grid_width,
4088 ww->workspace.horizontal_alignment, False);
4089 Align1D(&y, ww->workspace.surrogates[0].height + 1, ww->workspace.grid_height,
4090 ww->workspace.vertical_alignment, False);
4091 p[0].x = x;
4092 p[0].y = y;
4093 }
4094 p[2].x = p[0].x + ww->workspace.surrogates[0].width + 1;
4095 p[2].y = p[0].y + ww->workspace.surrogates[0].height + 1;
4096
4097
4098 p[1].x = p[2].x;
4099 p[1].y = p[0].y;
4100 p[3].x = p[0].x;
4101 p[3].y = p[2].y;
4102 r = XPolygonRegion (p, 4, WindingRule);
4103
4104 for( i=1; i<ww->workspace.num_surrogates; i++ )
4105 {
4106 XRectangle rect;
4107
4108 /*
4109 * Use gridded postions
4110 */
4111 rect.width = ww->workspace.surrogates[i].width + 1;
4112 rect.height = ww->workspace.surrogates[i].height + 1;
4113 if (ww->workspace.snap_to_grid) {
4114 int x = ww->workspace.surrogates[i].x + delta_x;
4115 int y = ww->workspace.surrogates[i].y + delta_y;
4116
4117 Align1D(&x, rect.width, ww->workspace.grid_width,
4118 ww->workspace.horizontal_alignment, False);
4119 rect.x = (int)x;
4120
4121 Align1D(&y, rect.height, ww->workspace.grid_height,
4122 ww->workspace.vertical_alignment, False);
4123 rect.y = (int)y;
4124 } else {
4125 rect.x = ww->workspace.surrogates[i].x + delta_x;
4126 rect.y = ww->workspace.surrogates[i].y + delta_y;
4127 }
4128
4129 XUnionRectWithRegion(&rect, r, r);
4130 }
4131 for (i=0; i<ww->composite.num_children; i++)
4132 {
4133 Widget child = ww->composite.children[i];
4134 XmWorkspaceConstraints constraints = WORKSPACE_CONSTRAINT(child);
4135 int x = child->core.x;
4136 int y = child->core.y;
4137 int width = child->core.width;
4138 int height = child->core.height;
4139 if (!child->core.managed) continue;
4140 if (!constraints->workspace.is_managed) continue;
4141 if (!child->core.mapped_when_managed) continue;
4142 if( constraints->workspace.is_selected == TRUE ) continue;
4143 if (XRectInRegion (r, x,y,width,height) != RectangleOut) {
4144 overlaps = True;
4145 break;
4146 }
4147 }
4148 XDestroyRegion(r);
4149 ww->workspace.overlaps = overlaps;
4150 return overlaps;
4151 }
4152
4153 /* Subroutine: ResizeSurrogate
4154 * Purpose: Resize the surrogates (to track pointer)
4155 */
ResizeSurrogate(XmWorkspaceWidget ww,int width,int height)4156 static void ResizeSurrogate( XmWorkspaceWidget ww, int width, int height )
4157 {
4158 int i;
4159 int j;
4160 Widget child;
4161 XmWorkspaceConstraints constraints;
4162
4163 if( ww->workspace.surrogate_is_visible )
4164 DrawSurrogate(ww);
4165
4166 for( j=0, i=0; i<ww->composite.num_children; i++ )
4167 {
4168 child = ww->composite.children[i];
4169 constraints = WORKSPACE_CONSTRAINT(child);
4170 if( constraints->workspace.is_selected == TRUE )
4171 {
4172 if(constraints->workspace.is_v_resizable)
4173 ww->workspace.surrogates[j].height = height;
4174 if(constraints->workspace.is_h_resizable)
4175 ww->workspace.surrogates[j].width = width;
4176 ++j;
4177 }
4178 }
4179 DrawSurrogate(ww);
4180 }
4181
4182
4183 /* Subroutine: PerformSpaceWars
4184 * Purpose: Prevent move from causing overlap by shifting children in
4185 * conflict to the right.
4186 * Note: Rules for "placement_policy" code:
4187 * 0: widgets are adjusted separately, initial order is maintained
4188 * >0: selected children move en-mass (keeping spacing among them)
4189 * 1: First selected child on left maintains ordered position
4190 * 2: Selected widgets stay put, all others move right as needed
4191 */
PerformSpaceWars(XmWorkspaceWidget ww,Boolean change_managed,XEvent * event)4192 static Boolean PerformSpaceWars( XmWorkspaceWidget ww, Boolean change_managed, XEvent* event)
4193 {
4194 struct SortRec* sortlist;
4195 struct SortRec* current;
4196 struct SortRec* next;
4197 struct SortRec* right_sort;
4198 struct SortRec* sortmem;
4199 Boolean moved = False, first_selected = TRUE;
4200
4201 if (ww->workspace.auto_arrange) return False;
4202
4203 sortlist = GetSortList(ww, change_managed, &sortmem);
4204 if (sortlist != NULL)
4205 {
4206 /* Call potentially recursive (but not) space resolution algorithm */
4207 moved = ResolveOverlaps(ww, sortlist, &first_selected, event);
4208 /* Perform insertion sort of linked list, by x_right */
4209 for( current = sortlist->next, sortlist->next = NULL;
4210 current != NULL;
4211 current = next )
4212 {
4213 next = current->next;
4214 right_sort = sortlist;
4215 while( (right_sort->next != NULL)
4216 && (right_sort->next->x_right < current->x_right) )
4217 right_sort = right_sort->next;
4218 current->next = right_sort->next;
4219 right_sort->next = current;
4220 }
4221 /* Now move the windows in right to left order to avoid expose races */
4222 (void)MoveIfDisplaced(ww, sortlist, 0, 0);
4223 }
4224 if (sortmem)
4225 XtFree((char*)sortmem);
4226 return moved;
4227 }
4228
4229
4230 /* Subroutine: ResolveOverlaps
4231 * Purpose: Move widgets to clear any overlaps caused by the movement of
4232 * widgets (children marked as selected or displaced)
4233 * Method: The basic idea is to go through the list in outer & inner loops,
4234 * applying the rules at each overlap. Either outer or inner
4235 * progress through the list can be reset back as needed to repeat
4236 * overlap checks on sublists of widgets.
4237 */
ResolveOverlaps(XmWorkspaceWidget ww,struct SortRec * sortlist,Boolean * first_selected,XEvent * event)4238 static Boolean ResolveOverlaps( XmWorkspaceWidget ww, struct SortRec* sortlist,
4239 Boolean* first_selected, XEvent* event )
4240 {
4241 struct SortRec* current;
4242 struct SortRec* current_next;
4243 struct SortRec* other;
4244 struct SortRec* other_next;
4245 short delta_x = 0;
4246 Boolean moved = False;
4247
4248 current = sortlist;
4249 while( current != NULL )
4250 {
4251 /* Set up next for normal progress (may be overwridden to back up) */
4252 current_next = current->next;
4253
4254 if( (current->is_selected || current->is_displaced ) &&
4255 ( !current->child->core.being_destroyed ) )
4256 {
4257 /* Look for overlap with widgets before this in the sort list */
4258 other = sortlist;
4259 while((other != current) && (!other->child->core.being_destroyed))
4260 {
4261 other_next = other->next;
4262 if( (other->y_upper <= current->y_lower)
4263 && (other->y_lower >= current->y_upper)
4264 && (other->x_left <= current->x_right)
4265 && (other->x_right >= current->x_left) )
4266 {
4267 int policy = ww->workspace.placement_policy;
4268 if( ( (policy == XmSPACE_WARS_SELECTED_STAYS)
4269 && (other->is_selected == FALSE)
4270 && ( current->is_selected
4271 || (other->x_index > current->x_index)))
4272 || ( (policy == XmSPACE_WARS_LEFT_MOST_STAYS)
4273 && (*first_selected == FALSE)
4274 && current->is_selected) )
4275 {
4276 /* Push overlapping widgets farther to right */
4277 (void)MoveAToRightOfB(ww, other, current, event);
4278 /* Make resolution repeat from displaced widget */
4279 if( current_next == current->next )
4280 current_next = other;
4281 }
4282 else
4283 {
4284 /* Slide to right of overlapping widgets on left */
4285 delta_x += MoveAToRightOfB(ww, current, other, event);
4286 /* Check list of widgets again for more conflict */
4287 other_next = sortlist;
4288 }
4289 moved = True;
4290 }
4291 other = other_next;
4292 }
4293 /* If we moved the first_selected, adjust the other selected */
4294 if( (ww->workspace.placement_policy == XmSPACE_WARS_LEFT_MOST_STAYS)
4295 && *first_selected
4296 && current->is_selected
4297 && delta_x > 0 )
4298 {
4299 /* Move all other selected widgets by the same amount */
4300 RepositionSelectedChildren(current, delta_x);
4301 /* Indicate that selected widgets are now fixed */
4302 *first_selected = FALSE;
4303 }
4304 /* Look for overlap with widgets after this in the sort list */
4305 other = current->next;
4306 while(other != NULL)
4307 {
4308 if (other->child->core.being_destroyed)
4309 {
4310 other = other->next;
4311 continue;
4312 }
4313 if( (other->y_upper <= current->y_lower)
4314 && (other->y_lower >= current->y_upper)
4315 && (other->x_left <= current->x_right)
4316 && (other->x_right >= current->x_left) )
4317 {
4318 /* For policies 1 and 2, selected widgets stay put */
4319 if( (ww->workspace.placement_policy != XmSPACE_WARS_SELECTED_MIGRATE)
4320 && other->is_selected
4321 && (!current->is_selected) )
4322 {
4323 /* Slide to right of overlapping widgets on right */
4324 (void)MoveAToRightOfB(ww, current, other, event);
4325 /* Make resolution repeat with this widget */
4326 if( current_next == current->next )
4327 current_next = current;
4328 }
4329 /* For policy 0, the order is maintained (move >sort) */
4330 else
4331 {
4332 /* Push overlapping widgets on right farther right */
4333 (void)MoveAToRightOfB(ww, other, current, event);
4334 }
4335 moved = True;
4336 }
4337 other = other->next;
4338 }
4339 }
4340 current = current_next;
4341 }
4342 return moved;
4343 }
4344
4345
4346 /* Subroutine: MoveAToRightOfB
4347 * Purpose: Move the x position of movee to right of mover.
4348 */
MoveAToRightOfB(XmWorkspaceWidget ww,struct SortRec * movee,struct SortRec * mover,XEvent * event)4349 static int MoveAToRightOfB( XmWorkspaceWidget ww,
4350 struct SortRec* movee, struct SortRec *mover, XEvent* event )
4351 {
4352 int delta_x;
4353 delta_x = 1 + mover->x_right - movee->x_left;
4354 if (ww->workspace.snap_to_grid)
4355 {
4356 delta_x += ww->workspace.grid_width;
4357 }
4358 else
4359 {
4360 delta_x += ww->workspace.collision_spacing;
4361 }
4362
4363 movee->x_left += delta_x;
4364 movee->x_right += delta_x;
4365 movee->constraints->workspace.x_delta =
4366 movee->x_left - movee->constraints->workspace.x_left;
4367 if( ww->workspace.snap_to_grid )
4368 {
4369 short delta;
4370 /* Move into closest grid position (left&down) */
4371 SnapToGrid(ww, movee->child, movee->constraints, TRUE);
4372 if ( ((movee->constraints->workspace.x_delta != 0) ||
4373 (movee->constraints->workspace.y_delta != 0)) &&
4374 !ww->workspace.suppress_callbacks)
4375 {
4376 XmWorkspacePositionChangeCallbackStruct call_data;
4377
4378 call_data.child = movee->child;
4379 call_data.x = movee->constraints->workspace.x_left +
4380 movee->constraints->workspace.x_delta;
4381 call_data.y = movee->constraints->workspace.y_upper +
4382 movee->constraints->workspace.y_delta;
4383 call_data.event = event;
4384 XtCallCallbacks((Widget)
4385 ww, XmNpositionChangeCallback, &call_data);
4386 }
4387 /* Update link-list record to new coords */
4388 delta = movee->constraints->workspace.x_delta;
4389 movee->x_left = movee->constraints->workspace.x_left + delta;
4390 movee->x_right = movee->constraints->workspace.x_right + delta;
4391 delta = movee->constraints->workspace.y_delta;
4392 movee->y_upper = movee->constraints->workspace.y_upper + delta;
4393 movee->y_lower = movee->constraints->workspace.y_lower + delta;
4394 } else
4395 {
4396 XmWorkspacePositionChangeCallbackStruct call_data;
4397
4398 call_data.child = movee->child;
4399 call_data.x = movee->constraints->workspace.x_left +
4400 movee->constraints->workspace.x_delta;
4401 call_data.y = movee->constraints->workspace.y_upper +
4402 movee->constraints->workspace.y_delta;
4403 call_data.event = event;
4404 XtCallCallbacks((Widget)
4405 ww, XmNpositionChangeCallback, &call_data);
4406 }
4407 movee->is_displaced = TRUE;
4408 return delta_x;
4409 }
4410
4411
4412 /* Subroutine: RepositionSelectedChildren
4413 * Purpose: Move the selected children to follow the leader, then
4414 * change sort order so everybody isn't necessarily forced
4415 * to the right of them
4416 */
RepositionSelectedChildren(struct SortRec * current,short delta_x)4417 static void RepositionSelectedChildren( struct SortRec* current, short delta_x )
4418 {
4419 struct SortRec* other;
4420
4421 /* Look for the other selected ones */
4422 other = current->next;
4423 while( other != NULL )
4424 {
4425 if( other->is_selected )
4426 {
4427 /* Reposition each other selected one */
4428 other->x_left += delta_x;
4429 other->x_right += delta_x;
4430 other->is_displaced = TRUE;
4431 }
4432 /* Keep track of connection point */
4433 current = other;
4434 other = other->next;
4435 }
4436 }
4437
4438
4439 /* Subroutine: MoveIfDisplaced
4440 * Purpose: Tail recursive call to move chidren being moved rightmost first.
4441 */
MoveIfDisplaced(XmWorkspaceWidget ww,struct SortRec * sortlist,int max_x,int max_y)4442 static Boolean MoveIfDisplaced( XmWorkspaceWidget ww, struct SortRec *sortlist,
4443 int max_x, int max_y )
4444 {
4445 if( sortlist->is_selected || sortlist->is_displaced )
4446 {
4447 if( sortlist->x_right > max_x )
4448 max_x = sortlist->x_right;
4449 if( sortlist->y_lower > max_y )
4450 max_y = sortlist->y_lower;
4451 }
4452 if( sortlist->next != NULL )
4453 {
4454 /* Not the end of the sortlist, recurse */
4455 if( MoveIfDisplaced(ww, sortlist->next, max_x, max_y) == FALSE )
4456 {
4457 ResetChild(ww, sortlist->constraints);
4458 return FALSE;
4459 }
4460 }
4461 else if( (max_x >= ww->core.width) || (max_y >= ww->core.height) )
4462 {
4463 /* End of the sortlist, check necessity of resize */
4464 XtWidgetGeometry request, reply;
4465 XtGeometryResult result;
4466
4467 request.width = MAX(max_x + 1, ww->core.width);
4468 request.height = MAX(max_y + 1, ww->core.height);
4469 request.request_mode = CWWidth | CWHeight;
4470 result = XtMakeGeometryRequest((Widget)ww, &request, &reply);
4471 ReallocCollideLists(ww);
4472 if( (result == XtGeometryNo) || (result == XtGeometryAlmost) )
4473 {
4474 ResetChild(ww, sortlist->constraints);
4475 return FALSE;
4476 }
4477 }
4478 if( sortlist->is_selected || sortlist->is_displaced )
4479 MoveChild(ww, sortlist->child, sortlist->constraints);
4480 return TRUE;
4481 }
4482
4483
4484 /* Subroutine: GetSortList
4485 * Purpose: Create a list of chidren sorted by x position and priority
4486 * Note: Priority is x, then non-selected, then y where x and y can
4487 * be left, center, or right based on policy variable.
4488 * Note: List is used to arbitrate who moves in cases of overlap
4489 */
4490 static struct SortRec *GetSortList( XmWorkspaceWidget ww,
4491 Boolean change_managed,
4492 struct SortRec** sortmem )
4493 #ifdef EXPLAIN
4494 XmWorkspaceWidget ww; /* The widget */
4495 Boolean change_managed; /* Need to mark children just managed */
4496 struct SortRec** sortmem; /* Xtalloc pointer to be XtFree'd when done */
4497 #endif
4498 {
4499 struct SortRec* sortlist;
4500 struct SortRec* heap;
4501 #ifdef DEBUG
4502 /* Stupid debugger can't access variables not defined at top */
4503 struct SortRec* current;
4504 struct SortRec* place_search;
4505 XmWorkspaceConstraints nc;
4506 #endif
4507 int i;
4508 int count;
4509
4510 count = ww->composite.num_children;
4511 if (count > 0)
4512 heap = (struct SortRec *) XtCalloc(count, sizeof(struct SortRec));
4513 else
4514 heap = NULL;
4515
4516 *sortmem = heap;
4517 sortlist = NULL;
4518 for( i = 0; i < count; i++ )
4519 {
4520 #ifndef DEBUG
4521 /* Debugger can't access variables not defined at top! */
4522 struct SortRec* current;
4523 XmWorkspaceConstraints nc;
4524 #endif
4525 current = &(heap[i]);
4526 current->child = ww->composite.children[i];
4527 nc = WORKSPACE_CONSTRAINT(current->child);
4528 current->constraints = nc;
4529 /* Accomodate special case of children just placed by application */
4530 if( change_managed && nc->workspace.is_managed && nc->workspace.is_newly_managed )
4531 {
4532 current->is_displaced = TRUE;
4533 nc->workspace.is_newly_managed = FALSE;
4534 }
4535 else
4536 current->is_displaced = FALSE;
4537 /* Only count those children that are managed (mapped to screen) */
4538 if( nc->workspace.is_managed )
4539 {
4540 /* Proposed position is offset by delta's */
4541 current->x_left = nc->workspace.x_left + nc->workspace.x_delta;
4542 current->x_right = nc->workspace.x_right + nc->workspace.x_delta;
4543 current->y_upper = nc->workspace.y_upper + nc->workspace.y_delta;
4544 current->y_lower = nc->workspace.y_lower + nc->workspace.y_delta;
4545 current->is_selected = nc->workspace.is_selected;
4546 /* Index is x position only and has been offset as appropriate */
4547 /* Make an index with x then selected then y absolute priority */
4548 current->x_index = nc->workspace.x_index * 16384;
4549 if( current->is_selected == (POLICY(ww) != XmSPACE_WARS_SELECTED_STAYS) )
4550 /* Selected children come first (policy > 1) or last (< 2) */
4551 current->x_index += 8192;
4552 if( ww->workspace.sort_policy == XmALIGNMENT_BEGINNING )
4553 current->x_index += current->y_upper;
4554 else if( ww->workspace.sort_policy == XmALIGNMENT_CENTER )
4555 current->x_index +=
4556 (nc->workspace.y_center + nc->workspace.y_delta);
4557 else
4558 current->x_index += current->y_lower;
4559 if( (sortlist == NULL) || (sortlist->x_index > current->x_index) )
4560 {
4561 current->next = sortlist;
4562 sortlist = current;
4563 }
4564 else
4565 {
4566 /* Perform insertion sort of linked list */
4567 #ifndef DEBUG
4568 struct SortRec* place_search;
4569 #endif
4570 place_search = sortlist;
4571 while( (place_search->next != NULL)
4572 && (place_search->next->x_index < current->x_index) )
4573 place_search = place_search->next;
4574 current->next = place_search->next;
4575 place_search->next = current;
4576 }
4577 }
4578 }
4579 return sortlist;
4580 }
4581
4582 /* Subroutine: XmCreateWorkspaceLine
4583 * Purpose: Export routine to register an application line for management
4584 */
4585 XmWorkspaceLine
XmCreateWorkspaceLine(XmWorkspaceWidget ww,int color,Widget source,short src_x_offset,short src_y_offset,Widget dest,short dst_x_offset,short dst_y_offset)4586 XmCreateWorkspaceLine( XmWorkspaceWidget ww, int color,
4587 Widget source, short src_x_offset, short src_y_offset,
4588 Widget dest, short dst_x_offset, short dst_y_offset )
4589 {
4590 XmWorkspaceConstraints constraints;
4591 int i;
4592 XmWorkspaceLine line;
4593 Boolean source_not_found, destination_not_found;
4594
4595 /* Check to make sure this one is here */
4596 source_not_found = TRUE;
4597 destination_not_found = TRUE;
4598 for( i=0; i<ww->composite.num_children; i++ )
4599 {
4600 if( ww->composite.children[i] == source )
4601 source_not_found = FALSE;
4602 if( ww->composite.children[i] == dest )
4603 destination_not_found = FALSE;
4604 }
4605 if( source_not_found || destination_not_found )
4606 {
4607 XtWarning("Attempt to create line for non-child widget.");
4608 return NULL;
4609 }
4610
4611 line = (XmWorkspaceLine)XtMalloc(sizeof(XmWorkspaceLineRec));
4612 memset(line, 0, sizeof(XmWorkspaceLineRec));
4613
4614 /* Set the source end and install it in the source's list */
4615 line->source = source;
4616 line->src_x = source->core.x + src_x_offset;
4617 line->src_y = source->core.y + src_y_offset;
4618 line->src_x_offset = src_x_offset;
4619 constraints = WORKSPACE_CONSTRAINT(source);
4620 line->src_next = constraints->workspace.source_lines;
4621 constraints->workspace.source_lines = line;
4622 /* Set the destination end and install it in the destination's list */
4623 line->destination = dest;
4624 line->dst_x = dest->core.x + dst_x_offset;
4625 line->dst_y = dest->core.y + dst_y_offset;
4626 line->dst_x_offset = dst_x_offset;
4627 constraints = WORKSPACE_CONSTRAINT(dest);
4628 line->dst_next = constraints->workspace.destination_lines;
4629 constraints->workspace.destination_lines = line;
4630 /* Set the color or the default color */
4631 if( color == -1 )
4632 line->color = ww->manager.foreground;
4633 else
4634 line->color = color;
4635 /* Install it in the master line list */
4636 line->next = ww->workspace.lines;
4637 ww->workspace.lines = line;
4638 ww->workspace.num_lines++;
4639 line->is_to_be_moved = TRUE;
4640
4641 /* Get the GC and set it to this color */
4642 if( XtIsRealized((Widget)ww) )
4643 {
4644 if( xmWorkspaceClassRec.workspace_class.lineGC == NULL )
4645 InitLineGC(ww, line->color);
4646 else
4647 XSetForeground(XtDisplay(ww),
4648 xmWorkspaceClassRec.workspace_class.lineGC,
4649 line->color);
4650 line->is_to_be_drawn = FALSE;
4651 }
4652 else
4653 line->is_to_be_drawn = TRUE;
4654
4655 if (ww->workspace.line_drawing_enabled)
4656 {
4657 RerouteLines(ww, FALSE);
4658 /* Manually clear out the exposure area */
4659 if (XtWindow(ww))
4660 XClearArea(XtDisplay(ww), XtWindow(ww), ww->workspace.expose_left,
4661 ww->workspace.expose_upper,
4662 ww->workspace.expose_right - ww->workspace.expose_left,
4663 ww->workspace.expose_lower - ww->workspace.expose_upper, False);
4664 RefreshLines(ww);
4665 }
4666 UnsetExposureArea(ww);
4667 line->is_to_be_collapsed = TRUE;
4668 return line;
4669 }
4670
4671 /* Subroutine: SetLineRoute
4672 * Purpose: Set the points for drawing the line
4673 */
SetLineRoute(XmWorkspaceWidget ww,XmWorkspaceLine new)4674 static void SetLineRoute( XmWorkspaceWidget ww, XmWorkspaceLine new )
4675 {
4676 short i;
4677 LineElement *line_list;
4678 int cost, failnum;
4679
4680 /* Point 1 */
4681 new->point[0].x = new->src_x;
4682 new->point[0].y = new->src_y;
4683
4684 if( !ww->workspace.manhattan_route )
4685 {
4686 /* Point 2 */
4687 new->point[1].x = new->dst_x;
4688 new->point[1].y = new->dst_y;
4689
4690 new->num_points = 2;
4691 }
4692
4693 /* If doing Manhattan routing... */
4694 else
4695 {
4696 {
4697 line_list = Manhattan(ww, new->src_x, new->src_y, new->dst_x,
4698 new->dst_y, 0, &cost, new->source,
4699 new->destination, new, &failnum);
4700 if (cost < 999)
4701 {
4702 CopyPointsToLine(ww, line_list, new);
4703 AddLineToCollideList(ww, new);
4704 }
4705 else
4706 {
4707 XmWorkspaceErrorCallbackStruct call_value;
4708
4709 new->num_points = -1;
4710
4711 call_value.reason = XmCR_ERROR;
4712 call_value.failnum = failnum;
4713 call_value.source = new->source;
4714 call_value.destination = new->destination;
4715 call_value.srcx = new->src_x;
4716 call_value.srcy = new->src_y;
4717 call_value.dstx = new->dst_x;
4718 call_value.dsty = new->dst_y;
4719 XtCallCallbacks((Widget)ww, XmNerrorCallback, &call_value);
4720 }
4721 }
4722 if (line_list)
4723 FreeLineElementList(line_list);
4724 }
4725 /* Define the bounding box of this line */
4726 new->x_left = new->x_right = new->point[0].x;
4727 new->y_upper = new->y_lower = new->point[0].y;
4728 for( i=1; i<new->num_points; i++ )
4729 {
4730 if( new->point[i].x < new->x_left )
4731 new->x_left = new->point[i].x;
4732 else if( new->point[i].x > new->x_right )
4733 new->x_right = new->point[i].x;
4734 if( new->point[i].y < new->y_upper )
4735 new->y_upper = new->point[i].y;
4736 else if( new->point[i].y > new->y_lower )
4737 new->y_lower = new->point[i].y;
4738 }
4739 AugmentExposureAreaForLine(ww, new);
4740 }
4741
4742 /* Subroutine: RerouteLines
4743 * Purpose: Find suitable routes for all lines waiting to be moved
4744 */
RerouteLines(XmWorkspaceWidget ww,Boolean reroute_all)4745 void RerouteLines( XmWorkspaceWidget ww, Boolean reroute_all )
4746 {
4747 XmWorkspaceLine line;
4748 Widget child;
4749 int i;
4750
4751 if (!ww->workspace.line_drawing_enabled)
4752 return;
4753
4754 for( i=ww->composite.num_children-1; i>=0; i-- )
4755 {
4756 child = ww->composite.children[i];
4757 if (child->core.being_destroyed)
4758 {
4759 XmWorkspaceConstraints nc;
4760 nc = WORKSPACE_CONSTRAINT(child);
4761 if (!nc->workspace.line_invisibility)
4762 DeleteWidgetFromCollideList(child);
4763 }
4764 }
4765
4766 if(ww->workspace.lines)
4767 {
4768 MarkCommonLines(ww);
4769 for (line = ww->workspace.lines; line; line = line->next)
4770 {
4771 if( line->is_to_be_moved || reroute_all )
4772 {
4773 RemoveLineFromCollideList(ww, line);
4774 }
4775 }
4776 for (line = ww->workspace.lines; line; line = line->next)
4777 {
4778 if( line->is_to_be_moved || reroute_all )
4779 {
4780 /* Adjust exposure area to include all of old line's route */
4781 SetLineRoute(ww, line);
4782 line->is_to_be_drawn = TRUE;
4783 line->is_to_be_moved = FALSE;
4784 }
4785 }
4786 }
4787 }
4788
4789 /* Subroutine: XmDestroyWorkspaceLine
4790 * Purpose: Exported routine to remove an application line
4791 */
XmDestroyWorkspaceLine(XmWorkspaceWidget ww,XmWorkspaceLine line,Boolean middle_of_group)4792 void XmDestroyWorkspaceLine( XmWorkspaceWidget ww, XmWorkspaceLine line,
4793 Boolean middle_of_group )
4794 {
4795 if( line != NULL )
4796 {
4797 /* Before this line is removed, mark all lines that share its source
4798 or destination to be re-routed, since they may have been following
4799 this lines path */
4800 line->is_to_be_moved = TRUE;
4801 MarkCommonLines(ww);
4802 AugmentExposureAreaForLine(ww, line);
4803 if( DestroyLine(ww, line) )
4804 {
4805 RemoveLineFromCollideList(ww, line);
4806 XSetForeground(XtDisplay(ww),
4807 xmWorkspaceClassRec.workspace_class.lineGC,
4808 ww->core.background_pixel);
4809 if(ww->workspace.line_drawing_enabled)
4810 {
4811 RerouteLines(ww, FALSE);
4812 /* Manually clear out the exposure area */
4813 if (XtWindow(ww))
4814 XClearArea(XtDisplay(ww), XtWindow(ww), ww->workspace.expose_left,
4815 ww->workspace.expose_upper,
4816 ww->workspace.expose_right - ww->workspace.expose_left,
4817 ww->workspace.expose_lower - ww->workspace.expose_upper, True);
4818 if (!middle_of_group) RefreshLines(ww);
4819 UnsetExposureArea(ww);
4820 }
4821 XtFree((char*)line);
4822 }
4823 }
4824 else
4825 {
4826 if( ww->workspace.expose_left < ww->workspace.expose_right )
4827 middle_of_group = FALSE;
4828 else
4829 middle_of_group = TRUE;
4830 }
4831 if( !middle_of_group && ww->workspace.line_drawing_enabled )
4832 {
4833 RerouteLines(ww, FALSE);
4834 RefreshLines(ww);
4835 UnsetExposureArea(ww);
4836 }
4837 }
4838
4839 /* Subroutine: DestroyLine
4840 * Purpose: Remove a single line
4841 * Returns: False if line was not in list
4842 */
DestroyLine(XmWorkspaceWidget ww,XmWorkspaceLine old)4843 static Boolean DestroyLine( XmWorkspaceWidget ww, XmWorkspaceLine old )
4844 {
4845 XmWorkspaceLine line;
4846 XmWorkspaceConstraints constraints;
4847
4848 /* Remove link from main list */
4849 if( ww->workspace.lines == old )
4850 ww->workspace.lines = old->next;
4851 else
4852 {
4853 for( line = ww->workspace.lines;
4854 (line->next && (line->next != old));
4855 line = line->next );
4856 if( line->next == NULL )
4857 {
4858 XtWarning("Attempt to destroy line not known to workspace.");
4859 return False;
4860 }
4861 line->next = old->next;
4862 }
4863 ww->workspace.num_lines--;
4864 /* Remove line from source list */
4865 constraints = WORKSPACE_CONSTRAINT(old->source);
4866 if( constraints->workspace.source_lines == old )
4867 constraints->workspace.source_lines = old->src_next;
4868 else
4869 {
4870 for( line = constraints->workspace.source_lines;
4871 (line->src_next && (line->src_next != old));
4872 line = line->src_next );
4873 if( line->src_next )
4874 line->src_next = old->src_next;
4875 }
4876 /* Remove line from destination list */
4877 constraints = WORKSPACE_CONSTRAINT(old->destination);
4878 if( constraints->workspace.destination_lines == old )
4879 constraints->workspace.destination_lines = old->dst_next;
4880 else
4881 {
4882 for( line = constraints->workspace.destination_lines;
4883 (line->dst_next && (line->dst_next != old));
4884 line = line->dst_next );
4885 if( line->dst_next )
4886 line->dst_next = old->dst_next;
4887 }
4888 return TRUE;
4889 }
4890
4891
4892 #define IF_MORE(a,b) if((a)>(b))(b)=(a)
4893 #define IF_LESS(a,b) if((a)<(b))(b)=(a)
4894 /* Subroutine: AugmentExposeAreaForLine
4895 * Purpose: Extend expose area to include box of this line
4896 */
AugmentExposureAreaForLine(XmWorkspaceWidget ww,XmWorkspaceLine line)4897 void AugmentExposureAreaForLine( XmWorkspaceWidget ww,
4898 XmWorkspaceLine line )
4899 {
4900 short line_excess = ww->workspace.line_thickness;
4901 IF_LESS(line->x_left - line_excess, ww->workspace.expose_left);
4902 IF_MORE(line->x_right + line_excess, ww->workspace.expose_right);
4903 IF_LESS(line->y_upper - line_excess, ww->workspace.expose_upper);
4904 IF_MORE(line->y_lower + line_excess, ww->workspace.expose_lower);
4905 }
4906 #undef IF_MORE
4907 #undef IF_LESS
4908
4909
4910 /* Subroutine: UnsetExposureArea
4911 * Purpose: Set exposure area to show nothing and be ready for
4912 * first augmentation
4913 */
UnsetExposureArea(XmWorkspaceWidget ww)4914 static void UnsetExposureArea( XmWorkspaceWidget ww )
4915 {
4916 ww->workspace.expose_left = ww->core.width;
4917 ww->workspace.expose_right = -1;
4918 ww->workspace.expose_upper = ww->core.height;
4919 ww->workspace.expose_lower = -1;
4920 }
4921
4922
4923 /* Subroutine: RefreshLines
4924 * Purpose: Redraw all lines marked for movement, or within identified
4925 * expose bounds.
4926 */
RefreshLines(XmWorkspaceWidget ww)4927 void RefreshLines( XmWorkspaceWidget ww )
4928 {
4929 XmWorkspaceLine line, tmp_line;
4930 int color = -1;
4931 XRectangle rect;
4932
4933 if(!ww->workspace.line_drawing_enabled)
4934 return;
4935 if (XtIsRealized((Widget)ww) == False)
4936 return ;
4937
4938 /*
4939 * Redraw all lines that are in the cleared region, but clip the drawing
4940 * to the cleared region. This eliminate undesired side effects for
4941 * "copied" lines with haloing. The alternative is to redraw all lines
4942 * every time (too slow).
4943 */
4944 if (ww->workspace.lines)
4945 {
4946 if ( (ww->workspace.expose_right > ww->workspace.expose_left) &&
4947 (ww->workspace.expose_upper < ww->workspace.expose_lower) )
4948 {
4949 rect.x = ww->workspace.expose_left;
4950 rect.y = ww->workspace.expose_upper;
4951 rect.width = ww->workspace.expose_right -
4952 ww->workspace.expose_left +
4953 ww->workspace.line_thickness;
4954 rect.height = ww->workspace.expose_lower -
4955 ww->workspace.expose_upper +
4956 ww->workspace.line_thickness;
4957 XSetClipRectangles( XtDisplay(ww),
4958 xmWorkspaceClassRec.workspace_class.lineGC,
4959 0, 0,
4960 &rect, 1,
4961 YXBanded);
4962 XSetClipRectangles( XtDisplay(ww),
4963 xmWorkspaceClassRec.workspace_class.lineGC2,
4964 0, 0,
4965 &rect, 1,
4966 YXBanded);
4967 }
4968 else
4969 {
4970 XSetClipMask( XtDisplay(ww),
4971 xmWorkspaceClassRec.workspace_class.lineGC,
4972 None);
4973 XSetClipMask( XtDisplay(ww),
4974 xmWorkspaceClassRec.workspace_class.lineGC2,
4975 None);
4976 }
4977 }
4978 if( (line = ww->workspace.lines) )
4979 {
4980 while( line )
4981 {
4982 /* If lines' region was cleared, redo it */
4983 if( (line->x_right >= ww->workspace.expose_left) &&
4984 (line->x_left <= ww->workspace.expose_right) &&
4985 (line->y_lower >= ww->workspace.expose_upper) &&
4986 (line->y_upper <= ww->workspace.expose_lower) )
4987 {
4988 line->is_to_be_drawn = True;
4989 }
4990 line->two_phase_draw = False;
4991 line = line->next;
4992 }
4993 }
4994
4995 if( (line = ww->workspace.lines) )
4996 {
4997 while( line )
4998 {
4999 if( line->is_to_be_drawn )
5000 /*
5001 * Look through the rest of the list and see if we have a
5002 * "sibling" line (same source x,y). If we do, mark it for
5003 * 2 phase drawing and defer.
5004 */
5005 {
5006 tmp_line = line->next;
5007 while( tmp_line )
5008 {
5009 if ( (line->point[0].x == tmp_line->point[0].x) &&
5010 (line->point[0].y == tmp_line->point[0].y) )
5011 {
5012 line->two_phase_draw = True;
5013 tmp_line->two_phase_draw = True;
5014 break;
5015 }
5016 tmp_line = tmp_line->next;
5017 }
5018 if( XtIsRealized((Widget)ww) )
5019 {
5020 color = line->color;
5021 /* Get the GC and set it to this color */
5022 if( xmWorkspaceClassRec.workspace_class.lineGC == NULL )
5023 InitLineGC(ww, color);
5024 else
5025 XSetForeground
5026 (XtDisplay(ww),
5027 xmWorkspaceClassRec.workspace_class.lineGC,
5028 color);
5029 }
5030 if( ( XtIsRealized((Widget)ww) ) && (!line->two_phase_draw) )
5031 {
5032 if (line->num_points > 0)
5033 {
5034 XDrawLines(XtDisplay(ww), XtWindow(ww),
5035 xmWorkspaceClassRec.workspace_class.lineGC2,
5036 line->point, line->num_points,
5037 CoordModeOrigin);
5038
5039 XDrawLines(XtDisplay(ww), XtWindow(ww),
5040 xmWorkspaceClassRec.workspace_class.lineGC,
5041 line->point, line->num_points,
5042 CoordModeOrigin);
5043 line->is_to_be_drawn = FALSE;
5044 }
5045 }
5046 }
5047 line = line->next;
5048 }
5049 /*
5050 * Do the 2 phase draw
5051 */
5052 line = ww->workspace.lines;
5053 while( line )
5054 {
5055 if( line->two_phase_draw )
5056 {
5057 if( XtIsRealized((Widget)ww) )
5058 {
5059 color = line->color;
5060 /* Get the GC and set it to this color */
5061 if( xmWorkspaceClassRec.workspace_class.lineGC == NULL )
5062 InitLineGC(ww, color);
5063 else
5064 XSetForeground
5065 (XtDisplay(ww),
5066 xmWorkspaceClassRec.workspace_class.lineGC,
5067 color);
5068 }
5069 if( XtIsRealized((Widget)ww) )
5070 {
5071 if (line->num_points > 0)
5072 {
5073 XDrawLines(XtDisplay(ww), XtWindow(ww),
5074 xmWorkspaceClassRec.workspace_class.lineGC2,
5075 line->point, line->num_points,
5076 CoordModeOrigin);
5077
5078 }
5079 }
5080 tmp_line = line->next;
5081 while( tmp_line )
5082 {
5083 if ( (tmp_line->two_phase_draw) &&
5084 (tmp_line->point[0].x == line->point[0].x) &&
5085 (tmp_line->point[0].y == line->point[0].y) )
5086 {
5087 if (tmp_line->num_points > 0)
5088 {
5089 XDrawLines(XtDisplay(ww), XtWindow(ww),
5090 xmWorkspaceClassRec.workspace_class.lineGC2,
5091 tmp_line->point, tmp_line->num_points,
5092 CoordModeOrigin);
5093
5094 }
5095 }
5096 tmp_line = tmp_line->next;
5097 }
5098
5099 if( XtIsRealized((Widget)ww) )
5100 {
5101 if (line->num_points > 0)
5102 {
5103 XDrawLines(XtDisplay(ww), XtWindow(ww),
5104 xmWorkspaceClassRec.workspace_class.lineGC,
5105 line->point, line->num_points,
5106 CoordModeOrigin);
5107
5108 line->two_phase_draw = False;
5109 line->is_to_be_drawn = False;
5110 }
5111 }
5112 tmp_line = line->next;
5113 while( tmp_line )
5114 {
5115 if ( (tmp_line->two_phase_draw) &&
5116 (tmp_line->point[0].x == line->point[0].x) &&
5117 (tmp_line->point[0].y == line->point[0].y) )
5118 {
5119 if (tmp_line->num_points > 0)
5120 {
5121 XDrawLines(XtDisplay(ww), XtWindow(ww),
5122 xmWorkspaceClassRec.workspace_class.lineGC,
5123 tmp_line->point, tmp_line->num_points,
5124 CoordModeOrigin);
5125
5126 tmp_line->two_phase_draw = False;
5127 tmp_line->is_to_be_drawn = False;
5128 }
5129 }
5130 tmp_line = tmp_line->next;
5131 }
5132 }
5133 line = line->next;
5134 }
5135 }
5136 }
5137 /* Subroutine: InitLineGC
5138 * Purpose: Create the GC for drawing application lines in the workspace
5139 */
InitLineGC(XmWorkspaceWidget ww,int color)5140 static void InitLineGC( XmWorkspaceWidget ww, int color )
5141 {
5142 XGCValues values;
5143 unsigned long valuemask;
5144
5145 values.foreground = (unsigned long)color;
5146 values.function = GXcopy;
5147 values.line_width = ww->workspace.line_thickness;
5148 if( values.line_width > 0 )
5149 {
5150 valuemask = GCForeground | GCFunction | GCLineWidth ;
5151 }
5152 else
5153 valuemask = GCForeground | GCFunction ;
5154 /*Use X call in place of Xt call since we will be changing gc's values */
5155 xmWorkspaceClassRec.workspace_class.lineGC =
5156 XtGetGC((Widget)ww, valuemask, &values);
5157
5158 /*
5159 * Create the line halo GC
5160 */
5161 values.foreground = ww->core.background_pixel;
5162 values.line_width = ww->workspace.line_thickness +
5163 2*ww->workspace.halo_thickness;
5164 xmWorkspaceClassRec.workspace_class.lineGC2 =
5165 XtGetGC((Widget)ww, valuemask, &values);
5166 }
5167
5168
5169 /* Subroutine: CvtStringToWorkspaceType
5170 * Purpose: Resource converter to be registered in class init to handle
5171 * strings XXXX_XXXX which represent XmXXXX_XXXX from
5172 * .Xdefaults file
5173 */
CvtStringToWorkspaceType(XrmValue * args,Cardinal num_args,XrmValue * from_val,XrmValue * to_val)5174 static void CvtStringToWorkspaceType( XrmValue* args, Cardinal num_args,
5175 XrmValue* from_val, XrmValue* to_val )
5176 {
5177 char * in_str = (char *) (from_val->addr);
5178 static unsigned char i;
5179
5180 to_val->size = sizeof (unsigned char);
5181 to_val->addr = (void *) &i;
5182
5183 if( StringsAreEqual(in_str, "include_all") )
5184 i = XmINCLUDE_ALL;
5185 else if( StringsAreEqual(in_str, "include_any") )
5186 i = XmINCLUDE_ANY;
5187 else if( StringsAreEqual(in_str, "include_center") )
5188 i = XmINCLUDE_CENTER;
5189 else if( StringsAreEqual(in_str, "accent_background") )
5190 i = XmACCENT_BACKGROUND;
5191 else if( StringsAreEqual(in_str, "accent_border") )
5192 i = XmACCENT_BORDER;
5193 else if( StringsAreEqual(in_str, "accent_none") )
5194 i = XmACCENT_NONE;
5195 else if( StringsAreEqual(in_str, "outline_each") )
5196 i = XmOUTLINE_EACH;
5197 else if( StringsAreEqual(in_str, "outline_all") )
5198 i = XmOUTLINE_ALL;
5199 else if( StringsAreEqual(in_str, "outline_plus") )
5200 i = XmOUTLINE_PLUS;
5201 else if( StringsAreEqual(in_str, "draw_none") )
5202 i = XmDRAW_NONE;
5203 else if( StringsAreEqual(in_str, "draw_hash") )
5204 i = XmDRAW_HASH;
5205 else if( StringsAreEqual(in_str, "draw_line") )
5206 i = XmDRAW_LINE;
5207 else if( StringsAreEqual(in_str, "draw_outline") )
5208 i = XmDRAW_OUTLINE;
5209 else
5210 {
5211 to_val->size = 0;
5212 to_val->addr = NULL;
5213 XtStringConversionWarning ((char *)from_val->addr, XmRWorkspaceType);
5214 }
5215 }
5216
StringsAreEqual(register char * in_str,register char * test_str)5217 static Boolean StringsAreEqual( register char * in_str,
5218 register char * test_str )
5219 {
5220 register int i;
5221 register int j;
5222
5223 for (;;)
5224 {
5225 i = *in_str;
5226 j = *test_str;
5227
5228 if (isupper (i)) i = tolower (i);
5229 if (i != j) return (False);
5230 if (i == 0) return (True);
5231
5232 in_str++;
5233 test_str++;
5234 }
5235 }
5236
5237
5238 /* Subroutine: XmCreateWorkspace
5239 * Purpose: Externally accessable convenience function to create
5240 * workspace widget
5241 */
XmCreateWorkspace(Widget parent,char * name,Arg arglist[],int argCount)5242 Widget XmCreateWorkspace( Widget parent, char* name,
5243 Arg arglist[], int argCount )
5244 {
5245 return XtCreateWidget(name, xmWorkspaceWidgetClass, parent,
5246 arglist, argCount);
5247 }
5248
5249
5250 /* Subroutine: AddWorkspaceAddCallback
5251 * Purpose: Register a callback for selection changes due to workspace
5252 * widget management events.
5253 * Note: This routine must be used in place of XtAddCallback since
5254 * Xt code cannot handle callback lists in constraint fields.
5255 */
XmWorkspaceAddCallback(Widget child,String name,XtCallbackProc callback,XtPointer client_data)5256 void XmWorkspaceAddCallback( Widget child, String name,
5257 XtCallbackProc callback, XtPointer client_data )
5258 {
5259 XmWorkspaceConstraints constraints;
5260
5261 /* Bypass Xt weakness of not handling callbacks in constraint resources */
5262 if( callback )
5263 {
5264 constraints = WORKSPACE_CONSTRAINT(child);
5265 if( name && STRCMP(name, XmNaccentCallback) == 0 )
5266 AddConstraintCallback(child,
5267 &(constraints->workspace.accent_callbacks),
5268 callback, client_data);
5269 else if( name && STRCMP(name, XmNselectionCallback) == 0 )
5270 AddConstraintCallback(child,
5271 &(constraints->workspace.select_callbacks),
5272 callback, client_data);
5273 else if( name && STRCMP(name, XmNresizingCallback) == 0 )
5274 AddConstraintCallback(child,
5275 &(constraints->workspace.resizing_callbacks),
5276 callback, client_data);
5277 }
5278 }
5279
5280 #if 0
5281 void XmWorkspaceGetMaxWidthHeight(Widget w, int *width, int *height)
5282 {
5283 XmWorkspaceWidget ww = (XmWorkspaceWidget)w;
5284 int i;
5285 Widget child;
5286 XmWorkspaceConstraints constraints;
5287
5288 *width = *height = 0;
5289
5290 for( i=0; i<ww->composite.num_children; i++ )
5291 {
5292 child = ww->composite.children[i];
5293 if(!child->core.being_destroyed)
5294 {
5295 constraints = WORKSPACE_CONSTRAINT(child);
5296 if(constraints->workspace.x_right > *width)
5297 *width = constraints->workspace.x_right;
5298 if(constraints->workspace.y_lower > *height)
5299 *height = constraints->workspace.y_lower;
5300 }
5301 }
5302 (*width)++;
5303 (*height)++;
5304 }
5305 #else
XmWorkspaceGetMaxWidthHeight(Widget w,int * width,int * height)5306 void XmWorkspaceGetMaxWidthHeight(Widget w, int *width, int *height)
5307 {
5308 XmWorkspaceWidget ww = (XmWorkspaceWidget)w;
5309 int i,mw, mh,ext;
5310 Widget child;
5311
5312 mw = mh = 0;
5313 for (i=0; i<ww->composite.num_children; i++) {
5314 child = ww->composite.children[i];
5315 if (!XtIsManaged(child)) continue;
5316 if (XtClass(child) == xmWorkspaceWidgetClass) {
5317 int tmpw, tmph;
5318 XmWorkspaceGetMaxWidthHeight(child, &tmpw, &tmph);
5319 mw = MAX(mw, tmpw);
5320 mh = MAX(mh, tmph);
5321 } else {
5322 ext = child->core.x + child->core.width;
5323 mw = MAX(mw, ext);
5324 ext = child->core.y + child->core.height;
5325 mh = MAX(mh, ext);
5326 }
5327 }
5328
5329 *width = mw;
5330 *height = mh;
5331 }
5332 #endif
5333
5334 /* Subroutine: XmAddWorkspaceEventHandler
5335 * Pupose: Export routine to add event-handler type callback for button
5336 * motion and button-release in Workspace background.
5337 * Note: The event owner widget need not be a child of the workspace.
5338 */
XmAddWorkspaceEventHandler(XmWorkspaceWidget ww,Widget owner,XtEventHandler handler,XtPointer client_data)5339 void XmAddWorkspaceEventHandler( XmWorkspaceWidget ww, Widget owner,
5340 XtEventHandler handler, XtPointer client_data )
5341 {
5342 Window child;
5343 int x_offset, y_offset;
5344
5345 /* If this is a void call, clear the handler */
5346 if( handler == NULL )
5347 ww->workspace.button_tracker = NULL;
5348 else
5349 {
5350 /* Install the pointers */
5351 ww->workspace.button_tracker = handler;
5352 ww->workspace.track_widget = owner;
5353 XTranslateCoordinates(XtDisplay(ww), XtWindow(ww), XtWindow(owner),
5354 0, 0, &x_offset, &y_offset, &child);
5355 ww->workspace.track_x = x_offset;
5356 ww->workspace.track_y = y_offset;
5357 ww->workspace.track_client_data = client_data;
5358 }
5359 }
5360
5361 /*
5362 * Note on memory bug:
5363 * The code in this file and in Findroute.c assumes that all children are within
5364 * the bounds of this widget. (ww->core.{width,height} > bottom,right corner of
5365 * every child.) If that becomes not true, then a core dump is imminent. I added
5366 * the use of newWidth,newHeight here and a safety check in Findroute.c to protect
5367 * against this.
5368 */
ReallocCollideLists(XmWorkspaceWidget ww)5369 void ReallocCollideLists(XmWorkspaceWidget ww)
5370 {
5371 CollideList **cl_ptr;
5372 CollideList *ce_ptr;
5373 CollideList *n_ce_ptr;
5374 int old_width = ww->workspace.collide_width;
5375 int old_height = ww->workspace.collide_height;
5376 int block_size;
5377 int i;
5378 int newWidth, newHeight, maxw, maxh;
5379
5380 newWidth = ww->core.width;
5381 newHeight = ww->core.height;
5382 XmWorkspaceGetMaxWidthHeight ((Widget)ww, &maxw, &maxh);
5383 if ((maxw > ww->core.width) || (maxh > ww->core.height)) {
5384 /*
5385 * Being here is dangerous becuase the code
5386 * assumes that the bottom right of the farthest
5387 * widget is inside the Workspace
5388 */
5389 if (maxw > ww->core.width) newWidth = maxw;
5390 if (maxh > ww->core.height) newHeight = maxh;
5391 }
5392
5393 /* Do our own realloc since the other does not do the copy */
5394 if (newWidth > old_width) {
5395 cl_ptr = ww->workspace.collide_list_x;
5396 ww->workspace.collide_list_x =
5397 (CollideList **)XtMalloc(sizeof(CollideList*)*(newWidth));
5398 memset(ww->workspace.collide_list_x, 0,
5399 sizeof (CollideList*) * newWidth);
5400 block_size = sizeof(CollideList*) * MIN(old_width, newWidth);
5401 memcpy(ww->workspace.collide_list_x, cl_ptr, block_size);
5402 XtFree((char*)cl_ptr);
5403 ww->workspace.collide_width = ww->core.width;
5404 } else {
5405 cl_ptr = ww->workspace.collide_list_x;
5406 for (i = newWidth; i < old_width; ++i)
5407 {
5408 for (ce_ptr = cl_ptr[i]; ce_ptr; ce_ptr = n_ce_ptr)
5409 {
5410 n_ce_ptr = ce_ptr->next;
5411 XtFree((char*)ce_ptr);
5412 }
5413 cl_ptr[i] = 0;
5414 }
5415 }
5416
5417 if (newHeight > old_height) {
5418 cl_ptr = ww->workspace.collide_list_y;
5419 ww->workspace.collide_list_y =
5420 (CollideList **)XtMalloc(sizeof(CollideList*)*(newHeight));
5421 memset(ww->workspace.collide_list_y, 0,
5422 sizeof (CollideList*) * newHeight);
5423 block_size = sizeof(CollideList*) * MIN(old_height, newHeight);
5424 memcpy(ww->workspace.collide_list_y, cl_ptr, block_size);
5425 XtFree((char*)cl_ptr);
5426 ww->workspace.collide_height = newHeight;
5427 } else {
5428 cl_ptr = ww->workspace.collide_list_y;
5429 for (i = newHeight; i < old_height; ++i)
5430 {
5431 for (ce_ptr = cl_ptr[i]; ce_ptr; ce_ptr = n_ce_ptr)
5432 {
5433 n_ce_ptr = ce_ptr->next;
5434 XtFree((char*)ce_ptr);
5435 }
5436 cl_ptr[i] = 0;
5437 }
5438 }
5439
5440 }
5441 /*
5442 * Return the number of distinct points in the path as the return value.
5443 * Place in the x and y arrays, the list of connecting points.
5444 * The return arrays x and y, must be XtFree()'d by the caller.
5445 */
XmWorkspaceLineGetPath(XmWorkspaceLine wl,int ** x,int ** y)5446 int XmWorkspaceLineGetPath(XmWorkspaceLine wl, int **x, int **y)
5447 {
5448 int *xx, *yy, i, points;
5449
5450 points = wl->num_points;
5451
5452 if (points > 0) {
5453 xx = (int*)XtMalloc(points * sizeof(int));
5454 yy = (int*)XtMalloc(points * sizeof(int));
5455 for (i=0; i<points ; i++) {
5456 xx[i] = wl->point[i].x;
5457 yy[i] = wl->point[i].y;
5458 }
5459 *x = xx;
5460 *y = yy;
5461 } else {
5462 *x = NULL;
5463 *y = NULL;
5464 }
5465 return points;
5466
5467 }
5468
5469
5470 /*
5471 * A quick-n-dirty way to check if a place is occupied by a standin. This allows
5472 * StandIn not to inherit from DropSite. It's a way to reject drops that would
5473 * land on top of an existing StandIn. This was sought due to a theory that
5474 * said it was very expensive to put a StandIn on the screen if it had to be
5475 * registered as a drop site in addition to all its other responsibilities.
5476 * - Martin
5477 */
5478 Boolean
XmWorkspaceLocationEmpty(Widget w,int x,int y)5479 XmWorkspaceLocationEmpty (Widget w, int x, int y)
5480 {
5481 XmWorkspaceWidget ww = (XmWorkspaceWidget)w;
5482 Boolean unoccupied = True;
5483 Widget child;
5484 int i;
5485
5486 for (i=0; ((i<ww->composite.num_children)&&(unoccupied)); i++) {
5487 child = ww->composite.children[i];
5488 if (!XtIsManaged(child)) continue;
5489
5490 if (x<child->core.x) continue;
5491 if (y<child->core.y) continue;
5492 if (x>(child->core.x + child->core.width)) continue;
5493 if (y>(child->core.y + child->core.height)) continue;
5494 unoccupied = False;
5495 }
5496 return unoccupied;
5497 }
5498
5499
5500 Boolean
XmWorkspaceRectangleEmpty(Widget w,int x,int y,int width,int height)5501 XmWorkspaceRectangleEmpty (Widget w, int x, int y, int width, int height)
5502 {
5503 XmWorkspaceWidget ww = (XmWorkspaceWidget)w;
5504 Boolean unoccupied = True;
5505 Widget child;
5506 int i;
5507
5508 for (i=0; ((i<ww->composite.num_children)&&(unoccupied)); i++) {
5509 child = ww->composite.children[i];
5510 if (!XtIsManaged(child)) continue;
5511
5512 if ((x+width)<child->core.x) continue;
5513 if ((y+height)<child->core.y) continue;
5514 if (x>(child->core.x + child->core.width)) continue;
5515 if (y>(child->core.y + child->core.height)) continue;
5516 unoccupied = False;
5517 }
5518 return unoccupied;
5519 }
5520
5521
5522
5523 #if RESIZE_HANDLES
status_check(Widget w,XEvent * event)5524 static void status_check (Widget w, XEvent *event)
5525 {
5526 XmWorkspaceWidget ww;
5527 Widget grab_child;
5528 int i;
5529 XmWorkspaceConstraints constraints;
5530
5531 if (!ww->workspace.is_resizing) {
5532 for (i=0; i<ww->composite.num_children; i++)
5533 if (inHierarchy(XtWindowToWidget(XtDisplay(ww), event->xany.window), ww, i))
5534 break;
5535 /* This call comes from the accelerator so it should have a child */
5536 if( i >= ww->composite.num_children )
5537 return;
5538 grab_child = ww->composite.children[i];
5539 constraints = WORKSPACE_CONSTRAINT(grab_child);
5540
5541 /* Prepare to resize */
5542 CreateSurrogate(ww, grab_child);
5543 ww->workspace.is_resizing = TRUE;
5544 /* Use base variables to keep track of move applied so far */
5545 ww->workspace.start.x = 0;
5546 ww->workspace.start.y = 0;
5547 ww->workspace.corner.x = grab_child->core.width;
5548 ww->workspace.corner.y = grab_child->core.height;
5549 ww->workspace.grab_x = event->xbutton.x;
5550 ww->workspace.grab_y = event->xbutton.y;
5551 ww->workspace.base_x = 0;
5552 ww->workspace.base_y = 0;
5553 }
5554
5555 if( ww->workspace.move_cursor_installed == FALSE ) {
5556 XDefineCursor(XtDisplay(ww), XtWindow(ww),
5557 xmWorkspaceClassRec.workspace_class.move_cursor);
5558 ww->workspace.move_cursor_installed = TRUE;
5559 }
5560 }
5561
ResizeNE(Widget w,XEvent * event,String * params,Cardinal * num_params)5562 static void ResizeNE( Widget w, XEvent* event, String* params, Cardinal* num_params )
5563 {
5564 XmWorkspaceWidget ww;
5565 XPoint loc, size;
5566 int tx,ty;
5567 Widget child;
5568
5569 if (!(ww = WorkspaceOfWidget(w))) return ;
5570
5571 if (ww->workspace.auto_arrange) return ;
5572
5573 status_check (w, event);
5574 ww->workspace.is_moving = TRUE;
5575
5576 loc.x = event->xbutton.x - ww->workspace.start.x;
5577 loc.y = event->xbutton.y - ww->workspace.start.y;
5578 size.x = ww->workspace.corner.x + event->xbutton.x;
5579 size.y = ww->workspace.corner.y - event->xbutton.y;
5580 MoveSurrogate(ww, 0, loc.y);
5581 childRelative (ww, event, &tx, &ty);
5582 size.x = MAX(10, tx);
5583 ResizeSurrogate (ww, size.x, size.y);
5584 ww->workspace.start.x = event->xbutton.x;
5585 ww->workspace.start.y = event->xbutton.y;
5586 }
ResizeNW(Widget w,XEvent * event,String * params,Cardinal * num_params)5587 static void ResizeNW( Widget w, XEvent* event, String* params, Cardinal* num_params )
5588 {
5589 XmWorkspaceWidget ww;
5590 XPoint loc, size;
5591 int tx,ty;
5592 Widget child;
5593
5594 if (!(ww = WorkspaceOfWidget(w))) return ;
5595
5596 if (ww->workspace.auto_arrange) return ;
5597
5598 status_check (w, event);
5599 ww->workspace.is_moving = TRUE;
5600
5601 loc.x = event->xbutton.x - ww->workspace.start.x;
5602 loc.y = event->xbutton.y - ww->workspace.start.y;
5603 size.x = ww->workspace.corner.x - event->xbutton.x;
5604 size.y = ww->workspace.corner.y - event->xbutton.y;
5605 MoveSurrogate(ww, loc.x, loc.y);
5606 ResizeSurrogate (ww, size.x, size.y);
5607 ww->workspace.start.x = event->xbutton.x;
5608 ww->workspace.start.y = event->xbutton.y;
5609 }
ResizeSE(Widget w,XEvent * event,String * params,Cardinal * num_params)5610 static void ResizeSE( Widget w, XEvent* event, String* params, Cardinal* num_params )
5611 {
5612 XmWorkspaceWidget ww;
5613 int width, height, tx,ty;
5614
5615 if (!(ww = WorkspaceOfWidget(w))) return ;
5616
5617 if (ww->workspace.auto_arrange) return ;
5618
5619 status_check (w, event);
5620 ww->workspace.is_moving = FALSE;
5621 tx = event->xbutton.x; ty = event->xbutton.y;
5622 childRelative (ww, event, &tx, &ty);
5623 width = MAX(10, tx); height = MAX(10, ty);
5624 ResizeSurrogate(ww, width, height);
5625 }
ResizeSW(Widget w,XEvent * event,String * params,Cardinal * num_params)5626 static void ResizeSW( Widget w, XEvent* event, String* params, Cardinal* num_params )
5627 {
5628 XmWorkspaceWidget ww;
5629 XPoint loc, size;
5630 int tx,ty;
5631 Widget child;
5632
5633 if (!(ww = WorkspaceOfWidget(w))) return ;
5634
5635 if (ww->workspace.auto_arrange) return ;
5636
5637 status_check (w, event);
5638 ww->workspace.is_moving = TRUE;
5639
5640 loc.x = event->xbutton.x - ww->workspace.start.x;
5641 loc.y = event->xbutton.y - ww->workspace.start.y;
5642 size.x = ww->workspace.corner.x - event->xbutton.x;
5643 MoveSurrogate(ww, loc.x, 0);
5644 childRelative (ww, event, &tx, &ty);
5645 size.y = MAX(10, ty);
5646 ResizeSurrogate (ww, size.x, size.y);
5647 ww->workspace.start.x = event->xbutton.x;
5648 ww->workspace.start.y = event->xbutton.y;
5649
5650 }
5651
5652
NewDrop(Widget w,XEvent * event,String * params,Cardinal * num_params)5653 static void NewDrop( Widget w, XEvent* event, String* params, Cardinal* num_params )
5654 {
5655 Widget child;
5656 XmWorkspaceWidget ww;
5657
5658 if (!(ww = WorkspaceOfWidget(w))) return ;
5659
5660 if (ww->workspace.auto_arrange) return ;
5661
5662 child = w;
5663 while ((child) && (XtParent(child) != (Widget)ww)) child = XtParent(child);
5664 if ((child) && (XtParent(child) == (Widget)ww))
5665 XtVaSetValues (child, XmNmappedWhenManaged, False, NULL);
5666
5667 DropSelections (w, event, params, num_params);
5668
5669 if ((child) && (XtParent(child) == (Widget)ww)) {
5670 XSync (XtDisplay(child), False);
5671 XtVaSetValues (child, XmNmappedWhenManaged, True, NULL);
5672 }
5673 }
5674 #endif
5675