summaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-01-03 16:12:30 +0100
committerPierre Ossman <ossman@cendio.se>2017-02-10 17:00:04 +0100
commit13548819fa30b58f8d007a367d48934c7f064914 (patch)
tree8eef07e8dbae0aa20b7c742386808fff551e034e /vncviewer
parent5b092766fcc0e476d2f6563a54ab706e97c7e970 (diff)
downloadtigervnc-13548819fa30b58f8d007a367d48934c7f064914.tar.gz
tigervnc-13548819fa30b58f8d007a367d48934c7f064914.zip
Handle scrolling manually
Stop fighting with the FLTK scroll widget and handle layout ourselves. This opens up the possibility of doing more complex drawing as well.
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/DesktopWindow.cxx193
-rw-r--r--vncviewer/DesktopWindow.h9
2 files changed, 146 insertions, 56 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 2787bee3..707628ee 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -37,7 +37,8 @@
#include "Viewport.h"
#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Scrollbar.H>
+#include <FL/fl_draw.H>
#include <FL/x.H>
#ifdef WIN32
@@ -61,15 +62,23 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
: Fl_Window(w, h), cc(cc_), firstUpdate(true),
delayedFullscreen(false), delayedDesktopSize(false)
{
- scroll = new Fl_Scroll(0, 0, w, h);
- scroll->color(FL_BLACK);
+ Fl_Group* group;
- // Automatically adjust the scroll box to the window
- resizable(scroll);
+ // Dummy group to prevent FLTK from moving our widgets around
+ group = new Fl_Group(0, 0, w, h);
+ group->resizable(NULL);
+ resizable(group);
viewport = new Viewport(w, h, serverPF, cc);
- scroll->end();
+ // Position will be adjusted later
+ hscroll = new Fl_Scrollbar(0, 0, 0, 0);
+ vscroll = new Fl_Scrollbar(0, 0, 0, 0);
+ hscroll->type(FL_HORIZONTAL);
+ hscroll->callback(handleScroll, this);
+ vscroll->callback(handleScroll, this);
+
+ group->end();
callback(handleClose, this);
@@ -150,11 +159,8 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
}
#endif
- // The window manager might give us an initial window size that is different
- // than the one we requested, and in those cases we need to manually adjust
- // the scroll widget for things to behave sanely.
- if ((w != this->w()) || (h != this->h()))
- scroll->size(this->w(), this->h());
+ // Adjust layout now that we're visible and know our final size
+ repositionWidgets();
if (delayedFullscreen) {
// Hack: Fullscreen requests may be ignored, so we need a timeout for
@@ -242,14 +248,7 @@ void DesktopWindow::resizeFramebuffer(int new_w, int new_h)
viewport->size(new_w, new_h);
- // We might not resize the main window, so we need to manually call this
- // to make sure the viewport is centered.
- repositionViewport();
-
- // repositionViewport() makes sure the scroll widget notices any changes
- // in position, but it might be just the size that changes so we also
- // need a poke here as well.
- redraw();
+ repositionWidgets();
}
@@ -260,6 +259,57 @@ void DesktopWindow::setCursor(int width, int height, const Point& hotspot,
}
+void DesktopWindow::draw()
+{
+ bool redraw;
+
+ int W, H;
+
+ // Active area inside scrollbars
+ W = w() - (vscroll->visible() ? vscroll->w() : 0);
+ H = h() - (hscroll->visible() ? hscroll->h() : 0);
+
+ // Full redraw?
+ redraw = (damage() & ~FL_DAMAGE_CHILD);
+
+ // Redraw background only on full redraws
+ if (redraw) {
+ if (viewport->h() < h()) {
+ fl_rectf(0, 0, W, viewport->y(), 40, 40, 40);
+ fl_rectf(0, viewport->y() + viewport->h(), W,
+ h() - (viewport->y() + viewport->h()),
+ 40, 40, 40);
+ }
+ if (viewport->w() < w()) {
+ fl_rectf(0, 0, viewport->x(), H, 40, 40, 40);
+ fl_rectf(viewport->x() + viewport->w(), 0,
+ w() - (viewport->x() + viewport->w()),
+ H, 40, 40, 40);
+ }
+ }
+
+ // Make sure the viewport isn't trampling on the scrollbars
+ fl_push_clip(0, 0, W, H);
+
+ if (redraw)
+ draw_child(*viewport);
+ else
+ update_child(*viewport);
+
+ fl_pop_clip();
+
+ // Finally the scrollbars
+
+ if (redraw) {
+ draw_child(*hscroll);
+ draw_child(*vscroll);
+ } else {
+ update_child(*hscroll);
+ update_child(*vscroll);
+ }
+}
+
+
void DesktopWindow::resize(int x, int y, int w, int h)
{
bool resizing;
@@ -334,8 +384,7 @@ void DesktopWindow::resize(int x, int y, int w, int h)
Fl::add_timeout(0.5, handleResizeTimeout, this);
}
- // Deal with some scrolling corner cases
- repositionViewport();
+ repositionWidgets();
}
}
@@ -346,15 +395,8 @@ int DesktopWindow::handle(int event)
case FL_FULLSCREEN:
fullScreen.setParam(fullscreen_active());
- if (fullscreen_active())
- scroll->type(0);
- else
- scroll->type(Fl_Scroll::BOTH);
-
- // The scroll widget isn't clever enough to actually redraw the
- // scroll bars when they are added/removed, so we need to give
- // it a push.
- scroll->redraw();
+ // Update scroll bars
+ repositionWidgets();
if (!fullscreenSystemKeys)
break;
@@ -751,17 +793,11 @@ void DesktopWindow::remoteResize(int width, int height)
}
-void DesktopWindow::repositionViewport()
+void DesktopWindow::repositionWidgets()
{
int new_x, new_y;
- // Deal with some scrolling corner cases:
- //
- // a) If the window is larger then the viewport, center the viewport.
- // b) If the window is smaller than the viewport, make sure there is
- // no wasted space on the sides.
- //
- // FIXME: Doesn't compensate for scroll widget size properly.
+ // Viewport position
new_x = viewport->x();
new_y = viewport->y();
@@ -787,11 +823,40 @@ void DesktopWindow::repositionViewport()
if ((new_x != viewport->x()) || (new_y != viewport->y())) {
viewport->position(new_x, new_y);
-
- // The scroll widget does not notice when you move around child widgets,
- // so redraw everything to make sure things update.
- redraw();
+ damage(FL_DAMAGE_SCROLL);
}
+
+ // Scrollbars visbility
+
+ if (!fullscreen_active() && (w() < viewport->w()))
+ hscroll->show();
+ else
+ hscroll->hide();
+
+ if (!fullscreen_active() && (h() < viewport->h()))
+ vscroll->show();
+ else
+ vscroll->hide();
+
+ // Scrollbars positions
+
+ hscroll->resize(0, h() - Fl::scrollbar_size(),
+ w() - (vscroll->visible() ? Fl::scrollbar_size() : 0),
+ Fl::scrollbar_size());
+ vscroll->resize(w() - Fl::scrollbar_size(), 0,
+ Fl::scrollbar_size(),
+ h() - (hscroll->visible() ? Fl::scrollbar_size() : 0));
+
+ // Scrollbars range
+
+ hscroll->value(-viewport->x(),
+ w() - (vscroll->visible() ? vscroll->w() : 0),
+ 0, viewport->w());
+ vscroll->value(-viewport->y(),
+ h() - (hscroll->visible() ? hscroll->h() : 0),
+ 0, viewport->h());
+ hscroll->value(hscroll->clamp(hscroll->value()));
+ vscroll->value(vscroll->clamp(vscroll->value()));
}
void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
@@ -829,6 +894,38 @@ void DesktopWindow::handleFullscreenTimeout(void *data)
}
}
+void DesktopWindow::scrollTo(int x, int y)
+{
+ x = hscroll->clamp(x);
+ y = vscroll->clamp(y);
+
+ hscroll->value(x);
+ vscroll->value(y);
+
+ if (!hscroll->visible())
+ x = -viewport->x();
+ if (!vscroll->visible())
+ y = -viewport->y();
+
+ // Scrollbar position results in inverse movement of
+ // the viewport widget
+ x = -x;
+ y = -y;
+
+ if ((viewport->x() == x) && (viewport->y() == y))
+ return;
+
+ viewport->position(x, y);
+ damage(FL_DAMAGE_SCROLL);
+}
+
+void DesktopWindow::handleScroll(Fl_Widget *widget, void *data)
+{
+ DesktopWindow *self = (DesktopWindow *)data;
+
+ self->scrollTo(self->hscroll->value(), self->vscroll->value());
+}
+
void DesktopWindow::handleEdgeScroll(void *data)
{
DesktopWindow *self = (DesktopWindow *)data;
@@ -874,17 +971,7 @@ void DesktopWindow::handleEdgeScroll(void *data)
if ((dx == 0) && (dy == 0))
return;
- // Make sure we don't move the viewport too much
- if (self->viewport->x() + dx > 0)
- dx = -self->viewport->x();
- if (self->viewport->x() + dx + self->viewport->w() < self->w())
- dx = self->w() - (self->viewport->x() + self->viewport->w());
- if (self->viewport->y() + dy > 0)
- dy = -self->viewport->y();
- if (self->viewport->y() + dy + self->viewport->h() < self->h())
- dy = self->h() - (self->viewport->y() + self->viewport->h());
-
- self->scroll->scroll_to(self->scroll->xposition() - dx, self->scroll->yposition() - dy);
+ self->scrollTo(self->hscroll->value() + dx, self->vscroll->value() + dy);
Fl::repeat_timeout(0.1, handleEdgeScroll, data);
}
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index d755b6dd..d0e2eae4 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -32,7 +32,7 @@ namespace rfb { class ModifiablePixelBuffer; }
class CConn;
class Viewport;
-class Fl_Scroll;
+class Fl_Scrollbar;
class DesktopWindow : public Fl_Window {
public:
@@ -58,6 +58,7 @@ public:
void* data, void* mask);
// Fl_Window callback methods
+ void draw();
void resize(int x, int y, int w, int h);
int handle(int event);
@@ -78,7 +79,7 @@ private:
static void handleResizeTimeout(void *data);
void remoteResize(int width, int height);
- void repositionViewport();
+ void repositionWidgets();
static void handleClose(Fl_Widget *wnd, void *data);
@@ -86,11 +87,13 @@ private:
static void handleFullscreenTimeout(void *data);
+ void scrollTo(int x, int y);
+ static void handleScroll(Fl_Widget *wnd, void *data);
static void handleEdgeScroll(void *data);
private:
CConn* cc;
- Fl_Scroll *scroll;
+ Fl_Scrollbar *hscroll, *vscroll;
Viewport *viewport;
bool firstUpdate;