libgeda

s_conn.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <ctype.h>
00024 #ifdef HAVE_STDLIB_H
00025 #include <stdlib.h>
00026 #endif
00027 
00028 #include "libgeda_priv.h"
00029 
00030 #ifdef HAVE_LIBDMALLOC
00031 #include <dmalloc.h>
00032 #endif
00033 
00059 CONN *s_conn_return_new(OBJECT * other_object, int type, int x, int y,
00060             int whichone, int other_whichone)
00061 {
00062   CONN *new_conn;
00063 
00064   new_conn = (CONN *) g_malloc(sizeof(CONN));
00065 
00066 #if DEBUG
00067   printf("** creating: %s %d %d\n", other_object->name, x, y);
00068 #endif
00069 
00070   new_conn->other_object = other_object;
00071   new_conn->type = type;
00072   new_conn->x = x;
00073   new_conn->y = y;
00074   new_conn->whichone = whichone;
00075   new_conn->other_whichone = other_whichone;
00076 
00077   return (new_conn);
00078 }
00079 
00088 int s_conn_uniq(GList * conn_list, CONN * input_conn)
00089 {
00090   GList *c_current;
00091   CONN *conn;
00092 
00093   c_current = conn_list;
00094   while (c_current != NULL) {
00095     conn = (CONN *) c_current->data;
00096 
00097     if (conn->other_object == input_conn->other_object &&
00098         conn->x == input_conn->x && conn->y == input_conn->y &&
00099         conn->type == input_conn->type) {
00100       return (FALSE);
00101     }
00102 
00103     c_current = g_list_next(c_current);
00104   }
00105 
00106   return (TRUE);
00107 }
00108 
00118 int s_conn_remove_other (TOPLEVEL *toplevel, OBJECT *other_object,
00119                          OBJECT *to_remove)
00120 {
00121     GList *c_current = NULL;
00122     CONN *conn = NULL;
00123 
00124     o_emit_pre_change_notify (toplevel, other_object);
00125 
00126     c_current = other_object->conn_list;
00127     while (c_current != NULL) {
00128     conn = (CONN *) c_current->data;
00129 
00130     if (conn->other_object == to_remove) {
00131         other_object->conn_list =
00132         g_list_remove(other_object->conn_list, conn);
00133 
00134 #if DEBUG
00135         printf("Found other_object in remove_other\n");
00136         printf("Freeing other: %s %d %d\n", conn->other_object->name,
00137            conn->x, conn->y);
00138 #endif
00139 
00140         /* Do not write modify c_current like this, since this will cause */
00141         /* very nasty data corruption and upset glib's memory slice */
00142         /* allocator. */
00143         /* c_current->data = NULL;   Do not comment in */
00144 
00145         g_free(conn);
00146 
00147 #if 0 /* this does not work right */
00148             if (other_object->type == OBJ_BUS &&
00149                 other_object->conn_list == NULL) {
00150               other_object->bus_ripper_direction = 0;
00151             }
00152 #endif
00153         s_conn_emit_conns_changed (toplevel, other_object);
00154             
00155         return (TRUE);
00156     }
00157 
00158     c_current = g_list_next(c_current);
00159     }
00160 
00161     o_emit_change_notify (toplevel, other_object);
00162 
00163     return (FALSE);
00164 }
00165 
00175 static void s_conn_remove_glist (TOPLEVEL *toplevel, GList *obj_list)
00176 {
00177   OBJECT *o_current;
00178   GList *iter;
00179 
00180   for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
00181     o_current = iter->data;
00182     s_conn_remove_object (toplevel, o_current);
00183   }
00184 }
00185 
00193 void s_conn_remove_object (TOPLEVEL *toplevel, OBJECT *to_remove)
00194 {
00195   GList *c_iter;
00196   CONN *conn;
00197 
00198   switch (to_remove->type) {
00199     case OBJ_PIN:
00200     case OBJ_NET:
00201     case OBJ_BUS:
00202       for (c_iter = to_remove->conn_list;
00203            c_iter != NULL;
00204            c_iter = g_list_next (c_iter)) {
00205         conn = c_iter->data;
00206 
00207 
00208         s_conn_freeze_hooks (toplevel, conn->other_object);
00209         /* keep calling this till it returns false (all refs removed) */
00210         /* there is NO body to this while loop */
00211         while (s_conn_remove_other (toplevel, conn->other_object, to_remove));
00212 
00213         c_iter->data = NULL;
00214         s_conn_thaw_hooks (toplevel, conn->other_object);
00215         g_free (conn);
00216       }
00217 
00218       g_list_free (to_remove->conn_list);
00219       to_remove->conn_list = NULL;
00220       break;
00221 
00222     case OBJ_COMPLEX:
00223     case OBJ_PLACEHOLDER:
00224       s_conn_remove_glist (toplevel, to_remove->complex->prim_objs);
00225       break;
00226   }
00227 
00228   s_conn_emit_conns_changed (toplevel, to_remove);
00229 }
00230 
00240 OBJECT *s_conn_check_midpoint(OBJECT *o_current, int x, int y)
00241 {
00242   int min_x, min_y, max_x, max_y;
00243 
00244   switch(o_current->type) {
00245     case(OBJ_NET):
00246     case(OBJ_PIN):
00247     case(OBJ_BUS):
00248       min_y = min(o_current->line->y[0], 
00249                   o_current->line->y[1]);
00250       max_y = max(o_current->line->y[0], 
00251                   o_current->line->y[1]);
00252 
00253                 /* vertical */
00254       if ( (o_current->line->x[0] == x) &&
00255            (y > min_y) && (y < max_y) &&
00256            (o_current->line->x[0] ==
00257             o_current->line->x[1]) ) {
00258 #if DEBUG
00259         printf("Found vertical point\n");
00260 #endif
00261         return(o_current);
00262       }
00263 
00264       min_x = min(o_current->line->x[0], 
00265                   o_current->line->x[1]);
00266       max_x = max(o_current->line->x[0], 
00267                   o_current->line->x[1]);
00268 
00269                 /* horizontal */
00270       if ( (o_current->line->y[0] == y) &&
00271            (x > min_x) && (x < max_x) &&
00272            (o_current->line->y[0] ==
00273             o_current->line->y[1]) ) {
00274 #if DEBUG
00275         printf("Found horizontal point\n");
00276 #endif
00277         return(o_current);
00278       }
00279 
00280       break;
00281   }
00282   return(NULL);
00283 }
00284 
00294 void s_conn_update_glist (TOPLEVEL *toplevel, GList *obj_list)
00295 {
00296   OBJECT *o_current;
00297   GList *iter;
00298 
00299   for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
00300     o_current = iter->data;
00301     s_conn_update_object (toplevel, o_current);
00302   }
00303 }
00304 
00305 
00314 static int is_bus_related (OBJECT *object)
00315 {
00316   return (object->type == OBJ_BUS ||
00317            (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_BUS));
00318 }
00319 
00320 
00330 static int check_direct_compat (OBJECT *object1, OBJECT *object2)
00331 {
00332   return (is_bus_related (object1) == is_bus_related (object2));
00333 }
00334 
00335 
00336 static void add_connection (TOPLEVEL *toplevel,
00337                             OBJECT *object, OBJECT *other_object,
00338                             int type, int x, int y,
00339                             int whichone, int other_whichone)
00340 {
00341   /* Describe the connection */
00342   CONN *new_conn = s_conn_return_new (other_object, type, x, y,
00343                                       whichone, other_whichone);
00344   /* Do uniqness check */
00345   if (s_conn_uniq (object->conn_list, new_conn)) {
00346     object->conn_list = g_list_append (object->conn_list, new_conn);
00347     s_conn_emit_conns_changed (toplevel, object);
00348     s_conn_emit_conns_changed (toplevel, other_object);
00349   } else {
00350     g_free (new_conn);
00351   }
00352 }
00353 
00363 static void s_conn_update_line_object (TOPLEVEL *toplevel, OBJECT *object)
00364 {
00365   TILE *t_current;
00366   GList *tl_current;
00367   GList *object_list;
00368   OBJECT *other_object;
00369   OBJECT *found;
00370   int j, k;
00371 
00372   s_conn_freeze_hooks (toplevel, object);
00373 
00374   /* loop over all tiles which object appears in */
00375   for (tl_current = object->tiles;
00376        tl_current != NULL;
00377        tl_current = g_list_next (tl_current)) {
00378     t_current = tl_current->data;
00379 
00380     for (object_list = t_current->objects;
00381          object_list != NULL;
00382          object_list = g_list_next (object_list)) {
00383       other_object = object_list->data;
00384 
00385       if (object == other_object)
00386         continue;
00387 
00388       s_conn_freeze_hooks (toplevel, other_object);
00389 
00390       /* Here is where you check the end points */
00391       /* Check both end points of the other object */
00392       for (k = 0; k < 2; k++) {
00393 
00394         /* If the other object is a pin, only check the correct end */
00395         if (other_object->type == OBJ_PIN && other_object->whichend != k)
00396           continue;
00397 
00398         /* Check both end points of the object */
00399         for (j = 0; j < 2; j++) {
00400 
00401           /* If the object is a pin, only check the correct end */
00402           if (object->type == OBJ_PIN && object->whichend != j)
00403             continue;
00404 
00405           /* Check for coincidence and compatability between
00406              the objects being tested. */
00407           if (object->line->x[j] == other_object->line->x[k] &&
00408               object->line->y[j] == other_object->line->y[k] &&
00409               check_direct_compat (object, other_object)) {
00410 
00411             o_emit_pre_change_notify (toplevel, other_object);
00412 
00413             add_connection (toplevel, object, other_object, CONN_ENDPOINT,
00414                             other_object->line->x[k],
00415                             other_object->line->y[k], j, k);
00416 
00417             add_connection (toplevel, other_object, object, CONN_ENDPOINT,
00418                             object->line->x[j],
00419                             object->line->y[j], k, j);
00420 
00421             o_emit_change_notify (toplevel, other_object);
00422           }
00423         }
00424       }
00425 
00426       /* Check both end points of the object against midpoints of the other */
00427       for (k = 0; k < 2; k++) {
00428 
00429         /* If the object is a pin, only check the correct end */
00430         if (object->type == OBJ_PIN && object->whichend != k)
00431           continue;
00432 
00433         /* check for midpoint of other object, k endpoint of current obj*/
00434         found = s_conn_check_midpoint (other_object, object->line->x[k],
00435                                                      object->line->y[k]);
00436 
00437         /* Pins are not allowed midpoint connections onto them. */
00438         /* Allow nets to connect to the middle of buses. */
00439         /* Allow compatible objects to connect. */
00440         if (found && other_object->type != OBJ_PIN &&
00441             ((object->type == OBJ_NET && other_object->type == OBJ_BUS) ||
00442               check_direct_compat (object, other_object))) {
00443 
00444           add_connection (toplevel, object, other_object, CONN_MIDPOINT,
00445                           object->line->x[k],
00446                           object->line->y[k], k, -1);
00447 
00448           add_connection (toplevel, other_object, object, CONN_MIDPOINT,
00449                           object->line->x[k],
00450                           object->line->y[k], -1, k);
00451 
00452         }
00453       }
00454 
00455       /* Check both end points of the other object against midpoints of the first */
00456       for (k = 0; k < 2; k++) {
00457 
00458         /* If the other object is a pin, only check the correct end */
00459         if (other_object->type == OBJ_PIN && other_object->whichend != k)
00460           continue;
00461 
00462         /* do object's endpoints cross the middle of other_object? */
00463         /* check for midpoint of other object, k endpoint of current obj*/
00464         found = s_conn_check_midpoint (object, other_object->line->x[k],
00465                                                other_object->line->y[k]);
00466 
00467         /* Pins are not allowed midpoint connections onto them. */
00468         /* Allow nets to connect to the middle of buses. */
00469         /* Allow compatible objects to connect. */
00470         if (found && object->type != OBJ_PIN &&
00471              ((object->type == OBJ_BUS && other_object->type == OBJ_NET) ||
00472                check_direct_compat (object, other_object))) {
00473 
00474           add_connection (toplevel, object, other_object, CONN_MIDPOINT,
00475                           other_object->line->x[k],
00476                           other_object->line->y[k], -1, k);
00477 
00478           add_connection (toplevel, other_object, object, CONN_MIDPOINT,
00479                           other_object->line->x[k],
00480                           other_object->line->y[k], k, -1);
00481         }
00482       }
00483 
00484       s_conn_thaw_hooks (toplevel, other_object);
00485     }
00486   }
00487 
00488 #if DEBUG
00489   s_conn_print(object->conn_list);
00490 #endif
00491 
00492   s_conn_thaw_hooks (toplevel, object);
00493 }
00494 
00505 void s_conn_update_object (TOPLEVEL *toplevel, OBJECT *object)
00506 {
00507   switch (object->type) {
00508     case OBJ_PIN:
00509     case OBJ_NET:
00510     case OBJ_BUS:
00511       s_conn_update_line_object (toplevel, object);
00512       break;
00513 
00514     case OBJ_COMPLEX:
00515     case OBJ_PLACEHOLDER:
00516       s_conn_update_glist (toplevel, object->complex->prim_objs);
00517       break;
00518   }
00519 }
00520 
00526 void s_conn_print(GList * conn_list)
00527 {
00528   CONN *conn;
00529   GList *cl_current;
00530 
00531   printf("\nStarting s_conn_print\n");
00532   cl_current = conn_list;
00533   while (cl_current != NULL) {
00534 
00535     conn = (CONN *) cl_current->data;
00536     printf("-----------------------------------\n");
00537     printf("other object: %s\n", conn->other_object->name);
00538     printf("type: %d\n", conn->type);
00539     printf("x: %d y: %d\n", conn->x, conn->y);
00540     printf("whichone: %d\n", conn->whichone);
00541     printf("other_whichone: %d\n", conn->other_whichone);
00542     printf("-----------------------------------\n");
00543 
00544     cl_current = g_list_next(cl_current);
00545   }
00546 
00547 }
00548 
00560 int s_conn_net_search(OBJECT* new_net, int whichone, GList * conn_list)
00561 {
00562   CONN *conn;
00563   GList *cl_current;
00564 
00565   cl_current = conn_list;
00566   while (cl_current != NULL) {
00567 
00568     conn = (CONN *) cl_current->data;
00569     if (conn != NULL && conn->whichone == whichone && 
00570         conn->x == new_net->line->x[whichone] &&
00571     conn->y == new_net->line->y[whichone])
00572     {
00573        return TRUE;
00574     }
00575 
00576     cl_current = g_list_next(cl_current);
00577   }
00578  
00579   return FALSE;
00580 }
00581 
00596 static GList *s_conn_return_glist_others (GList *input_list, GList *obj_list)
00597 {
00598   GList *return_list;
00599   GList *iter;
00600   OBJECT *o_current;
00601 
00602   return_list = input_list;
00603 
00604   for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
00605     o_current = iter->data;
00606     return_list = s_conn_return_others (return_list, o_current);
00607   }
00608 
00609   return return_list;
00610 }
00611 
00627 GList *s_conn_return_others(GList *input_list, OBJECT *object)
00628 {
00629   GList *c_iter;
00630   GList *return_list;
00631 
00632   return_list = input_list;
00633 
00634   switch (object->type) {
00635     case OBJ_PIN:
00636     case OBJ_NET:
00637     case OBJ_BUS:
00638       for (c_iter = object->conn_list;
00639            c_iter != NULL; c_iter = g_list_next (c_iter)) {
00640         CONN *conn = c_iter->data;
00641 
00642         if (conn->other_object && conn->other_object != object) {
00643           return_list = g_list_append(return_list, conn->other_object);
00644         }
00645       }
00646       break;
00647 
00648     case OBJ_COMPLEX:
00649     case OBJ_PLACEHOLDER:
00650       return_list = s_conn_return_glist_others (return_list,
00651                                                 object->complex->prim_objs);
00652       break;
00653   }
00654 
00655   return return_list;
00656 }
00657 
00658 
00659 typedef struct {
00660   ConnsChangedFunc func;
00661   void *data;
00662 } ConnsChangedHook;
00663 
00664 
00665 void s_conn_append_conns_changed_hook (TOPLEVEL *toplevel,
00666                                        ConnsChangedFunc func,
00667                                        void *data)
00668 {
00669   ConnsChangedHook *new_hook;
00670 
00671   new_hook = g_new0 (ConnsChangedHook, 1);
00672   new_hook->func = func;
00673   new_hook->data = data;
00674 
00675   toplevel->conns_changed_hooks =
00676     g_list_append (toplevel->conns_changed_hooks, new_hook);
00677 }
00678 
00679 
00680 static void call_conns_changed_hook (gpointer data, gpointer user_data)
00681 {
00682   ConnsChangedHook *hook = data;
00683   OBJECT *object = user_data;
00684 
00685   hook->func (hook->data, object);
00686 }
00687 
00688 
00689 void s_conn_emit_conns_changed (TOPLEVEL *toplevel, OBJECT *object)
00690 {
00691   if (object->conn_notify_freeze_count > 0) {
00692     object->conn_notify_pending = 1;
00693     return;
00694   }
00695 
00696   object->conn_notify_pending = 0;
00697 
00698   g_list_foreach (toplevel->conns_changed_hooks,
00699                   call_conns_changed_hook, object);
00700 }
00701 
00702 void s_conn_freeze_hooks (TOPLEVEL *toplevel, OBJECT *object)
00703 {
00704   object->conn_notify_freeze_count += 1;
00705 }
00706 
00707 void s_conn_thaw_hooks (TOPLEVEL *toplevel, OBJECT *object)
00708 {
00709   g_return_if_fail (object->conn_notify_freeze_count > 0);
00710 
00711   object->conn_notify_freeze_count -= 1;
00712 
00713   if (object->conn_notify_freeze_count == 0 &&
00714       object->conn_notify_pending)
00715     s_conn_emit_conns_changed (toplevel, object);
00716 }
00717 
00718 static void refresh_connectivity_cache (TOPLEVEL *toplevel, OBJECT *object)
00719 {
00720     if (object->type == OBJ_NET) {
00721         /* FIXME: suboptimal to refresh cache every time */
00722         /* better approach would invalidate cache without refresh */
00723         /* refresh would be done on redraw of pin cues */
00724         o_net_refresh_conn_cache (toplevel, object);
00725     }
00726 }
00727 
00728 static void s_conn_init_toplevel (TOPLEVEL *toplevel)
00729 {
00730     /* Connect the hooks for tracking net connectivity here */
00731     s_conn_append_conns_changed_hook (toplevel,
00732                                       (ConnsChangedFunc)
00733                                           refresh_connectivity_cache,
00734                                       toplevel);
00735 
00736     o_attrib_append_attribs_changed_hook (toplevel,
00737                                           (AttribsChangedFunc)
00738                                               refresh_connectivity_cache,
00739                                           toplevel);
00740 }
00741 
00742 void s_conn_init (void)
00743 {
00744     s_toplevel_append_new_hook ((NewToplevelFunc) s_conn_init_toplevel,
00745                                 NULL);
00746 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines