Github user jmuehlner commented on a diff in the pull request:

    
https://github.com/apache/incubator-guacamole-manual/pull/17#discussion_r84208194
  
    --- Diff: src/chapters/adding-protocol.xml ---
    @@ -118,385 +221,564 @@ AM_CFLAGS = -Werror -Wall -pedantic
     lib_LTLIBRARIES = libguac-client-ball.la
     
     # All source files of libguac-client-ball
    -libguac_client_ball_la_SOURCES = src/ball_client.c
    +libguac_client_ball_la_SOURCES = src/ball.c
     
     # libtool versioning information
     libguac_client_ball_la_LDFLAGS = -version-info 
0:0:0</programlisting></para>
             <para>The GNU Automake files will remain largely unchanged 
throughout
                 the rest of the tutorial. </para>
    -        <para>Once you have created all of the above files, you will have a
    -            functioning client plugin. It doesn't do anything yet, but it 
does
    -            work, and guacd will load it when requested, and unload it 
when the
    -            connection terminates.</para>
    +        <para>Once you have created all of the above files, you will have 
a functioning client
    +            plugin. It doesn't do anything yet, and any connection will be 
extremely short-lived
    +            (the lack of any data sent by the server will lead to the 
client disconnecting under the
    +            assumption that the connection has stopped responding), but it 
does technically
    +            work.</para>
         </section>
         <section xml:id="libguac-client-ball-display-init">
             <title>Initializing the remote display</title>
    -        <para>Now that we have a basic functioning skeleton, we need to 
actually
    -            do something with the remote display. A good first step would 
be
    -            initializing the display - giving the connection a name, 
setting the
    -            remote display size, and providing a basic background.</para>
    -        <para>In this case, we name our connection "Bouncing Ball", set the
    -            display to a nice default of 1024x768, and fill the background 
with
    -            a simple gray:</para>
    +        <para>Now that we have a basic functioning skeleton, we need to 
actually do something with
    +            the remote display. A good first step would be simply 
initializing the display - setting
    +            the remote display size and providing a basic 
background.</para>
    +        <para>In this case, we'll set the display to a nice default of 
1024x768, and fill the
    +            background with gray. Though the size of the display 
<emphasis>can</emphasis> be chosen
    +            based on the size of the user's browser window (which is 
provided by the user during the
    +                <link xmlns:xlink="http://www.w3.org/1999/xlink";
    +                linkend="guacamole-protocol-handshake">Guacamole protocol 
handshake</link>), or even
    +            updated when the window size changes (provided by the user via 
<link
    +                xmlns:xlink="http://www.w3.org/1999/xlink"; 
linkend="size-event-instruction">"size"
    +                instructions</link>), we won't be doing that here for the 
simplicity's sake:</para>
             <informalexample>
    -        <programlisting xml:id="ball-02-ball_client.c" version="5.0" 
xml:lang="en">int guac_client_init(guac_client* client, int argc, char** argv) {
    -<emphasis>
    -    /* Send the name of the connection */
    -    guac_protocol_send_name(client->socket, "Bouncing Ball");
    +        <programlisting xml:id="ball-02-ball_client.c" version="5.0" 
xml:lang="en">#include &lt;guacamole/client.h>
    +<emphasis>#include &lt;guacamole/protocol.h>
    +#include &lt;guacamole/socket.h>
    +#include &lt;guacamole/user.h></emphasis>
    +
    +#include &lt;stdlib.h>
    +
    +...
    +
    +<emphasis>int ball_join_handler(guac_user* user, int argc, char** argv) {
    +
    +    /* Get client associated with user */
    +    guac_client* client = user->client;
    +
    +    /* Get user-specific socket */
    +    guac_socket* socket = user->socket;
     
         /* Send the display size */
    -    guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, 1024, 768);
    +    guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, 1024, 768);
     
         /* Fill with solid color */
    -    guac_protocol_send_rect(client->socket, GUAC_DEFAULT_LAYER,
    +    guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
                 0, 0, 1024, 768);
     
    -    guac_protocol_send_cfill(client->socket,
    +    guac_protocol_send_cfill(socket,
                 GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
                 0x80, 0x80, 0x80, 0xFF);
     
    +    /* Mark end-of-frame */
    +    guac_protocol_send_sync(socket, client->last_sent_timestamp);
    +
         /* Flush buffer */
    -    guac_socket_flush(client->socket);
    +    guac_socket_flush(socket);
    +
    +    /* User successfully initialized */
    +    return 0;
    +
    +}</emphasis>
    +
    +int guac_client_init(guac_client* client) {
    +
    +    /* This example does not implement any arguments */
    +    client->args = TUTORIAL_ARGS;
    +<emphasis>
    +    /* Client-level handlers */
    +    client->join_handler = ball_join_handler;
     </emphasis>
    -    /* Done */
         return 0;
     
     }</programlisting></informalexample>
    -        <para>Note how communication is done with the remote display. The
    -                <classname>guac_client</classname> given to
    -                <methodname>guac_client_init</methodname> has a member,
    -                <property>socket</property>, which is used for 
bidirectional
    -            communication. Guacamole protocol functions, all starting with
    -                "<methodname>guac_protocol_send_</methodname>", provide a
    -            slightly high-level mechanism for sending specific Guacamole
    -            protocol instructions to the remote display over the client's
    -            socket.</para>
    -        <para>Here, we set the name of the connection using a "name" 
instruction
    -            (using <methodname>guac_protocol_send_name</methodname>), we 
resize
    -            the display using a "size" instruction (using
    -                <methodname>guac_protocol_send_size</methodname>), and we 
then
    -            draw to the display using drawing instructions (rect and
    -            cfill).</para>
    +        <para>The most important thing to notice here is the new
    +                <function>ball_join_handler()</function> function. As it 
is assigned to
    +                <property>join_handler</property> of the 
<classname>guac_client</classname> given to
    +                <function>guac_client_init</function>, users which join 
the connection (including
    +            the user that opened the connection in the first place) will 
be passed to this function.
    +            It is the duty of the join handler to initialize the provided
    +                <classname>guac_user</classname>, taking into account any 
arguments received from
    +            the user during the connection handshake (exposed through 
<varname>argc</varname> and
    +                <varname>argv</varname> to the join handler). We aren't 
implementing any arguments,
    +            so these values are simply ignored, but we do need to 
initialize the user with respect
    +            to display state. In this case, we:</para>
    +        <orderedlist>
    +            <listitem>
    +                <para>Send a <link 
xmlns:xlink="http://www.w3.org/1999/xlink";
    +                        linkend="size-instruction">"size" 
instruction</link>, initializing the
    +                    display size to 1024x768.</para>
    +            </listitem>
    +            <listitem>
    +                <para>Draw a 1024x768 gray rectangle over the display 
using the <link
    +                        xmlns:xlink="http://www.w3.org/1999/xlink"; 
linkend="rect-instruction"
    +                        >"rect"</link> and <link 
xmlns:xlink="http://www.w3.org/1999/xlink";
    +                        linkend="cfill-instruction">"cfill"</link> 
instructions.</para>
    +            </listitem>
    +            <listitem>
    +                <para>Send a <link 
xmlns:xlink="http://www.w3.org/1999/xlink";
    +                        linkend="server-sync-instruction">"sync" 
instruction</link>, informing the
    +                    remote display that a frame has been completed.</para>
    +            </listitem>
    +            <listitem>
    +                <para>Flush the socket, ensuring that all data written to 
the socket thus far is
    +                    immediately sent to the user.</para>
    +            </listitem>
    +        </orderedlist>
    +        <para>At this point, if you build, install, and connect using the 
plugin, you will see a
    +            gray screen. The connection will still be extremely 
short-lived, however, since the only
    +            data ever sent by the plugin is sent when the user first 
joins. The lack of any data
    +            sent by the server over the remaining life of the connection 
will lead to the client
    +            disconnecting under the assumption that the connection has 
stopped responding. This will
    +            be rectified shortly once we add the bouncing ball.</para>
         </section>
         <section xml:id="libguac-client-ball-layer">
             <title>Adding the ball</title>
    -        <para>This tutorial is about making a bouncing ball "client", so
    -            naturally we need a ball to bounce. </para>
    -        <para>While we could repeatedly draw and erase a ball on the remote
    -            display, a more efficient technique would be to leverage 
Guacamole's
    -            layers.</para>
    -        <para>The remote display has a single root layer,
    -                <varname>GUAC_DEFAULT_LAYER</varname>, but there can be
    -            infinitely many other child layers, which can have themselves 
have
    -            child layers, and so on. Each layer can be dynamically 
repositioned
    -            within and relative to another layer. Because the compositing 
of
    -            these layers is handled by the remote display, and is likely
    -            hardware-accelerated, this is a much better way to repeatedly
    -            reposition something we expect to move a lot:</para>
    +        <para>This tutorial is about making a bouncing ball "client", so 
naturally we need a ball to
    +            bounce. While we could repeatedly draw and erase a ball on the 
remote display, a more
    +            efficient technique would be to leverage Guacamole's 
layers.</para>
    +        <para>The remote display has a single root layer, 
<varname>GUAC_DEFAULT_LAYER</varname>, but
    +            there can be infinitely many other child layers, which can 
have themselves have child
    +            layers, and so on. Each layer can be dynamically repositioned 
within and relative to
    +            another layer. Because the compositing of these layers is 
handled by the remote display,
    +            and is likely hardware-accelerated, this is a much better way 
to repeatedly reposition
    +            something we expect to move a lot.</para>
    +        <para>Since we're finally adding the ball, and there needs to be 
some structure which
    +            maintains the state of the ball, we must create a header file,
    +                <filename>src/ball.h</filename>, to define this:</para>
             <informalexample>
    -        <programlisting xml:id="ball-03-ball_client.c" version="5.0" 
xml:lang="en">int guac_client_init(guac_client* client, int argc, char** argv) {
    -<emphasis>
    -    /* The layer which will contain our ball */
    +            <programlisting version="5.0" xml:lang="en">#ifndef BALL_H
    +#define BALL_H
    +
    +#include &lt;guacamole/layer.h>
    +
    +typedef struct ball_client_data {
    +
         guac_layer* ball;
    +
    +} ball_client_data;
    +
    +#endif</programlisting>
    +        </informalexample>
    +        <para>To make the build system aware of the existence of the new
    +                <filename>src/ball.h</filename> header file, 
<filename>Makefile.am</filename> must
    +            be updated as well:</para>
    +        <informalexample>
    +            <programlisting version="5.0" xml:lang="en">...
    +
    +# All source files of libguac-client-ball
    +<emphasis>noinst_HEADERS = src/ball.h</emphasis>
    +libguac_client_ball_la_SOURCES = src/ball.c
    +
    +...</programlisting>
    +        </informalexample>
    +        <para>This new structure is intended to house the client-level 
state of the ball,
    +            independent of any users which join or leave the connection. 
The structure must be
    +            allocated when the client begins (within 
<function>guac_client_init</function>), freed
    +            when the client terminates (via a new client free handler), 
and must contain the layer
    +            which represents the ball within the remote display. As this 
layer is part of the remote
    +            display state, it must additionally be initialized when a user 
joins, in the same way
    +            that the display overall was initialized in earlier 
steps:</para>
    +        <informalexample>
    +        <programlisting xml:id="ball-03-ball_client.c" version="5.0" 
xml:lang="en"><emphasis>#include "ball.h"</emphasis>
    +
    +#include &lt;guacamole/client.h>
    +<emphasis>#include &lt;guacamole/layer.h></emphasis>
    +#include &lt;guacamole/protocol.h>
    +#include &lt;guacamole/socket.h>
    +#include &lt;guacamole/user.h>
    +
    +#include &lt;stdlib.h>
    +
    +...
    +
    +int ball_join_handler(guac_user* user, int argc, char** argv) {
    +
    +    /* Get client associated with user */
    +    guac_client* client = user->client;
    +<emphasis>
    +    /* Get ball layer from client data */
    +    ball_client_data* data = (ball_client_data*) client->data;
    +    guac_layer* ball = data->ball;
     </emphasis>
         ...
     <emphasis>
    -    /* Set up our ball layer */
    -    ball = guac_client_alloc_layer(client);
    -    guac_protocol_send_size(client->socket, ball, 128, 128);
    +    /* Set up ball layer */
    +    guac_protocol_send_size(socket, ball, 128, 128);
     
         /* Fill with solid color */
    -    guac_protocol_send_rect(client->socket, ball,
    +    guac_protocol_send_rect(socket, ball,
                 0, 0, 128, 128);
     
    -    guac_protocol_send_cfill(client->socket,
    +    guac_protocol_send_cfill(socket,
    --- End diff --
    
    Isn't this the instruction that fills the color?
    
    And the other one creates a rectangle?
    
    Comments are a little confusing.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastruct...@apache.org or file a JIRA ticket
with INFRA.
---

Reply via email to