зеркало из https://github.com/mozilla/gecko-dev.git
627 строки
16 KiB
C
627 строки
16 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Name: <Xfe/ClientData.c> */
|
|
/* Description: Manager of Arbitrary Client Data for widgets & gadget. */
|
|
/* Author: Ramiro Estrugo <ramiro@netscape.com> */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
#include <Xfe/ClientData.h>
|
|
#include <Xfe/Linked.h>
|
|
#include <Xfe/XfeP.h>
|
|
|
|
/*
|
|
* How it works.
|
|
*
|
|
* The basic idea is to allocate a structure and associate it with the
|
|
* hash key (the Widget pointer) using the client side X context manager.
|
|
*
|
|
* I originally used the item's Window as the hash key, but then I
|
|
* realized it would considerably simply things to use the Widget pointer
|
|
* itself. That is why there is all the parent_info hackery in the code
|
|
* below. Im #ifdef-ing it in in case we ever need to use the actual Window
|
|
* XID as the has key.
|
|
*/
|
|
|
|
|
|
/*
|
|
* HASH_KEY - use the widget itself for hashing.
|
|
*/
|
|
|
|
#define HASH_KEY(w) ((XID) w)
|
|
|
|
/*
|
|
* Using the window for the has key would require the widget or gadget's
|
|
* parent to be realized. This would complicate the adding and changing
|
|
* if tip/doc strings significantl.
|
|
*
|
|
* I looked at the Xlib source for the XSaveContext() and XFindContext().
|
|
* There is nothing special about using an XID (a Window) as the hash
|
|
* key. It is simply a key.
|
|
*
|
|
* Using the Widget pointer instead of the Window will work just as well
|
|
* with the following 2 caveats:
|
|
*
|
|
* 1. The has function might not be as effecient. No big deal.
|
|
*
|
|
* 2. If a random Window happens to be numerically identical to a Widget
|
|
* pointer, these will hash to the same value if-and-only-of the same
|
|
* unique context is used (XUniqueContext()).
|
|
*
|
|
* Since context management happens on the client side, this will not
|
|
* be a problem since the unique context (_xfe_tt_manager_context)
|
|
* used for the tool tip magic, is not available outside this module.
|
|
*
|
|
* One alternative solution would be to install realize (the first mapping)
|
|
* event handlers for Widgets or gadget parents and install the tooltips
|
|
* there. However, this seems like too much work given the above solution
|
|
* works well. Also, this would not allow the caller to modify tooltips
|
|
* until the widgets were realized - which would suck.
|
|
*/
|
|
|
|
|
|
#if 0
|
|
#define DEBUG_CLIENT_DATA yes
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* _XfeCDItemInfoRec */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
typedef struct
|
|
{
|
|
/* Item */
|
|
Widget item;
|
|
|
|
/* The item's key */
|
|
XfeClientDataKey item_key;
|
|
|
|
|
|
/* The client's data */
|
|
XtPointer client_data;
|
|
|
|
/* The client's free function */
|
|
XfeClientDataFreeFunc free_func;
|
|
|
|
/* Used for gadgets only */
|
|
XfeLinkNode gadget_node;
|
|
|
|
#if PARENT_INFO
|
|
/* Used for manager's only */
|
|
XfeLinked children_list;
|
|
#endif /* PARENT_INFO */
|
|
|
|
} _XfeCDItemInfoRec,*_XfeCDItemInfo;
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Widget functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo WidgetGetInfo (Widget,XfeClientDataKey);
|
|
static void WidgetAddInfo (Widget,XfeClientDataKey,
|
|
_XfeCDItemInfo);
|
|
static void WidgetRemoveInfo (Widget,_XfeCDItemInfo);
|
|
|
|
#if PARENT_INFO
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Gadget functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo GadgetGetInfo (Widget,XfeClientDataKey);
|
|
static XfeLinkNode GadgetAddInfo (Widget,
|
|
_XfeCDItemInfo,
|
|
_XfeCDItemInfo);
|
|
static void GadgetRemoveInfo (Widget,_XfeCDItemInfo);
|
|
#endif /* PARENT_INFO */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Item (Widget or Gadget) functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static void ItemDestroyCB (Widget,XtPointer,XtPointer);
|
|
static void ItemFreeInfo (_XfeCDItemInfo);
|
|
static _XfeCDItemInfo ItemAllocateInfo (Widget);
|
|
static _XfeCDItemInfo ItemGetInfo (Widget,XfeClientDataKey);
|
|
|
|
#if PARENT_INFO
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Manager XfeLinked children list functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static Boolean ChildrenListTestFunc (XtPointer,XtPointer);
|
|
#endif /* PARENT_INFO */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Widget functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo
|
|
WidgetGetInfo(Widget w,XfeClientDataKey key)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
int find_result;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
/* assert( XtIsWidget(w) ); */
|
|
|
|
find_result = XFindContext(XtDisplay(w),
|
|
HASH_KEY(w),
|
|
(XContext) key,
|
|
(XPointer *) &info);
|
|
|
|
|
|
if (find_result != 0)
|
|
{
|
|
info = NULL;
|
|
}
|
|
|
|
return info;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
WidgetAddInfo(Widget w,XfeClientDataKey key,_XfeCDItemInfo info)
|
|
{
|
|
int save_result;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
assert( info != NULL );
|
|
assert( _XfeIsAlive(w) );
|
|
/* assert( XtIsWidget(w) ); */
|
|
|
|
/* Make sure the info is not already installed */
|
|
assert( XFindContext(XtDisplay(w),
|
|
HASH_KEY(w),
|
|
(XContext) key,
|
|
(XPointer *) &info) != 0);
|
|
|
|
save_result = XSaveContext(XtDisplay(w),
|
|
HASH_KEY(w),
|
|
(XContext) key,
|
|
(XPointer) info);
|
|
|
|
assert( save_result == 0 );
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
WidgetRemoveInfo(Widget w,_XfeCDItemInfo info)
|
|
{
|
|
int delete_result;
|
|
|
|
assert( w != NULL );
|
|
assert( info != NULL );
|
|
assert( info->item_key != 0 );
|
|
|
|
#ifdef DEBUG_CLIENT_DATA
|
|
printf("WidgetRemoveInfo(%s,window = %p)\n",XtName(w),HASH_KEY(w));
|
|
#endif
|
|
|
|
delete_result = XDeleteContext(XtDisplay(w),
|
|
HASH_KEY(w),
|
|
(XContext) info->item_key);
|
|
|
|
assert( delete_result == 0 );
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
#if PARENT_INFO
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Gadget functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo
|
|
GadgetGetInfo(Widget w,XfeClientDataKey key)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
_XfeCDItemInfo parent_info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
assert( XmIsGadget(w) );
|
|
|
|
/* Look for the parent info */
|
|
parent_info = WidgetGetInfo(_XfeParent(w),key);
|
|
|
|
if (parent_info != NULL)
|
|
{
|
|
XfeLinkNode node = XfeLinkedFind(parent_info->children_list,
|
|
ChildrenListTestFunc,
|
|
(XtPointer) w);
|
|
|
|
if (node != NULL)
|
|
{
|
|
info = (_XfeCDItemInfo) XfeLinkNodeItem(node);
|
|
}
|
|
}
|
|
|
|
return info;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static XfeLinkNode
|
|
GadgetAddInfo(Widget w,_XfeCDItemInfo parent_info,_XfeCDItemInfo info)
|
|
{
|
|
assert( w != NULL );
|
|
assert( _XfeIsAlive(w) );
|
|
assert( XmIsGadget(w) );
|
|
assert( parent_info != NULL );
|
|
assert( info != NULL );
|
|
|
|
assert( parent_info->children_list != NULL );
|
|
|
|
/* Make sure the item is not already on the list */
|
|
assert( XfeLinkedFind(parent_info->children_list,
|
|
ChildrenListTestFunc,
|
|
(XtPointer) w) == NULL);
|
|
|
|
/* Add this gadget to the tool tip children list */
|
|
return XfeLinkedInsertAtTail(parent_info->children_list,info);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
GadgetRemoveInfo(Widget w,_XfeCDItemInfo info)
|
|
{
|
|
_XfeCDItemInfo parent_info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( XmIsGadget(w) );
|
|
assert( info != NULL );
|
|
assert( info->item_key != 0 );
|
|
|
|
/* Look for the parent info */
|
|
parent_info = WidgetGetInfo(_XfeParent(w),info->item_key);
|
|
|
|
assert( parent_info != NULL );
|
|
|
|
assert( info->gadget_node != NULL );
|
|
|
|
assert( XfeLinkedFind(parent_info->children_list,
|
|
ChildrenListTestFunc,
|
|
(XtPointer) w) == info->gadget_node);
|
|
|
|
/* Remove the item info from the list */
|
|
XfeLinkedRemoveNode(parent_info->children_list,
|
|
info->gadget_node);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
#endif /* PARENT_INFO */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Item (Widget or Gadget) functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
ItemDestroyCB(Widget w,XtPointer client_data,XtPointer call_data)
|
|
{
|
|
_XfeCDItemInfo info = (_XfeCDItemInfo) client_data;
|
|
|
|
assert( info != NULL );
|
|
|
|
/* Invoke the client's free function if needed */
|
|
if (info->free_func != NULL)
|
|
{
|
|
(*info->free_func)(w,info->client_data);
|
|
}
|
|
|
|
#if PARENT_INFO
|
|
if (XmIsGadget(w))
|
|
{
|
|
/* Remove the info */
|
|
GadgetRemoveInfo(w,info);
|
|
|
|
/* Free the item info */
|
|
ItemFreeInfo(info);
|
|
}
|
|
else
|
|
{
|
|
/* Remove the info */
|
|
WidgetRemoveInfo(w,info);
|
|
|
|
/* Free the info */
|
|
ItemFreeInfo(info);
|
|
}
|
|
#else
|
|
/* Remove the info */
|
|
WidgetRemoveInfo(w,info);
|
|
|
|
/* Free the info */
|
|
ItemFreeInfo(info);
|
|
#endif /* PARENT_INFO */
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo
|
|
ItemAllocateInfo(Widget w)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( _XfeIsAlive(w) );
|
|
|
|
info = (_XfeCDItemInfo) XtMalloc(sizeof(_XfeCDItemInfoRec) * 1);
|
|
|
|
/* Initialize the members */
|
|
info->item = w;
|
|
info->item_key = 0;
|
|
info->client_data = NULL;
|
|
info->free_func = NULL;
|
|
|
|
info->gadget_node = NULL;
|
|
|
|
#if PARENT_INFO
|
|
info->children_list = NULL;
|
|
#endif /* PARENT_INFO */
|
|
|
|
/* Garbage collection */
|
|
XtAddCallback(w,XmNdestroyCallback,ItemDestroyCB,(XtPointer) info);
|
|
|
|
return info;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
ItemFreeInfo(_XfeCDItemInfo info)
|
|
{
|
|
assert( info != NULL );
|
|
|
|
#if PARENT_INFO
|
|
/* Destroy the children list if needed */
|
|
if (info->children_list != NULL)
|
|
{
|
|
XfeLinkedDestroy(info->children_list,NULL,NULL);
|
|
}
|
|
#endif /* PARENT_INFO */
|
|
|
|
XtFree((char *) info);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static _XfeCDItemInfo
|
|
ItemGetInfo(Widget w,XfeClientDataKey key)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
|
|
#if PARENT_INFO
|
|
if (XmIsGadget(w))
|
|
{
|
|
info = GadgetGetInfo(w,key);
|
|
}
|
|
else
|
|
{
|
|
info = WidgetGetInfo(w,key);
|
|
}
|
|
#else
|
|
info = WidgetGetInfo(w,key);
|
|
#endif /* PARENT_INFO */
|
|
|
|
return info;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
#if PARENT_INFO
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* Manager XfeLinked children list functions */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static Boolean
|
|
ChildrenListTestFunc(XtPointer item,XtPointer client_data)
|
|
{
|
|
_XfeCDItemInfo info = (_XfeCDItemInfo) item;
|
|
Widget w = (Widget) client_data;
|
|
|
|
assert( info != NULL );
|
|
|
|
return (info->item == w);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
#endif /* PARENT_INFO */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* XfeClientData public methods */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
/* extern */ void
|
|
XfeClientDataAdd(Widget w,
|
|
XfeClientDataKey key,
|
|
XtPointer client_data,
|
|
XfeClientDataFreeFunc free_func)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
|
|
#ifdef DEBUG_CLIENT_DATA
|
|
printf("XfeClientDataAdd(%s)\n",XtName(w));
|
|
#endif
|
|
|
|
/* Look for the item info */
|
|
info = ItemGetInfo(w,key);
|
|
|
|
/* Allocate the info if needed */
|
|
if (info == NULL)
|
|
{
|
|
info = ItemAllocateInfo(w);
|
|
}
|
|
|
|
assert( info != NULL );
|
|
|
|
#if PARENT_INFO
|
|
/* Allocate info according to item type */
|
|
if (XmIsGadget(w))
|
|
{
|
|
_XfeCDItemInfo parent_info = NULL;
|
|
XfeLinkNode node = NULL;
|
|
|
|
/* Look for the parent's info */
|
|
parent_info = WidgetGetInfo(_XfeParent(w),key);
|
|
|
|
/* Allocate the parent info if needed */
|
|
if (parent_info == NULL)
|
|
{
|
|
parent_info = ItemAllocateInfo(_XfeParent(w));
|
|
|
|
WidgetAddInfo(_XfeParent(w),key,parent_info);
|
|
|
|
/* Construct the children list */
|
|
parent_info->children_list = XfeLinkedConstruct();
|
|
}
|
|
|
|
assert( parent_info != NULL );
|
|
|
|
/* Add info to gadget */
|
|
node = GadgetAddInfo(w,parent_info,info);
|
|
|
|
/* Assign the gadget node */
|
|
info->gadget_node = node;
|
|
}
|
|
else
|
|
{
|
|
WidgetAddInfo(w,key,info);
|
|
}
|
|
#else
|
|
WidgetAddInfo(w,key,info);
|
|
#endif /* PARENT_INFO */
|
|
|
|
/* Assign the item */
|
|
info->item = w;
|
|
|
|
/* Assign the item key */
|
|
info->item_key = key;
|
|
|
|
/* Assign the client data */
|
|
info->client_data = client_data;
|
|
|
|
/* Assign the client free function */
|
|
info->free_func = free_func;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
/* extern */ XtPointer
|
|
XfeClientDataRemove(Widget w,XfeClientDataKey key)
|
|
{
|
|
XtPointer client_data = NULL;
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
|
|
#ifdef DEBUG_CLIENT_DATA
|
|
printf("XfeClientDataGet(%s)\n",XtName(w));
|
|
#endif
|
|
|
|
/* Obtain the item's info */
|
|
info = ItemGetInfo(w,key);
|
|
|
|
assert( info != NULL );
|
|
|
|
/* Save the client data so we can return it later */
|
|
client_data = info->client_data;
|
|
|
|
#if PARENT_INFO
|
|
/* Remove info according to item type */
|
|
if (XmIsGadget(w))
|
|
{
|
|
GadgetRemoveInfo(w,info);
|
|
}
|
|
else
|
|
{
|
|
WidgetRemoveInfo(w,info);
|
|
}
|
|
#else
|
|
WidgetRemoveInfo(w,info);
|
|
#endif /* PARENT_INFO */
|
|
|
|
return client_data;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
/* extern */ XtPointer
|
|
XfeClientDataGet(Widget w,XfeClientDataKey key)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
|
|
#ifdef DEBUG_CLIENT_DATA
|
|
printf("XfeClientDataGet(%s)\n",XtName(w));
|
|
#endif
|
|
|
|
/* Obtain the item's info */
|
|
info = ItemGetInfo(w,key);
|
|
|
|
if (!info)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
assert( info->item == w );
|
|
|
|
return info->client_data;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
/* extern */ void
|
|
XfeClientDataSet(Widget w,
|
|
XfeClientDataKey key,
|
|
XtPointer client_data,
|
|
XfeClientDataFreeFunc free_func)
|
|
{
|
|
_XfeCDItemInfo info = NULL;
|
|
|
|
assert( w != NULL );
|
|
assert( key != 0 );
|
|
|
|
#ifdef DEBUG_CLIENT_DATA
|
|
printf("XfeClientDataSet(%s)\n",XtName(w));
|
|
#endif
|
|
|
|
/* Obtaon the item's info */
|
|
info = ItemGetInfo(w,key);
|
|
|
|
assert( info != NULL );
|
|
|
|
assert( info->item == w );
|
|
assert( info->item_key == key );
|
|
|
|
/* Assign the client data */
|
|
info->client_data = client_data;
|
|
|
|
/* Assign the client free function */
|
|
info->free_func = free_func;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
/* extern */ XfeClientDataKey
|
|
XfeClientGetUniqueKey(void)
|
|
{
|
|
return (XfeClientDataKey) XUniqueContext();
|
|
}
|
|
/*----------------------------------------------------------------------*/
|