Merge branches 'format-security' and 'module-ldnow-master' of https://github.com/twaugh/tigervnc
diff --git a/tests/encperf.cxx b/tests/encperf.cxx
index 60905c8..2628b46 100644
--- a/tests/encperf.cxx
+++ b/tests/encperf.cxx
@@ -1,15 +1,16 @@
/* Copyright 2015 Pierre Ossman <ossman@cendio.se> for Cendio AB
- *
+ * Copyright (C) 2015 D. R. Commander. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
@@ -48,9 +49,14 @@
static rfb::IntParameter width("width", "Frame buffer width", 0);
static rfb::IntParameter height("height", "Frame buffer height", 0);
+static rfb::IntParameter count("count", "Number of benchmark iterations", 9);
static rfb::StringParameter format("format", "Pixel format (e.g. bgr888)", "");
+static rfb::BoolParameter translate("translate",
+ "Translate 8-bit and 16-bit datasets into 24-bit",
+ true);
+
// The frame buffer (and output) is always this format
static const rfb::PixelFormat fbPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
@@ -58,7 +64,8 @@
static const rdr::S32 encodings[] = {
rfb::encodingTight, rfb::encodingCopyRect, rfb::encodingRRE,
rfb::encodingHextile, rfb::encodingZRLE, rfb::pseudoEncodingLastRect,
- rfb::pseudoEncodingQualityLevel0 + 8 };
+ rfb::pseudoEncodingQualityLevel0 + 8,
+ rfb::pseudoEncodingCompressLevel0 + 2};
class DummyOutStream : public rdr::OutStream {
public:
@@ -79,7 +86,8 @@
CConn(const char *filename);
~CConn();
- double getRatio();
+ void getStats(double& ratio, unsigned long long& bytes,
+ unsigned long long& rawEquivalent);
virtual void setDesktopSize(int w, int h);
virtual void setCursor(int, int, const rfb::Point&, void*, void*);
@@ -96,7 +104,7 @@
protected:
rdr::FileInStream *in;
- rfb::Decoder *decoders[rfb::encodingMax+1];
+ rfb::Decoder *decoders[rfb::encodingMax + 1];
rfb::ManagedPixelBuffer pb;
rfb::SimpleUpdateTracker updates;
class SConn *sc;
@@ -106,7 +114,7 @@
public:
Manager(class rfb::SConnection *conn);
- double getRatio();
+ void getStats(double&, unsigned long long&, unsigned long long&);
};
class SConn : public rfb::SConnection {
@@ -116,7 +124,7 @@
void writeUpdate(const rfb::UpdateInfo& ui, const rfb::PixelBuffer* pb);
- double getRatio();
+ void getStats(double&, unsigned long long&, unsigned long long&);
virtual void setAccessRights(AccessRights ar);
@@ -163,15 +171,13 @@
setStreams(in, NULL);
memset(decoders, 0, sizeof(decoders));
- for (i = 0;i < rfb::encodingMax;i++) {
+ for (i = 0; i < rfb::encodingMax; i++) {
if (!rfb::Decoder::supported(i))
continue;
decoders[i] = rfb::Decoder::createDecoder(i, this);
}
- pb.setPF(fbPF);
-
// Need to skip the initial handshake and ServerInit
setState(RFBSTATE_NORMAL);
// That also means that the reader and writer weren't setup
@@ -182,9 +188,11 @@
pf.parse(format);
setPixelFormat(pf);
+ pb.setPF((bool)translate ? fbPF : pf);
+
sc = new SConn();
sc->cp.setPF(pb.getPF());
- sc->setEncodings(sizeof(encodings)/sizeof(*encodings), encodings);
+ sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
}
CConn::~CConn()
@@ -195,13 +203,14 @@
delete in;
- for (i = 0;i < rfb::encodingMax;i++)
+ for (i = 0; i < rfb::encodingMax; i++)
delete decoders[i];
}
-double CConn::getRatio()
+void CConn::getStats(double& ratio, unsigned long long& bytes,
+ unsigned long long& rawEquivalent)
{
- return sc->getRatio();
+ sc->getStats(ratio, bytes, rawEquivalent);
}
void CConn::setDesktopSize(int w, int h)
@@ -266,21 +275,24 @@
{
}
-double Manager::getRatio()
+void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
+ unsigned long long& rawEquivalent)
{
StatsVector::iterator iter;
unsigned long long bytes, equivalent;
bytes = equivalent = 0;
- for (iter = stats.begin();iter != stats.end();++iter) {
+ for (iter = stats.begin(); iter != stats.end(); ++iter) {
StatsVector::value_type::iterator iter2;
- for (iter2 = iter->begin();iter2 != iter->end();++iter2) {
+ for (iter2 = iter->begin(); iter2 != iter->end(); ++iter2) {
bytes += iter2->bytes;
equivalent += iter2->equivalent;
}
}
- return (double)equivalent / bytes;
+ ratio = (double)equivalent / bytes;
+ encodedBytes = bytes;
+ rawEquivalent = equivalent;
}
SConn::SConn()
@@ -304,9 +316,10 @@
manager->writeUpdate(ui, pb, NULL);
}
-double SConn::getRatio()
+void SConn::getStats(double& ratio, unsigned long long& bytes,
+ unsigned long long& rawEquivalent)
{
- return manager->getRatio();
+ manager->getStats(ratio, bytes, rawEquivalent);
}
void SConn::setAccessRights(AccessRights ar)
@@ -318,7 +331,8 @@
{
}
-static double runTest(const char *fn, double *ratio)
+static double runTest(const char *fn, double& ratio, unsigned long long& bytes,
+ unsigned long long& rawEquivalent)
{
CConn *cc;
double time;
@@ -335,7 +349,7 @@
}
time = cc->encodeTime;
- *ratio = cc->getRatio();
+ cc->getStats(ratio, bytes, rawEquivalent);
delete cc;
@@ -348,20 +362,18 @@
int i;
do {
sorted = true;
- for (i = 1;i < count;i++) {
+ for (i = 1; i < count; i++) {
if (array[i-1] > array[i]) {
double d;
d = array[i];
- array[i] = array[i-1];
- array[i-1] = d;
+ array[i] = array[i - 1];
+ array[i - 1] = d;
sorted = false;
}
}
} while (!sorted);
}
-static const int runCount = 9;
-
static void usage(const char *argv0)
{
fprintf(stderr, "Syntax: %s [options] <rfb file>\n", argv0);
@@ -376,17 +388,14 @@
const char *fn;
- double times[runCount], dev[runCount];
- double median, meddev, ratio;
-
fn = NULL;
for (i = 1; i < argc; i++) {
if (rfb::Configuration::setParam(argv[i]))
continue;
if (argv[i][0] == '-') {
- if (i+1 < argc) {
- if (rfb::Configuration::setParam(&argv[i][1], argv[i+1])) {
+ if (i + 1 < argc) {
+ if (rfb::Configuration::setParam(&argv[i][1], argv[i + 1])) {
i++;
continue;
}
@@ -400,6 +409,11 @@
fn = argv[i];
}
+ int runCount = count;
+ double times[runCount], dev[runCount];
+ double median, meddev, ratio;
+ unsigned long long bytes, equivalent;
+
if (fn == NULL) {
fprintf(stderr, "No file specified!\n\n");
usage(argv[0]);
@@ -416,23 +430,25 @@
}
// Warmup
- runTest(fn, &ratio);
+ runTest(fn, ratio, bytes, equivalent);
// Multiple runs to get a good average
- for (i = 0;i < runCount;i++)
- times[i] = runTest(fn, &ratio);
+ for (i = 0; i < runCount; i++)
+ times[i] = runTest(fn, ratio, bytes, equivalent);
// Calculate median and median deviation
sort(times, runCount);
- median = times[runCount/2];
+ median = times[runCount / 2];
- for (i = 0;i < runCount;i++)
+ for (i = 0; i < runCount; i++)
dev[i] = fabs((times[i] - median) / median) * 100;
sort(dev, runCount);
- meddev = dev[runCount/2];
+ meddev = dev[runCount / 2];
- printf("CPU time: %g s (+/- %g %)\n", median, meddev);
+ printf("CPU time: %g s (+/- %g %%)\n", median, meddev);
+ printf("Encoded bytes: %lld\n", bytes);
+ printf("Raw equivalent bytes: %lld\n", equivalent);
printf("Ratio: %g\n", ratio);
return 0;
diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am
index ab8becb..7940f1b 100644
--- a/unix/xserver/hw/vnc/Makefile.am
+++ b/unix/xserver/hw/vnc/Makefile.am
@@ -62,7 +62,7 @@
-I$(top_srcdir)/include \
${XSERVERLIBS_CFLAGS} -I$(includedir)
-libvnc_la_LDFLAGS = -module -avoid-version
+libvnc_la_LDFLAGS = -module -avoid-version -Wl,-z,now
libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS)
diff --git a/unix/xserver/hw/vnc/xorg-version.h b/unix/xserver/hw/vnc/xorg-version.h
index 057c31e..083c1b1 100644
--- a/unix/xserver/hw/vnc/xorg-version.h
+++ b/unix/xserver/hw/vnc/xorg-version.h
@@ -48,8 +48,10 @@
#define XORG 115
#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (16 * 100000) + (99 * 1000))
#define XORG 116
+#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (17 * 100000) + (99 * 1000))
+#define XORG 117
#else
-#error "X.Org newer than 1.16 is not supported"
+#error "X.Org newer than 1.17 is not supported"
#endif
#endif
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 04dd0b9..cc87efb 100644
--- a/unix/xserver/hw/vnc/xvnc.c
+++ b/unix/xserver/hw/vnc/xvnc.c
@@ -87,11 +87,6 @@
#endif
#include "site.h"
-#if XORG >= 110
-#define Xalloc malloc
-#define Xfree free
-#endif
-
#define XVNCVERSION "TigerVNC 1.4.80"
#define XVNCCOPYRIGHT ("Copyright (C) 1999-2015 TigerVNC Team and many others (see README.txt)\n" \
"See http://www.tigervnc.org for information on TigerVNC.\n")
@@ -346,6 +341,13 @@
return TRUE;
}
+#define fail_unless_args(_argc,_i,_n) \
+ if (_i + _n >= _argc) \
+ { \
+ UseMsg(); \
+ return 0; \
+ }
+
int
ddxProcessArgument(int argc, char *argv[], int i)
{
@@ -365,12 +367,13 @@
if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */
{
int screenNum;
- if (i + 2 >= argc) UseMsg();
+ fail_unless_args(argc, i, 2);
screenNum = atoi(argv[i+1]);
if (screenNum < 0 || screenNum >= MAXSCREENS)
{
ErrorF("Invalid screen number %d\n", screenNum);
UseMsg();
+ return 0;
}
if (3 != sscanf(argv[i+2], "%dx%dx%d",
&vfbScreens[screenNum].fb.width,
@@ -379,6 +382,7 @@
{
ErrorF("Invalid screen configuration %s\n", argv[i+2]);
UseMsg();
+ return 0;
}
if (screenNum >= vfbNumScreens)
@@ -391,13 +395,15 @@
{
int depth, ret = 1;
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
while ((i < argc) && (depth = atoi(argv[i++])) != 0)
{
if (depth < 0 || depth > 32)
{
ErrorF("Invalid pixmap depth %d\n", depth);
UseMsg();
+ return 0;
}
vfbPixmapDepths[depth] = TRUE;
ret++;
@@ -420,7 +426,8 @@
if (strcmp (argv[i], "-blackpixel") == 0) /* -blackpixel n */
{
Pixel pix;
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
pix = atoi(argv[i]);
if (-1 == lastScreen)
{
@@ -440,7 +447,8 @@
if (strcmp (argv[i], "-whitepixel") == 0) /* -whitepixel n */
{
Pixel pix;
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
pix = atoi(argv[i]);
if (-1 == lastScreen)
{
@@ -460,7 +468,8 @@
if (strcmp (argv[i], "-linebias") == 0) /* -linebias n */
{
unsigned int linebias;
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
linebias = atoi(argv[i]);
if (-1 == lastScreen)
{
@@ -487,18 +496,21 @@
if (strcmp(argv[i], "-geometry") == 0)
{
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
if (sscanf(argv[i],"%dx%d",&vfbScreens[0].fb.width,
&vfbScreens[0].fb.height) != 2) {
ErrorF("Invalid geometry %s\n", argv[i]);
UseMsg();
+ return 0;
}
return 2;
}
if (strcmp(argv[i], "-depth") == 0)
{
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
vfbScreens[0].fb.depth = atoi(argv[i]);
return 2;
}
@@ -507,10 +519,12 @@
{
char rgbbgr[4];
int bits1, bits2, bits3;
- if (++i >= argc) UseMsg();
+ fail_unless_args(argc, i, 1);
+ ++i;
if (sscanf(argv[i], "%3s%1d%1d%1d", rgbbgr,&bits1,&bits2,&bits3) < 4) {
ErrorF("Invalid pixel format %s\n", argv[i]);
UseMsg();
+ return 0;
}
#define SET_PIXEL_FORMAT(vfbScreen) \
@@ -528,6 +542,7 @@
} else { \
ErrorF("Invalid pixel format %s\n", argv[i]); \
UseMsg(); \
+ return 0; \
}
if (-1 == lastScreen)
@@ -679,9 +694,11 @@
entries = pmap->pVisual->ColormapEntries;
pVisual = pmap->pVisual;
- ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
- prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
- defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
+ ppix = (Pixel *)calloc(entries, sizeof(Pixel));
+ prgb = (xrgb *)calloc(entries, sizeof(xrgb));
+ defs = (xColorItem *)calloc(entries, sizeof(xColorItem));
+ if (!ppix || !prgb || !defs)
+ FatalError ("Not enough memory for color map\n");
for (i = 0; i < entries; i++) ppix[i] = i;
/* XXX truecolor */
@@ -700,9 +717,9 @@
}
(*pmap->pScreen->StoreColors)(pmap, entries, defs);
- xfree(ppix);
- xfree(prgb);
- xfree(defs);
+ free(ppix);
+ free(prgb);
+ free(defs);
}
}
@@ -786,7 +803,7 @@
break;
#endif
case NORMAL_MEMORY_FB:
- pfb->pfbMemory = Xalloc(pfb->sizeInBytes);
+ pfb->pfbMemory = malloc(pfb->sizeInBytes);
break;
}
@@ -813,7 +830,7 @@
break;
#endif /* HAS_SHM */
case NORMAL_MEMORY_FB:
- Xfree(pfb->pfbMemory);
+ free(pfb->pfbMemory);
break;
}
diff --git a/unix/xserver117.patch b/unix/xserver117.patch
new file mode 100644
index 0000000..8a21040
--- /dev/null
+++ b/unix/xserver117.patch
@@ -0,0 +1,137 @@
+diff -up xorg-server-1.17.1/configure.ac.vnc xorg-server-1.17.1/configure.ac
+--- xorg-server-1.17.1/configure.ac.vnc 2015-02-10 22:43:52.000000000 +0000
++++ xorg-server-1.17.1/configure.ac 2015-02-13 16:14:05.074515927 +0000
+@@ -74,6 +74,7 @@ dnl forcing an entire recompile.x
+ AC_CONFIG_HEADERS(include/version-config.h)
+
+ AM_PROG_AS
++AC_PROG_CXX
+ AC_PROG_LN_S
+ LT_PREREQ([2.2])
+ LT_INIT([disable-static win32-dll])
+@@ -1795,6 +1796,10 @@ if test "x$XVFB" = xyes; then
+ AC_SUBST([XVFB_SYS_LIBS])
+ fi
+
++dnl Xvnc DDX
++AC_SUBST([XVNC_CPPFLAGS], ["-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS"])
++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"])
++AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"])
+
+ dnl Xnest DDX
+
+@@ -1830,6 +1835,8 @@ if test "x$XORG" = xauto; then
+ fi
+ AC_MSG_RESULT([$XORG])
+
++AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
++
+ if test "x$XORG" = xyes; then
+ XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common'
+ XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os'
+@@ -2059,7 +2066,6 @@ if test "x$XORG" = xyes; then
+ AC_DEFINE(XORG_SERVER, 1, [Building Xorg server])
+ AC_DEFINE(XORGSERVER, 1, [Building Xorg server])
+ AC_DEFINE(XFree86Server, 1, [Building XFree86 server])
+- AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
+ AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs])
+ AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions])
+ AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server])
+@@ -2599,6 +2605,7 @@ hw/dmx/Makefile
+ hw/dmx/man/Makefile
+ hw/vfb/Makefile
+ hw/vfb/man/Makefile
++hw/vnc/Makefile
+ hw/xnest/Makefile
+ hw/xnest/man/Makefile
+ hw/xwin/Makefile
+diff -up xorg-server-1.17.1/hw/Makefile.am.vnc xorg-server-1.17.1/hw/Makefile.am
+--- xorg-server-1.17.1/hw/Makefile.am.vnc 2014-04-16 21:24:00.000000000 +0100
++++ xorg-server-1.17.1/hw/Makefile.am 2015-02-13 16:14:05.131516821 +0000
+@@ -38,7 +38,8 @@ SUBDIRS = \
+ $(DMX_SUBDIRS) \
+ $(KDRIVE_SUBDIRS) \
+ $(XQUARTZ_SUBDIRS) \
+- $(XWAYLAND_SUBDIRS)
++ $(XWAYLAND_SUBDIRS) \
++ vnc
+
+ DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
+
+diff -up xorg-server-1.17.1/mi/miinitext.c.vnc xorg-server-1.17.1/mi/miinitext.c
+--- xorg-server-1.17.1/mi/miinitext.c.vnc 2015-01-17 23:42:52.000000000 +0000
++++ xorg-server-1.17.1/mi/miinitext.c 2015-02-13 16:14:05.131516821 +0000
+@@ -111,6 +111,10 @@ SOFTWARE.
+ #include "micmap.h"
+ #include "globals.h"
+
++#ifdef TIGERVNC
++extern void vncExtensionInit(INITARGS);
++#endif
++
+ /* The following is only a small first step towards run-time
+ * configurable extensions.
+ */
+@@ -235,6 +239,9 @@ EnableDisableExtensionError(const char *
+
+ /* List of built-in (statically linked) extensions */
+ static const ExtensionModule staticExtensions[] = {
++#ifdef TIGERVNC
++ {vncExtensionInit, "VNC-EXTENSION", NULL},
++#endif
+ {GEExtensionInit, "Generic Event Extension", &noGEExtension},
+ {ShapeExtensionInit, "SHAPE", NULL},
+ #ifdef MITSHM
+diff -up xorg-server-1.17.1/os/WaitFor.c.vnc xorg-server-1.17.1/os/WaitFor.c
+--- xorg-server-1.17.1/os/WaitFor.c.vnc 2015-01-26 18:40:30.000000000 +0000
++++ xorg-server-1.17.1/os/WaitFor.c 2015-02-13 16:14:05.132516837 +0000
+@@ -125,6 +125,9 @@ static void DoTimer(OsTimerPtr timer, CA
+ static void CheckAllTimers(void);
+ static volatile OsTimerPtr timers = NULL;
+
++extern void vncWriteBlockHandler(fd_set *fds);
++extern void vncWriteWakeupHandler(int nfds, fd_set *fds);
++
+ /*****************
+ * WaitForSomething:
+ * Make the server suspend until there is
+@@ -150,6 +153,7 @@ WaitForSomething(int *pClientsReady)
+ INT32 timeout = 0;
+ fd_set clientsReadable;
+ fd_set clientsWritable;
++ fd_set socketsWritable;
+ int curclient;
+ int selecterr;
+ static int nready;
+@@ -212,6 +216,9 @@ WaitForSomething(int *pClientsReady)
+ XFD_COPYSET(&AllSockets, &LastSelectMask);
+ }
+
++ FD_ZERO(&socketsWritable);
++ vncWriteBlockHandler(&socketsWritable);
++
+ BlockHandler((void *) &wt, (void *) &LastSelectMask);
+ if (NewOutputPending)
+ FlushAllOutput();
+@@ -223,10 +230,20 @@ WaitForSomething(int *pClientsReady)
+ i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
+ }
+ else {
+- i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
++ if (AnyClientsWriteBlocked)
++ XFD_ORSET(&socketsWritable, &ClientsWriteBlocked, &socketsWritable);
++
++ if (XFD_ANYSET(&socketsWritable)) {
++ i = Select(MaxClients, &LastSelectMask, &socketsWritable, NULL, wt);
++ if (AnyClientsWriteBlocked)
++ XFD_ANDSET(&clientsWritable, &socketsWritable, &ClientsWriteBlocked);
++ } else {
++ i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
++ }
+ }
+ selecterr = GetErrno();
+ WakeupHandler(i, (void *) &LastSelectMask);
++ vncWriteWakeupHandler(i, &socketsWritable);
+ if (i <= 0) { /* An error or timeout occurred */
+ if (dispatchException)
+ return 0;
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index f367840..9fa9a66 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -724,19 +724,9 @@
menuKeyChoice = new Fl_Choice(LBLLEFT(tx, ty, 150, CHOICE_HEIGHT, _("Menu key")));
- Fl_Menu_Item items[getMenuKeySymbolCount() + 2];
-
- memset(items, 0, sizeof(items));
-
- items[0].text = strdup(_("None"));
- items[0].flags = FL_MENU_DIVIDER;
-
+ fltk_menu_add(menuKeyChoice, _("None"), 0, NULL, (void*)0, FL_MENU_DIVIDER);
for (int i = 0; i < getMenuKeySymbolCount(); i++)
- items[i+1].text = strdup(getMenuKeySymbols()[i].name);
-
- items[getMenuKeySymbolCount()+1].text = NULL;
-
- menuKeyChoice->copy(items);
+ fltk_menu_add(menuKeyChoice, getMenuKeySymbols()[i].name, 0, NULL, 0, 0);
ty += CHOICE_HEIGHT + TIGHT_MARGIN;
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 463523f..6c77e58 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -24,7 +24,6 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
-#include <stdint.h>
#include <rfb/CMsgWriter.h>
#include <rfb/LogWriter.h>
@@ -1061,69 +1060,50 @@
void Viewport::initContextMenu()
{
- size_t i;
- Fl_Menu_Item items[] = {
- { strdup(_("E&xit viewer")), 0, NULL, (void*)ID_EXIT, FL_MENU_DIVIDER },
+ contextMenu->clear();
+
+ fltk_menu_add(contextMenu, _("E&xit viewer"), 0, NULL,
+ (void*)ID_EXIT, FL_MENU_DIVIDER);
#ifdef HAVE_FLTK_FULLSCREEN
- { strdup(_("&Full screen")), 0, NULL, (void*)ID_FULLSCREEN, FL_MENU_TOGGLE },
+ fltk_menu_add(contextMenu, _("&Full screen"), 0, NULL, (void*)ID_FULLSCREEN,
+ FL_MENU_TOGGLE | (window()->fullscreen_active()?FL_MENU_VALUE:0));
#endif
- { strdup(_("Resize &window to session")), 0, NULL, (void*)ID_RESIZE, FL_MENU_DIVIDER },
-
- { strdup(_("&Ctrl")), 0, NULL, (void*)ID_CTRL, FL_MENU_TOGGLE },
- { strdup(_("&Alt")), 0, NULL, (void*)ID_ALT, FL_MENU_TOGGLE },
-
- { strdup("Menu key"), 0, NULL, (void*)ID_MENUKEY, 0 },
- { strdup("Secret shortcut menu key"), menuKeyCode, NULL, (void*)ID_MENUKEY, FL_MENU_INVISIBLE },
- { strdup(_("Send Ctrl-Alt-&Del")), 0, NULL, (void*)ID_CTRLALTDEL, FL_MENU_DIVIDER },
-
- { strdup(_("&Refresh screen")), 0, NULL, (void*)ID_REFRESH, FL_MENU_DIVIDER },
-
- { strdup(_("&Options...")), 0, NULL, (void*)ID_OPTIONS, 0 },
- { strdup(_("Connection &info...")), 0, NULL, (void*)ID_INFO, 0 },
- { strdup(_("About &TigerVNC viewer...")), 0, NULL, (void*)ID_ABOUT, FL_MENU_DIVIDER },
-
- { strdup(_("Dismiss &menu")), 0, NULL, (void*)ID_DISMISS, 0 },
-
- {0}
- };
-
- // Update any state
- for (i = 0;i < sizeof(items)/sizeof(items[0]);i++) {
- switch ((intptr_t)items[i].user_data_) {
+ fltk_menu_add(contextMenu, _("Resize &window to session"), 0, NULL,
+ (void*)ID_RESIZE,
#ifdef HAVE_FLTK_FULLSCREEN
- case ID_FULLSCREEN:
- if (window()->fullscreen_active())
- items[i].flags |= FL_MENU_VALUE;
- break;
- case ID_RESIZE:
- if (window()->fullscreen_active())
- items[i].flags |= FL_MENU_INACTIVE;
- break;
+ (window()->fullscreen_active()?FL_MENU_INACTIVE:0) |
#endif
- case ID_CTRL:
- if (menuCtrlKey)
- items[i].flags |= FL_MENU_VALUE;
- break;
- case ID_ALT:
- if (menuAltKey)
- items[i].flags |= FL_MENU_VALUE;
- break;
- case ID_MENUKEY:
- // The menu key needs to have its fields updated, or the entries hidden
- if (!menuKeySym)
- items[i].flags |= FL_MENU_INACTIVE | FL_MENU_INVISIBLE;
- else if (!(items[i].flags & FL_MENU_INVISIBLE)) {
- char sendMenuKey[64];
- snprintf(sendMenuKey, 64, _("Send %s"), (const char *)menuKey);
- free((void*)items[i].text);
- items[i].text = strdup(sendMenuKey);
- }
- break;
- }
+ FL_MENU_DIVIDER);
+
+ fltk_menu_add(contextMenu, _("&Ctrl"), 0, NULL, (void*)ID_CTRL,
+ FL_MENU_TOGGLE | (menuCtrlKey?FL_MENU_VALUE:0));
+ fltk_menu_add(contextMenu, _("&Alt"), 0, NULL, (void*)ID_ALT,
+ FL_MENU_TOGGLE | (menuAltKey?FL_MENU_VALUE:0));
+
+ if (menuKeySym) {
+ char sendMenuKey[64];
+ snprintf(sendMenuKey, 64, _("Send %s"), (const char *)menuKey);
+ fltk_menu_add(contextMenu, sendMenuKey, 0, NULL, (void*)ID_MENUKEY, 0);
+ fltk_menu_add(contextMenu, "Secret shortcut menu key", menuKeyCode, NULL,
+ (void*)ID_MENUKEY, FL_MENU_INVISIBLE);
}
- contextMenu->copy(items);
+ fltk_menu_add(contextMenu, _("Send Ctrl-Alt-&Del"), 0, NULL,
+ (void*)ID_CTRLALTDEL, FL_MENU_DIVIDER);
+
+ fltk_menu_add(contextMenu, _("&Refresh screen"), 0, NULL,
+ (void*)ID_REFRESH, FL_MENU_DIVIDER);
+
+ fltk_menu_add(contextMenu, _("&Options..."), 0, NULL,
+ (void*)ID_OPTIONS, 0);
+ fltk_menu_add(contextMenu, _("Connection &info..."), 0, NULL,
+ (void*)ID_INFO, 0);
+ fltk_menu_add(contextMenu, _("About &TigerVNC viewer..."), 0, NULL,
+ (void*)ID_ABOUT, FL_MENU_DIVIDER);
+
+ fltk_menu_add(contextMenu, _("Dismiss &menu"), 0, NULL,
+ (void*)ID_DISMISS, 0);
}
diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm
index e9e0968..0992100 100644
--- a/vncviewer/cocoa.mm
+++ b/vncviewer/cocoa.mm
@@ -203,7 +203,7 @@
layout = NULL;
-#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) || defined(__x86_64__)
TISInputSourceRef keyboard;
CFDataRef uchr;
diff --git a/vncviewer/fltk_layout.h b/vncviewer/fltk_layout.h
index c16a359..21fb00a 100644
--- a/vncviewer/fltk_layout.h
+++ b/vncviewer/fltk_layout.h
@@ -20,6 +20,7 @@
#define __FLTK_LAYOUT_H__
#include <FL/fl_draw.H>
+#include <FL/Fl_Menu_.H>
/* Calculates the width of a string as printed by FLTK (pixels) */
static inline int gui_str_len(const char *str)
@@ -67,6 +68,53 @@
return len;
}
+/* Filter out unsafe characters for menu entries */
+static inline int fltk_menu_escape(const char *in, char *out, size_t maxlen)
+{
+ int len;
+
+ len = 0;
+
+ while (*in != '\0') {
+ if (*in == '/') {
+ if (maxlen >= 3) {
+ *out++ = '\\';
+ *out++ = '/';
+ maxlen -= 2;
+ }
+
+ len += 2;
+ } else {
+ if (maxlen >= 2) {
+ *out++ = *in;
+ maxlen--;
+ }
+
+ len += 1;
+ }
+
+ in++;
+ }
+
+ if (maxlen)
+ *out = '\0';
+
+ return len;
+}
+
+/* Helper to add menu entries safely */
+static inline void fltk_menu_add(Fl_Menu_ *menu, const char *text,
+ int shortcut, Fl_Callback *cb,
+ void *data = 0, int flags = 0)
+{
+ char buffer[1024];
+
+ if (fltk_menu_escape(text, buffer, sizeof(buffer)) >= sizeof(buffer))
+ return;
+
+ menu->add(buffer, shortcut, cb, data, flags);
+}
+
/**** MARGINS ****/
#define OUTER_MARGIN 10