1. 程式人生 > >GTK簡單畫圖程式

GTK簡單畫圖程式

最近做了個簡單的畫圖程式,改自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;
}