00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "RenderThread.h"
00020 #include <sys/time.h>
00021 #include <time.h>
00022 #include <errno.h>
00023 #include "controller.h"
00024 #include "PDFViewerLog.h"
00025 #include <unistd.h>
00026 #include <gdk/gdkx.h>
00027
00028 CRenderThread::CRenderThread(void)
00029 : bRunning(gFalse)
00030 {
00031 initialize();
00032 }
00033
00034 CRenderThread::~CRenderThread(void)
00035 {
00036 destroy();
00037 }
00038
00039 CRenderThread::threadState CRenderThread::abortState = Initialized;
00040
00041 void CRenderThread::initialize()
00042 {
00043 pthread_mutex_init(&mutex, NULL);
00044 pthread_cond_init(&cond, NULL);
00045 pthread_mutex_init(&abort, NULL);
00046 renderingPage = NULL;
00047 }
00048
00049 void CRenderThread::destroy()
00050 {
00051 pthread_mutex_destroy(&mutex);
00052 pthread_cond_destroy(&cond);
00053 pthread_mutex_destroy(&abort);
00054 }
00055
00056 GBool CRenderThread::abortCheckFunc(void *data)
00057 {
00058 if (abortState == ToAbort)
00059 {
00060
00061 return gTrue;
00062 }
00063 return gFalse;
00064
00065 }
00066
00067 extern void OnTerminated(int sig);
00068 static void installThreadTermHandler()
00069 {
00070
00071 struct sigaction on_term;
00072 memset(&on_term, 0x00, sizeof(on_term));
00073 on_term.sa_handler = OnTerminated;
00074 sigaction(SIGTERM, &on_term, NULL);
00075 }
00076
00077 void CRenderThread::start(ThreadParam * p)
00078 {
00079 if (bRunning)
00080 {
00081 PV_ERRORPRINTF("Thread already running!");
00082 return;
00083 }
00084 param = p;
00085 param->bQuit = gFalse;
00086 param->thread = this;
00087 renderingPage = NULL;
00088 abortState = Initialized;
00089 if (pthread_create(&thread, NULL, threadProc, p) != 0)
00090 {
00091 PV_ERRORPRINTF("Could not create thread!");
00092 return;
00093 }
00094 PV_LOGPRINTF("Create render thread done!");
00095 bRunning = gTrue;
00096 }
00097
00098 void CRenderThread::stop()
00099 {
00100 if (!bRunning) return;
00101
00102 abortState = Initialized;
00103 param->bQuit = gTrue;
00104 pthread_mutex_lock(&mutex);
00105 pthread_cond_signal(&cond);
00106 pthread_mutex_unlock(&mutex);
00107 pthread_join(thread, NULL);
00108 bRunning = gFalse;
00109 renderingPage = NULL;
00110 }
00111
00112 void CRenderThread::clearTodoList()
00113 {
00114 param->todoList->clear();
00115 }
00116
00117 void CRenderThread::addTodoItem(TodoItem * item, GBool bHead)
00118 {
00119 param->todoList->pushItem(item, bHead);
00120 }
00121
00122 void CRenderThread::signal()
00123 {
00124 pthread_mutex_lock(&mutex);
00125 pthread_cond_signal(&cond);
00126 pthread_mutex_unlock(&mutex);
00127 }
00128
00129 void CRenderThread::adjustPageList(const int current)
00130 {
00131
00132
00133
00134 static const int MEM = 1024 * 1024 * 15;
00135
00136 {
00137 char * p = (char *)malloc(MEM);
00138 if (p)
00139 {
00140
00141 free(p);
00142 return;
00143 }
00144 else
00145 {
00146
00147 for(int i = 0; i < RemovePages; ++i)
00148 {
00149 param->pageList->removeOldestOne(current);
00150 }
00151 }
00152 }
00153 }
00154
00155 void CRenderThread::renderPageNow(TodoItem * item)
00156 {
00157
00158 pthread_mutex_lock(&abort);
00159 if (abortState == Rendering &&
00160 renderingPage &&
00161 renderingPage->isSame(item->pageNumber, item->zoom, item->rotate))
00162 {
00163 PV_LOGPRINTF("Page %d is in rendering!", item->pageNumber);
00164 delete item;
00165 pthread_mutex_unlock(&abort);
00166 return;
00167 }
00168
00169 if (abortState == Rendering)
00170 {
00171 abortState = ToAbort;
00172 }
00173 param->todoList->pushItem(item, gTrue);
00174 signal();
00175 pthread_mutex_unlock(&abort);
00176 }
00177
00178 GBool CRenderThread::isInRendering(TodoItem * item)
00179 {
00180 pthread_mutex_lock(&abort);
00181 if (abortState == Rendering &&
00182 renderingPage &&
00183 renderingPage->isSame(item->pageNumber, item->zoom, item->rotate))
00184 {
00185 pthread_mutex_unlock(&abort);
00186 return gTrue;
00187 }
00188 pthread_mutex_unlock(&abort);
00189 return gFalse;
00190 }
00191
00192
00193
00194
00195 static void postEvent(ThreadParam * param, CPageInfo *page)
00196 {
00197 XKeyEvent xev;
00198 xev.type = KeyPress;
00199 xev.display = param->ctrl->gtkMgr.display;
00200 xev.root = RootWindow(param->ctrl->gtkMgr.display, param->ctrl->gtkMgr.screenNum);
00201 xev.window = GDK_WINDOW_XWINDOW(param->ctrl->gtkMgr.window->window);
00202 xev.subwindow = None;
00203 xev.time = 0;
00204 xev.x = page->pageNumber;
00205 xev.y = 1;
00206 xev.x_root = -1;
00207 xev.y_root = -1;
00208 xev.same_screen = 1;
00209 xev.state = page->pageNumber;
00210 xev.keycode = page->pageNumber;
00211 XSendEvent(param->ctrl->gtkMgr.display,
00212 GDK_WINDOW_XWINDOW(param->ctrl->gtkMgr.window->window), 1, KeyPressMask, (XEvent *)&xev);
00213 XFlush(xev.display);
00214 }
00215
00217
00218
00219
00220
00221
00222
00223
00224
00225 void * CRenderThread::threadProc(void * pvoid)
00226 {
00227
00228 installThreadTermHandler();
00229
00230
00231
00232 ThreadParam * param = (ThreadParam *)pvoid;
00233
00234
00235 for(;;)
00236 {
00237 if (param->bQuit)
00238 {
00239 PV_LOGPRINTF("Quit from thread!");
00240 return NULL;
00241 }
00242
00243
00244 TodoItem *pItem = param->todoList->popItem();
00245 if (NULL == pItem)
00246 {
00247 pthread_mutex_lock(¶m->thread->mutex);
00248 PV_LOGPRINTF("Waiting...");
00249 pthread_cond_wait(¶m->thread->cond, ¶m->thread->mutex);
00250 pthread_mutex_unlock(¶m->thread->mutex);
00251 continue;
00252 }
00253
00254
00255 CPageInfo * page = param->pageList->checkPage(pItem);
00256 if (page)
00257 {
00258 delete pItem;
00259 continue;
00260 }
00261
00262
00263 param->thread->adjustPageList(param->ctrl->settings.getCurrentPage());
00264
00265
00266 page = new CPageInfo;
00267 page->pageNumber = pItem->pageNumber;
00268 page->pageZoom = pItem->zoom;
00269 page->rotate = pItem->rotate;
00270 page->timestamp = pItem->timeStamp;
00271 delete pItem;
00272
00273
00274 pthread_mutex_lock(¶m->thread->abort);
00275 param->thread->renderingPage = page;
00276 param->thread->abortState = Rendering;
00277 pthread_mutex_unlock(¶m->thread->abort);
00278
00279
00280 RenderRet ret = param->ctrl->core->renderPage(*page,
00281 gFalse, gTrue, gTrue, abortCheckFunc, NULL);
00282
00283
00284 pthread_mutex_lock(¶m->thread->abort);
00285 param->thread->renderingPage = NULL;
00286 param->thread->abortState = RenderFinished;
00287 pthread_mutex_unlock(¶m->thread->abort);
00288
00289
00290 if (ret != Render_Done)
00291 {
00292 if (ret == Render_Abort)
00293 {
00294 PV_LOGPRINTF("Page %d is aborted!", page->pageNumber);
00295 }
00296 delete page;
00297 continue;
00298 }
00299
00300
00301 param->pageList->addPage(page);
00302
00303
00304 postEvent(param, page);
00305 }
00306 return NULL;
00307 }