title: Change image in GTK window on function call
body: <p>I am writing a C program to display raw images using GTK. Now that I can display an image, I'd like to increase the functionality to display multiple images back-to-back in the same window (like a media player). This program is to be used in conjunction with an image decoder that updates the image buffers as more images are decoded, and GTK will follow update the window to let us know we have decoded the images correctly.</p>
  <p>Since gtk_main() is the last function to be called, I have opened a separate thread to setup the window and keep it running. The next step is to run a function that loads the images and changes them in the GTK window, but I am having trouble getting this to work. Here is my code to setup the window:</p>
  <pre><code>    gtk_init(NULL, NULL);
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  
      gtk_window_set_title(GTK_WINDOW (window), &quot;Image Player&quot;);
      g_signal_connect(window, &quot;destroy&quot;, G_CALLBACK (gtk_main_quit), NULL);
      
      gtk_widget_show_all(window);
      gtk_main();
  
  </code></pre>
  <p>This will run in it's own thread. Now, I want to run this block of code to change and display the image, which is working for a single image when I run them together in one function, but I'd like to simply call a function called changeImage() which reassigns the <em>image</em> variable through the updated pixbuf and automatically updates it in the window.</p>
  <pre><code>GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ((guchar*)buf_rgb, GDK_COLORSPACE_RGB,
          FALSE, 8, width, height, stride_rgb*3, NULL, NULL);
  image = gtk_image_new_from_pixbuf (pixbuf);
  gtk_container_add(GTK_CONTAINER (window), image);
  gtk_widget_show_all(window);
  </code></pre>
  <p>How would I achieve this in GTK? I have just started learning how to use this tool last week, I believe I'm supposed to create an event using g_signal_connect, but I'm not sure how to tie it to a function call like changeImage() where I can simply update the image or call the function and the image in the display window will change.</p>
  <p>EDIT: Test script included below:</p>
  <pre><code>#include &lt;gtk/gtk.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;pthread.h&gt;
  
  FILE *x1, *y_1, *z1;
  FILE *x2, *y2, *z2;
  
  // image needs to be converted from greyscale to RGB
  // using this structure works with GTK
  typedef struct{
      uint8_t r;
      uint8_t g;
      uint8_t b;
  }rgb;
  
  GtkWidget *window;
  GtkWidget *image;
  GdkPixbuf *pixbuf;
  GtkWidget *button;
  GtkWidget *hbox;
  
  // Function to display image 8-bits
  // This is the function I was using to display 1 image per window
  void displayImage8_RGB(uint8_t *x, uint8_t *y, uint8_t *z, const int width, const int height){
      size_t size = width * height;
      size_t stride_16 = width;
      size_t stride_rgb = width;
  
  
      rgb *buf_rgb = (rgb*)malloc(stride_rgb*height*sizeof(rgb));
  
      for(size_t i = 0; i &lt; width; i++){
          for(size_t j = 0; j &lt; height; j++){
              //printf(&quot;%d\t%d\n&quot;, x, y);
              float y_ = x[stride_16*j+i];
              float cb = y[stride_16*j+i];
              float cr = z[stride_16*j+i];
              cr = cr - 128;
              cb = cb - 128;
              y_ = (y_ * 219) + 16;
              cb = (cb * 244) + 128;
              cr = (cr * 224) + 128;
              
              uint16_t r_ = (y_ + 1.402 * cr) / 255;
              uint16_t g_ = (y_ - 0.344136*cb - 0.714136*cr) / 255;
              uint16_t b_ = (y_ + 1.772*cb) / 255;
  
              if (r_ &gt; 255){
                  r_ = (uint8_t) 0;
              }
              if (g_ &gt; 255){
                  g_ = (uint8_t) 0; 
              }
              if (b_ &gt; 255){
                  b_ = (uint8_t) 0;
              }
  
              buf_rgb[stride_rgb*j+i].r = r_;
              buf_rgb[stride_rgb*j+i].g = g_;
              buf_rgb[stride_rgb*j+i].b = b_;
              //printf(&quot;x: %d\ty: %d\tz: %d\nr: %d\tg: %d\tb: %d\n&quot;, x_c, y_c, z_c, buf_rgb[stride_rgb*j+i].r, buf_rgb[stride_rgb*j+i].g, buf_rgb[stride_rgb*j+i].b);
          }
      }
  
      GtkWidget* image;
  
      gtk_init (NULL, NULL);
  
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ((guchar*)buf_rgb, GDK_COLORSPACE_RGB,
          FALSE, 8, width, height, stride_rgb*3, NULL, NULL);
  
      gtk_window_set_title (GTK_WINDOW (window), &quot;Image Viewer&quot;);
      g_signal_connect (window, &quot;destroy&quot;, G_CALLBACK (gtk_main_quit), NULL);
  
      image = gtk_image_new_from_pixbuf (pixbuf);
      gtk_container_add(GTK_CONTAINER (window), image);
  
      
  
      gtk_widget_show_all (window);
  
      gtk_main ();
  
  
      free(buf_rgb);
      return;
  }
  
  void changeImage(uint8_t *x, uint8_t *y, uint8_t *z, const int width, const int height){
      printf(&quot;displaying image\n&quot;);
      size_t size = width * height;
      size_t stride_16 = width;
      size_t stride_rgb = width;
  
      rgb *buf_rgb = (rgb*)malloc(stride_rgb*height*sizeof(rgb));
  
      for(size_t i = 0; i &lt; width; i++){
          for(size_t j = 0; j &lt; height; j++){
              //printf(&quot;%d\t%d\n&quot;, x, y);
              float y_ = x[stride_16*j+i];
              float cb = y[stride_16*j+i];
              float cr = z[stride_16*j+i];
              cr = cr - 128;
              cb = cb - 128;
              y_ = (y_ * 219) + 16;
              cb = (cb * 244) + 128;
              cr = (cr * 224) + 128;
              
              uint16_t r_ = (y_ + 1.402 * cr) / 255;
              uint16_t g_ = (y_ - 0.344136*cb - 0.714136*cr) / 255;
              uint16_t b_ = (y_ + 1.772*cb) / 255;
  
              if (r_ &gt; 255){
                  r_ = (uint8_t) 0;
              }
              if (g_ &gt; 255){
                  g_ = (uint8_t) 0; 
              }
              if (b_ &gt; 255){
                  b_ = (uint8_t) 0;
              }
  
              buf_rgb[stride_rgb*j+i].r = r_;
              buf_rgb[stride_rgb*j+i].g = g_;
              buf_rgb[stride_rgb*j+i].b = b_;
              //printf(&quot;x: %d\ty: %d\tz: %d\nr: %d\tg: %d\tb: %d\n&quot;, x_c, y_c, z_c, buf_rgb[stride_rgb*j+i].r, buf_rgb[stride_rgb*j+i].g, buf_rgb[stride_rgb*j+i].b);
          }
      }
  
      GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ((guchar*)buf_rgb, GDK_COLORSPACE_RGB,
          FALSE, 8, width, height, stride_rgb*3, NULL, NULL);
  
  
      gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
  
      //gtk_container_add(GTK_CONTAINER (window), image);
  
      //gtk_widget_show_all(window);
  
      g_object_unref(pixbuf);
      free(buf_rgb);
      return;
  }
  
  void* setupWindow(){
      gtk_init(NULL, NULL);
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  
      gtk_window_set_title(GTK_WINDOW (window), &quot;Image Player&quot;);
      g_signal_connect(window, &quot;destroy&quot;, G_CALLBACK (gtk_main_quit), NULL);
      
      rgb *buf_rgb = (rgb*)malloc(1998*1080*sizeof(rgb));
  
      memset(buf_rgb, 255, (1998*1080*3));
  
      GdkPixbuf *s_pixbuf = gdk_pixbuf_new_from_data((guchar*)buf_rgb, GDK_COLORSPACE_RGB,
      FALSE, 8, 1998, 1080, 1998*3, NULL, NULL);
  
      image = gtk_image_new_from_pixbuf(s_pixbuf);
  
  
      gtk_container_add(GTK_CONTAINER (window), image);
  
      gtk_widget_show_all(window);
  
      gtk_main();
  }
  
  int main(int argc, char *argv[]){
      // for demo, pass files in this order:
      // idwt_bin0_test1.raw idwt_bin1_test1.raw idwt_bin2_test1.raw idwt_bin0_test2.raw idwt_bin1_test2.raw idwt_bin2_test2.raw
  
      // files passed to function are 3 components (.raw) for 2 uncompressed images
  
      pthread_t win, changer;
  
      x1 = fopen(&quot;mtest/idwt_bin0_test1.raw&quot;, &quot;rb&quot;);
      y_1 = fopen(&quot;mtest/idwt_bin1_test1.raw&quot;, &quot;rb&quot;);
      z1 = fopen(&quot;mtest/idwt_bin2_test1.raw&quot;, &quot;rb&quot;);
  
      x2 = fopen(&quot;mtest/idwt_bin0_test2.raw&quot;, &quot;rb&quot;);
      y2 = fopen(&quot;mtest/idwt_bin1_test2.raw&quot;, &quot;rb&quot;);
      z2 = fopen(&quot;mtest/idwt_bin2_test2.raw&quot;, &quot;rb&quot;);
      // test1 1998x1080
      // busy4k 4096x2160
      const int w = 1998, h = 1080;
      int size = w * h; // multiply by 2 for 16-bit
  
      uint8_t *xbuf1 = (uint8_t*)malloc(sizeof(uint8_t)*size);
      uint8_t *ybuf1 = (uint8_t*)malloc(sizeof(uint8_t)*size);
      uint8_t *zbuf1 = (uint8_t*)malloc(sizeof(uint8_t)*size);
  
      uint8_t *xbuf2 = (uint8_t*)malloc(sizeof(uint8_t)*size);
      uint8_t *ybuf2 = (uint8_t*)malloc(sizeof(uint8_t)*size);
      uint8_t *zbuf2 = (uint8_t*)malloc(sizeof(uint8_t)*size);
  
      // comp0 comp2 comp1
  
      fread(xbuf1, 1, size, x1);
      fread(ybuf1, 1, size, y_1);
      fread(zbuf1, 1, size, z1);
  
      fread(xbuf2, 1, size, x2);
      fread(ybuf2, 1, size, y2);
      fread(zbuf2, 1, size, z2);
  
  
      // thread to setup main gtk window
      pthread_create(&amp;win, NULL, setupWindow, NULL);
  
      changeImage(xbuf1, ybuf1, zbuf1, w, h); // change to image 1
      sleep(3); // gtk's timer could be used instead
      changeImage(xbuf2, ybuf2, zbuf2, w, h); // change to image 2
      sleep(3);
  
      fclose(x1);
      fclose(x2);
      fclose(y_1);
      fclose(y2);
      fclose(z1);
      fclose(z2);
      return 0;
  }```
  </code></pre>