summaryrefslogtreecommitdiffstats
path: root/vncviewer/DesktopWindow.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer/DesktopWindow.cxx')
-rw-r--r--vncviewer/DesktopWindow.cxx155
1 files changed, 154 insertions, 1 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 8fdd59b7..1f0f55f2 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -64,7 +64,9 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
CConn* cc_)
: Fl_Window(w, h), cc(cc_), offscreen(NULL), overlay(NULL),
firstUpdate(true),
- delayedFullscreen(false), delayedDesktopSize(false)
+ delayedFullscreen(false), delayedDesktopSize(false),
+ statsLastFrame(0), statsLastPixels(0), statsLastPosition(0),
+ statsGraph(NULL)
{
Fl_Group* group;
@@ -174,6 +176,12 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
fullscreen_on();
}
+ // Throughput graph for debugging
+ if (vlog.getLevel() >= LogWriter::LEVEL_DEBUG) {
+ memset(&stats, 0, sizeof(stats));
+ Fl::add_timeout(0, handleStatsTimeout, this);
+ }
+
// Show hint about menu key
Fl::add_timeout(0.5, menuOverlay, this);
}
@@ -187,6 +195,7 @@ DesktopWindow::~DesktopWindow()
Fl::remove_timeout(handleResizeTimeout, this);
Fl::remove_timeout(handleFullscreenTimeout, this);
Fl::remove_timeout(handleEdgeScroll, this);
+ Fl::remove_timeout(handleStatsTimeout, this);
Fl::remove_timeout(menuOverlay, this);
Fl::remove_timeout(updateOverlay, this);
@@ -195,6 +204,8 @@ DesktopWindow::~DesktopWindow()
delete overlay;
delete offscreen;
+ delete statsGraph;
+
// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
}
@@ -325,6 +336,23 @@ void DesktopWindow::draw()
update_child(*viewport);
}
+ // Debug graph (if active)
+ if (statsGraph) {
+ int ox, oy, ow, oh;
+
+ ox = X = w() - statsGraph->width() - 30;
+ oy = Y = h() - statsGraph->height() - 30;
+ ow = statsGraph->width();
+ oh = statsGraph->height();
+
+ fl_clip_box(ox, oy, ow, oh, ox, oy, ow, oh);
+
+ if (offscreen)
+ statsGraph->blend(offscreen, ox - X, oy - Y, ox, oy, ow, oh, 204);
+ else
+ statsGraph->blend(ox - X, oy - Y, ox, oy, ow, oh, 204);
+ }
+
// Overlay (if active)
if (overlay) {
int ox, oy, ow, oh;
@@ -1161,3 +1189,128 @@ void DesktopWindow::handleEdgeScroll(void *data)
Fl::repeat_timeout(0.1, handleEdgeScroll, data);
}
+
+void DesktopWindow::handleStatsTimeout(void *data)
+{
+ DesktopWindow *self = (DesktopWindow*)data;
+
+ const size_t statsCount = sizeof(stats)/sizeof(stats[0]);
+
+ unsigned frame, pixels, pos;
+ unsigned elapsed;
+
+ const unsigned statsWidth = 200;
+ const unsigned statsHeight = 100;
+ const unsigned graphWidth = statsWidth - 10;
+ const unsigned graphHeight = statsHeight - 25;
+
+ Fl_Image_Surface *surface;
+ Fl_RGB_Image *image;
+
+ unsigned maxFPS, maxPPS, maxBPS;
+ size_t i;
+
+ char buffer[256];
+
+ frame = self->cc->getFrameCount();
+ pixels = self->cc->getPixelCount();
+ pos = self->cc->getPosition();
+ elapsed = msSince(&self->statsLastTime);
+ if (elapsed < 1)
+ elapsed = 1;
+
+ memmove(&self->stats[0], &self->stats[1], sizeof(stats[0])*(statsCount-1));
+
+ self->stats[statsCount-1].fps = (frame - self->statsLastFrame) * 1000 / elapsed;
+ self->stats[statsCount-1].pps = (pixels - self->statsLastPixels) * 1000 / elapsed;
+ self->stats[statsCount-1].bps = (pos - self->statsLastPosition) * 1000 / elapsed;
+
+ gettimeofday(&self->statsLastTime, NULL);
+ self->statsLastFrame = frame;
+ self->statsLastPixels = pixels;
+ self->statsLastPosition = pos;
+
+#if !defined(WIN32) && !defined(__APPLE__)
+ // FLTK < 1.3.5 crashes if fl_gc is unset
+ if (!fl_gc)
+ fl_gc = XDefaultGC(fl_display, 0);
+#endif
+
+ surface = new Fl_Image_Surface(statsWidth, statsHeight);
+ surface->set_current();
+
+ fl_rectf(0, 0, statsWidth, statsHeight, FL_BLACK);
+
+ fl_rect(5, 5, graphWidth, graphHeight, FL_WHITE);
+
+ maxFPS = maxPPS = maxBPS = 0;
+ for (i = 0;i < statsCount;i++) {
+ if (self->stats[i].fps > maxFPS)
+ maxFPS = self->stats[i].fps;
+ if (self->stats[i].pps > maxPPS)
+ maxPPS = self->stats[i].pps;
+ if (self->stats[i].bps > maxBPS)
+ maxBPS = self->stats[i].bps;
+ }
+
+ if (maxFPS != 0) {
+ fl_color(FL_GREEN);
+ for (i = 0;i < statsCount-1;i++) {
+ fl_line(5 + i * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i].fps / maxFPS,
+ 5 + (i+1) * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i+1].fps / maxFPS);
+ }
+ }
+
+ if (maxPPS != 0) {
+ fl_color(FL_YELLOW);
+ for (i = 0;i < statsCount-1;i++) {
+ fl_line(5 + i * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i].pps / maxPPS,
+ 5 + (i+1) * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i+1].pps / maxPPS);
+ }
+ }
+
+ if (maxBPS != 0) {
+ fl_color(FL_RED);
+ for (i = 0;i < statsCount-1;i++) {
+ fl_line(5 + i * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i].bps / maxBPS,
+ 5 + (i+1) * graphWidth / statsCount,
+ 5 + graphHeight - graphHeight * self->stats[i+1].bps / maxBPS);
+ }
+ }
+
+ fl_font(FL_HELVETICA, 10);
+
+ fl_color(FL_GREEN);
+ snprintf(buffer, sizeof(buffer), "%u fps", self->stats[statsCount-1].fps);
+ fl_draw(buffer, 5, statsHeight - 5);
+
+ fl_color(FL_YELLOW);
+ siPrefix(self->stats[statsCount-1].pps * 8, "pix/s",
+ buffer, sizeof(buffer), 3);
+ fl_draw(buffer, 5 + (statsWidth-10)/3, statsHeight - 5);
+
+ fl_color(FL_RED);
+ iecPrefix(self->stats[statsCount-1].bps * 8, "Bps",
+ buffer, sizeof(buffer), 3);
+ fl_draw(buffer, 5 + (statsWidth-10)*2/3, statsHeight - 5);
+
+ image = surface->image();
+ delete surface;
+
+ Fl_Display_Device::display_device()->set_current();
+
+ delete self->statsGraph;
+ self->statsGraph = new Surface(image);
+ delete image;
+
+ self->damage(FL_DAMAGE_CHILD, self->w() - statsWidth - 30,
+ self->h() - statsHeight - 30,
+ statsWidth, statsHeight);
+
+ Fl::repeat_timeout(0.5, handleStatsTimeout, data);
+}