/* sf_view.c */ #include #include #include #include #include #include #include #include "getopt.h" #include "sf.h" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #define BORDER 8 #define DEFAULT_WIDTH 256 #define DEFAULT_HEIGHT 256 #define PING_INTERVAL 5000 /* milliseconds */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* initial snowflake image * static char* sf_snowflake_xpm[]; */ #include "sf_snowflake_xpm.h" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static msg_pipe mp; /* View <-> Control pipe */ static char* img_image; /* shared memory XPM image */ static int img_sem; /* image mutex */ static int pid; /* our process id */ static int control_pid; /* Control process id */ static gint control_timer = 0; /* Control process timer */ static gint input_tag = -1; /* Control input handle */ static gint internal_image = TRUE; /* internal image? */ static gint closing = FALSE; /* are we closing? */ static GtkWidget* window; static GtkStyle* style; static GtkWidget* drawingarea; static GdkPixmap* backing_pixmap = (GdkPixmap*)0; static GdkPixmap* pixmap = (GdkPixmap*)0; static GdkBitmap* mask; static gchar name[128] = { '\0' }; static gint width; static gint height; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* prototypes */ static void view_Exit ( gint send_QUIT ); static void view_Quit ( GtkWidget* widget, GdkEvent* event, gpointer* data ); static gint view_Close ( GtkWidget* widget, GdkEvent* event, gpointer* data ); static gint check_parent ( gpointer data ); static void input_Callback ( gpointer clientdata, gint source, GdkInputCondition condition ); static gint configure_Event ( GtkWidget* widget, GdkEventConfigure* event ); static gint expose_Event ( GtkWidget* widget, GdkEventExpose* event ); static void view_image ( gchar** img ); static void apply_args ( int argc,char* argv[] ); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void view_main( int argc, char* argv[], msg_pipe control, int image_semid, char* image ) { mp = control; img_sem = image_semid; img_image = image; pid = getpid(); control_pid = getppid(); strcpy( name,"" ); if ( sscanf( sf_snowflake_xpm[0],"%d %d",&width,&height ) != 2 ) { fprintf( stderr,"View: invalid default image\n" ); exit( 1 ); } gtk_init( &argc,&argv ); window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_signal_connect( GTK_OBJECT( window ), "destroy", GTK_SIGNAL_FUNC( view_Quit ), NULL ); gtk_signal_connect( GTK_OBJECT( window ), "delete_event", GTK_SIGNAL_FUNC( view_Close ), NULL ); gtk_container_border_width( GTK_CONTAINER( window ),BORDER ); /* show the window; until the window has been realized, the pixmap * cannot determine the window's visual class */ gtk_widget_show( window ); /* check for command line options */ apply_args( argc,argv ); view_image( (gchar**)sf_snowflake_xpm ); control_timer = gtk_timeout_add( PING_INTERVAL, check_parent, (gpointer)control_pid ); input_tag = gdk_input_add( control.rcv, GDK_INPUT_READ, input_Callback, (gpointer)control.rcv ); gtk_main(); view_Exit( TRUE ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* quit, cleaning up before we go */ static void view_Exit( gint send_QUIT ) { snowflake_message msg; if ( send_QUIT && !closing ) { msg.cmd = cmd_QUIT; if ( !snd_msg( mp,&msg ) ) fprintf( stderr,"View: unable to send QUIT message\n" ); } if ( control_timer ) gtk_timeout_remove( control_timer ); control_timer = 0; gtk_widget_hide( drawingarea ); gdk_pixmap_unref( backing_pixmap ); gdk_pixmap_unref( pixmap ); if ( input_tag != -1 ) gdk_input_remove( input_tag ); close( mp.snd ); close( mp.rcv ); gtk_main_quit(); gdk_exit( 0 ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "destroy" signal request to quit */ static void view_Quit( GtkWidget* widget, GdkEvent* event, gpointer* data ) { view_Exit( TRUE ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* a window manager request to quit */ static gint view_Close( GtkWidget* widget, GdkEvent* event, gpointer* data ) { snowflake_message msg; closing = TRUE; /* do not 'close' View itself * get Control to tell us to Quit */ msg.cmd = cmd_CLOSE; if ( !snd_msg( mp,&msg ) ) fprintf( stderr,"View: unable to send CLOSE message\n" ); return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static gint check_parent( gpointer data ) { if ( !is_alive( control_pid ) ) view_Exit( FALSE ); return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void input_Callback( gpointer clientdata, gint source, GdkInputCondition condition ) { snowflake_message msg; if ( !rcv_msg( mp,&msg ) ) { fprintf( stderr,"View: incomplete message\n" ); view_Exit( TRUE ); } switch ( msg.cmd ) { case cmd_QUIT : /* Control is telling us to quit */ view_Exit( FALSE ); break; case cmd_PING : /* respond to a Control ping */ msg.cmd = cmd_PONG; msg.data.i = pid; if ( !snd_msg( mp,&msg ) ) view_Exit( FALSE ); break; case cmd_PONG : /* only in response to a PING */ break; case cmd_VIEW : /* view request */ if ( sscanf( msg.data.s,VIEW_SCAN_FORMAT, name, &width, &height ) != 3 ) { fprintf( stderr,"View: ill-formed command data\n" ); view_Exit( TRUE ); } /* wait on semaphore before reading image */ sem_wait( img_sem ); view_image( (gchar**)img_image ); /* signal semaphore after reading image */ sem_signal( img_sem ); /* acknowledge generate command */ msg.cmd = cmd_ACK; if ( !snd_msg( mp,&msg ) ) view_Exit( FALSE ); break; case cmd_GENERATE : /* only for the Generate process */ break; case cmd_TIMEOUT : /* only for the Generate process */ break; case cmd_ACK : /* only in response to VIEW */ break; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* Create a new backing pixmap of the appropriate size */ static gint configure_Event( GtkWidget* widget,GdkEventConfigure* event ) { if ( backing_pixmap ) gdk_pixmap_unref( backing_pixmap ); backing_pixmap = gdk_pixmap_new( widget->window, widget->allocation.width, widget->allocation.height, -1 ); gdk_draw_rectangle( backing_pixmap, widget->style->white_gc, TRUE, 0,0, widget->allocation.width, widget->allocation.height ); return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* (Re)Draw the screen from the image pixmap */ static gint expose_Event( GtkWidget* widget,GdkEventExpose* event ) { gdk_draw_pixmap( widget->window, widget->style->fg_gc[ GTK_WIDGET_STATE( widget ) ], pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width,event->area.height ); return FALSE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* mouse button click */ static gint button_Press_Event( GtkWidget* widget,GdkEventButton* event ) { #ifdef DEBUG printf( "button %d [%d,%d] ", event->button,(int)event->x,(int)event->y ); #endif return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void view_image( gchar** img ) { snowflake_message msg; gchar title[256]; if ( !internal_image ) { gdk_pixmap_unref( pixmap ); gdk_pixmap_unref( mask ); } else { style = gtk_widget_get_style( window ); } pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask, &style->bg[GTK_STATE_NORMAL], img ); if ( !internal_image ) { gtk_drawing_area_size( GTK_DRAWING_AREA( drawingarea ),width,height ); gtk_widget_queue_draw( drawingarea ); } else { drawingarea = gtk_drawing_area_new(); gtk_drawing_area_size( GTK_DRAWING_AREA( drawingarea ),width,height ); gtk_signal_connect( GTK_OBJECT( drawingarea ), "configure_event", (GtkSignalFunc)configure_Event, NULL ); gtk_signal_connect( GTK_OBJECT( drawingarea ), "expose_event", (GtkSignalFunc)expose_Event, NULL ); gtk_signal_connect( GTK_OBJECT( drawingarea ), "button_press_event", (GtkSignalFunc)button_Press_Event, NULL ); gtk_widget_set_events( drawingarea, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK ); gtk_container_add( GTK_CONTAINER( window ),drawingarea ); gtk_widget_show( drawingarea ); internal_image = FALSE; } gdk_window_resize( window->window,width+2*BORDER,height+2*BORDER ); sprintf( title,"%s",name ); gtk_window_set_title( GTK_WINDOW( window ),title ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void apply_args( int argc,char* argv[] ) { int command = 0; int option_index = 0; int val; int i; opterr = 0; /* disable getopt() generated messages */ while ( command >= 0 ) { option_index = 0; command = getopt_long( argc, argv, short_options, long_options, &option_index ); if ( command == -1 ) break; switch ( command ) { case c_VIEW_GEOMETRY : { int x,y; if ( !optarg || !*optarg ) { fprintf( stderr,"View: option %s requires an argument\n", argv[optind-1] ); break; } if ( sscanf( optarg,"%d%d",&x,&y ) == 2 ) { gint width,height; gint w_x,w_y,w_width,w_height,w_depth; width = gdk_screen_width(); height = gdk_screen_height(); gdk_window_get_geometry( window->window, &w_x,&w_y,&w_width,&w_height,&w_depth ); if ( x < 0 ) x = width - w_width + x; if ( y < 0 ) y = height - w_height + y; gtk_widget_set_uposition( window,x,y ); } } break; case '?' : break; default: /*fprintf( stderr,"getopt() returned code 0x%X ?\n",command );*/ break; } } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */