1 #ifndef production
2 static char rcsId[]="$Header$";
3 #endif
4 /*****
5 * frames.c : XmHTML frame support
6 *
7 * This file Version $Revision$
8 *
9 * Creation date: Tue Mar 25 18:53:12 GMT+0100 1997
10 * Last modification: $Date$
11 * By: $Author$
12 * Current State: $State$
13 *
14 * Author: newt
15 *
16 * Copyright (C) 1994-1997 by Ripley Software Development
17 * All Rights Reserved
18 *
19 * This file is part of the XmHTML Widget Library.
20 *
21 * This library is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU Library General Public
23 * License as published by the Free Software Foundation; either
24 * version 2 of the License, or (at your option) any later version.
25 *
26 * This library is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * Library General Public License for more details.
30 *
31 * You should have received a copy of the GNU Library General Public
32 * License along with this library; if not, write to the Free
33 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 *
35 * Note:
36 * Many thanks to Eric Bello <belloer@gemse.fr> for fixing the original
37 * code!!
38 *****/
39 /*****
40 * ChangeLog
41 * $Log$
42 * Revision 1.1 2011/06/30 16:10:30 rwcox
43 * Cadd
44 *
45 * Revision 1.10 1998/04/27 06:59:39 newt
46 * tka stuff and a few bugfixes in argument checking
47 *
48 * Revision 1.9 1998/04/04 06:28:10 newt
49 * XmHTML Beta 1.1.3
50 *
51 * Revision 1.8 1997/10/23 00:25:01 newt
52 * XmHTML Beta 1.1.0 release
53 *
54 * Revision 1.7 1997/08/31 17:35:37 newt
55 * Several fixes in form creation & destruction and widget reuse. kd & rr
56 *
57 * Revision 1.6 1997/08/30 01:04:16 newt
58 * _XmHTMLWarning proto & color changes: XmHTML now uses manager's color fields.
59 *
60 * Revision 1.5 1997/08/01 13:01:40 newt
61 * my_strdup -> strdup, minor bugfixes and updated comments.
62 *
63 * Revision 1.4 1997/05/28 01:48:13 newt
64 * Sped up _XmHTMLCheckForFrames considerably.
65 *
66 * Revision 1.3 1997/04/29 14:27:00 newt
67 * Header files modifications.
68 *
69 * Revision 1.2 1997/04/03 05:35:36 newt
70 * Changed default name from _top to _frame appended with a number
71 *
72 * Revision 1.1 1997/03/28 07:02:46 newt
73 * Initial Revision
74 *
75 *****/
76 #ifdef HAVE_CONFIG_H
77 #include <config.h>
78 #endif
79
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83
84 #include "toolkit.h"
85 #include XmHTMLPrivateHeader
86 #include "stack.h"
87
88 /*** External Function Prototype Declarations ***/
89
90 /*** Public Variable Declarations ***/
91 /* how many times may we retry frame alignment? */
92 #define MAX_FRAME_ITERATIONS 100
93 #define ROW 1
94 #define COL 2
95 #define ROW_COL 4
96
97 /* usefull defines */
98 #define IS_FRAMESET(F) \
99 ((F)->is_frameset)
100 #define IS_FRAME_SIZE_RELATIVE(F) \
101 ((F)->size_type == FRAME_SIZE_RELATIVE)
102 #define IS_FRAME_SIZE_OPTIONAL(F) \
103 ((F)->size_type == FRAME_SIZE_OPTIONAL)
104 #define IS_FRAME_SIZE_FIXED(F) \
105 ((F)->size_type == FRAME_SIZE_FIXED)
106 #define IS_FRAMESET_LAYOUT_ROWS(F) \
107 (IS_FRAMESET(F) && ((F)->layout == FRAMESET_LAYOUT_ROWS))
108 #define IS_FRAMESET_LAYOUT_COLS(F) \
109 (IS_FRAMESET(F) && ((F)->layout == FRAMESET_LAYOUT_COLS))
110 #define IS_FRAMESET_LAYOUT_ROW_COLS(F) \
111 (IS_FRAMESET(F) && ((F)->layout == FRAMESET_LAYOUT_ROW_COLS))
112
113
114 /*** Private Datatype Declarations ****/
115
116 /* definition of a HTML frameset */
117 typedef struct _frameSet{
118 int type; /* type of this set, either ROW or COL */
119 int border; /* frame border value */
120 int *sizes; /* array of child sizes */
121 FrameSize *size_types; /* array of possible size specifications */
122 int nchilds; /* max no of childs */
123 int childs_done; /* no of childs processed so far */
124 int insert_pos; /* insertion position of current child */
125 struct _frameSet *parent; /* parent frameset of this frameset */
126 struct _frameSet *childs; /* list of childs */
127 struct _frameSet *next; /* ptr to next frameSet */
128 XmHTMLFrameWidget *actualFrameSet; /* ptr to saved FrameSet */
129 }frameSet;
130
131 /* stack of framesets */
132 typedef struct _frameStack{
133 frameSet *frame_set;
134 struct _frameStack *next;
135 }frameStack;
136
137 /*** Private Function Prototype Declarations ****/
138 static frameSet *popFrameSet(void);
139 static void pushFrameSet(frameSet *frame_set);
140 static frameSet *doFrameSet(String attributes);
141 static XmHTMLFrameWidget *doFrame(XmHTMLWidget html, String attributes);
142 static void insertFrameSetChild(frameSet *parent, frameSet *child);
143 static void insertFrameChild(frameSet *current_set, XmHTMLFrameWidget *frame);
144 static void makeFrameSets(XmHTMLWidget html, XmHTMLObject *frameset);
145 static void adjustConstraints(XmHTMLWidget html);
146 static void adjustFrame(XmHTMLFrameWidget *parent, int *p_width, int *p_height);
147 static void destroyFrameSets(frameSet *set);
148 static void mapFrames(XmHTMLWidget html);
149 static void frameDestroyCallback(XmHTMLWidget html, XmHTMLFrameWidget *frame);
150
151 /*** Private Variable Declarations ***/
152 static int current_frame; /* running frame counter */
153 static frameSet *frame_sets; /* list of all framesets processed */
154 static frameStack frame_base, *frame_stack;
155
156 /*****
157 * Name: pushFrameSet
158 * Return Type: void
159 * Description: pushes a frameset on the stack
160 * In:
161 * frame_set: frameset to push
162 * Returns:
163 * nothing
164 *****/
165 static void
pushFrameSet(frameSet * frame_set)166 pushFrameSet(frameSet *frame_set)
167 {
168 frameStack *tmp;
169
170 tmp = (frameStack*)malloc(sizeof(frameStack));
171 tmp->frame_set = frame_set;
172 tmp->next = frame_stack;
173 frame_stack = tmp;
174 }
175
176 /*****
177 * Name: popFrameSet
178 * Return Type: frameSet*
179 * Description: pops a frameset of the stack
180 * In:
181 * nothing
182 * Returns:
183 * the next frameset on the stack, or NULL when stack is empty
184 *****/
185 static frameSet*
popFrameSet(void)186 popFrameSet(void)
187 {
188 frameStack *tmp;
189 frameSet *frame_set;
190
191 if(frame_stack->next)
192 {
193 tmp = frame_stack;
194 frame_stack = frame_stack->next;
195 frame_set = tmp->frame_set;
196 free(tmp);
197 return(frame_set);
198 }
199 return(NULL);
200 }
201
202 /*****
203 * Name: doFrameSet
204 * Return Type: frameSet*
205 * Description: creates and fills a frameSet structure with the info in it's
206 * attributes
207 * In:
208 * attributes: attributes for this frameset
209 * Returns:
210 * a newly created frameset.
211 * Note:
212 * this routine inserts each frameset it creates in a linked list which
213 * is used for stack purposes.
214 *****/
215 static frameSet*
doFrameSet(String attributes)216 doFrameSet(String attributes)
217 {
218 frameSet *list, *tmp;
219 String chPtr, tmpPtr, ptr;
220 int i;
221
222 /* nothing to do if no attributes */
223 if(attributes == NULL)
224 return(frame_sets);
225
226 /* create new entry */
227 list = (frameSet*)malloc(sizeof(frameSet));
228 (void)memset(list, 0, sizeof(frameSet));
229
230 list->type = ROW;
231
232 if((chPtr = _XmHTMLTagGetValue(attributes, "rows")) == NULL)
233 {
234 if((chPtr = _XmHTMLTagGetValue(attributes, "cols")) == NULL)
235 {
236 /* useless sanity, should be catched upon entry */
237 free(list);
238 return(frame_sets);
239 }
240 else
241 list->type = COL;
242 }
243
244 /*
245 * count how many childs this frameset has: the no of childs is given by
246 * the no of entries within the COLS or ROWS tag
247 * Note that childs can be frames and/or framesets as well.
248 */
249 for(tmpPtr = chPtr; *tmpPtr != '\0'; tmpPtr++)
250 if(*tmpPtr == ',')
251 list->nchilds++;
252 list->nchilds++;
253
254 list->sizes = (int*)calloc(list->nchilds, sizeof(int));
255 list->size_types = (FrameSize*)calloc(list->nchilds, sizeof(FrameSize));
256 list->childs = (frameSet*)calloc(list->nchilds, sizeof(frameSet));
257
258 /*****
259 * get dimensions: when we encounter a ``*'' in a size definition it
260 * means we are free to choose any size we want. When its a number
261 * followed by a ``%'' we must choose the size relative against the total
262 * width of the render area. When it's a number not followed by anything
263 * we have an absolute size.
264 *****/
265 tmpPtr = ptr = chPtr;
266 i = 0;
267 while(True)
268 {
269 if(*tmpPtr == ',' || *tmpPtr == '\0')
270 {
271 if(*(tmpPtr-1) == '*')
272 list->size_types[i] = FRAME_SIZE_OPTIONAL;
273 else if(*(tmpPtr-1) == '%')
274 list->size_types[i] = FRAME_SIZE_RELATIVE;
275 else
276 list->size_types[i] = FRAME_SIZE_FIXED;
277
278 list->sizes[i++] = atoi(ptr);
279
280 if(*tmpPtr == '\0')
281 break;
282 ptr = tmpPtr+1;
283 }
284 tmpPtr++;
285 /* sanity */
286 if(i == list->nchilds)
287 break;
288 }
289 free(chPtr);
290
291 /*****
292 * Frame borders can be specified by both frameborder or border, they
293 * are equal.
294 *****/
295 if((chPtr = _XmHTMLTagGetValue(attributes, "frameborder")) != NULL)
296 {
297 /*
298 * Sigh, stupid Netscape frameset definition allows a tag to have
299 * a textvalue or a number.
300 */
301 if(!(strcasecmp(chPtr, "no")) || *chPtr == '0')
302 list->border = 0;
303 else
304 list->border = atoi(chPtr);
305 free(chPtr);
306 }
307 else
308 list->border = _XmHTMLTagGetNumber(attributes, "border", 5);
309
310 /* insert this new frame in the overal frameset list. */
311 if(frame_sets == NULL)
312 frame_sets = list;
313 else
314 {
315 for(tmp = frame_sets; tmp != NULL && tmp->next != NULL;
316 tmp = tmp->next);
317 tmp->next = list;
318 }
319
320 /* create actual representation of frameset */
321 {
322 XmHTMLFrameWidget *actualFrameSet = NULL ;
323 actualFrameSet = (XmHTMLFrameWidget*)calloc(1, sizeof(XmHTMLFrameWidget));
324 actualFrameSet->is_frameset = True ;
325 actualFrameSet->layout =
326 (list->type == ROW ? FRAMESET_LAYOUT_ROWS : FRAMESET_LAYOUT_COLS);
327 list->actualFrameSet = actualFrameSet ;
328 }
329 return(list);
330 }
331
332 /*****
333 * Name: doFrame
334 * Return Type: XmHTMLFrameWidget*
335 * Description: fills a HTML frame structure with data from it's attributes
336 * In:
337 * html: XmHTMLWidget id;
338 * attributes: frame attributes
339 * Returns:
340 * updated frame
341 * Note:
342 * this routine takes the frame to update from an already allocated list
343 * of frames and increments the running frame counter when it returns.
344 *****/
345 static XmHTMLFrameWidget*
doFrame(XmHTMLWidget html,String attributes)346 doFrame(XmHTMLWidget html, String attributes)
347 {
348 XmHTMLFrameWidget *frame;
349 String chPtr;
350
351 frame = html->html.frames[current_frame];
352
353 /* default frame sizing & scrolling */
354 frame->size_type = FRAME_SIZE_FIXED;
355 frame->scroll_type = FRAME_SCROLL_AUTO;
356
357 /* get frame name, default to _frame if not present */
358 if(!attributes ||
359 (frame->name = _XmHTMLTagGetValue(attributes, "name")) == NULL)
360 {
361 char buf[24];
362 sprintf(buf, "_frame%i", current_frame);
363 frame->name = strdup(buf);
364 }
365
366 /* pick up all remaining frame attributes */
367 if(attributes)
368 {
369 frame->src = _XmHTMLTagGetValue(attributes, "src");
370 frame->margin_width = (Dimension)_XmHTMLTagGetNumber(attributes,
371 "marginwidth", 5);
372 frame->margin_height = (Dimension)_XmHTMLTagGetNumber(attributes,
373 "marginheight", 5);
374
375 /* inherit margins from parent if we'd gotten an invalid spec */
376 if(!frame->margin_width)
377 frame->margin_width = html->html.margin_width;
378 if(!frame->margin_height)
379 frame->margin_height = html->html.margin_height;
380
381 /*
382 * This is useless as we don't support frame resizing. I think this is
383 * a thing the caller must be able to do. A possible way could be to
384 * overlay the render area with a PanedWidget and store these HTML
385 * widgets as childs of this paned widget.
386 */
387 frame->resize = !_XmHTMLTagCheck(attributes, "noresize");
388
389 /* what about scrolling? */
390 if((chPtr = _XmHTMLTagGetValue(attributes, "scrolling")) != NULL)
391 {
392 if(!(strcasecmp(chPtr, "yes")))
393 frame->scroll_type = FRAME_SCROLL_YES;
394 else if(!(strcasecmp(chPtr, "no")))
395 frame->scroll_type = FRAME_SCROLL_NONE;
396 free(chPtr);
397 }
398 }
399 else
400 {
401 frame->src = NULL;
402 frame->margin_width = 5;
403 frame->margin_height = 5;
404 frame->resize = True;
405 }
406
407 _XmHTMLDebug(11, ("frames.c: doFrame, frame %i created\n"
408 "\tname: %s\n"
409 "\tsrc : %s\n"
410 "\tmargin width : %i\n"
411 "\tmargin height: %i\n"
412 "\tresize : %s\n"
413 "\tscrolling : %s\n", current_frame, frame->name,
414 frame->src ? frame->src : "<none>", frame->margin_width,
415 frame->margin_height, frame->resize ? "yes" : "no",
416 frame->scroll_type == FRAME_SCROLL_AUTO ? "auto" :
417 (frame->scroll_type == FRAME_SCROLL_YES ? "always" : "none")));
418
419 /*
420 * Actual widget creation is postponed until the very last moment
421 * of _XmHTMLCreateFrames
422 */
423
424 /* increment running frame counter */
425 current_frame++;
426 return(frame);
427 }
428
429 /*****
430 * Name: insertFrameSetChild
431 * Return Type: void
432 * Description: inserts a child frameset in it's parent list
433 * In:
434 * parent: parent of this frameset
435 * child: obvious
436 * Returns:
437 * nothing
438 *****/
439 static void
insertFrameSetChild(frameSet * parent,frameSet * child)440 insertFrameSetChild(frameSet *parent, frameSet *child)
441 {
442 if(parent && parent->childs_done < parent->nchilds)
443 {
444 int idx = parent->childs_done;
445 XmHTMLFrameWidget *c, *dad, *son;
446
447 child->parent = parent;
448 child->insert_pos = idx;
449
450 dad = parent->actualFrameSet;
451 son = child->actualFrameSet;
452
453 son->size_s = parent->sizes[child->insert_pos];
454 son->size_type = parent->size_types[child->insert_pos];
455
456 if(son->size_s == 0)
457 son->size_type = FRAME_SIZE_OPTIONAL;
458
459 /* set additional constraints for this frame */
460 son->border = parent->border;
461
462 /* disable resizing if we don't have a border */
463 if(!son->border)
464 son->resize = False;
465
466 for(c = dad->children ; c != NULL ; c = c->next)
467 if(!c->next)
468 break;
469 if(c)
470 c->next = son;
471 else
472 dad->children = son ;
473 son->prev = c ;
474 son->frameset = dad ;
475
476 parent->childs[parent->childs_done] = *child;
477 parent->childs_done++;
478 }
479 }
480
481 /*****
482 * Name: insertFrameChild
483 * Return Type: void
484 * Description: sets the geometry constraints on a HTML frame
485 * In:
486 * frame_set: frameset parent of this frame;
487 * frame: frame for which to set the constraints
488 * Returns:
489 * nothing, but frame is updated.
490 *****/
491 static void
insertFrameChild(frameSet * frame_set,XmHTMLFrameWidget * frame)492 insertFrameChild(frameSet *frame_set, XmHTMLFrameWidget *frame)
493 {
494 XmHTMLFrameWidget *c, *dad;
495 int insert_pos = frame_set->childs_done;
496
497 frame->size_s = frame_set->sizes[insert_pos];
498 frame->size_type = frame_set->size_types[insert_pos];
499
500 if(frame->size_s == 0)
501 frame->size_type = FRAME_SIZE_OPTIONAL;
502
503 /* set additional constraints for this frame */
504 frame->border = frame_set->border;
505
506 /* disable resizing if we don't have a border */
507 if(!frame->border)
508 frame->resize = False;
509
510 dad = frame_set->actualFrameSet;
511 for(c = dad->children ; c != NULL ; c = c->next)
512 if(!c->next)
513 break;
514 if(c)
515 c->next = frame;
516 else
517 dad->children = frame;
518 frame->prev = c;
519 frame->frameset = dad;
520
521 frame_set->childs_done++;
522 }
523
524 /*****
525 * Name: makeFrameSets
526 * Return Type: void
527 * Description: creates all HTML framesets and sets the geometry constraints
528 * on each frame.
529 * In:
530 * html: XmHTMLWidget id;
531 * frameset: XmHTMLObject data;
532 * Returns:
533 * nothing
534 * Note:
535 * This routine was *very* difficult to conceive, so don't let the simplicity
536 * of it deceive you.
537 *****/
538 static void
makeFrameSets(XmHTMLWidget html,XmHTMLObject * frameset)539 makeFrameSets(XmHTMLWidget html, XmHTMLObject *frameset)
540 {
541 XmHTMLObject *tmp;
542 XmHTMLFrameWidget *frame;
543 frameSet *current_set = NULL, *parent_set = NULL;
544 int idx = 0;
545
546 for(tmp = frameset; tmp != NULL; tmp = tmp->next)
547 {
548 switch(tmp->id)
549 {
550 case HT_FRAMESET:
551 if(tmp->is_end)
552 {
553 /* frameset terminated, pop from stack */
554 current_set = popFrameSet();
555 /*
556 * no more sets left on the stack: we've reached the
557 * end of the outermost frameset and are done here.
558 */
559 if(current_set == NULL)
560 return;
561 }
562 else
563 {
564 /* A new frameset, push the current frameset on the stack */
565 pushFrameSet(current_set);
566 parent_set = frame_stack->frame_set;
567
568 /* Check if we still have room for this thing. */
569 if(!parent_set ||
570 parent_set->childs_done < parent_set->nchilds)
571 {
572 /* create a new frameset */
573 current_set = doFrameSet(tmp->attributes);
574 insertFrameSetChild(parent_set, current_set);
575 idx = 0;
576 }
577 else
578 {
579 /*
580 * No more room available, this is an unspecified
581 * frameset, kill it and all childs it might have.
582 */
583 int depth = 1;
584 int start_line = tmp->line;
585 for(tmp = tmp->next; tmp != NULL; tmp = tmp->next)
586 {
587 if(tmp->id == HT_FRAMESET)
588 {
589 if(tmp->is_end)
590 {
591 if(--depth == 0)
592 break;
593 }
594 else /* child frameset */
595 depth++;
596 }
597 }
598 _XmHTMLWarning(__WFUNC__(html, "doFrameSets"),
599 XMHTML_MSG_58, start_line, tmp ? tmp->line : -1);
600 }
601 }
602 break;
603 case HT_FRAME:
604 /* check if we have room left */
605 if(current_set->childs_done < current_set->nchilds)
606 {
607 /* insert child in current frameset */
608 frame = doFrame(html, tmp->attributes);
609 insertFrameChild(current_set, frame);
610 idx++;
611 }
612 else
613 _XmHTMLWarning(__WFUNC__(html, "doFrameSets"),
614 XMHTML_MSG_59, tmp->line);
615 /*****
616 * Note: </FRAME> doesn't exist. The parser is smart enough
617 * to kick these out.
618 *****/
619 /* fall thru */
620 default:
621 break;
622 }
623 if(idx == html->html.nframes)
624 return;
625 }
626 }
627
628 static XmHTMLFrameWidget*
getRootFrameset(XmHTMLWidget html)629 getRootFrameset(XmHTMLWidget html)
630 {
631 XmHTMLFrameWidget *frame;
632
633 for (frame = html->html.frames[0];
634 frame != NULL && frame->frameset != NULL; frame = frame->frameset);
635
636 return(frame);
637 }
638
639
640 static void
adjustFramesetRows(XmHTMLFrameWidget * parent,int * p_width,int * p_height)641 adjustFramesetRows(XmHTMLFrameWidget *parent, int *p_width, int *p_height)
642 {
643 XmHTMLFrameWidget *child = NULL ;
644 int width, height ;
645 int cum_fixed_size = 0, cum_rel_size = 0, cum_opt_size = 0 ;
646
647 /* Begin with fixed-sized children */
648 cum_fixed_size = 0 ;
649 for (child = parent->children ; child != NULL ; child = child->next)
650 {
651 if(IS_FRAME_SIZE_FIXED(child))
652 {
653 width = *p_width ;
654 height = child->size_s ;
655
656 adjustFrame(child, &width, &height);
657
658 child->width = width ;
659 child->height = height ;
660 cum_fixed_size += height ;
661 }
662 }
663
664 /* Then do relative-sized children */
665 cum_rel_size = 0 ;
666 for (child = parent->children ; child != NULL ; child = child->next)
667 {
668 if(IS_FRAME_SIZE_RELATIVE(child))
669 {
670 width = *p_width ;
671 height = child->size_s * (*p_height) / 100 ;
672
673 adjustFrame(child, &width, &height);
674
675 child->width = width ;
676 child->height = height ;
677 cum_rel_size += height ;
678 }
679 }
680
681 /* Finally, end up with optional-sized children */
682 cum_opt_size = 0 ;
683 {
684 int nb_opt = 0;
685
686 /* count how many optional they are */
687 for (child = parent->children ; child != NULL ; child = child->next)
688 if(IS_FRAME_SIZE_OPTIONAL(child))
689 ++nb_opt;
690
691 if(nb_opt > 0)
692 {
693 int cum_size, remain_size, mean_opt_size ;
694
695 /*****
696 * stupid hack : equal sizes for all optional fields.
697 * FIXME! find sth smarter than that!
698 *****/
699 cum_size = cum_fixed_size + cum_rel_size ;
700 remain_size = *p_height - cum_size ;
701 if(remain_size <= nb_opt)
702 remain_size = nb_opt ;
703 mean_opt_size = remain_size / nb_opt ;
704
705 /* go adjust */
706 for(child = parent->children ; child != NULL ; child = child->next)
707 {
708 if(IS_FRAME_SIZE_OPTIONAL(child))
709 {
710 width = *p_width ;
711 height = mean_opt_size ;
712
713 adjustFrame(child, &width, &height);
714
715 child->width = width ;
716 child->height = height ;
717 cum_opt_size += height ;
718 }
719 }
720 }
721 } /* end of optional-sized children mgt */
722
723 #ifdef FEEDBACK_SIZES
724 *p_height = cum_fixed_size + cum_rel_size + cum_opt_size ;
725 if(*p_height <= 0)
726 *p_height = 1 ;
727 #endif
728 }
729
730 static void
adjustFramesetColumns(XmHTMLFrameWidget * parent,int * p_width,int * p_height)731 adjustFramesetColumns(XmHTMLFrameWidget *parent, int *p_width, int *p_height)
732 {
733 XmHTMLFrameWidget *child = NULL ;
734 int width, height ;
735 int cum_fixed_size = 0, cum_rel_size = 0, cum_opt_size = 0 ;
736
737 /* Begin with fixed-sized children */
738 cum_fixed_size = 0 ;
739 for(child = parent->children ; child != NULL ; child = child->next)
740 {
741 if(IS_FRAME_SIZE_FIXED(child))
742 {
743 width = child->size_s ;
744 height = *p_height ;
745
746 adjustFrame(child, &width, &height);
747
748 child->width = width ;
749 child->height = height ;
750 cum_fixed_size += width ;
751 }
752 }
753
754 /* Then do relative-sized children */
755 cum_rel_size = 0 ;
756 for (child = parent->children ; child != NULL ; child = child->next)
757 {
758 if(IS_FRAME_SIZE_RELATIVE(child))
759 {
760 width = child->size_s * (*p_width) / 100 ;
761 height = *p_height ;
762
763 adjustFrame(child, &width, &height);
764
765 child->width = width ;
766 child->height = height ;
767 cum_rel_size += width ;
768 }
769 }
770
771 /* Finally, end up with optional-sized children */
772 cum_opt_size = 0 ;
773 {
774 int nb_opt = 0;
775
776 /* count how many optional they are */
777 for (child = parent->children ; child != NULL ; child = child->next)
778 if(IS_FRAME_SIZE_OPTIONAL(child))
779 ++nb_opt;
780
781 if(nb_opt > 0)
782 {
783 int cum_size, remain_size, mean_opt_size ;
784
785 /*****
786 * stupid hack : equal sizes for all optional fields.
787 * FIXME! find sth smarter than that!
788 *****/
789 cum_size = cum_fixed_size + cum_rel_size ;
790 remain_size = *p_width - cum_size ;
791 if(remain_size <= nb_opt)
792 remain_size = nb_opt ;
793 mean_opt_size = remain_size / nb_opt ;
794
795 /* go adjust */
796 for(child = parent->children ; child != NULL ; child = child->next)
797 {
798 if(IS_FRAME_SIZE_OPTIONAL(child))
799 {
800 width = mean_opt_size ;
801 height = *p_height ;
802
803 adjustFrame(child, &width, &height);
804
805 child->width = width ;
806 child->height = height ;
807 cum_opt_size += width ;
808 }
809 }
810 }
811 } /* end of optional-sized children mgt */
812
813 #ifdef FEEDBACK_SIZES
814 *p_width = cum_fixed_size + cum_rel_size + cum_opt_size ;
815 if(*p_width <= 0)
816 *p_width = 1 ;
817 #endif
818 }
819
820 static void
adjustFrame(XmHTMLFrameWidget * parent,int * p_width,int * p_height)821 adjustFrame(XmHTMLFrameWidget *parent, int *p_width, int *p_height)
822 {
823 if(*p_width <= 0)
824 *p_width = 1 ;
825 if(*p_height <= 0)
826 *p_height = 1 ;
827
828 if(IS_FRAMESET(parent)) /* do recursion only if it is a frameset */
829 {
830 if(parent->layout == FRAMESET_LAYOUT_ROWS)
831 adjustFramesetRows(parent, p_width, p_height);
832 else if(parent->layout == FRAMESET_LAYOUT_COLS)
833 adjustFramesetColumns(parent, p_width, p_height);
834 }
835 }
836
837 static void
locateFrame(XmHTMLFrameWidget * parent,int x,int y)838 locateFrame(XmHTMLFrameWidget *parent, int x, int y)
839 {
840 parent->x = x;
841 parent->y = y;
842
843 if(IS_FRAMESET(parent)) /* do recursion only if it is a frameset */
844 {
845 XmHTMLFrameWidget *frame ;
846
847 if(IS_FRAMESET_LAYOUT_ROWS(parent))
848 {
849 for(frame = parent->children ; frame != NULL ; frame = frame->next)
850 {
851 locateFrame(frame, x, y);
852 y += frame->height ;
853 }
854 }
855
856 if(IS_FRAMESET_LAYOUT_COLS(parent))
857 {
858 for(frame = parent->children ; frame != NULL ; frame = frame->next)
859 {
860 locateFrame(frame, x, y);
861 x += frame->width ;
862 }
863 }
864 }
865 }
866
867
868 static void
adjustConstraints(XmHTMLWidget html)869 adjustConstraints(XmHTMLWidget html)
870 {
871 XmHTMLFrameWidget *root_frame;
872 int work_width, work_height;
873
874 /* this uses the core dimensions */
875 work_width = html->core.width;
876 work_height = html->core.height;
877
878 /* get the root frame */
879 root_frame = getRootFrameset(html);
880
881 /* adjust frames' dimensions */
882 adjustFrame(root_frame, &work_width, &work_height);
883
884 /* adjust frames' positions */
885 locateFrame(root_frame, 0, 0);
886 }
887
888
889 /*****
890 * Name: destroyFrameSets
891 * Return Type: void
892 * Description: destroys the memory used by the framesets
893 * In:
894 * set: list of framesets to be destroyed
895 * Returns:
896 * nothing
897 *****/
898 static void
destroyFrameSets(frameSet * set)899 destroyFrameSets(frameSet *set)
900 {
901 frameSet *tmp;
902
903 while(set)
904 {
905 tmp = set->next;
906 if(set->sizes)
907 free(set->sizes);
908 if(set->size_types)
909 free(set->size_types);
910 if(set->childs)
911 free(set->childs);
912 free(set);
913 set = tmp;
914 }
915 set = NULL;
916 }
917
918 /*****
919 * Name: mapFrames
920 * Return Type: void
921 * Description: map's all XmHTML frame childs to screen
922 * In:
923 * html: XmHTMLWidget id
924 * Returns:
925 * nothing
926 *****/
927 static void
mapFrames(XmHTMLWidget html)928 mapFrames(XmHTMLWidget html)
929 {
930 XmHTMLFrameWidget *frame;
931 int i;
932
933 /* map all XmHTML frame childs */
934 for(i = 0; i < html->html.nframes; i++)
935 {
936 frame = html->html.frames[i];
937 /* map to screen */
938 HTML_ATTR(tka)->SetMappedWhenManaged(frame->frame, True);
939 /* call notifier */
940 _XmHTMLFrameDoneCallback(html, frame, frame->frame);
941 }
942 /* resync */
943 if(HTML_ATTR(gc))
944 HTML_ATTR(tka)->Sync(HTML_ATTR(tka)->dpy, False);
945 }
946
947 /*****
948 * Name: frameDestroyCallback
949 * Return Type: void
950 * Description: frame destruction notifier
951 * In:
952 * html: XmHTMLWidget id;
953 * frame: frame data;
954 * Returns:
955 * nothing
956 *****/
957 static void
frameDestroyCallback(XmHTMLWidget html,XmHTMLFrameWidget * frame)958 frameDestroyCallback(XmHTMLWidget html, XmHTMLFrameWidget *frame)
959 {
960 int ret_val;
961
962 if((ret_val = _XmHTMLFrameDestroyCallback(html, frame)) == -1)
963 return;
964
965 /* always destroy this */
966 if(frame->src) {
967 free(frame->src);
968 frame->src = NULL; /* sanity */
969 }
970 if(frame->name) {
971 free(frame->name);
972 frame->name = NULL; /* sanity */
973 }
974 frame->frameset = NULL; /* sanity */
975
976 /* return if we may not destroy this frame */
977 if(ret_val == 0)
978 {
979 /* destroy frame data, but keep the widget alive */
980 free(frame);
981 frame = NULL;
982 return;
983 }
984
985 /* destroy everything */
986 if(frame->frame)
987 HTML_ATTR(tka)->DestroyWidget(frame->frame);
988 free(frame);
989 frame = NULL;
990 }
991
992 static void
recursiveDestroyFrameset(XmHTMLFrameWidget * frame)993 recursiveDestroyFrameset(XmHTMLFrameWidget *frame)
994 {
995 if (!frame) /* sanity */
996 return ;
997
998 if (IS_FRAMESET(frame))
999 {
1000 XmHTMLFrameWidget *child, *tmp ;
1001 for(child = frame->children ; child != NULL ; )
1002 {
1003 tmp = child->next;
1004 recursiveDestroyFrameset(child);
1005 child = tmp ;
1006 }
1007 frame->children = NULL ;
1008
1009 if(frame->src)
1010 {
1011 free(frame->src);
1012 frame->src = NULL; /* sanity */
1013 }
1014 if(frame->name)
1015 {
1016 free(frame->name);
1017 frame->name = NULL; /* sanity */
1018 }
1019 frame->frameset = NULL; /* sanity */
1020
1021 free(frame);
1022 frame = NULL ;
1023 }
1024 }
1025
1026 static Boolean
areAllSizesOptional(XmHTMLFrameWidget * frameset)1027 areAllSizesOptional(XmHTMLFrameWidget *frameset)
1028 {
1029 Boolean all_opt = True ;
1030 if (IS_FRAMESET(frameset))
1031 {
1032 XmHTMLFrameWidget *frame;
1033
1034 for(frame = frameset->children ; frame != NULL ; frame = frame->next)
1035 {
1036 if(IS_FRAME_SIZE_OPTIONAL(frame))
1037 {
1038 all_opt = False;
1039 break;
1040 }
1041 }
1042 }
1043 return(all_opt);
1044 }
1045
1046 static Boolean
areAllSizesRelative(XmHTMLFrameWidget * frameset)1047 areAllSizesRelative(XmHTMLFrameWidget *frameset)
1048 {
1049 Boolean all_rel = False ;
1050 if(IS_FRAMESET(frameset))
1051 {
1052 XmHTMLFrameWidget *frame;
1053
1054 all_rel = True ;
1055 for(frame = frameset->children ; frame != NULL ; frame = frame->next)
1056 {
1057 if (IS_FRAME_SIZE_RELATIVE(frame))
1058 {
1059 all_rel = False;
1060 break;
1061 }
1062 }
1063 }
1064 return(all_rel);
1065 }
1066
1067 static int
relativeSizesSum(XmHTMLFrameWidget * frameset)1068 relativeSizesSum(XmHTMLFrameWidget *frameset)
1069 {
1070 int rel_sum = 0 ;
1071 if(IS_FRAMESET(frameset))
1072 {
1073 XmHTMLFrameWidget *frame;
1074 for(frame = frameset->children ; frame != NULL ; frame = frame->next)
1075 {
1076 if (IS_FRAME_SIZE_RELATIVE(frame))
1077 {
1078 rel_sum += frame->size_s ;
1079 }
1080 }
1081 }
1082 return(rel_sum);
1083 }
1084
1085 /********
1086 ****** Public Functions
1087 ********/
1088
1089 /*****
1090 * Name: _XmHTMLCheckForFrames
1091 * Return Type: int
1092 * Description: checks if the given list of objects contains HTML frames
1093 * In:
1094 * html: XmHTMLWidget id;
1095 * objects: parser output to check
1096 * Returns:
1097 * no of frames found in the current document.
1098 *****/
1099 int
_XmHTMLCheckForFrames(XmHTMLWidget html,XmHTMLObject * objects)1100 _XmHTMLCheckForFrames(XmHTMLWidget html, XmHTMLObject *objects)
1101 {
1102 XmHTMLObject *tmp;
1103 int nframes = 0;
1104
1105 /* we only support frames if user has attached a frame callback */
1106 if(!html->html.frame_callback)
1107 return(0);
1108
1109 /*
1110 * frames are not allowed to appear inside the BODY tag.
1111 * So we never have to walk the entire contents of the current document
1112 * but simply break out of the loop once we encounter the <BODY> tag.
1113 * This is a fairly huge performance increase.
1114 */
1115 for(tmp = objects; tmp != NULL && tmp->id != HT_BODY; tmp = tmp->next)
1116 if(tmp->id == HT_FRAME)
1117 nframes++;
1118
1119 return(nframes);
1120 }
1121
1122 /*****
1123 * Name: _XmHTMLDestroyFrames
1124 * Return Type: void
1125 * Description: frame destroyer
1126 * In:
1127 * html: XmHTMLWidget id
1128 * nframes: no of frames to destroy;
1129 * Returns:
1130 * nothing, but the frames list of the widget is destroyed.
1131 *****/
1132 void
_XmHTMLDestroyFrames(XmHTMLWidget html,int nframes)1133 _XmHTMLDestroyFrames(XmHTMLWidget html, int nframes)
1134 {
1135 int i = 0;
1136 XmHTMLFrameWidget *root_frame = NULL;
1137
1138 /* unmap all XmHTML frame childs */
1139 for(i = 0; i < html->html.nframes; i++)
1140 HTML_ATTR(tka)->SetMappedWhenManaged(html->html.frames[i]->frame,False);
1141
1142 /* free them */
1143 root_frame = getRootFrameset(html);
1144 recursiveDestroyFrameset(root_frame);
1145
1146 for(i = 0; i < nframes; i++)
1147 {
1148 frameDestroyCallback(html, html->html.frames[i]);
1149 html->html.frames[i] = NULL ;/* sanity */
1150 }
1151 free(html->html.frames);
1152 html->html.frames = NULL;
1153 html->html.nframes = 0;
1154 }
1155
1156 /*****
1157 * Name: _XmHTMLReconfigureFrames
1158 * Return Type: void
1159 * Description: resize method for XmHTML frame childs
1160 * In:
1161 * html: XmHTMLWidget id
1162 * Returns:
1163 * nothing
1164 *****/
1165 void
_XmHTMLReconfigureFrames(XmHTMLWidget html)1166 _XmHTMLReconfigureFrames(XmHTMLWidget html)
1167 {
1168 XmHTMLFrameWidget *frame;
1169 int i;
1170
1171 _XmHTMLDebug(11, ("frames.c: _XmHTMLReconfigureFrames Start\n"));
1172 /* compute new screen positions */
1173 adjustConstraints(html);
1174
1175 /* reconfigure all widgets */
1176 for(i = 0; i < html->html.nframes; i++)
1177 {
1178 frame = html->html.frames[i];
1179
1180 _XmHTMLDebug(11, ("frames.c: _XmHTMLReconfigureFrames doing frame "
1181 "%s.\n", frame->name));
1182
1183 HTML_ATTR(tka)->ConfigureWidget(frame->frame, frame->x, frame->y,
1184 frame->width - frame->border,
1185 frame->height - frame->border, frame->border);
1186 }
1187 _XmHTMLDebug(11, ("frames.c: _XmHTMLReconfigureFrames End.\n"));
1188 }
1189
1190 /*****
1191 * Name: _XmHTMLCreateFrame
1192 * Return Type: Widget
1193 * Description: creates a htmlWidgetClass widget for use in HTML frames.
1194 * In:
1195 * html: parent XmHTMLWidget id;
1196 * frame: data for frame (dimensions, name, ...)
1197 * fptr: callback data from the XmNframeCallback callback function.
1198 * Returns:
1199 * A newly created XmHTMLWidget.
1200 *****/
1201 Widget
_XmHTMLCreateFrame(XmHTMLWidget html,XmHTMLFrameWidget * frame,XmHTMLFrameCallbackStruct * fptr)1202 _XmHTMLCreateFrame(XmHTMLWidget html, XmHTMLFrameWidget *frame,
1203 XmHTMLFrameCallbackStruct *fptr)
1204 {
1205 Arg args[20];
1206 Dimension argc = 0;
1207 static Widget widget;
1208 XmHTMLWidget html_widget;
1209 ToolkitAbstraction *tka = HTML_ATTR(tka);
1210
1211 /* set constraints and other frame stuff */
1212 XtSetArg(args[argc], XmNx, frame->x); argc++;
1213 XtSetArg(args[argc], XmNy, frame->y); argc++;
1214 XtSetArg(args[argc], XmNwidth, frame->width - frame->border); argc++;
1215 XtSetArg(args[argc], XmNheight, frame->height - frame->border); argc++;
1216 XtSetArg(args[argc], XmNmarginWidth, frame->margin_width); argc++;
1217 XtSetArg(args[argc], XmNmarginHeight, frame->margin_height); argc++;
1218 XtSetArg(args[argc], XmNborderWidth, frame->border); argc++;
1219 XtSetArg(args[argc], XmNborderColor, html->manager.top_shadow_color);argc++;
1220 XtSetArg(args[argc], XmNmappedWhenManaged, False); argc++;
1221
1222 /* scrolling gets handled in the widget code itself, so don't set it */
1223
1224 /*
1225 * Create when we have to, the widget is NULL or the widget isn't a
1226 * XmHTML widget.
1227 */
1228 if(fptr->doit == True || fptr->html == NULL)
1229 widget = XmCreateHTML(HTML_ATTR(work_area), fptr->name, args, argc);
1230 else if(!XmIsHTML(fptr->html))
1231 {
1232 /* not a HTML widget, spit out a warning and create one ourselves */
1233 _XmHTMLWarning(__WFUNC__(fptr->html, "_XmHTMLFrameCreateCallback"),
1234 XMHTML_MSG_60);
1235 widget = XmCreateHTML(HTML_ATTR(work_area), fptr->name, args, argc);
1236 }
1237 else
1238 {
1239 widget = fptr->html;
1240
1241 /* first unmanage if it's still up */
1242 if(tka->IsManaged(widget))
1243 tka->UnmanageChild(widget);
1244
1245 /* check if we need to clear any existing source */
1246 if(ATTR_HTML(widget, source) != NULL)
1247 {
1248 XtSetArg(args[argc], XmNvalue, NULL);
1249 argc++;
1250 }
1251
1252 /* reconfigure this widget so it'll fit our purposes */
1253 XtSetValues(widget, args, argc);
1254
1255 /* unmanage scrollbars as well */
1256 ATTR_HTML(widget, needs_vsb) = False;
1257 ATTR_HTML(widget, needs_hsb) = False;
1258 tka->UnmanageChild(ATTR_HTML(widget, hsb));
1259 tka->UnmanageChild(ATTR_HTML(widget, vsb));
1260 }
1261
1262 html_widget = (XmHTMLWidget)widget;
1263 ATTR_HTML(html_widget, is_frame) = True;
1264 ATTR_HTML(html_widget, frame_border) = frame->border;
1265 ATTR_HTML(html_widget, scroll_type) = frame->scroll_type;
1266
1267 /* manage it */
1268 tka->ManageChild(widget);
1269
1270 return(widget);
1271 }
1272
1273 /*****
1274 * Name: _XmHTMLCreateFrames
1275 * Return Type: Boolean
1276 * Description: main frame creator
1277 * In:
1278 * html_old: previous XmHTMLWidget id;
1279 * html: XmHTMLWidget id;
1280 * Returns:
1281 * True when all frames could be created, False otherwise.
1282 *****/
1283 Boolean
_XmHTMLCreateFrames(XmHTMLWidget old,XmHTMLWidget html)1284 _XmHTMLCreateFrames(XmHTMLWidget old, XmHTMLWidget html)
1285 {
1286 int i;
1287 XmHTMLObject *tmp;
1288 static Widget frame;
1289
1290 frame_stack = &frame_base;
1291 frame_stack->next = NULL;
1292 frame_stack->frame_set = NULL;
1293
1294 /* first destroy all previous frames of this widget */
1295 if(old && old->html.nframes)
1296 _XmHTMLDestroyFrames(old, old->html.nframes);
1297
1298 if(frame_sets)
1299 destroyFrameSets(frame_sets);
1300 frame_sets = NULL;
1301
1302 /*
1303 * Don't do a thing if we are destroying the previous list, we don't have
1304 * a frame callback or the new widget doesn't have any frames at all
1305 */
1306 if(html == NULL || !html->html.frame_callback || html->html.nframes == 0)
1307 return(False);
1308
1309 frame = NULL;
1310
1311 /* create the list of HTML frame childs */
1312 html->html.frames = (XmHTMLFrameWidget**)calloc(html->html.nframes,
1313 sizeof(XmHTMLFrameWidget*));
1314
1315 /* create individual HTML frame child ptrs */
1316 for(i = 0; i < html->html.nframes; i++)
1317 {
1318 XmHTMLFrameWidget *frame_w;
1319 frame_w = (XmHTMLFrameWidget*)malloc(sizeof(XmHTMLFrameWidget));
1320 (void)memset(frame_w, 0, sizeof(XmHTMLFrameWidget));
1321 html->html.frames[i] = frame_w;
1322 }
1323
1324 /* move to the first frameset declaration */
1325 for(tmp = html->html.elements; tmp != NULL && tmp->id != HT_FRAMESET;
1326 tmp = tmp->next);
1327
1328 current_frame = 0;
1329
1330 /* create all frames (and possibly nested framesets also) */
1331 makeFrameSets(html, tmp);
1332
1333 /* adjust framecount, makeFrameSets might have found some invalid sets */
1334 html->html.nframes = current_frame;
1335
1336 #ifdef DEBUG
1337 _XmHTMLDebug(11, ("frames.c: _XmHTMLCreateFrames, raw frame listing\n"));
1338 for(i = 0; i < html->html.nframes; i++)
1339 {
1340 _XmHTMLDebug(11, ("frame %i\n"
1341 "\tname : %s\n"
1342 "\tsrc : %s\n"
1343 "\tsize : %i\n",
1344 i, html->html.frames[i]->src, html->html.frames[i]->name,
1345 html->html.frames[i]->size_s));
1346 }
1347 #endif
1348
1349 adjustConstraints(html);
1350
1351 #ifdef DEBUG
1352 _XmHTMLDebug(11, ("frames.c: _XmHTMLCreateFrames, adjusted frame "
1353 "listing\n"));
1354 for(i = 0; i < html->html.nframes; i++)
1355 {
1356 _XmHTMLDebug(11, ("frame %i\n"
1357 "\tname : %s\n"
1358 "\tsrc : %s\n"
1359 "\twidth by height: %ix%i\n"
1360 "\tx offset : %i\n"
1361 "\ty offset : %i\n",
1362 i, html->html.frames[i]->src, html->html.frames[i]->name,
1363 html->html.frames[i]->width, html->html.frames[i]->height,
1364 html->html.frames[i]->x, html->html.frames[i]->y));
1365 }
1366 #endif
1367 /* and now create all frames */
1368 for(i = 0; i < html->html.nframes; i++)
1369 {
1370 html->html.frames[i]->frame = _XmHTMLFrameCreateCallback(html,
1371 html->html.frames[i]);
1372 }
1373 /* erase a few glitches by calling adjustConstraints again */
1374 _XmHTMLReconfigureFrames(html);
1375
1376 /* and now map them to screen */
1377 mapFrames(html);
1378
1379 return(True);
1380 }
1381
1382 /* doesn't work yet */
1383 #if 0
1384 void
1385 _XmHTMLDrawFrameBorder(XmHTMLWidget html)
1386 {
1387 int x = html->core.x;
1388 int y = html->core.y;
1389 int width = html->html.frame_border;
1390 int height = html->core.height;
1391 Display *dsp = XtDisplay((Widget)html);
1392 GC gc;
1393 Window win = XtWindow((Widget)html);
1394
1395 gc = html->manager.bottom_shadow_GC;
1396 XFillRectangle(dsp, win, gc, x, y, width, 1);
1397 XFillRectangle(dsp, win, gc, x, y, 1, height-1);
1398
1399 gc = html->manager.top_shadow_GC;
1400 XFillRectangle(dsp, win, gc, x+1, y + height-1, width-1, 1);
1401 XFillRectangle(dsp, win, gc, x + width - 1, y + 1, 1, height-2);
1402 }
1403 #endif
1404
1405 /********
1406 ****** Public XmHTML Functions
1407 ********/
1408
1409 /*****
1410 * Name: XmHTMLFrameGetChild
1411 * Return Type: Widget
1412 * Description: returns the Widget id of a frame child given it's name.
1413 * In:
1414 * w: XmHTMLWidget
1415 * name: name of frame to locate.
1416 * Returns:
1417 * If found, the widget id of the requested frame, NULL otherwise.
1418 *****/
1419 Widget
XmHTMLFrameGetChild(Widget w,String name)1420 XmHTMLFrameGetChild(Widget w, String name)
1421 {
1422 XmHTMLWidget html;
1423 int i;
1424
1425 /* sanity check */
1426 if(!w || !XmIsHTML(w) || name == NULL)
1427 {
1428 String func = "FrameGetChild";
1429 if(name == NULL)
1430 _XmHTMLWarning(__WFUNC__(w, func),
1431 XMHTML_MSG_21, "NULL frame name", func);
1432 else
1433 _XmHTMLBadParent(w, func);
1434 return(NULL);
1435 }
1436
1437 html = (XmHTMLWidget)w;
1438
1439 for(i = 0; i < html->html.nframes; i++)
1440 {
1441 if(!(strcmp(html->html.frames[i]->name, name)))
1442 return(html->html.frames[i]->frame);
1443 }
1444 return(NULL);
1445 }
1446