GTK簡單畫圖程式
阿新 • • 發佈:2019-02-13
最近做了個簡單的畫圖程式,改自gtk example中的scribble-simple的程式,原來的例子是將報出來的點為基準然後向周圍擴散了一個區域。
現在是將報出來的點畫成線,
/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <stdlib.h> #include <gtk/gtk.h> #include <linux/fb.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <sys/ioctl.h> #include <unistd.h> #define LOG_BUF_MAX 512 #define LINE_LEN 50 #define UPDATEMODE_ADD 0x4004462d // address of update mode #define UPDATEDATE_ADD 0x4040462e // address of update date #define FBIOGET_VSCREENINFO 0x4600 #define FBIOGET_FSCREENINFO 0x4602 const char fb_dev[] = "/dev/fb0"; const char log[] = "/fb_ctrol.log"; int log_fd; struct fb_var_screeninfo info; void *scrbuf; int fb_fd; int cal_val[7]; int lx=0; //last x int ly=0; //last y int lx_root=0; //last root x int ly_root=0; //last root y int firstpoint = 1; int NewRegion = 0; int updateFlag = 1; struct Rect { __u32 top; __u32 left; __u32 width; __u32 height; }; struct mxcfb_rect { __u32 top; __u32 left; __u32 width; __u32 height; }; struct mxcfb_alt_buffer_data { __u32 phys_addr; __u32 width; /* width of entire buffer */ __u32 height; /* height of entire buffer */ struct mxcfb_rect alt_update_region; /* region within buffer to update */ }; struct mxcfb_update_data { struct mxcfb_rect update_region; __u32 waveform_mode; __u32 update_mode; __u32 update_marker; int temp; uint flags; struct mxcfb_alt_buffer_data alt_buffer_data; }; struct mxcfb_update_data upd_data; struct Rect lastRect; struct Rect mRect; GMutex *mutex =NULL; GtkWidget *window; GtkWidget *drawing_area; void log_write(const char *fmt, ...) { char buf[LOG_BUF_MAX]; va_list ap; if (log_fd < 0) return; va_start(ap, fmt); vsnprintf(buf, LOG_BUF_MAX, fmt, ap); buf[LOG_BUF_MAX - 1] = 0; va_end(ap); write(log_fd, buf, strlen(buf)); } /* Backing pixmap for drawing area */ static GdkPixmap *pixmap = NULL; /* Create a new backing pixmap of the appropriate size */ static gboolean configure_event( GtkWidget *widget, GdkEventConfigure *event ) { if (pixmap) g_object_unref (pixmap); pixmap = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1); gdk_draw_rectangle (pixmap, widget->style->white_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); return TRUE; } /* Change the update mode to 0 (manualy) */ void informDriver_manualy( ) { int infocus = 0; if(-1 == ioctl(fb_fd, UPDATEMODE_ADD, &infocus)) printf("in focus inform driver to change mode failed \n"); } /* Change the update mode to 1 (auto) */ static gboolean informDriver_auto( GtkWidget *widget, GdkEventExpose *event ) { //printf("set mode 1 \n"); int outfocus = 1; if(-1 == ioctl(fb_fd, UPDATEMODE_ADD, &outfocus)) printf("out focus inform driver to change mode failed \n"); return FALSE; } /* Redraw the screen from the backing pixmap */ static gboolean expose_event( GtkWidget *widget, GdkEventExpose *event ) { gdk_draw_drawable (widget->window, widget->style->fg_gc[gtk_widget_get_state (widget)], pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } /* Draw line on the screen */ static void draw_brush( GtkWidget *widget, gdouble x, gdouble y, gdouble x_root, gdouble y_root) { GdkRectangle update_rect; if ( firstpoint == 1 ) { lx=x; ly=y; lx_root=x_root; ly_root=y_root; firstpoint=0; } if ( 1 == NewRegion ) { lx = x; ly = y; lx_root=x_root; ly_root=y_root; NewRegion = 0; } g_mutex_lock(mutex); if ( x>lx ) { update_rect.width = x-lx+3; update_rect.x = lx; mRect.left =lx_root; mRect.width = x_root-lx_root+3; } else { update_rect.width = lx-x+3; update_rect.x = x; mRect.left=x_root; mRect.width=lx_root-x_root+3; } if ( y>ly ) { update_rect.height = y-ly+3; update_rect.y = ly; mRect.top=ly_root; mRect.height=y_root-ly_root+3; } else { update_rect.height = ly-y+3; update_rect.y = y; mRect.top=y_root; mRect.height=ly_root-y_root+3; } if ( 1 == NewRegion ) { lastRect.left = mRect.left; lastRect.top = mRect.top; lastRect.width= mRect.width; lastRect.height=mRect.height; NewRegion = 0; } g_mutex_unlock(mutex); gdk_draw_line(pixmap,widget->style->black_gc,lx,ly,x, y); lx = x; ly = y; gtk_widget_queue_draw_area(widget,update_rect.x,update_rect.y, update_rect.width,update_rect.height); lx_root=x_root; ly_root=y_root; } static gboolean button_press_event( GtkWidget *widget, GdkEventButton *event ) { if (event->button == 1 && pixmap != NULL) { NewRegion = 1; informDriver_manualy(); draw_brush (widget, event->x,event->y,event->x_root, event->y_root); } return TRUE; } static gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) { int x, y, x_root, y_root; GdkModifierType state, state2; if (event->is_hint) { gdk_window_get_pointer (widget->window, &x, &y, &state); gdk_window_get_pointer (gdk_get_default_root_window(), &x_root, &y_root, &state2); } else { x = event->x; y = event->y; x_root=event->x_root; y_root=event->y_root; state = event->state; } if (state & GDK_BUTTON1_MASK && pixmap != NULL) draw_brush (widget, x, y,x_root,y_root); return TRUE; } /* clear window */ static void clear(GtkWidget *widget) { int width, height; gtk_window_get_size(window, &width, &height); gdk_window_clear(window); gdk_draw_rectangle(pixmap , drawing_area->style->white_gc , TRUE , 0 , 0 , width,height); gtk_widget_queue_draw(drawing_area); int quitmode = 1; if(-1 == ioctl(fb_fd, UPDATEMODE_ADD, &quitmode)) printf("quit out focus inform driver to change mode failed \n"); upd_data.waveform_mode = 257; upd_data.update_mode = 1; upd_data.update_region.left = 0; upd_data.update_region.width = 826; upd_data.update_region.top = 0; upd_data.update_region.height = 1200; if(-1 == ioctl(fb_fd, UPDATEDATE_ADD, &upd_data)) { printf("quit full flush ioctl failed \n" ); } } void quit () { int quitmode = 1; if(-1 == ioctl(fb_fd, UPDATEMODE_ADD, &quitmode)) printf("quit out focus inform driver to change mode failed \n"); upd_data.waveform_mode = 257; upd_data.update_mode = 1; upd_data.update_region.left = 0; upd_data.update_region.width = 826; upd_data.update_region.top = 0; upd_data.update_region.height = 1200; if(-1 == ioctl(fb_fd, UPDATEDATE_ADD, &upd_data)) { printf("quit full flush ioctl failed \n" ); } exit (0); } /* update */ void update() { while(TRUE) { if(lastRect.left != mRect.left || lastRect.top != mRect.top || lastRect.width != mRect.width || lastRect.height != mRect.height ) { g_mutex_lock(mutex); upd_data.update_region.left = mRect.left; upd_data.update_region.top = mRect.top; upd_data.update_region.width = mRect.width; upd_data.update_region.height = mRect.height; upd_data.waveform_mode = 1; upd_data.update_mode = 0; upd_data.update_marker = 0; g_mutex_unlock(mutex); g_mutex_lock(mutex); if(-1 == ioctl(fb_fd, UPDATEDATE_ADD, &upd_data)) { printf("draw_brush failed \n" ); } g_mutex_unlock(mutex); g_mutex_lock(mutex); lastRect.left = upd_data.update_region.left; lastRect.top = upd_data.update_region.top; lastRect.width= upd_data.update_region.width; lastRect.height=upd_data.update_region.height; g_mutex_unlock(mutex); } } } /* start update thread */ void startUpdateThread() { if(!g_thread_supported()) g_thread_init(NULL); GThread *thread1 = g_thread_create(update,"update", FALSE, NULL); g_thread_set_priority(thread1, 3 ); } int main( int argc, char *argv[] ) { GtkWidget *vbox,*hbox; GtkWidget *button, *clearbutton; struct fb_fix_screeninfo finfo; /* open log */ log_fd = open(log, O_WRONLY | O_CREAT | O_TRUNC); /* read framebuffer for resolution */ fb_fd = open(fb_dev, O_RDWR); if (fb_fd <= 0) { log_write("Failed to open %s\n", fb_dev); close(log_fd); return 0; } if (-1 == ioctl(fb_fd, FBIOGET_VSCREENINFO, &info)) { log_write("Failed to get screen info\n"); close(fb_fd); close(log_fd); return 0; } log_write("Screen resolution: %dx%d\n", info.xres, info.yres); if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) { log_write("Failed to get screen info: %d\n", errno); close(fb_fd); close(log_fd); return 0; } gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); // gtk_window_set_default_size(window,600,700); gdk_window_maximize(window); gtk_widget_set_name (window, "Draw Line"); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); // craete a new thread to update data startUpdateThread(); nice(0); g_signal_connect (window, "destroy", G_CALLBACK (quit), NULL); g_signal_connect (window, "focus_out_event", G_CALLBACK (informDriver_auto),NULL); mutex = g_mutex_new(); drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200); gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); gtk_widget_show (drawing_area); /* Signals used to handle backing pixmap */ g_signal_connect (drawing_area, "expose-event", G_CALLBACK (expose_event), NULL); g_signal_connect (drawing_area,"configure-event", G_CALLBACK (configure_event), NULL); /* Event signals */ g_signal_connect (drawing_area, "motion-notify-event", G_CALLBACK (motion_notify_event), NULL); g_signal_connect (drawing_area, "button-press-event", G_CALLBACK (button_press_event), NULL); gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); /* Add a h box to contain quit and clear button */ hbox = gtk_hbox_new(FALSE, 0); gtk_widget_show(hbox); /* .. And a quit button */ button = gtk_button_new_with_label ("Quit"); clearbutton = gtk_button_new_with_label ("clear"); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), clearbutton, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox,FALSE, FALSE, 0); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); g_signal_connect (clearbutton, "clicked", G_CALLBACK (clear),NULL); gtk_widget_show (button); gtk_widget_show (clearbutton); gtk_widget_show (window); gtk_main (); return 0; }