blob: f131e7e8c88815b9bdc2758547867ff7819deee9 [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
34#include <x0vncserver/Image.h>
35#include <x0vncserver/PollingManager.h>
36
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000037BoolParameter PollingManager::pollPointer
38("PollPointer",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000039 "DEBUG: Poll area under the pointer with higher priority",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000040 true);
41
42IntParameter PollingManager::pollingType
43("PollingType",
Constantin Kaplinskya4f07362006-02-10 11:54:49 +000044 "DEBUG: Select particular polling algorithm (0..3)",
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000045 3);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000046
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000047const int PollingManager::m_pollingOrder[32] = {
48 0, 16, 8, 24, 4, 20, 12, 28,
49 10, 26, 18, 2, 22, 6, 30, 14,
50 1, 17, 9, 25, 7, 23, 15, 31,
51 19, 3, 27, 11, 29, 13, 5, 21
52};
53
54//
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000055// Constructor.
56//
57// Note that dpy and image should remain valid during the object
58// lifetime, while factory is used only in the constructor itself.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000059//
60
61PollingManager::PollingManager(Display *dpy, Image *image,
62 ImageFactory *factory)
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000063 : m_dpy(dpy), m_server(0), m_image(image), m_pointerPosKnown(false),
64 m_pollingStep(0)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000065{
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000066 // Save width and height of the screen (and the image).
67 m_width = m_image->xim->width;
68 m_height = m_image->xim->height;
69
70 // Compute width and height in 32x32 tiles.
71 m_widthTiles = (m_width + 31) / 32;
72 m_heightTiles = (m_height + 31) / 32;
73
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000074 // Create additional images used in the polling algorithm.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000075 // FIXME: verify that these images use the same pixel format as in m_image.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000076 m_rowImage = factory->newImage(m_dpy, m_width, 1);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000077 m_tileImage = factory->newImage(m_dpy, 32, 32);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000078 m_areaImage = factory->newImage(m_dpy, 128, 128);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000079
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000080 // FIXME: Extend the comment.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000081 // Create a matrix with one byte per each 32x32 tile. It will be
82 // used to limit the rate of updates on continuously-changed screen
83 // areas (like video).
84 int numTiles = m_widthTiles * m_heightTiles;
85 m_statusMatrix = new char[numTiles];
86 memset(m_statusMatrix, 0, numTiles);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000087
88 // FIXME: Extend the comment.
89 // Create a matrix with one byte per each 32x32 tile. It will be
90 // used to limit the rate of updates on continuously-changed screen
91 // areas (like video).
92 m_rateMatrix = new char[numTiles];
93 m_videoFlags = new char[numTiles];
94 m_changedFlags = new char[numTiles];
95 memset(m_rateMatrix, 0, numTiles);
96 memset(m_videoFlags, 0, numTiles);
97 memset(m_changedFlags, 0, numTiles);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +000098
99#ifdef DEBUG
100 memset(&m_timeSaved, 0, sizeof(m_timeSaved));
101#endif
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000102}
103
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000104PollingManager::~PollingManager()
105{
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000106 delete[] m_changedFlags;
107 delete[] m_videoFlags;
108 delete[] m_rateMatrix;
109
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000110 delete[] m_statusMatrix;
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000111
112 delete m_areaImage;
113 delete m_tileImage;
114 delete m_rowImage;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000115}
116
117//
118// Register VNCServer object.
119//
120
121void PollingManager::setVNCServer(VNCServer *s)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000122{
123 m_server = s;
124}
125
126//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000127// Update current pointer position which may be used as a hint for
128// polling algorithms.
129//
130
131void PollingManager::setPointerPos(const Point &pos)
132{
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000133 m_pointerPosTime = time(NULL);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000134 m_pointerPos = pos;
135 m_pointerPosKnown = true;
136}
137
138//
139// Indicate that current pointer position is unknown.
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000140//
141
142void PollingManager::unsetPointerPos()
143{
144 m_pointerPosKnown = false;
145}
146
147//
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000148// DEBUG: Measuring time spent in the poll() function,
149// as well as time intervals between poll() calls.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000150//
151
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000152#ifdef DEBUG
153void PollingManager::debugBeforePoll()
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000154{
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000155 struct timeval timeNow;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000156 struct timezone tz;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000157 gettimeofday(&timeNow, &tz);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000158 int diff = (int)((timeNow.tv_usec - m_timeSaved.tv_usec + 500) / 1000 +
159 (timeNow.tv_sec - m_timeSaved.tv_sec) * 1000);
160 fprintf(stderr, "[wait%4dms]\t[step %2d]\t", diff, m_pollingStep % 32);
161 m_timeSaved = timeNow;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000162}
163
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000164void PollingManager::debugAfterPoll()
165{
166 struct timeval timeNow;
167 struct timezone tz;
168 gettimeofday(&timeNow, &tz);
169 int diff = (int)((timeNow.tv_usec - m_timeSaved.tv_usec + 500) / 1000 +
170 (timeNow.tv_sec - m_timeSaved.tv_sec) * 1000);
171 fprintf(stderr, "[poll%4dms]\n", diff);
172 m_timeSaved = timeNow;
173}
174
175#endif
176
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000177//
178// Search for changed rectangles on the screen.
179//
180
181void PollingManager::poll()
182{
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000183#ifdef DEBUG
184 debugBeforePoll();
185#endif
186
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000187 // First step: full-screen polling.
188
189 bool changes1 = false;
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000190
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000191 switch((int)pollingType) {
192 case 0:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000193 changes1 = poll_Dumb();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000194 break;
195 case 1:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000196 changes1 = poll_Traditional();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000197 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000198 case 2:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000199 changes1 = poll_SkipCycles();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000200 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000201//case 3:
202 default:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000203 changes1 = poll_DetectVideo();
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000204 break;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000205 }
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000206
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000207 // Second step: optional thorough polling of the area around the pointer.
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000208 // We do that only if the pointer position is known and was set recently.
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000209
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000210 bool changes2 = false;
211 if (pollPointer) {
212 if (m_pointerPosKnown && time(NULL) - m_pointerPosTime >= 5) {
213 unsetPointerPos();
214 }
215 if (m_pointerPosKnown) {
216 changes2 = pollPointerArea();
217 }
218 }
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000219
220 // Update if needed.
221
222 if (changes1 || changes2)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000223 m_server->tryUpdate();
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000224
225#ifdef DEBUG
226 debugAfterPoll();
227#endif
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000228}
229
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000230bool PollingManager::poll_DetectVideo()
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000231{
232 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000233 return false;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000234
235 const int GRAND_STEP_DIVISOR = 8;
236 const int VIDEO_THRESHOLD_0 = 3;
237 const int VIDEO_THRESHOLD_1 = 5;
238
239 bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
240
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000241 // FIXME: Save shortcuts in member variables?
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000242 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
243 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
244 int bytesPerLine = m_image->xim->bytes_per_line;
245
246 Rect rect;
247 int nTilesChanged = 0;
248 int idx = 0;
249
250 for (int y = 0; y * 32 < m_height; y++) {
251 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
252 if (scanLine >= tile_h)
253 break;
254 int scan_y = y * 32 + scanLine;
255 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
256 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
257 char *ptr_new = m_rowImage->xim->data;
258 for (int x = 0; x * 32 < m_width; x++) {
259 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
260 int nBytes = tile_w * bytesPerPixel;
261
262 char wasChanged = (memcmp(ptr_old, ptr_new, nBytes) != 0);
263 m_rateMatrix[idx] += wasChanged;
264
265 if (grandStep) {
266 if (m_rateMatrix[idx] <= VIDEO_THRESHOLD_0) {
267 m_videoFlags[idx] = 0;
268 } else if (m_rateMatrix[idx] >= VIDEO_THRESHOLD_1) {
269 m_videoFlags[idx] = 1;
270 }
271 m_rateMatrix[idx] = 0;
272 }
273
274 m_changedFlags[idx] |= wasChanged;
275 if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
276 if (tile_w == 32 && tile_h == 32) {
277 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
278 } else {
279 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
280 tile_w, tile_h);
281 }
282 m_image->updateRect(m_tileImage, x * 32, y * 32);
283 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
284 m_server->add_changed(rect);
285 nTilesChanged++;
286 m_changedFlags[idx] = 0;
287 }
288
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000289 ptr_old += nBytes;
290 ptr_new += nBytes;
291 idx++;
292 }
293 }
294
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000295 if (grandStep)
296 adjustVideoArea();
297
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000298 return (nTilesChanged != 0);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000299}
300
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000301bool PollingManager::poll_SkipCycles()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000302{
303 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000304 return false;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000305
306 enum {
307 NOT_CHANGED, CHANGED_ONCE, CHANGED_AGAIN
308 };
309
310 bool grandStep = (m_pollingStep % 8 == 0);
311
312 int nTilesChanged = 0;
313 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
314 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
315 int bytesPerLine = m_image->xim->bytes_per_line;
316 char *pstatus = m_statusMatrix;
317 bool wasChanged;
318 Rect rect;
319
320 for (int y = 0; y * 32 < m_height; y++) {
321 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
322 if (scanLine >= tile_h)
323 scanLine %= tile_h;
324 int scan_y = y * 32 + scanLine;
325 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
326 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
327 char *ptr_new = m_rowImage->xim->data;
328 for (int x = 0; x * 32 < m_width; x++) {
329 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
330 int nBytes = tile_w * bytesPerPixel;
331
332 if (grandStep || *pstatus != CHANGED_AGAIN) {
333 wasChanged = (*pstatus == CHANGED_AGAIN) ?
334 true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
335 if (wasChanged) {
336 if (grandStep || *pstatus == NOT_CHANGED) {
337 if (tile_w == 32 && tile_h == 32) {
338 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
339 } else {
340 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
341 tile_w, tile_h);
342 }
343 m_image->updateRect(m_tileImage, x * 32, y * 32);
344 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
345 m_server->add_changed(rect);
346 nTilesChanged++;
347 *pstatus = CHANGED_ONCE;
348 } else {
349 *pstatus = CHANGED_AGAIN;
350 }
351 } else if (grandStep) {
352 *pstatus = NOT_CHANGED;
353 }
354 }
355
356 ptr_old += nBytes;
357 ptr_new += nBytes;
358 pstatus++;
359 }
360 }
361
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000362 return (nTilesChanged != 0);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000363}
364
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000365bool PollingManager::poll_Traditional()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000366{
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000367 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000368 return false;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000369
370 int nTilesChanged = 0;
371 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
372 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
373 int bytesPerLine = m_image->xim->bytes_per_line;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000374 Rect rect;
375
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000376 for (int y = 0; y * 32 < m_height; y++) {
377 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000378 if (scanLine >= tile_h)
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000379 break;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000380 int scan_y = y * 32 + scanLine;
381 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
382 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
383 char *ptr_new = m_rowImage->xim->data;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000384 for (int x = 0; x * 32 < m_width; x++) {
385 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000386 int nBytes = tile_w * bytesPerPixel;
387 if (memcmp(ptr_old, ptr_new, nBytes)) {
388 if (tile_w == 32 && tile_h == 32) {
389 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
390 } else {
391 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
392 tile_w, tile_h);
393 }
394 m_image->updateRect(m_tileImage, x * 32, y * 32);
395 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
396 m_server->add_changed(rect);
397 nTilesChanged++;
398 }
399 ptr_old += nBytes;
400 ptr_new += nBytes;
401 }
402 }
403
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000404 return (nTilesChanged != 0);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000405}
406
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000407//
408// Simplest polling method, from the original x0vncserver of VNC4.
409//
410
411bool PollingManager::poll_Dumb()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000412{
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000413 if (!m_server)
414 return false;
415
416 m_image->get(DefaultRootWindow(m_dpy));
417 Rect rect(0, 0, m_width, m_height);
418 m_server->add_changed(rect);
419
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000420 // Report that some changes have been detected.
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000421 return true;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000422}
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000423
424//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000425// Compute coordinates of the rectangle around the pointer.
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000426//
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000427// ASSUMES: (m_pointerPosKnown != false)
428//
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000429
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000430void PollingManager::computePointerArea(Rect *r)
431{
432 int x = m_pointerPos.x - 64;
433 int y = m_pointerPos.y - 64;
434 int w = 128;
435 int h = 128;
436 if (x < 0) {
437 w += x; x = 0;
438 }
439 if (x + w > m_width) {
440 w = m_width - x;
441 }
442 if (y < 0) {
443 h += y; y = 0;
444 }
445 if (y + h > m_height) {
446 h = m_height - y;
447 }
448
449 r->setXYWH(x, y, w, h);
450}
451
452//
453// Poll the area under current pointer position. Each pixel of the
454// area should be compared. Using such polling option gives higher
455// priority to screen area under the pointer.
456//
457// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
458//
459
460bool PollingManager::pollPointerArea()
461{
462 Rect r;
463 computePointerArea(&r);
464
465 // Shortcuts for coordinates.
466 int x = r.tl.x, y = r.tl.y;
467 int w = r.width(), h = r.height();
468
469 // Get new pixels.
470 if (w == 128 && h == 128) {
471 m_areaImage->get(DefaultRootWindow(m_dpy), x, y);
472 } else {
473 m_areaImage->get(DefaultRootWindow(m_dpy), x, y, w, h);
474 }
475
476 // Now, try to minimize the rectangle by cutting out unchanged
477 // borders (at top and bottom).
478 //
479 // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
480 // to produce a region instead of a rectangle. If there would
481 // be just one universal polling algorithm, it could be
482 // better to integrate pointer area polling into that
483 // algorithm, instead of a separate pollPointerArea()
484 // function.
485
486 // Shortcuts.
487 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
488 int oldBytesPerLine = m_image->xim->bytes_per_line;
489 int newBytesPerLine = m_areaImage->xim->bytes_per_line;
490 char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
491 char *newPtr = m_areaImage->xim->data;
492
493 // Check and cut out unchanged rows at the top.
494 int ty;
495 for (ty = 0; ty < h; ty++) {
496 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
497 break;
498 oldPtr += oldBytesPerLine;
499 newPtr += newBytesPerLine;
500 }
501 if (ty == h) {
502 return false; // no changes at all
503 }
504 y += ty; h -= ty;
505
506 // Check and cut out unchanged rows at the bottom.
507 oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
508 newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
509 int by;
510 for (by = 0; by < h - 1; by++) {
511 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
512 break;
513 oldPtr -= oldBytesPerLine;
514 newPtr -= newBytesPerLine;
515 }
516 h -= by;
517
518 // Copy pixels.
519 m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
520
521 // Report updates to the server.
522 Rect rect(x, y, x+w, y+h);
523 m_server->add_changed(rect);
524 return true;
525}
526
527//
528// Make video area pattern more regular.
529//
530// FIXME: Replace the above with a normal comment.
531// FIXME: Is the function efficient enough?
532//
533
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000534void PollingManager::adjustVideoArea()
535{
536 char newFlags[m_widthTiles * m_heightTiles];
537 char *ptr = newFlags;
538 int x, y;
539
540 // DEBUG:
541 // int nVideoTiles = 0;
542
543 for (y = 0; y < m_heightTiles; y++) {
544 for (x = 0; x < m_widthTiles; x++) {
545
546 // DEBUG:
547 // nVideoTiles += m_videoFlags[y * m_widthTiles + x];
548
549 int weightedSum = 0, n;
550 if (y > 0 && x > 0) {
551 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
552 m_videoFlags[(y-1) * m_widthTiles + (x-1)] +
553 m_videoFlags[(y-1) * m_widthTiles + x ]);
554 if (n == 3) {
555 *ptr++ = 1;
556 continue;
557 }
558 weightedSum += n;
559 }
560 if (y > 0 && x < m_widthTiles - 1) {
561 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
562 m_videoFlags[(y-1) * m_widthTiles + (x+1)] +
563 m_videoFlags[(y-1) * m_widthTiles + x ]);
564 if (n == 3) {
565 *ptr++ = 1;
566 continue;
567 }
568 weightedSum += n;
569 }
570 if (y < m_heightTiles - 1 && x > 0) {
571 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
572 m_videoFlags[(y+1) * m_widthTiles + (x-1)] +
573 m_videoFlags[(y+1) * m_widthTiles + x ]);
574 if (n == 3) {
575 *ptr++ = 1;
576 continue;
577 }
578 weightedSum += n;
579 }
580 if (y < m_heightTiles - 1 && x < m_widthTiles - 1) {
581 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
582 m_videoFlags[(y+1) * m_widthTiles + (x+1)] +
583 m_videoFlags[(y+1) * m_widthTiles + x ]);
584 if (n == 3) {
585 *ptr++ = 1;
586 continue;
587 }
588 weightedSum += n;
589 }
590 *ptr++ = (weightedSum <= 3) ? 0 : m_videoFlags[y * m_widthTiles + x];
591 }
592 }
593
594 /*
595 /// DEBUG: ------------------------------------------------------
596 if (nVideoTiles) {
597 for (y = 0; y < m_heightTiles; y++) {
598 for (x = 0; x < m_widthTiles; x++) {
599 printf("%c", m_videoFlags[y * m_widthTiles + x] ? '@' : ':');
600 }
601 printf(" ");
602 for (x = 0; x < m_widthTiles; x++) {
603 printf("%c", newFlags[y * m_widthTiles + x] ? '@' : ':');
604 }
605 printf("\n");
606 }
607 printf("\n");
608 }
609 /// -------------------------------------------------------------
610 */
611
612 memcpy(m_videoFlags, newFlags, m_widthTiles * m_heightTiles);
613}