blob: 3c6be4f8ac765e50a7d9268ce1dcf621e35e287f [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 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 Kaplinskyb247d7d2006-02-15 16:14:07 +0000145// DEBUG: Measuring time spent in the poll() function,
146// as well as time intervals between poll() calls.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000147//
148
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000149#ifdef DEBUG
150void PollingManager::debugBeforePoll()
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000151{
Constantin Kaplinskyfbaab7f2006-02-16 04:51:38 +0000152 TimeMillis timeNow;
153 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000154 fprintf(stderr, "[wait%4dms]\t[step %2d]\t", diff, m_pollingStep % 32);
155 m_timeSaved = timeNow;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000156}
157
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000158void PollingManager::debugAfterPoll()
159{
Constantin Kaplinskyfbaab7f2006-02-16 04:51:38 +0000160 TimeMillis timeNow;
161 int diff = timeNow.diffFrom(m_timeSaved);
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000162 fprintf(stderr, "[poll%4dms]\n", diff);
163 m_timeSaved = timeNow;
164}
165
166#endif
167
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000168//
169// Search for changed rectangles on the screen.
170//
171
172void PollingManager::poll()
173{
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000174#ifdef DEBUG
175 debugBeforePoll();
176#endif
177
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000178 // First step: full-screen polling.
179
180 bool changes1 = false;
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000181
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000182 switch((int)pollingType) {
183 case 0:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000184 changes1 = poll_Dumb();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000185 break;
186 case 1:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000187 changes1 = poll_Traditional();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000188 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000189 case 2:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000190 changes1 = poll_SkipCycles();
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000191 break;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000192//case 3:
193 default:
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000194 changes1 = poll_DetectVideo();
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000195 break;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000196 }
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000197
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000198 // Second step: optional thorough polling of the area around the pointer.
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000199 // We do that only if the pointer position is known and was set recently.
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000200
Constantin Kaplinskyaf2ebeb2006-02-10 12:19:11 +0000201 bool changes2 = false;
202 if (pollPointer) {
203 if (m_pointerPosKnown && time(NULL) - m_pointerPosTime >= 5) {
204 unsetPointerPos();
205 }
206 if (m_pointerPosKnown) {
207 changes2 = pollPointerArea();
208 }
209 }
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000210
211 // Update if needed.
212
213 if (changes1 || changes2)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000214 m_server->tryUpdate();
Constantin Kaplinskyb247d7d2006-02-15 16:14:07 +0000215
216#ifdef DEBUG
217 debugAfterPoll();
218#endif
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000219}
220
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000221bool PollingManager::poll_DetectVideo()
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000222{
223 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000224 return false;
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000225
226 const int GRAND_STEP_DIVISOR = 8;
227 const int VIDEO_THRESHOLD_0 = 3;
228 const int VIDEO_THRESHOLD_1 = 5;
229
230 bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
231
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000232 // FIXME: Save shortcuts in member variables?
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000233 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
234 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
235 int bytesPerLine = m_image->xim->bytes_per_line;
236
237 Rect rect;
238 int nTilesChanged = 0;
239 int idx = 0;
240
241 for (int y = 0; y * 32 < m_height; y++) {
242 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
243 if (scanLine >= tile_h)
244 break;
245 int scan_y = y * 32 + scanLine;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000246 getRow(scan_y);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000247 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
248 char *ptr_new = m_rowImage->xim->data;
249 for (int x = 0; x * 32 < m_width; x++) {
250 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
251 int nBytes = tile_w * bytesPerPixel;
252
253 char wasChanged = (memcmp(ptr_old, ptr_new, nBytes) != 0);
254 m_rateMatrix[idx] += wasChanged;
255
256 if (grandStep) {
257 if (m_rateMatrix[idx] <= VIDEO_THRESHOLD_0) {
258 m_videoFlags[idx] = 0;
259 } else if (m_rateMatrix[idx] >= VIDEO_THRESHOLD_1) {
260 m_videoFlags[idx] = 1;
261 }
262 m_rateMatrix[idx] = 0;
263 }
264
265 m_changedFlags[idx] |= wasChanged;
266 if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000267 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000268 m_image->updateRect(m_tileImage, x * 32, y * 32);
269 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
270 m_server->add_changed(rect);
271 nTilesChanged++;
272 m_changedFlags[idx] = 0;
273 }
274
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000275 ptr_old += nBytes;
276 ptr_new += nBytes;
277 idx++;
278 }
279 }
280
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000281 if (grandStep)
282 adjustVideoArea();
283
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000284 return (nTilesChanged != 0);
Constantin Kaplinskydc54fc12005-10-19 13:57:16 +0000285}
286
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000287bool PollingManager::poll_SkipCycles()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000288{
289 if (!m_server)
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000290 return false;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000291
292 enum {
293 NOT_CHANGED, CHANGED_ONCE, CHANGED_AGAIN
294 };
295
296 bool grandStep = (m_pollingStep % 8 == 0);
297
298 int nTilesChanged = 0;
299 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
300 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
301 int bytesPerLine = m_image->xim->bytes_per_line;
302 char *pstatus = m_statusMatrix;
303 bool wasChanged;
304 Rect rect;
305
306 for (int y = 0; y * 32 < m_height; y++) {
307 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
308 if (scanLine >= tile_h)
309 scanLine %= tile_h;
310 int scan_y = y * 32 + scanLine;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000311 getRow(scan_y);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000312 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
313 char *ptr_new = m_rowImage->xim->data;
314 for (int x = 0; x * 32 < m_width; x++) {
315 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
316 int nBytes = tile_w * bytesPerPixel;
317
318 if (grandStep || *pstatus != CHANGED_AGAIN) {
319 wasChanged = (*pstatus == CHANGED_AGAIN) ?
320 true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
321 if (wasChanged) {
322 if (grandStep || *pstatus == NOT_CHANGED) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000323 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000324 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;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000362 getRow(scan_y);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000363 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)) {
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000369 getTile32(x, y, tile_w, tile_h);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000370 m_image->updateRect(m_tileImage, x * 32, y * 32);
371 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
372 m_server->add_changed(rect);
373 nTilesChanged++;
374 }
375 ptr_old += nBytes;
376 ptr_new += nBytes;
377 }
378 }
379
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000380 return (nTilesChanged != 0);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000381}
382
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000383//
384// Simplest polling method, from the original x0vncserver of VNC4.
385//
386
387bool PollingManager::poll_Dumb()
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000388{
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000389 if (!m_server)
390 return false;
391
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000392 getScreen();
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000393 Rect rect(0, 0, m_width, m_height);
394 m_server->add_changed(rect);
395
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000396 // Report that some changes have been detected.
Constantin Kaplinskyc42eab22006-02-01 05:59:21 +0000397 return true;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000398}
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000399
400//
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000401// Compute coordinates of the rectangle around the pointer.
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000402//
Constantin Kaplinsky98bfcd32006-02-10 06:39:35 +0000403// ASSUMES: (m_pointerPosKnown != false)
404//
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000405
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000406void PollingManager::computePointerArea(Rect *r)
407{
408 int x = m_pointerPos.x - 64;
409 int y = m_pointerPos.y - 64;
410 int w = 128;
411 int h = 128;
412 if (x < 0) {
413 w += x; x = 0;
414 }
415 if (x + w > m_width) {
416 w = m_width - x;
417 }
418 if (y < 0) {
419 h += y; y = 0;
420 }
421 if (y + h > m_height) {
422 h = m_height - y;
423 }
424
425 r->setXYWH(x, y, w, h);
426}
427
428//
429// Poll the area under current pointer position. Each pixel of the
430// area should be compared. Using such polling option gives higher
431// priority to screen area under the pointer.
432//
433// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
434//
435
436bool PollingManager::pollPointerArea()
437{
438 Rect r;
439 computePointerArea(&r);
440
441 // Shortcuts for coordinates.
442 int x = r.tl.x, y = r.tl.y;
443 int w = r.width(), h = r.height();
444
445 // Get new pixels.
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000446 getArea128(x, y, w, h);
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000447
448 // Now, try to minimize the rectangle by cutting out unchanged
449 // borders (at top and bottom).
450 //
451 // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
452 // to produce a region instead of a rectangle. If there would
453 // be just one universal polling algorithm, it could be
454 // better to integrate pointer area polling into that
455 // algorithm, instead of a separate pollPointerArea()
456 // function.
457
458 // Shortcuts.
459 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
460 int oldBytesPerLine = m_image->xim->bytes_per_line;
461 int newBytesPerLine = m_areaImage->xim->bytes_per_line;
462 char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
463 char *newPtr = m_areaImage->xim->data;
464
465 // Check and cut out unchanged rows at the top.
466 int ty;
467 for (ty = 0; ty < h; ty++) {
468 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
469 break;
470 oldPtr += oldBytesPerLine;
471 newPtr += newBytesPerLine;
472 }
473 if (ty == h) {
474 return false; // no changes at all
475 }
476 y += ty; h -= ty;
477
478 // Check and cut out unchanged rows at the bottom.
479 oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
480 newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
481 int by;
482 for (by = 0; by < h - 1; by++) {
483 if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
484 break;
485 oldPtr -= oldBytesPerLine;
486 newPtr -= newBytesPerLine;
487 }
488 h -= by;
489
490 // Copy pixels.
491 m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
492
493 // Report updates to the server.
494 Rect rect(x, y, x+w, y+h);
495 m_server->add_changed(rect);
496 return true;
497}
498
499//
500// Make video area pattern more regular.
501//
502// FIXME: Replace the above with a normal comment.
503// FIXME: Is the function efficient enough?
504//
505
Constantin Kaplinsky6df69902006-02-03 11:42:00 +0000506void PollingManager::adjustVideoArea()
507{
508 char newFlags[m_widthTiles * m_heightTiles];
509 char *ptr = newFlags;
510 int x, y;
511
512 // DEBUG:
513 // int nVideoTiles = 0;
514
515 for (y = 0; y < m_heightTiles; y++) {
516 for (x = 0; x < m_widthTiles; x++) {
517
518 // DEBUG:
519 // nVideoTiles += m_videoFlags[y * m_widthTiles + x];
520
521 int weightedSum = 0, n;
522 if (y > 0 && x > 0) {
523 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
524 m_videoFlags[(y-1) * m_widthTiles + (x-1)] +
525 m_videoFlags[(y-1) * m_widthTiles + x ]);
526 if (n == 3) {
527 *ptr++ = 1;
528 continue;
529 }
530 weightedSum += n;
531 }
532 if (y > 0 && x < m_widthTiles - 1) {
533 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
534 m_videoFlags[(y-1) * m_widthTiles + (x+1)] +
535 m_videoFlags[(y-1) * m_widthTiles + x ]);
536 if (n == 3) {
537 *ptr++ = 1;
538 continue;
539 }
540 weightedSum += n;
541 }
542 if (y < m_heightTiles - 1 && x > 0) {
543 n = (m_videoFlags[ y * m_widthTiles + (x-1)] +
544 m_videoFlags[(y+1) * m_widthTiles + (x-1)] +
545 m_videoFlags[(y+1) * m_widthTiles + x ]);
546 if (n == 3) {
547 *ptr++ = 1;
548 continue;
549 }
550 weightedSum += n;
551 }
552 if (y < m_heightTiles - 1 && x < m_widthTiles - 1) {
553 n = (m_videoFlags[ y * m_widthTiles + (x+1)] +
554 m_videoFlags[(y+1) * m_widthTiles + (x+1)] +
555 m_videoFlags[(y+1) * m_widthTiles + x ]);
556 if (n == 3) {
557 *ptr++ = 1;
558 continue;
559 }
560 weightedSum += n;
561 }
562 *ptr++ = (weightedSum <= 3) ? 0 : m_videoFlags[y * m_widthTiles + x];
563 }
564 }
565
566 /*
567 /// DEBUG: ------------------------------------------------------
568 if (nVideoTiles) {
569 for (y = 0; y < m_heightTiles; y++) {
570 for (x = 0; x < m_widthTiles; x++) {
571 printf("%c", m_videoFlags[y * m_widthTiles + x] ? '@' : ':');
572 }
573 printf(" ");
574 for (x = 0; x < m_widthTiles; x++) {
575 printf("%c", newFlags[y * m_widthTiles + x] ? '@' : ':');
576 }
577 printf("\n");
578 }
579 printf("\n");
580 }
581 /// -------------------------------------------------------------
582 */
583
584 memcpy(m_videoFlags, newFlags, m_widthTiles * m_heightTiles);
585}