Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtappbuilder / src / libABobj / obj.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23
24 /*
25  * $XConsortium: obj.c /main/4 1996/10/02 16:11:56 drk $
26  * 
27  * @(#)obj.c    3.46 11 Feb 1994        cde_app_builder/src/libABobj
28  * 
29  * RESTRICTED CONFIDENTIAL INFORMATION:
30  * 
31  * The information in this document is subject to special restrictions in a
32  * confidential disclosure agreement between HP, IBM, Sun, USL, SCO and
33  * Univel.  Do not distribute this document outside HP, IBM, Sun, USL, SCO,
34  * or Univel without Sun's specific written approval.  This document and all
35  * copies and derivative works thereof must be returned or destroyed at Sun's
36  * request.
37  * 
38  * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  * 
40  */
41
42
43 /*
44  * ABObj.c - manipulations of one gobj structure
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <ctype.h>
50 #if !defined(CSRG_BASED)
51 #include <values.h>
52 #endif
53 #include <stdlib.h>
54 #include <sys/param.h>
55 #include <string.h>
56 #include "objP.h"               /* include first! */
57 #include <ab_private/trav.h>
58 #include <ab_private/util.h>
59 #include "obj_names_listP.h"
60 #include "obj_notifyP.h"
61
62 static int 
63 objP_or_tree_update_clients_with_data(
64                                       ABObj obj,
65                                       BOOL update_subtree,
66                                       int update_code,
67                                       void *update_data,
68                                       UpdateDataFreeFunc free_func
69 );
70
71 /*
72  * Gets the item for this object with index which_item
73  */
74 ABObj
75 obj_get_item(ABObj obj, int which_item)
76 {
77     AB_TRAVERSAL        trav;
78     ABObj               item = NULL;
79     int                 item_num = -1;  /* must be -1 */
80
81     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
82          (item = trav_next(&trav)) != NULL;)
83     {
84         ++item_num;
85         if (item_num == which_item)
86         {
87             break;
88         }
89     }
90     trav_close(&trav);
91     return item;
92 }
93
94 /*
95  * Return the Help Item for a given menubar
96  */
97 ABObj
98 obj_get_menubar_help_item(
99                           ABObj obj
100 )
101 {
102     AB_TRAVERSAL        trav;
103     ABObj               help_item = NULL;
104     ABObj               item;
105
106     if (!obj_is_menubar(obj))
107         return NULL;
108
109     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
110          (item = trav_next(&trav)) != NULL;)
111     {
112         if (obj_is_help_item(item) == TRUE)
113         {
114             help_item = item;
115             break;
116         }
117     }
118     trav_close(&trav);
119     return help_item;
120
121 }
122
123 /*
124  * Returns the number of this object, as a child of it's parent.
125  */
126 int
127 obj_get_child_num(ABObj obj)
128 {
129     int                 child_num = -1;
130     ABObj               child;
131
132     if (obj->parent == NULL)
133     {
134         goto epilogue;
135     }
136
137     for (child = obj->parent->first_child;
138          child != NULL; child = child->next_sibling)
139     {
140         ++child_num;
141         if (obj == child)
142         {
143             break;
144         }
145     }
146
147 epilogue:
148     return child_num;
149 }
150
151
152 ABObj
153 obj_get_container_child(ABObj obj)
154 {
155     ABObj               child;
156     for (child = obj->first_child; child != NULL;
157          child = child->next_sibling)
158     {
159         if (obj_is_container(child))
160         {
161             break;
162         }
163     }
164     return child;
165 }
166
167
168 /*
169  * Returns the item number of this object, with reference to it's parent
170  */
171 int
172 obj_get_item_num(ABObj obj)
173 {
174     int                 item_num = -1;
175     ABObj               item;
176     for (item = obj->parent->first_child;
177          item != NULL; item = item->next_sibling)
178     {
179         if (!obj_is_item(item))
180         {
181             continue;
182         }
183         ++item_num;
184         if (item == obj)
185         {
186             break;
187         }
188     }
189     return item_num;
190 }
191
192
193 ABObj
194 obj_get_menu(ABObj obj)
195 {
196     ABObj               child = NULL;
197     for (child = obj->first_child; child != NULL; child = child->next_sibling)
198     {
199         if (obj_is_menu(child))
200         {
201             break;
202         }
203     }
204     return child;
205 }
206
207
208 ABObj
209 obj_get_pane_child(ABObj obj)
210 {
211     ABObj               child;
212     for (child = obj->first_child; child != NULL;
213          child = child->next_sibling)
214     {
215         if (obj_is_pane(child))
216         {
217             break;
218         }
219     }
220     return child;
221 }
222
223
224 BOOL
225 obj_has_menu(ABObj obj)
226 {
227     if (!util_strempty(obj_get_menu_name(obj)))
228         return TRUE;
229     else
230         return FALSE;
231
232 }
233
234 /*
235  * Moves the children only if *all* the children can be moved.
236  */
237 int
238 obj_move_children(ABObj to, ABObj from)
239 {
240     int                 iReturn = 0;
241     int                 iRC = 0;/* return code */
242     ABObj               child = NULL;
243
244     /*
245      * Get permission for all children
246      */
247     for (child = from->first_child;
248          child != NULL; child = child->next_sibling)
249     {
250         if ((iRC = objP_notify_send_allow_reparent(child, to)) < 0)
251         {
252             iReturn = iRC;
253             goto epilogue;
254         }
255     }
256
257     while ((child = from->first_child) != NULL)
258     {
259
260         /*
261          * Don't send reparent to NULL
262          */
263
264         objP_notify_push_mode();
265         objP_notify_clear_mode(OBJEV_MODE_SEND_NOTIFY_EVS);
266         obj_unparent(child);
267         obj_append_child(to, child);
268         objP_notify_pop_mode();
269
270         objP_notify_send_reparent(child, from);
271     }
272
273 epilogue:
274     return iReturn;
275 }
276
277 /*
278  * maxlen < 1 means no max.
279  */
280 int
281 obj_ensure_unique_name(ABObj obj, ABObj root, int maxlen)
282 {
283     BOOL                unique = FALSE;
284     BOOL                error = FALSE;
285     BOOL                name_changed = FALSE;
286     char                mod_name[256];
287     char                obj_name[2048];
288     int                 oldlen;
289     int                 modlen;
290     int                 newlen;
291     AB_TRAVERSAL        trav;
292     ABObj               other_obj = NULL;
293     int                 modifier = 0;
294     unsigned            trav_type;
295
296     if (obj->name == NULL)
297     {
298         return -1;
299     }
300     if (maxlen < 1)
301     {
302         maxlen = 2048;
303     }
304     strncpy(obj_name, istr_string(obj->name), maxlen);
305     obj_name[2047] = 0;
306     modifier = 0;
307     unique = FALSE;
308     if (obj_is_module(obj))
309     {
310         trav_type = AB_TRAV_MODULES;
311     }
312     else
313     {
314         trav_type = AB_TRAV_UI;
315     }
316     while ((!unique) && (!error))
317     {
318         unique = TRUE;
319         for (trav_open(&trav, root, trav_type);
320              (other_obj = trav_next(&trav)) != NULL;)
321         {
322             if ((other_obj != obj)
323                 && (other_obj->name != NULL)
324                 && (strncmp(istr_string(other_obj->name), obj_name, maxlen)
325                     == 0))
326             {
327                 unique = FALSE;
328                 name_changed = TRUE;
329                 sprintf(mod_name, "%d", ++modifier);
330                 if ((strlen(mod_name) + 1) > (unsigned) maxlen)
331                 {
332                     error = TRUE;
333                     break;
334                 }
335                 oldlen = istr_len(obj->name);
336                 modlen = strlen(mod_name);
337                 newlen = oldlen + modlen;
338                 if (newlen > maxlen)
339                 {
340                     newlen = maxlen;
341                     oldlen = newlen - modlen;
342                 }
343                 strncpy(obj_name, istr_string(obj->name),
344                         oldlen);
345                 obj_name[oldlen] = 0;
346                 strcat(obj_name, mod_name);
347             }
348         }
349         trav_close(&trav);
350     }
351     if (name_changed && (!error))
352     {
353         /* printf("CHANGED %s -> %s\n", obj->name, obj_name); */
354
355         /*
356          * REMIND: CHANGE ALL BY-NAME REFS TO THIS OBJECT!
357          */
358         obj_set_name(obj, obj_name);
359     }
360
361     return error ? -1 : 0;
362 }
363
364
365 /*
366  * Munges name, as necessary to get uniqueness
367  */
368 int
369 obj_set_unique_name_istr(ABObj obj, ISTRING name)
370 {
371     int         rc = 0;         /* return code */
372     ISTRING     newName = obj_alloc_unique_name_istr(obj, name, -1);
373     rc = obj_set_name_istr(obj, newName);
374     istr_destroy(newName);
375     return rc;
376 }
377
378
379 int
380 obj_set_unique_name(ABObj obj, STRING strName)
381 {
382     int         return_value = 0;
383     ISTRING     name = istr_create(strName);
384
385     return_value = obj_set_unique_name_istr(obj, name);
386
387     istr_destroy(name);
388     return return_value;
389 }
390
391
392 STRING          
393 obj_alloc_unique_name(
394                         ABObj   obj, 
395                         STRING  name, 
396                         int     maxNameLen
397 )
398 {
399     ABObj       parent = obj->parent;
400     if (   (parent == NULL)
401         || (obj_find_by_name(parent, name) == obj) )
402     {
403         return strdup(name);
404     }
405     return obj_alloc_unique_name_for_child(parent, name, maxNameLen);
406 }
407
408
409 ISTRING         
410 obj_alloc_unique_name_istr(
411                         ABObj   obj, 
412                         ISTRING name, 
413                         int     maxNameLen
414 )
415 {
416     ABObj       parent = obj->parent;
417     if (   (parent == NULL)
418         || (obj_find_by_name(parent, istr_string(name)) == obj) )
419     {
420         return istr_dup(name);
421     }
422     return obj_alloc_unique_name_istr_for_child(parent, name, maxNameLen);
423 }
424
425
426 STRING          
427 obj_get_unique_name(
428                         ABObj   obj, 
429                         STRING  name, 
430                         int     maxNameLen,
431                         STRING  nameOutBuf
432 )
433 {
434     ABObj       parent = obj->parent;
435     if (   (parent == NULL)
436         || (obj_find_by_name(parent, name) == obj) )
437     {
438         return name;
439     }
440     return obj_get_unique_name_for_child(parent, name, maxNameLen-1, nameOutBuf);
441 }
442
443
444 /*
445  * maxlen < 1 means no max.
446  */
447 STRING
448 obj_alloc_unique_name_for_child(
449                       ABObj     obj,
450                       STRING    name,
451                       int       maxlen
452 )
453 {
454     char        nameBuf[8192];
455     STRING      unique_name = NULL;
456     *nameBuf = 0;
457
458     if (maxlen < 0)
459     {
460         maxlen = 8192;
461     }
462
463     maxlen = util_min(8192,maxlen);     /* don't overrun buf */
464
465     /*
466      * Alloc space and copy-in the unique name
467      */
468     unique_name = strdup(
469                 obj_get_unique_name_for_child(obj, name, maxlen-1, nameBuf));
470      
471     return unique_name;
472 }
473
474
475 ISTRING
476 obj_alloc_unique_name_istr_for_child(
477                       ABObj     obj,
478                       ISTRING   name,
479                       int       maxlen
480 )
481 {
482     char        nameBuf[8192];
483     ISTRING     unique_name = NULL;
484     *nameBuf = 0;
485
486     if (maxlen < 0)
487     {
488         maxlen = 8192;
489     }
490     maxlen = util_min(8192,maxlen);
491     unique_name = istr_create(
492         obj_get_unique_name_for_child(obj, istr_string(name), maxlen-1, nameBuf));
493
494     return unique_name;
495 }
496
497
498 STRING
499 obj_get_unique_name_for_child(
500     ABObj       obj,
501     STRING      name,
502     int         maxlen,
503     STRING      nameOutBuf
504 )
505 {
506     STRING      returnName = NULL;
507     int         nameOutBufSize = maxlen+1;      
508     StringList  namesList = NULL;
509     BOOL        done = FALSE;
510     BOOL        unique = FALSE;
511     int         nameLen = 0;
512     int         i = 0;
513     int         objNumberStart = 0;
514     int         objNumber = 0;
515
516     namesList = objP_get_names_scope_for_children(obj);
517     if (namesList == NULL)
518     {
519         returnName = name;
520         goto epilogue;
521     }
522
523     unique = !strlist_str_exists(namesList, name);
524     if (unique)
525     {
526         returnName = name;
527         goto epilogue;
528     }
529
530     /*
531      * Determine trailing number
532      */
533     util_strncpy(nameOutBuf, name, nameOutBufSize);
534     nameLen = strlen(nameOutBuf);
535     for (i = nameLen-1; i >= 0; --i)
536     {
537         if (!isdigit(nameOutBuf[i]))
538         {
539             break;
540         }
541     }
542     objNumberStart = i + 1;
543     objNumber = atoi(&(nameOutBuf[objNumberStart]));
544
545     /*
546      * Search for a unique name by incrementing trailing #
547      */
548     unique = FALSE;
549     done = FALSE;
550     while (!done)
551     {
552         if (++objNumber == 1)
553         {
554             /* skip 1 - name w/no # is implied 1 */
555             objNumber = 2;
556         }
557         sprintf(&(nameOutBuf[objNumberStart]), "%d", objNumber);
558         unique = !strlist_str_exists(namesList, nameOutBuf);
559         done = unique;
560     }
561     if (unique)
562     {
563         returnName = nameOutBuf;
564     }
565
566 epilogue:
567     return returnName;
568 }
569
570
571 /*
572  * Don't run this on a project!!! It's a severe dog, and can take many
573  * seconds to complete.
574  * 
575  * Run it on each module (root = an module) instead.
576  */
577 int
578 obj_tree_ensure_unique_names(ABObj root, int maxnamelen)
579 {
580     AB_TRAVERSAL        trav;
581     ABObj               obj;
582
583     for (trav_open(&trav, root, AB_TRAV_UI);
584          (obj = trav_next(&trav)) != NULL;)
585     {
586         obj_ensure_unique_name(obj, root, maxnamelen);
587     }
588     trav_close(&trav);
589     return 0;
590 }
591
592
593 /*
594  * Calls obj_tree_ensure_unique_names on each module in the given tree.
595  */
596 int
597 obj_tree_ensure_unique_names_in_modules(ABObj root, int maxnamelen)
598 {
599     AB_TRAVERSAL        trav;
600     ABObj               module;
601
602     for (trav_open(&trav, root, AB_TRAV_MODULES);
603          (module = trav_next(&trav)) != NULL;)
604     {
605         obj_tree_ensure_unique_names(module, maxnamelen);
606     }
607     trav_close(&trav);
608     return 0;
609 }
610
611 /*
612  * Gives an object a name by munging it's parent's name with it's own label.
613  * Used for item children, which aren't given names directly.
614  * 
615  * actual_parent overrides the parent of the object.  If actual_parent is NULL,
616  * the "normal" parent of the object is used.
617  */
618 int
619 obj_set_name_from_label(ABObj obj, STRING parent_name_in)
620 {
621     STRING              parent_name = NULL;
622     STRING              item_label = NULL;
623     STRING              new_name = NULL;
624
625     parent_name =
626         (parent_name_in == NULL ?
627          (obj->parent == NULL ?
628           NULL
629           :
630           istr_string(obj->parent->name)
631           )
632          :
633          parent_name
634         );
635     if (parent_name == NULL)
636     {
637         return -1;
638     }
639
640     if (istr_len(obj->label) > 0)
641     {
642         item_label = istr_string(obj->label);
643     }
644     else
645     {
646         item_label = "item";
647     }
648
649     obj_set_unique_name(obj,
650                  ab_ident_from_name_and_label(parent_name, item_label));
651
652     return 0;
653 }
654
655 int
656 obj_set_name_from_parent(ABObj obj, STRING suffix)
657 {
658     STRING              parent_name;
659     STRING              new_name = NULL;
660
661     parent_name = (obj->parent == NULL ?
662                    NULL
663                    :
664                    istr_string(obj->parent->name)
665         );
666
667     if (parent_name == NULL)
668     {
669         return -1;
670     }
671
672     obj_set_unique_name(obj,
673                  ab_ident_from_name_and_label(parent_name,
674                                               suffix));
675
676     return 0;
677
678 }
679
680 /*
681  * Gets a name for an object. Object may be NULL, or have a NULL name
682  * 
683  * Copies name into passed-in buffer name, guarantees 0 termination. returns
684  * parameter string
685  */
686 STRING
687 obj_get_safe_name(ABObj obj, STRING name, int name_size)
688 {
689     if (name_size < 1)
690     {
691         return name;
692     }
693
694     if (obj == NULL)
695     {
696         strncpy(name, "(nil ABObj)", name_size);
697     }
698     else if (obj_get_name(obj) == NULL)
699     {
700         char                buf[256];
701         sprintf(buf, "(ABObj:0x%08lx)", (unsigned long) obj);
702         strncpy(name, buf, name_size);
703     }
704     else
705     {
706         strncpy(name, obj_get_name(obj), name_size);
707     }
708
709     name[name_size - 1] = 0;
710
711     return name;
712 }
713
714 /*************************************************************************
715 **                                                                      **
716 **              UPDATE_CLIENTS METHODS                                  **
717 **                                                                      **
718 *************************************************************************/
719
720 int
721 obj_update_clients(ABObj obj)
722 {
723     return objP_notify_send_update(obj, FALSE);
724 }
725
726
727 int
728 obj_tree_update_clients(ABObj tree)
729
730 {
731     return objP_notify_send_update(tree, TRUE);
732 }
733
734
735 int
736 obj_update_clients_with_data(
737                              ABObj obj,
738                              int update_code,
739                              void *update_data,
740                              UpdateDataFreeFunc free_func)
741 {
742     return objP_or_tree_update_clients_with_data(
743                            obj, FALSE, update_code, update_data, free_func);
744 }
745
746
747 int
748 obj_tree_update_clients_with_data(ABObj obj,
749                                   int update_code,
750                                   void *update_data,
751                                   UpdateDataFreeFunc free_func)
752 {
753     return objP_or_tree_update_clients_with_data(
754                             obj, TRUE, update_code, update_data, free_func);
755 }
756
757
758 static int
759 objP_or_tree_update_clients_with_data(
760                                       ABObj obj,
761                                       BOOL update_subtree,
762                                       int update_code,
763                                       void *update_data,
764                                       UpdateDataFreeFunc free_func
765 )
766 {
767     int                 iReturn = 0;
768
769     /*
770      * event notification will only free the data if the notify events are
771      * batched.  It's pretty smart about it, so we're going to go to batch
772      * mode and let it handle it.
773      */
774     objP_notify_push_mode();
775     objP_notify_set_mode(OBJEV_MODE_BATCH_NOTIFY_EVS);
776
777     iReturn = objP_notify_send_update_with_data(
778                   obj, update_subtree, update_code, update_data, free_func);
779
780     objP_notify_pop_mode();
781     return iReturn;
782 }