blob: 8328101ae1e805e0dda36885c4bbb762c2bfc516 [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,
Constantin Kaplinsky44e99642006-05-20 12:58:38 +000061 ImageFactory *factory,
62 int offsetLeft, int offsetTop)
63 : m_dpy(dpy), m_server(0), m_image(image),
64 m_offsetLeft(offsetLeft), m_offsetTop(offsetTop),
65 m_pointerPosKnown(false), 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 Kaplinsky99d65142006-05-22 05:45:20 +000075 // Get initial screen image.
76 m_image->get(DefaultRootWindow(m_dpy), m_offsetLeft, m_offsetTop);
77
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000078 // Create additional images used in the polling algorithm.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000079 // FIXME: verify that these images use the same pixel format as in m_image.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000080 m_rowImage = factory->newImage(m_dpy, m_width, 1);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000081 m_tileImage = factory->newImage(m_dpy, 32, 32);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +000082 m_areaImage = factory->newImage(m_dpy, 128, 128);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000083
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000084 // FIXME: Extend the comment.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000085 // Create a matrix with one byte per each 32x32 tile. It will be
86 // used to limit the rate of updates on continuously-changed screen
87 // areas (like video).
88 int numTiles = m_widthTiles * m_heightTiles;
89 m_statusMatrix = new char[numTiles];
90 memset(m_statusMatrix, 0, numTiles);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +000091
92 // FIXME: Extend the comment.
93 // Create a matrix with one byte per each 32x32 tile. It will be
94 // used to limit the rate of updates on continuously-changed screen
95 // areas (like video).
96 m_rateMatrix = new char[numTiles];
97 m_videoFlags = new char[numTiles];
98 m_changedFlags = new char[numTiles];
99 memset(m_rateMatrix, 0, numTiles);
100 memset(m_videoFlags, 0, numTiles);
101 memset(m_changedFlags, 0, numTiles);
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 Kaplinskyfbaab7f2006-02-16 04:51:38 +0000155 TimeMillis timeNow;
156 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000157 fprintf(stderr, "[wait%4dms]\t[step %2d]\t", diff, m_pollingStep % 32);
158 m_timeSaved = timeNow;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000159}
160
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000161void PollingManager::debugAfterPoll()
162{
Constantin Kaplinskyfbaab7f2006-02-16 04:51:38 +0000163 TimeMillis timeNow;
164 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000165 fprintf(stderr, "[poll%4dms]\n", diff);
166 m_timeSaved = timeNow;
167}
168
169#endif
170
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000171//
172// Search for changed rectangles on the screen.
173//
174
175void PollingManager::poll()
176{
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000177#ifdef DEBUG
178 debugBeforePoll();
179#endif
180
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000181 // First step: full-screen polling.
182
183 bool changes1 = false;
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000184
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000185 switch((int)pollingType) {
186 case 0:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000187 changes1 = poll_Dumb();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000188 break;
189 case 1:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000190 changes1 = poll_Traditional();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000191 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000192 case 2:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000193 changes1 = poll_SkipCycles();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000194 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000195//case 3:
196 default:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000197 changes1 = poll_DetectVideo();
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000198 break;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000199 }
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000200
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000201 // Second step: optional thorough polling of the area around the pointer.
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000202 // We do that only if the pointer position is known and was set recently.
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000203
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000204 bool changes2 = false;
205 if (pollPointer) {
206 if (m_pointerPosKnown && time(NULL) - m_pointerPosTime >= 5) {
207 unsetPointerPos();
208 }
209 if (m_pointerPosKnown) {
210 changes2 = pollPointerArea();
211 }
212 }
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000213
214 // Update if needed.
215
216 if (changes1 || changes2)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000217 m_server->tryUpdate();
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000218
219#ifdef DEBUG
220 debugAfterPoll();
221#endif
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000222}
223
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000224bool PollingManager::poll_DetectVideo()
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000225{
226 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000227 return false;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000228
229 const int GRAND_STEP_DIVISOR = 8;
230 const int VIDEO_THRESHOLD_0 = 3;
231 const int VIDEO_THRESHOLD_1 = 5;
232
233 bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
234
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000235 // FIXME: Save shortcuts in member variables?
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000236 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
237 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
238 int bytesPerLine = m_image->xim->bytes_per_line;
239
240 Rect rect;
241 int nTilesChanged = 0;
242 int idx = 0;
243
244 for (int y = 0; y * 32 < m_height; y++) {
245 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
246 if (scanLine >= tile_h)
247 break;
248 int scan_y = y * 32 + scanLine;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000249 getRow(scan_y);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000250 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
251 char *ptr_new = m_rowImage->xim->data;
252 for (int x = 0; x * 32 < m_width; x++) {
253 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
254 int nBytes = tile_w * bytesPerPixel;
255
256 char wasChanged = (memcmp(ptr_old, ptr_new, nBytes) != 0);
257 m_rateMatrix[idx] += wasChanged;
258
259 if (grandStep) {
260 if (m_rateMatrix[idx] <= VIDEO_THRESHOLD_0) {
261 m_videoFlags[idx] = 0;
262 } else if (m_rateMatrix[idx] >= VIDEO_THRESHOLD_1) {
263 m_videoFlags[idx] = 1;
264 }
265 m_rateMatrix[idx] = 0;
266 }
267
268 m_changedFlags[idx] |= wasChanged;
269 if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000270 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000271 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;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000314 getRow(scan_y);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000315 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) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000326 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000327 m_image->updateRect(m_tileImage, x * 32, y * 32);
328 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
329 m_server->add_changed(rect);
330 nTilesChanged++;
331 *pstatus = CHANGED_ONCE;
332 } else {
333 *pstatus = CHANGED_AGAIN;
334 }
335 } else if (grandStep) {
336 *pstatus = NOT_CHANGED;
337 }
338 }
339
340 ptr_old += nBytes;
341 ptr_new += nBytes;
342 pstatus++;
343 }
344 }
345
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000346 return (nTilesChanged != 0);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000347}
348
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000349bool PollingManager::poll_Traditional()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000350{
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000351 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000352 return false;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000353
354 int nTilesChanged = 0;
355 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
356 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
357 int bytesPerLine = m_image->xim->bytes_per_line;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000358 Rect rect;
359
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000360 for (int y = 0; y * 32 < m_height; y++) {
361 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000362 if (scanLine >= tile_h)
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000363 break;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000364 int scan_y = y * 32 + scanLine;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000365 getRow(scan_y);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000366 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
367 char *ptr_new = m_rowImage->xim->data;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000368 for (int x = 0; x * 32 < m_width; x++) {
369 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000370 int nBytes = tile_w * bytesPerPixel;
371 if (memcmp(ptr_old, ptr_new, nBytes)) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000372 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000373 m_image->updateRect(m_tileImage, x * 32, y * 32);
374 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
375 m_server->add_changed(rect);
376 nTilesChanged++;
377 }
378 ptr_old += nBytes;
379 ptr_new += nBytes;
380 }
381 }
382
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000383 return (nTilesChanged != 0);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000384}
385
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000386//
387// Simplest polling method, from the original x0vncserver of VNC4.
388//
389
390bool PollingManager::poll_Dumb()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000391{
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000392 if (!m_server)
393 return false;
394
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000395 getScreen();
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000396 Rect rect(0, 0, m_width, m_height);
397 m_server->add_changed(rect);
398
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000399 // Report that some changes have been detected.
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000400 return true;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000401}
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000402
403//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000404// Compute coordinates of the rectangle around the pointer.
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000405//
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000406// ASSUMES: (m_pointerPosKnown != false)
407//
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000408
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000409void PollingManager::computePointerArea(Rect *r)
410{
411 int x = m_pointerPos.x - 64;
412 int y = m_pointerPos.y - 64;
413 int w = 128;
414 int h = 128;
415 if (x < 0) {
416 w += x; x = 0;
417 }
418 if (x + w > m_width) {
419 w = m_width - x;
420 }
421 if (y < 0) {
422 h += y; y = 0;
423 }
424 if (y + h > m_height) {
425 h = m_height - y;
426 }
427
428 r->setXYWH(x, y, w, h);
429}
430
431//
432// Poll the area under current pointer position. Each pixel of the
433// area should be compared. Using such polling option gives higher
434// priority to screen area under the pointer.
435//
436// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
437//
438
439bool PollingManager::pollPointerArea()
440{
441 Rect r;
442 computePointerArea(&r);
443
444 // Shortcuts for coordinates.
445 int x = r.tl.x, y = r.tl.y;
446 int w = r.width(), h = r.height();
447
448 // Get new pixels.
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000449 getArea128(x, y, w, h);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000450
451 // Now, try to minimize the rectangle by cutting out unchanged
452 // borders (at top and bottom).
453 //
454 // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
455 // to produce a region instead of a rectangle. If there would
456 // be just one universal polling algorithm, it could be
457 // better to integrate pointer area polling into that
458 // algorithm, instead of a separate pollPointerArea()
459 // function.
460
461 // Shortcuts.
462 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
463 int oldBytesPerLine = m_image->xim->bytes_per_line;
464 int newBytesPerLine = m_areaImage->xim->bytes_per_line;
465 char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
466 char *newPtr = m_areaImage->xim->data;
467
468 // Check and cut out unchanged rows at the top.
469 int ty;
470 for (ty = 0; ty < h; ty++) {
471 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
472 break;
473 oldPtr += oldBytesPerLine;
474 newPtr += newBytesPerLine;
475 }
476 if (ty == h) {
477 return false; // no changes at all
478 }
479 y += ty; h -= ty;
480
481 // Check and cut out unchanged rows at the bottom.
482 oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
483 newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
484 int by;
485 for (by = 0; by < h - 1; by++) {
486 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
487 break;
488 oldPtr -= oldBytesPerLine;
489 newPtr -= newBytesPerLine;
490 }
491 h -= by;
492
493 // Copy pixels.
494 m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
495
496 // Report updates to the server.
497 Rect rect(x, y, x+w, y+h);
498 m_server->add_changed(rect);
499 return true;
500}
501
502//
503// Make video area pattern more regular.
504//
505// FIXME: Replace the above with a normal comment.
506// FIXME: Is the function efficient enough?
507//
508
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000509void PollingManager::adjustVideoArea()
510{
511 char newFlags[m_widthTiles * m_heightTiles];
512 char *ptr = newFlags;
513 int x, y;
514
515 // DEBUG:
516 // int nVideoTiles = 0;
517
518 for (y = 0; y < m_heightTiles; y++) {
519 for (x = 0; x < m_widthTiles; x++) {
520
521 // DEBUG:
522 // nVideoTiles += m_videoFlags[y * m_widthTiles + x];
523
524 int weightedSum = 0, n;
525 if (y > 0 && x > 0) {
526 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
527 m_videoFlags[(y-1) * m_widthTiles + (x-1)] +
528 m_videoFlags[(y-1) * m_widthTiles + x ]);
529 if (n == 3) {
530 *ptr++ = 1;
531 continue;
532 }
533 weightedSum += n;
534 }
535 if (y > 0 && x < m_widthTiles - 1) {
536 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
537 m_videoFlags[(y-1) * m_widthTiles + (x+1)] +
538 m_videoFlags[(y-1) * m_widthTiles + x ]);
539 if (n == 3) {
540 *ptr++ = 1;
541 continue;
542 }
543 weightedSum += n;
544 }
545 if (y < m_heightTiles - 1 && x > 0) {
546 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
547 m_videoFlags[(y+1) * m_widthTiles + (x-1)] +
548 m_videoFlags[(y+1) * m_widthTiles + x ]);
549 if (n == 3) {
550 *ptr++ = 1;
551 continue;
552 }
553 weightedSum += n;
554 }
555 if (y < m_heightTiles - 1 && x < m_widthTiles - 1) {
556 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
557 m_videoFlags[(y+1) * m_widthTiles + (x+1)] +
558 m_videoFlags[(y+1) * m_widthTiles + x ]);
559 if (n == 3) {
560 *ptr++ = 1;
561 continue;
562 }
563 weightedSum += n;
564 }
565 *ptr++ = (weightedSum <= 3) ? 0 : m_videoFlags[y * m_widthTiles + x];
566 }
567 }
568
569 /*
570 /// DEBUG: ------------------------------------------------------
571 if (nVideoTiles) {
572 for (y = 0; y < m_heightTiles; y++) {
573 for (x = 0; x < m_widthTiles; x++) {
574 printf("%c", m_videoFlags[y * m_widthTiles + x] ? '@' : ':');
575 }
576 printf(" ");
577 for (x = 0; x < m_widthTiles; x++) {
578 printf("%c", newFlags[y * m_widthTiles + x] ? '@' : ':');
579 }
580 printf("\n");
581 }
582 printf("\n");
583 }
584 /// -------------------------------------------------------------
585 */
586
587 memcpy(m_videoFlags, newFlags, m_widthTiles * m_heightTiles);
588}