Exemplo n.º 1
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_edit_show_specific_text (GschemToplevel *w_current,
                                const GList *o_list,
                                const char *stext)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *o_current;
  const GList *iter;

  iter = o_list;
  while (iter != NULL) {
    o_current = (OBJECT *)iter->data;

    if (o_current->type == OBJ_TEXT) {
      const gchar *str = o_text_get_string (w_current->toplevel, o_current);
      if (!strncmp (stext, str, strlen (stext))) {
        if (!o_is_visible (toplevel, o_current)) {
          o_set_visibility (toplevel, o_current, VISIBLE);
          o_text_recreate(toplevel, o_current);

          gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
        }
      }
    }
    iter = g_list_next (iter);
  }
  o_undo_savestate_old(w_current, UNDO_ALL);
}
Exemplo n.º 2
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void pagesel_update (Pagesel *pagesel)
{
  GtkTreeModel *model;
  TOPLEVEL *toplevel;
  PAGE *p_current;
  GList *iter;

  g_assert (IS_PAGESEL (pagesel));

  g_return_if_fail (GSCHEM_DIALOG (pagesel)->w_current);

  toplevel = gschem_toplevel_get_toplevel (GSCHEM_DIALOG (pagesel)->w_current);
  model    = gtk_tree_view_get_model (pagesel->treeview);

  /* wipe out every thing in the store */
  gtk_tree_store_clear (GTK_TREE_STORE (model));
  /* now rebuild */
  for ( iter = geda_list_get_glist( toplevel->pages );
        iter != NULL;
        iter = g_list_next( iter ) ) {

    p_current = (PAGE *)iter->data;
    /* find every page that is not a hierarchy-down of another page */
    if (p_current->up < 0 ||
        s_page_search_by_page_id (toplevel->pages,
                                  p_current->up) == NULL) {
      add_page (model, NULL, toplevel->pages, p_current);
    }
  }

  /* select the current page in the treeview */
  select_page (pagesel->treeview, NULL, toplevel->page_current);  
}
Exemplo n.º 3
0
/*! \brief Replace all selected pictures with a new picture
 * \par Function Description
 * Replaces all pictures in the current selection with a new image.
 *
 * \param [in] w_current  The GschemToplevel object
 * \param [in] filename   The filename of the new picture
 * \param [out] error     The location to return error information.
 * \return TRUE on success, FALSE on failure.
 */
gboolean
o_picture_exchange (GschemToplevel *w_current,
                    const gchar *filename, GError **error)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  GList *iter;

  for (iter = geda_list_get_glist (toplevel->page_current->selection_list);
       iter != NULL;
       iter = g_list_next (iter)) {

    OBJECT *object = (OBJECT *) iter->data;
    g_assert (object != NULL);

    if (object->type == OBJ_PICTURE) {
      gboolean status;

      /* Erase previous picture */
      o_invalidate (w_current, object);

      status = o_picture_set_from_file (toplevel, object, filename, error);
      if (!status) return FALSE;

      /* Draw new picture */
      o_invalidate (w_current, object);
    }
  }
  return TRUE;
}
Exemplo n.º 4
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void x_window_setup (GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

  /* immediately setup user params */
  i_vars_set(w_current);

  /* Initialize the autosave callback */
  s_page_autosave_init(toplevel);

  /* Initialize the clipboard callback */
  x_clipboard_init (w_current);

  /* x_window_setup_world() - BEGIN */
  w_current->win_width  = default_width;
  w_current->win_height = default_height;
  /* x_window_setup_world() - END */

  /* Add to the list of windows */
  global_window_list = g_list_append (global_window_list, w_current);

  /* X related stuff */
  x_window_create_main (w_current);

  x_menu_attach_recent_files_submenu(w_current);
}
Exemplo n.º 5
0
/*! \brief Change visibility status of attribute object.
 *  \par Function Description
 *  This function toggles the visibility status of the attribute \a
 *  object and updates it. The object is erased or redrawn if
 *  necessary.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] object     The attribute object.
 */
void o_attrib_toggle_visibility(GschemToplevel *w_current, OBJECT *object)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

  g_return_if_fail (object != NULL && object->type == OBJ_TEXT);

  if (o_is_visible (object)) {
    /* only erase if we are not showing hidden text */
    if (!toplevel->show_hidden_text) {
      o_invalidate (w_current, object);
    }

    o_set_visibility (toplevel, object, INVISIBLE);

    if (toplevel->show_hidden_text) {
      /* draw text so that little I is drawn */
      o_invalidate (w_current, object);
    }

  } else {
    /* if we are in the special show hidden mode, then erase text first */
    /* to get rid of the little I */
    if (toplevel->show_hidden_text) {
      o_invalidate (w_current, object);
    }

    o_set_visibility (toplevel, object, VISIBLE);
    o_text_recreate(toplevel, object);
  }

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
}
Exemplo n.º 6
0
/*! \brief Closes a page.
 *  \par Function Description
 *  This function closes the page <B>page</B> of toplevel
 *  <B>toplevel</B>.
 *
 *  If necessary, the current page of <B>toplevel</B> is changed to
 *  the next valid page or to a new untitled page.
 *
 *  \param [in] w_current The toplevel environment.
 *  \param [in] page      The page to close.
 */
void
x_window_close_page (GschemToplevel *w_current, PAGE *page)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  PAGE *new_current = NULL;
  GList *iter;

  g_return_if_fail (toplevel != NULL);
  g_return_if_fail (page     != NULL);

  g_assert (page->pid != -1);

  /* If we're closing whilst inside an action, re-wind the
   * page contents back to their state before we started */
  if (w_current->inside_action) {
    i_callback_cancel (w_current, 0, NULL);
  }

  if (page == toplevel->page_current) {
    /* as it will delete current page, select new current page */
    /* first look up in page hierarchy */
    new_current = s_page_search_by_page_id (toplevel->pages, page->up);

    if (new_current == NULL) {
      /* no up in hierarchy, choice is prev, next, new page */
      iter = g_list_find( geda_list_get_glist( toplevel->pages ), page );

      if ( g_list_previous( iter ) ) {
        new_current = (PAGE *)g_list_previous( iter )->data;
      } else if ( g_list_next( iter ) ) {
        new_current = (PAGE *)g_list_next( iter )->data;
      } else {
        /* need to add a new untitled page */
        new_current = NULL;
      }
    }
    /* new_current will be the new current page at the end of the function */
  }

  s_log_message (page->CHANGED ?
                 _("Discarding page [%s]\n") : _("Closing [%s]\n"),
                 page->page_filename);
  /* remove page from toplevel list of page and free */
  s_page_delete (toplevel, page);
  gschem_toplevel_page_changed (w_current);

  /* Switch to a different page if we just removed the current */
  if (toplevel->page_current == NULL) {

    /* Create a new page if there wasn't another to switch to */
    if (new_current == NULL) {
      new_current = x_window_open_page (w_current, NULL);
    }

    /* change to new_current and update display */
    x_window_set_current_page (w_current, new_current);
  }
}
Exemplo n.º 7
0
/*! \brief Rotate all objects in list.
 *  \par Function Description
 *  Given an object <B>list</B>, and the center of rotation
 *  (<B>centerx</B>,<B>centery</B>, this function traverses all the selection
 *  list, rotating each object through angle <B>angle</B>.
 *  The list contains a given object and all its attributes
 *  (refdes, pinname, pinlabel, ...).
 *  There is a second pass to run the rotate hooks of non-simple objects,
 *  like pin or complex objects, for example.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] centerx    Center x coordinate of rotation.
 *  \param [in] centery    Center y coordinate of rotation.
 *  \param [in] angle      Angle to rotate the objects through.
 *  \param [in] list       The list of objects to rotate.
 */
void o_rotate_world_update(GschemToplevel *w_current,
                           int centerx, int centery, int angle, GList *list)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *o_current;
  GList *o_iter;

  /* this is okay if you just hit rotate and have nothing selected */
  if (list == NULL) {
    i_action_stop (w_current);
    i_set_state(w_current, SELECT);
    return;
  }

  o_invalidate_glist (w_current, list);

  /* Find connected objects, removing each object in turn from the
   * connection list. We only _really_ want those objects connected
   * to the selection, not those within in it.
   */
  for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) {
    o_current = o_iter->data;

    s_conn_remove_object_connections (toplevel, o_current);
  }

  o_glist_rotate_world( toplevel, centerx, centery, angle, list );

  /* Find connected objects, adding each object in turn back to the
   * connection list. We only _really_ want those objects connected
   * to the selection, not those within in it.
   */
  for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) {
    o_current = o_iter->data;

    s_conn_update_object (o_current->page, o_current);
  }

  o_invalidate_glist (w_current, list);

  /* Run rotate-objects-hook */
  g_run_hook_object_list (w_current, "%rotate-objects-hook", list);

  /* Don't save the undo state if we are inside an action */
  /* This is useful when rotating the selection while moving, for example */
  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
  if (!w_current->inside_action) {
    o_undo_savestate_old(w_current, UNDO_ALL);
  }

  if (w_current->event_state == ROTATEMODE) {
    i_set_state(w_current, SELECT);
  }
}
Exemplo n.º 8
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
int o_text_get_rendered_bounds (void *user_data, OBJECT *o_current,
                                int *min_x, int *min_y,
                                int *max_x, int *max_y)
{
  TOPLEVEL *toplevel;
  EdaRenderer *renderer;
  cairo_t *cr;
  cairo_matrix_t render_mtx;
  int result, render_flags = 0;
  double t, l, r, b;
  GschemToplevel *w_current = (GschemToplevel *) user_data;
  g_return_val_if_fail ((w_current != NULL), FALSE);

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_val_if_fail ((page_view != NULL), FALSE);

  toplevel = gschem_toplevel_get_toplevel (w_current);
  g_return_val_if_fail ((toplevel != NULL), FALSE);

  cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET(page_view)));

  /* Set up renderer based on configuration in w_current. Note that we
   * *don't* enable hinting, because if its enabled the calculated
   * bounds are zoom-level-dependent. */
  if (toplevel->show_hidden_text)
    render_flags |= EDA_RENDERER_FLAG_TEXT_HIDDEN;
  renderer = g_object_ref (w_current->renderer);
  g_object_set (G_OBJECT (renderer),
                "cairo-context", cr,
                "render-flags", render_flags,
                NULL);

  /* We need to transform the cairo context to approximate world
   * coordinates. */
  cairo_matrix_init (&render_mtx, 1, 0, 0, -1, -1, 1);
  cairo_set_matrix (cr, &render_mtx);

  /* Use the renderer to calculate text bounds */
  result = eda_renderer_get_user_bounds (renderer, o_current, &l, &t, &r, &b);

  /* Clean up */
  eda_renderer_destroy (renderer);
  cairo_destroy (cr);

  /* Round bounds to nearest integer */
  *min_x = lrint (fmin (l, r));
  *min_y = lrint (fmin (t, b));
  *max_x = lrint (fmax (l, r));
  *max_y = lrint (fmax (t, b));

  return result;
}
Exemplo n.º 9
0
/*! \brief Set what part of an attribute is shown.
 *  \par Function Description
 *  This function changes what part (name, value or both) of an
 *  attribute is shown by its attribute object. The attribute object
 *  is erased, updated and finally redrawn.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] object     The attribute object.
 *  \param [in] show_name_value  The new display flag for attribute.
 */
void o_attrib_toggle_show_name_value(GschemToplevel *w_current,
                                     OBJECT *object, int show_name_value)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

  g_return_if_fail (object != NULL && object->type == OBJ_TEXT);

  o_invalidate (w_current, object);
  object->show_name_value = show_name_value;
  o_text_recreate(toplevel, object);

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
}
Exemplo n.º 10
0
/*! \brief Allow the undo manager to process changes
 *
 *  \param [in] w_current
 */
static void
handle_undo (GschemToplevel *w_current)
{
  TOPLEVEL *toplevel;

  g_return_if_fail (w_current != NULL);

  toplevel = gschem_toplevel_get_toplevel (w_current);
  g_return_if_fail (toplevel != NULL);

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
  o_undo_savestate_old (w_current, UNDO_ALL);
}
Exemplo n.º 11
0
/*! \brief Delete an object.
 *  \par Function Description
 *  This function erases the object \a object before deleting it. It
 *  deals with connection and object connected to it.
 *
 *  \param [in] w_current The GschemToplevel object.
 *  \param [in] object    The object to delete.
 */
void o_delete (GschemToplevel *w_current, OBJECT *object)
{
    TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

    g_return_if_fail (object != NULL);

    o_selection_remove (toplevel, toplevel->page_current->selection_list, object);
    s_page_remove (toplevel, toplevel->page_current, object);
    g_run_hook_object (w_current, "%remove-objects-hook", object);
    s_delete_object (toplevel, object);

    gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
}
Exemplo n.º 12
0
/*! \brief Creates a new X window.
 *
 * \par Function description
 *
 * Creates and initializes new GschemToplevel object and then sets
 * and setups its libgeda \a toplevel.
 *
 * \param toplevel The libgeda TOPLEVEL object.
 * \return Pointer to the new GschemToplevel object.
 */
GschemToplevel* x_window_new (TOPLEVEL *toplevel)
{
  GschemToplevel *w_current;

  w_current = gschem_toplevel_new ();
  gschem_toplevel_set_toplevel (w_current,
                                (toplevel != NULL) ? toplevel : s_toplevel_new ());

  gschem_toplevel_get_toplevel (w_current)->load_newer_backup_func = x_fileselect_load_backup;
  gschem_toplevel_get_toplevel (w_current)->load_newer_backup_data = w_current;

  o_text_set_rendered_bounds_func (gschem_toplevel_get_toplevel (w_current),
                                   o_text_get_rendered_bounds, w_current);

  /* Damage notifications should invalidate the object on screen */
  o_add_change_notify (gschem_toplevel_get_toplevel (w_current),
                       (ChangeNotifyFunc) o_invalidate,
                       (ChangeNotifyFunc) o_invalidate, w_current);

  x_window_setup (w_current);

  return w_current;
}
Exemplo n.º 13
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_mirror_world_update(GschemToplevel *w_current, int centerx, int centery, GList *list)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *o_current;
  GList *o_iter;

  if (list == NULL) {
    i_action_stop (w_current);
    i_set_state(w_current, SELECT);
    return;
  }

  o_invalidate_glist (w_current, list);

  /* Find connected objects, removing each object in turn from the
   * connection list. We only _really_ want those objects connected
   * to the selection, not those within in it.
   */
  for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) {
    o_current = o_iter->data;

    s_conn_remove_object_connections (toplevel, o_current);
  }

  o_glist_mirror_world( toplevel, centerx, centery, list );

  /* Find connected objects, adding each object in turn back to the
   * connection list. We only _really_ want those objects connected
   * to the selection, not those within in it.
   */
  for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) {
    o_current = o_iter->data;

    s_conn_update_object (o_current->page, o_current);
  }

  o_invalidate_glist (w_current, list);

  /* Run mirror-objects-hook */
  g_run_hook_object_list (w_current, "%mirror-objects-hook", list);

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
  o_undo_savestate_old(w_current, UNDO_ALL);

  if (w_current->event_state == MIRRORMODE) {
    i_set_state(w_current, SELECT);
  }
}
Exemplo n.º 14
0
/*! \brief End the input of a circle.
 *  \par Function Description
 *  This function ends the input of the second corner of a picture.
 *  The picture is defined by (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>
 *  and (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>.
 *
 *  The temporary picture frame is erased ; a new picture object is allocated,
 *  initialized and linked to the object list ; The object is finally
 *  drawn on the current sheet.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] w_x        (unused)
 *  \param [in] w_y        (unused)
 */
void o_picture_end(GschemToplevel *w_current, int w_x, int w_y)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *new_obj;
  int picture_width, picture_height;
  int picture_left, picture_top;

  g_assert( w_current->inside_action != 0 );

  /* erase the temporary picture */
  /* o_picture_draw_rubber(w_current); */
  w_current->rubber_visible = 0;
  
  picture_width  = GET_PICTURE_WIDTH (w_current);
  picture_height = GET_PICTURE_HEIGHT(w_current);
  picture_left   = GET_PICTURE_LEFT  (w_current);
  picture_top    = GET_PICTURE_TOP   (w_current);

  /* pictures with null width and height are not allowed */
  if ((picture_width == 0) && (picture_height == 0)) {
    /* cancel the object creation */
    return;
  }

  /* create the object */
  new_obj = o_picture_new(toplevel,
                          NULL, 0, w_current->pixbuf_filename,
                          OBJ_PICTURE,
                          picture_left, picture_top,
                          picture_left + picture_width,
                          picture_top - picture_height,
                          0, FALSE, FALSE);
  s_page_append (toplevel, toplevel->page_current, new_obj);

  /* Run %add-objects-hook */
  g_run_hook_object (w_current, "%add-objects-hook", new_obj);

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
  o_undo_savestate_old(w_current, UNDO_ALL);
}
Exemplo n.º 15
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
gboolean
o_find_selected_object (GschemToplevel *w_current, int w_x, int w_y)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_val_if_fail (page_view != NULL, FALSE);

  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  g_return_val_if_fail (toplevel != NULL, FALSE);

  int w_slack = gschem_page_view_WORLDabs (page_view, w_current->select_slack_pixels);
  GList *s_current;

  for (s_current = geda_list_get_glist (toplevel->page_current->selection_list);
       s_current != NULL; s_current = g_list_next (s_current)) {
    OBJECT *o_current = s_current->data;

    if (is_object_hit (w_current, o_current, w_x, w_y, w_slack))
      return TRUE;
  }

  return FALSE;
}
Exemplo n.º 16
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_edit_show_hidden_lowlevel (GschemToplevel *w_current,
                                  const GList *o_list)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *o_current;
  const GList *iter;

  iter = o_list;
  while (iter != NULL) {
    o_current = (OBJECT *)iter->data;
    if (o_current->type == OBJ_TEXT && !o_is_visible (toplevel, o_current)) {

      /* don't toggle the visibility flag */
      o_text_recreate (toplevel, o_current);
    }

    if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
      o_edit_show_hidden_lowlevel(w_current, o_current->complex->prim_objs);
      o_current->w_bounds_valid_for = NULL;
    }

    iter = g_list_next (iter);
  }
}
Exemplo n.º 17
0
/*! \brief Saves a page to a file.
 *  \par Function Description
 *  This function saves the page <B>page</B> to a file named
 *  <B>filename</B>.
 *
 *  It returns the value returned by function <B>f_save()</B> trying
 *  to save page <B>page</B> to file <B>filename</B> (1 on success, 0
 *  on failure).
 *
 *  <B>page</B> may not be the current page of <B>toplevel</B>. The
 *  current page of <B>toplevel</B> is not affected by this function.
 *
 *  \param [in] w_current The toplevel environment.
 *  \param [in] page      The page to save.
 *  \param [in] filename  The name of the file in which to save page.
 *  \returns 1 on success, 0 otherwise.
 */
gint
x_window_save_page (GschemToplevel *w_current, PAGE *page, const gchar *filename)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  const gchar *log_msg, *state_msg;
  gint ret;
  GError *err = NULL;

  g_return_val_if_fail (toplevel != NULL, 0);
  g_return_val_if_fail (page     != NULL, 0);
  g_return_val_if_fail (filename != NULL, 0);

  /* try saving page to filename */
  ret = (gint)f_save (toplevel, page, filename, &err);

  if (ret != 1) {
    log_msg   = _("Could NOT save page [%s]\n");
    state_msg = _("Error while trying to save");

    GtkWidget *dialog;

    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 save file"));
    gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_widget_destroy (dialog);
    g_clear_error (&err);
  } else {
    /* successful save of page to file, update page... */
    /* change page name if necessary and prepare log message */
    if (g_ascii_strcasecmp (page->page_filename, filename) != 0) {
      g_free (page->page_filename);
      page->page_filename = g_strdup (filename);

      log_msg = _("Saved as [%s]\n");
    } else {
      log_msg = _("Saved [%s]\n");
    }
    state_msg = _("Saved");

    /* reset page CHANGED flag */
    page->CHANGED = 0;

    /* add to recent file list */
    gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(filename, NULL, NULL));

    i_set_filename (w_current, page->page_filename);
    x_pagesel_update (w_current);
  }

  /* log status of operation */
  s_log_message (log_msg, filename);

  i_set_state_msg  (w_current, SELECT, state_msg);

  return ret;
}
Exemplo n.º 18
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 (GschemToplevel *w_current, const gchar *filename)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  PAGE *page;
  gchar *fn;

  g_return_val_if_fail (toplevel != NULL, NULL);

  /* Generate untitled filename if none was specified */
  if (filename == NULL) {
    gchar *cwd, *tmp, *untitled_name;
    EdaConfig *cfg;
    cwd = g_get_current_dir ();
    cfg = eda_config_get_context_for_path (cwd);
    untitled_name = eda_config_get_string (cfg, "gschem", "default-filename", NULL);
    tmp = g_strdup_printf ("%s_%d.sch",
                           untitled_name,
                           ++w_current->num_untitled);
    fn = g_build_filename (cwd, tmp, NULL);
    g_free (untitled_name);
    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;
  }

  page = s_page_new (toplevel, fn);
  s_page_goto (toplevel, page);
  gschem_toplevel_page_changed (w_current);

  /* 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_with_markup
        (GTK_WINDOW (w_current->main_window),
         GTK_DIALOG_DESTROY_WITH_PARENT,
         GTK_MESSAGE_ERROR,
         GTK_BUTTONS_CLOSE,
         _("<b>An error occurred while loading the requested file.</b>\n\nLoading from '%s' failed: %s. The gschem log may contain more information."),
         fn, 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);

    g_run_hook_page (w_current, "%new-page-hook", toplevel->page_current);
  }

  gschem_page_view_set_page (page_view,
                             toplevel->page_current);

  o_undo_savestate (w_current, toplevel->page_current, UNDO_ALL);

  /* 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;
}
Exemplo n.º 19
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void x_window_close(GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  gboolean last_window = FALSE;

  /* If we're closing whilst inside an action, re-wind the
   * page contents back to their state before we started */
  if (w_current->inside_action) {
    i_callback_cancel (w_current, 0, NULL);
  }

  /* last chance to save possible unsaved pages */
  if (!x_dialog_close_window (w_current)) {
    /* user somehow cancelled the close */
    return;
  }

  x_clipboard_finish (w_current);

#if DEBUG
  o_conn_print_hash(w_current->page_current->conn_table);
#endif

  w_current->dont_invalidate = TRUE;

  /* close all the dialog boxes */
  if (w_current->sowindow)
  gtk_widget_destroy(w_current->sowindow);

  if (w_current->cswindow)
  gtk_widget_destroy(w_current->cswindow);

  if (w_current->tiwindow)
  gtk_widget_destroy(w_current->tiwindow);

  if (w_current->tewindow)
  gtk_widget_destroy(w_current->tewindow);

  if (w_current->aawindow)
  gtk_widget_destroy(w_current->aawindow);

  x_multiattrib_close (w_current);

  if (w_current->aewindow)
  gtk_widget_destroy(w_current->aewindow);

  if (w_current->trwindow)
  gtk_widget_destroy(w_current->trwindow);

  x_pagesel_close (w_current);

  if (w_current->sswindow)
  gtk_widget_destroy(w_current->sswindow);

  if (w_current->iwindow)
  gtk_widget_destroy(w_current->iwindow);

  if (w_current->hkwindow)
  gtk_widget_destroy(w_current->hkwindow);

  if (w_current->cowindow)
  gtk_widget_destroy(w_current->cowindow);

  if (w_current->sewindow)
  gtk_widget_destroy(w_current->sewindow);

  if (g_list_length (global_window_list) == 1) {
    /* no more window after this one, remember to quit */
    last_window = TRUE;
  }

  if (toplevel->major_changed_refdes) {
    GList* current = toplevel->major_changed_refdes;
    while (current)
    {
      /* printf("yeah freeing: %s\n", (char*) current->data); */
      g_free(current->data);
      current = g_list_next(current);
    }
    g_list_free(toplevel->major_changed_refdes);
  }

  /* stuff that has to be done before we free w_current */
  if (last_window) {
    /* close the log file */
    s_log_close ();
    /* free the buffers */
    o_buffer_free (w_current);
  }

  x_window_free_gc(w_current);

  /* Clear Guile smob weak ref */
  if (w_current->smob != SCM_UNDEFINED) {
    SCM_SET_SMOB_DATA (w_current->smob, NULL);
    w_current->smob = SCM_UNDEFINED;
  }

  /* finally close the main window */
  gtk_widget_destroy(w_current->main_window);

  global_window_list = g_list_remove (global_window_list, w_current);
  gschem_toplevel_free (w_current);

  /* just closed last window, so quit */
  if (last_window) {
    gschem_quit();
  }
}
Exemplo n.º 20
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void x_window_create_main(GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

  GtkPolicyType policy;
  GtkWidget *main_box=NULL;
  GtkWidget *menubar=NULL;
  GtkWidget *toolbar=NULL;
  GtkWidget *handlebox=NULL;
  GtkWidget *hscrollbar;
  GtkWidget *vscrollbar;
  GtkAdjustment *hadjustment;
  GtkAdjustment *vadjustment;
  char *right_button_text;

  /* used to signify that the window isn't mapped yet */
  w_current->window = NULL;

  w_current->main_window = GTK_WIDGET (gschem_main_window_new ());

  gtk_widget_set_name (w_current->main_window, "gschem");
  gtk_window_set_policy (GTK_WINDOW (w_current->main_window), TRUE, TRUE, TRUE);

  /* We want the widgets to flow around the drawing area, so we don't
   * set a size of the main window.  The drawing area's size is fixed,
   * see below
   */

   /*
    * normally we let the window manager handle locating and sizing
    * the window.  However, for some batch processing of schematics
    * (generating a pdf of all schematics for example) we want to
    * override this.  Hence "auto_place_mode".
    */
   if( auto_place_mode )
   	gtk_widget_set_uposition (w_current->main_window, 10, 10);

  /* this should work fine */
  g_signal_connect (G_OBJECT (w_current->main_window), "delete_event",
                    G_CALLBACK (i_callback_close_wm),
                    w_current);

  /* Containers first */
  main_box = gtk_vbox_new(FALSE, 1);
  gtk_container_border_width(GTK_CONTAINER(main_box), 0);
  gtk_container_add(GTK_CONTAINER(w_current->main_window), main_box);

  menubar = get_main_menu (w_current);
  if (w_current->handleboxes) {
  	handlebox = gtk_handle_box_new ();
  	gtk_box_pack_start(GTK_BOX(main_box), handlebox, FALSE, FALSE, 0);
  	gtk_container_add (GTK_CONTAINER (handlebox), menubar);
  } else {
  	gtk_box_pack_start(GTK_BOX(main_box), menubar, FALSE, FALSE, 0);
  }

  w_current->menubar = menubar;
  gtk_widget_realize (w_current->main_window);

  if (w_current->handleboxes && w_current->toolbars) {
  	handlebox = gtk_handle_box_new ();
  	gtk_box_pack_start (GTK_BOX (main_box), handlebox, FALSE, FALSE, 0);
  }

  if (w_current->toolbars) {
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar),
                                 GTK_ORIENTATION_HORIZONTAL);
    gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);

    if (w_current->handleboxes) {
      gtk_container_add (GTK_CONTAINER (handlebox), toolbar);
    } else {
      gtk_box_pack_start(GTK_BOX(main_box), toolbar, FALSE, FALSE, 0);
    }

    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("New"),
                             _("New file"),
                             "toolbar/new",
                             x_window_stock_pixmap("new", w_current),
                             (GtkSignalFunc) i_callback_toolbar_file_new,
                             w_current);
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Open"),
                             _("Open file..."),
                             "toolbar/open",
                             x_window_stock_pixmap("open", w_current),
                             (GtkSignalFunc) i_callback_toolbar_file_open,
                             w_current);
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Save"),
                             _("Save file"),
                             "toolbar/save",
                             x_window_stock_pixmap("save", w_current),
                             (GtkSignalFunc) i_callback_toolbar_file_save,
                             w_current);
    gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Undo"),
                             _("Undo last operation"),
                             "toolbar/undo",
                             x_window_stock_pixmap("undo", w_current),
                             (GtkSignalFunc) i_callback_toolbar_edit_undo,
                             w_current);
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Redo"),
                             _("Redo last undo"),
                             "toolbar/redo",
                             x_window_stock_pixmap("redo", w_current),
                             (GtkSignalFunc) i_callback_toolbar_edit_redo,
                             w_current);
    gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
    /* not part of any radio button group */
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Component"),
                             _("Add component...\nSelect library and component from list, move the mouse into main window, click to place\nRight mouse button to cancel"),
                             "toolbar/component",
                             x_window_stock_pixmap("insert-symbol", w_current),
                             (GtkSignalFunc) i_callback_toolbar_add_component,
                             w_current);
    w_current->toolbar_net =
      gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
                                 NULL,
                                 _("Nets"),
                                 _("Add nets mode\nRight mouse button to cancel"),
                                 "toolbar/nets",
                                 x_window_stock_pixmap("insert-net", w_current),
                                 (GtkSignalFunc) i_callback_toolbar_add_net,
                                 w_current);
    w_current->toolbar_bus =
      gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
                                 w_current->toolbar_net,
                                 _("Bus"),
                                 _("Add buses mode\nRight mouse button to cancel"),
                                 "toolbar/bus",
                                 x_window_stock_pixmap("insert-bus", w_current),
                                 (GtkSignalFunc) i_callback_toolbar_add_bus,
                                 w_current);
    /* not part of any radio button group */
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
                             _("Text"),
                             _("Add Text..."),
                             "toolbar/text",
                             x_window_stock_pixmap("insert-text", w_current),
                             (GtkSignalFunc) i_callback_toolbar_add_text,
                             w_current);
    gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
    w_current->toolbar_select =
      gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
                                 w_current->toolbar_bus,
                                 _("Select"),
                                 _("Select mode"),
                                 "toolbar/select",
                                 x_window_stock_pixmap("select", w_current),
                                 (GtkSignalFunc) i_callback_toolbar_edit_select,
                                 w_current);


    gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_current->toolbar_select),
                                 TRUE);
  }


  /*  Try to create popup menu (appears in right mouse button  */
  w_current->popup_menu = (GtkWidget *) get_main_popup(w_current);


  /* Setup a GtkScrolledWindow for the drawing area */
  hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
                                                    0.0,
                                                    toplevel->init_right,
                                                    100.0,
                                                    100.0,
                                                    10.0));

  vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (toplevel->init_bottom,
                                                    0.0,
                                                    toplevel->init_bottom,
                                                    100.0,
                                                    100.0,
                                                    10.0));

  w_current->scrolled = gtk_scrolled_window_new (hadjustment, vadjustment);
  gtk_container_add(GTK_CONTAINER(main_box), w_current->scrolled);
  x_window_create_drawing(w_current->scrolled, w_current);
  x_window_setup_draw_events(w_current);

  policy = (w_current->scrollbars_flag) ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER;
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w_current->scrolled), policy, policy);

  hscrollbar = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (w_current->scrolled));
  gtk_range_set_update_policy (GTK_RANGE (hscrollbar), GTK_UPDATE_CONTINUOUS);

  vscrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (w_current->scrolled));
  gtk_range_set_update_policy (GTK_RANGE (vscrollbar), GTK_UPDATE_CONTINUOUS);

  /* macro box */
  w_current->macro_widget = GTK_WIDGET (g_object_new (GSCHEM_TYPE_MACRO_WIDGET, NULL));

  gtk_box_pack_start (GTK_BOX (main_box),
                      w_current->macro_widget,
                      FALSE,
                      FALSE,
                      0);

  g_signal_connect (w_current->macro_widget,
                    "response",
                    G_CALLBACK (&x_window_invoke_macro),
                    w_current);

  /* bottom box */
  if (default_third_button == POPUP_ENABLED) {
    right_button_text = _("Menu/Cancel");
  } else {
    right_button_text = _("Pan/Cancel");
  }

  w_current->bottom_widget = GTK_WIDGET (g_object_new (GSCHEM_TYPE_BOTTOM_WIDGET,
      "grid-mode",          gschem_options_get_grid_mode (w_current->options),
      "grid-size",          gschem_options_get_snap_size (w_current->options), /* x_grid_query_drawn_spacing (w_current), -- occurs before the page is set */
      "left-button-text",   _("Pick"),
      "middle-button-text", _("none"),
      "right-button-text",  right_button_text,
      "snap-mode",          gschem_options_get_snap_mode (w_current->options),
      "snap-size",          gschem_options_get_snap_size (w_current->options),
      "status-text",        _("Select Mode"),
      NULL));

  i_update_middle_button (w_current, NULL, NULL);

  gtk_box_pack_start (GTK_BOX (main_box), w_current->bottom_widget, FALSE, FALSE, 0);

  gtk_widget_show_all (w_current->main_window);

  w_current->window = w_current->drawing_area->window;

  w_current->drawable = w_current->window;

  x_window_setup_gc(w_current);
}
Exemplo n.º 21
0
/*! \brief Update a component.
 *
 * \par Function Description
 * Updates \a o_current to the latest version of the symbol available
 * in the symbol library, while preserving any attributes set in the
 * current schematic. On success, returns the new OBJECT which
 * replaces \a o_current on the page; \a o_current is deleted. On
 * failure, returns NULL, and \a o_current is left unchanged.
 *
 * \param [in]     w_current The GschemToplevel object.
 * \param [in,out] o_current The OBJECT to be updated.
 *
 * \return the new OBJECT that replaces \a o_current.
 */
OBJECT *
o_update_component (GschemToplevel *w_current, OBJECT *o_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *o_new;
  PAGE *page;
  GList *new_attribs;
  GList *old_attribs;
  GList *iter;
  const CLibSymbol *clib;

  g_return_val_if_fail (o_current != NULL, NULL);
  g_return_val_if_fail (o_current->type == OBJ_COMPLEX, NULL);
  g_return_val_if_fail (o_current->complex_basename != NULL, NULL);

  page = o_get_page (toplevel, o_current);

  /* Force symbol data to be reloaded from source */
  clib = s_clib_get_symbol_by_name (o_current->complex_basename);
  s_clib_symbol_invalidate_data (clib);

  if (clib == NULL) {
    s_log_message (_("Could not find symbol [%s] in library. Update failed.\n"),
                   o_current->complex_basename);
    return NULL;
  }

  /* Unselect the old object. */
  o_selection_remove (toplevel, page->selection_list, o_current);

  /* Create new object and set embedded */
  o_new = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
                         o_current->complex->x,
                         o_current->complex->y,
                         o_current->complex->angle,
                         o_current->complex->mirror,
                         clib, o_current->complex_basename,
                         1);
  if (o_complex_is_embedded (o_current)) {
    o_embed (toplevel, o_new);
  }

  new_attribs = o_complex_promote_attribs (toplevel, o_new);

  /* Cull any attributes from new COMPLEX that are already attached to
   * old COMPLEX. Note that the new_attribs list is kept consistent by
   * setting GList data pointers to NULL if their OBJECTs are
   * culled. At the end, the new_attribs list is updated by removing
   * all list items with NULL data. This is slightly magic, but
   * works. */
  for (iter = new_attribs; iter != NULL; iter = g_list_next (iter)) {
    OBJECT *attr_new = iter->data;
    gchar *name;
    gchar *value;

    g_assert (attr_new->type == OBJ_TEXT);

    o_attrib_get_name_value (attr_new, &name, NULL);

    value = o_attrib_search_attached_attribs_by_name (o_current, name, 0);
    if (value != NULL) {
      o_attrib_remove (toplevel, &o_new->attribs, attr_new);
      s_delete_object (toplevel, attr_new);
      iter->data = NULL;
    }

    g_free (name);
    g_free (value);
  }
  new_attribs = g_list_remove_all (new_attribs, NULL);

  /* Detach attributes from old OBJECT and attach to new OBJECT */
  old_attribs = g_list_copy (o_current->attribs);
  o_attrib_detach_all (toplevel, o_current);
  o_attrib_attach_list (toplevel, old_attribs, o_new, 1);
  g_list_free (old_attribs);

  /* Add new attributes to page */
  s_page_append_list (toplevel, page, new_attribs);

  /* Update pinnumbers for current slot */
  s_slot_update_object (toplevel, o_new);

  /* Replace old OBJECT with new OBJECT */
  s_page_replace (toplevel, page, o_current, o_new);
  s_delete_object (toplevel, o_current);

  /* Select new OBJECT */
  o_selection_add (toplevel, page->selection_list, o_new);

  /* mark the page as modified */
  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
  o_undo_savestate_old (w_current, UNDO_ALL);

  return o_new;
}
Exemplo n.º 22
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *  <B>type</B> can be one of the following values:
 *  <DL>
 *    <DT>*</DT><DD>UNDO_ACTION
 *    <DT>*</DT><DD>REDO_ACTION
 *  </DL>
 */
void
o_undo_callback (GschemToplevel *w_current, PAGE *page, int type)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  UNDO *u_current;
  UNDO *u_next;
  UNDO *save_bottom;
  UNDO *save_tos;
  UNDO *save_current;
  int save_logging;
  int find_prev_data=FALSE;

  char *save_filename;

  g_return_if_fail (w_current != NULL);
  g_return_if_fail (page != NULL);

  if (w_current->undo_control == FALSE) {
    s_log_message(_("Undo/Redo disabled in rc file\n"));
    return;
  }

  if (page->undo_current == NULL) {
    return;
  }

  if (type == UNDO_ACTION) {
    u_current = page->undo_current->prev;
  } else {
    u_current = page->undo_current->next;
  }

  u_next = page->undo_current;

  if (u_current == NULL) {
    return;
  }

  if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) {
#if DEBUG
    printf("Type: %d\n", u_current->type);
    printf("Current is an undo all, next is viewport only!\n");
#endif
    find_prev_data = TRUE;

    if (w_current->undo_type == UNDO_DISK) {
      u_current->filename = o_undo_find_prev_filename(u_current);
    } else {
      u_current->object_list = o_undo_find_prev_object_head (u_current);
    }
  }

  /* save filename */
  save_filename = g_strdup (page->page_filename);

  /* save structure so it's not nuked */
  save_bottom = page->undo_bottom;
  save_tos = page->undo_tos;
  save_current = page->undo_current;
  page->undo_bottom = NULL;
  page->undo_tos = NULL;
  page->undo_current = NULL;

  o_select_unselect_all (w_current);

  if (w_current->undo_type == UNDO_DISK && u_current->filename) {
    /* delete objects of page */
    s_page_delete_objects (toplevel, page);

    /* Free the objects in the place list. */
    geda_object_list_delete (toplevel, page->place_list);
    page->place_list = NULL;

    gschem_toplevel_page_content_changed (w_current, page);
  } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) {
    /* delete objects of page */
    s_page_delete_objects (toplevel, page);

    /* Free the objects in the place list. */
    geda_object_list_delete (toplevel, page->place_list);
    page->place_list = NULL;

    gschem_toplevel_page_content_changed (w_current, page);
  }


  /* temporarily disable logging */
  save_logging = do_logging;
  do_logging = FALSE;

  if (w_current->undo_type == UNDO_DISK && u_current->filename) {

    f_open(toplevel, page, u_current->filename, NULL);

  } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) {

    s_page_append_list (toplevel, page,
                        o_glist_copy_all (toplevel, u_current->object_list,
                                          NULL));
  }

  page->page_control = u_current->page_control;
  page->up = u_current->up;
  gschem_toplevel_page_content_changed (w_current, page);

  GschemPageView *view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (view != NULL);

  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view);

  if (u_current->scale != 0) {
    gschem_page_geometry_set_viewport (geometry,
                                       u_current->x,
                                       u_current->y,
                                       u_current->scale);
    gschem_page_view_invalidate_all (view);
  } else {
    gschem_page_view_zoom_extents (view, u_current->object_list);
  }

  /* restore logging */
  do_logging = save_logging;

  /* set filename right */
  g_free(page->page_filename);
  page->page_filename = save_filename;

  /* final redraw */
  x_pagesel_update (w_current);
  x_multiattrib_update (w_current);
  i_update_menus(w_current);

  /* restore saved undo structures */
  page->undo_bottom = save_bottom;
  page->undo_tos = save_tos;
  page->undo_current = save_current;

  if (type == UNDO_ACTION) {
    if (page->undo_current) {
      page->undo_current = page->undo_current->prev;
      if (page->undo_current == NULL) {
        page->undo_current = page->undo_bottom;
      }
    }
  } else { /* type is REDO_ACTION */
    if (page->undo_current) {
      page->undo_current = page->undo_current->next;
      if (page->undo_current == NULL) {
        page->undo_current = page->undo_tos;
      }
    }
  }

  /* don't have to free data here since filename, object_list are */
  /* just pointers to the real data (lower in the stack) */
  if (find_prev_data) {
    u_current->filename = NULL;
    u_current->object_list = NULL;
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif
}
Exemplo n.º 23
0
/*! \brief Create dialog to exchange picture objects
 *  \par Function Description
 *  This function opens a file chooser and replaces all pictures of the selections
 *  with the new picture.
 *
 *  \todo Maybe merge this dialog function with picture_selection_dialog()
 */
void picture_change_filename_dialog (GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  gchar *filename;
  gboolean result;
  GError *error = NULL;
  
  w_current->pfswindow = gtk_file_chooser_dialog_new (_("Select a picture file..."),
						      GTK_WINDOW(w_current->main_window),
						      GTK_FILE_CHOOSER_ACTION_OPEN,
						      GTK_STOCK_CANCEL, 
						      GTK_RESPONSE_CANCEL,
						      GTK_STOCK_OPEN, 
						      GTK_RESPONSE_ACCEPT,
						      NULL);

  /* Set the alternative button order (ok, cancel, help) for other systems */
  gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->pfswindow),
					  GTK_RESPONSE_ACCEPT,
					  GTK_RESPONSE_CANCEL,
					  -1);

  if (w_current->pixbuf_filename)
    gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current->pfswindow), 
				  w_current->pixbuf_filename);
    
  if (gtk_dialog_run (GTK_DIALOG (w_current->pfswindow)) == GTK_RESPONSE_ACCEPT) {

    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current->pfswindow));
    gtk_widget_destroy(w_current->pfswindow);
    w_current->pfswindow=NULL;

    /* Actually update the pictures */
    result = o_picture_exchange (w_current, filename, &error);

    if (!result) {
      GtkWidget *dialog;

      dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
				       GTK_DIALOG_DESTROY_WITH_PARENT,
				       GTK_MESSAGE_ERROR,
				       GTK_BUTTONS_CLOSE,
				       _("Failed to replace pictures: %s"),
				       error->message);
      /* Wait for any user response */
      gtk_dialog_run (GTK_DIALOG (dialog));

      g_error_free (error);
      gtk_widget_destroy(dialog);
    } else {
      gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
    }
    g_free (filename);
  }

  i_update_toolbar(w_current);
  if (w_current->pfswindow) {
    gtk_widget_destroy(w_current->pfswindow);
    w_current->pfswindow=NULL;
  }
}
Exemplo n.º 24
0
/*! \brief Creates the add image dialog
 *  \par Function Description
 *  This function creates the add image dialog and loads the selected picture.
 */
void picture_selection_dialog (GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  gchar *filename;
  GdkPixbuf *pixbuf;
  GError *error = NULL;
  
  w_current->pfswindow = gtk_file_chooser_dialog_new (_("Select a picture file..."),
						      GTK_WINDOW(w_current->main_window),
						      GTK_FILE_CHOOSER_ACTION_OPEN,
						      GTK_STOCK_CANCEL, 
						      GTK_RESPONSE_CANCEL,
						      GTK_STOCK_OPEN, 
						      GTK_RESPONSE_ACCEPT,
						      NULL);
  /* Set the alternative button order (ok, cancel, help) for other systems */
  gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->pfswindow),
					  GTK_RESPONSE_ACCEPT,
					  GTK_RESPONSE_CANCEL,
					  -1);

  if (w_current->pixbuf_filename)
    gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current->pfswindow), 
				  w_current->pixbuf_filename);
    
  if (gtk_dialog_run (GTK_DIALOG (w_current->pfswindow)) == GTK_RESPONSE_ACCEPT) {

    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current->pfswindow));
    gtk_widget_destroy(w_current->pfswindow);
    w_current->pfswindow=NULL;

    pixbuf = gdk_pixbuf_new_from_file (filename, &error);
    
    if (!pixbuf) {
      GtkWidget *dialog;
      
      dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
				       GTK_DIALOG_DESTROY_WITH_PARENT,
				       GTK_MESSAGE_ERROR,
				       GTK_BUTTONS_CLOSE,
				       _("Failed to load picture: %s"),
				       error->message);
      /* Wait for any user response */
      gtk_dialog_run (GTK_DIALOG (dialog));
      
      g_error_free (error);
      gtk_widget_destroy(dialog);
    }
    else {
#if DEBUG
      printf("Picture loaded succesfully.\n");
#endif
      
      o_invalidate_rubber(w_current);
      i_update_middle_button(w_current, i_callback_add_picture, _("Picture"));
      w_current->inside_action = 0;
      
      o_picture_set_pixbuf(w_current, pixbuf, filename);
    
      gschem_toplevel_page_content_changed (w_current, toplevel->page_current);
      i_set_state(w_current, DRAWPICTURE);
    }
    g_free (filename);
  }

  i_update_toolbar(w_current);
  if (w_current->pfswindow) {
    gtk_widget_destroy(w_current->pfswindow);
    w_current->pfswindow=NULL;
  }
}
/*! \brief Asks for confirmation before closing a window.
 *  \par Function Description
 *  This function asks the user to confirm its closing order for
 *  the given window.
 *
 *  The user is given the possibility to save the pages that currently
 *  have unsaved changes, if any.
 *
 *  It returns TRUE if the user really accepts the close of the
 *  window. Otherwise the user has somehow cancelled and the window
 *  must not be closed.
 *
 *  \param [in] w_current The toplevel environment.
 *  \returns TRUE if the window can be closed, FALSE otherwise.
 */
gboolean
x_dialog_close_window (GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  GList *iter;
  GtkWidget *dialog;
  PAGE *p_current;
  PAGE *keep_page;
  GList *unsaved_pages, *p_unsaved;
  gboolean ret = FALSE;

  keep_page = toplevel->page_current;

  for ( iter = geda_list_get_glist( toplevel->pages ), unsaved_pages = NULL;
        iter != NULL;
        iter = g_list_next( iter ) ) {

    p_current = (PAGE*)iter->data;

    if (p_current->CHANGED) {
      unsaved_pages = g_list_append (unsaved_pages, (gpointer)p_current);
    }
  }

  if (unsaved_pages == NULL) {
    /* no page with unsaved changes, close window */
    return TRUE;
  }

  dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
                                     "unsaved-pages", unsaved_pages,
                                     NULL));

  gtk_window_set_transient_for (GTK_WINDOW (dialog),
                                GTK_WINDOW (w_current->main_window));

  g_list_free (unsaved_pages);
  switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
      case GTK_RESPONSE_NO:
        /* action selected: close without saving */
        /* discard changes, ok to close window */
        ret = TRUE;
        break;

      case GTK_RESPONSE_YES:
        /* action selected: save */
        g_object_get (dialog,
                      "selected-pages", &unsaved_pages,
                      NULL);
        for (p_unsaved = unsaved_pages, ret = TRUE;
             p_unsaved != NULL;
             p_unsaved = g_list_next (p_unsaved)) {
          p_current = (PAGE*)p_unsaved->data;

          s_page_goto (toplevel, p_current);
          gschem_toplevel_page_changed (w_current);

          i_callback_file_save(w_current, 0, NULL);
          /* if user cancelled previous, do not close window */
          ret &= !p_current->CHANGED;
        }
        g_list_free (unsaved_pages);
        break;

      case GTK_RESPONSE_CANCEL:
        /* action selected: cancel */
        /* fall through */
      default:
        /* Hit when the user breaks out of the dialog with the escape key
         * or otherwise destroys the dialog window without a proper response */
        ret = FALSE;
        break;
  }
  gtk_widget_destroy (dialog);

  /* Switch back to the page we were on */
  g_return_val_if_fail (keep_page != NULL, ret);
  s_page_goto (toplevel, keep_page);
  gschem_toplevel_page_changed (w_current);

  return ret;
}
Exemplo n.º 26
0
/* text item */
OBJECT *o_attrib_add_attrib(GschemToplevel *w_current,
			    const char *text_string, int visibility, 
			    int show_name_value, OBJECT *object)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *new_obj;
  int world_x = - 1, world_y = -1;
  int align = LOWER_LEFT;
  int angle = 0;
  int color;
  int left, right, top, bottom;
  OBJECT *o_current;

  color = DETACHED_ATTRIBUTE_COLOR;

  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):
      case(OBJ_PLACEHOLDER):
        world_x = o_current->complex->x;
        world_y = o_current->complex->y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_ARC):
        world_x = o_current->arc->x;
        world_y = o_current->arc->y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_CIRCLE):
        world_x = o_current->circle->center_x;
        world_y = o_current->circle->center_y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_BOX):
        world_x = o_current->box->upper_x;
        world_y = o_current->box->upper_y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_LINE):
      case(OBJ_NET):
      case(OBJ_PIN):
      case(OBJ_BUS):
        {
          int dx = o_current->line->x[1] - o_current->line->x[0];
          int dy = o_current->line->y[1] - o_current->line->y[0];

          if (dy == 0) {
              if (dx > 0) {
                  world_x = o_current->line->x[0] + SPACING_FROM_END;
                  world_y = o_current->line->y[0] + SPACING_PERPENDICULAR;

                  align = LOWER_LEFT;
                  angle = 0;
              }
              else {
                  world_x = o_current->line->x[0] - SPACING_FROM_END;
                  world_y = o_current->line->y[0] + SPACING_PERPENDICULAR;

                  align = LOWER_RIGHT;
                  angle = 0;
              }
          }
          else if (dx == 0) {
              if (dy > 0) {
                  world_x = o_current->line->x[0] - SPACING_PERPENDICULAR;
                  world_y = o_current->line->y[0] + SPACING_FROM_END;

                  align = LOWER_LEFT;
                  angle = 90;
              }
              else {
                  world_x = o_current->line->x[0] - SPACING_PERPENDICULAR;
                  world_y = o_current->line->y[0] - SPACING_FROM_END;

                  align = LOWER_RIGHT;
                  angle = 90;
              }
          }
          else {
              world_x = o_current->line->x[0];
              world_y = o_current->line->y[0];

              align = LOWER_LEFT;
              angle = 0;
          }

          color = ATTRIBUTE_COLOR;
        }
        break;

      case(OBJ_TEXT):
        world_x = o_current->text->x;
        world_y = o_current->text->y;
        color = DETACHED_ATTRIBUTE_COLOR;
        align = LOWER_LEFT;
        angle = 0;
        o_current = NULL;
        break;
    }
  } else {
    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); */
    align = LOWER_LEFT;
    angle = 0;
    color = DETACHED_ATTRIBUTE_COLOR;
  }

  /* first create text item */
  new_obj = o_text_new(toplevel, color, world_x, world_y,
                       align, angle, text_string,
                       w_current->text_size, /* current text size */
                       visibility, show_name_value);
  s_page_append (toplevel, toplevel->page_current, new_obj);

  /* 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);

  /* handle slot= attribute, it's a special case */
  if (o_current != NULL &&
      g_ascii_strncasecmp (text_string, "slot=", 5) == 0) {
    o_slot_end (w_current, o_current, text_string);
  }

  /* Call add-objects-hook. */
  g_run_hook_object (w_current, "%add-objects-hook", new_obj);
  g_run_hook_object (w_current, "%select-objects-hook", new_obj);

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);

  return new_obj;
}
Exemplo n.º 27
0
/*! \brief Find an OBJECT at a given set of coordinates
 *
 *  \par Function Description
 *  Tests for OBJECTS hit at a given set of coordinates. If
 *  change_selection is TRUE, it updates the page's selection.
 *
 *  Find operations resume searching after the last object which was
 *  found, so multiple find operations at the same point will cycle
 *  through any objects on top of each other at this location.
 *
 *  \param [in] w_current         The GschemToplevel object.
 *  \param [in] w_x               The X coordinate to test (in world coords).
 *  \param [in] w_y               The Y coordinate to test (in world coords).
 *  \param [in] change_selection  Whether to select the found object or not.
 *  \returns TRUE if the object was hit at the given coordinates,
 *           otherwise FALSE.
 */
gboolean o_find_object (GschemToplevel *w_current, int w_x, int w_y,
                        gboolean change_selection)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_val_if_fail (page_view != NULL, FALSE);

  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  g_return_val_if_fail (toplevel != NULL, FALSE);

  int w_slack;
  const GList *iter = NULL;

  w_slack = gschem_page_view_WORLDabs (page_view, w_current->select_slack_pixels);

  /* Decide whether to iterate over all object or start at the last
     found object. If there is more than one object below the
     (w_x/w_y) position, this will select the next object below the
     position point. You can change the selected object by clicking
     at the same place multiple times. */
  if (toplevel->page_current->object_lastplace != NULL) {
    /* NB: g_list_find doesn't declare its input const, so we cast */
    iter = g_list_find ((GList *)s_page_objects (toplevel->page_current),
                        toplevel->page_current->object_lastplace);
    iter = g_list_next (iter);
  }

  /* do first search (if we found any objects after the last found object) */
  while (iter != NULL) {
    OBJECT *o_current = iter->data;
    if (find_single_object (w_current, o_current,
                            w_x, w_y, w_slack, change_selection)) {
      return TRUE;
    }
    iter = g_list_next (iter);
  }

  /* now search from the beginning up until the object_lastplace */
  for (iter = s_page_objects (toplevel->page_current);
       iter != NULL; iter = g_list_next (iter)) {
    OBJECT *o_current = iter->data;
    if (find_single_object (w_current, o_current,
                            w_x, w_y, w_slack, change_selection)) {
      return TRUE;
    }
    /* break once we've inspected up to where we started the first loop */
    if (o_current == toplevel->page_current->object_lastplace)
      break;
  }

  /* didn't find anything.... reset lastplace */
  toplevel->page_current->object_lastplace = NULL;

  /* deselect everything only if shift key isn't pressed and
     the caller allows it */
  if (change_selection && (!w_current->SHIFTKEY)) {
    o_select_unselect_all (w_current);
  }

  i_update_menus(w_current);
  return FALSE;
}
Exemplo n.º 28
0
/*! \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

}
Exemplo n.º 29
0
 * \return the newly created text object.
 */
SCM_DEFINE (add_attrib_x, "%add-attrib!", 5, 0, 0,
            (SCM target_s, SCM name_s, SCM value_s, SCM visible_s, SCM show_s),
            "Add an attribute to an object, or floating")
{
  SCM_ASSERT ((edascm_is_page (target_s) ||
               edascm_is_object (target_s) ||
               scm_is_false (target_s)),
              target_s, SCM_ARG1, s_add_attrib_x);
  SCM_ASSERT (scm_is_string (name_s), name_s, SCM_ARG2, s_add_attrib_x);
  SCM_ASSERT (scm_is_string (value_s), value_s, SCM_ARG3, s_add_attrib_x);
  SCM_ASSERT (scm_is_symbol (show_s), show_s, SCM_ARG5, s_add_attrib_x);

  GschemToplevel *w_current = g_current_window ();
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);

  /* Check target object, if present */
  OBJECT *obj = NULL;
  if (edascm_is_object (target_s)) {
    obj = edascm_to_object (target_s);
    if (o_get_page (toplevel, obj) != toplevel->page_current) {
      scm_error (object_state_sym,
                 s_add_attrib_x,
                 _("Object ~A is not included in the current gschem page."),
                 scm_list_1 (target_s), SCM_EOL);
    }
  }

  /* Visibility */
  int visibility;
Exemplo n.º 30
0
/*! \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 GschemToplevel object to search for autosave's.
 */
void o_autosave_backups(GschemToplevel *w_current)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  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);
      gschem_toplevel_page_changed (w_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);
  gschem_toplevel_page_changed (w_current);
}