blob: c0670107414340718e057e0f2bfc35add4627c86 [file] [log] [blame]
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +00001/* Copyright (C) 2004-2005 Constantin Kaplinsky. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18//
19// PollingManager.cxx
20//
21
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000022// FIXME: Don't compare pixels already marked as changed.
23// FIXME: Use Image::copyPixels() instead of Image::updateRect()?
24// In that case, note the fact that arguments are not checked.
25
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000026#include <stdio.h>
27#include <string.h>
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +000028#include <time.h>
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000029#include <X11/Xlib.h>
30#include <rfb/VNCServer.h>
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000031#include <rfb/Configuration.h>
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000032#include <rfb/ServerCore.h>
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000033
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000034#include <x0vncserver/PollingManager.h>
35
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000036BoolParameter PollingManager::pollPointer
37("PollPointer",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000038 "DEBUG: Poll area under the pointer with higher priority",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000039 true);
40
41IntParameter PollingManager::pollingType
42("PollingType",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000043 "DEBUG: Select particular polling algorithm (0..3)",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000044 3);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000045
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000046const int PollingManager::m_pollingOrder[32] = {
47 0, 16, 8, 24, 4, 20, 12, 28,
48 10, 26, 18, 2, 22, 6, 30, 14,
49 1, 17, 9, 25, 7, 23, 15, 31,
50 19, 3, 27, 11, 29, 13, 5, 21
51};
52
53//
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000054// Constructor.
55//
56// Note that dpy and image should remain valid during the object
57// lifetime, while factory is used only in the constructor itself.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000058//
59
60PollingManager::PollingManager(Display *dpy, Image *image,
61 ImageFactory *factory)
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000062 : m_dpy(dpy), m_server(0), m_image(image), m_pointerPosKnown(false),
63 m_pollingStep(0)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000064{
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000065 // Save width and height of the screen (and the image).
66 m_width = m_image->xim->width;
67 m_height = m_image->xim->height;
68
69 // Compute width and height in 32x32 tiles.
70 m_widthTiles = (m_width + 31) / 32;
71 m_heightTiles = (m_height + 31) / 32;
72
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000073 // Create additional images used in the polling algorithm.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000074 // FIXME: verify that these images use the same pixel format as in m_image.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000075 m_rowImage = factory->newImage(m_dpy, m_width, 1);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000076 m_tileImage = factory->newImage(m_dpy, 32, 32);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000077 m_areaImage = factory->newImage(m_dpy, 128, 128);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000078
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000079 // FIXME: Extend the comment.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000080 // Create a matrix with one byte per each 32x32 tile. It will be
81 // used to limit the rate of updates on continuously-changed screen
82 // areas (like video).
83 int numTiles = m_widthTiles * m_heightTiles;
84 m_statusMatrix = new char[numTiles];
85 memset(m_statusMatrix, 0, numTiles);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000086
87 // FIXME: Extend the comment.
88 // Create a matrix with one byte per each 32x32 tile. It will be
89 // used to limit the rate of updates on continuously-changed screen
90 // areas (like video).
91 m_rateMatrix = new char[numTiles];
92 m_videoFlags = new char[numTiles];
93 m_changedFlags = new char[numTiles];
94 memset(m_rateMatrix, 0, numTiles);
95 memset(m_videoFlags, 0, numTiles);
96 memset(m_changedFlags, 0, numTiles);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000097}
98
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000099PollingManager::~PollingManager()
100{
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000101 delete[] m_changedFlags;
102 delete[] m_videoFlags;
103 delete[] m_rateMatrix;
104
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000105 delete[] m_statusMatrix;
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000106
107 delete m_areaImage;
108 delete m_tileImage;
109 delete m_rowImage;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000110}
111
112//
113// Register VNCServer object.
114//
115
116void PollingManager::setVNCServer(VNCServer *s)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000117{
118 m_server = s;
119}
120
121//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000122// Update current pointer position which may be used as a hint for
123// polling algorithms.
124//
125
126void PollingManager::setPointerPos(const Point &pos)
127{
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000128 m_pointerPosTime = time(NULL);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000129 m_pointerPos = pos;
130 m_pointerPosKnown = true;
131}
132
133//
134// Indicate that current pointer position is unknown.
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000135//
136
137void PollingManager::unsetPointerPos()
138{
139 m_pointerPosKnown = false;
140}
141
142//
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000143// DEBUG: Measuring time spent in the poll() function,
144// as well as time intervals between poll() calls.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000145//
146
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000147#ifdef DEBUG
148void PollingManager::debugBeforePoll()
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000149{
Constantin Kaplinskyfbaab7f2006-02-16 04:51:38 +0000150 TimeMillis timeNow;
151 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000152 fprintf(stderr, "[wait%4dms]\t[step %2d]\t", diff, m_pollingStep % 32);
153 m_timeSaved = timeNow;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000154}
155
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000156void PollingManager::debugAfterPoll()
157{
Constantin Kaplinskyfbaab7f2006-02-16 04:51:38 +0000158 TimeMillis timeNow;
159 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000160 fprintf(stderr, "[poll%4dms]\n", diff);
161 m_timeSaved = timeNow;
162}
163
164#endif
165
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000166//
167// Search for changed rectangles on the screen.
168//
169
170void PollingManager::poll()
171{
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000172#ifdef DEBUG
173 debugBeforePoll();
174#endif
175
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000176 // First step: full-screen polling.
177
178 bool changes1 = false;
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000179
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000180 switch((int)pollingType) {
181 case 0:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000182 changes1 = poll_Dumb();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000183 break;
184 case 1:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000185 changes1 = poll_Traditional();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000186 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000187 case 2:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000188 changes1 = poll_SkipCycles();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000189 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000190//case 3:
191 default:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000192 changes1 = poll_DetectVideo();
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000193 break;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000194 }
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000195
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000196 // Second step: optional thorough polling of the area around the pointer.
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000197 // We do that only if the pointer position is known and was set recently.
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000198
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000199 bool changes2 = false;
200 if (pollPointer) {
201 if (m_pointerPosKnown && time(NULL) - m_pointerPosTime >= 5) {
202 unsetPointerPos();
203 }
204 if (m_pointerPosKnown) {
205 changes2 = pollPointerArea();
206 }
207 }
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000208
209 // Update if needed.
210
211 if (changes1 || changes2)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000212 m_server->tryUpdate();
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000213
214#ifdef DEBUG
215 debugAfterPoll();
216#endif
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000217}
218
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000219bool PollingManager::poll_DetectVideo()
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000220{
221 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000222 return false;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000223
224 const int GRAND_STEP_DIVISOR = 8;
225 const int VIDEO_THRESHOLD_0 = 3;
226 const int VIDEO_THRESHOLD_1 = 5;
227
228 bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
229
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000230 // FIXME: Save shortcuts in member variables?
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000231 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
232 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
233 int bytesPerLine = m_image->xim->bytes_per_line;
234
235 Rect rect;
236 int nTilesChanged = 0;
237 int idx = 0;
238
239 for (int y = 0; y * 32 < m_height; y++) {
240 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
241 if (scanLine >= tile_h)
242 break;
243 int scan_y = y * 32 + scanLine;
244 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
245 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
246 char *ptr_new = m_rowImage->xim->data;
247 for (int x = 0; x * 32 < m_width; x++) {
248 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
249 int nBytes = tile_w * bytesPerPixel;
250
251 char wasChanged = (memcmp(ptr_old, ptr_new, nBytes) != 0);
252 m_rateMatrix[idx] += wasChanged;
253
254 if (grandStep) {
255 if (m_rateMatrix[idx] <= VIDEO_THRESHOLD_0) {
256 m_videoFlags[idx] = 0;
257 } else if (m_rateMatrix[idx] >= VIDEO_THRESHOLD_1) {
258 m_videoFlags[idx] = 1;
259 }
260 m_rateMatrix[idx] = 0;
261 }
262
263 m_changedFlags[idx] |= wasChanged;
264 if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
265 if (tile_w == 32 && tile_h == 32) {
266 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
267 } else {
268 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
269 tile_w, tile_h);
270 }
271 m_image->updateRect(m_tileImage, x * 32, y * 32);
272 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
273 m_server->add_changed(rect);
274 nTilesChanged++;
275 m_changedFlags[idx] = 0;
276 }
277
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000278 ptr_old += nBytes;
279 ptr_new += nBytes;
280 idx++;
281 }
282 }
283
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000284 if (grandStep)
285 adjustVideoArea();
286
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000287 return (nTilesChanged != 0);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000288}
289
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000290bool PollingManager::poll_SkipCycles()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000291{
292 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000293 return false;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000294
295 enum {
296 NOT_CHANGED, CHANGED_ONCE, CHANGED_AGAIN
297 };
298
299 bool grandStep = (m_pollingStep % 8 == 0);
300
301 int nTilesChanged = 0;
302 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
303 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
304 int bytesPerLine = m_image->xim->bytes_per_line;
305 char *pstatus = m_statusMatrix;
306 bool wasChanged;
307 Rect rect;
308
309 for (int y = 0; y * 32 < m_height; y++) {
310 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
311 if (scanLine >= tile_h)
312 scanLine %= tile_h;
313 int scan_y = y * 32 + scanLine;
314 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
315 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
316 char *ptr_new = m_rowImage->xim->data;
317 for (int x = 0; x * 32 < m_width; x++) {
318 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
319 int nBytes = tile_w * bytesPerPixel;
320
321 if (grandStep || *pstatus != CHANGED_AGAIN) {
322 wasChanged = (*pstatus == CHANGED_AGAIN) ?
323 true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
324 if (wasChanged) {
325 if (grandStep || *pstatus == NOT_CHANGED) {
326 if (tile_w == 32 && tile_h == 32) {
327 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
328 } else {
329 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
330 tile_w, tile_h);
331 }
332 m_image->updateRect(m_tileImage, x * 32, y * 32);
333 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
334 m_server->add_changed(rect);
335 nTilesChanged++;
336 *pstatus = CHANGED_ONCE;
337 } else {
338 *pstatus = CHANGED_AGAIN;
339 }
340 } else if (grandStep) {
341 *pstatus = NOT_CHANGED;
342 }
343 }
344
345 ptr_old += nBytes;
346 ptr_new += nBytes;
347 pstatus++;
348 }
349 }
350
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000351 return (nTilesChanged != 0);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000352}
353
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000354bool PollingManager::poll_Traditional()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000355{
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000356 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000357 return false;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000358
359 int nTilesChanged = 0;
360 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
361 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
362 int bytesPerLine = m_image->xim->bytes_per_line;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000363 Rect rect;
364
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000365 for (int y = 0; y * 32 < m_height; y++) {
366 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000367 if (scanLine >= tile_h)
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000368 break;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000369 int scan_y = y * 32 + scanLine;
370 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
371 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
372 char *ptr_new = m_rowImage->xim->data;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000373 for (int x = 0; x * 32 < m_width; x++) {
374 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000375 int nBytes = tile_w * bytesPerPixel;
376 if (memcmp(ptr_old, ptr_new, nBytes)) {
377 if (tile_w == 32 && tile_h == 32) {
378 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
379 } else {
380 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
381 tile_w, tile_h);
382 }
383 m_image->updateRect(m_tileImage, x * 32, y * 32);
384 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
385 m_server->add_changed(rect);
386 nTilesChanged++;
387 }
388 ptr_old += nBytes;
389 ptr_new += nBytes;
390 }
391 }
392
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000393 return (nTilesChanged != 0);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000394}
395
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000396//
397// Simplest polling method, from the original x0vncserver of VNC4.
398//
399
400bool PollingManager::poll_Dumb()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000401{
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000402 if (!m_server)
403 return false;
404
405 m_image->get(DefaultRootWindow(m_dpy));
406 Rect rect(0, 0, m_width, m_height);
407 m_server->add_changed(rect);
408
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000409 // Report that some changes have been detected.
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000410 return true;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000411}
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000412
413//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000414// Compute coordinates of the rectangle around the pointer.
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000415//
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000416// ASSUMES: (m_pointerPosKnown != false)
417//
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000418
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000419void PollingManager::computePointerArea(Rect *r)
420{
421 int x = m_pointerPos.x - 64;
422 int y = m_pointerPos.y - 64;
423 int w = 128;
424 int h = 128;
425 if (x < 0) {
426 w += x; x = 0;
427 }
428 if (x + w > m_width) {
429 w = m_width - x;
430 }
431 if (y < 0) {
432 h += y; y = 0;
433 }
434 if (y + h > m_height) {
435 h = m_height - y;
436 }
437
438 r->setXYWH(x, y, w, h);
439}
440
441//
442// Poll the area under current pointer position. Each pixel of the
443// area should be compared. Using such polling option gives higher
444// priority to screen area under the pointer.
445//
446// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
447//
448
449bool PollingManager::pollPointerArea()
450{
451 Rect r;
452 computePointerArea(&r);
453
454 // Shortcuts for coordinates.
455 int x = r.tl.x, y = r.tl.y;
456 int w = r.width(), h = r.height();
457
458 // Get new pixels.
459 if (w == 128 && h == 128) {
460 m_areaImage->get(DefaultRootWindow(m_dpy), x, y);
461 } else {
462 m_areaImage->get(DefaultRootWindow(m_dpy), x, y, w, h);
463 }
464
465 // Now, try to minimize the rectangle by cutting out unchanged
466 // borders (at top and bottom).
467 //
468 // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
469 // to produce a region instead of a rectangle. If there would
470 // be just one universal polling algorithm, it could be
471 // better to integrate pointer area polling into that
472 // algorithm, instead of a separate pollPointerArea()
473 // function.
474
475 // Shortcuts.
476 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
477 int oldBytesPerLine = m_image->xim->bytes_per_line;
478 int newBytesPerLine = m_areaImage->xim->bytes_per_line;
479 char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
480 char *newPtr = m_areaImage->xim->data;
481
482 // Check and cut out unchanged rows at the top.
483 int ty;
484 for (ty = 0; ty < h; ty++) {
485 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
486 break;
487 oldPtr += oldBytesPerLine;
488 newPtr += newBytesPerLine;
489 }
490 if (ty == h) {
491 return false; // no changes at all
492 }
493 y += ty; h -= ty;
494
495 // Check and cut out unchanged rows at the bottom.
496 oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
497 newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
498 int by;
499 for (by = 0; by < h - 1; by++) {
500 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
501 break;
502 oldPtr -= oldBytesPerLine;
503 newPtr -= newBytesPerLine;
504 }
505 h -= by;
506
507 // Copy pixels.
508 m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
509
510 // Report updates to the server.
511 Rect rect(x, y, x+w, y+h);
512 m_server->add_changed(rect);
513 return true;
514}
515
516//
517// Make video area pattern more regular.
518//
519// FIXME: Replace the above with a normal comment.
520// FIXME: Is the function efficient enough?
521//
522
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000523void PollingManager::adjustVideoArea()
524{
525 char newFlags[m_widthTiles * m_heightTiles];
526 char *ptr = newFlags;
527 int x, y;
528
529 // DEBUG:
530 // int nVideoTiles = 0;
531
532 for (y = 0; y < m_heightTiles; y++) {
533 for (x = 0; x < m_widthTiles; x++) {
534
535 // DEBUG:
536 // nVideoTiles += m_videoFlags[y * m_widthTiles + x];
537
538 int weightedSum = 0, n;
539 if (y > 0 && x > 0) {
540 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
541 m_videoFlags[(y-1) * m_widthTiles + (x-1)] +
542 m_videoFlags[(y-1) * m_widthTiles + x ]);
543 if (n == 3) {
544 *ptr++ = 1;
545 continue;
546 }
547 weightedSum += n;
548 }
549 if (y > 0 && x < m_widthTiles - 1) {
550 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
551 m_videoFlags[(y-1) * m_widthTiles + (x+1)] +
552 m_videoFlags[(y-1) * m_widthTiles + x ]);
553 if (n == 3) {
554 *ptr++ = 1;
555 continue;
556 }
557 weightedSum += n;
558 }
559 if (y < m_heightTiles - 1 && x > 0) {
560 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
561 m_videoFlags[(y+1) * m_widthTiles + (x-1)] +
562 m_videoFlags[(y+1) * m_widthTiles + x ]);
563 if (n == 3) {
564 *ptr++ = 1;
565 continue;
566 }
567 weightedSum += n;
568 }
569 if (y < m_heightTiles - 1 && x < m_widthTiles - 1) {
570 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
571 m_videoFlags[(y+1) * m_widthTiles + (x+1)] +
572 m_videoFlags[(y+1) * m_widthTiles + x ]);
573 if (n == 3) {
574 *ptr++ = 1;
575 continue;
576 }
577 weightedSum += n;
578 }
579 *ptr++ = (weightedSum <= 3) ? 0 : m_videoFlags[y * m_widthTiles + x];
580 }
581 }
582
583 /*
584 /// DEBUG: ------------------------------------------------------
585 if (nVideoTiles) {
586 for (y = 0; y < m_heightTiles; y++) {
587 for (x = 0; x < m_widthTiles; x++) {
588 printf("%c", m_videoFlags[y * m_widthTiles + x] ? '@' : ':');
589 }
590 printf(" ");
591 for (x = 0; x < m_widthTiles; x++) {
592 printf("%c", newFlags[y * m_widthTiles + x] ? '@' : ':');
593 }
594 printf("\n");
595 }
596 printf("\n");
597 }
598 /// -------------------------------------------------------------
599 */
600
601 memcpy(m_videoFlags, newFlags, m_widthTiles * m_heightTiles);
602}