Аннотация статьи.
#ifndef MAIN_H
#define MAIN_H
#include <gtk/gtk.h>
typedef struct{
GtkApplication *restrict app;
GtkWidget *restrict win;
GtkBuilder *restrict builder;
}appdata;
appdata data;
appdata *data_ptr;
#endif
CC = gcc -std=c99
PKGCONFIG = $(shell which pkg-config)
CFLAGS = $(shell $(PKGCONFIG) --cflags gio-2.0 gtk+-3.0 librsvg-2.0) -rdynamic -O3
LIBS = $(shell $(PKGCONFIG) --libs gio-2.0 gtk+-3.0 gmodule-2.0 librsvg-2.0 epoxy) -lm
GLIB_COMPILE_RESOURCES = $(shell $(PKGCONFIG) --variable=glib_compile_resources gio-2.0)
SRC = $(wildcard *.c)
GEN = gresources.c
BIN = main
ALL = $(GEN) $(SRC)
OBJS = $(ALL:.c=.o)
all: $(BIN)
gresources.c: string.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=. --generate-dependencies string.gresource.xml)
$(GLIB_COMPILE_RESOURCES) string.gresource.xml --target=$@ --sourcedir=. --generate-source
%.o: %.c
$(CC) $(CFLAGS) -c -o $(@F) $<
$(BIN): $(OBJS)
$(CC) -o $(@F) $(OBJS) $(LIBS)
clean:
@rm -f $(GEN) $(OBJS) $(BIN)
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/com/example/YourApp">
<file preprocess="xml-stripblanks" compressed="true">window.glade</file>
</gresource>
</gresources>
#include "main.h"
GtkBuilder* builder_init(void)
{
GError *error = NULL;
data.builder = gtk_builder_new();
if (!gtk_builder_add_from_resource (data.builder, "/com/example/YourApp/window.glade", &error))
{
// загрузить файл не удалось
g_critical ("Не могу загрузить файл: %s", error->message);
g_error_free (error);
}
gtk_builder_connect_signals (data.builder,NULL);
return data.builder;
}
void application_activate(GtkApplication *application, gpointer user_data)
{
GtkBuilder *builder=builder_init();
data_ptr=&data;
data.win=GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
gtk_widget_set_size_request(data.win,360,240);
gtk_application_add_window(data.app,GTK_WINDOW(data.win));
gtk_widget_show_all(data.win);
}
void application_shutdown(GtkApplication *application, gpointer user_data)
{
g_object_unref(data.builder);
}
int main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
gint res;
data.app = gtk_application_new("gtk.org", G_APPLICATION_FLAGS_NONE);
g_signal_connect(data.app, "activate", G_CALLBACK(application_activate), NULL);
g_signal_connect(data.app, "shutdown", G_CALLBACK(application_shutdown), NULL);
res = g_application_run(G_APPLICATION(data.app), 0, NULL);
return 0;
}
typedef struct{
GtkApplication *restrict app;
GtkWidget *restrict win;
GtkBuilder *restrict builder;
GtkDrawingArea *restrict draw;
GtkImage *restrict image;
GtkEventBox *restrict eventbox1;
RsvgHandle *restrict svg_handle_image;
RsvgHandle *restrict svg_handle_svg;
GdkPixbuf *pixbuf;
cairo_t *restrict cr;
cairo_surface_t *restrict surf;
}appdata;
void application_activate(GtkApplication *application, gpointer user_data)
{
GtkBuilder *builder=builder_init();
data_ptr=&data;
data.win=GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
data.draw=GTK_DRAWING_AREA(gtk_builder_get_object(builder, "drawingarea1"));
data.image=GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
gtk_widget_set_size_request(data.win,640,480);
gtk_application_add_window(data.app,GTK_WINDOW(data.win));
gtk_widget_show_all(data.win);
}
gboolean
drawingarea1_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
if(!data.svg_handle_svg)
{data.svg_handle_svg=rsvg_handle_new_from_file("compassmarkings.svg",NULL);}
gboolean result=rsvg_handle_render_cairo(data.svg_handle_svg,cr);
if(result&&cr)
{cairo_stroke(cr);}
else
printf("Ошибка отрисовки\n");
return FALSE;
}
gboolean
image1_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
if(!data.svg_handle_image)
{
data.svg_handle_image=rsvg_handle_new_from_file("compassmarkings.svg",NULL);
data.surf=cairo_image_surface_create_from_png("2.png");
data.pixbuf=rsvg_handle_get_pixbuf(data.svg_handle_image);
}
if(data.pixbuf)
{
cairo_set_source_surface(cr,data.surf,0,0);
GdkPixbuf *dest=gdk_pixbuf_scale_simple (data.pixbuf,250,250,GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf (data.image,dest);
g_object_unref(dest);
cairo_paint(cr);
}
}
void application_shutdown(GtkApplication *application, gpointer user_data)
{
cairo_surface_destroy(data.surf);
g_object_unref(data.svg_handle_image);
g_object_unref(data.svg_handle_svg);
g_object_unref(data.pixbuf);
g_object_unref(data.builder);
}
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#include <stdbool.h>
int char_to_digit(char num)
{
switch(num)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case '.': return -1;
default: return -2;
}
}
//считывает число с позиции указателя text
double read_num_in_text(char* text)
{
double result=0;
int i=0;
bool fractional_flag=FALSE;
char whole_part[16]={0};
char whole_digits=0;
char fractional_part[16]={0};
char fractional_digits=0;
while(char_to_digit(text[i])!=-2)
{
if(char_to_digit(text[i])!=-1&&!fractional_flag)
{
whole_part[whole_digits]=char_to_digit(text[i]);
printf("text_num=%d|%c\n",char_to_digit(text[i]),text[i]);
++whole_digits;
++i;
}
else
{
if(char_to_digit(text[i])==-1)
{ printf("fractional flag is true\n");
fractional_flag=TRUE;
++i;
}
else
{
fractional_part[fractional_digits]=char_to_digit(text[i]);
++fractional_digits;
printf("frac_digit=%d|%c\n",char_to_digit(text[i]),text[i]);
++i;
}
}
}
///вычисление непосредственно самого числа
i=whole_digits;
result=whole_part[whole_digits];
while(i>0)
{
--i;
printf("whole=%d\n",whole_part[i]);
result=result+pow(10,whole_digits-i-1)*whole_part[i];
}
i=0;
while(i<=fractional_digits)
{
result=result+pow(0.1,i+1)*fractional_part[i];
++i;
}
printf("result_read_num=%lf\n",result);
return result;
}
//подситывает количество символов, которые надо удалить
//
int count_of_digits_for_delete(char* text)
{
int i=0;
bool fractional_flag=FALSE;
char whole_part[16]={0};
int whole_digits=0;
char fractional_part[16]={0};
int fractional_digits=0;
while(char_to_digit(text[i])!=-2)
{
if(char_to_digit(text[i])!=-1&&!fractional_flag)
{
whole_part[whole_digits]=char_to_digit(text[i]);
printf("text_num=%d|%c\n",char_to_digit(text[i]),text[i]);
++whole_digits;
++i;
}
else
{
if(char_to_digit(text[i])==-1)
{ printf("fractional flag is true\n");
fractional_flag=TRUE;
++i;
}
else
{
fractional_part[fractional_digits]=char_to_digit(text[i]);
++fractional_digits;
printf("frac_digit=%d|%c\n",char_to_digit(text[i]),text[i]);
++i;
}
}
}
if(fractional_flag)
return whole_digits+1+fractional_digits;
else
return whole_digits;
}
//создаёт пустой файл в каталоге рамдиска /dev/shm
//с именем совпадающим с названием файла
char* create_dump_file(char *file_with_path)
{
char *file=NULL;
int i=0;
while(file_with_path[i]!='\0')
{++i;}
while(file_with_path[i]!='/'&&i>0)
{--i;}
file=file_with_path+i;
GString *string=g_string_new("test -f /dev/shm");
g_string_append(string,file);
g_string_append(string,"|| touch /dev/shm/");
g_string_append(string,file);
system(string->str);
///нужно сформировать строку-полный путь
GString *full_path=g_string_new("/dev/shm");
g_string_append(full_path,file);
char *result=g_string_free(full_path,FALSE);
return result;
}
//result must be freed with g_string_free
GString* read_file_in_buffer(char *file_with_path)
{
FILE *input = NULL;
struct stat buf;
int fh, result;
char *body=NULL; //содержимое
GString *resultat=g_string_new("");
fh=open(file_with_path, O_RDONLY);
result=fstat(fh, &buf);
if (result !=0)
printf("Плох дескриптор файла\n");
else
{
printf("%s",file_with_path);
printf("Размер файла: %ld\n", buf.st_size);
printf("Номер устройства: %lu\n", buf.st_dev);
printf("Время модификации: %s", ctime(&buf.st_atime));
input = fopen(file_with_path, "r");
if (input == NULL)
{
printf("Error opening file");
}
body=(char*)calloc(buf.st_size+64,sizeof(char)); //дополнительная память для цифр
//проверяем хватило ли памяти
if(body==NULL)
{
printf("Не хватает оперативной памяти для резмещения body\n");
}
int size_count=fread(body,sizeof(char),buf.st_size, input);
if(size_count!=buf.st_size)
printf("Считался не весь файл");
resultat=g_string_append(resultat,body);
free(body);
}
fclose(input);
return resultat;
}
void* write_string_to_file(char* writed_file, char* str_for_write, int lenght)
{
FILE * ptrFile = fopen (writed_file ,"wb");
size_t writed_byte_count=fwrite(str_for_write,1,lenght,ptrFile);
//if(writed_byte_count>4) return TRUE;
//else return FALSE;
fclose(ptrFile);
}
//возвращаемый результат нужно удалить при помощи g_free
char* get_resized_svg(char *file_with_path, int width, int height)
{
char *writed_file=create_dump_file(file_with_path);
//открываем файл и копируем содержимое в буфер
GString *body=read_file_in_buffer(file_with_path);
char *start_search=NULL;
char *end_search=NULL;
char *width_start=NULL;
char *width_end=NULL;
char *height_start=NULL;
char *height_end=NULL;
start_search=strstr(body->str,"<svg");
int j=0;
//анализируем содержимое файла
if(start_search)
{
end_search=strstr(start_search,">");
if(end_search)
{
///обработка параметра width
width_start=strstr(start_search,"width");
width_end=width_start+strlen("width");
///переход от тега width к его значению
while(width_end[j]==0x0A||width_end[j]==0x20) ++j;
if(width_end[j]=='=') ++j;
while(width_end[j]==0x0A||width_end[j]==0x20) ++j;
if(width_end[j]!='"')
printf("Ошибка анализа синтаксиса svg. Отсутсвует кавычки в параметре width=%c\n",width_end[j]);
else ++j; ///кавычка есть
///вычисление количества символов, подлежащих удалению
gssize size=count_of_digits_for_delete(width_end+j);
///вычисление относительной позиции (1 позиция - 1 байт)
gssize pos=width_end+j-body->str;
///удаляем ненужное значение ширины и вставляем нужное
g_string_erase(body,pos,size);
char width_new[8];
g_snprintf(width_new,8,"%d",width);
g_string_insert(body, pos, width_new);
///обработка параметра height
height_start=strstr(start_search,"height");
height_end=height_start+strlen("height");
///переход от тега height к его значению
j=0;
while(height_end[j]==0x0A||height_end[j]==0x20) ++j;
if(height_end[j]=='=') ++j;
while(height_end[j]==0x0A||height_end[j]==0x20) ++j;
if(height_end[j]!='"')
printf("Ошибка анализа синтаксиса svg. Отсутсвует кавычки в параметре height=%c%c%c\n",height_end[j-1],height_end[j],height_end[j+1]);
else ++j; ///кавычка есть
///вычисление количества символов, подлежащих удалению
size=count_of_digits_for_delete(height_end+j);
///вычисление относительной позиции (1 позиция - 1 байт)
pos=height_end+j-body->str;
///удаляем ненужное значение высоты и вставляем нужное
g_string_erase(body,pos,size);
char height_new[8];
g_snprintf(height_new,8,"%d",height);
g_string_insert(body, pos, height_new);
///нужно открыть на запись файл в dev/shm/
///записать изменённый массив
write_string_to_file(writed_file,body->str,strlen(body->str));
return writed_file;
//g_free(writed_file);
g_string_free(body,TRUE);
}
else
printf("Ошибка анализа: нет закрывающей скобки у тега svg");
}
}
void resized_svg_free(char *path)
{
if (remove (path)==-1 )
{
printf("Не удалось удалить файл %s\n",path);
}
}
#ifndef SVG_TO_PIXBUF_CLASS_H
#define SVG_TO_PIXBUF_CLASS_H
void resized_svg_free(char *path);
char* get_resized_svg(char *file_with_path, int width, int height); //result must be freed with g_free()
#endif
gboolean
drawingarea1_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
if(!data.svg_handle_svg)
{
char* path=get_resized_svg("/home/alex/svg_habr/compassmarkings.svg", 220, 220);
data.svg_handle_svg=rsvg_handle_new_from_file(path,NULL);
resized_svg_free(path);
g_free(path);
}
gboolean result=rsvg_handle_render_cairo(data.svg_handle_svg,cr);
if(result&&cr)
{cairo_stroke(cr);}
else
printf("Ошибка отрисовки\n");
return FALSE;
}
//результат экспортируется в data.path
void get_real_path(char *argv0)
{
char* result=(char*)calloc(1024,sizeof(char));
char* cwd=(char*)calloc(1024,sizeof(char));
getcwd(cwd, 1024);
int i=0;
while(argv0[i]!='\0'&&i<1024)
++i;
while(argv0[i]!='/'&&i>0)
--i;
result[i]='\0';
while(i>0)
{
--i;
result[i]=argv0[i];
}
/*alex@alex-System-Product-Name:~/project_manager$ ./manager.elf
argv[0]=./manager.elf
path=/home/alex/project_manager*/
if(strlen(result)<=strlen(cwd)) //путь слишком короткий
{
free(result);
strcpy(data.path,cwd);
strcat(data.path,"/");
//printf("path_cwd=%s\n",cwd);
free(cwd);}
else
{
/*alex@alex-System-Product-Name:/home$ '/home/alex/project_manager/manager.elf'
argv[0]=/home/alex/project_manager/manager.elf
path=/home*/
free(cwd);
strcpy(data.path,result);
strcat(data.path,"/");
//printf("path_result=%s\n",result);
free(result);
}
}
char cwd[1024];
getcwd(cwd, sizeof(cwd));
get_real_path(argv[0]);
gboolean
drawingarea1_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
if(!data.svg_handle_svg)
{
char image_path[1024];
strcat(image_path,data.path);
strcat(image_path,"compassmarkings.svg");
printf("image_path=%s\n",image_path);
char* path=get_resized_svg(image_path, 220, 220);
data.svg_handle_svg=rsvg_handle_new_from_file(path,NULL);
resized_svg_free(path);
g_free(path);
}
gboolean result=rsvg_handle_render_cairo(data.svg_handle_svg,cr);
if(result&&cr)
{cairo_stroke(cr);}
else
printf("Ошибка отрисовки\n");
return FALSE;
}
clock_t tic = clock();
clock_t toc = clock();
printf("image1_draw_cb elapsed : %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);
gboolean
image1_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
clock_t tic = clock();
if(!data.svg_handle_image)
{
data.svg_handle_image=rsvg_handle_new_from_file("compassmarkings.svg",NULL);
data.surf=cairo_image_surface_create_from_png("2.png");
data.pixbuf=rsvg_handle_get_pixbuf(data.svg_handle_image);
//}
//if(data.pixbuf)
// {
cairo_set_source_surface(cr,data.surf,0,0);
GdkPixbuf *dest=gdk_pixbuf_scale_simple (data.pixbuf,250,250,GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf (data.image,dest);
g_object_unref(dest);
//cairo_paint(cr);
}
clock_t toc = clock();
printf("image1_draw_cb elapsed : %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);
return FALSE;
}
К сожалению, не доступен сервер mySQL