blob: 0c972dd348cc1254a443f55af23f8763fbcaae55 [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 <sys/time.h>
30#include <X11/Xlib.h>
31#include <rfb/VNCServer.h>
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000032#include <rfb/Configuration.h>
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000033#include <rfb/ServerCore.h>
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000034
35#include <x0vncserver/Image.h>
36#include <x0vncserver/PollingManager.h>
37
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000038BoolParameter PollingManager::pollPointer
39("PollPointer",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000040 "DEBUG: Poll area under the pointer with higher priority",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000041 true);
42
43IntParameter PollingManager::pollingType
44("PollingType",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000045 "DEBUG: Select particular polling algorithm (0..3)",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000046 3);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000047
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000048const int PollingManager::m_pollingOrder[32] = {
49 0, 16, 8, 24, 4, 20, 12, 28,
50 10, 26, 18, 2, 22, 6, 30, 14,
51 1, 17, 9, 25, 7, 23, 15, 31,
52 19, 3, 27, 11, 29, 13, 5, 21
53};
54
55//
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000056// Constructor.
57//
58// Note that dpy and image should remain valid during the object
59// lifetime, while factory is used only in the constructor itself.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000060//
61
62PollingManager::PollingManager(Display *dpy, Image *image,
63 ImageFactory *factory)
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000064 : m_dpy(dpy), m_server(0), m_image(image), m_pointerPosKnown(false),
65 m_pollingStep(0)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000066{
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000067 // Save width and height of the screen (and the image).
68 m_width = m_image->xim->width;
69 m_height = m_image->xim->height;
70
71 // Compute width and height in 32x32 tiles.
72 m_widthTiles = (m_width + 31) / 32;
73 m_heightTiles = (m_height + 31) / 32;
74
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000075 // Create additional images used in the polling algorithm.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000076 // FIXME: verify that these images use the same pixel format as in m_image.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000077 m_rowImage = factory->newImage(m_dpy, m_width, 1);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000078 m_tileImage = factory->newImage(m_dpy, 32, 32);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000079 m_areaImage = factory->newImage(m_dpy, 128, 128);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000080
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000081 // FIXME: Extend the comment.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000082 // Create a matrix with one byte per each 32x32 tile. It will be
83 // used to limit the rate of updates on continuously-changed screen
84 // areas (like video).
85 int numTiles = m_widthTiles * m_heightTiles;
86 m_statusMatrix = new char[numTiles];
87 memset(m_statusMatrix, 0, numTiles);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000088
89 // FIXME: Extend the comment.
90 // Create a matrix with one byte per each 32x32 tile. It will be
91 // used to limit the rate of updates on continuously-changed screen
92 // areas (like video).
93 m_rateMatrix = new char[numTiles];
94 m_videoFlags = new char[numTiles];
95 m_changedFlags = new char[numTiles];
96 memset(m_rateMatrix, 0, numTiles);
97 memset(m_videoFlags, 0, numTiles);
98 memset(m_changedFlags, 0, numTiles);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000099}
100
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000101PollingManager::~PollingManager()
102{
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000103 delete[] m_changedFlags;
104 delete[] m_videoFlags;
105 delete[] m_rateMatrix;
106
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000107 delete[] m_statusMatrix;
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000108
109 delete m_areaImage;
110 delete m_tileImage;
111 delete m_rowImage;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000112}
113
114//
115// Register VNCServer object.
116//
117
118void PollingManager::setVNCServer(VNCServer *s)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000119{
120 m_server = s;
121}
122
123//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000124// Update current pointer position which may be used as a hint for
125// polling algorithms.
126//
127
128void PollingManager::setPointerPos(const Point &pos)
129{
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000130 m_pointerPosTime = time(NULL);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000131 m_pointerPos = pos;
132 m_pointerPosKnown = true;
133}
134
135//
136// Indicate that current pointer position is unknown.
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000137//
138
139void PollingManager::unsetPointerPos()
140{
141 m_pointerPosKnown = false;
142}
143
144//
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000145// DEBUG: a version of poll() measuring time spent in the function.
146//
147
148void PollingManager::pollDebug()
149{
150 struct timeval timeSaved, timeNow;
151 struct timezone tz;
152 timeSaved.tv_sec = 0;
153 timeSaved.tv_usec = 0;
154 gettimeofday(&timeSaved, &tz);
Constantin Kaplinsky6e34af42006-02-10 06:43:56 +0000155 int step = m_pollingStep;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000156
157 poll();
158
159 gettimeofday(&timeNow, &tz);
160 int diff = (int)((timeNow.tv_usec - timeSaved.tv_usec + 500) / 1000 +
161 (timeNow.tv_sec - timeSaved.tv_sec) * 1000);
162 if (diff != 0)
Constantin Kaplinsky6e34af42006-02-10 06:43:56 +0000163 fprintf(stderr, "DEBUG: poll(): %4d ms [step %2d]\n", diff, step % 32);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000164}
165
166//
167// Search for changed rectangles on the screen.
168//
169
170void PollingManager::poll()
171{
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000172 // First step: full-screen polling.
173
174 bool changes1 = false;
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000175
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000176 switch((int)pollingType) {
177 case 0:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000178 changes1 = poll_Dumb();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000179 break;
180 case 1:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000181 changes1 = poll_Traditional();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000182 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000183 case 2:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000184 changes1 = poll_SkipCycles();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000185 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000186//case 3:
187 default:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000188 changes1 = poll_DetectVideo();
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000189 break;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000190 }
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000191
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000192 // Second step: optional thorough polling of the area around the pointer.
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000193 // We do that only if the pointer position is known and was set recently.
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000194
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000195 bool changes2 = false;
196 if (pollPointer) {
197 if (m_pointerPosKnown && time(NULL) - m_pointerPosTime >= 5) {
198 unsetPointerPos();
199 }
200 if (m_pointerPosKnown) {
201 changes2 = pollPointerArea();
202 }
203 }
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000204
205 // Update if needed.
206
207 if (changes1 || changes2)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000208 m_server->tryUpdate();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000209}
210
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000211bool PollingManager::poll_DetectVideo()
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000212{
213 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000214 return false;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000215
216 const int GRAND_STEP_DIVISOR = 8;
217 const int VIDEO_THRESHOLD_0 = 3;
218 const int VIDEO_THRESHOLD_1 = 5;
219
220 bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
221
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000222 // FIXME: Save shortcuts in member variables?
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000223 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
224 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
225 int bytesPerLine = m_image->xim->bytes_per_line;
226
227 Rect rect;
228 int nTilesChanged = 0;
229 int idx = 0;
230
231 for (int y = 0; y * 32 < m_height; y++) {
232 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
233 if (scanLine >= tile_h)
234 break;
235 int scan_y = y * 32 + scanLine;
236 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
237 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
238 char *ptr_new = m_rowImage->xim->data;
239 for (int x = 0; x * 32 < m_width; x++) {
240 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
241 int nBytes = tile_w * bytesPerPixel;
242
243 char wasChanged = (memcmp(ptr_old, ptr_new, nBytes) != 0);
244 m_rateMatrix[idx] += wasChanged;
245
246 if (grandStep) {
247 if (m_rateMatrix[idx] <= VIDEO_THRESHOLD_0) {
248 m_videoFlags[idx] = 0;
249 } else if (m_rateMatrix[idx] >= VIDEO_THRESHOLD_1) {
250 m_videoFlags[idx] = 1;
251 }
252 m_rateMatrix[idx] = 0;
253 }
254
255 m_changedFlags[idx] |= wasChanged;
256 if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
257 if (tile_w == 32 && tile_h == 32) {
258 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
259 } else {
260 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
261 tile_w, tile_h);
262 }
263 m_image->updateRect(m_tileImage, x * 32, y * 32);
264 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
265 m_server->add_changed(rect);
266 nTilesChanged++;
267 m_changedFlags[idx] = 0;
268 }
269
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000270 ptr_old += nBytes;
271 ptr_new += nBytes;
272 idx++;
273 }
274 }
275
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000276 if (grandStep)
277 adjustVideoArea();
278
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000279 return (nTilesChanged != 0);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000280}
281
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000282bool PollingManager::poll_SkipCycles()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000283{
284 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000285 return false;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000286
287 enum {
288 NOT_CHANGED, CHANGED_ONCE, CHANGED_AGAIN
289 };
290
291 bool grandStep = (m_pollingStep % 8 == 0);
292
293 int nTilesChanged = 0;
294 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
295 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
296 int bytesPerLine = m_image->xim->bytes_per_line;
297 char *pstatus = m_statusMatrix;
298 bool wasChanged;
299 Rect rect;
300
301 for (int y = 0; y * 32 < m_height; y++) {
302 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
303 if (scanLine >= tile_h)
304 scanLine %= tile_h;
305 int scan_y = y * 32 + scanLine;
306 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
307 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
308 char *ptr_new = m_rowImage->xim->data;
309 for (int x = 0; x * 32 < m_width; x++) {
310 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
311 int nBytes = tile_w * bytesPerPixel;
312
313 if (grandStep || *pstatus != CHANGED_AGAIN) {
314 wasChanged = (*pstatus == CHANGED_AGAIN) ?
315 true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
316 if (wasChanged) {
317 if (grandStep || *pstatus == NOT_CHANGED) {
318 if (tile_w == 32 && tile_h == 32) {
319 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
320 } else {
321 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
322 tile_w, tile_h);
323 }
324 m_image->updateRect(m_tileImage, x * 32, y * 32);
325 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
326 m_server->add_changed(rect);
327 nTilesChanged++;
328 *pstatus = CHANGED_ONCE;
329 } else {
330 *pstatus = CHANGED_AGAIN;
331 }
332 } else if (grandStep) {
333 *pstatus = NOT_CHANGED;
334 }
335 }
336
337 ptr_old += nBytes;
338 ptr_new += nBytes;
339 pstatus++;
340 }
341 }
342
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000343 return (nTilesChanged != 0);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000344}
345
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000346bool PollingManager::poll_Traditional()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000347{
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000348 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000349 return false;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000350
351 int nTilesChanged = 0;
352 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
353 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
354 int bytesPerLine = m_image->xim->bytes_per_line;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000355 Rect rect;
356
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000357 for (int y = 0; y * 32 < m_height; y++) {
358 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000359 if (scanLine >= tile_h)
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000360 break;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000361 int scan_y = y * 32 + scanLine;
362 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
363 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
364 char *ptr_new = m_rowImage->xim->data;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000365 for (int x = 0; x * 32 < m_width; x++) {
366 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000367 int nBytes = tile_w * bytesPerPixel;
368 if (memcmp(ptr_old, ptr_new, nBytes)) {
369 if (tile_w == 32 && tile_h == 32) {
370 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
371 } else {
372 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
373 tile_w, tile_h);
374 }
375 m_image->updateRect(m_tileImage, x * 32, y * 32);
376 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
377 m_server->add_changed(rect);
378 nTilesChanged++;
379 }
380 ptr_old += nBytes;
381 ptr_new += nBytes;
382 }
383 }
384
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000385 return (nTilesChanged != 0);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000386}
387
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000388//
389// Simplest polling method, from the original x0vncserver of VNC4.
390//
391
392bool PollingManager::poll_Dumb()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000393{
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000394 if (!m_server)
395 return false;
396
397 m_image->get(DefaultRootWindow(m_dpy));
398 Rect rect(0, 0, m_width, m_height);
399 m_server->add_changed(rect);
400
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000401 // Report that some changes have been detected.
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000402 return true;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000403}
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000404
405//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000406// Compute coordinates of the rectangle around the pointer.
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000407//
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000408// ASSUMES: (m_pointerPosKnown != false)
409//
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000410
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000411void PollingManager::computePointerArea(Rect *r)
412{
413 int x = m_pointerPos.x - 64;
414 int y = m_pointerPos.y - 64;
415 int w = 128;
416 int h = 128;
417 if (x < 0) {
418 w += x; x = 0;
419 }
420 if (x + w > m_width) {
421 w = m_width - x;
422 }
423 if (y < 0) {
424 h += y; y = 0;
425 }
426 if (y + h > m_height) {
427 h = m_height - y;
428 }
429
430 r->setXYWH(x, y, w, h);
431}
432
433//
434// Poll the area under current pointer position. Each pixel of the
435// area should be compared. Using such polling option gives higher
436// priority to screen area under the pointer.
437//
438// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
439//
440
441bool PollingManager::pollPointerArea()
442{
443 Rect r;
444 computePointerArea(&r);
445
446 // Shortcuts for coordinates.
447 int x = r.tl.x, y = r.tl.y;
448 int w = r.width(), h = r.height();
449
450 // Get new pixels.
451 if (w == 128 && h == 128) {
452 m_areaImage->get(DefaultRootWindow(m_dpy), x, y);
453 } else {
454 m_areaImage->get(DefaultRootWindow(m_dpy), x, y, w, h);
455 }
456
457 // Now, try to minimize the rectangle by cutting out unchanged
458 // borders (at top and bottom).
459 //
460 // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
461 // to produce a region instead of a rectangle. If there would
462 // be just one universal polling algorithm, it could be
463 // better to integrate pointer area polling into that
464 // algorithm, instead of a separate pollPointerArea()
465 // function.
466
467 // Shortcuts.
468 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
469 int oldBytesPerLine = m_image->xim->bytes_per_line;
470 int newBytesPerLine = m_areaImage->xim->bytes_per_line;
471 char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
472 char *newPtr = m_areaImage->xim->data;
473
474 // Check and cut out unchanged rows at the top.
475 int ty;
476 for (ty = 0; ty < h; ty++) {
477 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
478 break;
479 oldPtr += oldBytesPerLine;
480 newPtr += newBytesPerLine;
481 }
482 if (ty == h) {
483 return false; // no changes at all
484 }
485 y += ty; h -= ty;
486
487 // Check and cut out unchanged rows at the bottom.
488 oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
489 newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
490 int by;
491 for (by = 0; by < h - 1; by++) {
492 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
493 break;
494 oldPtr -= oldBytesPerLine;
495 newPtr -= newBytesPerLine;
496 }
497 h -= by;
498
499 // Copy pixels.
500 m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
501
502 // Report updates to the server.
503 Rect rect(x, y, x+w, y+h);
504 m_server->add_changed(rect);
505 return true;
506}
507
508//
509// Make video area pattern more regular.
510//
511// FIXME: Replace the above with a normal comment.
512// FIXME: Is the function efficient enough?
513//
514
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000515void PollingManager::adjustVideoArea()
516{
517 char newFlags[m_widthTiles * m_heightTiles];
518 char *ptr = newFlags;
519 int x, y;
520
521 // DEBUG:
522 // int nVideoTiles = 0;
523
524 for (y = 0; y < m_heightTiles; y++) {
525 for (x = 0; x < m_widthTiles; x++) {
526
527 // DEBUG:
528 // nVideoTiles += m_videoFlags[y * m_widthTiles + x];
529
530 int weightedSum = 0, n;
531 if (y > 0 && x > 0) {
532 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
533 m_videoFlags[(y-1) * m_widthTiles + (x-1)] +
534 m_videoFlags[(y-1) * m_widthTiles + x ]);
535 if (n == 3) {
536 *ptr++ = 1;
537 continue;
538 }
539 weightedSum += n;
540 }
541 if (y > 0 && x < m_widthTiles - 1) {
542 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
543 m_videoFlags[(y-1) * m_widthTiles + (x+1)] +
544 m_videoFlags[(y-1) * m_widthTiles + x ]);
545 if (n == 3) {
546 *ptr++ = 1;
547 continue;
548 }
549 weightedSum += n;
550 }
551 if (y < m_heightTiles - 1 && x > 0) {
552 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
553 m_videoFlags[(y+1) * m_widthTiles + (x-1)] +
554 m_videoFlags[(y+1) * m_widthTiles + x ]);
555 if (n == 3) {
556 *ptr++ = 1;
557 continue;
558 }
559 weightedSum += n;
560 }
561 if (y < m_heightTiles - 1 && x < m_widthTiles - 1) {
562 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
563 m_videoFlags[(y+1) * m_widthTiles + (x+1)] +
564 m_videoFlags[(y+1) * m_widthTiles + x ]);
565 if (n == 3) {
566 *ptr++ = 1;
567 continue;
568 }
569 weightedSum += n;
570 }
571 *ptr++ = (weightedSum <= 3) ? 0 : m_videoFlags[y * m_widthTiles + x];
572 }
573 }
574
575 /*
576 /// DEBUG: ------------------------------------------------------
577 if (nVideoTiles) {
578 for (y = 0; y < m_heightTiles; y++) {
579 for (x = 0; x < m_widthTiles; x++) {
580 printf("%c", m_videoFlags[y * m_widthTiles + x] ? '@' : ':');
581 }
582 printf(" ");
583 for (x = 0; x < m_widthTiles; x++) {
584 printf("%c", newFlags[y * m_widthTiles + x] ? '@' : ':');
585 }
586 printf("\n");
587 }
588 printf("\n");
589 }
590 /// -------------------------------------------------------------
591 */
592
593 memcpy(m_videoFlags, newFlags, m_widthTiles * m_heightTiles);
594}