00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <cstring>
00028 #include <set>
00029
00030 #include "notepad_ipc.h"
00031 #include "notepad_utils.h"
00032 #include "notepad_display_sched.h"
00033 #include "notepad_doc.h"
00034 #include "notepad_commandqueue.h"
00035 #include "notepad_pages.h"
00036 #include "log.h"
00037
00038 namespace notepad
00039 {
00040
00041
00042 class renderCommand : public Command
00043 {
00044 public:
00045 renderCommand(CNotepadPages* pages, RenderPageCtx* aCtx) {the_pages = pages; params = aCtx; };
00046 bool execute() { bool r = the_pages->execRenderPage(params); LOGPRINTF(); delete params; return r; };
00047
00048 private:
00049 CNotepadPages* the_pages;
00050 RenderPageCtx* params;
00051 };
00052
00053
00054
00055
00056 CNotepadPages::CNotepadPages()
00057 : doc(0)
00058 , gctx(0)
00059 , current_page(0)
00060 , drawsem(0)
00061 , pages_rw_sem(1)
00062 {
00063 LOGPRINTF("entry");
00064 for (gint i = 0; i < NPAGES; i++)
00065 {
00066 pages[i].image = 0;
00067 pages[i].pageno = 0;
00068 pages[i].dirty = TRUE;
00069 }
00070 LOGPRINTF("exit");
00071 }
00072
00073 CNotepadPages::~CNotepadPages()
00074 {
00075 stop();
00076 for (gint i = 0; i < NPAGES; i++)
00077 {
00078 if (pages[i].image != 0)
00079 {
00080 g_object_unref(G_OBJECT(pages[i].image) );
00081 pages[i].image = 0;
00082 }
00083 }
00084 }
00085
00086 void CNotepadPages::init(CNotepadDoc* aDoc, GCtx* aCtx, int aPage, GdkVisual* aVisual)
00087 {
00088 g_assert(aDoc != 0);
00089 g_assert(aCtx != 0);
00090 g_assert(aPage > 0);
00091 g_assert(aVisual!= 0);
00092
00093 visual = aVisual;
00094 doc = aDoc;
00095 gctx = aCtx;
00096 current_page = aPage;
00097
00098
00099
00100 cmd_queue.start();
00101 }
00102
00103 void CNotepadPages::stop()
00104 {
00105 cmd_queue.stop();
00106 }
00107
00108
00109
00110
00111
00112 gint CNotepadPages::find_page(const int pageno)
00113 {
00114 LOGPRINTF("entry %d", pageno);
00115
00116 g_assert(pageno > 0);
00117
00118
00119 for (gint i = 0; i < NPAGES; i++)
00120 {
00121 if (pages[i].pageno == pageno)
00122 {
00123 LOGPRINTF("exit, page %d(%d) i %d dirty %d", pages[i].pageno, pageno, i, pages[i].dirty);
00124 return i;
00125 }
00126 }
00127
00128 LOGPRINTF("exit, not found");
00129 return NOTFOUND;
00130 }
00131
00132 gint CNotepadPages::replace_page_at_index(gint index, int pageno)
00133 {
00134 LOGPRINTF("entry %d %d", index, pageno);
00135
00136 g_assert(pageno > 0);
00137 g_assert(index >= 0 && index < NPAGES);
00138
00139 GdkImage* image = pages[index].image;
00140
00141 if (image != 0)
00142 {
00143 g_object_unref(G_OBJECT(image));
00144 image = 0;
00145 }
00146
00147
00148 image = gdk_image_new(GDK_IMAGE_NORMAL, visual, gctx->width, gctx->height);
00149 LOGPRINTF("%p", image);
00150
00151
00152 g_assert(image != 0);
00153 memset(image->mem, 0xFF, image->bpl*image->height);
00154
00155 pages[index].image = image;
00156 pages[index].pageno = pageno;
00157 pages[index].dirty = TRUE;
00158
00159 LOGPRINTF("exit");
00160 return index;
00161 }
00162
00163 gint CNotepadPages::remove_from_cache(const gint index)
00164 {
00165
00166 LOGPRINTF("entry");
00167
00168 g_assert(index >= 0 && index < NPAGES);
00169
00170 if (pages[index].image != 0)
00171 {
00172 g_object_unref(G_OBJECT(pages[index].image) );
00173 pages[index].image = 0;
00174 }
00175 pages[index].pageno = 0;
00176 pages[index].dirty = TRUE;
00177
00178 LOGPRINTF("exit");
00179 return index;
00180 }
00181
00182 gint CNotepadPages::remove_page_from_cache(const int pageno)
00183 {
00184
00185 LOGPRINTF("entry");
00186
00187 g_assert(pageno > 0);
00188
00189 gint i = find_page(pageno);
00190 if (i != NOTFOUND)
00191 {
00192 i = remove_from_cache(i);
00193 }
00194
00195 LOGPRINTF("exit");
00196 return i;
00197 }
00198
00199 gint CNotepadPages::make_room(const int pageno)
00200 {
00201
00202
00203
00204
00205 LOGPRINTF("entry");
00206
00207 g_assert(pageno > 0);
00208
00209 gint ifarthest = 0;
00210 gint dfarthest = 0;
00211 gint i = 0;
00212
00213 for (i = 0; i < NPAGES; i++)
00214 {
00215 if (pages[i].pageno == 0)
00216 {
00217 LOGPRINTF("exit, found free at %d", i);
00218 return i;
00219 }
00220 else
00221 {
00222 gint dist = ABS(pages[i].pageno - pageno);
00223 if (dist > dfarthest)
00224 {
00225 dfarthest = dist;
00226 ifarthest = i;
00227 }
00228 }
00229 }
00230
00231
00232 i = remove_from_cache(ifarthest);
00233
00234 LOGPRINTF("exit, freed %d", ifarthest);
00235 return i;
00236 }
00237
00238
00239 void CNotepadPages::insert_page(const int pageno)
00240 {
00241
00242 LOGPRINTF("entry");
00243
00244 g_assert(pageno > 0);
00245
00246
00247 cmd_queue.flush();
00248
00249 pages_rw_sem.p();
00250
00251 gint ifree = make_room(pageno);
00252 g_assert(ifree >= 0 && ifree < NPAGES);
00253
00254 for (gint i = 0; i < NPAGES; i++)
00255 {
00256 if (pages[i].pageno >= pageno)
00257 {
00258
00259 pages[i].pageno++;
00260 }
00261 }
00262
00263 replace_page_at_index(ifree, pageno);
00264 pages_rw_sem.v();
00265
00266 LOGPRINTF("exit");
00267 }
00268
00269 void CNotepadPages::delete_page(const int pageno)
00270 {
00271
00272 LOGPRINTF("entry");
00273
00274 g_assert(pageno > 0);
00275
00276
00277 cmd_queue.flush();
00278
00279 pages_rw_sem.p();
00280
00281 gint i = find_page(pageno);
00282 if (i != NOTFOUND)
00283 {
00284 for (gint j = 0; j < NPAGES; j++)
00285 {
00286 if (pages[j].pageno > pageno)
00287 {
00288
00289 pages[j].pageno--;
00290 }
00291 }
00292 remove_from_cache(i);
00293 }
00294 pages_rw_sem.v();
00295
00296 LOGPRINTF("exit");
00297 }
00298
00299 void CNotepadPages::clear_page(const int pageno)
00300 {
00301
00302
00303 LOGPRINTF("entry");
00304
00305 g_assert(pageno > 0);
00306
00307 mark_dirty(pageno);
00308
00309 LOGPRINTF("exit");
00310 }
00311
00312 void CNotepadPages::mark_dirty(const int pageno)
00313 {
00314
00315 LOGPRINTF("entry");
00316
00317 g_assert(pageno > 0);
00318
00319 gint i = find_page(pageno);
00320 if (i != NOTFOUND)
00321 {
00322 pages[i].dirty = TRUE;
00323 }
00324
00325 LOGPRINTF("exit");
00326 }
00327
00328 void CNotepadPages::mark_all_dirty()
00329 {
00330
00331 LOGPRINTF("entry");
00332
00333 for (gint i = 0; i < NPAGES; i++)
00334 {
00335 pages[i].dirty = TRUE;
00336 }
00337
00338 LOGPRINTF("exit");
00339 }
00340
00341
00342
00343
00344 GdkImage* CNotepadPages::get_page(const int pageno)
00345 {
00346
00347 LOGPRINTF("entry %d", pageno);
00348
00349 g_assert(pageno > 0);
00350
00351 int i = find_page(pageno);
00352
00353
00354 if ((i == NOTFOUND) || (pageno != current_page) || pages[i].dirty)
00355 {
00356
00357 cmd_queue.flush();
00358
00359
00360 const int order[NPAGES] = {0, +1, +2, -1, +3, -2, +4, -3, +5, -4, -5};
00361
00362 for (gint j = 0; j < NPAGES; j++)
00363 {
00364 int relpage = pageno + order[j];
00365 if ( (relpage > 0) && (relpage <= doc->get_num_pages()) )
00366 {
00367 i = find_page(relpage);
00368 if ((i == NOTFOUND) || (pages[i].dirty))
00369 {
00370 LOGPRINTF("add to queue [%d] page %d", j, relpage);
00371 RenderPageCtx* params = new RenderPageCtx;
00372 memset(params, 0, sizeof params);
00373 params->pageno = relpage;
00374 params->isCurrent = (j == 0);
00375 renderCommand* rc = new renderCommand(this, params);
00376 cmd_queue.add(rc);
00377
00378 if (j == 0)
00379 {
00380 LOGPRINTF("waiting for semaphore");
00381 ipc_sys_busy(true);
00382 drawsem.p();
00383 LOGPRINTF("ready waiting for semaphore");
00384 }
00385 }
00386 }
00387 }
00388 }
00389
00390 i = find_page(pageno);
00391 g_assert(i >= 0 && i < NPAGES);
00392
00393
00394 current_page = pageno;
00395
00396 ipc_sys_busy(false);
00397
00398
00399 LOGPRINTF("exit");
00400 return pages[i].image;
00401 }
00402
00403
00404
00405
00406
00407 bool CNotepadPages::execRenderPage( RenderPageCtx* params )
00408 {
00409
00410 g_assert(params != 0);
00411
00412 bool redraw = false;
00413
00414 pages_rw_sem.p();
00415
00416
00417 int i = find_page(params->pageno);
00418 if (i == NOTFOUND)
00419 {
00420 i = make_room(params->pageno);
00421 LOGPRINTF("added page %d in %d", params->pageno, i);
00422 redraw = true;
00423 }
00424 else
00425 {
00426 redraw = pages[i].dirty;
00427 }
00428
00429 if (redraw)
00430 {
00431 LOGPRINTF("redraw page %d : %d c %d i %d", params->pageno, redraw, params->isCurrent, i);
00432
00433
00434 i = replace_page_at_index(i, params->pageno);
00435
00436
00437 g_assert(i >= 0 && i < NPAGES);
00438 g_assert(pages[i].image != 0);
00439 doc->draw_scribble_page(params->pageno, *gctx, pages[i].image);
00440 pages[i].dirty = FALSE;
00441 }
00442
00443 pages_rw_sem.v();
00444
00445 if (params->isCurrent)
00446 {
00447 LOGPRINTF("ready rendering current page");
00448 drawsem.v();
00449 }
00450
00451 LOGPRINTF("exit");
00452 return true;
00453 }
00454
00455 }
00456