-1

I'm having a few issues, that I have no idea how to solve with GTK+ 2.

  1. I made a function, supposed to be a callback when I click on the "Manual" item on the "Ajuda" (help) menu. However, when I compile and click there, the program closes, and I have no idea why.

  2. Cairo is not drawing on one of the boxes, as supposed, in fact, it is not drawing anywhere.

  3. I tried to make an horizontal separator between the menu and the toolbar,which seems not to be visible.

Sorry for the code semi-in-portuguese, I hope it won't make a difference...

   #include <gtk/gtk.h>
    #include <stdlib.h>
    #include <math.h>
    #include <cairo.h>

        /*FALTA:
          - Abrir o manual (dar mensagem de erro em caso de falha E compatibilidade com Windows/Mac)

        */            

        gboolean
        help_manual(void)
        {
          short int x;
          //x = system("xdg-open GCDmanual.pdf");
          /*if (x==-1)
            {
          */
          return TRUE;
        }

        gboolean
        on_expose_event (GtkWidget       *widget ,
                         GdkEventExpose  *event  ,
                         gpointer         data   )
        {
          cairo_t        *cr ;
          gchar           texto[128] ;
          gint            width, height;

          static double   pos1x = 100., pos1y = 80., pos2x = 600., pos2y = 100.;
          static double   s1x = 1., s1y = 0., s2x = 0., s2y = 0.; 
          static double   velscale1=4, velscale2=0;
          double r1=30, r2=50;

          gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
          cr = gdk_cairo_create(widget->window);

          cairo_move_to (cr, 20, 20);
          cairo_select_font_face(cr, "Courier", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
          cairo_set_font_size (cr, 18);
          sprintf (texto, "Exemplo de funcionamento de GTK+ Cairo                 Velocidade: %d\n",
                   (gint) velscale1);
          cairo_show_text (cr, texto);

          /* Circulo1 */

          cairo_set_source_rgb (cr, 0., 0., 0.);
          cairo_set_line_width (cr, 4.0);
          cairo_arc (cr, pos1x, pos1y, r1, 0., 2. * M_PI);
          cairo_stroke_preserve (cr);
          cairo_set_source_rgb (cr, 1, 1, 1);
          cairo_fill (cr);

          if ((pos1x < 30.) || ((pos1x + 30.) > width))
            s1x = - s1x;


          if ((pos1y < 30.) || ((pos1y + 30.) > height))
            s1y = - s1y;
          /* Circulo2 */

          cairo_set_source_rgb (cr, 0., 0., 0.);
          cairo_set_line_width (cr, 4.0);
          cairo_arc (cr, pos2x, pos2y, r2, 0., 2. * M_PI);
          cairo_stroke_preserve (cr);
          cairo_set_source_rgb (cr, 0, 1, 0);
          cairo_fill (cr);

          if ((pos2x < r2) || ((pos2x + r2) > width))
            s2x = - s2x;


          if ((pos2y < r2) || ((pos2y + r2) > height))
            s2y = - s2y;

          if ((pos1y-pos2y)*(pos1y-pos2y)+(pos1x-pos2x)*(pos1x-pos2x) <= (r1+r2)*(r1+r2))
            {
              printf("COLISAO");
              //angulovelrel
              printf("%lf", atan2((s2y*velscale2-s1y*velscale1),(s2x*velscale2-s1x*velscale1)));
              printf("%lf", atan2((pos2y-pos1y),(pos2x-pos1x)));
            }
          else
            {   
              pos1x = pos1x + s1x * velscale1;
              pos1y = pos1y + s1y * velscale1;



              pos2x = pos2x + s2x * velscale2;
              pos2y = pos2y + s2y * velscale2;
            }


          cairo_stroke(cr);
          cairo_destroy(cr);

          return FALSE;
        }

        static gboolean
        time_handler (GtkWidget *widget)
        {
          if (widget->window == NULL) 
            return FALSE;

          gtk_widget_queue_draw(widget);

          return TRUE;
        }

        int
        main(int argc, char **argv)
        {

          GtkWidget *janela;
          GtkWidget *vbox1, *hbox2, *vbox3_sett, *vbox3_field;
          GtkWidget *vboxseparator1;
          GtkWidget *menubar, *lvl1file, *lvl2file, *lvl1help, *lvl2help;
          GtkWidget *file_new, * file_open, *file_sep1, *file_quit;
          GtkWidget *help_manual, *help_about;
          GtkWidget *toolbar;
          GtkToolItem *tb_restart, *tb_pause, *tb_undo, *tb_redo, *tb_sep1;
          GtkWidget *statusbar;



          gtk_init(&argc, &argv);

          janela=gtk_window_new(GTK_WINDOW_TOPLEVEL);
          gtk_window_set_title(GTK_WINDOW(janela), "Grande Colisor de Discos");
          gtk_window_set_position (GTK_WINDOW (janela), GTK_WIN_POS_CENTER);
          gtk_window_set_default_size (GTK_WINDOW(janela), 800, 600); 

          g_signal_connect_swapped (G_OBJECT(janela), "destroy",
                                    G_CALLBACK(gtk_main_quit), NULL);
          g_signal_connect (janela, "expose-event", G_CALLBACK(on_expose_event), NULL);


          vbox1 = gtk_vbox_new (FALSE, 0);
          gtk_box_set_homogeneous (GTK_BOX (vbox1), FALSE);
          gtk_container_add (GTK_CONTAINER(janela), vbox1);


          /* MENU */

          menubar = gtk_menu_bar_new ();
          gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, TRUE, 0);

          lvl1file= gtk_menu_item_new_with_mnemonic ("_Ficheiro"); 
          gtk_menu_shell_append (GTK_MENU_SHELL(menubar), lvl1file); 
          lvl2file = gtk_menu_new ();
          gtk_menu_item_set_submenu (GTK_MENU_ITEM (lvl1file), lvl2file);

          file_new = gtk_image_menu_item_new_from_stock (GTK_STOCK_NEW, NULL);
        #if GTK_CHECK_VERSION(2,18,0)
          gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (file_new), TRUE);
        #endif

          file_open = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN, NULL);
        #if GTK_CHECK_VERSION(2,18,0)
          gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (file_open), TRUE);
        #endif

          file_sep1= gtk_separator_menu_item_new();
          file_quit= gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
        #if GTK_CHECK_VERSION(2,18,0)
          gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (file_quit), TRUE);
        #endif

          gtk_menu_shell_append (GTK_MENU_SHELL (lvl2file), file_new);
          gtk_menu_shell_append (GTK_MENU_SHELL (lvl2file), file_open);
          gtk_menu_shell_append (GTK_MENU_SHELL (lvl2file), file_sep1);
          gtk_menu_shell_append (GTK_MENU_SHELL (lvl2file), file_quit);



          //Ajuda

          lvl1help = gtk_menu_item_new_with_mnemonic ("_Ajuda");
          gtk_menu_shell_append (GTK_MENU_SHELL (menubar), lvl1help);
          lvl2help = gtk_menu_new();
          gtk_menu_item_set_submenu (GTK_MENU_ITEM (lvl1help), lvl2help);
          help_manual=gtk_menu_item_new_with_label("Manual de ajuda");
          help_about= gtk_menu_item_new_with_label("Sobre...");

          gtk_menu_shell_append(GTK_MENU_SHELL(lvl2help), help_manual);
          gtk_menu_shell_append(GTK_MENU_SHELL(lvl2help), help_about);



          //Menu Callbacks

          g_signal_connect(G_OBJECT(file_quit), "activate", G_CALLBACK(gtk_main_quit), NULL);
          g_signal_connect(G_OBJECT(help_manual), "activate", G_CALLBACK(help_manual), NULL);



          /* TOOLBAR */

          toolbar = gtk_toolbar_new();
          gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
          gtk_container_set_border_width (GTK_CONTAINER (toolbar), 0);

          tb_undo = gtk_tool_button_new_from_stock (GTK_STOCK_UNDO);
          gtk_widget_set_name (GTK_WIDGET (tb_undo), "undo");
          gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_undo, -1);

          tb_redo = gtk_tool_button_new_from_stock (GTK_STOCK_REDO);
          gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_redo, -1);

          tb_sep1 = gtk_separator_tool_item_new ();
          gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_sep1, -1);

          tb_pause = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_PAUSE);
          gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_pause, -1);

          tb_restart = gtk_tool_button_new_from_stock (GTK_STOCK_REFRESH);
          gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_restart, -1);

          /*tb_sep = gtk_separator_tool_item_new ();
            gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb_sep, -1);*/

          gtk_box_pack_start (GTK_BOX(vbox1), toolbar, FALSE, FALSE, 0); 

          /* HBOX2 */

          vboxseparator1 = gtk_hseparator_new ();
          gtk_box_pack_start (GTK_BOX (vbox1), vboxseparator1, FALSE, TRUE, 0);
          gtk_widget_show (vboxseparator1);

          hbox2= gtk_hbox_new (FALSE, 0);
          gtk_container_add (GTK_CONTAINER(vbox1), hbox2); 

          /* STATUSBAR */

          statusbar = gtk_statusbar_new();
          gtk_box_pack_end (GTK_BOX (vbox1), statusbar, FALSE, TRUE, 0);
          gtk_statusbar_push  (GTK_STATUSBAR (statusbar), 1, "  Isto e' uma     statusbar.");

          gtk_widget_show_all (janela);
          gtk_main();


          /* ÁREA DE TRABALHO */

          vbox3_field = gtk_vbox_new (FALSE, 0);
          gtk_container_add (GTK_CONTAINER (hbox2), vbox3_field);

          vbox3_sett = gtk_vbox_new (FALSE, 0);
          gtk_container_add (GTK_CONTAINER (hbox2), vbox3_sett);

          gtk_widget_set_app_paintable (vbox3_field, TRUE);
}
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
Kelthar
  • 124
  • 9
  • 1
    You should not use `system` that way try `if (fork() == 0) system("xdg-open GDCmanual.pdf");` otherwise it will block your application. – Iharob Al Asimi Jan 02 '15 at 19:57
  • 1
    Welcome to StackOverflow! Please read http://stackoverflow.com/help/behavior , especially the part about greetings. – Pascal Cuoq Jan 02 '15 at 22:01
  • A few corrections to the code: -I used gtk_main too early. Put now on the end. -I was lacking a line which called the function time_handler. However, it is still not drawing. (It was supposed to draw in vbox3_field) though I know the calculations are being made (they are printed to the terminal). Also: the problem is not on the on_expose_event or time_handler functions, because I tested them somewhere else(though drawing directly on the window) and it worked. the issue is in "main()", I believe. – Kelthar Jan 03 '15 at 00:04

1 Answers1

0

The GtkMenuItem * witdget's name is help_manual it conflicts with the function name, and in the scope of the main() function you are passing a pointer to GtkMenuItem instead of a callback since there your help_manual is a pointer of type GtkMenuItem and not a function, the fix is to rename the callback

static void
help_manual_callback(GtkMenuItem *item, gpointer data)
{
  fprintf(stderr, "ajuda!\n");

  if (fork() == 0)
  {
    system("xdg-open GCDmanual.pdf");
    _exit(0);
  }
}

and to connect

  g_signal_connect(G_OBJECT(help_manual), "activate", 
                       G_CALLBACK(help_manual_callback), NULL);

and always do that, add a suffix or prefix to identify the variable type, it makes it easier to keep track of types.

This will fix the crash, the drawing issue is something that depends on geometry and other stuff so you should check it to see if it's drawing to the right place.

The visibility of the separator could be a theme issue, may be those aren't visible with your current theme.

Also, you should fork() to show the manual in a new process and keep your process running, you could use threads but I don't think they are useful in this simple situation. fork() + system() is ok here. Although you might want to make it more robust by specifiying the full path to the help pdf file.

Extra: you must make your code follow it's own logic, I would create functions for each GUI part, for instance createToolbar() and createMenu() and such. It makes it easier to read.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • 1
    It does not make much sense to downvoate the **accepted** answer without commenting, since that may confuse the OP. – Iharob Al Asimi Jan 02 '15 at 23:50
  • They worked, the only issue now is the drawing, which was supposed to be in vbox3_field – Kelthar Jan 03 '15 at 00:07
  • @allg18 try to check your code, and if you find any thing you don't understand ask another question, this question as is looks to me like `too broad` so you should be **specific**, I can try to help you I have some `cairo` drawing knowledge, ask another question and I can see. – Iharob Al Asimi Jan 03 '15 at 00:13
  • Just another question, about your last sugestion: Having functions to create each GUI element: Do I simply make they take no argument, so like: void createToolbar(void)? {gtk_menu_bar_new... etc... return;} Will that work and gtk will remember those GUI elements? Because usually when a function ends, the variables are deleted from memory. So does GTK itself store the elements itself somewhere else? – Kelthar Jan 07 '15 at 18:44
  • 1
    @allg18 make them return the widget that contains all the subwidgets and add the returned widget to the appropriate container. – Iharob Al Asimi Jan 07 '15 at 18:51
  • Is there a fork equivalent in Windows? It gives me errors when trying to compile there. What would the windows version of the code translate to? – Kelthar Jan 15 '15 at 14:48
  • 1
    @allg18 I am not a windows fan, but [this](http://msdn.microsoft.com/en-us/library/ms682425.aspx) is what SO recommends, it's conceptually different, but presumably will help you achieve the same. – Iharob Al Asimi Jan 15 '15 at 14:54