blob: e225119f57e95d7d72bd9d98eb1875d09569d026 [file] [log] [blame]
Pierre Ossman5156d5e2011-03-09 09:42:34 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20#include <assert.h>
21#include <stdio.h>
22#include <string.h>
23
24#include <FL/fl_draw.H>
25
26#include <rfb/CMsgWriter.h>
27#include <rfb/LogWriter.h>
28
29#include "DesktopWindow.h"
30#include "CConn.h"
31#include "i18n.h"
32#include "parameters.h"
33
34using namespace rfb;
35
36extern void exit_vncviewer();
37
38static rfb::LogWriter vlog("DesktopWindow");
39
40DesktopWindow::DesktopWindow(int w, int h, const char *name,
41 const rfb::PixelFormat& serverPF,
42 CConn* cc_)
Pierre Ossmanc266e5a2011-03-09 10:24:12 +000043 : Fl_Window(w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL),
44 lastPointerPos(0, 0), lastButtonMask(0)
Pierre Ossman5156d5e2011-03-09 09:42:34 +000045{
46 callback(handleClose, this);
47
48 setName(name);
49
50 frameBuffer = new ManagedPixelBuffer(getPreferredPF(), w, h);
51 assert(frameBuffer);
52
53 setServerPF(serverPF);
54
55 show();
56}
57
58
59DesktopWindow::~DesktopWindow()
60{
Pierre Ossman3d5d8a02011-03-09 11:53:08 +000061 // Unregister all timeouts in case they get a change tro trigger
62 // again later when this object is already gone.
63 Fl::remove_timeout(handleUpdateTimeout, this);
64 Fl::remove_timeout(handleColourMap, this);
65 Fl::remove_timeout(handlePointerTimeout, this);
66
Pierre Ossman5156d5e2011-03-09 09:42:34 +000067 delete frameBuffer;
68
69 if (pixelTrans)
70 delete pixelTrans;
71}
72
73
74void DesktopWindow::setServerPF(const rfb::PixelFormat& pf)
75{
76 if (pixelTrans)
77 delete pixelTrans;
78 pixelTrans = NULL;
79
80 if (pf.equal(getPreferredPF()))
81 return;
82
83 pixelTrans = new PixelTransformer();
84 pixelTrans->init(pf, &colourMap, getPreferredPF());
85}
86
87
88const rfb::PixelFormat &DesktopWindow::getPreferredPF()
89{
90 static PixelFormat prefPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
91
92 return prefPF;
93}
94
95
96// Cursor stuff
97
98void DesktopWindow::setCursor(int width, int height, const Point& hotspot,
99 void* data, void* mask)
100{
101}
102
103
104void DesktopWindow::setName(const char *name)
105{
106 CharArray windowNameStr;
107 windowNameStr.replaceBuf(new char[256]);
108
109 snprintf(windowNameStr.buf, 256, _("TigerVNC: %.240s"), name);
110
111 copy_label(windowNameStr.buf);
112}
113
114// setColourMapEntries() changes some of the entries in the colourmap.
115// Unfortunately these messages are often sent one at a time, so we delay the
116// settings taking effect by 100ms. This is because recalculating the internal
117// translation table can be expensive.
118void DesktopWindow::setColourMapEntries(int firstColour, int nColours,
119 rdr::U16* rgbs)
120{
121 for (int i = 0; i < nColours; i++)
122 colourMap.set(firstColour+i, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
123
124 if (!Fl::has_timeout(handleColourMap, this))
125 Fl::add_timeout(0.100, handleColourMap, this);
126}
127
128
129// Copy the areas of the framebuffer that have been changed (damaged)
130// to the displayed window.
131
132void DesktopWindow::updateWindow()
133{
134 Rect r;
135
136 Fl::remove_timeout(handleUpdateTimeout, this);
137
138 r = damage.get_bounding_rect();
139 Fl_Window::damage(FL_DAMAGE_USER1, r.tl.x, r.tl.y, r.width(), r.height());
140
141 damage.clear();
142}
143
144
145void DesktopWindow::draw()
146{
147 int X, Y, W, H;
148
149 int pixel_bytes, stride_bytes;
150 const uchar *buf_start;
151
152 // Check what actually needs updating
153 fl_clip_box(0, 0, w(), h(), X, Y, W, H);
154 if ((W == 0) || (H == 0))
155 return;
156
157 pixel_bytes = frameBuffer->getPF().bpp/8;
158 stride_bytes = pixel_bytes * frameBuffer->getStride();
159 buf_start = frameBuffer->data +
160 pixel_bytes * X +
161 stride_bytes * Y;
162
163 // FIXME: Check how efficient this thing really is
164 fl_draw_image(buf_start, X, Y, W, H, pixel_bytes, stride_bytes);
165}
166
167
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000168int DesktopWindow::handle(int event)
169{
170 int buttonMask, wheelMask;
171
172 switch (event) {
173 case FL_PUSH:
174 case FL_RELEASE:
175 case FL_DRAG:
176 case FL_MOVE:
177 case FL_MOUSEWHEEL:
178 buttonMask = 0;
179 if (Fl::event_button1())
180 buttonMask |= 1;
181 if (Fl::event_button2())
182 buttonMask |= 2;
183 if (Fl::event_button3())
184 buttonMask |= 4;
185
186 if (event == FL_MOUSEWHEEL) {
187 if (Fl::event_dy() < 0)
188 wheelMask = 8;
189 else
190 wheelMask = 16;
191
192 // A quick press of the wheel "button", followed by a immediate
193 // release below
194 handlePointerEvent(Point(Fl::event_x(), Fl::event_y()),
195 buttonMask | wheelMask);
196 }
197
198 handlePointerEvent(Point(Fl::event_x(), Fl::event_y()), buttonMask);
199 return 1;
200 }
201
202 return Fl_Window::handle(event);
203}
204
205
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000206void DesktopWindow::handleUpdateTimeout(void *data)
207{
208 DesktopWindow *self = (DesktopWindow *)data;
209
210 assert(self);
211
212 self->updateWindow();
213}
214
215
216void DesktopWindow::handleColourMap(void *data)
217{
218 DesktopWindow *self = (DesktopWindow *)data;
219
220 assert(self);
221
222 if (self->pixelTrans != NULL)
223 self->pixelTrans->setColourMapEntries(0, 0);
224
225 self->Fl_Window::damage(FL_DAMAGE_ALL);
226}
227
228void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
229{
230 exit_vncviewer();
231}
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000232
233
234void DesktopWindow::handlePointerEvent(const rfb::Point& pos, int buttonMask)
235{
236 if (!viewOnly) {
237 if (pointerEventInterval == 0 || buttonMask != lastButtonMask) {
238 cc->writer()->pointerEvent(pos, buttonMask);
239 } else {
240 if (!Fl::has_timeout(handlePointerTimeout, this))
241 Fl::add_timeout((double)pointerEventInterval/1000.0,
242 handlePointerTimeout, this);
243 }
244 lastPointerPos = pos;
245 lastButtonMask = buttonMask;
246 }
247}
248
249
250void DesktopWindow::handlePointerTimeout(void *data)
251{
252 DesktopWindow *self = (DesktopWindow *)data;
253
254 assert(self);
255
Pierre Ossmane21ae3d2011-03-09 11:44:24 +0000256 self->cc->writer()->pointerEvent(self->lastPointerPos, self->lastButtonMask);
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000257}