ecore/fd_handler - Add an example.
authorRafael Antognolli <antognolli@gmail.com>
Tue, 28 Jun 2011 15:05:29 +0000 (15:05 +0000)
committerRafael Antognolli <antognolli@gmail.com>
Tue, 28 Jun 2011 15:05:29 +0000 (15:05 +0000)
SVN revision: 60766

legacy/ecore/doc/examples.dox
legacy/ecore/src/examples/Makefile.am
legacy/ecore/src/examples/ecore_fd_handler_example.c [new file with mode: 0644]

index 91c6283..06330b2 100644 (file)
  */
 
 /**
+ * @page ecore_event_example_c ecore fd handlers - Monitoring file descriptors
+ * @dontinclude ecore_fd_handler_example.c
+ *
+ * This is a very simple example where we will start monitoring the stdin of the
+ * program and, whenever there's something to be read, we call our callback that
+ * will read it.
+ *
+ * This seems to be stupid, since a similar result could be achieved by the
+ * following code:
+ *
+ * @code
+ * while (nbytes = read(STDIN_FILENO, buf, sizeof(buf)))
+ *   {
+ *      buf[nbytes - 1] = '\0';
+ *      printf("Read %zd bytes from input: \"%s\"\n", nbytes - 1, buf);
+ *   }
+ * @endcode
+ *
+ * However, the above code is blocking, and won't allow you to do anything else
+ * other than reading the input. Of course there are other methods to do a
+ * non-blocking reading, like setting the file descriptor to non-blocking and
+ * keep looping always checking if there's something to be read, and do other
+ * things otherwise. Or use a @c select call to watch for more than one file
+ * descriptor at the same time.
+ *
+ * The advantage of using an @ref Ecore_Fd_Handler is that you can monitor a
+ * file descriptor, while still iterating on the Ecore main loop. It will allow
+ * you to have timers working and expiring, events still being processed when
+ * received, idlers doing its work when there's nothing happening, and whenever
+ * there's something to be read from the file descriptor, your callback will be
+ * called. And it's everything monitored in the same main loop, no threads are
+ * needed, thus reducing the complexity of the program and any overhead caused
+ * by the use of threads.
+ *
+ * Now let's start our program. First we just declare a context structure that
+ * will be passed to our callback, with pointers to our handler and to a timer
+ * that will be used later:
+ *
+ * @until };
+ *
+ * Then we will declare a prepare_callback that is called before any fd_handler
+ * set in the program, and before the main loop select function is called. Just
+ * use one if you really know that you need it. We are just putting it here to
+ * exemplify its usage:
+ *
+ * @until }
+ *
+ * Now, our fd handler. In its arguments, the @c data pointer will have any data
+ * passed to it when it was registered, and the @c handler pointer will contain
+ * the fd handler returned by the ecore_main_fd_handler_add() call. It can be
+ * used, for example, to retrieve which file descriptor triggered this callback,
+ * since it could be added to more than one file descriptor, or to check what
+ * tipe of activity there's in the file descriptor.
+ *
+ * The code is very simple: we first check if the type of activity was an error.
+ * It probably won't happen with the default input, but could be the case of a
+ * network socket detecting a disconnection. Next, we get the file descriptor
+ * from this handler (as said before, the callback could be added to more than
+ * one file descriptor), and read it since we know that it shouldn't block,
+ * because our fd handler told us that there's some activity on it. If the
+ * result of the read was 0 bytes, we know that it's an end of file (EOF), so we
+ * can finish reading the input. Otherwise we just print the content read from
+ * it:
+ *
+ * @until }
+ *
+ * Also notice that this callback returns @ref ECORE_CALLBACK_RENEW to keep
+ * being called, as almost all other Ecore callbacks, otherwise if it returns
+ * @ref ECORE_CALLBACK_CANCEL then the file handler would be deleted.
+ *
+ * Just to demonstrate that our program isn't blocking in the input read but
+ * still can process other Ecore events, we are going to setup an @ref
+ * Ecore_Timer. This is its callback:
+ *
+ * @until }
+ *
+ * Now in the main code we are going to initialize the library, and setup
+ * callbacks for the file descriptor, the prepare callback, and the timer:
+ *
+ * @until timer_add
+ *
+ * Notice that the use of ecore_main_fd_handler_add() specifies what kind of
+ * activity we are monitoring. In this case, we want to monitor for read (since
+ * it's the standard input) and for errors. This is done by the flags @ref
+ * ECORE_FD_READ and @ref ECORE_FD_ERROR. For the three callbacks we are also
+ * giving a pointer to our context structure, which has pointers to the handlers
+ * added.
+ *
+ * Then we can start the main loop and see everything happening:
+ *
+ * @until }
+ *
+ * In the end we are just deleting the fd handler and the timer to demonstrate
+ * the API usage, since Ecore would already do it for us on its shutdown.
+ */
+
+/**
  * @example ecore_idler_example.c
  * This example shows when @ref Ecore_Idler, @ref Ecore_Idle_Enterer and @ref
  * Ecore_Idle_Exiter are called. See
  */
 
 /**
+ * @example ecore_fd_handler_example.c
+ * This example shows how to setup and use an fd_handler. See
+ * @ref ecore_fd_handler_example_c "the explanation here".
+ */
+
+/**
  * @example ecore_event_example.c
  * This example shows how to setup, change, and delete event handlers. See
  * @ref ecore_event_example_c "the explanation here".
index b1cb56a..76d0272 100644 (file)
@@ -12,6 +12,7 @@ LDADD = \
        @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @GLIB_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ @EFL_PTHREAD_LIBS@ @rt_libs@ -lm
 
 SRCS = \
+       ecore_fd_handler_example.c \
        ecore_event_example.c \
        ecore_idler_example.c \
        ecore_time_example.c \
@@ -34,6 +35,7 @@ endif
 
 if EFL_BUILD_EXAMPLES
 pkglib_PROGRAMS += \
+       ecore_fd_handler_example \
        ecore_event_example \
        ecore_idler_example \
        ecore_job_example \
diff --git a/legacy/ecore/src/examples/ecore_fd_handler_example.c b/legacy/ecore/src/examples/ecore_fd_handler_example.c
new file mode 100644 (file)
index 0000000..8f37e3a
--- /dev/null
@@ -0,0 +1,86 @@
+#include <Ecore.h>
+#include <unistd.h>
+
+struct context {
+     Ecore_Fd_Handler *handler;
+     Ecore_Timer *timer;
+};
+
+static void
+_fd_prepare_cb(void *data, Ecore_Fd_Handler *handler)
+{
+   printf("prepare_cb called.\n");
+}
+
+static Eina_Bool
+_fd_handler_cb(void *data, Ecore_Fd_Handler *handler)
+{
+   struct context *ctxt = data;
+   char buf[1024];
+   size_t nbytes;
+   int fd;
+
+   if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR))
+     {
+       printf("An error has occured. Stop watching this fd and quit.\n");
+       ecore_main_loop_quit();
+       ctxt->handler = NULL;
+       return ECORE_CALLBACK_CANCEL;
+     }
+
+   fd = ecore_main_fd_handler_fd_get(handler);
+   nbytes = read(fd, buf, sizeof(buf));
+   if (nbytes == 0)
+     {
+       printf("Nothing to read, exiting...\n");
+       ecore_main_loop_quit();
+       ctxt->handler = NULL;
+       return ECORE_CALLBACK_CANCEL;
+     }
+   buf[nbytes - 1] = '\0';
+
+   printf("Read %zd bytes from input: \"%s\"\n", nbytes - 1, buf);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_timer_cb(void *data)
+{
+   printf("Timer expired after 5 seconds...\n");
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+int main(int argc, char **argv)
+{
+   struct context ctxt = {0};
+
+   if (!ecore_init())
+     {
+       printf("ERROR: Cannot init Ecore!\n");
+       return -1;
+     }
+
+   ctxt.handler = ecore_main_fd_handler_add(STDIN_FILENO,
+                                           ECORE_FD_READ | ECORE_FD_ERROR,
+                                           _fd_handler_cb,
+                                           &ctxt, NULL, NULL);
+   ecore_main_fd_handler_prepare_callback_set(ctxt.handler, _fd_prepare_cb, &ctxt);
+   ctxt.timer = ecore_timer_add(5, _timer_cb, &ctxt);
+
+   printf("Starting the main loop. Type anything and hit <enter> to "
+         "activate the fd_handler callback, or CTRL+d to shutdown.\n");
+
+   ecore_main_loop_begin();
+
+   if (ctxt.handler)
+     ecore_main_fd_handler_del(ctxt.handler);
+
+   if (ctxt.timer)
+     ecore_timer_del(ctxt.timer);
+
+   ecore_shutdown();
+
+   return 0;
+}