blob: 25111cdf3fd195a4905d4adde20fdd029d3829db [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
22#include <stdio.h>
23#include <string.h>
24#include <sys/time.h>
25#include <X11/Xlib.h>
26#include <rfb/VNCServer.h>
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000027#include <rfb/Configuration.h>
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000028
29#include <x0vncserver/Image.h>
30#include <x0vncserver/PollingManager.h>
31
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000032IntParameter pollingType("PollingType", "Polling algorithm to use (0..2)", 2);
33
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000034const int PollingManager::m_pollingOrder[32] = {
35 0, 16, 8, 24, 4, 20, 12, 28,
36 10, 26, 18, 2, 22, 6, 30, 14,
37 1, 17, 9, 25, 7, 23, 15, 31,
38 19, 3, 27, 11, 29, 13, 5, 21
39};
40
41//
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000042// Constructor.
43//
44// Note that dpy and image should remain valid during the object
45// lifetime, while factory is used only in the constructor itself.
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000046//
47
48PollingManager::PollingManager(Display *dpy, Image *image,
49 ImageFactory *factory)
50 : m_dpy(dpy), m_server(0), m_image(image), m_pollingStep(0)
51{
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000052 // Save width and height of the screen (and the image).
53 m_width = m_image->xim->width;
54 m_height = m_image->xim->height;
55
56 // Compute width and height in 32x32 tiles.
57 m_widthTiles = (m_width + 31) / 32;
58 m_heightTiles = (m_height + 31) / 32;
59
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000060 // Create two additional images used in the polling algorithm.
61 // FIXME: verify that these images use the same pixel format as in m_image.
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000062 m_rowImage = factory->newImage(m_dpy, m_width, 1);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000063 m_tileImage = factory->newImage(m_dpy, 32, 32);
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000064
65 // Create a matrix with one byte per each 32x32 tile. It will be
66 // used to limit the rate of updates on continuously-changed screen
67 // areas (like video).
68 int numTiles = m_widthTiles * m_heightTiles;
69 m_statusMatrix = new char[numTiles];
70 memset(m_statusMatrix, 0, numTiles);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000071}
72
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +000073PollingManager::~PollingManager()
74{
75 delete[] m_statusMatrix;
76}
77
78//
79// Register VNCServer object.
80//
81
82void PollingManager::setVNCServer(VNCServer *s)
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000083{
84 m_server = s;
85}
86
87//
88// DEBUG: a version of poll() measuring time spent in the function.
89//
90
91void PollingManager::pollDebug()
92{
93 struct timeval timeSaved, timeNow;
94 struct timezone tz;
95 timeSaved.tv_sec = 0;
96 timeSaved.tv_usec = 0;
97 gettimeofday(&timeSaved, &tz);
98
99 poll();
100
101 gettimeofday(&timeNow, &tz);
102 int diff = (int)((timeNow.tv_usec - timeSaved.tv_usec + 500) / 1000 +
103 (timeNow.tv_sec - timeSaved.tv_sec) * 1000);
104 if (diff != 0)
105 fprintf(stderr, "DEBUG: poll(): %4d ms\n", diff);
106}
107
108//
109// Search for changed rectangles on the screen.
110//
111
112void PollingManager::poll()
113{
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000114 switch((int)pollingType) {
115 case 0:
116 poll_Dumb();
117 break;
118 case 1:
119 poll_Traditional();
120 break;
121//case 2:
122 default:
123 poll_SkipCycles();
124 break;
125 }
126}
127
128void PollingManager::poll_SkipCycles()
129{
130 if (!m_server)
131 return;
132
133 enum {
134 NOT_CHANGED, CHANGED_ONCE, CHANGED_AGAIN
135 };
136
137 bool grandStep = (m_pollingStep % 8 == 0);
138
139 int nTilesChanged = 0;
140 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
141 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
142 int bytesPerLine = m_image->xim->bytes_per_line;
143 char *pstatus = m_statusMatrix;
144 bool wasChanged;
145 Rect rect;
146
147 for (int y = 0; y * 32 < m_height; y++) {
148 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
149 if (scanLine >= tile_h)
150 scanLine %= tile_h;
151 int scan_y = y * 32 + scanLine;
152 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
153 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
154 char *ptr_new = m_rowImage->xim->data;
155 for (int x = 0; x * 32 < m_width; x++) {
156 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
157 int nBytes = tile_w * bytesPerPixel;
158
159 if (grandStep || *pstatus != CHANGED_AGAIN) {
160 wasChanged = (*pstatus == CHANGED_AGAIN) ?
161 true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
162 if (wasChanged) {
163 if (grandStep || *pstatus == NOT_CHANGED) {
164 if (tile_w == 32 && tile_h == 32) {
165 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
166 } else {
167 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
168 tile_w, tile_h);
169 }
170 m_image->updateRect(m_tileImage, x * 32, y * 32);
171 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
172 m_server->add_changed(rect);
173 nTilesChanged++;
174 *pstatus = CHANGED_ONCE;
175 } else {
176 *pstatus = CHANGED_AGAIN;
177 }
178 } else if (grandStep) {
179 *pstatus = NOT_CHANGED;
180 }
181 }
182
183 ptr_old += nBytes;
184 ptr_new += nBytes;
185 pstatus++;
186 }
187 }
188
189 if (nTilesChanged)
190 m_server->tryUpdate();
191}
192
193void PollingManager::poll_Traditional()
194{
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000195 if (!m_server)
196 return;
197
198 int nTilesChanged = 0;
199 int scanLine = m_pollingOrder[m_pollingStep++ % 32];
200 int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
201 int bytesPerLine = m_image->xim->bytes_per_line;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000202 Rect rect;
203
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000204 for (int y = 0; y * 32 < m_height; y++) {
205 int tile_h = (m_height - y * 32 >= 32) ? 32 : m_height - y * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000206 if (scanLine >= tile_h)
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000207 break;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000208 int scan_y = y * 32 + scanLine;
209 m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
210 char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
211 char *ptr_new = m_rowImage->xim->data;
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000212 for (int x = 0; x * 32 < m_width; x++) {
213 int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000214 int nBytes = tile_w * bytesPerPixel;
215 if (memcmp(ptr_old, ptr_new, nBytes)) {
216 if (tile_w == 32 && tile_h == 32) {
217 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
218 } else {
219 m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
220 tile_w, tile_h);
221 }
222 m_image->updateRect(m_tileImage, x * 32, y * 32);
223 rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
224 m_server->add_changed(rect);
225 nTilesChanged++;
226 }
227 ptr_old += nBytes;
228 ptr_new += nBytes;
229 }
230 }
231
232 if (nTilesChanged)
233 m_server->tryUpdate();
234}
235
Constantin Kaplinsky14cd5472005-09-29 17:12:11 +0000236void PollingManager::poll_Dumb()
237{
238 if (m_server) {
239 m_image->get(DefaultRootWindow(m_dpy));
240 Rect rect(0, 0, m_width, m_height);
241 m_server->add_changed(rect);
242 m_server->tryUpdate();
243 }
244}