GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-component-manager.c
1/********************************************************************\
2 * gnc-component-manager.h - GUI component manager interface *
3 * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation; either version 2 of *
8 * the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
18\********************************************************************/
19
20#include <config.h>
21
22#include <stdio.h>
23
24#include "gnc-component-manager.h"
25#include "qof.h"
26#include "gnc-ui-util.h"
27
28
31#define CM_DEBUG 0
32
33typedef struct
34{
35 QofIdType entity_type;
36 QofEventId event_mask;
38
39typedef struct
40{
41 GHashTable * event_masks;
42 GHashTable * entity_events;
43
44 gboolean match;
46
47typedef struct
48{
49 GNCComponentRefreshHandler refresh_handler;
50 GNCComponentCloseHandler close_handler;
51 gpointer user_data;
52
53 ComponentEventInfo watch_info;
54
55 char *component_class;
56 gint component_id;
57 gpointer session;
59
60
62static guint suspend_counter = 0;
63/* Some code foolishly uses 0 instead of NO_COMPONENT, so we start with 1. */
64static gint next_component_id = 1;
65static GList *components = NULL;
66
67static ComponentEventInfo changes = { NULL, NULL, FALSE };
68static ComponentEventInfo changes_backup = { NULL, NULL, FALSE };
69
70
71/* This static indicates the debugging module that this .o belongs to. */
72static QofLogModule log_module = GNC_MOD_GUI;
73
74
76static void gnc_gui_refresh_internal (gboolean force);
77static GList * find_component_ids_by_class (const char *component_class);
78static gboolean got_events = FALSE;
79
80
83#if CM_DEBUG
84static void
85dump_components (void)
86{
87 GList *node;
88
89 fprintf (stderr, "Components:\n");
90
91 for (node = components; node; node = node->next)
92 {
93 ComponentInfo *ci = node->data;
94
95 fprintf (stderr, " %s:\t%d\n",
96 ci->component_class ? ci->component_class : "(null)",
97 ci->component_id);
98 }
99
100 fprintf (stderr, "\n");
101}
102#endif
103
104static void
105clear_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
106{
107 QofEventId * et = value;
108
109 *et = 0;
110}
111
112/* clear a hash table of the form string --> QofEventId,
113 * where the values are g_malloced and the keys are in the engine
114 * string cache. */
115static void
116clear_mask_hash (GHashTable *hash)
117{
118 if (hash == NULL)
119 return;
120
121 g_hash_table_foreach (hash, clear_mask_hash_helper, NULL);
122}
123
124static gboolean
125destroy_mask_hash_helper (gpointer key, gpointer value, gpointer user_data)
126{
128 g_free (value);
129
130 return TRUE;
131}
132
133static void
134destroy_mask_hash (GHashTable *hash)
135{
136 g_hash_table_foreach_remove (hash, destroy_mask_hash_helper, NULL);
137 g_hash_table_destroy (hash);
138}
139
140static gboolean
141destroy_event_hash_helper (gpointer key, gpointer value, gpointer user_data)
142{
143 GncGUID *guid = key;
144 EventInfo *ei = value;
145
146 guid_free (guid);
147 g_free (ei);
148
149 return TRUE;
150}
151
152/* clear a hash table of the form GncGUID --> EventInfo, where
153 * both keys and values are g_malloced */
154static void
155clear_event_hash (GHashTable *hash)
156{
157 if (hash == NULL)
158 return;
159
160 g_hash_table_foreach_remove (hash, destroy_event_hash_helper, NULL);
161}
162
163static void
164destroy_event_hash (GHashTable *hash)
165{
166 clear_event_hash (hash);
167 g_hash_table_destroy (hash);
168}
169
170static void
171clear_event_info (ComponentEventInfo *cei)
172{
173 if (!cei)
174 return;
175
176 clear_mask_hash (cei->event_masks);
177 clear_event_hash (cei->entity_events);
178}
179
180static void
181add_event (ComponentEventInfo *cei, const GncGUID *entity,
182 QofEventId event_mask, gboolean or_in)
183{
184 GHashTable *hash;
185
186 if (!cei || !cei->entity_events || !entity)
187 return;
188
189 hash = cei->entity_events;
190
191 if (event_mask == 0)
192 {
193 gpointer key;
194 gpointer value;
195
196 if (or_in)
197 return;
198
199 if (g_hash_table_lookup_extended (hash, entity, &key, &value))
200 {
201 g_hash_table_remove (hash, entity);
202 guid_free (key);
203 g_free (value);
204 }
205 }
206 else
207 {
208 EventInfo *ei;
209
210 ei = g_hash_table_lookup (hash, entity);
211 if (ei == NULL)
212 {
213 GncGUID *key;
214
215 key = guid_malloc ();
216 *key = *entity;
217
218 ei = g_new (EventInfo, 1);
219 ei->event_mask = 0;
220
221 g_hash_table_insert (hash, key, ei);
222 }
223
224 if (or_in)
225 ei->event_mask |= event_mask;
226 else
227 ei->event_mask = event_mask;
228 }
229}
230
231static void
232add_event_type (ComponentEventInfo *cei, QofIdTypeConst entity_type,
233 QofEventId event_mask, gboolean or_in)
234{
235 QofEventId *mask;
236
237 g_return_if_fail (cei);
238 g_return_if_fail (cei->event_masks);
239 g_return_if_fail (entity_type);
240
241 mask = g_hash_table_lookup (cei->event_masks, entity_type);
242 if (!mask)
243 {
244 const char * key = qof_string_cache_insert ((gpointer) entity_type);
245 mask = g_new0 (QofEventId, 1);
246 g_hash_table_insert (cei->event_masks, (gpointer)key, mask);
247 }
248
249 if (or_in)
250 *mask |= event_mask;
251 else
252 *mask = event_mask;
253}
254
255static void
256gnc_cm_event_handler (QofInstance *entity,
257 QofEventId event_type,
258 gpointer user_data,
259 gpointer event_data)
260{
261 const GncGUID *guid = qof_entity_get_guid(entity);
262#if CM_DEBUG
263 gchar guidstr[GUID_ENCODING_LENGTH+1];
264 guid_to_string_buff (guid, guidstr);
265 fprintf (stderr, "event_handler: event %d, entity %p, guid %s\n", event_type,
266 entity, guidstr);
267#endif
268 add_event (&changes, guid, event_type, TRUE);
269
270 if (QOF_CHECK_TYPE(entity, GNC_ID_SPLIT))
271 {
272 /* split events are never generated by the engine, but might
273 * be generated by a backend (viz. the postgres backend.)
274 * Handle them like a transaction modify event. */
275 add_event_type (&changes, GNC_ID_TRANS, QOF_EVENT_MODIFY, TRUE);
276 }
277 else
278 add_event_type (&changes, entity->e_type, event_type, TRUE);
279
280 got_events = TRUE;
281
282 if (suspend_counter == 0)
283 gnc_gui_refresh_internal (FALSE);
284}
285
286static gint handler_id;
287
288void
289gnc_component_manager_init (void)
290{
291 if (changes.entity_events)
292 {
293 PERR ("component manager already initialized");
294 return;
295 }
296
297 changes.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
298 changes.entity_events = guid_hash_table_new ();
299
300 changes_backup.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
301 changes_backup.entity_events = guid_hash_table_new ();
302
303 handler_id = qof_event_register_handler (gnc_cm_event_handler, NULL);
304}
305
306void
307gnc_component_manager_shutdown (void)
308{
309 if (!changes.entity_events)
310 {
311 PERR ("component manager not initialized");
312 return;
313 }
314
315 destroy_mask_hash (changes.event_masks);
316 changes.event_masks = NULL;
317
318 destroy_event_hash (changes.entity_events);
319 changes.entity_events = NULL;
320
321 destroy_mask_hash (changes_backup.event_masks);
322 changes_backup.event_masks = NULL;
323
324 destroy_event_hash (changes_backup.entity_events);
325 changes_backup.entity_events = NULL;
326
327 qof_event_unregister_handler (handler_id);
328}
329
330static ComponentInfo *
331find_component (gint component_id)
332{
333 GList *node;
334
335 for (node = components; node; node = node->next)
336 {
337 ComponentInfo *ci = node->data;
338
339 if (ci->component_id == component_id)
340 return ci;
341 }
342
343 return NULL;
344}
345
346static GList *
347find_components_by_data (gpointer user_data)
348{
349 GList *list = NULL;
350 GList *node;
351
352 for (node = components; node; node = node->next)
353 {
354 ComponentInfo *ci = node->data;
355
356 if (ci->user_data == user_data)
357 list = g_list_prepend (list, ci);
358 }
359
360 return list;
361}
362
363static GList *
364find_components_by_session (gpointer session)
365{
366 GList *list = NULL;
367 GList *node;
368
369 for (node = components; node; node = node->next)
370 {
371 ComponentInfo *ci = node->data;
372
373 if (ci->session == session)
374 list = g_list_prepend (list, ci);
375 }
376
377 return list;
378}
379
380static ComponentInfo *
381gnc_register_gui_component_internal (const char * component_class)
382{
383 ComponentInfo *ci;
384 gint component_id;
385
386 g_return_val_if_fail (component_class, NULL);
387
388 /* look for a free handler id */
389 component_id = next_component_id;
390
391 /* design warning: if we ever get 2^32-1 components,
392 this loop is infinite. Instead of fixing it, we'll just
393 complain when (if) we get half way there (probably never).
394 */
395 while (find_component (component_id))
396 if (++component_id == NO_COMPONENT)
397 component_id++;
398
399 if (component_id < 0)
400 PERR("Amazing! Half way to running out of component_ids.");
401
402 /* found one, add the handler */
403 ci = g_new0 (ComponentInfo, 1);
404
405 ci->watch_info.event_masks = g_hash_table_new (g_str_hash, g_str_equal);
406 ci->watch_info.entity_events = guid_hash_table_new ();
407
408 ci->component_class = g_strdup (component_class);
409 ci->component_id = component_id;
410 ci->session = NULL;
411
412 components = g_list_prepend (components, ci);
413
414 /* update id for next registration */
415 next_component_id = component_id + 1;
416
417#if CM_DEBUG
418 fprintf (stderr, "Register component %d in class %s\n",
419 component_id, component_class ? component_class : "(null)");
420 dump_components ();
421#endif
422
423 return ci;
424}
425
426gint
427gnc_register_gui_component (const char *component_class,
428 GNCComponentRefreshHandler refresh_handler,
429 GNCComponentCloseHandler close_handler,
430 gpointer user_data)
431{
432 ComponentInfo *ci;
433
434 /* sanity check */
435 if (!component_class)
436 {
437 PERR ("no class specified");
438 return NO_COMPONENT;
439 }
440
441 ci = gnc_register_gui_component_internal (component_class);
442 g_return_val_if_fail (ci, NO_COMPONENT);
443
444 ci->refresh_handler = refresh_handler;
445 ci->close_handler = close_handler;
446 ci->user_data = user_data;
447
448 return ci->component_id;
449}
450
451void
452gnc_gui_component_watch_entity (gint component_id,
453 const GncGUID *entity,
454 QofEventId event_mask)
455{
456 ComponentInfo *ci;
457
458 if (entity == NULL)
459 return;
460
461 ci = find_component (component_id);
462 if (!ci)
463 {
464 PERR ("component not found");
465 return;
466 }
467
468 add_event (&ci->watch_info, entity, event_mask, FALSE);
469}
470
471void
472gnc_gui_component_watch_entity_type (gint component_id,
473 QofIdTypeConst entity_type,
474 QofEventId event_mask)
475{
476 ComponentInfo *ci;
477
478 ci = find_component (component_id);
479 if (!ci)
480 {
481 PERR ("component not found");
482 return;
483 }
484
485 add_event_type (&ci->watch_info, entity_type, event_mask, FALSE);
486}
487
488const EventInfo *
489gnc_gui_get_entity_events (GHashTable *changes, const GncGUID *entity)
490{
491 if (!changes || !entity)
492 return QOF_EVENT_NONE;
493
494 return g_hash_table_lookup (changes, entity);
495}
496
497void
498gnc_gui_component_clear_watches (gint component_id)
499{
500 ComponentInfo *ci;
501
502 ci = find_component (component_id);
503 if (!ci)
504 {
505 PERR ("component not found");
506 return;
507 }
508
509 clear_event_info (&ci->watch_info);
510}
511
512void
513gnc_unregister_gui_component (gint component_id)
514{
515 ComponentInfo *ci;
516
517 ci = find_component (component_id);
518 if (!ci)
519 {
520 PERR ("component %d not found", component_id);
521 return;
522 }
523
524#if CM_DEBUG
525 fprintf (stderr, "Unregister component %d in class %s\n",
526 ci->component_id,
527 ci->component_class ? ci->component_class : "(null)");
528#endif
529
530 gnc_gui_component_clear_watches (component_id);
531
532 components = g_list_remove (components, ci);
533
534 destroy_mask_hash (ci->watch_info.event_masks);
535 ci->watch_info.event_masks = NULL;
536
537 destroy_event_hash (ci->watch_info.entity_events);
538 ci->watch_info.entity_events = NULL;
539
540 g_free (ci->component_class);
541 ci->component_class = NULL;
542
543 g_free (ci);
544
545#if CM_DEBUG
546 dump_components ();
547#endif
548}
549
550void
551gnc_unregister_gui_component_by_data (const char *component_class,
552 gpointer user_data)
553{
554 GList *list;
555 GList *node;
556
557 list = find_components_by_data (user_data);
558
559 for (node = list; node; node = node->next)
560 {
561 ComponentInfo *ci = node->data;
562
563 if (component_class &&
564 g_strcmp0 (component_class, ci->component_class) != 0)
565 continue;
566
567 gnc_unregister_gui_component (ci->component_id);
568 }
569
570 g_list_free (list);
571}
572
573void
574gnc_suspend_gui_refresh (void)
575{
576 suspend_counter++;
577
578 if (suspend_counter == 0)
579 {
580 PERR ("suspend counter overflow");
581 }
582}
583
584void
585gnc_resume_gui_refresh (void)
586{
587 if (suspend_counter == 0)
588 {
589 PERR ("suspend counter underflow");
590 return;
591 }
592
593 suspend_counter--;
594
595 if (suspend_counter == 0)
596 gnc_gui_refresh_internal (FALSE);
597}
598
599static void
600match_type_helper (gpointer key, gpointer value, gpointer user_data)
601{
602 ComponentEventInfo *cei = user_data;
603 QofIdType id_type = key;
604 QofEventId * et = value;
605 QofEventId * et_2;
606
607 et_2 = g_hash_table_lookup (cei->event_masks, id_type);
608 if (!et_2)
609 return;
610
611 if (*et & *et_2)
612 cei->match = TRUE;
613}
614
615static void
616match_helper (gpointer key, gpointer value, gpointer user_data)
617{
618 GncGUID *guid = key;
619 EventInfo *ei_1 = value;
620 EventInfo *ei_2;
621 ComponentEventInfo *cei = user_data;
622
623 ei_2 = g_hash_table_lookup (cei->entity_events, guid);
624 if (!ei_2)
625 return;
626
627 if (ei_1->event_mask & ei_2->event_mask)
628 cei->match = TRUE;
629}
630
631static gboolean
632changes_match (ComponentEventInfo *cei, ComponentEventInfo *changes)
633{
634 ComponentEventInfo *big_cei;
635 GHashTable *smalltable;
636
637 if (cei == NULL)
638 return FALSE;
639
640 /* check types first, for efficiency */
641 cei->match = FALSE;
642 g_hash_table_foreach (changes->event_masks, match_type_helper, cei);
643 if (cei->match)
644 return TRUE;
645
646 if (g_hash_table_size (cei->entity_events) <=
647 g_hash_table_size (changes->entity_events))
648 {
649 smalltable = cei->entity_events;
650 big_cei = changes;
651 }
652 else
653 {
654 smalltable = changes->entity_events;
655 big_cei = cei;
656 }
657
658 big_cei->match = FALSE;
659
660 g_hash_table_foreach (smalltable, match_helper, big_cei);
661
662 return big_cei->match;
663}
664
665static void
666gnc_gui_refresh_internal (gboolean force)
667{
668 GList *list;
669 GList *node;
670
671 if (!got_events && !force)
672 return;
673
674 gnc_suspend_gui_refresh ();
675
676 {
677 GHashTable *table;
678
679 table = changes_backup.event_masks;
680 changes_backup.event_masks = changes.event_masks;
681 changes.event_masks = table;
682
683 table = changes_backup.entity_events;
684 changes_backup.entity_events = changes.entity_events;
685 changes.entity_events = table;
686 }
687
688#if CM_DEBUG
689 fprintf (stderr, "%srefresh!\n", force ? "forced " : "");
690#endif
691
692 list = find_component_ids_by_class (NULL);
693 // reverse the list so class GncPluginPageRegister is before register-single
694 list = g_list_reverse (list);
695
696 for (node = list; node; node = node->next)
697 {
698 ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
699
700 if (!ci)
701 continue;
702
703 if (!ci->refresh_handler)
704 {
705#if CM_DEBUG
706 fprintf (stderr, "no handlers for %s:%d\n", ci->component_class, ci->component_id);
707#endif
708 continue;
709 }
710
711 if (force)
712 {
713 if (ci->refresh_handler)
714 {
715#if CM_DEBUG
716 fprintf (stderr, "calling %s:%d C handler\n", ci->component_class, ci->component_id);
717#endif
718 ci->refresh_handler (NULL, ci->user_data);
719 }
720 }
721 else if (changes_match (&ci->watch_info, &changes_backup))
722 {
723 if (ci->refresh_handler)
724 {
725#if CM_DEBUG
726 fprintf (stderr, "calling %s:%d C handler\n", ci->component_class, ci->component_id);
727#endif
728 ci->refresh_handler (changes_backup.entity_events, ci->user_data);
729 }
730 }
731 else
732 {
733#if CM_DEBUG
734 fprintf (stderr, "no match for %s:%d\n", ci->component_class, ci->component_id);
735#endif
736 }
737 }
738
739 clear_event_info (&changes_backup);
740 got_events = FALSE;
741
742 g_list_free (list);
743
744 gnc_resume_gui_refresh ();
745}
746
747void
748gnc_gui_refresh_all (void)
749{
750 if (suspend_counter != 0)
751 {
752 PERR ("suspend counter not zero");
753 return;
754 }
755
756 gnc_gui_refresh_internal (TRUE);
757}
758
759gboolean
760gnc_gui_refresh_suspended (void)
761{
762 return suspend_counter != 0;
763}
764
765void
766gnc_close_gui_component (gint component_id)
767{
768 ComponentInfo *ci;
769
770 ci = find_component (component_id);
771 if (!ci)
772 {
773 PERR ("component not found");
774 return;
775 }
776
777 if (!ci->close_handler)
778 return;
779
780 if (ci->close_handler)
781 ci->close_handler (ci->user_data);
782}
783
784void
785gnc_close_gui_component_by_data (const char *component_class,
786 gpointer user_data)
787{
788 GList *list;
789 GList *node;
790
791 list = find_components_by_data (user_data);
792
793 for (node = list; node; node = node->next)
794 {
795 ComponentInfo *ci = node->data;
796
797 if (component_class &&
798 g_strcmp0 (component_class, ci->component_class) != 0)
799 continue;
800
801 gnc_close_gui_component (ci->component_id);
802 }
803
804 g_list_free (list);
805}
806
807void
808gnc_gui_component_set_session (gint component_id, gpointer session)
809{
810 ComponentInfo *ci;
811
812 ci = find_component (component_id);
813 if (!ci)
814 {
815 PERR ("component not found");
816 return;
817 }
818
819 ci->session = session;
820}
821
822void
823gnc_gui_component_reset_session (gpointer old_session, gpointer new_session)
824{
825 GList *node;
826
827 for (node = components; node; node = node->next)
828 {
829 ComponentInfo *ci = node->data;
830
831 if (ci->session == old_session)
832 ci->session = new_session;
833 }
834}
835
836void
837gnc_close_gui_component_by_session (gpointer session)
838{
839 GList *list;
840 GList *node;
841
842 list = find_components_by_session (session);
843
844 // reverse the list so class like dialog-options close before window-report
845 list = g_list_reverse (list);
846
847 for (node = list; node; node = node->next)
848 {
849 ComponentInfo *ci = node->data;
850
851 gnc_close_gui_component (ci->component_id);
852 }
853
854 g_list_free (list);
855}
856
857GList *
858gnc_find_gui_components (const char *component_class,
859 GNCComponentFindHandler find_handler,
860 gpointer find_data)
861{
862 GList *list = NULL;
863 GList *node;
864
865 if (!component_class)
866 return NULL;
867
868 for (node = components; node; node = node->next)
869 {
870 ComponentInfo *ci = node->data;
871
872 if (g_strcmp0 (component_class, ci->component_class) != 0)
873 continue;
874
875 if (find_handler && !find_handler (find_data, ci->user_data))
876 continue;
877
878 list = g_list_prepend (list, ci->user_data);
879 }
880
881 return list;
882}
883
884gpointer
885gnc_find_first_gui_component (const char *component_class,
886 GNCComponentFindHandler find_handler,
887 gpointer find_data)
888{
889 GList *list;
890 gpointer user_data;
891
892#if CM_DEBUG
893 fprintf (stderr, "find: class %s, fn %p, data %p\n", component_class,
894 find_handler, find_data);
895#endif
896 if (!component_class)
897 return NULL;
898
899 list = gnc_find_gui_components (component_class, find_handler, find_data);
900 if (!list)
901 return NULL;
902
903 user_data = list->data;
904
905 g_list_free (list);
906
907#if CM_DEBUG
908 fprintf (stderr, "found: data %p\n", user_data);
909#endif
910 return user_data;
911}
912
913static GList *
914find_component_ids_by_class (const char *component_class)
915{
916 GList *list = NULL;
917 GList *node;
918
919 for (node = components; node; node = node->next)
920 {
921 ComponentInfo *ci = node->data;
922
923 if (component_class &&
924 g_strcmp0 (component_class, ci->component_class) != 0)
925 continue;
926
927 list = g_list_prepend (list, GINT_TO_POINTER (ci->component_id));
928 }
929
930 return list;
931}
932
933gint
934gnc_forall_gui_components (const char *component_class,
935 GNCComponentHandler handler,
936 gpointer iter_data)
937{
938 GList *list;
939 GList *node;
940 gint count = 0;
941
942 if (!handler)
943 return(0);
944
945 /* so components can be destroyed during the forall */
946 list = find_component_ids_by_class (component_class);
947
948 for (node = list; node; node = node->next)
949 {
950 ComponentInfo *ci = find_component (GPOINTER_TO_INT (node->data));
951
952 if (!ci)
953 continue;
954
955 if (handler (ci->component_class, ci->component_id, ci->user_data, iter_data))
956 count++;
957 }
958
959 g_list_free (list);
960 return(count);
961}
utility functions for the GnuCash UI
const gchar * QofIdType
QofIdType declaration.
Definition qofid.h:80
#define QOF_CHECK_TYPE(obj, type)
return TRUE if object is of the given type
Definition qofid.h:102
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition qofid.h:82
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition qofevent.cpp:103
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition qofevent.cpp:73
gint QofEventId
Define the type of events allowed.
Definition qofevent.h:45
#define QOF_EVENT_NONE
Default events for backwards compatibility.
Definition qofevent.h:72
GHashTable * guid_hash_table_new(void)
Returns a GHashTable with <GUID*> as key and a <gpointer> as value and no destructor functions for ke...
Definition guid.cpp:276
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition guid.cpp:139
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...
The type used to store guids in C.
Definition guid.h:75