multi_thread_test.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: multi_thread_test.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-plaintext.
00007  *
00008  * uds-plugin-plaintext is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * uds-plugin-plaintext is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 #include <stdio.h>
00028 #include <glib.h>
00029 #include <gtk/gtk.h>
00030 #include <gdk/gdkkeysyms.h>
00031 
00032 #include "text_config.h"
00033 #include "text_model.h"
00034 #include "text_view.h"
00035 
00036 using namespace text;
00037 
00038 // Global variables.
00039 GdkPixbuf *pix_buf = NULL;
00040 GtkWidget *top_level_window = NULL;
00041 
00042 static int page_index = 0;
00043 static int total_pages = 0;
00044 
00045 struct RenderData
00046 {
00047     RenderData(const PluginBitmapAttributes& _ba, const Position& _pos)
00048     : ba(_ba), pos(_pos)
00049     {
00050     }
00051 
00052 public:
00053     PluginBitmapAttributes ba;
00054     Position pos;
00055 };
00056 
00057 struct SearchResult
00058 {
00059     int    matches;
00060     Range* ranges;
00061 };
00062 
00063 struct Event
00064 {
00065 public:
00066     Event()
00067     {
00068     }
00069     Event(TextEvent e, void *_data)
00070     : event(e), data(_data)
00071     {
00072     }
00073 
00074 public:
00075     TextEvent event;
00076     void      *data;
00077 };
00078 
00079 class EventQueue
00080 {
00081 public:
00082     EventQueue()
00083     {
00084         mutex = g_mutex_new();
00085     }
00086     ~EventQueue()
00087     {
00088         g_mutex_free(mutex);
00089     }
00090 
00091     void append_event(const Event& ev)
00092     {
00093         g_mutex_lock(mutex);
00094         event_queue.push_back(ev);
00095         g_mutex_unlock(mutex);
00096     }
00097 
00098     bool get_event(Event& ev)
00099     {
00100         bool ret = false;
00101         g_mutex_lock(mutex);
00102         if (!event_queue.empty())
00103         {
00104             ev = event_queue.front();
00105             event_queue.pop_front();
00106             ret = true;
00107         }
00108         g_mutex_unlock(mutex);
00109         return ret;
00110     }
00111 
00112 private:
00113     std::list<Event> event_queue;
00114     GMutex* mutex;
00115 };
00116 
00117 class EventHandler
00118 {
00119 public:
00120     EventHandler(EventQueue *_eq)
00121     : eq(_eq)
00122     {
00123     }
00124     ~EventHandler()
00125     {
00126     }
00127 public:
00128     void handle_paginate_start(unsigned int page_count)
00129     {
00130         Event e(PAGINATE_STARTED, (void *)1);
00131         eq->append_event(e);
00132     }
00133 
00134     void handle_paginate_end(unsigned int page_count)
00135     {
00136         Event e(PAGINATE_ENDED, (void *)page_count);
00137         eq->append_event(e);
00138     }
00139 
00140     void handle_render_done(const PluginBitmapAttributes& ba, const Position& start_pos)
00141     {
00142         RenderData *rd = new RenderData(ba, start_pos);
00143         Event e(RENDER_DONE, (void *)rd);
00144         eq->append_event(e);
00145     }
00146 
00147     void handle_search_done(const std::vector<Range>& result_ranges, const SearchContext& search_context)
00148     {
00149         SearchResult *p = new SearchResult;
00150         p->matches = result_ranges.size();
00151         p->ranges  = new Range[p->matches];
00152 
00153         for (unsigned int i=0; i<result_ranges.size(); i++)
00154         {
00155             p->ranges[i] = result_ranges[i];
00156         }
00157 
00158         Event e(SEARCH_DONE, (void *)p);
00159         eq->append_event(e);
00160     }
00161 
00162 private:
00163     EventQueue *eq;
00164 };
00165 
00166 void fill_pix_buf(const unsigned char *bmp, const int width, const int height)
00167 {
00168     if (pix_buf != NULL)
00169     {
00170         g_object_unref(pix_buf);
00171         pix_buf = NULL;
00172     }
00173 
00174     pix_buf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
00175         FALSE,
00176         8,
00177         width,
00178         height);
00179 
00180     guchar *pixels = gdk_pixbuf_get_pixels(pix_buf);
00181     int rowstride = gdk_pixbuf_get_rowstride(pix_buf);
00182     int channels = gdk_pixbuf_get_n_channels(pix_buf);
00183 
00184     guchar *p = NULL;
00185     for (int y=0; y<height; y++)
00186     {
00187         for (int x=0; x<width; x++)
00188         {
00189             p = pixels + y*rowstride + x*channels;
00190             p[0] = p[1] = p[2] = bmp[y*width+x];
00191         }
00192     }
00193 }
00194 
00195 void handle_event(const Event& ev)
00196 {
00197     const unsigned char *bmp = 0;
00198     RenderData *rd = 0;
00199     Position pos;
00200     SearchResult *sr = 0;
00201 
00202     switch (ev.event)
00203     {
00204     case PAGINATE_STARTED:
00205         printf("Pagination starts...\n");
00206         break;
00207 
00208     case PAGINATE_ENDED:
00209         total_pages = (unsigned int)ev.data;
00210         printf("Pagination end, total_pages = %d.\n", total_pages);
00211         break;
00212 
00213     case RENDER_DONE:
00214         rd = (RenderData *)ev.data;
00215         pos = rd->pos;
00216         bmp = rd->ba.data;
00217         fill_pix_buf(bmp, rd->ba.width, rd->ba.height);
00218         delete[] bmp;
00219         delete rd;
00220         rd = 0;
00221         printf("Render done for pos (%d, %d).\n", pos.paragraph, pos.offset);
00222         gdk_window_invalidate_rect(top_level_window->window, NULL, TRUE);
00223         break;
00224 
00225     case SEARCH_DONE:
00226         printf("Search done.\n");
00227         sr = (SearchResult *)ev.data;
00228         for (int i=0; i<sr->matches; i++)
00229         {
00230             printf("Match %3d: (%d, %d)~(%d, %d)\n",
00231                 i+1,
00232                 sr->ranges[i].start.paragraph,
00233                 sr->ranges[i].start.offset,
00234                 sr->ranges[i].end.paragraph,
00235                 sr->ranges[i].end.offset);
00236         }
00237         delete[] sr->ranges;
00238         delete sr;
00239         break;
00240 
00241     default:
00242         break;
00243     }
00244 }
00245 
00246 static gboolean widget_event_handler(GtkWidget *widget, GdkEvent *event, gpointer user_data)
00247 {
00248     guint key_code;
00249     TextController *ctrl = (TextController *)user_data;
00250 
00251     switch (event->type)
00252     {
00253         case GDK_KEY_PRESS:
00254             key_code = ((GdkEventKey*)event)->keyval;
00255             if (key_code == GDK_Page_Up)
00256             {
00257                 if (page_index == 0)
00258                 {
00259                     return FALSE;
00260                 }
00261                 --page_index;
00262             }
00263             else if (key_code == GDK_Page_Down)
00264             {
00265                 if (page_index == total_pages-1)
00266                 {
00267                     return FALSE;
00268                 }
00269                 ++page_index;
00270             }
00271             ctrl->render(page_index);
00272             break;
00273 
00274         default:
00275             break;
00276     }
00277 
00278     return TRUE;
00279 }
00280 gboolean timeout_handler(gpointer data)
00281 {
00282     Event ev;
00283     EventQueue *eq = (EventQueue *)data;
00284     while (eq->get_event(ev))
00285     {
00286         handle_event(ev);
00287     }
00288     
00289     return TRUE;
00290 }
00291 
00292 static gboolean my_expose(GtkWidget *da, GdkEventExpose *event, gpointer data)
00293 {
00294     GdkGC *gc = gdk_gc_new(da->window);
00295     GdkPixbuf** pix_buf = (GdkPixbuf**)data;
00296     if (*pix_buf != NULL)
00297     {
00298         gdk_draw_pixbuf(da->window,
00299             gc,
00300             *pix_buf,
00301             0,
00302             0,
00303             0,
00304             0,
00305             -1,
00306             -1,
00307             GDK_RGB_DITHER_NORMAL,
00308             0,
00309             0);
00310     }
00311 
00312     return TRUE;
00313 }
00314 
00315 static void destroy(GtkWidget *widget, gpointer data)
00316 {
00317     gtk_main_quit ();
00318 }
00319 
00320 int main(int argc, char* argv[])
00321 {
00322     gtk_init(&argc, &argv);
00323 
00324     if (argc != 2)
00325     {
00326         fprintf(stderr, "Usage: %s <file_name>.\n", argv[0]);
00327         return -1;
00328     }
00329 
00330     // Read content from disk file.
00331     TextModel model(argv[1]);
00332     model.open();
00333 
00334     // Create view and controller.
00335     TextView view(&model);
00336     g_thread_init(NULL);
00337     TextController ctrl(&model, &view);
00338 
00339     // Add signal handler.
00340     EventQueue eq;
00341     EventHandler event_handler(&eq);
00342     model.search_done_signal.add_slot<EventHandler>(&event_handler, &EventHandler::handle_search_done);
00343     view.pagination_start_signal.add_slot<EventHandler>(&event_handler, &EventHandler::handle_paginate_start);
00344     view.pagination_end_signal.add_slot<EventHandler>(&event_handler, &EventHandler::handle_paginate_end);
00345     view.render_done_signal.add_slot<EventHandler>(&event_handler, &EventHandler::handle_render_done);
00346 
00347     // GTK stuff
00348     top_level_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00349     gtk_widget_set_size_request(top_level_window, DEFAULT_SURFACE_WIDTH, DEFAULT_SURFACE_HEIGHT);
00350 
00351     // Register signal handler
00352     g_signal_connect(G_OBJECT(top_level_window), "destroy", G_CALLBACK(destroy), NULL);
00353     g_signal_connect(G_OBJECT(top_level_window), "expose_event", G_CALLBACK(my_expose), &pix_buf);
00354     gtk_signal_connect(GTK_OBJECT(top_level_window), "key_press_event", GTK_SIGNAL_FUNC(widget_event_handler), &ctrl);
00355     g_timeout_add(10, timeout_handler, &eq);
00356 
00357     // Show all widget
00358     gtk_widget_show_all(top_level_window);
00359 
00360     // Render page 0
00361     ctrl.render(page_index);
00362     ctrl.search(SearchContext(SEARCH_ALL, Position(0, 0), "render", true, true, false));
00363     gtk_main();
00364 
00365     g_object_unref(pix_buf);
00366     return 0;
00367 }
00368 
Generated by  doxygen 1.6.2-20100208