最近做了个简单的画图程序,改自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;
}