/*! \brief consolidate all net objects * \par Function Description * This function consolidates all net objects in a page until no more * consolidations are possible. * * \param toplevel The TOPLEVEL object. * \param page The PAGE to consolidate nets in. */ void o_net_consolidate(TOPLEVEL *toplevel, PAGE *page) { OBJECT *o_current; const GList *iter; int status = 0; g_return_if_fail (toplevel != NULL); g_return_if_fail (page != NULL); iter = s_page_objects (page); while (iter != NULL) { o_current = (OBJECT *)iter->data; if (o_current->type == OBJ_NET) { status = o_net_consolidate_segments(toplevel, o_current); } if (status == -1) { iter = s_page_objects (page); status = 0; } else { iter = g_list_next (iter); } } }
/*! \brief Updates the preview widget. * \par Function Description * This function update the preview: if the preview is active and a * filename has been given, it opens the file and display * it. Otherwise it display a blank page. * * \param [in] preview The preview widget. */ static void preview_update (Preview *preview) { GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current; TOPLEVEL *preview_toplevel = preview_w_current->toplevel; int left, top, right, bottom; int width, height; if (preview_toplevel->page_current == NULL) { return; } /* delete old preview, create new page */ /* it would be better to just resets current page - Fix me */ s_page_delete (preview_toplevel, preview_toplevel->page_current); s_page_goto (preview_toplevel, s_page_new (preview_toplevel, "preview")); if (preview->active) { g_assert ((preview->filename == NULL) || (preview->buffer == NULL)); if (preview->filename != NULL) { /* open up file in current page */ f_open_flags (preview_toplevel, preview_toplevel->page_current, preview->filename, F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL); /* test value returned by f_open... - Fix me */ /* we should display something if there an error occured - Fix me */ } if (preview->buffer != NULL) { /* Load the data buffer */ s_page_append_list (preview_toplevel, preview_toplevel->page_current, o_read_buffer (preview_toplevel, NULL, preview->buffer, -1, _("Preview Buffer"))); } } if (world_get_object_glist_bounds (preview_toplevel, s_page_objects (preview_toplevel->page_current), &left, &top, &right, &bottom)) { /* Clamp the canvas size to the extents of the page being previewed */ width = right - left; height = bottom - top; preview_toplevel->init_left = left - ((double)width * OVER_ZOOM_FACTOR); preview_toplevel->init_right = right + ((double)width * OVER_ZOOM_FACTOR); preview_toplevel->init_top = top - ((double)height * OVER_ZOOM_FACTOR); preview_toplevel->init_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR); } /* display current page (possibly empty) */ a_zoom_extents (preview_w_current, s_page_objects (preview_toplevel->page_current), A_PAN_DONT_REDRAW); o_invalidate_all (preview_w_current); }
/*! \brief Completes initialitation of the widget after realization. * \par Function Description * This function terminates the initialization of preview's GSCHEM_TOPLEVEL * and TOPLEVEL environments after the widget has been realized. * * It creates a preview page in the TOPLEVEL environment. * * \param [in] widget The preview widget. * \param [in] user_data Unused user data. */ static void preview_callback_realize (GtkWidget *widget, gpointer user_data) { Preview *preview = PREVIEW (widget); GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current; TOPLEVEL *preview_toplevel = preview_w_current->toplevel; PAGE *preview_page; preview_w_current->window = preview_w_current->drawing_area->window; gtk_widget_grab_focus (preview_w_current->drawing_area); preview_toplevel->width = preview_w_current->drawing_area->allocation.width; preview_toplevel->height = preview_w_current->drawing_area->allocation.height; preview_w_current->win_width = preview_toplevel->width; preview_w_current->win_height = preview_toplevel->height; preview_w_current->drawable = preview_w_current->window; x_window_setup_gc (preview_w_current); preview_page = s_page_new (preview_toplevel, "unknown"); s_page_goto (preview_toplevel, preview_page); a_zoom_extents(preview_w_current, s_page_objects (preview_page), A_PAN_DONT_REDRAW); o_invalidate_all (preview_w_current); }
/* otherwise unembed all components in all pages */ void s_util_embed(TOPLEVEL *pr_current, int embed_mode) { GList *p_iter, *o_iter; for (p_iter = geda_list_get_glist (pr_current->pages); p_iter != NULL; p_iter = g_list_next (p_iter)) { PAGE *p_current = p_iter->data; /* Cast removes const qualifier from return value of * s_page_objects() */ for (o_iter = (GList *) s_page_objects (p_current); o_iter != NULL; o_iter = g_list_next (o_iter)) { OBJECT *o_current = o_iter->data; if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PICTURE) { if (embed_mode == TRUE) { o_embed(pr_current, o_current); } else { o_unembed(pr_current, o_current); } } } } }
/* Actually draws a page. If page is NULL, uses the first open page. */ static void export_draw_page (PAGE *page) { const GList *contents; GList *iter; cairo_t *cr; cr = eda_renderer_get_cairo_context (renderer); if (page == NULL) { const GList *pages = geda_list_get_glist (toplevel->pages); g_assert (pages != NULL && pages->data != NULL); page = (PAGE *) pages->data; } /* Draw background */ eda_cairo_set_source_color (cr, OUTPUT_BACKGROUND_COLOR, eda_renderer_get_color_map (renderer)); cairo_paint (cr); /* Draw objects & cues */ contents = s_page_objects (page); for (iter = (GList *) contents; iter != NULL; iter = g_list_next (iter)) eda_renderer_draw (renderer, (OBJECT *) iter->data); for (iter = (GList *) contents; iter != NULL; iter = g_list_next (iter)) eda_renderer_draw_cues (renderer, (OBJECT *) iter->data); }
/*! \brief get the subpages of a schematic page * * if any subpages are not loaded, this function will load them. * * \param [in] page the parent page * \return a list of all the subpages */ static GList* get_subpages (PAGE *page) { const GList *object_iter; GList *page_list = NULL; g_return_val_if_fail (page != NULL, NULL); object_iter = s_page_objects (page); while (object_iter != NULL) { char *attrib; char **filenames; char **iter; OBJECT *object = (OBJECT*) object_iter->data; object_iter = g_list_next (object_iter); if (object == NULL) { g_warning ("NULL object encountered"); continue; } if (object->type != OBJ_COMPLEX) { continue; } attrib = o_attrib_search_attached_attribs_by_name (object, "source", 0); if (attrib == NULL) { attrib = o_attrib_search_inherited_attribs_by_name (object, "source", 0); } if (attrib == NULL) { continue; } filenames = g_strsplit (attrib, ",", 0); if (filenames == NULL) { continue; } for (iter = filenames; *iter != NULL; iter++) { PAGE *subpage = s_hierarchy_load_subpage (page, *iter, NULL); if (subpage != NULL) { page_list = g_list_prepend (page_list, subpage); } } g_strfreev (filenames); } return g_list_reverse (page_list); }
/*! \brief Find all text objects that match a pattern * * \param pages the list of pages to search * \param text the pattern to match * \return a list of objects that match the given pattern */ static GSList* find_objects_using_pattern (GSList *pages, const char *text) { GSList *object_list = NULL; GSList *page_iter = pages; GPatternSpec *pattern; g_return_val_if_fail (text != NULL, NULL); pattern = g_pattern_spec_new (text); while (page_iter != NULL) { const GList *object_iter; PAGE *page = (PAGE*) page_iter->data; page_iter = g_slist_next (page_iter); if (page == NULL) { g_warning ("NULL page encountered"); continue; } object_iter = s_page_objects (page); while (object_iter != NULL) { OBJECT *object = (OBJECT*) object_iter->data; const char *str; object_iter = g_list_next (object_iter); if (object == NULL) { g_warning ("NULL object encountered"); continue; } if (object->type != OBJ_TEXT) { continue; } if (!(o_is_visible (page->toplevel, object) || page->toplevel->show_hidden_text)) { continue; } str = geda_text_object_get_string (object); if (str == NULL) { g_warning ("NULL string encountered"); continue; } if (g_pattern_match_string (pattern, str)) { object_list = g_slist_prepend (object_list, object); } } } g_pattern_spec_free (pattern); return g_slist_reverse (object_list); }
/*! \brief Verify the entire design * * This function loops through all components in the * design looking for components which are placeholders. * * Placeholders are inserted into the object list when * no symbol file is found. If this function finds a * placeholder, it warns the user. * * \param toplevel pointer to the toplevel object to be verified */ void s_toplevel_verify_design (TOPLEVEL *toplevel) { GList *p_iter; const GList *o_iter; int missing_sym_flag = 0; for (p_iter = geda_list_get_glist (toplevel->pages); p_iter != NULL; p_iter = g_list_next (p_iter)) { PAGE *p_current = p_iter->data; for (o_iter = s_page_objects (p_current); o_iter != NULL; o_iter = g_list_next (o_iter)) { OBJECT *o_current = o_iter->data; /* --- look for object, and verify that it has a symbol file attached. ---- */ if (o_current->type == OBJ_PLACEHOLDER) { missing_sym_flag = 1; /* flag to signal that problem exists. */ } } } if (missing_sym_flag) { x_dialog_missing_sym(); /* dialog gives user option to quit */ } }
void s_traverse_start(TOPLEVEL * pr_current) { GList *iter; PAGE *p_current; for ( iter = geda_list_get_glist( pr_current->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; /* only traverse pages which are toplevel, ie not underneath */ if (p_current->page_control == 0) { pr_current->page_current = p_current; s_traverse_sheet (pr_current, s_page_objects (p_current), NULL); } } /* now that all the sheets have been read, go through and do the */ /* post processing work */ s_netlist_post_process(pr_current, netlist_head); /* Now match the graphical netlist with the net names already assigned */ s_netlist_name_named_nets(pr_current, netlist_head, graphical_netlist_head); if (verbose_mode) { printf("\nInternal netlist representation:\n\n"); s_netlist_print(netlist_head); } }
/*! \brief Get a list of symbols used. * \par Function Description * * Scan a #TOPLEVEL structure's object list looking for symbols, and * return them in a list. * * \warning The #CLibSymbol instances in the \b GList returned belong * to the component library, and should be considered constants; they * should not be manipulated or free()'d. On the other hand, the \b * GList returned must be freed with \b g_list_free() when no longer * needed. Note that the values returned will be invalidated by a * call to s_clib_free() or s_clib_refresh(). * * \bug Only includes components which are not embedded, but they * should (probably) also appear in the list. * * \param toplevel #TOPLEVEL structure to scan. * \return GList of symbols. */ GList *s_toplevel_get_symbols (const TOPLEVEL *toplevel) { GList *result = NULL; GList *iter = NULL; OBJECT *o = NULL; PAGE *page; GList *symlist = NULL; CLibSymbol *sym = NULL; const GList *p_iter; const GList *o_iter; g_return_val_if_fail ((toplevel != NULL), NULL); for ( p_iter = geda_list_get_glist( toplevel->pages ); p_iter != NULL; p_iter = g_list_next( p_iter )) { page = (PAGE *)p_iter->data; for (o_iter = s_page_objects (page); o_iter != NULL; o_iter = g_list_next (o_iter)) { o = (OBJECT *)o_iter->data; if (o->type != OBJ_COMPLEX) continue; if (o->complex_basename == NULL) continue; /* Since we're not looking at embedded symbols, the first * component with the given name will be the one we need. * N.b. we don't use s_clib_get_symbol_by_name() because it's * spammeh. */ symlist = s_clib_search (o->complex_basename, CLIB_EXACT); if (symlist == NULL) continue; sym = (CLibSymbol *) symlist->data; g_list_free (symlist); /* We do the list insertion by evilly comparing pointers. This * is okay, because we always take the first symbol with the * given name, and symbol pointers don't change while this * function is running (we hope). Note that this creates a * sorted list.*/ for (iter = result; iter != NULL; iter = g_list_next(iter)) { if (iter->data == sym) { break; /* Already in list */ } if (compare_symbol_name (iter->data, sym) > 0) { /* not in list yet, and gone past point where it should go */ result = g_list_insert_before (result, iter, sym); break; } } if (iter == NULL) { /* not in list yet, and at end of list */ result = g_list_append (result, sym); } } } return result; }
CPINLIST *s_traverse_component(TOPLEVEL * pr_current, OBJECT * component, char *hierarchy_tag) { CPINLIST *cpinlist_head = NULL; CPINLIST *cpins = NULL; NET *nets_head = NULL; NET *nets = NULL; GList *iter; cpinlist_head = cpins = s_cpinlist_add(NULL); cpins->plid = -1; for (iter = component->complex->prim_objs; iter != NULL; iter = g_list_next (iter)) { OBJECT *o_current = iter->data; /* Ignore objects which aren't net pins */ if (o_current->type != OBJ_PIN || o_current->pin_type != PIN_TYPE_NET) continue; /* add cpin node */ cpins = s_cpinlist_add(cpins); cpins->plid = o_current->sid; cpins->type = o_current->pin_type; cpins->pin_number = o_attrib_search_object_attribs_by_name (o_current, "pinnumber", 0); cpins->pin_label = o_attrib_search_object_attribs_by_name (o_current, "pinlabel", 0); /* head nets node */ /* is this really need */ nets_head = nets = s_net_add(NULL); nets->nid = -1; /* This avoids us adding an unnamed net for an unconnected pin */ if (o_current->conn_list != NULL) { s_traverse_net (pr_current, nets, TRUE, o_current, hierarchy_tag, cpins->type); s_traverse_clear_all_visited (s_page_objects (pr_current->page_current)); } cpins->nets = nets_head; /* s_net_print(nets); */ } return (cpinlist_head); }
/*! \brief Return the objects in a page. * \par Function Description * Returns an object smob list with all the objects in the given page. * \param [in] page_smob Page to look at. * \return the object smob list with the objects in the page. * */ SCM g_get_objects_in_page(SCM page_smob) { TOPLEVEL *toplevel; PAGE *page; OBJECT *object; const GList *iter; SCM return_list=SCM_EOL; /* Get toplevel and the page */ SCM_ASSERT (g_get_data_from_page_smob (page_smob, &toplevel, &page), page_smob, SCM_ARG1, "add-component"); if (page && s_page_objects (page)) { iter = s_page_objects (page); while (iter != NULL) { object = (OBJECT *)iter->data; return_list = scm_cons (g_make_object_smob(toplevel, object), return_list); iter = g_list_next (iter); } } return return_list; }
static gboolean preview_event_configure (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { gboolean retval; GSCHEM_TOPLEVEL *preview_w_current = PREVIEW (widget)->preview_w_current; PAGE *preview_page = preview_w_current->toplevel->page_current; retval = x_event_configure (widget, event, preview_w_current); if (preview_page != NULL) { a_zoom_extents(preview_w_current, s_page_objects (preview_page), 0); } return retval; }
int s_check_all(TOPLEVEL *pr_current) { GList *iter; PAGE *p_current; int return_status=0; for ( iter = geda_list_get_glist( pr_current->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; if (s_page_objects (p_current)) { return_status = return_status + s_check_symbol (pr_current, p_current, s_page_objects (p_current)); if (!quiet_mode) s_log_message("\n"); } } return(return_status); }
/*! \brief Export a figure-style PDF file of the current page. * \par Function Description * Exports the current page as a PDF file to \a filename. The export * is carried out using a page size matching the size of the visible * extents of the schematic page. * * \param w_current A #GschemToplevel structure. * \param filename The filename for generated PDF. * * \returns TRUE if the operation was successful. */ gboolean x_print_export_pdf (GschemToplevel *w_current, const gchar *filename) { cairo_surface_t *surface; cairo_status_t cr_status; cairo_t *cr; int status, wx_min, wy_min, wx_max, wy_max; double width, height; /* First, calculate a transformation matrix for the cairo * context. We want to center the extents of the page in the * available page area. */ status = world_get_object_glist_bounds (w_current->toplevel, s_page_objects (w_current->toplevel->page_current), &wx_min, &wy_min, &wx_max, &wy_max); if (status) { width = (wx_max - wx_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI; height = (wy_max - wy_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI; } else { /* Fallback size if there are no drawable objects */ width = height = DEFAULT_PDF_SIZE; } surface = cairo_pdf_surface_create (filename, width, height); cr = cairo_create (surface); x_print_draw_page (w_current->toplevel, w_current->toplevel->page_current, cr, NULL, width, height, w_current->toplevel->image_color, FALSE); cairo_destroy (cr); cairo_surface_finish (surface); cr_status = cairo_surface_status (surface); if (cr_status != CAIRO_STATUS_SUCCESS) { g_warning (_("Failed to write PDF to '%1$s': %2$s\n"), filename, cairo_status_to_string (cr_status)); return FALSE; } cairo_surface_destroy (surface); return TRUE; }
/*! \brief Create a default page setup for a schematic page. * \par Function Description * Creates and returns a new #GtkPageSetup for \a page, taking into * account the requested \a paper_size_name. If \a paper_size_name is * NULL, the system default paper size is used. The \a orientation may * be LANDSCAPE, PORTRAIT or AUTOLAYOUT. If \a AUTOLAYOUT is chosen, * the page orientation that best fits the page contents is chosen. * * \param toplevel A #TOPLEVEL structure. * \param page The #PAGE to generate a page setup for. * \param paper_size_name The name of the paper size to use. * \param orientation The paper orientation to use. * * \returns A newly-created page setup. */ static GtkPageSetup * x_print_default_page_setup (TOPLEVEL *toplevel, PAGE *page) { GtkPageSetup *setup = gtk_page_setup_new (); GtkPaperSize *papersize; int status, wx_min, wy_min, wx_max, wy_max; EdaConfig *cfg; gchar *paper, *orientation; /* Get configuration values */ cfg = eda_config_get_context_for_path (s_page_get_filename (page)); paper = eda_config_get_string (cfg, CFG_GROUP_PRINTING, CFG_KEY_PRINTING_PAPER, NULL); orientation = eda_config_get_string (cfg, CFG_GROUP_PRINTING, CFG_KEY_PRINTING_ORIENTATION, NULL); /* If the paper size is valid, set it up with default margins. */ papersize = gtk_paper_size_new (paper); if (papersize != NULL) { gtk_page_setup_set_paper_size_and_default_margins (setup, papersize); } if (g_strcmp0 (orientation, "landscape") == 0) { gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE); } else if (g_strcmp0 (orientation, "portrait") == 0) { gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT); } else if (orientation == NULL || g_strcmp0 (orientation, "auto") == 0) { /* Automatically choose the orientation that fits best */ status = world_get_object_glist_bounds (toplevel, s_page_objects (page), &wx_min, &wy_min, &wx_max, &wy_max); if (!status || (wx_max - wx_min) > (wy_max - wy_min)) { /* Default to landscape */ gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE); } else { gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT); } } g_free (paper); g_free (orientation); return setup; }
/* still highly temp and doesn't work right */ SCM g_get_toplevel_attribute(SCM scm_wanted_attrib) { const GList *p_iter; PAGE *p_current; char *wanted_attrib; char *attrib_value = NULL; SCM scm_return_value; TOPLEVEL *toplevel = edascm_c_current_toplevel (); SCM_ASSERT(scm_is_string (scm_wanted_attrib), scm_wanted_attrib, SCM_ARG1, "gnetlist:get-toplevel-attribute"); wanted_attrib = scm_to_utf8_string (scm_wanted_attrib); for (p_iter = geda_list_get_glist (toplevel->pages); p_iter != NULL; p_iter = g_list_next (p_iter)) { p_current = p_iter->data; /* only look for first occurrance of the attribute on each page */ attrib_value = o_attrib_search_floating_attribs_by_name (s_page_objects (p_current), wanted_attrib, 0); /* Stop when we find the first one */ if (attrib_value != NULL) break; } free (wanted_attrib); if (attrib_value != NULL) { scm_return_value = scm_from_utf8_string (attrib_value); g_free (attrib_value); } else { scm_return_value = scm_from_utf8_string ("not found"); } return (scm_return_value); }
/*! \brief Search for first TOPLEVEL attribute. * \par Function Description * This function searches all loaded pages for the first * TOPLEVEL attribute found. * The caller is responsible for freeing the returned value. * See #o_attrib_search_toplevel() for other comments. * * \param [in] page_list Page list to search through. * \param [in] name Character string name to search for. * \return Character string from the found attribute, NULL otherwise. */ char *o_attrib_search_toplevel_all(GedaPageList *page_list, char *name) { const GList *iter; PAGE *p_current; char *ret_value=NULL; iter = geda_list_get_glist( page_list ); while( iter != NULL ) { p_current = (PAGE *)iter->data; /* only look for first occurrance of the attribute */ ret_value = o_attrib_search_toplevel (s_page_objects (p_current), name, 0); if (ret_value != NULL) { return(ret_value); } iter = g_list_next( iter ); } return(NULL); }
/*! \brief Do autosave on all pages that are marked. * \par Function Description * Looks for pages with the do_autosave_backup flag activated and * autosaves them. * * \param [in] w_current The GSCHEM_TOPLEVEL object to search for autosave's. */ void o_autosave_backups(GSCHEM_TOPLEVEL *w_current) { TOPLEVEL *toplevel = w_current->toplevel; GList *iter; PAGE *p_save, *p_current; gchar *backup_filename; gchar *real_filename; gchar *only_filename; gchar *dirname; mode_t saved_umask; mode_t mask; struct stat st; /* save current page */ p_save = toplevel->page_current; for ( iter = geda_list_get_glist( toplevel->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; if (p_current->do_autosave_backup == 0) { continue; } if (p_current->ops_since_last_backup != 0) { /* make p_current the current page of toplevel */ s_page_goto (toplevel, p_current); /* Get the real filename and file permissions */ real_filename = follow_symlinks (p_current->page_filename, NULL); if (real_filename == NULL) { s_log_message (_("o_autosave_backups: Can't get the real filename of %s."), p_current->page_filename); } else { /* Get the directory in which the real filename lives */ dirname = g_path_get_dirname (real_filename); only_filename = g_path_get_basename(real_filename); backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING, dirname, G_DIR_SEPARATOR, only_filename); /* If there is not an existing file with that name, compute the * permissions and uid/gid that we will use for the newly-created file. */ if (stat (real_filename, &st) != 0) { #if defined(HAVE_GETUID) && defined(HAVE_GETGID) struct stat dir_st; int result; #endif /* Use default permissions */ saved_umask = umask(0); st.st_mode = 0666 & ~saved_umask; umask(saved_umask); #if defined(HAVE_GETUID) && defined(HAVE_GETGID) st.st_uid = getuid (); result = stat (dirname, &dir_st); if (result == 0 && (dir_st.st_mode & S_ISGID)) st.st_gid = dir_st.st_gid; else st.st_gid = getgid (); #endif } g_free (dirname); g_free (only_filename); g_free (real_filename); /* Make the backup file writable before saving a new one */ if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) { saved_umask = umask(0); if (chmod(backup_filename, (S_IWRITE|S_IWGRP|S_IWOTH) & ((~saved_umask) & 0777)) != 0) { s_log_message (_("Could NOT set previous backup file [%s] read-write\n"), backup_filename); } umask(saved_umask); } if (o_save (toplevel, s_page_objects (toplevel->page_current), backup_filename, NULL)) { p_current->ops_since_last_backup = 0; p_current->do_autosave_backup = 0; /* Make the backup file readonly so a 'rm *' command will ask the user before deleting it */ saved_umask = umask(0); mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH); mask = (~mask)&0777; mask &= ((~saved_umask) & 0777); if (chmod(backup_filename,mask) != 0) { s_log_message (_("Could NOT set backup file [%s] readonly\n"), backup_filename); } umask(saved_umask); } else { s_log_message (_("Could NOT save backup file [%s]\n"), backup_filename); } g_free (backup_filename); } } } /* restore current page */ s_page_goto (toplevel, p_save); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * * <B>flag</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ALL * <DT>*</DT><DD>UNDO_VIEWPORT_ONLY * </DL> */ void o_undo_savestate (GschemToplevel *w_current, PAGE *page, int flag) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); char *filename = NULL; GList *object_list = NULL; int levels; UNDO *u_current; UNDO *u_current_next; GschemPageView *view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (view != NULL); g_return_if_fail (page != NULL); GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view); /* save autosave backups if necessary */ o_autosave_backups(w_current); if (w_current->undo_control == FALSE) { return; } if (flag == UNDO_ALL) { /* Increment the number of operations since last backup if auto-save is enabled */ if (toplevel->auto_save_interval != 0) { page->ops_since_last_backup++; } /* HACK */ /* Before we save the undo state, consolidate nets as necessary */ /* This is where the net consolidation call would have been * triggered before it was removed from o_save_buffer(). */ if (toplevel->net_consolidate == TRUE) geda_net_object_consolidate (toplevel, page); } if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) { filename = g_strdup_printf("%s%cgschem.save%d_%d.sch", tmp_path, G_DIR_SEPARATOR, prog_pid, undo_file_index++); /* Changed from f_save to o_save when adding backup copy creation. */ /* f_save manages the creaton of backup copies. This way, f_save is called only when saving a file, and not when saving an undo backup copy */ o_save (toplevel, s_page_objects (page), filename, NULL); } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) { object_list = o_glist_copy_all (toplevel, s_page_objects (page), object_list); } /* Clear Anything above current */ if (page->undo_current) { s_undo_remove_rest(toplevel, page->undo_current->next); page->undo_current->next = NULL; } else { /* undo current is NULL */ s_undo_remove_rest(toplevel, page->undo_bottom); page->undo_bottom = NULL; } page->undo_tos = page->undo_current; if (geometry != NULL) { page->undo_tos = s_undo_add(page->undo_tos, flag, filename, object_list, (geometry->viewport_left + geometry->viewport_right) / 2, (geometry->viewport_top + geometry->viewport_bottom) / 2, /* scale */ max (((double) abs (geometry->viewport_right - geometry->viewport_left) / geometry->screen_width), ((double) abs (geometry->viewport_top - geometry->viewport_bottom) / geometry->screen_height)), page->page_control, page->up); } else { page->undo_tos = s_undo_add(page->undo_tos, flag, filename, object_list, 0, /* center x */ 0, /* center y */ 0, /* scale */ page->page_control, page->up); } page->undo_current = page->undo_tos; if (page->undo_bottom == NULL) { page->undo_bottom = page->undo_tos; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(page->undo_bottom); printf("BOTTOM: %s\n", page->undo_bottom->filename); printf("TOS: %s\n", page->undo_tos->filename); printf("CURRENT: %s\n", page->undo_current->filename); printf("----\n"); #endif g_free(filename); /* Now go through and see if we need to free/remove some undo levels */ /* so we stay within the limits */ /* only check history every 10 undo savestates */ if (undo_file_index % 10) { return; } levels = s_undo_levels(page->undo_bottom); #if DEBUG printf("levels: %d\n", levels); #endif if (levels >= w_current->undo_levels + UNDO_PADDING) { levels = levels - w_current->undo_levels; #if DEBUG printf("Trimming: %d levels\n", levels); #endif u_current = page->undo_bottom; while (levels > 0) { /* Because we use a pad you are always guaranteed to never */ /* exhaust the list */ g_assert (u_current != NULL); u_current_next = u_current->next; if (u_current->filename) { #if DEBUG printf("Freeing: %s\n", u_current->filename); #endif unlink(u_current->filename); g_free(u_current->filename); } if (u_current->object_list) { geda_object_list_delete (toplevel, u_current->object_list); u_current->object_list = NULL; } u_current->next = NULL; u_current->prev = NULL; g_free(u_current); u_current = u_current_next; levels--; } g_assert (u_current != NULL); u_current->prev = NULL; page->undo_bottom = u_current; #if DEBUG printf("New current is: %s\n", u_current->filename); #endif } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(page->undo_bottom); printf("BOTTOM: %s\n", page->undo_bottom->filename); printf("TOS: %s\n", page->undo_tos->filename); printf("CURRENT: %s\n", page->undo_current->filename); printf("----\n"); #endif }
/*! \brief Find all text objects that match a regex * * \param pages the list of pages to search * \param text the regex to match * \return a list of objects that match the given regex */ static GSList* find_objects_using_regex (GSList *pages, const char *text, GError **error) { GError *ierror = NULL; GSList *object_list = NULL; GSList *page_iter = pages; GRegex *regex; g_return_val_if_fail (text != NULL, NULL); regex = g_regex_new (text, (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, &ierror); if (ierror != NULL) { g_propagate_error (error, ierror); return NULL; } while (page_iter != NULL) { const GList *object_iter; PAGE *page = (PAGE*) page_iter->data; page_iter = g_slist_next (page_iter); if (page == NULL) { g_warning ("NULL page encountered"); continue; } object_iter = s_page_objects (page); while (object_iter != NULL) { OBJECT *object = (OBJECT*) object_iter->data; const char *str; object_iter = g_list_next (object_iter); if (object == NULL) { g_warning ("NULL object encountered"); continue; } if (object->type != OBJ_TEXT) { continue; } if (!(o_is_visible (page->toplevel, object) || page->toplevel->show_hidden_text)) { continue; } str = geda_text_object_get_string (object); if (str == NULL) { g_warning ("NULL string encountered"); continue; } if (g_regex_match (regex, str, (GRegexMatchFlags) 0, NULL)) { object_list = g_slist_prepend (object_list, object); } } } g_regex_unref (regex); return g_slist_reverse (object_list); }
/*! \brief Find page hierarchy below a page. * \par Function Description * This function traverses the hierarchy tree of pages and returns a * flat list of pages that are below \a p_current. There are two \a * flags that can be used to control the way that the return value is * constructed: <B>HIERARCHY_NODUPS</B> returns a list without * duplicate pages, and <B>HIERARCHY_POSTORDER</B> traverses the * hierarchy tree and returns a postorder list instead of preorder. * * \param toplevel The TOPLEVEL structure. * \param p_current The PAGE to traverse hierarchy for. * \param flags Flags controlling form of return value. * \return A GList of PAGE pointers. * * \warning * Caller must destroy returned GList with g_list_free(). */ GList * s_hierarchy_traversepages (TOPLEVEL *toplevel, PAGE *p_current, gint flags) { OBJECT *o_current; PAGE *child_page; char *filename = NULL; static GList *pages = NULL; const GList *iter; g_return_val_if_fail ((toplevel != NULL), NULL); g_return_val_if_fail ((p_current != NULL), NULL); /* init static variables the first time*/ if (!(flags & HIERARCHY_INNERLOOP)) { pages = NULL; } /* preorder traversing */ if (!(flags & HIERARCHY_POSTORDER)) { /* check whether we already visited this page */ if ((flags & HIERARCHY_NODUPS) && (g_list_find (pages, p_current) != NULL)) { return pages; /* drop the page subtree */ } pages = g_list_append (pages, p_current); } /* walk throught the page objects and search for underlaying schematics */ for (iter = s_page_objects (p_current); iter != NULL ; iter = g_list_next (iter)) { o_current = (OBJECT *)iter->data; /* only complex things like symbols can contain attributes */ if (o_current->type != OBJ_COMPLEX) continue; filename = o_attrib_search_attached_attribs_by_name (o_current, "source", 0); /* if above is NULL, then look inside symbol */ if (filename == NULL) { filename = o_attrib_search_inherited_attribs_by_name (o_current, "source", 0); } if (filename == NULL) continue; /* we got a schematic source attribute lets load the page and dive into it */ GError *err = NULL; child_page = s_hierarchy_down_schematic_single (toplevel, filename, p_current, 0, HIERARCHY_NORMAL_LOAD, &err); if (child_page != NULL) { /* call the recursive function */ s_hierarchy_traversepages (toplevel, child_page, flags | HIERARCHY_INNERLOOP); } else { s_log_message (_("Failed to descend hierarchy into '%1$s': %2$s"), filename, err->message); g_error_free (err); } g_free (filename); filename = NULL; } /* postorder traversing */ if (flags & HIERARCHY_POSTORDER) { /* check whether we already visited this page */ if ((flags & HIERARCHY_NODUPS) && (g_list_find (pages, p_current) != NULL)) { return pages; /* don't append it */ } pages = g_list_append (pages, p_current); } return pages; }
/*! \brief Draw a page. * \par Function Description * Draws the \a page on the Cairo context \a cr, which should have * dimensions \a cr_width and \a cr_height. If the Pango context \a * pc is provided, it is used for rendering of text. The parameter \a * is_color controls whether to enable color printing, and \a * is_raster should be set if drawing to a raster surface such as an * image. * * \param toplevel A #TOPLEVEL structure. * \param page The #PAGE to be rendered. * \param cr The Cairo context to render to. * \param pc A Pango context for text rendering, or NULL. * \param cr_width The width of the drawing area. * \param cr_height The height of the drawing area. * \param is_color TRUE if drawing should be in color; FALSE otherwise. * \param is_raster TRUE if drawing to a raster image surface; FALSE otherwise. */ static void x_print_draw_page (TOPLEVEL *toplevel, PAGE *page, cairo_t *cr, PangoContext *pc, double cr_width, double cr_height, gboolean is_color, gboolean is_raster) { EdaRenderer *renderer; cairo_matrix_t mtx; GArray *color_map; int status, wx_min, wy_min, wx_max, wy_max; double w_width, w_height, scale; GList *iter; /* First, calculate a transformation matrix for the cairo * context. We want to center the extents of the page in the * available page area. */ status = world_get_object_glist_bounds (toplevel, s_page_objects (page), &wx_min, &wy_min, &wx_max, &wy_max); /* If there are no printable objects, draw nothing. */ if (!status) return; w_width = wx_max - wx_min; w_height = wy_max - wy_min; scale = fmin (cr_width / w_width, cr_height / w_height); cairo_matrix_init (&mtx, scale, 0, 0, -scale, - (wx_min + 0.5*w_width) * scale + 0.5*cr_width, (wy_min + 0.5*w_height) * scale + 0.5*cr_height); /* Second, build the color map. If no color printing is desired, * transform the print color map into a black-and-white color map by * making the background color transparent and replacing all other * enabled colors with solid black. */ color_map = g_array_sized_new (FALSE, FALSE, sizeof(GedaColor), MAX_COLORS); color_map = g_array_append_vals (color_map, print_colors, MAX_COLORS); if (!is_color) { int i; for (i = 0; i < MAX_COLORS; i++) { GedaColor *c = &g_array_index (color_map, GedaColor, i); if (!c->enabled) continue; /* Disable background color & fully-transparent colors */ if (c->a == 0 || i == BACKGROUND_COLOR) { c->enabled = FALSE; continue; } /* Set any remaining colors solid black */ c->r = 0; c->g = 0; c->b = 0; c->a = ~0; } } /* Thirdly, create and initialise a renderer */ renderer = EDA_RENDERER (g_object_new (EDA_TYPE_RENDERER, "cairo-context", cr, "pango-context", pc, "color-map", color_map, "render-flags", is_raster ? EDA_RENDERER_FLAG_HINTING : 0, NULL)); /* Finally, actually do drawing */ cairo_save (cr); cairo_transform (cr, &mtx); /* Draw background */ eda_cairo_set_source_color (cr, BACKGROUND_COLOR, color_map); cairo_paint (cr); /* Draw all objects and cues */ for (iter = (GList *) s_page_objects (page); iter != NULL; iter = g_list_next (iter)) { eda_renderer_draw (renderer, (OBJECT *) iter->data); } for (iter = (GList *) s_page_objects (page); iter != NULL; iter = g_list_next (iter)) { eda_renderer_draw_cues (renderer, (OBJECT *) iter->data); } cairo_restore (cr); g_object_unref (renderer); g_array_free (color_map, TRUE); }
/* Calculates a page layout. If page is NULL, uses the first page * (this is convenient for single-page rendering). The required size * of the page is returned in extents, and the cairo transformation * matrix needed to fit the drawing into the page is returned in mtx. * Takes into account all of the margin/orientation/paper settings, * and the size of the drawing itself. */ static void export_layout_page (PAGE *page, cairo_rectangle_t *extents, cairo_matrix_t *mtx) { cairo_rectangle_t drawable; int wx_min, wy_min, wx_max, wy_max, w_width, w_height; gboolean landscape = FALSE; gdouble m[4]; /* Calculated margins */ gdouble s; /* Calculated scale */ gdouble slack[2]; /* Calculated alignment slack */ if (page == NULL) { const GList *pages = geda_list_get_glist (toplevel->pages); g_assert (pages != NULL && pages->data != NULL); page = (PAGE *) pages->data; } /* Set the margins. If none were provided by the user, get them * from the paper size (if a paper size is being used) or just use a * sensible default. */ if (settings.margins[0] >= 0) { memcpy (m, settings.margins, 4*sizeof(gdouble)); } else if (settings.paper != NULL) { m[0] = gtk_paper_size_get_default_top_margin (settings.paper, GTK_UNIT_POINTS); m[1] = gtk_paper_size_get_default_left_margin (settings.paper, GTK_UNIT_POINTS); m[2] = gtk_paper_size_get_default_bottom_margin (settings.paper, GTK_UNIT_POINTS); m[3] = gtk_paper_size_get_default_right_margin (settings.paper, GTK_UNIT_POINTS); } else { m[0] = DEFAULT_MARGIN; m[1] = DEFAULT_MARGIN; m[2] = DEFAULT_MARGIN; m[3] = DEFAULT_MARGIN; } /* Now calculate extents of objects within page */ world_get_object_glist_bounds (toplevel, s_page_objects (page), &wx_min, &wy_min, &wx_max, &wy_max); w_width = wx_max - wx_min; w_height = wy_max - wy_min; /* If a size was specified, use it. Otherwise, use paper size, if * provided. Fall back to just using the size of the drawing. */ extents->x = extents->y = 0; if (settings.size[0] >= 0) { /* get extents from size */ extents->width = settings.size[0]; extents->height = settings.size[1]; } else if (settings.paper != NULL) { /* get extents from paper */ gdouble p_width, p_height; /* Select orientation */ switch (settings.layout) { case ORIENTATION_LANDSCAPE: landscape = TRUE; break; case ORIENTATION_PORTRAIT: landscape = FALSE; break; case ORIENTATION_AUTO: default: landscape = (w_width > w_height); break; } p_width = gtk_paper_size_get_width (settings.paper, GTK_UNIT_POINTS); p_height = gtk_paper_size_get_height (settings.paper, GTK_UNIT_POINTS); if (landscape) { extents->width = p_height; extents->height = p_width; } else { extents->width = p_width; extents->height = p_height; } } else { /* get extents from drawing */ extents->width = w_width * settings.scale; /* in points */ extents->height = w_height * settings.scale; /* in points */ /* If the extents were obtained from the drawing, grow the extents * rather than shrinking the drawable area. This ensures that the * overall aspect ratio of the image remains correct. */ extents->width += m[1] + m[3]; extents->height += m[0] + m[2]; } drawable.x = m[1]; drawable.y = m[0]; drawable.width = extents->width - m[1] - m[3]; drawable.height = extents->height - m[0] - m[2]; /* Calculate optimum scale */ s = fmin (drawable.width / w_width, drawable.height / w_height); /* Calculate alignment slack */ slack[0] = fmin (1, fmax (0, settings.align[0])) * (drawable.width - w_width * s); slack[1] = fmin (1, fmax (0, settings.align[1])) * (drawable.height - w_height * s); /* Finally, create and set a cairo transformation matrix that * centres the drawing into the drawable area. */ cairo_matrix_init (mtx, s, 0, 0, -s, - wx_min * s + drawable.x + slack[0], (wy_min + w_height) * s + drawable.y + slack[1]); }
/*! \brief Updates the preview widget. * \par Function Description * This function updates the preview: if the preview is active and a * filename has been given, it opens the file and displays * it. Otherwise it displays a blank page. * * \param [in] preview The preview widget. */ static void preview_update (Preview *preview) { int left, top, right, bottom; int width, height; GError * err = NULL; GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview); g_return_if_fail (preview_view != NULL); PAGE *preview_page = gschem_page_view_get_page (preview_view); if (preview_page == NULL) { return; } TOPLEVEL *preview_toplevel = preview_page->toplevel; /* delete old preview */ s_page_delete_objects (preview_toplevel, preview_page); if (preview->active) { g_assert ((preview->filename == NULL) || (preview->buffer == NULL)); if (preview->filename != NULL) { /* open up file in current page */ f_open_flags (preview_toplevel, preview_page, preview->filename, F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL); /* test value returned by f_open... - Fix me */ /* we should display something if there an error occured - Fix me */ } if (preview->buffer != NULL) { /* Load the data buffer */ GList * objects = o_read_buffer (preview_toplevel, NULL, preview->buffer, -1, _("Preview Buffer"), &err); if (err == NULL) { s_page_append_list (preview_toplevel, preview_page, objects); } else { s_page_append (preview_toplevel, preview_page, o_text_new(preview_toplevel, OBJ_TEXT, 2, 100, 100, LOWER_MIDDLE, 0, err->message, 10, VISIBLE, SHOW_NAME_VALUE)); g_error_free(err); } } } if (world_get_object_glist_bounds (preview_toplevel, s_page_objects (preview_page), &left, &top, &right, &bottom)) { /* Clamp the canvas size to the extents of the page being previewed */ width = right - left; height = bottom - top; GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (preview_view); geometry->world_left = left - ((double)width * OVER_ZOOM_FACTOR); geometry->world_right = right + ((double)width * OVER_ZOOM_FACTOR); geometry->world_top = top - ((double)height * OVER_ZOOM_FACTOR); geometry->world_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR); } /* display current page (possibly empty) */ gschem_page_view_zoom_extents (preview_view, NULL); }
void s_hierarchy_traverse(TOPLEVEL * pr_current, OBJECT * o_current, NETLIST * netlist) { char *attrib; int page_control=-1; PAGE *p_current; PAGE *child_page; int count = 0; int pcount = 0; int looking_inside = FALSE; int loaded_flag = FALSE; char *current_filename; int graphical=FALSE; attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", 0); /* if above is null, then look inside symbol */ if (attrib == NULL) { attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); looking_inside = TRUE; #if DEBUG printf("going to look inside now\n"); #endif } graphical = s_hierarchy_graphical_search(o_current, count); if (graphical) { /* Do not bother traversing the hierarchy if the symbol has an */ /* graphical attribute attached to it. */ if (attrib) { g_free(attrib); attrib = NULL; } } while (attrib) { /* look for source=filename,filename, ... */ pcount = 0; current_filename = u_basic_breakup_string(attrib, ',', pcount); /* loop over all filenames */ while (current_filename != NULL) { s_log_message(_("Going to traverse source [%1$s]"), current_filename); /* guts here */ /* guts for a single filename */ p_current = pr_current->page_current; #if DEBUG printf("Going down %s\n", current_filename); #endif GError *err = NULL; child_page = s_hierarchy_down_schematic_single(pr_current, current_filename, pr_current->page_current, page_control, HIERARCHY_FORCE_LOAD, &err); if (child_page == NULL) { g_warning (_("Failed to load subcircuit '%1$s': %2$s\n"), current_filename, err->message); fprintf(stderr, _("ERROR: Failed to load subcircuit '%1$s': %2$s\n"), current_filename, err->message); g_error_free (err); exit (2); } else { page_control = child_page->page_control; s_page_goto (pr_current, child_page); loaded_flag = TRUE; verbose_print("v\n"); verbose_reset_index(); netlist->composite_component = TRUE; /* can't do the following, don't know why... HACK TODO */ /*netlist->hierarchy_tag = u_basic_strdup (netlist->component_uref);*/ s_traverse_sheet (pr_current, s_page_objects (pr_current->page_current), netlist->component_uref); verbose_print("^"); } pr_current->page_current = p_current; g_free(current_filename); pcount++; current_filename = u_basic_breakup_string(attrib, ',', pcount); } g_free(attrib); g_free(current_filename); count++; /* continue looking outside first */ if (!looking_inside) { attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", count); } /* okay we were looking outside and didn't */ /* find anything, so now we need to look */ /* inside the symbol */ if (!looking_inside && attrib == NULL && !loaded_flag) { looking_inside = TRUE; #if DEBUG printf("switching to go to look inside\n"); #endif } if (looking_inside) { #if DEBUG printf("looking inside\n"); #endif attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); } graphical = s_hierarchy_graphical_search(o_current, count); if (graphical) { /* Do not bother looking further in the hierarchy if the symbol */ /* has an graphical attribute attached to it. */ if (attrib) { g_free(attrib); attrib = NULL; } } } }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * \todo Only descends into the first source schematic * */ int o_edit_find_text (GSCHEM_TOPLEVEL *w_current, const GList *o_list, char *stext, int descend, int skip) { TOPLEVEL *toplevel = w_current->toplevel; char *attrib = NULL; int count = 0; PAGE *parent = NULL; char *current_filename = NULL; int page_control = 0; int pcount = 0; int rv; int x1, y1, x2, y2; int text_screen_height; const GList *iter; OBJECT *o_current; skiplast = skip; iter = o_list; while (iter != NULL) { o_current = (OBJECT *)iter->data; if (descend) { if (o_current->type == OBJ_COMPLEX) { parent = toplevel->page_current; attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", count); /* if above is null, then look inside symbol */ if (attrib == NULL) { attrib = o_attrib_search_inherited_attribs_by_name (o_current, "source", count); /* looking_inside = TRUE; */ } if (attrib) { pcount = 0; current_filename = u_basic_breakup_string(attrib, ',', pcount); if (current_filename != NULL) { PAGE *child_page = s_hierarchy_down_schematic_single(toplevel, current_filename, parent, page_control, HIERARCHY_NORMAL_LOAD); if (child_page != NULL) { page_control = child_page->page_control; rv = o_edit_find_text (w_current, s_page_objects (child_page), stext, descend, skiplast); if (!rv) { s_page_goto( toplevel, child_page ); return 0; } } } } } } if (o_current->type == OBJ_TEXT) { const gchar *str = o_text_get_string (toplevel, o_current); /* replaced strcmp with strstr to simplify the search */ if (strstr (str,stext)) { if (!skiplast) { a_zoom(w_current, ZOOM_FULL, DONTCARE, A_PAN_DONT_REDRAW); world_get_single_object_bounds (toplevel, o_current, &x1, &y1, &x2, &y2); text_screen_height = SCREENabs (w_current, y2 - y1); /* this code will zoom/pan till the text screen height is about */ /* 50 pixels high, perhaps a future enhancement will be to make */ /* this number configurable */ while (text_screen_height < 50) { a_zoom(w_current, ZOOM_IN, DONTCARE, A_PAN_DONT_REDRAW); text_screen_height = SCREENabs (w_current, y2 - y1); } a_pan_general(w_current, o_current->text->x, o_current->text->y, 1, 0); /* Make sure the titlebar and scrollbars are up-to-date */ x_window_set_current_page(w_current, w_current->toplevel->page_current ); last_o = o_current; break; } if (last_o == o_current) { skiplast = 0; } } /* if (strstr(o_current->text->string,stext)) */ } /* if (o_current->type == OBJ_TEXT) */ iter = g_list_next (iter); if (iter == NULL) { return 1; } } return (iter == NULL); }
/*! \brief Attach attribute to object. * * Attach the name=value pair to the OBJECT "object". This function * was stolen from gschem/src/o_attrib.c:o_attrib_add_attrib and * hacked for gattrib. * \param toplevel TOPLEVEL to operate on * \param text_string * \param visibility * \param show_name_value * \param object * \returns pointer to the object * \todo Does it need to return OBJECT? */ OBJECT * s_object_attrib_add_attrib_in_object (TOPLEVEL *toplevel, char *text_string, int visibility, int show_name_value, OBJECT * object) { int world_x = -1, world_y = -1; int color; int left, right, top, bottom; OBJECT *o_current; OBJECT *new_obj; o_current = object; /* creating a toplevel or unattached attribute */ if (o_current) { /* get coordinates of where to place the text object */ switch (o_current->type) { case (OBJ_COMPLEX): world_x = o_current->complex->x; world_y = o_current->complex->y; color = ATTRIBUTE_COLOR; break; case (OBJ_NET): world_x = o_current->complex->x; world_y = o_current->complex->y; color = ATTRIBUTE_COLOR; break; default: fprintf(stderr, _("In s_object_attrib_add_attrib_in_object, trying to add attrib to non-complex or non-net!\n")); exit(-1); } } else { /* This must be a floating attrib, but what is that !?!?!?!?! */ world_get_object_glist_bounds (toplevel, s_page_objects (toplevel->page_current), &left, &top, &right, &bottom); /* this really is the lower left hand corner */ world_x = left; world_y = top; /* printf("%d %d\n", world_x, world_y); */ color = DETACHED_ATTRIBUTE_COLOR; } /* first create text item */ #if DEBUG printf("=== In s_object_attrib_add_attrib_in_object, about to attach new text attrib with properties:\n"); printf(" color = %d\n", color); printf(" text_string = %s \n", text_string); printf(" text_size = %d \n", toplevel->text_size); printf(" visibility = %d \n", visibility); printf(" show_name_value = %d \n", show_name_value); #endif new_obj = o_text_new (toplevel, color, world_x, world_y, LOWER_LEFT, 0, /* zero is angle */ text_string, DEFAULT_TEXT_SIZE, visibility, show_name_value); s_page_append (toplevel, toplevel->page_current, new_obj); /* now toplevel->page_current->object_tail contains new text item */ /* now attach the attribute to the object (if o_current is not NULL) */ /* remember that o_current contains the object to get the attribute */ if (o_current) { o_attrib_attach (toplevel, new_obj, o_current, FALSE); } o_selection_add (toplevel, toplevel->page_current->selection_list, new_obj); toplevel->page_current->CHANGED = 1; return new_obj; }
/*! \brief Save the schematic file * \par Function Description * This function saves the current schematic file in the toplevel object. * * \param [in,out] toplevel The TOPLEVEL object containing the schematic. * \param [in] filename The file name to save the schematic to. * \param [in,out] err #GError structure for error reporting, or * NULL to disable error reporting * \return 1 on success, 0 on failure. */ int f_save(TOPLEVEL *toplevel, PAGE *page, const char *filename, GError **err) { gchar *backup_filename; gchar *real_filename; gchar *only_filename; gchar *dirname; mode_t saved_umask, mask; struct stat st; GError *tmp_err = NULL; /* Get the real filename and file permissions */ real_filename = follow_symlinks (filename, &tmp_err); if (real_filename == NULL) { g_set_error (err, tmp_err->domain, tmp_err->code, _("Can't get the real filename of %s: %s"), filename, tmp_err->message); return 0; } /* Get the directory in which the real filename lives */ dirname = g_path_get_dirname (real_filename); only_filename = g_path_get_basename(real_filename); /* Do a backup if it's not an undo file backup and it was never saved. */ if (page->saved_since_first_loaded == 0) { if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) && (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) ) { backup_filename = g_strdup_printf("%s%c%s~", dirname, G_DIR_SEPARATOR, only_filename); /* Make the backup file read-write before saving a new one */ if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) { if (chmod(backup_filename, S_IREAD|S_IWRITE) != 0) { s_log_message (_("Could NOT set previous backup file [%s] read-write\n"), backup_filename); } } if (rename(real_filename, backup_filename) != 0) { s_log_message (_("Can't save backup file: %s."), backup_filename); } else { /* Make the backup file readonly so a 'rm *' command will ask the user before deleting it */ saved_umask = umask(0); mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH); mask = (~mask)&0777; mask &= ((~saved_umask) & 0777); if (chmod(backup_filename, mask) != 0) { s_log_message (_("Could NOT set backup file [%s] readonly\n"), backup_filename); } umask(saved_umask); } g_free(backup_filename); } } /* If there is not an existing file with that name, compute the * permissions and uid/gid that we will use for the newly-created file. */ if (stat (real_filename, &st) != 0) { struct stat dir_st; int result; /* Use default permissions */ saved_umask = umask(0); st.st_mode = 0666 & ~saved_umask; umask(saved_umask); #ifdef HAVE_CHOWN st.st_uid = getuid (); result = stat (dirname, &dir_st); if (result == 0 && (dir_st.st_mode & S_ISGID)) st.st_gid = dir_st.st_gid; else st.st_gid = getgid (); #endif /* HAVE_CHOWN */ } g_free (dirname); g_free (only_filename); if (o_save (toplevel, s_page_objects (page), real_filename, &tmp_err)) { page->saved_since_first_loaded = 1; /* Reset the last saved timer */ g_get_current_time (&page->last_load_or_save_time); page->ops_since_last_backup = 0; page->do_autosave_backup = 0; /* Restore permissions. */ chmod (real_filename, st.st_mode); #ifdef HAVE_CHOWN if (chown (real_filename, st.st_uid, st.st_gid)) { /* Error occured with chown */ #warning FIXME: What do we do? } #endif g_free (real_filename); return 1; } else { g_set_error (err, tmp_err->domain, tmp_err->code, _("Could NOT save file: %s"), tmp_err->message); g_clear_error (&tmp_err); g_free (real_filename); return 0; } }
/*! \brief Opens a new page from a file. * \par Function Description * This function opens the file whose name is <B>filename</B> in a * new PAGE of <B>toplevel</B>. * * If there is no page for <B>filename</B> in <B>toplevel</B>'s list * of pages, it creates a new PAGE, loads the file in it and returns * a pointer on the new page. Otherwise it returns a pointer on the * existing page. * * If the filename passed is NULL, this function creates an empty, * untitled page. The name of the untitled page is build from * configuration data ('untitled-name') and a counter for uniqueness. * * The opened page becomes the current page of <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] filename The name of the file to open or NULL for a blank page. * \returns A pointer on the new page. * * \bug This code should check to make sure any untitled filename * does not conflict with a file on disk. */ PAGE* x_window_open_page (GSCHEM_TOPLEVEL *w_current, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current, *page; gchar *fn; g_return_val_if_fail (toplevel != NULL, NULL); /* Generate untitled filename if none was specified */ if (filename == NULL) { gchar *cwd, *tmp; cwd = g_get_current_dir (); tmp = g_strdup_printf ("%s_%d.sch", toplevel->untitled_name, ++w_current->num_untitled); fn = g_build_filename (cwd, tmp, NULL); g_free(cwd); g_free(tmp); } else { fn = g_strdup (filename); } /* Return existing page if it is already loaded */ page = s_page_search (toplevel, fn); if ( page != NULL ) { g_free(fn); return page; } old_current = toplevel->page_current; page = s_page_new (toplevel, fn); s_page_goto (toplevel, page); /* Load from file if necessary, otherwise just print a message */ if (filename != NULL) { GError *err = NULL; if (!quiet_mode) s_log_message (_("Loading schematic [%s]\n"), fn); if (!f_open (toplevel, page, (gchar *) fn, &err)) { GtkWidget *dialog; g_warning ("%s\n", err->message); dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (err); } else { gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL)); } } else { if (!quiet_mode) s_log_message (_("New file [%s]\n"), toplevel->page_current->page_filename); } if (scm_is_false (scm_hook_empty_p (new_page_hook))) scm_run_hook (new_page_hook, scm_cons (g_make_page_smob (toplevel, page), SCM_EOL)); a_zoom_extents (w_current, s_page_objects (toplevel->page_current), A_PAN_DONT_REDRAW); o_undo_savestate (w_current, UNDO_ALL); if ( old_current != NULL ) s_page_goto (toplevel, old_current); /* This line is generally un-needed, however if some code * wants to open a page, yet not bring it to the front, it is * needed needed to add it into the page manager. Otherwise, * it will get done in x_window_set_current_page(...) */ x_pagesel_update (w_current); /* ??? */ g_free (fn); return page; }