My problem is: I have a picture in my buffer buffer = (unsigned short *) malloc(imageSize*2);
This picture is 8 bit per pixel and 1 byte per pixel, so it is a Grayscale picture.
But to display it I need an RGB picture. Because only an RGB picture is supported.
So I need to change the picture from:
index | 1 | 2 |...
grayvalue | 128 | 135 |...
to
index | 1 | 2 |...
grayvalue | 128,128,128 | 135,135,135 |...
for | r,g,b |.
My idea is to make an array from the buffer array[grayvalue] = buffer[count], somehow add 2 grayvalues to the same pixel and change the array back into a buffer. But I can´t find how to get an array from a buffer and how to add the grayvalues to 1 pixel. I hope someone has an idea what I mean and can link me to information that I overlooked.
Edit:
#include <stdlib.h>
#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
long int imageSize = 0;
unsigned short *buffer = NULL;
const int Width = 1936, Height = 1460;
/*code to take raw image data from camera*/
// Put raw image data from the camera in the buffer.
buffer = (unsigned short *) malloc(imageSize*2);
// GTK
GtkWidget *window;
GtkWidget* image;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ((unsigned short *) buffer, GDK_COLORSPACE_RGB,FALSE, 8,
Width, Height, Width*1, NULL, NULL);
gtk_window_set_title (GTK_WINDOW (window), "Image Viewer");
g_signal_connect (window, "destroy", 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 (buffer);
return 0;
}
This is the program I use to Display my Image. The Code that I use to take a picture with the camera can´t be shared.
Your code hase 1 main problem:
You create the pixbuf with wrong rowstride value. It is in bytes, not in pixels. For RGB pixels you need 3 bytes.
After this is fixed you need to convert your greyscale pixels to RGBB pixels. This is not "combining pixels" but simply repeating the same value.
This is some sample code to convert 8bit greyscale to 24bit RGB pixels:
// build:
// gcc -o test `pkg-config --cflags gtk+-3.0` test.c `pkg-config --libs gtk+-3.0`
#include <stdlib.h>
#include <stdint.h>
#include <gtk/gtk.h>
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} rgb;
int main (int argc, char *argv[])
{
size_t Width = 1936;
size_t Height = 1280;
size_t Stride_8 = Width; // Might need rounding up
size_t Stride_rgb = Width; // Might need rounding up
//Due to lack of camera data, lets use some dummy data...
uint8_t *buffer_8 = malloc(Stride_8*Height);
for (size_t x = 0; x < Width; x++)
for (size_t y = 0; y < Height; y++)
buffer_8[Stride_8*y + x] = (x+y) & 0xFF;
/*code to take raw image data from camera*/
// Put greyscale image data from the camera into the RGB buffer.
rgb *buffer_rgb = malloc(Stride_rgb * Height * sizeof(rgb));
for (size_t x = 0; x < Width; x++)
for (size_t y = 0; y < Height; y++)
{
// Convert 1 byte greyscale in 3 byte RGB:
uint8_t grey = buffer_8[Stride_8*y + x];
buffer_rgb[Stride_rgb*y + x].r = grey;
buffer_rgb[Stride_rgb*y + x].g = grey;
buffer_rgb[Stride_rgb*y + x].b = grey;
}
// GTK
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "test");
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GdkPixbuf *pixbuf_rgb = gdk_pixbuf_new_from_data((guchar*)buffer_rgb, GDK_COLORSPACE_RGB,FALSE, 8,
Width, Height, Stride_rgb*3, NULL, NULL);
GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf_rgb);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(window);
gtk_main();
free(buffer_rgb);
free(buffer_8);
return 0;
}
Related
I'm trying to find an example of showing an image in GTK 4.0 from an existing memory buffer, where the image is stored in the form of an array of floats of size width x height x 3. I understand I need to use GtkImage, but I don't know how to pass such an array to it.
Just for context, I wanted to implement a prototype for rendering some images, they are all rendered in memory, and as a result, I have an array of such floats, three floats for each pixel. Unfortunately, I could not find any examples for the latest GTK 4.0. There are plenty of examples of loading an image from the disk, but it seems like jumping unnecessary hoops for my case. I used to load these as OpenGL texture and show them on a quad, but it also seems like driving nails with a sledgehammer.
Thank you in advance for any help!
You can use GdkMemoryTexture for an image in memory and use a GtkPicture and set the texture using gtk_picture_set_paintable() to paint it. The following is an example that creates an opaque 8bit RGB image and displays it on the screen:
/* pixel.c
*
* Compile: cc -ggdb pixel.c -o pixel $(pkg-config --cflags --libs gtk4) -o pixel
* Run: ./pixel
*
* Author: Mohammed Sadiq <www.sadiqpk.org>
*
* SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
*/
#include <gtk/gtk.h>
#define BYTES_PER_R8G8B8 3
#define WIDTH 400
static void
fill_row (GByteArray *array,
guint8 value,
int row_size)
{
guint i;
for (i = 0; i < row_size; i++) {
/* Fill the same values for RGB */
g_byte_array_append (array, &value, 1); /* R */
g_byte_array_append (array, &value, 1); /* G */
g_byte_array_append (array, &value, 1); /* B */
}
}
static void
add_pixel_picture (GtkPicture *picture)
{
g_autoptr(GBytes) bytes = NULL;
GdkTexture *texture;
GByteArray *pixels;
gsize height;
/* Draw something interesting */
pixels = g_byte_array_new ();
for (guint i = 0; i <= 0xff ; i++)
fill_row (pixels, i, WIDTH);
for (guint i = 0; i <= 0xff; i++)
fill_row (pixels, 0xff - i, WIDTH);
height = pixels->len / (WIDTH * BYTES_PER_R8G8B8);
bytes = g_byte_array_free_to_bytes (pixels);
texture = gdk_memory_texture_new (WIDTH, height,
GDK_MEMORY_R8G8B8,
bytes,
WIDTH * BYTES_PER_R8G8B8);
gtk_picture_set_paintable (picture, GDK_PAINTABLE (texture));
}
static void
app_activated_cb (GtkApplication *app)
{
GtkWindow *window;
GtkWidget *picture;
window = GTK_WINDOW (gtk_application_window_new (app));
g_object_set (window,
"width-request", 500,
"height-request", 400,
NULL);
picture = gtk_picture_new ();
gtk_widget_add_css_class (picture, "frame");
g_object_set (picture,
"margin-start", 96,
"margin-end", 96,
"margin-top", 96,
"margin-bottom", 96,
NULL);
gtk_window_set_child (window, picture);
add_pixel_picture (GTK_PICTURE (picture));
gtk_window_present (window);
}
int
main (int argc,
char *argv[])
{
g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
return g_application_run (G_APPLICATION (app), argc, argv);
}
Use the GdkMemoryFormat that suites your data, or convert it to one that's supported.
This piece of SDL2 code draws some white pixels on-screen using OpenGL, then grabs the pixels field of the window's SDL_Surface and loops through it, printing out the values of the contents. Even though I just drew a white triangle, the loop shows that there's nothing but zeros in that buffer (the code just prints 0 to standard out over and over).
How can I actually get at the modified pixel buffer, in something like RGB or ARGB or RGBA format?
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <GL/glu.h>
int main()
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
const int WINDOW_WIDTH = 100;
const int WINDOW_HEIGHT = 100;
SDL_Window *window = SDL_CreateWindow("OpenGL Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL);
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLenum error = glGetError();
if( error != GL_NO_ERROR )
{
printf( "Error initializing OpenGL! %s\n", gluErrorString(error));
}
glClearColor(0, 0, 0, 1);
int quit = 0;
SDL_Event event;
while (!quit)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
quit = 1;
break;
}
}
glBegin(GL_TRIANGLES);
glColor3f(255, 255, 255);
glVertex2f(0, 0);
glVertex2f(0, 1);
glVertex2f(1, 0);
glEnd();
SDL_GL_SwapWindow(window);
SDL_Surface *surface = SDL_GetWindowSurface(window);
int pixel_depth = SDL_BYTESPERPIXEL(surface->format->format);
char *pixels = (char*) surface->pixels;
int max_value = 0;
for (int i = 0; i < WINDOW_WIDTH * WINDOW_HEIGHT * pixel_depth; i++)
{
if (pixels[i] > max_value)
{
max_value = pixels[i];
}
}
SDL_FreeSurface(surface);
SDL_Log("%d", max_value);
}
SDL_Quit();
return 0;
}
SDL_GetWindowSurface() doesn't work with OpenGL:
You may not combine this with 3D or the rendering API on this window.
Use glReadPixels() instead.
Use PBO to read data from from the pixel buffer.
glReadBuffer(GL_COLOR_ATTACHMENT0);
writeIndex = (writeIndex + 1) % 2;
readIndex = (readIndex + 1) % 2;
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]);
// copy from framebuffer to PBO asynchronously. it will be ready in the NEXT frame
glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// now read other PBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]);
unsigned char* Data = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
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.
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:
gtk_init(NULL, NULL);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "Image Player");
g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
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 image variable through the updated pixbuf and automatically updates it in the window.
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);
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.
EDIT: Test script included below:
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
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 < width; i++){
for(size_t j = 0; j < height; j++){
//printf("%d\t%d\n", 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_ > 255){
r_ = (uint8_t) 0;
}
if (g_ > 255){
g_ = (uint8_t) 0;
}
if (b_ > 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("x: %d\ty: %d\tz: %d\nr: %d\tg: %d\tb: %d\n", 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), "Image Viewer");
g_signal_connect (window, "destroy", 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("displaying image\n");
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 < width; i++){
for(size_t j = 0; j < height; j++){
//printf("%d\t%d\n", 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_ > 255){
r_ = (uint8_t) 0;
}
if (g_ > 255){
g_ = (uint8_t) 0;
}
if (b_ > 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("x: %d\ty: %d\tz: %d\nr: %d\tg: %d\tb: %d\n", 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), "Image Player");
g_signal_connect(window, "destroy", 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("mtest/idwt_bin0_test1.raw", "rb");
y_1 = fopen("mtest/idwt_bin1_test1.raw", "rb");
z1 = fopen("mtest/idwt_bin2_test1.raw", "rb");
x2 = fopen("mtest/idwt_bin0_test2.raw", "rb");
y2 = fopen("mtest/idwt_bin1_test2.raw", "rb");
z2 = fopen("mtest/idwt_bin2_test2.raw", "rb");
// 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(&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;
}```
I'm trying to use GtkTextView for highlighting C++ style comments in code but it does not seem to work right. I want to create a function that first resets all the highlight to default (black) and then paints only the part of the text that matches pattern /.?*/ While the regex part works I have serious problem with Gtk obedience - it just paints the text black and stops. Is there any logical explaination for this? Am I doing something wrong? I'm placing the sample code that should work but it does not. The compilation command is
gcc -o highlight_syntax_comments highlight_syntax_comments.c `pkg-config --cflags --libs gtk+-3.0`
#define GLIB_VERSION_2_28 (G_ENCODE_VERSION (2, 28))
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_28
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
GtkTextBuffer *buffer;
GtkTextIter iter;
size_t f_size;
char* string;
int err;
static void highlight_syntax() {
GtkTextIter match_start, match_end;
GtkTextSearchFlags flags;
GtkTextTagTable* table = gtk_text_buffer_get_tag_table (buffer);
GtkTextTag* orange_tag = gtk_text_tag_table_lookup (table, "orange");
GtkTextTag* black_tag = gtk_text_tag_table_lookup (table, "black");
GtkTextTag* green_tag = gtk_text_tag_table_lookup (table, "green");
// reset color to black
gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER (buffer), &match_start);
gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (buffer), &match_end);
gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer), black_tag, &match_start, &match_end);
// color first 100 chars
gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER (buffer), &match_start, 0);
gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER (buffer), &match_end, 100);
gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer), orange_tag, &match_start, &match_end);
}
static gboolean key_callback(GtkWidget *widget,
GdkEventKey *event,
GtkIMContext *im_context) {
highlight_syntax();
return FALSE;
}
#include <stdio.h>
#include <stdlib.h>
#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TO_LARGE 2
#define FILE_READ_ERROR 3
char * c_read_file(const char * f_name, int * err, size_t* f_size) {
char * buffer;
size_t length;
FILE * f = fopen(f_name, "rb");
size_t read_length;
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = (char *)malloc(length + 1);
read_length = fread(buffer, 1, length, f);
fclose(f);
*err = FILE_OK;
buffer[length] = '\0';
*f_size = length;
}
else {
*err = FILE_NOT_EXIST;
return NULL;
}
return buffer;
}
int main(int argc, gchar *argv[]) {
GtkWidget *window;
GtkWidget *view;
GtkWidget *vbox;
GtkWidget *scrolled_window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
GtkIMContext *im_context = gtk_im_multicontext_new();
GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
gtk_im_context_set_client_window(im_context, gdk_window);
gtk_im_context_focus_in(im_context);
vbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
view = gtk_text_view_new();
gtk_widget_add_events(view, GDK_BUTTON_PRESS_MASK);
gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (scrolled_window),
vbox);
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
gtk_text_buffer_create_tag(buffer, "orange", "foreground", "#e87d3e", NULL);
gtk_text_buffer_create_tag(buffer, "green", "foreground", "#A6E22E", NULL);
gtk_text_buffer_create_tag(buffer, "black", "foreground", "#000000", NULL);
string = c_read_file("./highlight_syntax_comments.c", &err, &f_size);
gtk_text_buffer_insert(buffer, &iter, string, -1);
highlight_syntax();
gtk_container_add(GTK_CONTAINER(window), scrolled_window);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "key-press-event",
G_CALLBACK(key_callback), im_context);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
This is explained in the documentation for gtk_text_tag_set_priority() — setting one tag does not remove another, so both the orange and black tags are applying to the text at the same time. Since the black tag was added to the tag table last, its priority is highest, so it overrides the orange tag, even though you applied the orange tag on the text after applying the black tag.
The solution is to give the orange tag a higher priority, or make sure that you remove the black tag from the text that you want to apply the orange tag to.
I'm using gtk+2.0 and cairo. I wrote a simple program that open a window and
move a point. A simple biliard, only horizontal motion. It's just a test.
The problem is that it seems to be not so smooth, and I would ask if there
are some gtk or cairo expert here that could check for errors in the code.
Thanks.
#include <gtk/gtk.h>
#include <math.h>
gboolean timeout(gpointer data)
{
GtkWidget *widget = GTK_WIDGET(data);
if (!widget->window) return TRUE;
gtk_widget_queue_draw(widget);
}
gboolean configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
return TRUE;
}
double px = 10;
double vx = **2**;
gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height);
cairo_clip(cr);
cairo_set_source_rgb(cr,1,0,0);
cairo_arc(cr, px, 100, 6, 0, 2*M_PI);
cairo_fill(cr);
cairo_set_source_rgb(cr,0,0,0);
cairo_destroy(cr);
if (px <= 3 || px >= 200-3) vx = -vx;
px += vx;
return FALSE;
}
int main(int argc, char *argv[])
{
char *title = "Test";
int sx = 200;
int sy = 200;
gtk_init(NULL,NULL);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),title);
gtk_container_set_border_width(GTK_CONTAINER (window), 2);
g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit),&window);
GtkWidget *drawing_area = gtk_drawing_area_new();
//g_signal_connect(window,"key-press-event",G_CALLBACK(on_key_press),NULL);
const GdkColor bianco = { 0, 0xffff, 0xffff, 0xffff };
const GdkColor nero = { 0, 0x0, 0x0, 0x0 };
gtk_widget_modify_bg(drawing_area, GTK_STATE_NORMAL, &bianco);
gtk_widget_set_size_request(drawing_area, sx, sy);
g_signal_connect(drawing_area,"configure_event",G_CALLBACK(configure), NULL);
g_signal_connect(drawing_area,"expose_event",G_CALLBACK(expose),NULL);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
gtk_widget_show(drawing_area);
g_timeout_add(**10**, timeout, window);
if (!GTK_WIDGET_VISIBLE (window))
gtk_widget_show_all(window);
else {
gtk_widget_destroy (window);
window = NULL;
}
gtk_main();
return 0;
}
Not so smooth ? Well, with a period of 100ms, you're drawing at best 10 frames per second, no wonder it's not smooth... You should aim for 60 fps. Furthermore, you're invalidating the whole widget by calling gtk_widget_queue_draw, so your call to cairo_clip is mostly useless, as the clipping region is the whole widget. You should call gtk_widget_queue_draw_area instead so your clipping region is useful, and determining the area by keeping a record of the animation at frame n and n-1, so you redraw both areas to avoid the previous frame not being deleted.
There are lots of interesting stuff on animation perception on Owen Tailor's blog, starting with this post and more recent:
http://blog.fishsoup.net/2009/05/28/frames-not-idles/
Give a look at all the posts with figures, it's a gold mine.