Passing values from spinbutton callbacks to a calculation/drawing function via activate() in main()

Hi there and thanks for your time,

Problem(s): To pass single-values and arrays between functions in seperate source files without using extern global definitions, or writing then reading to and from an intermediate text file.

I’m using GTK+3. on Ubuntu 18.04.1 LTS with C language. A simplified version of my app is provided to show the problem, it consists of three c-source code files : 1) simplified.c (with main()), 2) callback_drawing1.c & 3) callback_drawing2.c, as well as the header file globals.h, Makefile and simplified.ui. The (simplified) app uses 4 SpinButtons (simplified.ui and associated callbacks in simplified.c) to define 2 points to which a straight line equation is fitted and drawn (in callback_drawing1.c) and the resulting array is then transferred to a function in another file (callback_drawing2.c) by writing to, then reading from, an intermediate text file.

In order to facilitate efficient use of my app on a web-server (to avoid name-clashes and writing to the hard-drive) I don’t want to use global definitions and writing/reading files to transfer data between functions, as they are at present, but haven’t yet succeeded in doing this as everything is done by the gtk_builder in the activate() function, and that has so far proved to be rather opaque. I have tried passing the values as arguments to the drawing functions (with and without) using return values in the SpinButton callbacks, as well as various other builder functions, and coded g_signal_connect() in activate(). It compiles but the values aren’t passed. What am I missing here, what do I need to do? Is the problem(s) one of C-programming or of GTK+ ? Should I unpack the contents of activate() back into main() and re-code ‘by hand’ rather than with builder.ui (big job!)?

Roger.

/*Start of globals.h *************************************************************/
float x1_line = 200.0;
float y1_line = 200.0;
float x2_line = 600.0;
float y2_line = 600.0;
/*End of globals.h *************************************************************/

/*Start of simplified.c *** contains main() *****************************************/
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdlib.h>
#include <gtk/gtk.h>

#include "globals.h"
/**********************/
void callback_x1_line (GtkSpinButton *spin_button, GtkBuilder *builder)
{
 GtkWidget *drawing_area1;
 int x_da;
 int y_da;
 extern float x1_line;

 x1_line = gtk_spin_button_get_value (spin_button);

 drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, "drawing_area1");
 gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);
 gtk_widget_set_size_request (drawing_area1, x_da, y_da);
 gtk_widget_queue_resize (drawing_area1);
}
/**********************/
void callback_y1_line (GtkSpinButton *spin_button, GtkBuilder *builder)
{
 GtkWidget *drawing_area1;
 int x_da;
 int y_da;
 extern float y1_line;

 y1_line = gtk_spin_button_get_value (spin_button);

 drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, "drawing_area1");
 gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);
 gtk_widget_set_size_request (drawing_area1, x_da, y_da);
 gtk_widget_queue_resize (drawing_area1);
}
/**********************/
void callback_x2_line (GtkSpinButton *spin_button, GtkBuilder *builder)
{
 GtkWidget *drawing_area1;
 int x_da;
 int y_da;
 extern float x2_line;

 x2_line = gtk_spin_button_get_value (spin_button);

 drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, "drawing_area1");
 gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);
 gtk_widget_set_size_request (drawing_area1, x_da, y_da);
 gtk_widget_queue_resize (drawing_area1);
}
/**********************/
void callback_y2_line (GtkSpinButton *spin_button, GtkBuilder *builder)
{
 GtkWidget *drawing_area1;
 int x_da;
 int y_da;
 extern float y2_line;

 y2_line = gtk_spin_button_get_value (spin_button);

 drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, "drawing_area1");
 gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);
 gtk_widget_set_size_request (drawing_area1, x_da, y_da);
 gtk_widget_queue_resize (drawing_area1);
}
/**********************/
 GdkPixbuf *create_pixbuf1(const gchar * filename)
 {
 GdkPixbuf *pixbuf1;
 GError *error = NULL;
 pixbuf1 = gdk_pixbuf_new_from_file(filename, &error);
   if(!pixbuf1)
   {
   fprintf(stderr, "%s\n", error->message);
   g_error_free(error);
   }
 return pixbuf1;
 }
/**********************/
static void
activate (GtkApplication *app, gpointer user_data)
{
 int   argc;
 char **argv;
 GtkBuilder *builder;
 GtkWidget *window;

gtk_init (&argc, &argv);

builder = gtk_builder_new_from_file ("simplified.ui");
gtk_builder_connect_signals (builder, builder);
window = (GtkWidget *) gtk_builder_get_object (builder, "window");
gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf1("simplified.png"));
gtk_widget_show (window);

gtk_main ();

return;
}/*End of activate()*/
/**********************/
int main (int argc, char **argv)
{
struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY};
setrlimit(RLIMIT_STACK, &rlim);

  GtkApplication *app;
  int status;
  app = gtk_application_new ("roger.simplified", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);

  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);
  return status;
}/*End of main()*/
/*End of simplified.c *************************************************************/

/*Start of callback_drawing1.c *****************************************************/
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>

gboolean callback_drawing1 (GtkWidget *widget, cairo_t *cr)
{
int x_da;
int y_da;
GdkRGBA color;
GtkStyleContext *context;
extern float x1_line, y1_line, x2_line, y2_line;
int i;

context = gtk_widget_get_style_context (widget);
x_da = gtk_widget_get_allocated_width (widget);
y_da = gtk_widget_get_allocated_height (widget);
gtk_render_background (context, cr, 0, 0, x_da, y_da);

  cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
  cairo_paint(cr);

  cairo_set_source_rgba(cr, 0.6, 0, 0, 1.0);
  cairo_set_line_width(cr, 5.0);
  cairo_move_to(cr, x1_line, y1_line);
  cairo_line_to(cr, x2_line, y2_line);
  cairo_stroke(cr);

  double line_slope[1001];
  for (i=0; i<=1000; i++)
  {
  line_slope[i] = (y2_line-y1_line)/(x2_line-x1_line);
  }

  double line_yintercept[1001];
  for (i=0; i<=1000; i++)
  {
  line_yintercept[i] = y2_line-line_slope[i]*x2_line;
  }

  double line[1001];
  for (i=0; i<=1000; i++)
  {
  line[i] = (line_slope[i]*(double)i)+line_yintercept[i];
  }

  FILE* outfile_line = fopen("file_line", "w");
  for (i=0; i<=1000; i++)
  {
  fprintf(outfile_line,"%f\n", line[i]);
  }
  fclose(outfile_line);

  cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
  cairo_set_line_width(cr, 1.0);
  cairo_move_to(cr, 0, line[0]);
  for (i=0; i<=1000; i++)
  {
  cairo_line_to(cr, i, line[i]);
  }
  cairo_stroke(cr);

return FALSE;
}
/*End of callback_drawing1.c ******************************************************/

/*Start of callback_drawing2.c ******************************************************/
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>

gboolean callback_drawing2 (GtkWidget *widget, cairo_t *cr)
{
int x_da;
int y_da;
GdkRGBA color;
GtkStyleContext *context;
extern float x1_line, y1_line, x2_line, y2_line;
int i;

context = gtk_widget_get_style_context (widget);

x_da = gtk_widget_get_allocated_width (widget);
y_da = gtk_widget_get_allocated_height (widget);

gtk_render_background (context, cr, 0, 0, x_da, y_da);

  cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
  cairo_paint(cr);

  double line[1001];
  FILE* infile_line = fopen("file_line", "r");
  for (i=0; i<=1000; i++)
  {
  fscanf(infile_line,"%lf\n", &line[i]);
  }
  fclose(infile_line);

  cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
  cairo_set_line_width(cr, 1.0);
  cairo_move_to(cr, 0, line[0]);
  for (i=0; i<=1000; i++)
  {
  cairo_line_to(cr, i, line[i]);
  }
  cairo_stroke(cr);

return FALSE;
}
/*End of callback_drawing2.c ******************************************************/
/*Start of Makefile ***************************************************************/
CC       = gcc
CFLAGS   = `pkg-config --cflags gtk+-3.0`
CPPFLAGS = -mcmodel=large -rdynamic
LIBS     = `pkg-config --libs gtk+-3.0` -lm

all: simplified

simplified: simplified.o callback_drawing1.o callback_drawing2.o
	$(CC) $(CPPFLAGS) $(CFLAGS) -o simplified simplified.o callback_drawing1.o callback_drawing2.o $(LIBS)

clean:
	rm -f simplified
	rm -f *.o

.PHONY: all clean
/*End of Makefile ***************************************************************/
/*Start of simplified.ui ************************************************************/
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.10"/>
  <object class="GtkAdjustment" id="adjustment_y_da">
    <property name="upper">620</property>
    <property name="lower">100</property>
    <property name="value">484</property>
    <property name="step_increment">2</property>
    <property name="page_increment">2</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_scrolledwindow">
    <property name="upper">800</property>
    <property name="lower">0</property>
    <property name="value">300</property>
    <property name="step_increment">1</property>
    <property name="page_increment">1</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_x1_line">
    <property name="upper">500.0</property>
    <property name="lower">0.0</property>
    <property name="value">200.0</property>
    <property name="step_increment">1.0</property>
    <property name="page_increment">1.0</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_y1_line">
    <property name="upper">1001.0</property>
    <property name="lower">0.0</property>
    <property name="value">200.0</property>
    <property name="step_increment">1.0</property>
    <property name="page_increment">1.0</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_x2_line">
    <property name="upper">1001.0</property>
    <property name="lower">501.0</property>
    <property name="value">600.0</property>
    <property name="step_increment">1.0</property>
    <property name="page_increment">1.0</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_y2_line">
    <property name="upper">1001.0</property>
    <property name="lower">0.0</property>
    <property name="value">600.0</property>
    <property name="step_increment">1.0</property>
    <property name="page_increment">1.0</property>
  </object>
  <object class="GtkAdjustment" id="adjustment_scrolledwindow2">
    <property name="upper">800</property>
    <property name="lower">0</property>
    <property name="value">300</property>
    <property name="step_increment">1</property>
    <property name="page_increment">1</property>
  </object>
  <object class="GtkWindow" id="window">
    <property name="title">Simplified App</property>
    <property name="can_focus">False</property>
    <property name="default_width">1200</property>
    <property name="default_height">720</property>
    <signal name="delete-event" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object id="notebook" class="GtkNotebook">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <child>
          <object class="GtkBox" id="box1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkScrolledWindow" id="scrolledwindow">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="vexpand">True</property>
                <property name="shadow_type">in</property>
                <property name="vadjustment">adjustment_scrolledwindow</property>
                <child>
                  <object class="GtkViewport" id="viewport">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkDrawingArea" id="drawing_area1">
                        <property name="width_request">4000</property>
                        <property name="height_request">800</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="halign">start</property>
                        <property name="valign">start</property>
                        <signal name="draw" handler="callback_drawing1" swapped="no"/>
                      </object>
                    </child> <!--drawing_area -->
                  </object>
                </child> <!--viewport_line -->
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child> <!--scrolledwindow_line -->
            <child>
              <object class="GtkBox" id="box2_line">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="orientation">vertical</property>
                <child>
                  <object class="GtkButtonBox" id="buttonbox1_line">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="layout_style">spread</property>
                    <child>
                      <object class="GtkLabel" id="label_x1_line">
                        <property name="label">x1</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="label_y1_line">
                        <property name="label">y1</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="label_x2_line">
                        <property name="label">x2</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">4</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="label_y2_line">
                        <property name="label" >y2</property>
                        <property name="visible">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">6</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">3</property>
                  </packing>
                </child> <!--buttonbox1_line -->
                <child>
                  <object class="GtkButtonBox" id="buttonbox2_line">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="layout_style">spread</property>
                    <child>
                      <object class="GtkSpinButton" id="spin_x1_line">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="numeric">True</property>
                        <property name="snap-to-ticks">True</property>
                        <property name="progress_pulse_step">1</property>
                        <property name="adjustment">adjustment_x1_line</property>
                        <property name="climb_rate">1.0</property>
                        <property name="value">200.0</property>
                        <signal name="value-changed" handler="callback_x1_line" swapped="no"/>
                        <signal name="scroll-event" handler="gtk_true" swapped="no"/>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child> <!--spin_x1_line -->
                    <child>
                      <object class="GtkSpinButton" id="spin_y1_line">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="numeric">True</property>
                        <property name="snap-to-ticks">True</property>
                        <property name="progress_pulse_step">1</property>
                        <property name="adjustment">adjustment_y1_line</property>
                        <property name="climb_rate">1.0</property>
                        <property name="value">200.0</property>
                        <signal name="value-changed" handler="callback_y1_line" swapped="no"/>
                        <signal name="scroll-event" handler="gtk_true" swapped="no"/>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child> <!--spin_y1_line -->
                    <child>
                      <object class="GtkSpinButton" id="spin_x2_line">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="numeric">True</property>
                        <property name="snap-to-ticks">True</property>
                        <property name="progress_pulse_step">1</property>
                        <property name="adjustment">adjustment_x2_line</property>
                        <property name="climb_rate">1.0</property>
                        <property name="value">600.0</property>
                        <signal name="value-changed" handler="callback_x2_line" swapped="no"/>
                        <signal name="scroll-event" handler="gtk_true" swapped="no"/>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">4</property>
                      </packing>
                    </child> <!--spin_x2_line -->
                    <child>
                      <object class="GtkSpinButton" id="spin_y2_line">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="numeric">True</property>
                        <property name="snap-to-ticks">True</property>
                        <property name="progress_pulse_step">1</property>
                        <property name="adjustment">adjustment_y2_line</property>
                        <property name="climb_rate">1.0</property>
                        <property name="value">600.0</property>
                        <signal name="value-changed" handler="callback_y2_line" swapped="no"/>
                        <signal name="scroll-event" handler="gtk_true" swapped="no"/>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">6</property>
                      </packing>
                    </child> <!--spin_y2_line -->
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">False</property>
                    <property name="position">4</property>
                  </packing>
                </child> <!--buttonbox2_line -->
              </object>
            </child> <!--box2_line -->
          </object>
        </child> <!--box1 -->
        <child type="tab">
          <object class="GtkLabel" id="tab1">
            <property name="label">Page1</property>
          </object>
        </child> <!--tab1 -->
        <child>
          <object class="GtkBox" id="box2">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkScrolledWindow" id="scrolledwindow2">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="vexpand">True</property>
                <property name="shadow_type">in</property>
                <property name="vadjustment">adjustment_scrolledwindow2</property>
                <child>
                  <object class="GtkViewport" id="viewport2">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkDrawingArea" id="drawing_area2">
                        <property name="width_request">4000</property>
                        <property name="height_request">800</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="halign">start</property>
                        <property name="valign">start</property>
                        <signal name="draw" handler="callback_drawing2" swapped="no"/>
                      </object>
                    </child> <!--drawing_area2 -->
                  </object>
                </child> <!--viewport2 -->
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child> <!--scrolledwindow2 -->
          </object>
        </child> <!--box2 -->
        <child type="tab">
          <object class="GtkLabel" id="tab2">
            <property name="label">Page2</property>
          </object>
        </child> <!--tab2 -->
      </object>
    </child> <!--notebook -->
    <child type="titlebar">
      <placeholder/>
    </child> <!--window -->
  </object>
</interface>
/*End of simplified.ui ************************************************************/

First off, the idiomatic way to use global variables is to declare them extern in a header file, and define them in exactly one source file. Your code only works because you only include globals.h once.

For the bigger picture, you can use the user_data parameter to gtk_builder_connect_signals to pass data between your callbacks. At minimum, you can define a struct containing the float coords, some sort of array (e.g. an inline C array or a pointer to a GArray), and whatever else you need access to. In activate, allocate one with g_new0, and fill in the contents.

P.S. The documentation for gtk_builder_connect_signals says you need to link against gmodule-export-2.0 on posix systems.

It’s worth mentioning that you don’t have to use connect_signals; if you prefer, you can build your UI in GtkBuilder, and connect your signals in C. You may also consider using GtkBuilder templates, this is how many larger applications are built.

Hi Roger,

For your “activate” signal, a simple way is to have a static global in simplified.c that gets set. Then use gtk_widget_queue_draw() in the activate callback which calls your main draw callback for a redraw. If you have everything figured out and want to put your variables in a struct that can be passed to the “draw” callback that can be done also.

GArrays work good for moving drawing data around. You can even use an array of structs to add some flexibility with what you want to draw.

If you are outputting content for a web server, cairo can output your drawing to a .png, .pdf or .svg easy enough and then that can be published on the web server.

This might give you some ideas. The combo3d_combo_UI.c in

uses a cairo3d.c file to do some drawing and layout. It might be helpful for what you are working on.

Eric

Hi Chris and Eric,

thanks for your rapid replies, including:

Eric: “For your “activate” signal, a simple way is to have a static global in
simplified.c that gets set.”

Me: Could you please elaborate on the above, the program you suggested that I might find helpful doesn’t contain an activate() function, it’s all done from main(). I guess my question is
really this: If I build my app from main() without activate() is it still an ‘app’ or not? The reason I’m using activate() is to build the gui with builder.ui, previous versions of my program were coded in main() with calls to on_draw_event() to do_drawing(),
this worked but the problem was that the drawing would have to be re-drawn seperately after changing the spinbutton, whereas with the builder.ui and the -rdynamic flag in Makefile the drawing is updated with each click on the spinbutton, which will be much
better for future users.

Chris: “For the bigger picture, you can use the
user_data parameter to
gtk_builder_connect_signals to pass data between your callbacks.
At minimum, you can define a struct containing the float coords, some sort of array (e.g. an inline C array or a pointer to a
GArray), and whatever else you need access to. In
activate, allocate one with
g_new0, and fill in the contents.

P.S. The documentation for
gtk_builder_connect_signals says you need to link against gmodule-export-2.0
on posix systems.

Me: I have attempted to pass the structure ‘struct1’ as user_data into gtk_builder_connect_signals() in activate() as shown below. I have also attempted to pass as arguments the individual
structure members to the spinbutton callbacks but this can’t be done in activate() gtk_builder_connect_signals (builder, user_data) because it can only accept two arguments.

Following some examples found in several books on C programming I have
declared the structure globally (in globals.h) and defined the structure member values in main() (and also tried defining in activate()), although whether the 4th parameter of g_signal_connect (app, “activate”, G_CALLBACK (activate),
/NULL/ &struct1); is NULL or &struct1 makes no difference, ie., the program compiles, the gui is created but with an empty drawing area and when any of the spinbuttons are changed the new value is read, then the printf() call shows the new value, but then
the program crashes with a segmentation fault (with or without a return value in the spinbutton callbacks (whether as whole structure or as an individual structure.member)).

I have also attempted to link against gmodule-export-2.0 as in Makefile below, I don’t know how to do this but the addition of LIBS2 to the compile line of Makefile made no difference.

Thanks, Roger.

Compiled with:

/Start of Makefile************************************************************/

CC
= gcc

CFLAGS
= pkg-config --cflags gtk+-3.0

CPPFLAGS = -mcmodel=large -rdynamic

LIBS
= pkg-config --libs gtk+-3.0 -lm

LIBS2
= pkg-config --libs gmodule-export-2.0 -lrt

all: simplified

simplified: simplified.o callback_drawing1.o callback_drawing2.o

$(CC) $(CPPFLAGS) $(CFLAGS) -o simplified simplified.o callback_drawing1.o callback_drawing2.o $(LIBS) $(LIBS2)

clean:

rm -f simplified

rm -f *.o

.PHONY: all clean

/End of Makefile*************************************************************/

/Start of globals.h********************************************************/

/*float x1_line = 200.0;

float y1_line = 200.0;

float x2_line = 600.0;

float y2_line = 600.0;*/

struct Struct1{

gfloat x1_line;

gfloat y1_line;

gfloat x2_line;

gfloat y2_line;

};

typedef struct Struct1 struct1;

/End of globals.h********************************************************/

/Start of simplified.c********************************************************/

#include <stdio.h>

#include <math.h>

#include <errno.h>

#include <sys/time.h>

#include <sys/resource.h>

#include <stdlib.h>

#include <gtk/gtk.h>

#include “globals.h”

/********************************************************************/

struct1 callback_x1_line (GtkSpinButton *spin_button, GtkBuilder *builder, struct Struct1 *struct1)

{

GtkWidget *drawing_area1;

int x_da;

int y_da;

/* (struct1).x1_line = gtk_spin_button_get_value (spin_button);/

struct1->x1_line = gtk_spin_button_get_value (spin_button);

printf(“callback_x1_line= %f\n”, struct1->x1_line);

printf(“callback_y1_line= %f\n”, struct1->y1_line);

printf(“callback_x2_line= %f\n”, struct1->x2_line);

printf(“callback_y2_line= %f\n”, struct1->y2_line);

drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, “drawing_area1”);

gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);

gtk_widget_set_size_request (drawing_area1, x_da, y_da);

gtk_widget_queue_resize (drawing_area1);

/*return (struct1).x1_line;/

/return struct1->x1_line;/

return *struct1;

}

/********************************************************************/

gfloat /void/ callback_y1_line (GtkSpinButton *spin_button, GtkBuilder *builder, struct Struct1 *struct1)

{

GtkWidget *drawing_area1;

int x_da;

int y_da;

(*struct1).y1_line = gtk_spin_button_get_value (spin_button);

printf(“callback_y1_line= %f\n”, (*struct1).y1_line);

drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, “drawing_area1”);

gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);

gtk_widget_set_size_request (drawing_area1, x_da, y_da);

gtk_widget_queue_resize (drawing_area1);

return (*struct1).y1_line;

}

/********************************************************************/

gfloat callback_x2_line (GtkSpinButton *spin_button, GtkBuilder *builder, struct Struct1 *struct1)

{

GtkWidget *drawing_area1;

int x_da;

int y_da;

(*struct1).x2_line = gtk_spin_button_get_value (spin_button);

printf(“callback_x2_line= %f\n”, (*struct1).x2_line);

drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, “drawing_area1”);

gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);

gtk_widget_set_size_request (drawing_area1, x_da, y_da);

gtk_widget_queue_resize (drawing_area1);

return (*struct1).x2_line;

}

/********************************************************************/

gfloat callback_y2_line (GtkSpinButton *spin_button, GtkBuilder *builder, struct Struct1 *struct1)

{

/Struct1 params_line;/

GtkWidget *drawing_area1;

int x_da;

int y_da;

(*struct1).y2_line = gtk_spin_button_get_value (spin_button);

printf(“callback_y2_line= %f\n”, (*struct1).y2_line);

drawing_area1 = (GtkWidget*) gtk_builder_get_object (builder, “drawing_area1”);

gtk_widget_get_size_request (drawing_area1, &x_da, &y_da);

gtk_widget_set_size_request (drawing_area1, x_da, y_da);

gtk_widget_queue_resize (drawing_area1);

return (*struct1).y2_line;

}

/********************************************************************/

GdkPixbuf *create_pixbuf1(const gchar * filename)

{

GdkPixbuf *pixbuf1;

GError *error = NULL;

pixbuf1 = gdk_pixbuf_new_from_file(filename, &error);

if(!pixbuf1)

{

fprintf(stderr, “%s\n”, error->message);

g_error_free(error);

}

return pixbuf1;

}

/********************************************************************/

static void

/*activate (GtkApplication app, gpointer user_data)/

activate (GtkApplication *app, struct Struct1 *struct1)

{

int
argc;

char **argv;

GtkBuilder *builder;

GtkWidget *window;

gtk_init (&argc, &argv);

builder = gtk_builder_new_from_file (“simplified.ui”);

/gtk_builder_connect_signals (builder, builder);/

gtk_builder_connect_signals (builder, &struct1);

window = (GtkWidget *) gtk_builder_get_object (builder, “window”);

gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf1(“simplified.png”));

gtk_widget_show (window);

gtk_main ();

return;

}/End of activate()/

/*****************************/

int main (int argc, char **argv)

{

struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY};

setrlimit(RLIMIT_STACK, &rlim);

struct Struct1 struct1 = {200.0, 200.0, 600.0, 600.0};

GtkApplication *app;

int status;

app = gtk_application_new (“roger.simplified”, G_APPLICATION_FLAGS_NONE);

g_signal_connect (app, “activate”, G_CALLBACK (activate), /NULL/ &struct1);

status = g_application_run (G_APPLICATION (app), argc, argv);

g_object_unref (app);

return status;

}/End of main()/

/End of simplified.c******************************************************/

/*Start of callback_drawing1.c ********************************************/

#include <stdio.h>

#include <math.h>

#include <errno.h>

#include <sys/time.h>

#include <sys/resource.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <gtk/gtk.h>

#include “globals.h”

/*gboolean callback_drawing1 (GtkWidget *widget, cairo_t cr, gpointer user_data)/

gboolean callback_drawing1 (GtkWidget *widget, cairo_t *cr, struct Struct1 *struct1)

{

int x_da;

int y_da;

GdkRGBA color;

GtkStyleContext *context;

int i;

context = gtk_widget_get_style_context (widget);

x_da = gtk_widget_get_allocated_width (widget);

y_da = gtk_widget_get_allocated_height (widget);

gtk_render_background (context, cr, 0, 0, x_da, y_da);

cairo_set_source_rgba(cr, 1, 1, 1, 0.5);

cairo_paint(cr);

cairo_set_source_rgba(cr, 0.6, 0, 0, 1.0);

cairo_set_line_width(cr, 5.0);

cairo_move_to(cr, (*struct1).x1_line, (*struct1).y1_line);

cairo_line_to(cr, (*struct1).x2_line, (*struct1).y2_line);

cairo_stroke(cr);

double line_slope[1001];

for (i=0; i<=1000; i++)

{

line_slope[i] = ((*struct1).y2_line-(*struct1).y1_line)/((*struct1).x2_line-(*struct1).x1_line);

}

double line_yintercept[1001];

for (i=0; i<=1000; i++)

{

line_yintercept[i] = (struct1).y2_line-line_slope[i](*struct1).x2_line;

}

double line[1001];

for (i=0; i<=1000; i++)

{

line[i] = (line_slope[i]*(double)i)+line_yintercept[i];

}

FILE* outfile_line = fopen(“file_line”, “w”);

for (i=0; i<=1000; i++)

{

fprintf(outfile_line,"%f\n", line[i]);

}

fclose(outfile_line);

cairo_set_source_rgba(cr, 0, 0, 0, 0.5);

cairo_set_line_width(cr, 1.0);

cairo_move_to(cr, 0, line[0]);

for (i=0; i<=1000; i++)

{

cairo_line_to(cr, i, line[i]);

}

cairo_stroke(cr);

return FALSE;

}

/*End of callback_drawing1.c ********************************************/

You are on the right track there. I haven’t used builder so I am no help with the builder questions. To app or not? Both ways are usefull. I tend to write small test programs so just using main works well for that sort of thing.

Since you are getting a segfault, compile your program with -g and give valgrind a try.

If you intend to use a struct to package what you need maybe the following will do a little better than the previous link I posted. It looks like you will need an array along with a few other variables to pass to the functions.

Eric


//gcc -Wall app_draw1.c -o app_draw1 `pkg-config --cflags --libs gtk+-3.0`

#include<gtk/gtk.h>

struct da_points{
  GtkWidget *da;
  //Current points in spinners.
  gdouble x1;
  gdouble y1;
  gdouble x2;
  gdouble y2;
  //Saved points.
  GArray *lines;
};

//A struct for the lines array.
struct points{
  gdouble x1;
  gdouble y1;
  gdouble x2;
  gdouble y2;
};
 
static void app_activate(GtkApplication *app, struct da_points *coords);
static void x1_spin_changed(GtkSpinButton *spin_button, struct da_points *coords);
static void y1_spin_changed(GtkSpinButton *spin_button, struct da_points *coords);
static void x2_spin_changed(GtkSpinButton *spin_button, struct da_points *coords);
static void y2_spin_changed(GtkSpinButton *spin_button, struct da_points *coords);
static void save_line(GtkWidget *button, struct da_points *coords);
static gboolean draw_main(GtkWidget *da, cairo_t *cr, struct da_points *coords);

int main(int argc, char **argv)
  {
    GtkApplication *app;
    int status;
    struct da_points coords={.da=NULL, .x1=50.0, .y1=200.0, .x2=300.0, .y2=200.0, .lines=NULL};
    app=gtk_application_new("app.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(app_activate), &coords);
    status=g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    if(coords.lines!=NULL) g_array_free(coords.lines, TRUE);
    return(status);
  }
static void app_activate(GtkApplication *app, struct da_points *coords)
  {
    GtkWidget *window=gtk_application_window_new(GTK_APPLICATION(app));
    gtk_window_set_title(GTK_WINDOW(window), "App Draw");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    GtkWidget *da=gtk_drawing_area_new();
    gtk_widget_set_hexpand(da, TRUE);
    gtk_widget_set_vexpand(da, TRUE);
    coords->da=da;
    coords->lines=g_array_new(FALSE, FALSE, sizeof(struct points));
    g_signal_connect(da, "draw", G_CALLBACK(draw_main), coords); 

    GtkAdjustment *x1_adj=gtk_adjustment_new(50.0, 0.0, 400.0, 10.0, 0.0, 0.0);
    GtkAdjustment *y1_adj=gtk_adjustment_new(200.0, 0.0, 400.0, 10.0, 0.0, 0.0);
    GtkAdjustment *x2_adj=gtk_adjustment_new(300.0, 0.0, 400.0, 10.0, 0.0, 0.0);    
    GtkAdjustment *y2_adj=gtk_adjustment_new(200.0, 0.0, 400.0, 10.0, 0.0, 0.0);

    GtkWidget *x1_label=gtk_label_new("x1");
    GtkWidget *x1_spin=gtk_spin_button_new(x1_adj, 10.0, 1);
    g_signal_connect(x1_spin, "value-changed", G_CALLBACK(x1_spin_changed), coords);

    GtkWidget *y1_label=gtk_label_new("y1");
    GtkWidget *y1_spin=gtk_spin_button_new(y1_adj, 10.0, 1);
    g_signal_connect(y1_spin, "value-changed", G_CALLBACK(y1_spin_changed), coords);

    GtkWidget *x2_label=gtk_label_new("x2");
    GtkWidget *x2_spin=gtk_spin_button_new(x2_adj, 10.0, 1);
    g_signal_connect(x2_spin, "value-changed", G_CALLBACK(x2_spin_changed), coords);

    GtkWidget *y2_label=gtk_label_new("y2");
    GtkWidget *y2_spin=gtk_spin_button_new(y2_adj, 10.0, 1);
    g_signal_connect(y2_spin, "value-changed", G_CALLBACK(y2_spin_changed), coords);

    GtkWidget *button=gtk_button_new_with_label("Save Line");
    g_signal_connect(button, "clicked", G_CALLBACK(save_line), coords);

    GtkWidget *grid1=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid1), da, 0, 0, 4, 4);
    gtk_grid_attach(GTK_GRID(grid1), x1_label, 0, 4, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), x1_spin, 1, 4, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), y1_label, 2, 4, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), y1_spin, 3, 4, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), x2_label, 0, 5, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), x2_spin, 1, 5, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), y2_label, 2, 5, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), y2_spin, 3, 5, 1, 1);
    gtk_grid_attach(GTK_GRID(grid1), button, 1, 6, 2, 1);
   
    gtk_container_add(GTK_CONTAINER(window), grid1);

    gtk_widget_show_all(window);
  }
static void x1_spin_changed(GtkSpinButton *spin_button, struct da_points *coords)
  {
    coords->x1=gtk_spin_button_get_value(spin_button);
    gtk_widget_queue_draw(coords->da);
  }
static void y1_spin_changed(GtkSpinButton *spin_button, struct da_points *coords)
  {
    coords->y1=gtk_spin_button_get_value(spin_button);
    gtk_widget_queue_draw(coords->da);
  }
static void x2_spin_changed(GtkSpinButton *spin_button, struct da_points *coords)
  {
    coords->x2=gtk_spin_button_get_value(spin_button);
    gtk_widget_queue_draw(coords->da);
  }
static void y2_spin_changed(GtkSpinButton *spin_button, struct da_points *coords)
  {
    coords->y2=gtk_spin_button_get_value(spin_button);
    gtk_widget_queue_draw(coords->da);
  }
static void save_line(GtkWidget *button, struct da_points *coords)
  {
    struct points p1;
    p1.x1=coords->x1;p1.y1=coords->y1;p1.x2=coords->x2;p1.y2=coords->y2;
    g_array_append_val(coords->lines, p1);
    gtk_widget_queue_draw(coords->da);
  }
static gboolean draw_main(GtkWidget *da, cairo_t *cr, struct da_points *coords)
  {
    gint i=0;

    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
    cairo_paint(cr);

    cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
    cairo_set_line_width(cr, 4.0);
    cairo_move_to(cr, coords->x1, coords->y1);
    cairo_line_to(cr, coords->x2, coords->y2);
    cairo_stroke(cr);

    cairo_set_source_rgba(cr, 1.0, 0.0, 1.0, 1.0);
    cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
    cairo_set_line_width(cr, 14.0);
    cairo_move_to(cr, coords->x1, coords->y1);
    cairo_line_to(cr, coords->x1, coords->y1);
    cairo_stroke(cr);

    cairo_move_to(cr, coords->x2, coords->y2);
    cairo_line_to(cr, coords->x2, coords->y2);
    cairo_stroke(cr);

    cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
    cairo_set_line_width(cr, 2.0);
    struct points *p1=NULL;
    for(i=0;i<coords->lines->len;i++)
      {
        p1=&g_array_index(coords->lines, struct points, i);
        cairo_move_to(cr, p1->x1, p1->y1);
        cairo_line_to(cr, p1->x2, p1->y2);
        cairo_stroke(cr);
      }

    return FALSE;
  }

Hi Eric,

        again a swift reply, thanks Eric, It will take me some time to digest all that, I'll get back to you on that,

Roger

Your program doesn’t need to call gtk_init(). The GtkApplication class does it automatically.

You gave the same name to three different things: the type of a structure, a variable of that type, and the “user_data” parameters of the call-back functions. That can cause confusion. In activate(), the call to gtk_builder_connect_signals() must be given the value in struct1, not its address:

gtk_builder_connect_signals(builder, struct1);

Hi Eric,

         That’s a neat solution to the problem. I notice that there isn’t any gtk_init() and gtk_main() anywhere (as has since been pointed out to me by Greg King). I have commenced re-building my app based on this and

have worked out how to pass “in-line” C arrays, which is how I wanted to pass the 500 points defining the line in my example. The save_line button works great using g_array, but I am having some difficulty in trying to make it so that the user can delete only
the last line saved. I have made a button callback:

static void take_line_da1(GtkWidget *button, struct main_struct *coords)

{

int i;

for(i=coords->lines->len-1;i<coords->lines->len;i++)

  {

    g_array_unref(coords->lines);

  }

gtk_widget_queue_draw(coords->da1);

}

that deletes all the saved lines, and which causes it to crash upon the next save_line button-press, with error message:
realloc(): invalid old size Aborted (core dumped).

I’m assuming here that g_array_unref() has removed the first address of the array along with all it’s elements, even though the documentation states that it “Atomically decrements the reference count of
array by
one. If the reference count drops to 0, all memory allocated by the array is released.”

If I start the loop at 0 then a segfault occurs on pressing save_line.

I have also attempted various incantations such as:

    /*g_array_remove_range(coords->lines, 0, 1);*/

    /*g_array_remove_range(coords->lines, i, 1);*/

struct points p1t;

p1t.x1=coords->x1;p1t.y1=coords->y1;p1t.x2=coords->x2;p1t.y2=coords->y2;

for(i=0;i<coords->lines->len;i++)

  {

  g_array_index(coords->lines, struct points, i);

  g_array_remove_index(p1t.x1, i);

  }

struct points *p1t =NULL;

for(i=0;i<coords->lines->len;i++)

  {

    /*p1t=&g_array_index(coords->lines, struct points, i);*/

    /*g_array_remove_range(coords->lines, 0, 1);*/

    /*g_array_remove_range(coords->lines, i, 1);*/

  }

all to no avail. I don’t have anything in draw_main() that matches

cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);

cairo_set_line_width(cr, 1.0);

struct points *p1=NULL;

for(i=0;i<coords->lines->len;i++)

  {

    p1=&g_array_index(coords->lines, struct points, i);

    cairo_move_to(cr, (p1->x1, p1->y1);

    cairo_line_to(cr, p1->x2, p1->y2);

    cairo_stroke(cr);

  }

to remove lines. What do I need to do to step-back through deleting lines?

Thanks,

Roger.


Virus-free.
www.avg.com

The GArray starts with a reference count of one so if you unref it the count goes to 0 and the array is freed. No need to free the array. It is freed when the program exits.

In the take_line_da1() callback you can remove a line at the end of the array. Give this a try and see if it works.

Eric

gint end=coords->lines->len-1;
g_print("lines %i\n", coords->lines->len);
if(end>-1) g_array_remove_index_fast(coords->lines, end);
else g_print("No lines to remove\n");
g_print(" lines %i\n", coords->lines->len);
gtk_widget_queue_draw(coords->da);

Hi Eric,

        that is just the trick, I had read, but forgotten, that GArrays start at 1 instead of 0, as in C arrays.

I’m anticipating more problems soon to do with menubars and toolbars, I have created a menubar with submenus for file edit copy paste etc., and now have to work on populating these, I have Andrew Krause’s book but have had problems with deprecated things
previously when attempting to do this, can you point me in the direction of some, more recent, example code for this?

Thanks Heaps,

Roger.

P.S. I intend to make a donation sometime soon.


Virus-free.
www.avg.com

You can find a simple example of the modern approach with GMenu and GAction in bloatpad, an example application that ships with gtk.

Hi Eric and Chris,

                       I have started rebuilding my app in two versions:
  1. Based on the app_draw1.c that Eric Cashon sent to me, and

  2. Based on bloatpad.c that Chris Williams sent to me.

1)Concerning version 1 (Eric’s) I have it working nicely except for a functional menubar and toolbar. I have changed from using Garrays for
*lines and

struct points{gdouble x1;gdouble y1;gdouble x2;gdouble y2;};, and now use C arrays combined with buttons for ‘save_line’ and ‘take_line’ (as previously), as well as another spinbutton for selecting the line_number in the (fixed-size) array of saved lines. This
doesn’t have the problem that occurred when using the Garrays whereby if three or more lines have already been saved then when “taking” lines the run-time message would show on the terminal:

GLib-CRITICAL **: 19:46:43.557: g_array_remove_index: assertion ‘index_ < array->len’ failed

Even with this run-time error message the program would still run and show the lines being saved and deleted. However, using the C arrays, buttons and spinbutton this doesn’t occurr (something about g_print()……?) and I can now change the colour of, and selectively
delete lines.

I have a menubar constructed thus:

GtkWidget *box1 = gtk_box_new(TRUE, 5);

GtkAccelGroup *group = gtk_accel_group_new();

GtkWidget *menubar = gtk_menu_bar_new();

GtkWidget *file = gtk_menu_item_new_with_label("file");

GtkWidget *edit = gtk_menu_item_new_with_label("edit");

GtkWidget *help = gtk_menu_item_new_with_label("help");

GtkWidget *filemenu = gtk_menu_new();

GtkWidget *editmenu = gtk_menu_new();

GtkWidget *helpmenu = gtk_menu_new();

gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);

gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit), editmenu);

gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), helpmenu);

gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);

gtk_menu_shell_append(GTK_MENU_SHELL(menubar), edit);

gtk_menu_shell_append(GTK_MENU_SHELL(menubar), help);

GtkWidget *new = gtk_menu_item_new_with_label("new");

GtkWidget *open = gtk_menu_item_new_with_label("open");

gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new);

gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open);

GtkWidget *cut = gtk_menu_item_new_with_label("cut");

GtkWidget *copy = gtk_menu_item_new_with_label("copy");

GtkWidget *paste = gtk_menu_item_new_with_label("paste");

gtk_menu_shell_append(GTK_MENU_SHELL(editmenu), cut);

gtk_menu_shell_append(GTK_MENU_SHELL(editmenu), copy);

gtk_menu_shell_append(GTK_MENU_SHELL(editmenu), paste);

GtkWidget *contents = gtk_menu_item_new_with_label("contents");

GtkWidget *about = gtk_menu_item_new_with_label("about");

gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu), contents);

gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu), about);

and would like to make this functional if possible.

  1. Concerning the bloatpad.c app of Chris Williams I have managed to get it working (barely). At first it would compile with Makefile:

CC
= gcc

CFLAGS
= pkg-config --cflags gtk+-3.0

CPPFLAGS = -mcmodel=large -rdynamic -Wall

LIBS
= pkg-config --libs gtk+-3.0 -lm

all: bloatpad2

bloatpad2: bloatpad2.o

$(CC) $(CPPFLAGS) $(CFLAGS) -o bloatpad2 bloatpad2.o $(LIBS)

clean:

rm -f bloatpad2

rm -f *.o

.PHONY: all clean

but would segfault until I commented out:

/g_object_unref (item);/

/g_object_unref (icon);/

/*const gchar new_accels[] = { “n”, “t”, NULL };/ /Re-definition error/

in

static void bloat_pad_startup (GApplication *application) { },

and therefore must use ^c to interupt the process after closing the app.

When compiling I get these warnings:

bloatpad2.c: In function ‘bloat_pad_startup’:

bloatpad2.c:652:5: warning: unused variable ‘accels’ [-Wunused-variable]

} accels[] = {

bloatpad2.c:626:8: warning: unused variable ‘i’ [-Wunused-variable]

gint i;

bloatpad2.c:625:10: warning: unused variable ‘file’ [-Wunused-variable]

GFile *file;

bloatpad2.c:624:12: warning: unused variable ‘emblem’ [-Wunused-variable]

GEmblem *emblem;

bloatpad2.c:623:10: warning: unused variable ‘icon2’ [-Wunused-variable]

GIcon *icon2;

bloatpad2.c:622:10: warning: unused variable ‘icon’ [-Wunused-variable]

GIcon *icon;

bloatpad2.c:621:11: warning: unused variable ‘bytes’ [-Wunused-variable]

GBytes *bytes;

bloatpad2.c:620:14: warning: unused variable ‘item’ [-Wunused-variable]

GMenuItem *item;

bloatpad2.c:619:10: warning: unused variable ‘menu’ [-Wunused-variable]

GMenu *menu;

bloatpad2.c:618:19: warning: unused variable ‘app’ [-Wunused-variable]

GtkApplication *app = GTK_APPLICATION (application);

At top level:

bloatpad2.c:581:21: warning: ‘app_entries’ defined but not used [-Wunused-variable]

static GActionEntry app_entries[] = {

Then when I run the app the window appears, with a toolbar (or menubar?), containing three icons for left, centre and right justification, and a toggle for expanding the screen to full screen size, as well as the ‘view’ in a scrolled window in which I can type,
cut, copy, paste, delete, select all and insert Emoji. I also have functionality: win.fullscreen -> F11.

I can also build (but prefer not to use builder now):

GtkBuilder *builder;

builder = gtk_builder_new_from_file (“app-menu.ui”);

gtk_application_set_menubar (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, “app-menu”)));

a the builder.ui file supplied in the stuff about overlaying the Help menu (does that stuff go into a Makefile, if so could you show the complete Makefile), but only if I comment-out:

<file preprocess="xml-stripblanks">gtk/menus.ui</file>

<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>

which I don’t understand (and anyway I don’t want to use builder to build the gui).

I have added a notebook to the grid and attempted to add more accelerators:

struct {

const gchar *action_and_target;

/*const gchar *accelerators[2];*/

const gchar *accelerators[12];

} accels[] = {

{ "app.new", { "<Primary>n", NULL } },

{ "app.about", { "<Primary>a", NULL } },

{ "app.quit", { "<Primary>q", NULL } },

{ "app.edit-accels", { "<Primary>e", NULL } },

{ "app.time-active", { "<Primary>t", NULL } },

/*{ "app.clear-all", { "<Primary>t", NULL } },*/

{ "win.copy", { "<Primary>c", NULL } },

{ "win.paste", { "<Primary>p", NULL } },

{ "win.fullscreen", { "<Primary>f", NULL } },

{ "win.busy", { "<Primary>b", NULL } },

{ "win.justify::left", { "<Primary>l", NULL } },

{ "win.justify::center", { "<Primary>m", NULL } },

{ "win.justify::right", { "<Primary>r", NULL } }

};

const gchar *new_accels[] = { “n”, “a”, “q”, “e”, “t”, “c”, “p”, “f”, “b”, “l”, “m”, “r”, NULL };

with no apparent change in behaviour, and still with the run-time errors above, particularly that I have all those unused things.

How do I use them, and how do I get file save, re-naming etc., and directory searching menus happening?

Can the typed contents of the view be saved to file? If so how? This will be nice if I can get it working more fully.

Thanks,

Roger.


Virus-free.
www.avg.com

Hi Eric,

just a note to say that I’ve put some more questions re: Passing values from spinbuttons…… onto discourse,

Thanks,

Roger.


Virus-free.
www.avg.com

Hi Roger,

The “g_array_remove_index: assertion ‘index_ < array->len’ failed” error tells you that the index value that you passed to g_array_remove_index isn’t valid. Check your array->len value to make sure your index value is valid before trying to remove an item in the array. If it isn’t valid then you can handle the error without having glib warn you about it.

Having the array length in a GArray can be very usefull. If you are adding and subtracting items from an array a dynamic GArray is a good choice. If you are drawing everything in the array a sequential GArray makes a lot of sense. If you want to add a color value for each line you could even add the color values to the array. Then they are easily available for when you draw the lines. Just an idea that might be worth trying out.

struct points{
gdouble x1;
gdouble y1;
gdouble x2;
gdouble y2;
gdouble r;
gdouble g;
gdouble b;
gdouble a;
};

With a GtkApplication you can use a GMenu instead of a GtkMenu. Look in “Windows system menu doesn’t work” discussion from June 22. There is a short program in there for setting up a GMenu with a GtkApplication. Bloatpad uses a GtkApplication so maybe looking at the two programs together will help to get menus figured out.

Eric

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.