Github user jmuehlner commented on a diff in the pull request:
https://github.com/apache/incubator-guacamole-manual/pull/17#discussion_r84207528
--- 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 <guacamole/client.h>
+<emphasis>#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h></emphasis>
+
+#include <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
--- End diff --
This sentence may have too many haves in it.
---
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 [email protected] or file a JIRA ticket
with INFRA.
---