blob: d0cf014ce31287c839cfc09dc1945fde7a145716 [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{
61 delete frameBuffer;
62
63 if (pixelTrans)
64 delete pixelTrans;
65}
66
67
68void DesktopWindow::setServerPF(const rfb::PixelFormat& pf)
69{
70 if (pixelTrans)
71 delete pixelTrans;
72 pixelTrans = NULL;
73
74 if (pf.equal(getPreferredPF()))
75 return;
76
77 pixelTrans = new PixelTransformer();
78 pixelTrans->init(pf, &colourMap, getPreferredPF());
79}
80
81
82const rfb::PixelFormat &DesktopWindow::getPreferredPF()
83{
84 static PixelFormat prefPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
85
86 return prefPF;
87}
88
89
90// Cursor stuff
91
92void DesktopWindow::setCursor(int width, int height, const Point& hotspot,
93 void* data, void* mask)
94{
95}
96
97
98void DesktopWindow::setName(const char *name)
99{
100 CharArray windowNameStr;
101 windowNameStr.replaceBuf(new char[256]);
102
103 snprintf(windowNameStr.buf, 256, _("TigerVNC: %.240s"), name);
104
105 copy_label(windowNameStr.buf);
106}
107
108// setColourMapEntries() changes some of the entries in the colourmap.
109// Unfortunately these messages are often sent one at a time, so we delay the
110// settings taking effect by 100ms. This is because recalculating the internal
111// translation table can be expensive.
112void DesktopWindow::setColourMapEntries(int firstColour, int nColours,
113 rdr::U16* rgbs)
114{
115 for (int i = 0; i < nColours; i++)
116 colourMap.set(firstColour+i, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
117
118 if (!Fl::has_timeout(handleColourMap, this))
119 Fl::add_timeout(0.100, handleColourMap, this);
120}
121
122
123// Copy the areas of the framebuffer that have been changed (damaged)
124// to the displayed window.
125
126void DesktopWindow::updateWindow()
127{
128 Rect r;
129
130 Fl::remove_timeout(handleUpdateTimeout, this);
131
132 r = damage.get_bounding_rect();
133 Fl_Window::damage(FL_DAMAGE_USER1, r.tl.x, r.tl.y, r.width(), r.height());
134
135 damage.clear();
136}
137
138
139void DesktopWindow::draw()
140{
141 int X, Y, W, H;
142
143 int pixel_bytes, stride_bytes;
144 const uchar *buf_start;
145
146 // Check what actually needs updating
147 fl_clip_box(0, 0, w(), h(), X, Y, W, H);
148 if ((W == 0) || (H == 0))
149 return;
150
151 pixel_bytes = frameBuffer->getPF().bpp/8;
152 stride_bytes = pixel_bytes * frameBuffer->getStride();
153 buf_start = frameBuffer->data +
154 pixel_bytes * X +
155 stride_bytes * Y;
156
157 // FIXME: Check how efficient this thing really is
158 fl_draw_image(buf_start, X, Y, W, H, pixel_bytes, stride_bytes);
159}
160
161
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000162int DesktopWindow::handle(int event)
163{
164 int buttonMask, wheelMask;
165
166 switch (event) {
167 case FL_PUSH:
168 case FL_RELEASE:
169 case FL_DRAG:
170 case FL_MOVE:
171 case FL_MOUSEWHEEL:
172 buttonMask = 0;
173 if (Fl::event_button1())
174 buttonMask |= 1;
175 if (Fl::event_button2())
176 buttonMask |= 2;
177 if (Fl::event_button3())
178 buttonMask |= 4;
179
180 if (event == FL_MOUSEWHEEL) {
181 if (Fl::event_dy() < 0)
182 wheelMask = 8;
183 else
184 wheelMask = 16;
185
186 // A quick press of the wheel "button", followed by a immediate
187 // release below
188 handlePointerEvent(Point(Fl::event_x(), Fl::event_y()),
189 buttonMask | wheelMask);
190 }
191
192 handlePointerEvent(Point(Fl::event_x(), Fl::event_y()), buttonMask);
193 return 1;
194 }
195
196 return Fl_Window::handle(event);
197}
198
199
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000200void DesktopWindow::handleUpdateTimeout(void *data)
201{
202 DesktopWindow *self = (DesktopWindow *)data;
203
204 assert(self);
205
206 self->updateWindow();
207}
208
209
210void DesktopWindow::handleColourMap(void *data)
211{
212 DesktopWindow *self = (DesktopWindow *)data;
213
214 assert(self);
215
216 if (self->pixelTrans != NULL)
217 self->pixelTrans->setColourMapEntries(0, 0);
218
219 self->Fl_Window::damage(FL_DAMAGE_ALL);
220}
221
222void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
223{
224 exit_vncviewer();
225}
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000226
227
228void DesktopWindow::handlePointerEvent(const rfb::Point& pos, int buttonMask)
229{
230 if (!viewOnly) {
231 if (pointerEventInterval == 0 || buttonMask != lastButtonMask) {
232 cc->writer()->pointerEvent(pos, buttonMask);
233 } else {
234 if (!Fl::has_timeout(handlePointerTimeout, this))
235 Fl::add_timeout((double)pointerEventInterval/1000.0,
236 handlePointerTimeout, this);
237 }
238 lastPointerPos = pos;
239 lastButtonMask = buttonMask;
240 }
241}
242
243
244void DesktopWindow::handlePointerTimeout(void *data)
245{
246 DesktopWindow *self = (DesktopWindow *)data;
247
248 assert(self);
249
Pierre Ossmane21ae3d2011-03-09 11:44:24 +0000250 self->cc->writer()->pointerEvent(self->lastPointerPos, self->lastButtonMask);
Pierre Ossmanc266e5a2011-03-09 10:24:12 +0000251}