diff options
Diffstat (limited to 'vncviewer/DesktopWindow.cxx')
-rw-r--r-- | vncviewer/DesktopWindow.cxx | 155 |
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); +} |