Show emview_node.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* emview_node.c
*
* Author: girod
*
* $Id: emview_node.c,v 1.28 2005/06/09 23:01:39 girod Exp $
*/
#include "emview_i.h"
#include <time.h>
#include <math.h>
char emview_node_c_id[] = "$Id: emview_node.c,v 1.28 2005/06/09 23:01:39 girod Exp $";
QUEUE_INLINE_INSTANTIATIONS(emview_slot_list, ptrs, slots, slot_t, slot_list_t);
/*
* create and initialize node
*/
QUEUE_FUNCTION_INSTANTIATIONS(emview_node, ptrs, nodes, node_t, emview_node_list_t)
static
node_t *emview_node_create(node_id_t id)
{
node_t *n = g_new0(node_t, 1);
/* set the node ID */
elog(LOG_DEBUG(0), "Creating new node id=%d", id);
n->id = id;
/* new node defaults to visible */
n->visible = 1;
/* add to the list and the hash table */
emview_node_push(&(_core.node_list), n);
g_hash_table_insert(_core.node_list.fast_node_lookup, (void*)id, n);
/* add the node component */
emview_component_register(g_quark_from_string(EMVIEW_NODE_COMPONENT), n->id, EMVIEW_COMP_TYPE_NODE);
return n;
}
node_t *emview_node_lookup_nocreate(node_id_t id)
{
return (node_t*)g_hash_table_lookup(_core.node_list.fast_node_lookup, (void*)id);
}
node_t *emview_node_lookup(node_id_t id)
{
node_t *retval = emview_node_lookup_nocreate(id);
/* create if not present */
if (retval == NULL)
retval = emview_node_create(id);
return retval;
}
void emview_node_ref(node_id_t id, GQuark component)
{
node_t *n = emview_node_lookup(id);
n->referenced = 1;
if (component) {
component_t *c = emview_component_lookup_q(&(n->display.components), component);
if (c) c->referenced = 1;
}
}
int emview_node_is_direct(node_id_t id)
{
node_t *n = emview_node_lookup(id);
if (n) return (n->last_heard_direct == n->last_heard) ? 1 : 0;
return 0;
}
int emview_node_get_center(node_id_t id, GQuark component, int *x, int *y)
{
node_t *n = emview_node_lookup(id);
component_t *c;
/* skip if not visible */
if (!((n->visible && (n->active || n->referenced)) &&
(n->active || !_core.source_list.hide_inactive)))
return -1;
/* default to node component */
if (component == 0)
component = g_quark_from_string(EMVIEW_NODE_COMPONENT);
/* look up component */
c = emview_component_lookup_q(&(n->display.components), component);
if (c) {
/* skip if not visible */
if (!c->visible)
return -1;
if (x) *x = c->px + c->w/2;
if (y) *y = c->py + c->h/2;
return boolify(n->active);
}
return -1;
}
component_list_t *emview_node_get_component_list(node_id_t target)
{
node_t *n = emview_node_lookup_nocreate(target);
if (n) return &(n->display.components);
return NULL;
}
#if 0
void emview_node_reset_to_defaults();
/* $$$ */
#endif
/*
* relink display
*/
void emview_node_relink_display(node_t *n)
{
slot_t *ptr;
/* relink components */
emview_component_relink(&n->display.components, n->id, &(n->display.slots));
/* activate the link sources */
for (ptr = emview_slot_list_top(&(n->display.slots)); ptr; ptr = emview_slot_list_next(ptr)) {
if (ptr->enable_bit && (ptr->enable_type & EMVIEW_ENABLE_LINK) &&
(ptr->type == EMVIEW_SOURCE_LINK)) {
source_t *src = emview_source_lookup_q(ptr->source);
if (src)
emview_source_activate_deps(src);
else
elog(LOG_WARNING, "Link source points to nonexistent source!");
}
}
}
/*
* when we relink globally, we first clear the device active flags,
* which will then be set as sources are configured
*/
void emview_node_global_relink_display()
{
node_t *n;
/* clear device active flags */
emview_device_clear_active_flags();
/* relink each node */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n))
emview_node_relink_display(n);
/* force device update */
emview_device_update_command();
}
/*
* emview_node_handle_simconfig
*
*/
void emview_node_handle_simconfig(emproxy_reply_hdr_t *reply)
{
sim_config_t *cf;
int i;
elog(LOG_DEBUG(0), "Got sim_config reply.. ");
cf = (sim_config_t*)reply->data;
for (i=1; i<=cf->num_nodes; i++) {
node_t *n = emview_node_lookup(i);
n->pos = cf->node[i].pos;
}
emview_repos_nodes();
emview_reconfig();
/* run the emview commands */
emview_analysis_runcommands(cf);
}
void emview_node_clear_refs(node_t *n)
{
n->referenced = 0;
emview_component_list_clear_refs(&(n->display.components));
}
/*
* node_heard:
*
* * creates node if not present.
* * activates node if not active
* * updates last-heard time
*/
void emview_node_heard(node_id_t id, int direct)
{
/* lookup this node with creation */
node_t *n = emview_node_lookup(id);
component_t *c =
emview_component_lookup(&(n->display.components),
EMVIEW_NODE_COMPONENT);
/* is this node !active? */
if (!n->active) {
/*
* reinitialize this node:
* * reset the data sources
* * relink display components
* * mark active
*/
elog(LOG_DEBUG(0), "Activating node id %d", id);
emview_source_reset_node(id);
emview_node_relink_display(n);
n->active = 1;
/* make node component active */
if (c) c->active = 1;
/* reposition now */
emview_repos_nodes();
}
n->last_heard = time(0);
if (direct) {
n->last_heard_direct = n->last_heard;
if (c)
((node_component_t *)c)->direct = 1;
}
}
/*
* node timeout check
*/
static
int emview_node_check_timeouts(void *data, int interval, g_event_t *event)
{
node_t *n;
int cutoff = time(0) - EMVIEW_NODE_INACTIVITY_TIMEOUT;
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n)) {
/* remove direct flag */
if (n->last_heard_direct < cutoff) {
node_component_t *nc =
(node_component_t *)
emview_component_lookup(&(n->display.components),
EMVIEW_NODE_COMPONENT);
if (nc) nc->direct = 0;
}
/* deactivate */
if (n->last_heard < cutoff) {
if (n->active) {
/* call per-device callback function */
emview_device_note_timeout(n->id);
n->active = 0;
/* deactivate components */
emview_component_list_set_active(&(n->display.components), 0);
}
}
}
return TIMER_RENEW;
}
/*
* repositioning nodes
*/
void emview_repos_nodes()
{
node_t *n;
/* use grid */
if (_core.gui.layout_link_source == _core.source_list.grid) {
int node_count = emview_node_qlen(&(_core.node_list));
int i,j;
node_t *n;
j = ceil(sqrt(node_count));
for (i=0, n=emview_node_top(&(_core.node_list)); n; i++, n=emview_node_next(n)) {
n->display.x = i % j;
n->display.y = i / j;
}
}
/* use reported sim locations */
else if (_core.gui.layout_link_source == _core.source_list.reported) {
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n)) {
n->display.x = n->pos.x;
n->display.y = n->pos.y;
}
}
/* $$$ handle link scheme based graphs stuff */
/* force next redraw to be full one*/
emview_next_redraw_full();
}
/*
* drawing nodes
*/
/* reset continuation state */
void emview_draw_nodes_reset()
{
_core.node_list.phase = 0;
_core.node_list.last = NULL;
}
/* check timer, save spot and quit if timer past max */
int emview_node_check_timer(GTimer *timer, node_t *curr, int phase)
{
if ((int)(g_timer_elapsed(timer, NULL) * 1000) > EMVIEW_DEFAULT_REDRAW_SLICE) {
_core.node_list.last = curr;
_core.node_list.phase = phase;
return 1;
}
return 0;
}
/* draw or continue drawing nodes */
int emview_draw_nodes(GTimer *timer)
{
node_t *n;
/* start at last node */
n = _core.node_list.last;
/* jump into the middle */
switch (_core.node_list.phase) {
default:
break;
case DRAW_NODE_LINKS_PHASE:
goto continue_links;
case DRAW_NODE_NOTES_PHASE:
goto continue_notes;
case DRAW_NODE_NODES_PHASE:
goto continue_nodes;
}
/*
* compute referenced bits based on links
*/
#ifdef CLEAR_REFS_ON_EVERY_DRAW
/* first clear the referenced bits */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n))
emview_node_clear_refs(n);
#endif
/* then set them */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n))
if (n->visible) {
slot_t *ptr;
/* chase references in these assignments */
for (ptr = emview_slot_list_top(&(n->display.slots)); ptr;
ptr = emview_slot_list_next(ptr))
if (ptr->enable_bit && ptr->enable_type) {
source_t *src = emview_source_lookup_q(ptr->source);
if (src && src->type == EMVIEW_SOURCE_LINK) {
/* run through the links, mark referenced bits */
emview_source_links_track_refs((link_source_t *)src);
}
}
}
/* execute layout algorithm */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n))
if (n->visible) {
int referenced = 0;
/* initialize the cursor */
int cx = emview_m2p_x(n->display.x);
int cy = emview_m2p_y(n->display.y);
n->display.bx1 = cx;
n->display.bx2 = cx;
n->display.by1 = cy;
n->display.by2 = cy;
/* layout each item by type and set coords */
referenced =
emview_component_layout_type(n, EMVIEW_COMP_TYPE_NODE) || referenced;
referenced =
emview_component_layout_type(n, EMVIEW_COMP_TYPE_BOX) || referenced;
/* $$$ then do strip charts */
/* set referenced bit.. */
if (referenced) n->referenced = 1;
}
/* draw the links */
n = emview_node_top(&(_core.node_list));
continue_links:
for (; n; n = emview_node_next(n))
if ((n->visible && (n->active || n->referenced)) &&
(n->active || !_core.source_list.hide_inactive)) {
slot_t *ptr;
if (emview_node_check_timer(timer, n, DRAW_NODE_LINKS_PHASE)) return 1;
/* for each link source.. */
for (ptr = emview_slot_list_top(&(n->display.slots)); ptr;
ptr = emview_slot_list_next(ptr))
if (ptr->enable_bit && (ptr->enable_type & EMVIEW_ENABLE_LINK)) {
source_t *src = emview_source_lookup_q(ptr->source);
/* draw the links */
if (src && src->type == EMVIEW_SOURCE_LINK)
emview_source_links_draw((link_source_t *)src, n, ptr->field, ptr->component, 0);
}
}
/* draw the annotations */
n = emview_node_top(&(_core.node_list));
continue_notes:
for (; n; n = emview_node_next(n))
if ((n->visible && (n->active || n->referenced)) &&
(n->active || !_core.source_list.hide_inactive)) {
slot_t *ptr;
if (emview_node_check_timer(timer, n, DRAW_NODE_NOTES_PHASE)) return 1;
/* for each link source.. */
for (ptr = emview_slot_list_top(&(n->display.slots)); ptr;
ptr = emview_slot_list_next(ptr))
if (ptr->enable_bit && (ptr->enable_type & EMVIEW_ENABLE_LINK_NOTE)) {
source_t *src = emview_source_lookup_q(ptr->source);
/* draw the links */
if (src && src->type == EMVIEW_SOURCE_LINK)
emview_source_links_draw((link_source_t *)src, n, ptr->field, ptr->component, 1);
}
}
/* draw the nodes */
n = emview_node_top(&(_core.node_list));
continue_nodes:
for (; n; n = emview_node_next(n)) {
if (emview_node_check_timer(timer, n, DRAW_NODE_NODES_PHASE)) return 1;
if (n->visible && (n->active || n->referenced)) {
if (n->active || !_core.source_list.hide_inactive)
emview_components_draw(&(n->display.components));
}
}
/* reset and return */
emview_draw_nodes_reset();
return 0;
}
void emview_nodes_compute_extent()
{
node_t *n;
int first_node = 1;
float w,h;
/* compute the min and max of all node coords */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n))
if (n->visible && (n->active || n->referenced)) {
if (first_node || (_core.gui.extent_x_min > n->display.x))
_core.gui.extent_x_min = n->display.x;
if (first_node || (_core.gui.extent_x_max < n->display.x))
_core.gui.extent_x_max = n->display.x;
if (first_node || (_core.gui.extent_y_min > n->display.y))
_core.gui.extent_y_min = n->display.y;
if (first_node || (_core.gui.extent_y_max < n->display.y))
_core.gui.extent_y_max = n->display.y;
first_node = 0;
}
/* scale it up */
w = _core.gui.extent_x_max - _core.gui.extent_x_min;
h = _core.gui.extent_y_max - _core.gui.extent_y_min;
_core.gui.extent_x_max += w*EMVIEW_EXTENT_MARGIN*2.0;
_core.gui.extent_y_max += h*EMVIEW_EXTENT_MARGIN*1.5;
_core.gui.extent_y_min -= h*EMVIEW_EXTENT_MARGIN;
elog(LOG_DEBUG(5), "Current extent of nodes: %f,%f -> %f,%f",
_core.gui.extent_x_min,_core.gui.extent_y_min,
_core.gui.extent_x_max,_core.gui.extent_y_max);
}
/*
* status report
*/
static
int emview_nodes_status_printable(status_context_t *info, buf_t *buf)
{
int now = time(0);
node_t *n;
bufprintf(buf, "Nodes:\n");
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n)) {
bufprintf(buf, " %d: (%.2f,%.2f), [%d,%d:%d,%d], %s%s%s",
n->id, n->pos.x, n->pos.y,
n->display.bx1, n->display.by1,
n->display.bx2, n->display.by2,
n->visible ? "Visible, " : "",
n->active ? "Active, " : "",
n->referenced ? "Referenced, " : "");
if (n->last_heard > 0)
bufprintf(buf, "last heard %d secs ago\n",
now - n->last_heard);
else
bufprintf(buf, "never heard\n");
emview_component_list_status_printable(&(n->display.components), buf);
bufprintf(buf, " Slots:\n");
emview_slots_list_status_printable(&(n->display.slots), buf, 0);
}
return STATUS_MSG_COMPLETE;
}
void emview_node_list_init()
{
_core.node_list.fast_node_lookup = g_hash_table_new(g_direct_hash, g_direct_equal);
g_timer_add(EMVIEW_NODE_INACTIVITY_CHECK, emview_node_check_timeouts,
NULL, NULL, &(_core.node_list.node_timeout));
/* configure (optional) status device */
{
status_dev_opts_t opts = {
device: {
devname: "/dev/emview/nodes"
},
printable: emview_nodes_status_printable
};
g_status_dev(&opts, &(_core.node_list.stat));
}
}
See more files for this project here