# Ejemplo de uso del Widgetserver desde Octave.

Las comunicaciones con el Widgetserver se realizarán usando el comando de octave popen2. El problema es que la implementación de este comando falla. La implementación correcta de este comando sería:

    function [in, out, pid] = popen2 (command, args)

      in = -1;
      out = -1;
      pid = -1;

      if (nargin == 1 || nargin == 2)

        if (nargin == 1)
          args = "";
        endif

        if (ischar (command))

          [stdin_pipe, stdin_status] = pipe ();
          [stdout_pipe, stdout_status] = pipe ();

          if (stdin_status == 0 && stdout_status == 0)

            pid = fork ();

            if (pid == 0)

    	  ## In the child.

              fclose (nth (stdin_pipe, 2));
              fclose (nth (stdout_pipe, 1));

              dup2 (nth (stdin_pipe, 1), stdin);
              fclose (nth (stdin_pipe, 1));

              dup2 (nth (stdout_pipe, 2), stdout);
              fclose (nth (stdout_pipe, 2));

              if (exec (command, args) < 0)
                error ("popen2: unable to start process `%s'", command);
                exit (0);
              endif

            elseif (pid)

    	  ## In the parent.

              fclose (nth (stdin_pipe, 1));
              fclose (nth (stdout_pipe, 2));

              %if (fcntl (nth (stdout_pipe, 1), F_SETFL, O_NONBLOCK) < 0)
              %  error ("popen2: error setting file mode");
              %else
                in = nth (stdin_pipe, 2);
                out = nth (stdout_pipe, 1);
              %endif

            elseif (pid < 0)
              error ("popen2: fork failed -- unable to create child process");
            endif
          else
            error ("popen2: pipe creation failed");
          endif
        else
          error ("popen2: file name must be a string");
        endif
      else
        usage ("[in, out, pid] = popen2 (command, args)");
      endif

    endfunction

Se puede incluir dentro de los programas de Octave, pues Octave permite redefinir las funciones.

Para comunicarse con Octave se seguirán los siguientes pasos:
1. Se abrirán las comunicaciones con el Widgetserver usando popen2.
2. Se le mandarán las instrucciones necesarias para construir la ventana.
3. Se escucharán los eventos con fgets.

# Ejemplo comentado.

El siguiente ejemplo abre una ventana que pide el argumento de la función sombrero:

    [out,in,pid]=popen2("widgetserver");
    if(pid<0)
    	printf("Error widgetserver couldn't be executed\n");
    	exit(1);
    end

Lo que se ha hecho es abrir las comunicaciones con el Widgetserver. En el caso de que el programa widgetserver no se encuentre, se muestra un mensaje de error. En el caso de que no funcione correctamente, se puede usar la implementación de popen2 mostrada anteriormente.

    fprintf(out, "<window:frame>\n");
    fprintf(out, "	<title:Sombrero/>\n");
    fprintf(out, "	<p>\n");
    fprintf(out, "	<label:l1>\n");
    fprintf(out, "	 	Number of grids\n");
    fprintf(out, "	</label>\n");
    fprintf(out, "	<lineedit:w0>\n");
    fprintf(out, "		<text: 20/>\n");
    fprintf(out, "	</lineedit>\n");
    fprintf(out, "	</p>\n");
    fprintf(out, "	<html:ht1>\n");
    fprintf(out, "		Draws sombrero function\n");
    fprintf(out, "	</html>\n");
    fprintf(out, "	<p>\n");
    fprintf(out, "	<button:ok>\n");
    fprintf(out, "		<listen: clicked/>\n");
    fprintf(out, "		<text>\n");
    fprintf(out, "	 		Ok\n");
    fprintf(out, "		</text>\n");
    fprintf(out, "	</button>\n");
    fprintf(out, "	<button:cancel>\n");
    fprintf(out, "		<listen: clicked/>\n");
    fprintf(out, "		<text>\n");
    fprintf(out, "	 		Cancel\n");
    fprintf(out, "		</text>\n");
    fprintf(out, "	</button>\n");
    fprintf(out, "	</p>\n");
    fprintf(out, "</window>\n");

    fflush(out);

Se envía la ventana que se tiene que mostrar. El fflush(out) es importante para poder enviar los datos..Es mucho más cómodo escribir la ventana en un fichero y enviarla después leyendo el fichero.

    %Event loop
    while( isstr ( line=fgets(in) ) )
    	% Se procesan los eventos para cerrar la ventana
    	if(
    		( length(line)>=15 && strcmp(substr(line,1,16),'*clicked: cancel') )
    		||
    		( length(line)>=13 && strcmp(substr(line,1,13),'*close: frame') )
    	  )
    		fprintf(out, "<quit/>\n");
    		fflush(out);
    		break;
    	end;

    	% Se debe haber hecho click sobre el botón de Ok.

    	% Se lee la línea de texto.
    	fprintf(out, "<lineedit:w0>\n");
    	fprintf(out, "	<getText/>\n");
    	fprintf(out, "</lineedit>\n");
    	fflush(out);

    	line=fgets(in);
    	w0=fgets(in);

    	%Se dibuja el sombrero
    	sombrero(eval(w0));

    end

Este era el bucle de eventos, se van leyendo, línea a línea los datos que envía el Widgetserver y se procesan.
Las funciones strcmp, substr y length se usan para comparar las cadenas. La función strcmp compara dos cadenas e indica si son iguales. length sirve para indicar la longitud de un array (una cadena). substr sirve para extraer una parte de una cadena.

    fclose(in);
    fclose(out);

    % Fin del programa

En el fichero ej_sombrero.m se puede encontrar el ejemplo anterior.