libgeda
|
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 }