1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/cmd.c,v 1.15 2011/05/16 16:21:56 william Exp $
19 */
20
21 #define _INCLUDE_FROM_CMD_C_
22
23 #include "tgifdefs.h"
24
25 #include "attr.e"
26 #include "choice.e"
27 #include "cmd.e"
28 #include "color.e"
29 #include "dialog.e"
30 #include "drawing.e"
31 #include "dup.e"
32 #include "file.e"
33 #include "grid.e"
34 #include "imgproc.e"
35 #include "mainmenu.e"
36 #include "mark.e"
37 #include "miniline.e"
38 #include "move.e"
39 #include "msg.e"
40 #include "navigate.e"
41 #include "obj.e"
42 #include "page.e"
43 #include "remote.e"
44 #include "select.e"
45 #include "setup.e"
46 #include "stk.e"
47 #include "strtbl.e"
48 #include "text.e"
49 #include "util.e"
50 #include "wb.e"
51 #include "xpixmap.e"
52
53 int recordCmdIncludeTgifObj=FALSE;
54 int recordCmdUsesNewColormap=FALSE;
55 int undoingOrRedoing=FALSE;
56 int historyDepth=(-1), historyCount=0, defaultHistoryDepth=(-1);
57 struct CmdRec *firstCmd=NULL, *lastCmd=NULL, *curCmd=NULL;
58
59 struct SelRec *topSelBeforeInCmd=NULL, *botSelBeforeInCmd=NULL;
60 int *stackingPosition=NULL;
61 int stackingCount=0;
62 int stackingPositionHasIds=FALSE;
63
64 int composingCommand=FALSE;
65 int undoRedoRestoreDrawingMode=FALSE;
66 Colormap preparedColormap=None;
67
InsertCmd(PrevCmd,NextCmd,CmdPtr,ppFirstCmd,ppLastCmd)68 void InsertCmd(PrevCmd, NextCmd, CmdPtr, ppFirstCmd, ppLastCmd)
69 struct CmdRec *PrevCmd, *NextCmd, *CmdPtr;
70 struct CmdRec **ppFirstCmd, **ppLastCmd;
71 /* add CmdPtr between PrevCmd and NextCmd */
72 /* update *ppFirstCmd and *ppLastCmd */
73 {
74 CmdPtr->prev = PrevCmd;
75 CmdPtr->next = NextCmd;
76
77 if (PrevCmd == NULL) {
78 (*ppFirstCmd) = CmdPtr;
79 } else {
80 PrevCmd->next = CmdPtr;
81 }
82 if (NextCmd == NULL) {
83 (*ppLastCmd) = CmdPtr;
84 } else {
85 NextCmd->prev = CmdPtr;
86 }
87 }
88
89 static
GetCmdType(CmdType)90 char *GetCmdType(CmdType)
91 int CmdType;
92 {
93 switch (CmdType) {
94 case CMD_COMPOSITE: return "CMD_COMPOSITE";
95 case CMD_NEW: return "CMD_NEW";
96 case CMD_DELETE: return "CMD_DELETE";
97 case CMD_MOVE: return "CMD_MOVE";
98 case CMD_STRETCH: return "CMD_STRETCH";
99 case CMD_ONE_TO_MANY: return "CMD_ONE_TO_MANY";
100 case CMD_MANY_TO_ONE: return "CMD_MANY_TO_ONE";
101 case CMD_REPLACE: return "CMD_REPLACE";
102 case CMD_GOTO_PAGE: return "CMD_GOTO_PAGE";
103 case CMD_WB_CLEARALL: return "CMD_WB_CLEARALL";
104 case CMD_CHAT_A_LINE: return "CMD_CHAT_A_LINE";
105 case CMD_WB_SLIDESHOW: return "CMD_WB_SLIDESHOW";
106 default: return "(unknown)";
107 }
108 }
109
110 static
CreateCmdFromSerializationBuf(cmd_type,buf)111 struct CmdRec *CreateCmdFromSerializationBuf(cmd_type, buf)
112 int cmd_type;
113 char *buf;
114 {
115 struct CmdRec *cmd_ptr=NULL;
116
117 cmd_ptr = (struct CmdRec *)malloc(sizeof(struct CmdRec));
118 if (cmd_ptr == NULL) FailAllocMessage();
119 memset(cmd_ptr, 0, sizeof(struct CmdRec));
120
121 cmd_ptr->type = cmd_type;
122 cmd_ptr->serialization_buf = UtilStrDup(buf);
123 if (cmd_ptr->serialization_buf == NULL) FailAllocMessage();
124
125 return cmd_ptr;
126 }
127
CopyAndInsertCmd(from_remote,serialization_buf,PrevCmd,NextCmd,CmdPtr,ppFirstCmd,ppLastCmd)128 void CopyAndInsertCmd(from_remote, serialization_buf, PrevCmd, NextCmd, CmdPtr,
129 ppFirstCmd, ppLastCmd)
130 int from_remote;
131 char *serialization_buf;
132 struct CmdRec *PrevCmd, *NextCmd, *CmdPtr;
133 struct CmdRec **ppFirstCmd, **ppLastCmd;
134 /* add CmdPtr between PrevCmd and NextCmd */
135 /* update *ppFirstCmd and *ppLastCmd */
136 {
137 if ((!from_remote && CmdPtr->undone) || (from_remote && !CmdPtr->undone)) {
138 sprintf(gszMsgBox, "(%s) Found an %s command, type = %s.",
139 (from_remote ? "from_remote" : "local"),
140 (CmdPtr->undone ? "undone" : "not undone"),
141 GetCmdType(CmdPtr->type));
142 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
143 } else {
144 struct CmdRec *cmd_ptr=NULL;
145
146 #ifdef _TGIF_DBG_WB2
147 fprintf(stdout,
148 "<*><*><*>(%s) CopyAndInsertCmd() a command of type: %s.\n",
149 (from_remote ? "from_remote" : "local"),
150 GetCmdType(CmdPtr->type));
151 fflush(stdout);
152 #endif /* _TGIF_DBG_WB2 */
153
154 cmd_ptr = CreateCmdFromSerializationBuf(CmdPtr->type, serialization_buf);
155
156 cmd_ptr->prev = PrevCmd;
157 cmd_ptr->next = NextCmd;
158
159 if (PrevCmd == NULL) {
160 (*ppFirstCmd) = cmd_ptr;
161 } else {
162 PrevCmd->next = cmd_ptr;
163 }
164 if (NextCmd == NULL) {
165 (*ppLastCmd) = cmd_ptr;
166 } else {
167 NextCmd->prev = cmd_ptr;
168 }
169 }
170 }
171
172 static
UnlinkCmd(CmdPtr,ppFirstCmd,ppLastCmd)173 void UnlinkCmd(CmdPtr, ppFirstCmd, ppLastCmd)
174 struct CmdRec *CmdPtr;
175 struct CmdRec **ppFirstCmd, **ppLastCmd;
176 {
177 if ((*ppFirstCmd) == CmdPtr) {
178 (*ppFirstCmd) = CmdPtr->next;
179 } else {
180 CmdPtr->prev->next = CmdPtr->next;
181 }
182 if ((*ppLastCmd) == CmdPtr) {
183 (*ppLastCmd) = CmdPtr->prev;
184 } else {
185 CmdPtr->next->prev = CmdPtr->prev;
186 }
187 }
188
DeleteARedoRecord(CmdPtr,percent_start,percent_end)189 void DeleteARedoRecord(CmdPtr, percent_start, percent_end)
190 struct CmdRec *CmdPtr;
191 double percent_start, percent_end;
192 {
193 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
194 struct CmdRec *cmd_ptr=NULL, *prev_cmd=NULL;
195 int num_records=0;
196 double inc=0;
197
198 if (CmdPtr->pos_before_has_ids) {
199 if (CmdPtr->pos_before != NULL) {
200 int i=0;
201 char **s_ptr=(char**)(CmdPtr->pos_before);
202
203 for (i=0; i < CmdPtr->count_before; i++) {
204 if (s_ptr[i] != NULL) {
205 UtilFree(s_ptr[i]);
206 } else {
207 break;
208 }
209 }
210 free(CmdPtr->pos_before);
211 }
212 } else {
213 if (CmdPtr->pos_before != NULL) free(CmdPtr->pos_before);
214 }
215 if (CmdPtr->pos_after != NULL) free(CmdPtr->pos_after);
216
217 if (percent_start >= 0.0) {
218 sprintf(gszMsgBox, TgLoadCachedString(CSTID_FLUSH_UNDO_PERCENT),
219 round(percent_start));
220 SetStringStatus(gszMsgBox);
221 CheckInterrupt(TRUE);
222 }
223 switch (CmdPtr->type) {
224 case CMD_NEW:
225 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
226 next_sel = sel_ptr->next;
227 if (CmdPtr->undone) FreeObj(sel_ptr->obj);
228 free(sel_ptr);
229 }
230 break;
231 case CMD_DELETE:
232 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
233 next_sel = sel_ptr->next;
234 if (!CmdPtr->undone) FreeObj(sel_ptr->obj);
235 free(sel_ptr);
236 }
237 break;
238 case CMD_MOVE:
239 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
240 next_sel = sel_ptr->next;
241 free(sel_ptr);
242 }
243 if (CmdPtr->subcmd != NULL) {
244 free(CmdPtr->subcmd);
245 }
246 break;
247 case CMD_STRETCH:
248 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
249 next_sel = sel_ptr->next;
250 FreeObj(sel_ptr->obj);
251 free(sel_ptr);
252 }
253 if (CmdPtr->serialized) {
254 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
255 next_sel = sel_ptr->next;
256 free(sel_ptr);
257 }
258 }
259 break;
260 case CMD_REPLACE:
261 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
262 next_sel = sel_ptr->next;
263 FreeObj(sel_ptr->obj);
264 free(sel_ptr);
265 }
266 if (CmdPtr->serialized) {
267 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
268 next_sel = sel_ptr->next;
269 free(sel_ptr);
270 }
271 }
272 break;
273 case CMD_ONE_TO_MANY:
274 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
275 next_sel = sel_ptr->next;
276 if (!CmdPtr->undone) FreeObj(sel_ptr->obj);
277 free(sel_ptr);
278 }
279 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
280 next_sel = sel_ptr->next;
281 if (CmdPtr->undone) FreeObj(sel_ptr->obj);
282 free(sel_ptr);
283 }
284 break;
285 case CMD_MANY_TO_ONE:
286 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=next_sel) {
287 next_sel = sel_ptr->next;
288 if (!CmdPtr->undone) FreeObj(sel_ptr->obj);
289 free(sel_ptr);
290 }
291 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
292 next_sel = sel_ptr->next;
293 if (CmdPtr->undone) FreeObj(sel_ptr->obj);
294 free(sel_ptr);
295 }
296 break;
297 case CMD_COMPOSITE:
298 if (percent_start >= 0) {
299 for (cmd_ptr=CmdPtr->first; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->next) {
300 num_records++;
301 }
302 if (num_records > 0) {
303 inc = (percent_end-percent_start)/((double)num_records);
304 }
305 }
306 for (cmd_ptr=CmdPtr->last; cmd_ptr!=NULL; cmd_ptr=prev_cmd) {
307 prev_cmd = cmd_ptr->prev;
308 if (percent_start >= 0) {
309 DeleteARedoRecord(cmd_ptr, percent_start,
310 min(((double)percent_start+inc),((double)100.0)));
311 percent_start += inc;
312 } else {
313 DeleteARedoRecord(cmd_ptr, percent_start, percent_end);
314 }
315 }
316 break;
317 case CMD_CHAT_A_LINE:
318 if (CmdPtr->subcmd != NULL) {
319 UtilFree(CmdPtr->subcmd->detail.chat.buf);
320 free(CmdPtr->subcmd);
321 }
322 break;
323 case CMD_WB_SLIDESHOW:
324 if (CmdPtr->subcmd != NULL) free(CmdPtr->subcmd);
325 break;
326 case CMD_WB_CLEARALL:
327 if (CmdPtr->subcmd != NULL) free(CmdPtr->subcmd);
328 break;
329 }
330 if (gstWBInfo.do_whiteboard) {
331 if (CmdPtr->sender_process_id != NULL) {
332 UtilFree(CmdPtr->sender_process_id);
333 }
334 if (CmdPtr->serialization_buf != NULL) {
335 UtilFree(CmdPtr->serialization_buf);
336 }
337 }
338 free(CmdPtr);
339 }
340
ClearRedoRecords(CmdPtr)341 void ClearRedoRecords(CmdPtr)
342 struct CmdRec *CmdPtr;
343 {
344 struct CmdRec *cmd_ptr=NULL, *prev_cmd=NULL;
345
346 for (cmd_ptr=lastCmd; cmd_ptr != curCmd; cmd_ptr=prev_cmd) {
347 prev_cmd = cmd_ptr->prev;
348 DeleteARedoRecord(cmd_ptr, (-1.0), (-1.0));
349 historyCount--;
350 }
351 if ((lastCmd=curCmd) == NULL) firstCmd = NULL;
352 }
353
CleanUpCmds()354 void CleanUpCmds()
355 {
356 struct CmdRec *cmd_ptr=NULL, *prev_cmd=NULL;
357 int num_records=0;
358
359 for (cmd_ptr=lastCmd; cmd_ptr != NULL; cmd_ptr=cmd_ptr->prev) {
360 num_records++;
361 }
362 if (num_records > 0) {
363 double inc=(100.0/((double)num_records)), percent_start=0.0;
364
365 ShowInterrupt(1);
366 SaveStatusStrings();
367 for (cmd_ptr=lastCmd; cmd_ptr != NULL; cmd_ptr=prev_cmd,
368 percent_start += inc) {
369 prev_cmd = cmd_ptr->prev;
370 DeleteARedoRecord(cmd_ptr, percent_start,
371 min(((double)percent_start+inc),((double)100.0)));
372 }
373 RestoreStatusStrings();
374 HideInterrupt();
375 }
376 firstCmd = lastCmd = curCmd = NULL;
377 historyCount = 0;
378 }
379
CopySel(from_top_sel,count,to_top_sel,to_bot_sel)380 void CopySel(from_top_sel, count, to_top_sel, to_bot_sel)
381 struct SelRec *from_top_sel;
382 int count;
383 struct SelRec **to_top_sel, **to_bot_sel;
384 {
385 struct SelRec *sel_ptr=NULL;
386
387 *to_top_sel = *to_bot_sel = NULL;
388
389 for (sel_ptr=from_top_sel; sel_ptr!=NULL; sel_ptr=sel_ptr->next, count--) {
390 AddObjIntoSel(sel_ptr->obj, *to_bot_sel, NULL, to_top_sel, to_bot_sel);
391 }
392 if (count != 0) {
393 FatalUnexpectedError(
394 "Count != 0 in CopySel().", /* debug, do not translate */
395 TgLoadString(STID_UNDO_REDO_MAY_CAUSE_CRASH));
396 }
397 }
398
399 static
LinkJustTheObjects(TopSel,BotSel)400 void LinkJustTheObjects(TopSel, BotSel)
401 struct SelRec *TopSel, *BotSel;
402 {
403 struct SelRec *sel_ptr=NULL, *sel_ptr_next=NULL;
404
405 sel_ptr = TopSel;
406 sel_ptr_next = TopSel->next;
407 sel_ptr->obj->prev = NULL;
408 for ( ; sel_ptr_next!=NULL; sel_ptr=sel_ptr_next,
409 sel_ptr_next=sel_ptr->next) {
410 sel_ptr->obj->next = sel_ptr_next->obj;
411 sel_ptr_next->obj->prev = sel_ptr->obj;
412 }
413 sel_ptr->obj->next = NULL;
414 }
415
416 static
UndoNewCmd(CmdPtr)417 void UndoNewCmd(CmdPtr)
418 struct CmdRec *CmdPtr;
419 {
420 struct SelRec *sel_ptr=NULL;
421 struct ObjRec *obj_ptr=NULL, *next_obj=NULL;
422 int pos=0, count=0;
423
424 topSel = CmdPtr->top_after;
425 botSel = CmdPtr->bot_after;
426
427 sel_ptr = topSel;
428 pos = count = 0;
429 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj, pos++) {
430 next_obj = obj_ptr->next;
431 if (pos == CmdPtr->pos_after[count]) {
432 count++;
433 sel_ptr->obj = obj_ptr;
434 UnlinkObj(obj_ptr);
435 sel_ptr = sel_ptr->next;
436 if (count == CmdPtr->count_after) break;
437 }
438 }
439 LinkJustTheObjects(CmdPtr->top_after, CmdPtr->bot_after);
440
441 UpdSelBBox();
442 topSel = botSel = NULL;
443 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
444 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
445 SetFileModified(TRUE);
446 justDupped = FALSE;
447 }
448
449 static
RedoNewCmd(CmdPtr)450 void RedoNewCmd(CmdPtr)
451 struct CmdRec *CmdPtr;
452 {
453 struct ObjRec *saved_top_obj, *saved_bot_obj;
454
455 CopySel(CmdPtr->top_after, CmdPtr->count_after, &topSel, &botSel);
456
457 saved_top_obj = topObj;
458 saved_bot_obj = botObj;
459
460 curPage->top = topObj = CmdPtr->top_after->obj;
461 curPage->bot = botObj = CmdPtr->bot_after->obj;
462
463 AdjSplineVs();
464 AdjCaches();
465
466 curPage->top = topObj = saved_top_obj;
467 curPage->bot = botObj = saved_bot_obj;
468
469 if (topObj == NULL) {
470 curPage->bot = botObj = botSel->obj;
471 } else {
472 topObj->prev = botSel->obj;
473 }
474 botSel->obj->next = topObj;
475 curPage->top = topObj = topSel->obj;
476
477 UpdSelBBox();
478 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
479 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
480 if (!deserializingFile) HighLightForward();
481 SetFileModified(TRUE);
482 justDupped = FALSE;
483 }
484
485 static
ObjHasFullID(obj_ptr,psz_full_id)486 int ObjHasFullID(obj_ptr, psz_full_id)
487 struct ObjRec *obj_ptr;
488 char *psz_full_id;
489 {
490 if (*psz_full_id != '#') {
491 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
492 sprintf(gszMsgBox, "%s, psz_full_id = %s, pid = %ld.",
493 "Unexpected *psz_full_id != '#' in ObjHasFullID()",
494 psz_full_id, gstWBInfo.pid);
495 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
496 }
497 }
498 psz_full_id = strchr(psz_full_id, ':');
499 psz_full_id++;
500 if (obj_ptr->creator_full_id == NULL) {
501 char buf[MAXSTRING];
502
503 sprintf(buf, "%1d/%s", obj_ptr->id, gszLocalPID);
504 return (strcmp(buf, psz_full_id) == 0);
505 }
506 return (strcmp(obj_ptr->creator_full_id, psz_full_id) == 0);
507 }
508
509 static
GetPositionFromFullID(psz_full_id)510 int GetPositionFromFullID(psz_full_id)
511 char *psz_full_id;
512 {
513 int pos_to_match=INVALID;
514 char *psz=NULL;
515
516 if (*psz_full_id != '#') {
517 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
518 sprintf(gszMsgBox, "%s, psz_full_id = %s, pid = %ld.",
519 "Unexpected *psz_full_id != '#' in GetPositionFromFullID()",
520 psz_full_id, gstWBInfo.pid);
521 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
522 }
523 }
524 psz = strchr(++psz_full_id, ':');
525 *psz = '\0';
526 if (sscanf(psz_full_id, "%d", &pos_to_match) != 1 ||
527 pos_to_match == INVALID) {
528 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
529 sprintf(gszMsgBox, "%s %s (%s), psz_full_id = %s, pid = %ld.",
530 "Format error in parsing pos_to_match in",
531 "GetPositionFromFullID()", "cannot get pos_to_match",
532 psz_full_id, gstWBInfo.pid);
533 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
534 }
535 }
536 *psz = ':';
537
538 return pos_to_match;
539 }
540
541 static
UndoDeleteCmd(CmdPtr)542 void UndoDeleteCmd(CmdPtr)
543 struct CmdRec *CmdPtr;
544 {
545 struct SelRec *sel_ptr=NULL;
546 struct ObjRec *obj_ptr=NULL, *next_obj=NULL;
547 struct ObjRec *saved_top_obj=NULL, *saved_bot_obj=NULL;
548 int count=0, pos=0, pos_to_match=INVALID;
549
550 CopySel(CmdPtr->top_before, CmdPtr->count_before, &topSel, &botSel);
551
552 saved_top_obj = topObj;
553 saved_bot_obj = botObj;
554
555 LinkJustTheObjects(CmdPtr->top_before, CmdPtr->bot_before);
556
557 curPage->top = topObj = CmdPtr->top_before->obj;
558 curPage->bot = botObj = CmdPtr->bot_before->obj;
559
560 AdjSplineVs();
561 AdjCaches();
562
563 curPage->top = topObj = saved_top_obj;
564 curPage->bot = botObj = saved_bot_obj;
565
566 count = 0;
567 sel_ptr = topSel;
568
569 if (CmdPtr->pos_before_has_ids) {
570 pos_to_match = GetPositionFromFullID(
571 (char*)(long)(CmdPtr->pos_before[count]));
572 } else {
573 pos_to_match = CmdPtr->pos_before[count];
574 }
575 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj, pos++) {
576 if (pos == pos_to_match) {
577 AddObj(obj_ptr->prev, obj_ptr, sel_ptr->obj);
578 next_obj = obj_ptr;
579 count++;
580 sel_ptr = sel_ptr->next;
581 if (count == CmdPtr->count_before) break;
582
583 if (CmdPtr->pos_before_has_ids) {
584 pos_to_match = GetPositionFromFullID(
585 (char*)(long)(CmdPtr->pos_before[count]));
586 } else {
587 pos_to_match = CmdPtr->pos_before[count];
588 }
589 } else {
590 next_obj = obj_ptr->next;
591 }
592 }
593 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
594 AddObj(botObj, NULL, sel_ptr->obj);
595 }
596 UpdSelBBox();
597 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
598 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
599 if (!deserializingFile) HighLightForward();
600 SetFileModified(TRUE);
601 justDupped = FALSE;
602 }
603
604 static
SetupBeforePointers(CmdPtr,modify_before_pointers,pp_actual_pos_before)605 int SetupBeforePointers(CmdPtr, modify_before_pointers, pp_actual_pos_before)
606 struct CmdRec *CmdPtr;
607 int modify_before_pointers, **pp_actual_pos_before;
608 /*
609 * CmdPtr->pos_before is an array of strings containing
610 * "#<pos>:<oid>/<pid>:<hostname>".
611 * CmdPtr->count_before is assumed to be the number of elements in
612 * CmdPtr->pos_before.
613 *
614 * if (modify_before_pointers) {
615 * Setup CmdPtr->top_before and CmdPtr->bot_before.
616 * For these cases, <oid>/<pid>:<hostname> is used to locate the
617 * object positions to build the actual before pointers.
618 * } else {
619 * This can only happen if (CmdPtr->serialized &&
620 * CmdPtr->type == CMD_REPLACE && !CmdPtr->undone)
621 * In this case, the #<pos> should be used to setup up the actual
622 * before pointers.
623 * }
624 * if (pp_actual_pos_before != NULL) {
625 * Create an array of integers containing the positions of the
626 * objects referenced in CmdPtr->pos_before and return this array.
627 * }
628 */
629 {
630 int index, ok=TRUE, cur_pos=0;
631 struct ObjRec *obj_ptr=topObj;
632 struct SelRec *sel_ptr=NULL, *next_sel=NULL, *top_sel=NULL, *bot_sel=NULL;
633
634 if (modify_before_pointers) {
635 for (sel_ptr=CmdPtr->top_before; sel_ptr != NULL; sel_ptr=next_sel) {
636 next_sel = sel_ptr->next;
637 free(sel_ptr);
638 }
639 CmdPtr->top_before = CmdPtr->bot_before = NULL;
640 }
641 if (pp_actual_pos_before != NULL) {
642 *pp_actual_pos_before = (int*)malloc(CmdPtr->count_before*sizeof(int));
643 if (*pp_actual_pos_before == NULL) FailAllocMessage();
644 memset(*pp_actual_pos_before, 0, CmdPtr->count_before*sizeof(int));
645 }
646 for (index=0; index < CmdPtr->count_before; index++) {
647 char *psz_full_id=(((char**)CmdPtr->pos_before)[index]), *psz=NULL;
648 char pid_and_host[MAXSTRING];
649 int id=(-1), found=FALSE, pos_to_match=INVALID, obj_is_tgifobj=FALSE;
650
651 if (*psz_full_id == '#') {
652 psz = strchr(++psz_full_id, ':');
653 *psz = '\0';
654 if (!modify_before_pointers) {
655 if (sscanf(psz_full_id, "%d", &pos_to_match) != 1 ||
656 pos_to_match == INVALID) {
657 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
658 sprintf(gszMsgBox, "%s %s (%s), psz_full_id = %s, pid = %ld.",
659 "Format error in parsing pos_to_match in",
660 "SetupBeforePointers()", "cannot get pos_to_match",
661 psz_full_id, gstWBInfo.pid);
662 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
663 }
664 }
665 }
666 *psz++ = ':';
667 psz_full_id = psz;
668 }
669 psz = strchr(psz_full_id, '/');
670 *pid_and_host = '\0';
671 if (psz == NULL) {
672 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
673 sprintf(gszMsgBox, "%s (%s), psz_full_id = %s, pid = %ld.",
674 "Format error in parsing id in SetupBeforePointers()",
675 "cannot find ':'", psz_full_id, gstWBInfo.pid);
676 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
677 }
678 ok = FALSE;
679 break;
680 } else {
681 *psz = '\0';
682 if (sscanf(psz_full_id, "%d", &id) == 1) {
683 strcpy(pid_and_host, &psz[1]);
684 if (id == INVALID) {
685 obj_is_tgifobj = TRUE;
686 }
687 } else {
688 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
689 sprintf(gszMsgBox, "%s (%s), psz_full_id = %s, pid = %ld.",
690 "Format error in parsing id in SetupBeforePointers()",
691 "cannot find id", psz_full_id, gstWBInfo.pid);
692 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
693 }
694 ok = FALSE;
695 break;
696 }
697 *psz = '/';
698 }
699 if (ok) {
700 for (obj_ptr=topObj, cur_pos=0 ; ok && obj_ptr != NULL;
701 obj_ptr=obj_ptr->next, cur_pos++) {
702 if (pos_to_match == INVALID) {
703 if (obj_ptr->creator_full_id == NULL) {
704 if (obj_ptr->id == id &&
705 strcmp(pid_and_host, gszLocalPID) == 0) {
706 found = TRUE;
707 } else if (obj_ptr->id == INVALID &&
708 CmdPtr->include_tgif_obj && obj_is_tgifobj) {
709 found = TRUE;
710 }
711 } else {
712 if (strcmp(obj_ptr->creator_full_id, psz_full_id) == 0) {
713 found = TRUE;
714 }
715 }
716 } else if (pos_to_match == cur_pos) {
717 found = TRUE;
718 }
719 if (found) {
720 if (modify_before_pointers) {
721 AddObjIntoSel(obj_ptr, bot_sel, NULL, &top_sel, &bot_sel);
722 }
723 if (pp_actual_pos_before != NULL) {
724 (*pp_actual_pos_before)[index] = cur_pos;
725 }
726 obj_ptr = obj_ptr->next;
727 cur_pos++;
728 break;
729 }
730 }
731 }
732 if (ok && !found) {
733 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
734 #ifdef _TGIF_DBG_WB2 /* debug, do not translate */
735 fprintf(stderr, "%s: '%s' %s, pid = %ld.\n\t(%s=%1d, %s='%s')\n",
736 "@*@ Cannot find object id", psz_full_id,
737 "in SetupBeforePointers()", gstWBInfo.pid, "id", id,
738 "pid_and_host", pid_and_host);
739 #endif /* _TGIF_DBG_WB2 */
740 }
741 ok = FALSE;
742 break;
743 }
744 }
745 if (ok && index != CmdPtr->count_before) {
746 if (gstWBInfo.do_whiteboard) { /* debug, do not translate */
747 sprintf(gszMsgBox, "%s (%1d) %s (%1d) %s, pid = %ld.",
748 "Index", index, "!= CmdPtr->count_before", CmdPtr->count_before,
749 "in SetupBeforePointers()", gstWBInfo.pid);
750 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
751 }
752 ok = FALSE;
753 }
754 if (!ok) {
755 for (sel_ptr=top_sel; sel_ptr != NULL; sel_ptr=next_sel) {
756 next_sel = sel_ptr->next;
757 free(sel_ptr);
758 }
759 if (pp_actual_pos_before != NULL) {
760 free(*pp_actual_pos_before);
761 *pp_actual_pos_before = NULL;
762 }
763 } else {
764 if (modify_before_pointers) {
765 CmdPtr->top_before = top_sel;
766 CmdPtr->bot_before = bot_sel;
767 }
768 }
769 return ok;
770 }
771
772 static
RedoDeleteCmd(CmdPtr)773 int RedoDeleteCmd(CmdPtr)
774 struct CmdRec *CmdPtr;
775 {
776 struct SelRec *sel_ptr;
777
778 if (CmdPtr->serialized) {
779 if (CmdPtr->include_tgif_obj) {
780 AddObj(NULL, topObj, tgifObj);
781 }
782 if (!SetupBeforePointers(CmdPtr, TRUE, NULL)) {
783 if (CmdPtr->include_tgif_obj) {
784 UnlinkObj(topObj);
785 }
786 return FALSE;
787 }
788 if (CmdPtr->include_tgif_obj) {
789 UnlinkObj(topObj);
790 }
791 }
792 topSel = CmdPtr->top_before;
793 botSel = CmdPtr->bot_before;
794
795 sel_ptr = topSel;
796 if (CmdPtr->serialized) {
797 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
798 UnlinkObj(sel_ptr->obj);
799 }
800 } else {
801 struct ObjRec *obj_ptr=NULL, *next_obj=NULL;
802 int count=0;
803
804 if (CmdPtr->pos_before_has_ids) {
805 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj) {
806 next_obj = obj_ptr->next;
807 if (ObjHasFullID(obj_ptr,
808 (char*)(long)(CmdPtr->pos_before[count]))) {
809 count++;
810 sel_ptr->obj = obj_ptr;
811 UnlinkObj(obj_ptr);
812 sel_ptr = sel_ptr->next;
813 if (count == CmdPtr->count_before) break;
814 }
815 }
816 } else {
817 int pos=0;
818
819 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj, pos++) {
820 next_obj = obj_ptr->next;
821 if (pos == CmdPtr->pos_before[count]) {
822 count++;
823 sel_ptr->obj = obj_ptr;
824 UnlinkObj(obj_ptr);
825 sel_ptr = sel_ptr->next;
826 if (count == CmdPtr->count_before) break;
827 }
828 }
829 }
830 }
831 LinkJustTheObjects(CmdPtr->top_before, CmdPtr->bot_before);
832
833 UpdSelBBox();
834 topSel = botSel = NULL;
835 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
836 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
837 SetFileModified(TRUE);
838 justDupped = FALSE;
839 return TRUE;
840 }
841
842 static
UndoOrRedoMoveCmd(CmdPtr)843 int UndoOrRedoMoveCmd(CmdPtr)
844 struct CmdRec *CmdPtr;
845 {
846 struct SelRec *sel_ptr;
847 struct ObjRec *obj_ptr;
848 int dx, dy;
849
850 if (CmdPtr->serialized) {
851 if (CmdPtr->include_tgif_obj) {
852 AddObj(NULL, topObj, tgifObj);
853 }
854 if (!SetupBeforePointers(CmdPtr, TRUE, NULL)) {
855 if (CmdPtr->include_tgif_obj) {
856 UnlinkObj(topObj);
857 }
858 return FALSE;
859 }
860 if (CmdPtr->include_tgif_obj) {
861 UnlinkObj(topObj);
862 }
863 }
864 dx = (CmdPtr->undone) ? CmdPtr->subcmd->detail.move.dx :
865 -(CmdPtr->subcmd->detail.move.dx);
866 dy = (CmdPtr->undone) ? CmdPtr->subcmd->detail.move.dy :
867 -(CmdPtr->subcmd->detail.move.dy);
868
869 CopySel(CmdPtr->top_before, CmdPtr->count_before, &topSel, &botSel);
870
871 sel_ptr = topSel;
872 if (CmdPtr->serialized) {
873 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
874 obj_ptr = sel_ptr->obj;
875 if (!obj_ptr->locked) MoveObj(obj_ptr, dx, dy);
876 }
877 } else {
878 struct ObjRec *next_obj;
879 int count=0;
880
881 if (CmdPtr->pos_before_has_ids) {
882 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj) {
883 next_obj = obj_ptr->next;
884 if (ObjHasFullID(obj_ptr,
885 (char*)(long)(CmdPtr->pos_before[count]))) {
886 count++;
887 sel_ptr->obj = obj_ptr;
888 if (!obj_ptr->locked) MoveObj(obj_ptr, dx, dy);
889 sel_ptr = sel_ptr->next;
890 if (count == CmdPtr->count_before) break;
891 }
892 }
893 } else {
894 int pos=0;
895
896 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=next_obj, pos++) {
897 next_obj = obj_ptr->next;
898 if (pos == CmdPtr->pos_before[count]) {
899 count++;
900 sel_ptr->obj = obj_ptr;
901 if (!obj_ptr->locked) MoveObj(obj_ptr, dx, dy);
902 sel_ptr = sel_ptr->next;
903 if (count == CmdPtr->count_before) break;
904 }
905 }
906 }
907 }
908 UpdSelBBox();
909 RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1)-dx, selLtY-GRID_ABS_SIZE(1)-dy,
910 selRbX+GRID_ABS_SIZE(1)-dx, selRbY+GRID_ABS_SIZE(1)-dy,
911 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
912 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
913 if (!deserializingFile) HighLightForward();
914 SetFileModified(TRUE);
915 justDupped = FALSE;
916 return TRUE;
917 }
918
919 static
UpdateXPmObjectsInACmd(CmdPtr)920 void UpdateXPmObjectsInACmd(CmdPtr)
921 struct CmdRec *CmdPtr;
922 {
923 struct CmdRec *cmd_ptr;
924 struct SelRec *sel_ptr;
925
926 switch (CmdPtr->type) {
927 case CMD_COMPOSITE:
928 for (cmd_ptr=CmdPtr->first; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->next) {
929 UpdateXPmObjectsInACmd(cmd_ptr);
930 }
931 break;
932 case CMD_NEW:
933 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
934 UpdateXPmObjects(sel_ptr->obj);
935 }
936 break;
937 case CMD_DELETE: break;
938 case CMD_MOVE: break;
939 case CMD_STRETCH: break;
940 case CMD_REPLACE:
941 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
942 UpdateXPmObjects(sel_ptr->obj);
943 }
944 break;
945 case CMD_ONE_TO_MANY: break;
946 case CMD_MANY_TO_ONE:
947 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
948 UpdateXPmObjects(sel_ptr->obj);
949 }
950 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
951 UpdateXPmObjects(sel_ptr->obj);
952 }
953 break;
954 case CMD_GOTO_PAGE: break;
955 }
956 }
957
958 static
UpdatePixelInACmd(CmdPtr)959 int UpdatePixelInACmd(CmdPtr)
960 struct CmdRec *CmdPtr;
961 {
962 struct CmdRec *cmd_ptr;
963 struct SelRec *sel_ptr;
964 int changed=FALSE;
965
966 switch (CmdPtr->type) {
967 case CMD_COMPOSITE:
968 for (cmd_ptr=CmdPtr->first; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->next) {
969 if (UpdatePixelInACmd(cmd_ptr)) {
970 changed = TRUE;
971 }
972 }
973 break;
974 case CMD_NEW:
975 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
976 if (UpdatePixel(sel_ptr->obj)) {
977 changed = TRUE;
978 }
979 }
980 break;
981 case CMD_DELETE: break;
982 case CMD_MOVE: break;
983 case CMD_STRETCH: break;
984 case CMD_REPLACE:
985 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
986 if (UpdatePixel(sel_ptr->obj)) {
987 changed = TRUE;
988 }
989 }
990 break;
991 case CMD_ONE_TO_MANY: break;
992 case CMD_MANY_TO_ONE:
993 for (sel_ptr=CmdPtr->top_before; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
994 if (UpdatePixel(sel_ptr->obj)) {
995 changed = TRUE;
996 }
997 }
998 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
999 if (UpdatePixel(sel_ptr->obj)) {
1000 changed = TRUE;
1001 }
1002 }
1003 break;
1004 case CMD_GOTO_PAGE: break;
1005 }
1006 return changed;
1007 }
1008
1009 static
RefreshColormap(nRedoing,CmdPtr)1010 int RefreshColormap(nRedoing, CmdPtr)
1011 int nRedoing;
1012 struct CmdRec *CmdPtr;
1013 /*
1014 * This function mimics FlushColormap() in color.c.
1015 */
1016 {
1017 int changed=FALSE, saved_color_layers;
1018 struct ObjRec *obj_ptr=NULL;
1019 struct PageRec *page_ptr=NULL;
1020 Colormap colormap=XCopyColormapAndFree(mainDisplay, mainColormap);
1021
1022 mainColormap = colormap;
1023 newColormapUsed = TRUE;
1024 XSetWindowColormap(mainDisplay, mainWindow, mainColormap);
1025
1026 if (nRedoing) {
1027 /* need to scan forward to pick up objects */
1028 struct CmdRec *cmd_ptr;
1029
1030 for (page_ptr=firstPage; page_ptr != NULL; page_ptr=page_ptr->next) {
1031 for (obj_ptr=page_ptr->bot; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) {
1032 UpdateXPmObjects(obj_ptr);
1033 }
1034 }
1035 for (cmd_ptr=CmdPtr->next; cmd_ptr != NULL; cmd_ptr=cmd_ptr->next) {
1036 UpdateXPmObjectsInACmd(cmd_ptr);
1037 }
1038 } else {
1039 for (page_ptr=firstPage; page_ptr != NULL; page_ptr=page_ptr->next) {
1040 for (obj_ptr=page_ptr->bot; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) {
1041 UpdateXPmObjects(obj_ptr);
1042 }
1043 }
1044 }
1045 initColorDontReload = TRUE;
1046 CleanUpColors();
1047 XFreeColormap(mainDisplay, mainColormap);
1048 mainColormap = DefaultColormap(mainDisplay, mainScreen);
1049 XSetWindowColormap(mainDisplay, mainWindow, mainColormap);
1050 newColormapUsed = FALSE;
1051 saved_color_layers = colorLayers;
1052 InitColor();
1053 initColorDontReload = FALSE;
1054 colorLayers = saved_color_layers;
1055
1056 ShowColor(TRUE);
1057
1058 SaveStatusStrings();
1059 gnUpdatePixelObjCount = 0;
1060 if (nRedoing) {
1061 /* need to scan forward to pick up objects */
1062 struct CmdRec *cmd_ptr;
1063
1064 for (page_ptr=firstPage; page_ptr != NULL; page_ptr=page_ptr->next) {
1065 for (obj_ptr=page_ptr->bot; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) {
1066 if (UpdatePixel(obj_ptr)) {
1067 changed = TRUE;
1068 }
1069 }
1070 }
1071 for (cmd_ptr=CmdPtr->next; cmd_ptr != NULL; cmd_ptr=cmd_ptr->next) {
1072 if (UpdatePixelInACmd(cmd_ptr)) {
1073 changed = TRUE;
1074 }
1075 }
1076 } else {
1077 for (page_ptr=firstPage; page_ptr != NULL; page_ptr=page_ptr->next) {
1078 for (obj_ptr=page_ptr->bot; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) {
1079 if (UpdatePixel(obj_ptr)) {
1080 changed = TRUE;
1081 }
1082 }
1083 }
1084 }
1085 RestoreStatusStrings();
1086
1087 DestroyPinnedMenu(MENU_COLOR);
1088 if (colorLayers) {
1089 RedrawColorWindow();
1090 }
1091 return changed;
1092 }
1093
1094 static
UndoOrRedoReplaceCmd(CmdPtr,HighLightSingleObj)1095 int UndoOrRedoReplaceCmd(CmdPtr, HighLightSingleObj)
1096 struct CmdRec *CmdPtr;
1097 int HighLightSingleObj;
1098 {
1099 struct ObjRec *obj_ptr=NULL, *next_obj=NULL;
1100 struct SelRec *sel_ptr=NULL;
1101 struct SelRec *saved_top_sel=NULL, *saved_bot_sel=NULL;
1102 struct ObjRec *saved_top_obj=NULL, *saved_bot_obj=NULL;
1103 int ltx, lty, rbx, rby, pos, count, *pos_table, max_count;
1104 int need_clear_and_redraw=FALSE;
1105 int *actual_pos_before=NULL;
1106
1107 #ifdef _TGIF_DBG_WB2 /* debug, do not translate */
1108 if (gstWBInfo.do_whiteboard) {
1109 fprintf(stderr, "@@@ Beginning of UndoOrRedoReplaceCmd()...\n");
1110 fprintf(stderr, "\tCmdPtr->serialized=%1d...\n", CmdPtr->serialized);
1111 }
1112 #endif /* _TGIF_DBG_WB2 */
1113 if (CmdPtr->serialized) {
1114 int shuffle=FALSE;
1115
1116 if (CmdPtr->first_redo_after_deserialize && CmdPtr->undone) {
1117 CmdPtr->first_redo_after_deserialize = FALSE;
1118 shuffle = TRUE;
1119 }
1120 #ifdef _TGIF_DBG_WB2 /* debug, do not translate */
1121 if (gstWBInfo.do_whiteboard) {
1122 fprintf(stderr, "In UndoOrRedoReplaceCmd(), shuffle=%1d.\n", shuffle);
1123 }
1124 #endif /* _TGIF_DBG_WB2 */
1125 if (CmdPtr->include_tgif_obj) {
1126 AddObj(NULL, topObj, tgifObj);
1127 }
1128 if (shuffle) {
1129 if (!SetupBeforePointers(CmdPtr, TRUE, NULL)) {
1130 if (CmdPtr->include_tgif_obj) {
1131 UnlinkObj(topObj);
1132 }
1133 return FALSE;
1134 }
1135 topSel = CmdPtr->top_before;
1136 botSel = CmdPtr->bot_before;
1137 CmdPtr->top_before = CmdPtr->top_after;
1138 CmdPtr->bot_before = CmdPtr->bot_after;
1139 CmdPtr->top_after = topSel;
1140 CmdPtr->bot_after = botSel;
1141 topSel = botSel = NULL;
1142 } else {
1143 if (CmdPtr->undone) {
1144 struct SelRec *next_sel=NULL;
1145
1146 for (sel_ptr=CmdPtr->top_after; sel_ptr != NULL;
1147 sel_ptr=next_sel) {
1148 next_sel = sel_ptr->next;
1149 free(sel_ptr);
1150 }
1151 CmdPtr->top_after = CmdPtr->bot_after = NULL;
1152
1153 saved_top_sel = CmdPtr->top_before;
1154 saved_bot_sel = CmdPtr->bot_before;
1155 CmdPtr->top_before = CmdPtr->bot_before = NULL;
1156 if (!SetupBeforePointers(CmdPtr, TRUE, NULL)) {
1157 if (CmdPtr->include_tgif_obj) {
1158 UnlinkObj(topObj);
1159 }
1160 return FALSE;
1161 }
1162 CmdPtr->top_after = CmdPtr->top_before;
1163 CmdPtr->bot_after = CmdPtr->bot_before;
1164 CmdPtr->top_before = saved_top_sel;
1165 CmdPtr->bot_before = saved_bot_sel;
1166 } else {
1167 if (!SetupBeforePointers(CmdPtr, FALSE, &actual_pos_before)) {
1168 if (CmdPtr->include_tgif_obj) {
1169 UnlinkObj(topObj);
1170 }
1171 return FALSE;
1172 }
1173 }
1174 }
1175 if (CmdPtr->include_tgif_obj) {
1176 UnlinkObj(topObj);
1177 }
1178 }
1179 LinkJustTheObjects(CmdPtr->top_before, CmdPtr->bot_before);
1180
1181 CopySel(CmdPtr->top_before, CmdPtr->count_before, &topSel, &botSel);
1182
1183 if (CmdPtr->include_tgif_obj) {
1184 AddObj(NULL, topObj, tgifObj);
1185 }
1186 pos_table = (CmdPtr->undone) ? CmdPtr->pos_before : CmdPtr->pos_after;
1187 max_count = (CmdPtr->undone) ? CmdPtr->count_before : CmdPtr->count_after;
1188
1189 sel_ptr = topSel;
1190 if (CmdPtr->serialized && CmdPtr->undone) {
1191 struct SelRec *sel_ptr1;
1192
1193 for (sel_ptr1=CmdPtr->top_after; sel_ptr1 != NULL;
1194 sel_ptr1=sel_ptr1->next) {
1195 sel_ptr->obj = sel_ptr1->obj;
1196 UnlinkObj(sel_ptr1->obj);
1197 sel_ptr = sel_ptr->next;
1198 }
1199 } else {
1200 if (CmdPtr->serialized && !CmdPtr->undone) {
1201 pos_table = actual_pos_before;
1202 }
1203 pos = count = 0;
1204 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=next_obj, pos++) {
1205 next_obj = obj_ptr->next;
1206 if (pos == pos_table[count]) {
1207 count++;
1208 sel_ptr->obj = obj_ptr;
1209 UnlinkObj(obj_ptr);
1210 sel_ptr = sel_ptr->next;
1211 if (count == max_count) break;
1212 }
1213 }
1214 }
1215 UpdSelBBox();
1216 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
1217
1218 saved_top_sel = topSel;
1219 saved_bot_sel = botSel;
1220 topSel = CmdPtr->top_before;
1221 botSel = CmdPtr->bot_before;
1222 CmdPtr->top_before = saved_top_sel;
1223 CmdPtr->bot_before = saved_bot_sel;
1224
1225 saved_top_obj = topObj;
1226 saved_bot_obj = botObj;
1227
1228 curPage->top = topObj = topSel->obj;
1229 curPage->bot = botObj = botSel->obj;
1230
1231 AdjSplineVs();
1232 AdjCaches();
1233
1234 curPage->top = topObj = saved_top_obj;
1235 curPage->bot = botObj = saved_bot_obj;
1236
1237 pos_table = (CmdPtr->undone) ? CmdPtr->pos_after : CmdPtr->pos_before;
1238 max_count = (CmdPtr->undone) ? CmdPtr->count_after : CmdPtr->count_before;
1239
1240 pos = count = 0;
1241 sel_ptr = topSel;
1242 if (CmdPtr->serialized && !CmdPtr->undone) {
1243 pos_table = actual_pos_before;
1244 }
1245 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=next_obj, pos++) {
1246 if (pos == pos_table[count]) {
1247 AddObj(obj_ptr->prev, obj_ptr, sel_ptr->obj);
1248 next_obj = obj_ptr;
1249 count++;
1250 sel_ptr = sel_ptr->next;
1251 if (count == max_count) break;
1252 } else {
1253 next_obj = obj_ptr->next;
1254 }
1255 }
1256 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1257 AddObj(botObj, NULL, sel_ptr->obj);
1258 }
1259 if (CmdPtr->include_tgif_obj) {
1260 tgifObj = topObj;
1261 UnlinkObj(topObj);
1262
1263 sel_ptr = topSel;
1264 topSel = topSel->next;
1265 if (topSel == NULL) {
1266 botSel = NULL;
1267 } else {
1268 topSel->prev = NULL;
1269 }
1270 free(sel_ptr);
1271 }
1272 if (CmdPtr->new_colormap) {
1273 if (RefreshColormap(CmdPtr->undone, CmdPtr)) {
1274 need_clear_and_redraw = TRUE;
1275 }
1276 }
1277 UpdSelBBox();
1278 if (need_clear_and_redraw) {
1279 ClearAndRedrawDrawWindow();
1280 } else {
1281 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1282 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1283 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1284 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1285 }
1286 if (HighLightSingleObj && topSel != NULL) {
1287 if (!need_clear_and_redraw) {
1288 if (!deserializingFile) HighLightForward();
1289 }
1290 } else {
1291 RemoveAllSel();
1292 }
1293 SetFileModified(TRUE);
1294 justDupped = FALSE;
1295
1296 if (actual_pos_before != NULL) free(actual_pos_before);
1297
1298 return TRUE;
1299 }
1300
1301 static
UndoOrRedoOneToManyCmd(CmdPtr)1302 int UndoOrRedoOneToManyCmd(CmdPtr)
1303 struct CmdRec *CmdPtr;
1304 {
1305 struct ObjRec *obj_ptr, *next_obj;
1306 struct SelRec *sel_ptr;
1307 struct ObjRec *saved_top_obj, *saved_bot_obj;
1308 int ltx, lty, rbx, rby, pos, count, *pos_table, max_count;
1309 int need_clear_and_redraw=FALSE;
1310 int *actual_pos_before=NULL;
1311
1312 if (CmdPtr->serialized) {
1313 if (CmdPtr->include_tgif_obj) {
1314 AddObj(NULL, topObj, tgifObj);
1315 }
1316 if (CmdPtr->undone) {
1317 if (!SetupBeforePointers(CmdPtr, TRUE, &actual_pos_before)) {
1318 if (CmdPtr->include_tgif_obj) {
1319 UnlinkObj(topObj);
1320 }
1321 return FALSE;
1322 }
1323 }
1324 if (CmdPtr->include_tgif_obj) {
1325 UnlinkObj(topObj);
1326 }
1327 }
1328 if (CmdPtr->include_tgif_obj) {
1329 AddObj(NULL, topObj, tgifObj);
1330 AddNewSelObj(topObj);
1331 }
1332
1333 sel_ptr = (CmdPtr->undone) ? CmdPtr->top_before : CmdPtr->top_after;
1334 if (CmdPtr->serialized && CmdPtr->undone) {
1335 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1336 UnlinkObj(sel_ptr->obj);
1337 }
1338 } else {
1339 pos_table = (CmdPtr->undone) ? CmdPtr->pos_before : CmdPtr->pos_after;
1340 max_count = (CmdPtr->undone) ? CmdPtr->count_before : CmdPtr->count_after;
1341
1342 if (CmdPtr->serialized && CmdPtr->undone) {
1343 pos_table = actual_pos_before;
1344 }
1345 pos = count = 0;
1346 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=next_obj, pos++) {
1347 next_obj = obj_ptr->next;
1348 if (pos == pos_table[count]) {
1349 count++;
1350 sel_ptr->obj = obj_ptr;
1351 UnlinkObj(obj_ptr);
1352 sel_ptr = sel_ptr->next;
1353 if (count == max_count) break;
1354 }
1355 }
1356 }
1357 topSel = (CmdPtr->undone) ? CmdPtr->top_before : CmdPtr->top_after;
1358 botSel = (CmdPtr->undone) ? CmdPtr->bot_before : CmdPtr->bot_after;
1359 UpdSelBBox();
1360 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
1361
1362 if (CmdPtr->undone) {
1363 CopySel(CmdPtr->top_after, CmdPtr->count_after, &topSel, &botSel);
1364 } else {
1365 CopySel(CmdPtr->top_before, CmdPtr->count_before, &topSel, &botSel);
1366 }
1367 LinkJustTheObjects(topSel, botSel);
1368
1369 saved_top_obj = topObj;
1370 saved_bot_obj = botObj;
1371
1372 curPage->top = topObj = topSel->obj;
1373 curPage->bot = botObj = botSel->obj;
1374
1375 AdjSplineVs();
1376 AdjCaches();
1377
1378 curPage->top = topObj = saved_top_obj;
1379 curPage->bot = botObj = saved_bot_obj;
1380
1381 pos_table = (CmdPtr->undone) ? CmdPtr->pos_after : CmdPtr->pos_before;
1382 max_count = (CmdPtr->undone) ? CmdPtr->count_after : CmdPtr->count_before;
1383
1384 pos = count = 0;
1385 sel_ptr = topSel;
1386 if (CmdPtr->serialized && CmdPtr->undone) {
1387 pos_table = actual_pos_before;
1388 }
1389 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=next_obj, pos++) {
1390 if (pos == pos_table[count]) {
1391 AddObj(obj_ptr->prev, obj_ptr, sel_ptr->obj);
1392 next_obj = obj_ptr;
1393 count++;
1394 sel_ptr = sel_ptr->next;
1395 if (count == max_count) break;
1396 } else {
1397 next_obj = obj_ptr->next;
1398 }
1399 }
1400 for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1401 AddObj(botObj, NULL, sel_ptr->obj);
1402 }
1403 if (CmdPtr->include_tgif_obj) {
1404 tgifObj = topObj;
1405 UnlinkObj(topObj);
1406
1407 sel_ptr = topSel;
1408 topSel = topSel->next;
1409 if (topSel == NULL) {
1410 botSel = NULL;
1411 } else {
1412 topSel->prev = NULL;
1413 }
1414 free(sel_ptr);
1415 }
1416 if (CmdPtr->new_colormap) {
1417 if (RefreshColormap(CmdPtr->undone, CmdPtr)) {
1418 need_clear_and_redraw = TRUE;
1419 }
1420 }
1421 UpdSelBBox();
1422 if (need_clear_and_redraw) {
1423 ClearAndRedrawDrawWindow();
1424 } else {
1425 RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1426 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1),
1427 ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1428 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
1429 }
1430 if (!need_clear_and_redraw) {
1431 if (!deserializingFile) HighLightForward();
1432 }
1433 SetFileModified(TRUE);
1434 justDupped = FALSE;
1435
1436 if (actual_pos_before != NULL) free(actual_pos_before);
1437
1438 return TRUE;
1439 }
1440
1441 static
UndoOrRedoGotoPageCmd(CmdPtr)1442 void UndoOrRedoGotoPageCmd(CmdPtr)
1443 struct CmdRec *CmdPtr;
1444 {
1445 int new_page_num;
1446
1447 new_page_num = (CmdPtr->undone) ? CmdPtr->count_after : CmdPtr->count_before;
1448
1449 GotoPageNum(new_page_num);
1450 ClearAndRedrawDrawWindow();
1451 ShowPage();
1452 }
1453
1454 static
UndoOrRedoWBSlideShow(CmdPtr)1455 void UndoOrRedoWBSlideShow(CmdPtr)
1456 struct CmdRec *CmdPtr;
1457 {
1458 int into_slideshow=CmdPtr->subcmd->detail.slideshow.into_slideshow;
1459
1460 if (CmdPtr->undone) {
1461 /* executing the command */
1462 if (!inSlideShow && into_slideshow) {
1463 EnterSlideShow();
1464 } else if (inSlideShow && !into_slideshow) {
1465 LeaveSlideShow();
1466 }
1467 }
1468 }
1469
1470 typedef struct tagUndoRedoRestoreDrawingModeRec {
1471 int cur_choice;
1472 int text_cursor_shown;
1473 int editing_text;
1474 int cur_text_modified;
1475 int text_orig_x;
1476 int text_orig_baseline_y;
1477 } UndoRedoRestoreDrawingModeInfo;
1478
1479 static
SetUndoRedoRestoreDrawingModeInfo(p_urrdmi,cur_choice,text_cursor_shown,editing_text,cur_text_modified,text_orig_x,text_orig_baseline_y)1480 void SetUndoRedoRestoreDrawingModeInfo(p_urrdmi, cur_choice, text_cursor_shown,
1481 editing_text, cur_text_modified, text_orig_x, text_orig_baseline_y)
1482 UndoRedoRestoreDrawingModeInfo *p_urrdmi;
1483 int cur_choice, text_cursor_shown, editing_text, cur_text_modified;
1484 int text_orig_x, text_orig_baseline_y;
1485 {
1486 p_urrdmi->cur_choice = cur_choice;
1487 p_urrdmi->text_cursor_shown = text_cursor_shown;
1488 p_urrdmi->editing_text = editing_text;
1489 p_urrdmi->cur_text_modified = cur_text_modified;
1490 p_urrdmi->text_orig_x = text_orig_x;
1491 p_urrdmi->text_orig_baseline_y = text_orig_baseline_y;
1492 }
1493
1494 static
UndoRedoRestoreDrawingMode(p_urrdmi)1495 void UndoRedoRestoreDrawingMode(p_urrdmi)
1496 UndoRedoRestoreDrawingModeInfo *p_urrdmi;
1497 {
1498 if (inHyperSpace || !undoRedoRestoreDrawingMode) return;
1499
1500 switch (p_urrdmi->cur_choice) {
1501 case NOTHING: break;
1502 case DRAWTEXT:
1503 if (p_urrdmi->text_cursor_shown) {
1504 if (!p_urrdmi->cur_text_modified) {
1505 /* just leave things in text mode */
1506 SetCurChoice(p_urrdmi->cur_choice);
1507 } else if (p_urrdmi->editing_text) {
1508 /*
1509 * editing text should be undone, but the cursor should be
1510 * placed back to where it starts (in p_urrdmi->cur_text_obj)
1511 */
1512 SetCurChoice(p_urrdmi->cur_choice);
1513 } else {
1514 /*
1515 * creating a new text object
1516 * should just put the cursor where it starts
1517 * (but this may be difficult)
1518 */
1519 XEvent ev;
1520
1521 memset(&ev, 0, sizeof(XEvent));
1522 ev.type = ButtonPress;
1523 ev.xbutton.button = Button1;
1524 ev.xbutton.state = 0;
1525 ev.xbutton.x = p_urrdmi->text_orig_x;
1526 ev.xbutton.y = p_urrdmi->text_orig_baseline_y;
1527
1528 SetCurChoice(p_urrdmi->cur_choice);
1529 DrawText(&ev);
1530 }
1531 } else {
1532 SetCurChoice(p_urrdmi->cur_choice);
1533 }
1534 break;
1535 default: SetCurChoice(p_urrdmi->cur_choice); break;
1536 }
1537 }
1538
UndoACmd(CmdPtr,HighLight,nPerformAction)1539 void UndoACmd(CmdPtr, HighLight, nPerformAction)
1540 struct CmdRec *CmdPtr;
1541 int HighLight, nPerformAction;
1542 {
1543 struct CmdRec *cmd_ptr;
1544
1545 if (topSel != NULL) { HighLightReverse(); RemoveAllSel(); }
1546
1547 switch (CmdPtr->type) {
1548 case CMD_COMPOSITE:
1549 if (CmdPtr->first->type==CMD_MOVE || CmdPtr->first->type==CMD_STRETCH) {
1550 for (cmd_ptr=CmdPtr->last; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->prev) {
1551 UndoACmd(cmd_ptr, FALSE, nPerformAction);
1552 }
1553 } else {
1554 for (cmd_ptr=CmdPtr->last; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->prev) {
1555 UndoACmd(cmd_ptr, TRUE, nPerformAction);
1556 }
1557 }
1558 break;
1559 case CMD_NEW: UndoNewCmd(CmdPtr); break;
1560 case CMD_DELETE: UndoDeleteCmd(CmdPtr); break;
1561 case CMD_MOVE: UndoOrRedoMoveCmd(CmdPtr); break;
1562 case CMD_STRETCH: UndoOrRedoReplaceCmd(CmdPtr, TRUE); break;
1563 case CMD_REPLACE: UndoOrRedoReplaceCmd(CmdPtr, HighLight); break;
1564 case CMD_ONE_TO_MANY: UndoOrRedoOneToManyCmd(CmdPtr); break;
1565 case CMD_MANY_TO_ONE: UndoOrRedoOneToManyCmd(CmdPtr); break;
1566 case CMD_GOTO_PAGE: UndoOrRedoGotoPageCmd(CmdPtr); break;
1567 }
1568 CmdPtr->undone = TRUE;
1569 }
1570
UndoCmd()1571 void UndoCmd()
1572 {
1573 UndoRedoRestoreDrawingModeInfo urrdmi;
1574
1575 if (gstWBInfo.do_whiteboard) {
1576 MsgBox(TgLoadString(STID_UNDO_IN_WB), TOOL_NAME, INFO_MB);
1577 return;
1578 }
1579 SetUndoRedoRestoreDrawingModeInfo(&urrdmi, curChoice, textCursorShown,
1580 editingText, curTextModified, textOrigX, textOrigBaselineY);
1581
1582 TieLooseEnds();
1583 SetCurChoice(NOTHING);
1584 if (curCmd == NULL) {
1585 if (!inHyperSpace && undoRedoRestoreDrawingMode) {
1586 SetCurChoice(urrdmi.cur_choice);
1587 }
1588 MsgBox(TgLoadString(STID_NO_COMMANDS_TO_UNDO), TOOL_NAME, INFO_MB);
1589 return;
1590 }
1591 undoingOrRedoing = TRUE;
1592 UndoACmd(curCmd, TRUE, TRUE);
1593 curCmd = curCmd->prev;
1594 undoingOrRedoing = FALSE;
1595
1596 UndoRedoRestoreDrawingMode(&urrdmi);
1597 }
1598
RedoACmd(CmdPtr,HighLight,nPerformAction)1599 int RedoACmd(CmdPtr, HighLight, nPerformAction)
1600 struct CmdRec *CmdPtr;
1601 int HighLight, nPerformAction;
1602 {
1603 int ok=TRUE;
1604 struct CmdRec *cmd_ptr;
1605
1606 if (topSel != NULL) { HighLightReverse(); RemoveAllSel(); }
1607
1608 switch (CmdPtr->type) {
1609 case CMD_COMPOSITE:
1610 if (CmdPtr->first->type==CMD_MOVE || CmdPtr->first->type==CMD_STRETCH) {
1611 for (cmd_ptr=CmdPtr->first->next; cmd_ptr!=NULL;
1612 cmd_ptr=cmd_ptr->next) {
1613 if (!RedoACmd(cmd_ptr, FALSE, nPerformAction)) {
1614 ok = FALSE;
1615 break;
1616 }
1617 }
1618 if (ok) {
1619 if (!RedoACmd(CmdPtr->first, TRUE, nPerformAction)) {
1620 ok = FALSE;
1621 }
1622 }
1623 } else {
1624 for (cmd_ptr=CmdPtr->first; cmd_ptr!=NULL; cmd_ptr=cmd_ptr->next) {
1625 if (!RedoACmd(cmd_ptr, TRUE, nPerformAction)) {
1626 ok = FALSE;
1627 break;
1628 }
1629 }
1630 }
1631 break;
1632 case CMD_NEW: RedoNewCmd(CmdPtr); break;
1633 case CMD_DELETE: ok = RedoDeleteCmd(CmdPtr); break;
1634 case CMD_MOVE: ok = UndoOrRedoMoveCmd(CmdPtr); break;
1635 case CMD_STRETCH: ok = UndoOrRedoReplaceCmd(CmdPtr, TRUE); break;
1636 case CMD_REPLACE: ok = UndoOrRedoReplaceCmd(CmdPtr, HighLight); break;
1637 case CMD_ONE_TO_MANY: ok = UndoOrRedoOneToManyCmd(CmdPtr); break;
1638 case CMD_MANY_TO_ONE: ok = UndoOrRedoOneToManyCmd(CmdPtr); break;
1639 case CMD_GOTO_PAGE: UndoOrRedoGotoPageCmd(CmdPtr); break;
1640 case CMD_WB_SLIDESHOW: UndoOrRedoWBSlideShow(CmdPtr); break;
1641 }
1642 CmdPtr->undone = FALSE;
1643 return ok;
1644 }
1645
RedoCmd()1646 void RedoCmd()
1647 {
1648 UndoRedoRestoreDrawingModeInfo urrdmi;
1649
1650 if (gstWBInfo.do_whiteboard) {
1651 MsgBox(TgLoadString(STID_REDO_IN_WB), TOOL_NAME, INFO_MB);
1652 return;
1653 }
1654 SetUndoRedoRestoreDrawingModeInfo(&urrdmi, curChoice, textCursorShown,
1655 editingText, curTextModified, textOrigX, textOrigBaselineY);
1656
1657 TieLooseEnds();
1658 SetCurChoice(NOTHING);
1659 if (firstCmd==NULL || (curCmd!=NULL && curCmd->next==NULL)) {
1660 if (!inHyperSpace && undoRedoRestoreDrawingMode) {
1661 SetCurChoice(urrdmi.cur_choice);
1662 }
1663 MsgBox(TgLoadString(STID_NO_COMMANDS_TO_REDO), TOOL_NAME, INFO_MB);
1664 return;
1665 }
1666 if (curCmd == NULL) {
1667 curCmd = firstCmd;
1668 } else {
1669 curCmd = curCmd->next;
1670 }
1671 undoingOrRedoing = TRUE;
1672 RedoACmd(curCmd, TRUE, TRUE);
1673 undoingOrRedoing = FALSE;
1674
1675 UndoRedoRestoreDrawingMode(&urrdmi);
1676 }
1677
1678 struct CmdStkRec {
1679 struct CmdRec *first, *last, *cur;
1680 int history_count;
1681 struct CmdStkRec *next;
1682 };
1683
1684 static struct CmdStkRec *topCompositeCmdStk=NULL;
1685
StartCompositeCmd()1686 void StartCompositeCmd()
1687 {
1688 struct CmdStkRec *cmd_stk_ptr;
1689
1690 if (historyDepth == 0) return;
1691
1692 cmd_stk_ptr = (struct CmdStkRec *)malloc(sizeof(struct CmdStkRec));
1693 if (cmd_stk_ptr == NULL) FailAllocMessage();
1694 memset(cmd_stk_ptr, 0, sizeof(struct CmdStkRec));
1695
1696 cmd_stk_ptr->next = topCompositeCmdStk;
1697 cmd_stk_ptr->first = firstCmd;
1698 cmd_stk_ptr->last = lastCmd;
1699 cmd_stk_ptr->cur = curCmd;
1700 cmd_stk_ptr->history_count = historyCount;
1701 topCompositeCmdStk = cmd_stk_ptr;
1702
1703 firstCmd = lastCmd = curCmd = NULL;
1704 historyCount = 0;
1705
1706 composingCommand = TRUE;
1707 }
1708
EndCompositeCmd()1709 void EndCompositeCmd()
1710 {
1711 struct CmdRec *composite_cmd=NULL;
1712 int empty=FALSE;
1713
1714 if (historyDepth == 0) return;
1715
1716 if (firstCmd == NULL) {
1717 empty = TRUE;
1718 } else {
1719 composite_cmd = (struct CmdRec *)malloc(sizeof(struct CmdRec));
1720 if (composite_cmd == NULL) FailAllocMessage();
1721 memset(composite_cmd, 0, sizeof(struct CmdRec));
1722 composite_cmd->type = CMD_COMPOSITE;
1723 composite_cmd->include_tgif_obj = FALSE;
1724 composite_cmd->first = firstCmd;
1725 composite_cmd->last = lastCmd;
1726 composite_cmd->top_before = composite_cmd->bot_before = NULL;
1727 composite_cmd->top_after = composite_cmd->bot_after = NULL;
1728 }
1729 if (topCompositeCmdStk != NULL) {
1730 struct CmdStkRec *cmd_stk_ptr;
1731
1732 firstCmd = topCompositeCmdStk->first;
1733 lastCmd = topCompositeCmdStk->last;
1734 curCmd = topCompositeCmdStk->cur;
1735 historyCount = topCompositeCmdStk->history_count;
1736
1737 cmd_stk_ptr = topCompositeCmdStk;
1738 topCompositeCmdStk = topCompositeCmdStk->next;
1739 free(cmd_stk_ptr);
1740 } else {
1741 firstCmd = lastCmd = curCmd = NULL;
1742 historyCount = 0;
1743 }
1744
1745 if (!empty) {
1746 if (curCmd == NULL) {
1747 ClearRedoRecords(firstCmd);
1748 } else if (curCmd != lastCmd) {
1749 ClearRedoRecords(curCmd);
1750 }
1751 if (++historyCount == historyDepth) {
1752 struct CmdRec *new_first_cmd=firstCmd->next;
1753
1754 new_first_cmd->prev = NULL;
1755 firstCmd->next = NULL;
1756 DeleteARedoRecord(firstCmd, (-1.0), (-1.0));
1757 historyCount--;
1758 firstCmd = new_first_cmd;
1759 }
1760 curCmd = composite_cmd;
1761 InsertCmd(lastCmd, NULL, curCmd, &firstCmd, &lastCmd);
1762 }
1763 composingCommand = (topCompositeCmdStk != NULL);
1764 }
1765
RestoreDefaultHistoryDepth()1766 void RestoreDefaultHistoryDepth()
1767 {
1768 CleanUpCmds();
1769 historyDepth = defaultHistoryDepth;
1770 historyCount = 0;
1771 firstCmd = lastCmd = curCmd = NULL;
1772 }
1773
DisableUndo()1774 void DisableUndo()
1775 {
1776 if (gstWBInfo.do_whiteboard) {
1777 /* ``Undo'' is already disabled in whiteboard mode */
1778 return;
1779 }
1780 CleanUpCmds();
1781 while (composingCommand) {
1782 EndCompositeCmd();
1783 CleanUpCmds();
1784 }
1785 historyDepth = 0;
1786 }
1787
EnableUndo()1788 void EnableUndo()
1789 {
1790 if (gstWBInfo.do_whiteboard) {
1791 /* ``Redo'' is already disabled in whiteboard mode */
1792 return;
1793 }
1794 RestoreDefaultHistoryDepth();
1795 }
1796
PrepareStackingInfo(TopSel,BotSel,NumObjs,PreparePhase,ppnStackingPosition,pnStackingCount,pnStackingPositionHasIds)1797 struct SelRec *PrepareStackingInfo(TopSel, BotSel, NumObjs, PreparePhase,
1798 ppnStackingPosition, pnStackingCount, pnStackingPositionHasIds)
1799 struct SelRec *TopSel, *BotSel;
1800 int NumObjs, PreparePhase;
1801 int **ppnStackingPosition, *pnStackingCount, *pnStackingPositionHasIds;
1802 /*
1803 * In whiteboard mode and PreparePhase, *ppnStackingPosition will
1804 * be a list of full_ids. Otherwise, it will just be a
1805 * list of indices.
1806 */
1807 {
1808 int pos=0;
1809 struct SelRec *sel_ptr=NULL;
1810 struct ObjRec *obj_ptr=NULL;
1811
1812 if (gstWBInfo.do_whiteboard && PreparePhase) {
1813 char **ppsz_full_ids=(char**)malloc(NumObjs*sizeof(char*));
1814
1815 if (ppsz_full_ids == NULL) FailAllocMessage();
1816 memset(ppsz_full_ids, 0, NumObjs*sizeof(char*));
1817
1818 *ppnStackingPosition = NULL;
1819 *pnStackingCount = 0;
1820 pos = 0;
1821 sel_ptr = TopSel;
1822 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=obj_ptr->next, pos++) {
1823 if (obj_ptr == sel_ptr->obj) {
1824 char buf[MAXSTRING];
1825
1826 if (obj_ptr->creator_full_id == NULL) {
1827 sprintf(buf, "#%1d:%1d/%s", pos, obj_ptr->id, gszLocalPID);
1828 } else {
1829 sprintf(buf, "#%1d:%s", pos, obj_ptr->creator_full_id);
1830 }
1831 ppsz_full_ids[(*pnStackingCount)++] = UtilStrDup(buf);
1832 if (ppsz_full_ids[(*pnStackingCount)-1] == NULL) FailAllocMessage();
1833
1834 sel_ptr = sel_ptr->next;
1835 if (*pnStackingCount == NumObjs) break;
1836 }
1837 }
1838 *ppnStackingPosition = (int*)ppsz_full_ids;
1839 if (pnStackingPositionHasIds != NULL) *pnStackingPositionHasIds = TRUE;
1840 } else {
1841 *ppnStackingPosition = (int*)malloc(NumObjs*sizeof(int));
1842 if (*ppnStackingPosition == NULL) FailAllocMessage();
1843 memset(*ppnStackingPosition, 0, NumObjs*sizeof(int));
1844 *pnStackingCount = 0;
1845 pos = 0;
1846 sel_ptr = TopSel;
1847 for (obj_ptr=topObj; obj_ptr!=NULL; obj_ptr=obj_ptr->next, pos++) {
1848 if (obj_ptr == sel_ptr->obj) {
1849 (*ppnStackingPosition)[(*pnStackingCount)++] = pos;
1850 sel_ptr = sel_ptr->next;
1851 if (*pnStackingCount == NumObjs) break;
1852 }
1853 }
1854 if (pnStackingPositionHasIds != NULL) *pnStackingPositionHasIds = FALSE;
1855 }
1856 return sel_ptr;
1857 }
1858
1859 static
PrepareStacking(TopSel,BotSel,NumObjs,PreparePhase)1860 void PrepareStacking(TopSel, BotSel, NumObjs, PreparePhase)
1861 struct SelRec *TopSel, *BotSel;
1862 int NumObjs, PreparePhase;
1863 {
1864 struct SelRec *sel_ptr;
1865
1866 stackingPosition = NULL;
1867 stackingCount = 0;
1868 sel_ptr = PrepareStackingInfo(TopSel, BotSel, NumObjs, PreparePhase,
1869 &stackingPosition, &stackingCount, &stackingPositionHasIds);
1870 if (sel_ptr != NULL || stackingCount != NumObjs) {
1871 sprintf(gszMsgBox, TgLoadString(STID_SELECT_LIST_NOT_SORTED_IN),
1872 "PrepareStacking()");
1873 FatalUnexpectedError(gszMsgBox,
1874 TgLoadString(STID_UNDO_REDO_MAY_CAUSE_CRASH));
1875 }
1876 }
1877
PrepareToRecord(CmdType,TopSel,BotSel,NumObjs)1878 void PrepareToRecord(CmdType, TopSel, BotSel, NumObjs)
1879 int CmdType, NumObjs;
1880 struct SelRec *TopSel, *BotSel;
1881 {
1882 struct SelRec *sel_ptr=NULL, *to_sel_ptr=NULL;
1883
1884 if (historyDepth == 0) return;
1885
1886 preparedColormap = (gnInImageProc ? mainColormap : None);
1887
1888 topSelBeforeInCmd = botSelBeforeInCmd = NULL;
1889 stackingPosition = NULL;
1890 stackingCount = 0;
1891 stackingPositionHasIds = FALSE;
1892
1893 switch (CmdType) {
1894 case CMD_NEW: break;
1895
1896 case CMD_DELETE:
1897 case CMD_MOVE:
1898 case CMD_STRETCH:
1899 case CMD_REPLACE:
1900 PrepareStacking(TopSel, BotSel, NumObjs, TRUE);
1901 if (CmdType == CMD_MOVE) {
1902 CopySel(TopSel, NumObjs, &topSelBeforeInCmd, &botSelBeforeInCmd);
1903 } else {
1904 /* stackingPositionHasIds is TRUE if we are doing whiteboard */
1905 DupTheseObjects(TopSel, BotSel, &topSelBeforeInCmd,
1906 &botSelBeforeInCmd);
1907 for (sel_ptr=TopSel, to_sel_ptr=topSelBeforeInCmd; to_sel_ptr!=NULL;
1908 sel_ptr=sel_ptr->next, to_sel_ptr=to_sel_ptr->next) {
1909 CopyObjId(sel_ptr->obj, to_sel_ptr->obj);
1910 CopyObjLocks(sel_ptr->obj, to_sel_ptr->obj);
1911 }
1912 }
1913 break;
1914
1915 case CMD_GOTO_PAGE: stackingCount = NumObjs; break;
1916 case CMD_WB_CLEARALL: break;
1917 }
1918 return;
1919 }
1920
FreeAfterSel(CmdPtr)1921 void FreeAfterSel(CmdPtr)
1922 struct CmdRec *CmdPtr;
1923 {
1924 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
1925
1926 for (sel_ptr=CmdPtr->top_after; sel_ptr!=NULL; sel_ptr=next_sel) {
1927 next_sel = sel_ptr->next;
1928 free(sel_ptr);
1929 }
1930 CmdPtr->top_after = CmdPtr->bot_after = NULL;
1931 }
1932
1933 static
PrepareExtendedSerializationInfoForRecordCmd(SubCmdPtr,TopSel,BotSel,NumObjs,psi)1934 void PrepareExtendedSerializationInfoForRecordCmd(SubCmdPtr, TopSel, BotSel,
1935 NumObjs, psi)
1936 struct SubCmdRec *SubCmdPtr;
1937 struct SelRec *TopSel, *BotSel;
1938 int NumObjs;
1939 SerializationInfo *psi;
1940 {
1941 psi->subcmd = SubCmdPtr;
1942 psi->top_sel = TopSel;
1943 psi->bot_sel = BotSel;
1944 psi->num_objs = NumObjs;
1945
1946 psi->include_tgif_obj = recordCmdIncludeTgifObj;
1947 psi->new_colormap = recordCmdUsesNewColormap;
1948 psi->logical_clock = gstWBInfo.logical_clock;
1949 psi->sender_process_id = gszLocalPID;
1950
1951 psi->top_before = topSelBeforeInCmd;
1952 psi->bot_before = botSelBeforeInCmd;
1953 psi->pos_before = stackingPosition;
1954 psi->count_before = stackingCount;
1955 psi->pos_before_has_ids = stackingPositionHasIds;
1956 }
1957
RecordCmd(CmdType,SubCmdPtr,TopSel,BotSel,NumObjs)1958 void RecordCmd(CmdType, SubCmdPtr, TopSel, BotSel, NumObjs)
1959 int CmdType, NumObjs;
1960 struct SubCmdRec *SubCmdPtr;
1961 struct SelRec *TopSel, *BotSel;
1962 {
1963 int logical_clock=0;
1964 int wb_send_data_failed=FALSE, plain_wb_data_sz=0;
1965 char *psz_wb_data=NULL, *psz_plain_wb_data=NULL;
1966
1967 if (gstWBInfo.do_whiteboard) {
1968 if (gstWBInfo.dont_serialize || CmdType == CMD_GOTO_PAGE) {
1969 /*
1970 * One of the important thing that happens in SerializeCmd()
1971 * is that the local logical clock got incremented.
1972 * If we don't increment the logical clock, we may
1973 * create a new command that have the same logical clock
1974 * as the one created last time we got here and that's
1975 * illegal. Therefore, we must increment the logical clock.
1976 */
1977 logical_clock = gstWBInfo.logical_clock++;
1978 } else {
1979 SerializationInfo si;
1980
1981 memset(&si, 0, sizeof(SerializationInfo));
1982 PrepareExtendedSerializationInfoForRecordCmd(SubCmdPtr, TopSel, BotSel,
1983 NumObjs, &si);
1984
1985 serializingFile = TRUE;
1986
1987 psz_plain_wb_data = NULL;
1988 plain_wb_data_sz = 0;
1989 if ((psz_wb_data=SerializeCmd(CmdType, &si, &logical_clock,
1990 &psz_plain_wb_data, &plain_wb_data_sz)) != NULL) {
1991 if (!SendWBData(psz_wb_data,logical_clock)) {
1992 wb_send_data_failed = TRUE;
1993 }
1994 }
1995 serializingFile = FALSE;
1996 }
1997 } else {
1998 if (historyDepth == 0) return;
1999
2000 if (curCmd == NULL) {
2001 ClearRedoRecords(firstCmd);
2002 } else if (curCmd != lastCmd) {
2003 ClearRedoRecords(curCmd);
2004 }
2005 if (++historyCount == historyDepth && !composingCommand) {
2006 struct CmdRec *new_first_cmd=firstCmd->next;
2007
2008 new_first_cmd->prev = NULL;
2009 firstCmd->next = NULL;
2010 DeleteARedoRecord(firstCmd, (-1.0), (-1.0));
2011 historyCount--;
2012 firstCmd = new_first_cmd;
2013 }
2014 }
2015 curCmd = (struct CmdRec *)malloc(sizeof(struct CmdRec));
2016 if (curCmd == NULL) FailAllocMessage();
2017 memset(curCmd, 0, sizeof(struct CmdRec));
2018 curCmd->top_before = topSelBeforeInCmd;
2019 curCmd->bot_before = botSelBeforeInCmd;
2020 if (gstWBInfo.do_whiteboard) {
2021 curCmd->serialized = TRUE;
2022 }
2023 curCmd->pos_before = stackingPosition;
2024 curCmd->count_before = stackingCount;
2025 curCmd->pos_before_has_ids = stackingPositionHasIds;
2026 curCmd->type = CmdType;
2027 curCmd->undone = FALSE;
2028 curCmd->include_tgif_obj = recordCmdIncludeTgifObj;
2029 curCmd->new_colormap = recordCmdUsesNewColormap;
2030
2031 if (TopSel != NULL) {
2032 CopySel(TopSel, NumObjs, &(curCmd->top_after), &(curCmd->bot_after));
2033 PrepareStacking(TopSel, BotSel, NumObjs, FALSE);
2034 curCmd->pos_after = stackingPosition;
2035 curCmd->count_after = stackingCount;
2036 } else {
2037 curCmd->top_after = curCmd->bot_after = NULL;
2038 curCmd->pos_after = NULL;
2039 curCmd->count_after = 0;
2040 }
2041 if (gstWBInfo.do_whiteboard) {
2042 struct CmdRec *immed_right_cmd=NULL;
2043
2044 curCmd->logical_clock = logical_clock;
2045 curCmd->sender_process_id = UtilStrDup(gszLocalPID);
2046 if (curCmd->sender_process_id == NULL) FailAllocMessage();
2047
2048 if (!wb_send_data_failed) {
2049 /*
2050 * FindShadowCmdInsertionPoint() examine the logical clock of the new
2051 * command and decides where to insert it in the shadow cmd list.
2052 */
2053 FindCmdInsertionPoint(curCmd, &immed_right_cmd);
2054
2055 if (immed_right_cmd == NULL) {
2056 /* append */
2057 CopyAndInsertCmd(FALSE,
2058 (psz_plain_wb_data==NULL ? psz_wb_data : psz_plain_wb_data),
2059 gstWBInfo.last_shadow_cmd, NULL, curCmd,
2060 &gstWBInfo.first_shadow_cmd, &gstWBInfo.last_shadow_cmd);
2061 } else {
2062 /* insert */
2063 CopyAndInsertCmd(FALSE,
2064 (psz_plain_wb_data==NULL ? psz_wb_data : psz_plain_wb_data),
2065 immed_right_cmd->prev, immed_right_cmd, curCmd,
2066 &gstWBInfo.first_shadow_cmd, &gstWBInfo.last_shadow_cmd);
2067 }
2068 }
2069 immed_right_cmd = NULL;
2070 /*
2071 * FindCmdInsertionPoint() examine the logical clock of the new command
2072 * and decides where to insert it.
2073 */
2074 FindCmdInsertionPoint(curCmd, &immed_right_cmd);
2075
2076 if (immed_right_cmd == NULL) {
2077 /* append */
2078 InsertCmd(gstWBInfo.last_cmd, NULL, curCmd, &gstWBInfo.first_cmd,
2079 &gstWBInfo.last_cmd);
2080 } else {
2081 /* insert */
2082 InsertCmd(immed_right_cmd->prev, immed_right_cmd, curCmd,
2083 &gstWBInfo.first_cmd, &gstWBInfo.last_cmd);
2084 }
2085 if (CmdType == CMD_WB_CLEARALL) {
2086 CleanUpObsoletedWBCmds(curCmd);
2087 }
2088 } else {
2089 InsertCmd(lastCmd, NULL, curCmd, &firstCmd, &lastCmd);
2090 }
2091 switch (CmdType) {
2092 case CMD_NEW: break;
2093 case CMD_DELETE: break;
2094 case CMD_MOVE:
2095 curCmd->subcmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
2096 if (curCmd->subcmd == NULL) FailAllocMessage();
2097 memset(curCmd->subcmd, 0, sizeof(struct SubCmdRec));
2098 curCmd->subcmd->detail.move.dx = SubCmdPtr->detail.move.dx;
2099 curCmd->subcmd->detail.move.dy = SubCmdPtr->detail.move.dy;
2100 break;
2101 case CMD_STRETCH: FreeAfterSel(curCmd); break;
2102 case CMD_REPLACE: FreeAfterSel(curCmd); break;
2103 case CMD_ONE_TO_MANY: break;
2104 case CMD_MANY_TO_ONE: break;
2105 case CMD_GOTO_PAGE: curCmd->count_after = NumObjs; break;
2106 case CMD_WB_CLEARALL:
2107 curCmd->subcmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
2108 if (curCmd->subcmd == NULL) FailAllocMessage();
2109 memset(curCmd->subcmd, 0, sizeof(struct SubCmdRec));
2110 curCmd->subcmd->detail.clearall.page_style =
2111 SubCmdPtr->detail.clearall.page_style;
2112 curCmd->subcmd->detail.clearall.print_mag =
2113 SubCmdPtr->detail.clearall.print_mag;
2114 break;
2115 case CMD_CHAT_A_LINE:
2116 /* intentionally forget what has been chatted */
2117 break;
2118 case CMD_WB_SLIDESHOW:
2119 curCmd->subcmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
2120 if (curCmd->subcmd == NULL) FailAllocMessage();
2121 memset(curCmd->subcmd, 0, sizeof(struct SubCmdRec));
2122 curCmd->subcmd->detail.slideshow.into_slideshow =
2123 SubCmdPtr->detail.slideshow.into_slideshow;
2124 break;
2125 }
2126 if (gstWBInfo.do_whiteboard) {
2127 if (wb_send_data_failed) {
2128 UndoACmd(curCmd, FALSE, TRUE);
2129 UnlinkCmd(curCmd, &gstWBInfo.first_cmd, &gstWBInfo.last_cmd);
2130 DeleteARedoRecord(curCmd, (-1.0), (-1.0));
2131 }
2132 if (psz_wb_data != NULL) {
2133 SerializeFreeBuf(psz_wb_data);
2134 }
2135 if (psz_plain_wb_data != NULL) {
2136 UtilFree(psz_plain_wb_data);
2137 }
2138 }
2139 curCmd = lastCmd;
2140 }
2141
AbortPrepareCmd(CmdType)2142 void AbortPrepareCmd(CmdType)
2143 int CmdType;
2144 {
2145 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
2146
2147 if (historyDepth == 0) return;
2148
2149 for (sel_ptr=topSelBeforeInCmd; sel_ptr!=NULL; sel_ptr=next_sel) {
2150 next_sel = sel_ptr->next;
2151 switch (CmdType) {
2152 case CMD_REPLACE: FreeObj(sel_ptr->obj); break;
2153 }
2154 free(sel_ptr);
2155 }
2156 if (stackingPosition != NULL) {
2157 if (stackingPositionHasIds) {
2158 int i=0;
2159
2160 for (i=0; i < stackingCount; i++) {
2161 UtilFree((char*)(long)(stackingPosition[i]));
2162 }
2163 }
2164 free(stackingPosition);
2165 }
2166 stackingPosition = NULL;
2167 stackingCount = 0;
2168 stackingPositionHasIds = FALSE;
2169 topSelBeforeInCmd = botSelBeforeInCmd = NULL;
2170 }
2171
RecordNewObjCmd()2172 void RecordNewObjCmd()
2173 {
2174 if (historyDepth == 0) return;
2175
2176 if (topSel==NULL) {
2177 struct SelRec *sel_ptr;
2178
2179 sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
2180 if (sel_ptr == NULL) FailAllocMessage();
2181 memset(sel_ptr, 0, sizeof(struct SelRec));
2182 sel_ptr->next = sel_ptr->prev = NULL;
2183 sel_ptr->obj = topObj;
2184 PrepareToRecord(CMD_NEW, NULL, NULL, 0);
2185 RecordCmd(CMD_NEW, NULL, sel_ptr, sel_ptr, 1);
2186 free(sel_ptr);
2187 } else {
2188 PrepareToRecord(CMD_NEW, NULL, NULL, 0);
2189 RecordCmd(CMD_NEW, NULL, topSel, botSel, 1);
2190 }
2191 }
2192
PrepareToReplaceAnObj(BeforeObjPtr)2193 void PrepareToReplaceAnObj(BeforeObjPtr)
2194 struct ObjRec *BeforeObjPtr;
2195 {
2196 struct SelRec *sel_ptr;
2197
2198 if (historyDepth == 0) return;
2199
2200 sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
2201 if (sel_ptr == NULL) FailAllocMessage();
2202 memset(sel_ptr, 0, sizeof(struct SelRec));
2203 sel_ptr->next = sel_ptr->prev = NULL;
2204 sel_ptr->obj = BeforeObjPtr;
2205 PrepareToRecord(CMD_REPLACE, sel_ptr, sel_ptr, 1);
2206 free(sel_ptr);
2207 }
2208
RecordReplaceAnObj(AfterObjPtr)2209 void RecordReplaceAnObj(AfterObjPtr)
2210 struct ObjRec *AfterObjPtr;
2211 {
2212 struct SelRec *sel_ptr;
2213
2214 if (historyDepth == 0) return;
2215
2216 sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
2217 if (sel_ptr == NULL) FailAllocMessage();
2218 memset(sel_ptr, 0, sizeof(struct SelRec));
2219 sel_ptr->next = sel_ptr->prev = NULL;
2220 sel_ptr->obj = AfterObjPtr;
2221 RecordCmd(CMD_REPLACE, NULL, sel_ptr, sel_ptr, 1);
2222 free(sel_ptr);
2223 }
2224
ChangeReplaceOneCmdToDeleteCmd()2225 void ChangeReplaceOneCmdToDeleteCmd()
2226 {
2227 RecordCmd(CMD_DELETE, NULL, NULL, NULL, 0);
2228 }
2229
RecordWBClearAll()2230 void RecordWBClearAll()
2231 {
2232 if (gstWBInfo.do_whiteboard) {
2233 struct SubCmdRec subcmd;
2234
2235 memset(&subcmd, 0, sizeof(struct SubCmdRec));
2236 subcmd.detail.clearall.page_style = pageStyle;
2237 subcmd.detail.clearall.print_mag = printMag;
2238
2239 PrepareToRecord(CMD_WB_CLEARALL, NULL, NULL, 0);
2240 RecordCmd(CMD_WB_CLEARALL, &subcmd, NULL, NULL, 0);
2241 }
2242 }
2243
RecordWBSlideShow(into_slideshow)2244 void RecordWBSlideShow(into_slideshow)
2245 int into_slideshow;
2246 {
2247 if (gstWBInfo.do_whiteboard) {
2248 if (pageLayoutMode == PAGE_STACK && firstPage != lastPage) {
2249 struct SubCmdRec subcmd;
2250
2251 memset(&subcmd, 0, sizeof(struct SubCmdRec));
2252 subcmd.detail.slideshow.into_slideshow = into_slideshow;
2253
2254 PrepareToRecord(CMD_WB_SLIDESHOW, NULL, NULL, 0);
2255 RecordCmd(CMD_WB_SLIDESHOW, &subcmd, NULL, NULL, 0);
2256 }
2257 }
2258 }
2259
RecordWBChatALine(pSubCmdPtr)2260 void RecordWBChatALine(pSubCmdPtr)
2261 struct SubCmdRec *pSubCmdPtr;
2262 {
2263 if (gstWBInfo.do_whiteboard) {
2264 PrepareToRecord(CMD_CHAT_A_LINE, NULL, NULL, 0);
2265 RecordCmd(CMD_CHAT_A_LINE, pSubCmdPtr, NULL, NULL, 0);
2266 }
2267 }
2268
2269