{\scriptsize \begin{lstlisting}
     1	/**
     2	   @file
     3	
     4	   Server/User-Side Application with GUI to control the robot.
     5	*/
     6	
     7	#include <time.h>
     8	#include <math.h>
     9	#include <pthread.h>
    10	#include <stdio.h>
    11	#include <stdlib.h>
    12	#include <gtk/gtk.h>
    13	#include <glib.h>
    14	#include <unistd.h>
    15	#include <signal.h>
    16	
    17	#include "../lib/libcomm.h"
    18	#include "guicommon.h"
    19	
    20	// Pointer to the Main-Application-Object. Is necessary if a function
    21	// of the GUI is called from a not-gui-object.
    22	GtkWidget *gs_application;
    23	
    24	// Stores the absolut position of the robot. 
    25	int robot_x = 50, robot_y = 0;
    26	// ... fill it into a structure to be able to transfer it
    27	struct ROBOT_POSITION robot_position;
    28	
    29	// Stores the portnumber on which the server operates. serverport:
    30	// Datalink (remote/connect); serverport + 1: Linemonitor
    31	// (local/bind).
    32	int serverport;
    33	
    34	// filediscriptor which pointes to the socket-stream which is
    35	// connected to the robot's side and used fot the data-transfer.
    36	int sock;
    37	
    38	// Configuration for LineMonitor. Stores the Soft- and Hard-Timeout
    39	// and wait-times.
    40	int soft_msec;
    41	int hard_msec;
    42	int wait_msec;
    43	
    44	// File discriptor to the linemonitor() connection. Used for Emergercy
    45	// Stop command
    46	int ems_fd;
    47	
    48	
    49	
    50	/**
    51	
    52	    @param widget (GtkWidget *) pointer to affected object (for
    53	    example: window).
    54	
    55	    @param event (GdkEventM *) pointer to structure which
    56	    describes the event.
    57	
    58	    @param data (gpointer) pointer to additional data from gtk.
    59	
    60	*/
    61	static gbooleandelete_event(GtkWidget *widget,
    62				    GdkEvent  *event,
    63				    gpointer   data) {
    64	
    65	  linemonitor_emergencystop(ems_fd); // ??
    66	  fprintf(stderr, "Shut down...\n");
    67	  gtk_main_quit();
    68	  gdk_window_process_all_updates();
    69	  return FALSE;
    70	}
    71	
    72	
    73	/** This function is called if a signal (line C-c, terminate)
    74	    occurs. See in signal() -calls in main() for detals.
    75	
    76	    @param sig (int) number of orrured signal
    77	*/
    78	static void finish(int sig) {
    79	  gs_delete_event(gs_application, NULL);
    80	}
    81	
    82	
    83	/** This function will be called be gtk when the window gets a closing
    84	    command, it makes sure that the interface is down and the program
    85	    is finished.
    86	
    87	    @param widget (GtkWidget *) pointer to affected object (for
    88	    example: window).
    89	
    90	    @param data (gpointer) pointer to additional data from gtk.
    91	 */
    92	void gs_delete_event(GtkWidget *widget, gpointer data) {
    93	  linemonitor_emergencystop(ems_fd);
    94	  fprintf(stderr, "Shut down...\n");
    95	  gtk_main_quit();
    96	  gdk_window_process_all_updates();
    97	}
    98	
    99	
   100	/** This function is called by gtk if the drawing area (da) needs to
   101	    be redrawn. For example if it becomes visible.
   102	
   103	    @param widget (GtkWidget *) pointer to affected object (in this
   104	    case the drawing area).
   105	
   106	    @param data (gpointer) pointer to additional data from gtk.
   107	*/
   108	void gs_da_expose_event(GtkWidget *widget, gpointer data) {
   109	  gui_common_drawrobot(widget, &robot_x, &robot_y, -1, -1, 0);
   110	}
   111	
   112	
   113	/** This function is called if an event occurs (mose motion or mouse
   114	    button press) over the drawing area (da).
   115	
   116	    @param widget (GtkWidget *) pointer to affected object (in this
   117	    case the drawing area).
   118	
   119	    @param event (GdkEventMotion *) pointer to structure which
   120	    describes the event.
   121	*/
   122	static gint
   123	motion_notify_event(GtkWidget *widget, GdkEventMotion *event) {
   124	  // variables for the position of the mouse
   125	  int x, y;
   126	
   127	  GdkModifierType state;
   128	
   129	  // member-variable to store if a moving action takes place or not
   130	  static int move = 0;
   131	
   132	  // get positoin of the mouse-pointer
   133	  if (event->is_hint) {
   134	    gdk_window_get_pointer (event->window, &x, &y, &state);
   135	  } else {
   136	    x = event->x;
   137	    y = event->y;
   138	    state = event->state;
   139	  }
   140	
   141	  // if left mouse button is pressed ...
   142	  if (state & GDK_BUTTON1_MASK) {
   143	    // ... re-draw robot and dertermine new position of the robot if
   144	    // the click was on the robot
   145	    gui_common_drawrobot(widget, &robot_x, &robot_y, x, y, 1);
   146	    move = 1;
   147	    // if the connection to the robot is established...
   148	    if (sock != 0) {
   149	      // ... and the position of it was changed ...
   150	      if ((robot_position.x != robot_x) ||
   151		  (robot_position.y != robot_y)) {
   152		robot_position.x = robot_x;
   153		robot_position.y = robot_y;
   154	
   155		// ... send the new coordinates to the robot
   156		block_send(sock, 1, (char *) &robot_position,
   157			   sizeof(struct ROBOT_POSITION));
   158	      }
   159	    }
   160	  } else {
   161	    // moving event is finished, drwa robot.
   162	    if (move) {
   163	      gui_common_drawrobot(widget, &robot_x, &robot_y, x, y, 2);
   164	      move = 0;
   165	    }
   166	  }
   167	  
   168	  return TRUE;
   169	}
   170	
   171	
   172	
   173	/** This function is called if a button is pressed
   174	
   175	    @param widget (GtkWidget *) pointer to affected object (button).
   176	
   177	    @param event (GdkEventMotion *) pointer to structure which
   178	    describes the event.
   179	*/
   180	
   181	void gs_button_press_event(GtkWidget *widget, gpointer data) {
   182	  if(strcmp("Emergency Stop", (char *)data) == 0) {
   183	    linemonitor_emergencystop(ems_fd);
   184	    gs_delete_event(gs_application, NULL);
   185	    g_print("Emergency Stop Button pressed\n");
   186	  }
   187	}
   188	
   189	
   190	
   191	/** Exception function for linemonitor_server(), print exception
   192	    code and meaning on the screen and initiate appropriate
   193	    actions if necessary. See linemonitor_server() API. */
   194	linemonitor_exception(char *server, int port, int type) {
   195	  fprintf(stderr, "linemonitor_exception(%s, %d, %d): ",
   196		  server, port, type);
   197	  switch (type) {
   198	  case 0:
   199	    fprintf(stderr, "Connecion Fault\n");
   200	    gs_delete_event(gs_application, NULL);
   201	    break;
   202	  case 1:
   203	    fprintf(stderr, "Soft Real Time Exception\n");
   204	    break;
   205	  case 2:
   206	    fprintf(stderr, "HARD Real Time Exception\n");
   207	    gs_delete_event(gs_application, NULL);
   208	    break;
   209	  } /* switch() */
   210	}
   211	
   212	
   213	/**
   214	   Start the linemonitor_server() -- waiting for a connection in a
   215	   background-thread. This has to be a thread because otherwise the
   216	   system would block.  It would wait for a connection while it is
   217	   supposed to connect itself.
   218	*/
   219	thread_wait_for_linemonitor() {
   220	  ems_fd = linemonitor_server(serverport + 1,
   221				      soft_msec, hard_msec, wait_msec,
   222				      (void *) linemonitor_exception);
   223	  pthread_exit(NULL);
   224	}
   225	
   226	
   227	
   228	int main(int argc, char *argv[]) {
   229	  // GTK-Objecte. This is necessary to create the buttons on the
   230	  // screen and connect them to some actions
   231	  GtkWidget *button1, *button2, *button3, *button4;
   232	  // Sorting into tables.
   233	  GtkWidget *table, *table2;
   234	  // pointer to the DrawingArea-Object
   235	  GtkWidget *da;
   236	
   237	  // Init the gtk (GUI toolkit)
   238	  gtk_init(&argc, &argv);
   239	
   240	  // Connect the finish() -function to some signals which can cause a
   241	  // system shut down.
   242	  signal(SIGHUP, finish);  // 01  /  hangup     - close Window
   243	  signal(SIGINT, finish);  // 02  /  Interrupt  - ^C - C-c
   244	  signal(SIGQUIT, finish); // 03  /  Quit
   245	  signal(SIGTERM, finish); // 15  /  Terminierung -- kill
   246	  signal(SIGALRM, finish); // 14  /  Alarm
   247	
   248	  // load and examine parameters
   249	  if (argc != 6) {
   250	    sock = 0;
   251	    fprintf(stderr, "%s robot-address port soft_msec hard_msec wait_msec\n", argv[0]);
   252	    //    exit(0);
   253	  } else {
   254	    // ID and atributes for the threads
   255	    pthread_t        thrd_2;
   256	    pthread_attr_t   thrd_2_attr;
   257	
   258	    serverport = atoi(argv[2]);
   259	    soft_msec = atoi(argv[3]);
   260	    hard_msec = atoi(argv[4]);
   261	    wait_msec = atoi(argv[5]);
   262	
   263	    // launch thread_wait_for_linemonitor(), see
   264	    // thread_wait_for_linemonitor().
   265	    pthread_attr_init(&thrd_2_attr);
   266	    pthread_create(&thrd_2,
   267			   &thrd_2_attr,
   268			   (void *) thread_wait_for_linemonitor,
   269			   NULL);
   270	
   271	    // make sure, that the linemonitor_server() is ready before
   272	    // connect to the robot.
   273	    sleep(1);
   274	
   275	    // connect to the robot.
   276	    if ((sock = socket_connect(argv[1], serverport)) <= 0) {
   277	      perror("connect()");
   278	      sock = 0;
   279	    }
   280	  }
   281	
   282	  // create button(s)
   283	  button1  = gtk_button_new_with_label("Emergency Stop");
   284	  //  button2  = gtk_button_new_with_label("Button 2");
   285	  //  button3  = gtk_button_new_with_label("Button 3");
   286	  //  button4  = gtk_button_new_with_label("Button 4");
   287	
   288	
   289	  // connect the buttons to the function gr_button_press_event(). If
   290	  // the botton is pressed, this function will be colled.
   291	  gtk_signal_connect(GTK_OBJECT(button1), "clicked",
   292			     GTK_SIGNAL_FUNC(gs_button_press_event),
   293			     "Emergency Stop" );
   294	  /*  gtk_signal_connect(GTK_OBJECT(button2), "clicked",
   295			     GTK_SIGNAL_FUNC(gs_button_press_event),
   296			     "Button 2");
   297	  gtk_signal_connect(GTK_OBJECT(button3), "clicked",
   298			     GTK_SIGNAL_FUNC(gs_button_press_event),
   299			     "Button 3" );
   300	  gtk_signal_connect(GTK_OBJECT(button4), "clicked",
   301			     GTK_SIGNAL_FUNC(gs_button_press_event),
   302			     "Button 4");*/
   303	
   304	  // create tables to sort buttons and drawindarea in it
   305	  table = gtk_table_new(2,2,FALSE);
   306	  table2 = gtk_table_new(2,2,FALSE);
   307	
   308	  // create new application (wiindow)
   309	  gs_application = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   310	
   311	  // set window title
   312	  gtk_window_set_title(GTK_WINDOW (gs_application),
   313			       "Server - User Interface");
   314	
   315	  // connect the function gr_delete_event() with the event of a
   316	  // window-close.
   317	  g_signal_connect(G_OBJECT (gs_application), "delete_event",
   318			   G_CALLBACK (gs_delete_event), NULL);
   319	
   320	  // display window
   321	  gtk_widget_show(gs_application);
   322	
   323	  // create drawing area
   324	  da = gtk_drawing_area_new();
   325	
   326	  // set which events in the drawing area causing a expose-event
   327	  gtk_widget_set_events (da, GDK_EXPOSURE_MASK
   328				 | GDK_LEAVE_NOTIFY_MASK
   329				 | GDK_BUTTON_PRESS_MASK
   330				 | GDK_POINTER_MOTION_MASK
   331				 | GDK_POINTER_MOTION_HINT_MASK);
   332	  
   333	  // set a minimum size of da
   334	  gtk_widget_set_size_request (da, 100, 100);
   335	  
   336	  // connect the function gr_delete_event() with the event of a
   337	  // window-close.
   338	  gtk_signal_connect(GTK_OBJECT(gs_application), "delete_event",
   339			     GTK_SIGNAL_FUNC(gs_delete_event), NULL);
   340	
   341	  // connect the function gr_da_expose_event() with the expose-event
   342	  // of the drawing area.
   343	  gtk_signal_connect(GTK_OBJECT(da), "expose_event",
   344			     GTK_SIGNAL_FUNC(gs_da_expose_event), NULL);
   345	
   346	  // connect the function motion_notify_event() with the
   347	  // mouse-motion-event of the drawing area.
   348	  gtk_signal_connect(da, "motion_notify_event",
   349			     GTK_SIGNAL_FUNC(motion_notify_event), NULL);
   350	
   351	  // fill the buttons in the table
   352	  gtk_table_attach_defaults(GTK_TABLE(table2), button1, 0,1, 0,1);
   353	  /*  gtk_table_attach_defaults(GTK_TABLE(table2), button2, 0,1, 1,2);
   354	  gtk_table_attach_defaults(GTK_TABLE(table2), button3, 1,2, 0,1);
   355	  gtk_table_attach_defaults(GTK_TABLE(table2), button4, 1,2, 1,2); */
   356	
   357	  // fill the drawing area and the table into another table
   358	  gtk_table_attach_defaults(GTK_TABLE(table), da, 0,1, 0,1);
   359	  gtk_table_attach_defaults(GTK_TABLE(table), table2, 0,1, 1,2);
   360	
   361	  // fill this table into the windos
   362	  gtk_container_add(GTK_CONTAINER(gs_application),table);
   363	
   364	  // display it  
   365	  gtk_widget_show_all(gs_application);
   366	
   367	  // call gtk-main-loop
   368	  gtk_main();
   369	
   370	  return 0;
   371	}
   372	
   373	
\end{lstlisting}}
