Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/win/rfbplayer/ChoosePixelFormatDialog.h b/win/rfbplayer/ChoosePixelFormatDialog.h
new file mode 100644
index 0000000..ada820b
--- /dev/null
+++ b/win/rfbplayer/ChoosePixelFormatDialog.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- ChoosePixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class ChoosePixelFormatDialog : public rfb::win32::Dialog {
+public:
+ ChoosePixelFormatDialog(PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), combo(0) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_PIXELFORMAT), parent);
+ }
+ const long getPFIndex() const {return pfIndex;}
+ bool isBigEndian() {return isItemChecked(IDC_BIG_ENDIAN);}
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(combo, CB_SETCURSEL, pfIndex + 1, 0);
+ setItemChecked(IDC_BIG_ENDIAN, bigEndian);
+ }
+ virtual bool onOk() {
+ pfIndex = SendMessage(combo, CB_GETCURSEL, 0, 0) - 1;
+ bigEndian = isItemChecked(IDC_BIG_ENDIAN);
+ return true;
+ }
+ virtual bool onCancel() {
+ return false;
+ }
+ static long pfIndex;
+ static bool bigEndian;
+ PixelFormatList *supportedPF;
+ HWND combo;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/EditPixelFormatDialog.h b/win/rfbplayer/EditPixelFormatDialog.h
new file mode 100644
index 0000000..0765285
--- /dev/null
+++ b/win/rfbplayer/EditPixelFormatDialog.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- EditPixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+#define MAX_STR_LEN 256
+
+class EditPixelFormatDialog : public rfb::win32::Dialog {
+public:
+ EditPixelFormatDialog(PixelFormatList *_supportedPF, char *_format_name,
+ PixelFormat *_pf)
+ : Dialog(GetModuleHandle(0)), format_name(_format_name),
+ supportedPF(_supportedPF), pf(_pf) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_UPF_EDIT), parent);
+ }
+
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ HWND bppCombo = GetDlgItem(handle, IDC_BPP_COMBO);
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("8"));
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("16"));
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("32"));
+ SendMessage(bppCombo, CB_SETCURSEL, min(2, (pf->bpp - 8) / 8), 0);
+
+ HWND bigendianCombo = GetDlgItem(handle, IDC_BIGENDIAN_COMBO);
+ SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("No"));
+ SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Yes"));
+ SendMessage(bigendianCombo, CB_SETCURSEL, pf->bigEndian, 0);
+
+ setItemString(IDC_NAME_EDIT, format_name);
+ setItemInt(IDC_DEPTH_EDIT, pf->depth);
+ setItemInt(IDC_REDMAX_EDIT, pf->redMax);
+ setItemInt(IDC_GREENMAX_EDIT, pf->greenMax);
+ setItemInt(IDC_BLUEMAX_EDIT, pf->blueMax);
+ setItemInt(IDC_REDSHIFT_EDIT, pf->redShift);
+ setItemInt(IDC_GREENSHIFT_EDIT, pf->greenShift);
+ setItemInt(IDC_BLUESHIFT_EDIT, pf->blueShift);
+ }
+ virtual bool onOk() {
+ // Check for the errors
+ char err_msg[256] = "\0";
+ if (((getItemString(IDC_NAME_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_DEPTH_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_REDMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_GREENMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_BLUEMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_REDSHIFT_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_GREENSHIFT_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_BLUESHIFT_EDIT))[0] == '\0')) {
+ strcpy(err_msg, "Please fill the all fields in the dialog.");
+ }
+ int newIndex = supportedPF->getIndexByPFName(getItemString(IDC_NAME_EDIT));
+ if ((supportedPF->getIndexByPFName(format_name) != newIndex) &&
+ (newIndex != -1)) {
+ strcpy(err_msg, "The pixel format with that name is already exist.");
+ }
+ if (getItemInt(IDC_DEPTH_EDIT) <= 0) {
+ strcpy(err_msg, "The pixel depth must be larger than 0.");
+ }
+ if (err_msg[0] != 0) {
+ MessageBox(handle, err_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ }
+ // Fill the pixel format structure
+ strCopy(format_name, getItemString(IDC_NAME_EDIT), MAX_STR_LEN);
+ pf->bpp = getItemInt(IDC_BPP_COMBO);
+ pf->depth = getItemInt(IDC_DEPTH_EDIT);
+ pf->bigEndian = (SendMessage(GetDlgItem(handle, IDC_BIGENDIAN_COMBO),
+ CB_GETCURSEL, 0, 0)) ? true : false;
+ pf->trueColour = true;
+ pf->redMax = getItemInt(IDC_REDMAX_EDIT);
+ pf->greenMax = getItemInt(IDC_GREENMAX_EDIT);
+ pf->blueMax = getItemInt(IDC_BLUEMAX_EDIT);
+ pf->redShift = getItemInt(IDC_REDSHIFT_EDIT);
+ pf->greenShift = getItemInt(IDC_GREENSHIFT_EDIT);
+ pf->blueShift = getItemInt(IDC_BLUESHIFT_EDIT);
+ return true;
+ }
+
+ char *format_name;
+ PixelFormatList *supportedPF;
+ PixelFormat *pf;
+};
diff --git a/win/rfbplayer/FbsInputStream.cxx b/win/rfbplayer/FbsInputStream.cxx
new file mode 100644
index 0000000..6381a16
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.cxx
@@ -0,0 +1,251 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- FbsInputStream class
+
+#include <windows.h>
+
+#include <rfb/Exception.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+FbsInputStream::FbsInputStream(char* FileName) {
+ bufferSize = 0;
+ ptr = end = start = NULL;
+
+ timeOffset = 0;
+ seekOffset = -1;
+ startTime = GetTickCount();
+
+ playbackSpeed = 1.0;
+ seekBackwards = false;
+ paused = false;
+
+ interruptDelay = false;
+
+ fbsFile = fopen(FileName, "rb");
+ if (fbsFile == NULL) {
+ char *msg = new char[12 + sizeof(FileName)];
+ strcpy(msg, "Can't open ");
+ strcat(msg, FileName);
+ throw rfb::Exception(msg);
+ }
+
+ U8 b[12];
+ readNByte(b, 12);
+
+ if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
+ b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
+ b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' ||
+ b[10] < '0' || b[10] > '9' || b[11] != '\n') {
+ throw rfb::Exception("Incorrect protocol version");
+ }
+}
+
+FbsInputStream::~FbsInputStream() {
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ fclose(fbsFile);
+}
+
+int FbsInputStream::pos() {
+ return ptr - start;
+}
+
+//
+// Close FbsInputStream and free data buffer
+//
+
+void FbsInputStream::close() {
+ fclose(fbsFile);
+
+ startTime = -1;
+ timeOffset = 0;
+ seekOffset = -1;
+ seekBackwards = false;
+ paused = false;
+ playbackSpeed = 1.0;
+
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ bufferSize = 0;
+}
+
+//
+// Fill data buffer from the session file (InStream::overrun() override)
+//
+
+int FbsInputStream::overrun(int itemSize, int nItems, bool wait=true) {
+ // Just wait unless we are performing playback OR seeking.
+ waitWhilePaused();
+
+ // Perform backwardSeek (throws the special exception)
+ if (seekBackwards) {
+ throw rfb::Exception("[REWIND]");
+ }
+
+ // Save a tail of data
+ U8 *tmp;
+ int n = end - ptr;
+ if (n) {
+ tmp = new U8[n];
+ memmove(tmp, ptr, n);
+ }
+
+ bufferSize = (int)readUnsigned32();
+ if (bufferSize >= 0) {
+ if (start != NULL)
+ delete [] start;
+ int realSize = (bufferSize + 3) & 0xFFFFFFFC; // padding to multiple of 32-bits
+ ptr = start = new U8[realSize + n];
+ end = ptr + bufferSize + n;
+ if (n) {
+ memmove(start, tmp, n);
+ delete [] tmp;
+ }
+ readNByte(start + n, realSize);
+ timeOffset = (long)(readUnsigned32() / playbackSpeed);
+
+ if (itemSize * nItems > bufferSize)
+ nItems = bufferSize / itemSize;
+ }
+
+ if (bufferSize < 0 || timeOffset < 0) {
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ bufferSize = 0;
+ return 0;
+ }
+
+ if (seekOffset >= 0) {
+ if (timeOffset >= seekOffset) {
+ startTime = GetTickCount() - seekOffset;
+ seekOffset = -1;
+ } else {
+ return nItems;
+ }
+ }
+
+ while (!interruptDelay) {
+ long timeDiff = startTime + timeOffset - GetTickCount();
+ if (timeDiff <= 0) {
+ break;
+ }
+ Sleep(min(20, timeDiff));
+ waitWhilePaused();
+ }
+ interruptDelay = false;
+
+ return nItems;
+}
+
+int FbsInputStream::readUnsigned32() {
+ U8 buf[4];
+ if (!readNByte(buf, 4))
+ return -1;
+
+ return ((long)(buf[0] & 0xFF) << 24 |
+ (buf[1] & 0xFF) << 16 |
+ (buf[2] & 0xFF) << 8 |
+ (buf[3] & 0xFF));
+}
+
+//
+// Read n-bytes from the session file
+//
+
+bool FbsInputStream::readNByte(U8 b[], int n) {
+ int off = 0;
+
+ while (off != n) {
+ int count = fread(b, 1, n - off, fbsFile);
+ if (count < n) {
+ if (ferror(fbsFile))
+ throw rfb::Exception("Read error from session file");
+ if (feof(fbsFile))
+ throw rfb::Exception("[End Of File]");
+ }
+ off += count;
+ }
+ return true;
+}
+
+void FbsInputStream::waitWhilePaused() {
+ while (paused && !isSeeking()) {
+ // A small delay helps to decrease the cpu usage
+ Sleep(20);
+ }
+}
+
+void FbsInputStream::interruptFrameDelay() {
+ interruptDelay = true;
+}
+
+//
+// Methods providing additional functionality.
+//
+
+long FbsInputStream::getTimeOffset() {
+ //long off = max(seekOffset, timeOffset);
+ return (long)(timeOffset * playbackSpeed);
+}
+
+void FbsInputStream::setTimeOffset(long pos) {
+ seekOffset = (long)(pos / playbackSpeed);
+ if (seekOffset < timeOffset) {
+ seekBackwards = true;
+ }
+}
+
+void FbsInputStream::setSpeed(double newSpeed) {
+ long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
+ startTime += timeOffset - newOffset;
+ timeOffset = newOffset;
+ if (isSeeking()) {
+ seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
+ }
+ playbackSpeed = newSpeed;
+}
+
+double FbsInputStream::getSpeed() {
+ return playbackSpeed;
+}
+
+bool FbsInputStream::isSeeking() {
+ return (seekOffset >= 0);
+}
+
+long FbsInputStream::getSeekOffset() {
+ return (long)(seekOffset * playbackSpeed);
+}
+
+bool FbsInputStream::isPaused() {
+ return paused;
+}
+
+void FbsInputStream::pausePlayback() {
+ paused = true;
+}
+
+void FbsInputStream::resumePlayback() {
+ paused = false;
+ startTime = GetTickCount() - timeOffset;
+}
diff --git a/win/rfbplayer/FbsInputStream.h b/win/rfbplayer/FbsInputStream.h
new file mode 100644
index 0000000..9649273
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- FbsInputStream.h
+
+#include <rdr/InStream.h>
+
+using namespace rdr;
+
+class FbsInputStream : public InStream {
+ public:
+ FbsInputStream(char *FileName);
+ ~FbsInputStream();
+
+ // Methods are used to contol the Rfb Stream
+ long getTimeOffset();
+ void setTimeOffset(long pos);
+ double getSpeed();
+ void setSpeed(double newSpeed);
+ bool isSeeking();
+ long getSeekOffset();
+ bool isPaused();
+ void pausePlayback();
+ void resumePlayback();
+ void interruptFrameDelay();
+ void close();
+ int pos();
+
+ private:
+ U8 *start;
+ int bufferSize;
+ long startTime;
+ long timeOffset;
+ long seekOffset;
+ double playbackSpeed;
+ bool seekBackwards;
+ bool paused;
+ bool interruptDelay;
+
+ FILE *fbsFile;
+
+ // overrun() - overrides InStream::overrun().
+ // It is implemented to fill the data buffer from the session file.
+ // It ensures there are at least itemSize bytes of buffer data. Returns
+ // the number of items in the buffer (up to a maximum of nItems). itemSize
+ // is supposed to be "small" (a few bytes).
+
+ int overrun(int itemSize, int nItems, bool wait);
+
+ int readUnsigned32();
+ bool readNByte(U8 *b, int n);
+ void waitWhilePaused();
+};
diff --git a/win/rfbplayer/GotoPosDialog.h b/win/rfbplayer/GotoPosDialog.h
new file mode 100644
index 0000000..ddbbe53
--- /dev/null
+++ b/win/rfbplayer/GotoPosDialog.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- GotoPosDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class GotoPosDialog : public rfb::win32::Dialog {
+public:
+ GotoPosDialog() : Dialog(GetModuleHandle(0)) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_GOTO), parent);
+ }
+ const long getPos() const {return pos;}
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ setItemString(IDC_GOTO_EDIT, rfb::TStr("0"));
+ }
+ virtual bool onOk() {
+ pos = atol(rfb::CStr(getItemString(IDC_GOTO_EDIT)));
+ return true;
+ }
+
+ long pos;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/InfoDialog.h b/win/rfbplayer/InfoDialog.h
new file mode 100644
index 0000000..bbe9b26
--- /dev/null
+++ b/win/rfbplayer/InfoDialog.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- InfoDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class InfoDialog : public rfb::win32::Dialog {
+public:
+ InfoDialog(char *_info_message, char *_title = "Information")
+ : Dialog(GetModuleHandle(0)), info_message(_info_message), title(_title) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent = 0) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_INFO), parent);
+ }
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ SetWindowText(handle, title);
+ setItemString(IDC_INFO_EDIT, info_message);
+ }
+ char *info_message;
+ char *title;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/OptionsDialog.h b/win/rfbplayer/OptionsDialog.h
new file mode 100644
index 0000000..8c3a87d
--- /dev/null
+++ b/win/rfbplayer/OptionsDialog.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- OptionsDialog.h
+
+#include <rfbplayer/PlayerOptions.h>
+#include <rfbplayer/UserPixelFormatsDialog.h>
+
+class OptionsDialog : public rfb::win32::Dialog {
+public:
+ OptionsDialog(PlayerOptions *_options, PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), options(_options), combo(0),
+ supportedPF(_supportedPF) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_OPTIONS), parent);
+ }
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(combo, CB_SETCURSEL, options->pixelFormatIndex + 1, 0);
+ setItemChecked(IDC_ACCEPT_BELL, options->acceptBell);
+ setItemChecked(IDC_ACCEPT_CUT_TEXT, options->acceptCutText);
+ setItemChecked(IDC_AUTOPLAY, options->autoPlay);
+ setItemChecked(IDC_BIG_ENDIAN, options->bigEndianFlag);
+ if (options->askPixelFormat) {
+ setItemChecked(IDC_ASK_PF, true);
+ enableItem(IDC_PIXELFORMAT, false);
+ enableItem(IDC_BIG_ENDIAN, false);
+ }
+ }
+ virtual bool onOk() {
+ options->askPixelFormat = isItemChecked(IDC_ASK_PF);
+ options->acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+ options->acceptCutText = isItemChecked(IDC_ACCEPT_CUT_TEXT);
+ options->autoPlay = isItemChecked(IDC_AUTOPLAY);
+ options->bigEndianFlag = isItemChecked(IDC_BIG_ENDIAN);
+ if (!options->askPixelFormat) {
+ options->pixelFormatIndex = int(SendMessage(combo, CB_GETCURSEL, 0, 0)) - 1;
+ if (options->pixelFormatIndex < 0) {
+ options->autoDetectPF = true;
+ } else {
+ options->setPF(&((*supportedPF)[options->pixelFormatIndex])->PF);
+ options->pixelFormat.bigEndian = options->bigEndianFlag;
+ options->autoDetectPF = false;
+ }
+ }
+ options->writeToRegistry();
+ return true;
+ }
+ virtual bool onCommand(int item, int cmd) {
+ if (item == IDC_ASK_PF) {
+ enableItem(IDC_PIXELFORMAT, !isItemChecked(IDC_ASK_PF));
+ enableItem(IDC_BIG_ENDIAN, !isItemChecked(IDC_ASK_PF));
+ }
+ if (item == IDC_DEFAULT) {
+ SendMessage(combo, CB_SETCURSEL, DEFAULT_PF_INDEX + 1, 0);
+ enableItem(IDC_PIXELFORMAT, !DEFAULT_ASK_PF);
+ enableItem(IDC_BIG_ENDIAN, !DEFAULT_ASK_PF);
+ setItemChecked(IDC_ASK_PF, DEFAULT_ASK_PF);
+ setItemChecked(IDC_ACCEPT_BELL, DEFAULT_ACCEPT_BELL);
+ setItemChecked(IDC_ACCEPT_CUT_TEXT, DEFAULT_ACCEPT_CUT_TEXT);
+ setItemChecked(IDC_AUTOPLAY, DEFAULT_AUTOPLAY);
+ setItemChecked(IDC_BIG_ENDIAN, DEFAULT_BIG_ENDIAN);
+ }
+ if (item == IDC_EDIT_UPF) {
+ UserPixelFormatsDialog UpfListDialog(supportedPF);
+ if (UpfListDialog.showDialog(handle)) {
+ int index = SendMessage(combo, CB_GETCURSEL, 0, 0);
+ SendMessage(combo, CB_RESETCONTENT, 0, 0);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ if ( index > (SendMessage(combo, CB_GETCOUNT, 0, 0) - 1)) {
+ index = SendMessage(combo, CB_GETCOUNT, 0, 0) - 1;
+ }
+ SendMessage(combo, CB_SETCURSEL, index, 0);
+ options->pixelFormatIndex = index - 1;
+ }
+ }
+ return false;
+ }
+
+ HWND combo;
+ PlayerOptions *options;
+ PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.cxx b/win/rfbplayer/PixelFormatList.cxx
new file mode 100644
index 0000000..25996f6
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.cxx
@@ -0,0 +1,159 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PixelFormatList class
+
+#include <rfbplayer/PixelFormatList.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+PixelFormatList::PixelFormatList() {
+ PixelFormatListElement PFElem;
+
+ // -=- Add the default pixel formats to list
+ // PF_BGR233
+ PFElem.setName("8-bits depth (BGR233)");
+ PFElem.setPF(&PixelFormat(8,8,0,1,7,7,3,0,3,6));
+ PFList.push_back(PFElem);
+ // PF_RGB555
+ PFElem.setName("15-bits depth (RGB555)");
+ PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,10,5,0));
+ PFList.push_back(PFElem);
+ // PF_BGR555
+ PFElem.setName("15-bits depth (BGR555)");
+ PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,0,5,10));
+ PFList.push_back(PFElem);
+ // PF_RGB565
+ PFElem.setName("16-bits depth (RGB565)");
+ PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,11,5,0));
+ PFList.push_back(PFElem);
+ // PF_BGR565
+ PFElem.setName("16-bits depth (BGR565)");
+ PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,0,5,11));
+ PFList.push_back(PFElem);
+ // PF_RGB888
+ PFElem.setName("24-bits depth (RGB888)");
+ PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,16,8,0));
+ PFList.push_back(PFElem);
+ // PF_BGR888
+ PFElem.setName("24-bits depth (BGR888)");
+ PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,0,8,16));
+ PFList.push_back(PFElem);
+
+ PF_DEFAULT_COUNT = PFList.size();
+}
+
+PixelFormatListElement *PixelFormatList::operator[](int index) {
+ return &(*getIterator(index));
+}
+
+void PixelFormatList::add(char *format_name, PixelFormat PF) {
+ PixelFormatListElement PFElem;
+ PFElem.setName(format_name);
+ PFElem.setPF(&PF);
+ PFList.push_back(PFElem);
+}
+
+void PixelFormatList::insert(int index, char *format_name, PixelFormat PF) {
+ if (isDefaultPF(index))
+ rdr::Exception("PixelFormatList:can't insert to the default pixel format place");
+
+ PixelFormatListElement PFElem;
+ PFElem.setName(format_name);
+ PFElem.setPF(&PF);
+ PFList.insert(getIterator(index), PFElem);
+}
+
+void PixelFormatList::remove(int index) {
+ if (isDefaultPF(index))
+ rdr::Exception("PixelFormatList:can't remove the default pixel format");
+ PFList.erase(getIterator(index));
+}
+
+list <PixelFormatListElement>::iterator PixelFormatList::getIterator(int index) {
+ if ((index >= PFList.size()) || (index < 0))
+ rdr::Exception("PixelFormatList:out of range");
+
+ int i = 0;
+ list <PixelFormatListElement>::iterator iter;
+ for (iter = PFList.begin(); iter != PFList.end(); iter++) {
+ if (i++ == index) break;
+ }
+ return iter;
+}
+
+bool PixelFormatList::isDefaultPF(int index) {
+ if (index < PF_DEFAULT_COUNT) return true;
+ return false;
+}
+
+void PixelFormatList::readUserDefinedPF(HKEY root, const char *keypath) {
+ RegKey regKey;
+ regKey.createKey(root, keypath);
+ int count = regKey.getInt(_T("PixelFormatCount"), 0);
+ if (count > 0) {
+ // Erase all user defined pixel formats
+ int upf_count = getUserPFCount();
+ if (upf_count > 0) {
+ for(int i = 0; i < upf_count; i++) {
+ remove(PF_DEFAULT_COUNT);
+ }
+ }
+ // Add the user defined pixel formats from the registry
+ for(int i = 0; i < count; i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ int size = sizeof(PixelFormatListElement);
+ PixelFormatListElement *pPFElem = 0;// = &PFElem;
+ regKey.getBinary(upf_name, (void**)&pPFElem, &size);
+ PFList.push_back(*pPFElem);
+ if (pPFElem) delete pPFElem;
+ }
+ }
+}
+
+void PixelFormatList::writeUserDefinedPF(HKEY root, const char *keypath) {
+ RegKey regKey;
+
+ // Delete all user defined pixel formats from the regisry
+ regKey.createKey(root, keypath);//_T("Software\\TightVnc\\RfbPlayer\\UserDefinedPF"));
+ int count = regKey.getInt(_T("PixelFormatCount"), 0);
+ for (int i = 0; i < count; i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ regKey.deleteValue(upf_name);
+ }
+ regKey.setInt(_T("PixelFormatCount"), 0);
+
+ // Write new user defined pixel formats to the registry
+ regKey.setInt(_T("PixelFormatCount"), getUserPFCount());
+ for (i = 0; i < getUserPFCount(); i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ regKey.setBinary(upf_name, (void *)operator[](i+getDefaultPFCount()),
+ sizeof(PixelFormatListElement));
+ }
+}
+
+int PixelFormatList::getIndexByPFName(const char *format_name) {
+ for (int i = 0; i < PixelFormatList::count(); i++) {
+ if (_stricmp(operator[](i)->format_name, format_name) == 0) return i;
+ }
+ return -1;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.h b/win/rfbplayer/PixelFormatList.h
new file mode 100644
index 0000000..cd7c50a
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PixelFormatList.h
+
+// Definition of the PixelFormatList class, responsible for
+// controlling the list of supported pixel formats.
+
+#include <list>
+
+#include <rfb/Exception.h>
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+// Definition indexes of the default pixel formats
+#define PF_BGR233 0
+#define PF_RGB555 1
+#define PF_BGR555 2
+#define PF_RGB565 3
+#define PF_BGR565 4
+#define PF_RGB888 5
+#define PF_BGR888 6
+
+using namespace rfb;
+using namespace std;
+
+// PixelFormatListElement class, it is
+// an item of the PixelFormatList list.
+
+class PixelFormatListElement {
+public:
+ PixelFormatListElement() {
+ format_name[0] = 0;
+ }
+ char format_name[256];
+ PixelFormat PF;
+ void setName(const char *name) {
+ format_name[0] = '\0';
+ strcpy(format_name, name);
+ format_name[strlen(name)] = '\0';
+ }
+ void setPF(PixelFormat *_PF) {
+ memcpy(&PF, _PF, sizeof(PixelFormat));
+ }
+};
+
+class PixelFormatList {
+public:
+ PixelFormatList();
+
+ PixelFormatListElement* operator[](int index);
+ void add(char *format_name, PixelFormat PF);
+ void insert(int index, char *format_name, PixelFormat PF);
+ void remove(int index);
+
+ void readUserDefinedPF(HKEY root, const char *keypath);
+ void writeUserDefinedPF(HKEY root, const char *keypath);
+
+ int count() { return PFList.size(); }
+ int getDefaultPFCount() { return PF_DEFAULT_COUNT; }
+ int getUserPFCount() { return max(0, count() - PF_DEFAULT_COUNT); }
+ int getIndexByPFName(const char *format_name);
+ bool isDefaultPF(int index);
+
+protected:
+ list <PixelFormatListElement>::iterator getIterator(int index);
+ list <PixelFormatListElement> PFList;
+ int PF_DEFAULT_COUNT;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.cxx b/win/rfbplayer/PlayerOptions.cxx
new file mode 100644
index 0000000..5384c6e
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.cxx
@@ -0,0 +1,152 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PlayerOptions class
+
+#include <rfbplayer/PlayerOptions.h>
+
+using namespace rfb::win32;
+
+PlayerOptions::PlayerOptions() {
+ writeDefaults();
+};
+
+void PlayerOptions::readFromRegistry() {
+ try {
+ PixelFormat *pPF = 0;
+ int pfSize = sizeof(PixelFormat);
+ RegKey regKey;
+ regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+ autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+ autoDetectPF = regKey.getBool(_T("AutoDetectPixelFormat"), DEFAULT_AUTOPF);
+ bigEndianFlag = regKey.getBool(_T("BigEndianFlag"), DEFAULT_BIG_ENDIAN);
+ pixelFormatIndex = regKey.getInt(_T("PixelFormatIndex"), DEFAULT_PF_INDEX);
+ regKey.getBinary(_T("PixelFormat"), (void**)&pPF, &pfSize,
+ &PixelFormat(32,24,0,1,255,255,255,16,8,0), sizeof(PixelFormat));
+ setPF(pPF);
+ acceptBell = regKey.getBool(_T("AcceptBell"), DEFAULT_ACCEPT_BELL);
+ acceptCutText = regKey.getBool(_T("AcceptCutText"), DEFAULT_ACCEPT_CUT_TEXT);
+ autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+ askPixelFormat = regKey.getBool(_T("AskPixelFormat"), DEFAULT_ASK_PF);
+ if (pPF) delete pPF;
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+}
+
+void PlayerOptions::writeToRegistry() {
+ try {
+ RegKey regKey;
+ regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+ regKey.setBool(_T("AutoPlay"), autoPlay);
+ regKey.setBool(_T("AutoDetectPixelFormat"), autoDetectPF);
+ regKey.setBool(_T("BigEndianFlag"), bigEndianFlag);
+ regKey.setInt(_T("PixelFormatIndex"), pixelFormatIndex);
+ regKey.setBinary(_T("PixelFormat"), &pixelFormat, sizeof(PixelFormat));
+ regKey.setBool(_T("AcceptBell"), acceptBell);
+ regKey.setBool(_T("AcceptCutText"), acceptCutText);
+ regKey.setBool(_T("AutoPlay"), autoPlay);
+ regKey.setBool(_T("AskPixelFormat"), askPixelFormat);
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+}
+
+void PlayerOptions::writeDefaults() {
+ initTime = DEFAULT_INIT_TIME;
+ playbackSpeed = DEFAULT_SPEED;
+ autoDetectPF = DEFAULT_AUTOPF;
+ bigEndianFlag = DEFAULT_BIG_ENDIAN;
+ pixelFormatIndex = DEFAULT_PF_INDEX;
+ pixelFormat = PixelFormat(32,24,0,1,255,255,255,16,8,0);
+ frameScale = DEFAULT_FRAME_SCALE;
+ autoPlay = DEFAULT_AUTOPLAY;
+ fullScreen = DEFAULT_FULL_SCREEN;
+ acceptBell = DEFAULT_ACCEPT_BELL;
+ acceptCutText = DEFAULT_ACCEPT_CUT_TEXT;
+ loopPlayback = DEFAULT_LOOP_PLAYBACK;
+ askPixelFormat = DEFAULT_ASK_PF;
+ commandLineParam = false;
+}
+
+void PlayerOptions::setPF(PixelFormat *newPF) {
+ memcpy(&pixelFormat, newPF, sizeof(PixelFormat));
+}
+
+bool PlayerOptions::setPF(int rgb_order, int rm, int gm, int bm, bool big_endian) {
+ PixelFormat newPF;
+
+ // Calculate the colour bits per pixel
+ int bpp = rm + gm + bm;
+ if (bpp < 0) {
+ return false;
+ } else if (bpp <= 8 ) {
+ newPF.bpp = 8;
+ } else if (bpp <= 16) {
+ newPF.bpp = 16;
+ } else if (bpp <= 32) {
+ newPF.bpp = 32;
+ } else {
+ return false;
+ }
+ newPF.depth = bpp;
+
+ // Calculate the r, g and b bits shifts
+ switch (rgb_order) {
+ case RGB_ORDER:
+ newPF.redShift = gm + bm;
+ newPF.greenShift = bm;
+ newPF.blueShift = 0;
+ break;
+ case RBG_ORDER:
+ newPF.redShift = bm + gm;
+ newPF.blueShift = gm;
+ newPF.greenShift = 0;
+ break;
+ case GRB_ORDER:
+ newPF.greenShift = rm + bm;
+ newPF.redShift = bm;
+ newPF.blueShift = 0;
+ break;
+ case GBR_ORDER:
+ newPF.greenShift = bm + rm;
+ newPF.blueShift = rm;
+ newPF.redShift = 0;
+ break;
+ case BGR_ORDER:
+ newPF.blueShift = gm + rm;
+ newPF.greenShift = rm;
+ newPF.redShift = 0;
+ break;
+ case BRG_ORDER:
+ newPF.blueShift = rm + gm;
+ newPF.redShift = gm;
+ newPF.greenShift = 0;
+ break;
+ default:
+ return false;
+ }
+
+ newPF.trueColour = true;
+ newPF.bigEndian = big_endian;
+ newPF.redMax = (1 << rm) - 1;
+ newPF.greenMax = (1 << gm) - 1;
+ newPF.blueMax = (1 << bm) - 1;
+ setPF(&newPF);
+ return true;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.h b/win/rfbplayer/PlayerOptions.h
new file mode 100644
index 0000000..83618a7
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PlayerOptions.h
+
+// Definition of the PlayerOptions class, responsible for
+// storing & retrieving the RfbPlayer's options.
+
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+#define PF_MODES 3
+
+// The R, G and B values order in the pixel
+#define RGB_ORDER 0
+#define RBG_ORDER 1
+#define GRB_ORDER 2
+#define GBR_ORDER 3
+#define BGR_ORDER 4
+#define BRG_ORDER 5
+
+// Default options values
+//#define DEFAULT_PF 0
+#define DEFAULT_PF_INDEX -1
+#define DEFAULT_AUTOPF TRUE
+#define DEFAULT_INIT_TIME -1
+#define DEFAULT_SPEED 1.0
+#define DEFAULT_FRAME_SCALE 100
+#define DEFAULT_ACCEPT_BELL FALSE
+#define DEFAULT_ACCEPT_CUT_TEXT FALSE
+#define DEFAULT_BIG_ENDIAN FALSE
+#define DEFAULT_LOOP_PLAYBACK FALSE
+#define DEFAULT_ASK_PF FALSE
+#define DEFAULT_AUTOPLAY FALSE
+#define DEFAULT_FULL_SCREEN FALSE
+
+using namespace rfb;
+
+class PlayerOptions {
+public:
+ PlayerOptions();
+ void readFromRegistry();
+ void writeToRegistry();
+ void writeDefaults();
+ void setPF(PixelFormat *pf);
+ bool setPF(int rgb_order, int rm, int gm, int bm, bool big_endian=false);
+ long initTime;
+ double playbackSpeed;
+ bool autoPlay;
+ bool fullScreen;
+ bool autoDetectPF;
+ bool bigEndianFlag;
+ long pixelFormatIndex;
+ PixelFormat pixelFormat;
+ bool acceptBell;
+ bool acceptCutText;
+ bool loopPlayback;
+ bool askPixelFormat;
+ long frameScale;
+ bool commandLineParam;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.cxx b/win/rfbplayer/PlayerToolBar.cxx
new file mode 100644
index 0000000..3056f28
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.cxx
@@ -0,0 +1,248 @@
+/* Copyright (C) 2005 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PlayerToolBar.cxx
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/resource.h>
+
+PlayerToolBar::PlayerToolBar()
+: ToolBar(), hFont(0), timeStatic(0), speedEdit(0), posTrackBar(0),
+ speedUpDown(0), sliderDragging(false), sliderStepMs(0)
+{
+}
+
+void PlayerToolBar::create(RfbPlayer *player_, HWND parentHwnd_) {
+ HDC hdc;
+ SIZE sz;
+ RECT tRect;
+ NONCLIENTMETRICS nonClientMetrics;
+
+ player = player_;
+
+ // Get the default font for the main menu
+ nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);
+ if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nonClientMetrics, 0))
+ MessageBox(0, "Can't access to the system font.",
+ "RfbPlayer", MB_OK | MB_ICONERROR);
+ nonClientMetrics.lfMenuFont.lfHeight = 16;
+ hFont = CreateFontIndirect(&nonClientMetrics.lfMenuFont);
+
+ // Create the toolbar panel
+ ToolBar::create(ID_TOOLBAR, parentHwnd_,
+ WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NORESIZE);
+ addBitmap(4, IDB_TOOLBAR);
+
+ // Create the control buttons
+ addButton(0, ID_PLAY);
+ addButton(1, ID_PAUSE);
+ addButton(2, ID_STOP);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+ // Create the static control for the time output
+ timeStatic = CreateWindowEx(0, "Static", "00m:00s (00m:00s)",
+ WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, getHandle(), (HMENU)ID_TIME_STATIC,
+ GetModuleHandle(0), 0);
+ SendMessage(timeStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+ hdc = GetDC(timeStatic);
+ SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, "00m:00s (00m:00s)", 16, &sz);
+ addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(4, &tRect);
+ MoveWindow(timeStatic, tRect.left, tRect.top+2, tRect.right-tRect.left,
+ tRect.bottom-tRect.top, FALSE);
+
+ // Create the trackbar control for the time position
+ addButton(200, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(6, &tRect);
+ posTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, "Trackbar Control",
+ WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE,
+ tRect.left, tRect.top, tRect.right-tRect.left, tRect.bottom-tRect.top,
+ parentHwnd, (HMENU)ID_POS_TRACKBAR, GetModuleHandle(0), 0);
+ // It's need to send notify messages to toolbar parent window
+ SetParent(posTrackBar, getHandle());
+ addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+ // Create the label with "Speed:" caption
+ HWND speedStatic = CreateWindowEx(0, "Static", "Speed:", WS_CHILD | WS_VISIBLE,
+ 0, 0, 5, 5, getHandle(), (HMENU)ID_SPEED_STATIC, GetModuleHandle(0), 0);
+ SendMessage(speedStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+ hdc = GetDC(speedStatic);
+ SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, "Speed:", 6, &sz);
+ addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(8, &tRect);
+ MoveWindow(speedStatic, tRect.left, tRect.top+2, tRect.right-tRect.left,
+ tRect.bottom-tRect.top, FALSE);
+
+ // Create the edit control and the spin for the speed managing
+ addButton(60, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(9, &tRect);
+ speedEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "1.00",
+ WS_CHILD | WS_VISIBLE | ES_RIGHT, tRect.left, tRect.top,
+ tRect.right-tRect.left, tRect.bottom-tRect.top, parentHwnd,
+ (HMENU)ID_SPEED_EDIT, GetModuleHandle(0), 0);
+ SendMessage(speedEdit, WM_SETFONT,(WPARAM) hFont, TRUE);
+ // It's need to send notify messages to toolbar parent window
+ SetParent(speedEdit, getHandle());
+
+ speedUpDown = CreateUpDownControl(WS_CHILD | WS_VISIBLE
+ | WS_BORDER | UDS_ALIGNRIGHT, 0, 0, 0, 0, getHandle(),
+ ID_SPEED_UPDOWN, GetModuleHandle(0), speedEdit, 20, 1, 2);
+
+ // Resize the toolbar window
+ autoSize();
+}
+
+void PlayerToolBar::init(long sessionTimeMs_) {
+ sessionTimeMs = sessionTimeMs_;
+
+ setSessionTimeStr(sessionTimeMs);
+ SendMessage(posTrackBar, TBM_SETRANGE,
+ TRUE, MAKELONG(0, min(sessionTimeMs / 1000, MAX_POS_TRACKBAR_RANGE)));
+ if (sessionTimeMs == 0) {
+ sliderStepMs = 1;
+ } else {
+ sliderStepMs = sessionTimeMs / SendMessage(posTrackBar, TBM_GETRANGEMAX, 0, 0);
+ }
+ updatePos(0);
+}
+
+void PlayerToolBar::enable() {
+ enableButton(ID_PLAY, true);
+ enableButton(ID_PAUSE, true);
+ enableButton(ID_STOP, true);
+ enableButton(ID_FULLSCREEN, true);
+ EnableWindow(posTrackBar, true);
+ EnableWindow(speedEdit, true);
+ EnableWindow(speedUpDown, true);
+}
+
+void PlayerToolBar::disable() {
+ enableButton(ID_PLAY, false);
+ enableButton(ID_PAUSE, false);
+ enableButton(ID_STOP, false);
+ enableButton(ID_FULLSCREEN, false);
+ EnableWindow(posTrackBar, false);
+ EnableWindow(speedEdit, false);
+ EnableWindow(speedUpDown, false);
+}
+
+LRESULT PlayerToolBar::processWM_COMMAND(WPARAM wParam, LPARAM lParam) {
+ switch (LOWORD(wParam)) {
+
+ case ID_RETURN:
+ // Update the speed if return pressed in speedEdit
+ if (getSpeedEditHwnd() == GetFocus()) {
+ char speedStr[20], *stopStr;
+ GetWindowText(getSpeedEditHwnd(), speedStr, sizeof(speedStr));
+ double speed = strtod(speedStr, &stopStr);
+ if (speed > 0) {
+ speed = min(MAX_SPEED, speed);
+ } else {
+ speed = player->getSpeed();
+ }
+ player->setSpeed(speed);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_HSCROLL(WPARAM wParam, LPARAM lParam) {
+ long Pos = SendMessage(posTrackBar, TBM_GETPOS, 0, 0);
+ Pos *= sliderStepMs;
+
+ switch (LOWORD(wParam)) {
+ case TB_PAGEUP:
+ case TB_PAGEDOWN:
+ case TB_LINEUP:
+ case TB_LINEDOWN:
+ case TB_THUMBTRACK:
+ sliderDragging = true;
+ updatePos(Pos);
+ return FALSE;
+ case TB_THUMBPOSITION:
+ case TB_ENDTRACK:
+ player->setPos(Pos);
+ player->setPaused(player->isPaused());;
+ updatePos(Pos);
+ sliderDragging = false;
+ return FALSE;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+ switch (((NMHDR*)lParam)->code) {
+ case UDN_DELTAPOS:
+ if ((int)wParam == ID_SPEED_UPDOWN) {
+ char speedStr[20] = "\0";
+ DWORD speedRange = SendMessage(speedUpDown, UDM_GETRANGE, 0, 0);
+ LPNM_UPDOWN upDown = (LPNM_UPDOWN)lParam;
+ double speed;
+
+ // The out of range checking
+ if (upDown->iDelta > 0) {
+ speed = min(upDown->iPos + upDown->iDelta, LOWORD(speedRange)) * 0.5;
+ } else {
+ // It's need to round the UpDown position
+ if ((upDown->iPos * 0.5) != player->getSpeed()) {
+ upDown->iDelta = 0;
+ }
+ speed = max(upDown->iPos + upDown->iDelta, HIWORD(speedRange)) * 0.5;
+ }
+ player->setSpeed(speed);
+ }
+ }
+
+ // We always return TRUE to prevent the change in the updown contol
+ // position. The control's position changes in the RfbPlayer::setSpeed().
+ return TRUE;
+}
+
+void PlayerToolBar::updatePos(long newPos) {
+ // Update time pos in static control
+ char timePos[30] = "\0";
+ long time = newPos / 1000;
+ sprintf(timePos, "%.2um:%.2us (%s)", time/60, time%60, fullSessionTimeStr);
+ SetWindowText(timeStatic, timePos);
+
+ // Update the position of slider
+ if (!sliderDragging) {
+ double error = SendMessage(posTrackBar, TBM_GETPOS, 0, 0) *
+ sliderStepMs / double(newPos);
+ if (!((error > 1 - CALCULATION_ERROR) && (error <= 1 + CALCULATION_ERROR))) {
+ SendMessage(posTrackBar, TBM_SETPOS, TRUE, newPos / sliderStepMs);
+ }
+ }
+}
+
+void PlayerToolBar::setSessionTimeStr(long sessionTimeMs) {
+ sprintf(fullSessionTimeStr, "%.2um:%.2us",
+ sessionTimeMs / 1000 / 60, sessionTimeMs / 1000 % 60);
+}
+
+void PlayerToolBar::setTimePos(long pos) {
+ SendMessage(posTrackBar, TBM_SETPOS, TRUE, pos);
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.h b/win/rfbplayer/PlayerToolBar.h
new file mode 100644
index 0000000..17ab82e
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2005 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- PlayerToolBar.h
+
+// ToolBar for the RfbPlayer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+#define ID_TOOLBAR 500
+#define ID_PLAY 510
+#define ID_PAUSE 520
+#define ID_TIME_STATIC 530
+#define ID_SPEED_STATIC 540
+#define ID_SPEED_EDIT 550
+#define ID_POS_TRACKBAR 560
+#define ID_SPEED_UPDOWN 570
+
+#define MAX_SPEED 10.00
+#define CALCULATION_ERROR MAX_SPEED / 1000
+#define MAX_POS_TRACKBAR_RANGE 50
+
+class RfbPlayer;
+
+class PlayerToolBar : public ToolBar {
+public:
+ PlayerToolBar();
+ ~PlayerToolBar() {}
+
+ void create(RfbPlayer *player, HWND parentHwnd);
+
+ void init(long sessionTimeMs);
+
+ void enable();
+ void disable();
+
+ LRESULT processWM_COMMAND(WPARAM wParam, LPARAM lParam);
+ LRESULT processWM_HSCROLL(WPARAM wParam, LPARAM lParam);
+ LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+ HWND getSpeedEditHwnd() { return speedEdit; }
+ HWND getSpeedUpDownHwnd() { return speedUpDown; }
+
+ bool isPosSliderDragging() { return sliderDragging; };
+ void updatePos(long newPos);
+ void setSessionTimeStr(long sessionTimeMs);
+ void setTimePos(long newPos);
+
+protected:
+ RfbPlayer *player;
+ HFONT hFont;
+ HWND timeStatic;
+ HWND speedEdit;
+ HWND posTrackBar;
+ HWND speedUpDown;
+ char fullSessionTimeStr[20];
+ long sessionTimeMs;
+ bool sliderDragging;
+ long sliderStepMs;
+};
diff --git a/win/rfbplayer/RfbProto.cxx b/win/rfbplayer/RfbProto.cxx
new file mode 100644
index 0000000..5a7ff7f
--- /dev/null
+++ b/win/rfbplayer/RfbProto.cxx
@@ -0,0 +1,142 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- RFB Protocol
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+static LogWriter vlog("RfbProto");
+
+//
+// Constructor
+//
+
+RfbProto::RfbProto(char *fileName) {
+ is = NULL;
+ reader = NULL;
+ newSession(fileName);
+}
+
+//
+// Destructor
+//
+
+RfbProto::~RfbProto() {
+ if (is) delete is;
+ is = 0;
+ if (reader) delete reader;
+ reader = 0;
+}
+
+void RfbProto::newSession(char *fileName) {
+ // Close the previous session
+ if (is) {
+ delete is;
+ is = NULL;
+ delete reader;
+ reader = NULL;
+ }
+
+ // Begin the new session
+ if (fileName != NULL) {
+ is = new FbsInputStream(fileName);
+ reader = new CMsgReaderV3(this, is);
+ initialiseProtocol();
+ }
+}
+
+void RfbProto::initialiseProtocol() {
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void RfbProto::processMsg()
+{
+ switch (state_) {
+
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader->readMsg(); break;
+ default:
+ throw rfb::Exception("RfbProto::processMsg: invalid state");
+ }
+}
+
+void RfbProto::processVersionMsg()
+{
+ vlog.debug("reading protocol version");
+ memset(&cp, 0, sizeof(cp));
+ bool done;
+ if (!cp.readVersion(is, &done)) {
+ state_ = RFBSTATE_INVALID;
+ throw rfb::Exception("reading version failed: wrong file format?");
+ }
+ if (!done) return;
+
+ // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+ if (!cp.isVersion(3,3) && !cp.isVersion(3,7) && !cp.isVersion(3,8)) {
+ char msg[256];
+ sprintf(msg,"File have unsupported RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+ state_ = RFBSTATE_INVALID;
+ throw rfb::Exception(msg);
+ }
+
+ state_ = RFBSTATE_SECURITY;
+
+ vlog.info("Using RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+}
+
+void RfbProto::processSecurityMsg()
+{
+ vlog.debug("processing security types message");
+
+ int secType = secTypeInvalid;
+
+ // legacy 3.3 server may only offer "vnc authentication" or "none"
+ secType = is->readU32();
+ if (secType == secTypeInvalid) {
+ int reasonLen = is->readU32();
+ char *reason = new char[reasonLen];
+ is->readBytes(reason, reasonLen);
+ throw rfb::Exception(reason);
+ }
+
+ if (secType != secTypeNone) {
+ throw rfb::Exception("Wrong authentication type in the session file");
+ }
+
+ state_ = RFBSTATE_INITIALISATION;
+}
+
+void RfbProto::processInitMsg() {
+ vlog.debug("reading server initialisation");
+ reader->readServerInit();
+}
+
+void RfbProto::serverInit()
+{
+ state_ = RFBSTATE_NORMAL;
+ vlog.debug("initialisation done");
+}
diff --git a/win/rfbplayer/RfbProto.h b/win/rfbplayer/RfbProto.h
new file mode 100644
index 0000000..316ea26
--- /dev/null
+++ b/win/rfbplayer/RfbProto.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- RfbProto.h
+
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+using namespace rfb;
+
+class RfbProto : public CMsgHandler {
+ public:
+
+ RfbProto(char *fileName);
+ ~RfbProto();
+
+ void newSession(char *filename);
+ void initialiseProtocol();
+ void interruptFrameDelay() { is->interruptFrameDelay(); };
+ const rdr::InStream* getInStream() { return is; }
+
+ virtual void processMsg();
+
+ // serverInit() is called when the ServerInit message is received. The
+ // derived class must call on to CMsgHandler::serverInit().
+ void serverInit();
+
+ enum stateEnum {
+ RFBSTATE_PROTOCOL_VERSION,
+ RFBSTATE_SECURITY,
+ RFBSTATE_INITIALISATION,
+ RFBSTATE_NORMAL,
+ RFBSTATE_INVALID
+ };
+
+ stateEnum state() { return state_; }
+
+ protected:
+ void setState(stateEnum s) { state_ = s; }
+ virtual void framebufferUpdateEnd() {};
+
+ FbsInputStream* is;
+ CMsgReaderV3* reader;
+ stateEnum state_;
+
+ private:
+ void processVersionMsg();
+ void processSecurityMsg();
+ void processInitMsg();
+};
diff --git a/win/rfbplayer/SessionInfoDialog.h b/win/rfbplayer/SessionInfoDialog.h
new file mode 100644
index 0000000..2c036db
--- /dev/null
+++ b/win/rfbplayer/SessionInfoDialog.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- SessionInfoDialog.h
+
+#include <math.h>
+
+#include <rfb/ConnParams.h>
+
+#include <rfb_win32/Dialog.h>
+
+#define log2(n) log(n) / 0.693147180559945
+
+int max3(int v1, int v2, int v3) {
+ return max(v1, max(v2, v3));
+}
+
+class SessionInfoDialog : public rfb::win32::Dialog {
+public:
+ SessionInfoDialog(ConnParams *_cp, int _currentEncoding)
+ : Dialog(GetModuleHandle(0)), cp(_cp), currentEncoding(_currentEncoding) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent = 0) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_SESSION_INFO), parent);
+ }
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ char strValue[255] = "\0";
+ setItemString(IDC_DESKTOP_NAME, cp->name());
+
+ sprintf(strValue, "%ix%i", cp->width, cp->height);
+ setItemString(IDC_DESKTOP_SIZE, strValue);
+
+ int r = cp->pf().redShift, g = cp->pf().greenShift, b = cp->pf().blueShift;
+ int i = 3;
+ char buffer[10];
+ sprintf(strValue, "depth %i(%ibpp), ", cp->pf().depth, cp->pf().bpp);
+ while (i) {
+ if (r == max3(r, g, b)) {
+ strcat(strValue, "r");
+ _itoa(ceil(log2(cp->pf().redMax)), buffer, 10);
+ strcat(strValue, buffer);
+ r = -1;
+ i--;
+ continue;
+ } else if (g == max3(r, g, b)) {
+ strcat(strValue, "g");
+ _itoa(ceil(log2(cp->pf().greenMax)), buffer, 10);
+ strcat(strValue, buffer);
+ g = -1;
+ i--;
+ continue;
+ } else if (b == max3(r, g, b)) {
+ strcat(strValue, "b");
+ _itoa(ceil(log2(cp->pf().blueMax)), buffer, 10);
+ strcat(strValue, buffer);
+ b = -1;
+ i--;
+ continue;
+ } else break;
+ }
+ if (cp->pf().bigEndian) strcat(strValue, ", big-endian");
+ else strcat(strValue, ", little-endian");
+ setItemString(IDC_PIXEL_FORMAT, strValue);
+
+ switch (currentEncoding) {
+ case encodingRaw: strcpy(strValue, "Raw"); break;
+ case encodingCopyRect: strcpy(strValue, "CopyRect"); break;
+ case encodingRRE: strcpy(strValue, "RRE"); break;
+ case encodingCoRRE: strcpy(strValue, "CoRRE"); break;
+ case encodingHextile: strcpy(strValue, "Hextile"); break;
+ case encodingTight: strcpy(strValue, "Tight"); break;
+ case encodingZRLE: strcpy(strValue, "ZRLE"); break;
+ default: strcpy(strValue, "Unknown");
+ }
+ setItemString(IDC_CURRENT_ENCODING, strValue);
+
+ sprintf(strValue, "%i.%i", cp->majorVersion, cp->minorVersion);
+ setItemString(IDC_VERSION, strValue);
+ }
+ ConnParams *cp;
+ int currentEncoding;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/UserPixelFormatsDialog.h b/win/rfbplayer/UserPixelFormatsDialog.h
new file mode 100644
index 0000000..fe2ad22
--- /dev/null
+++ b/win/rfbplayer/UserPixelFormatsDialog.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- UserPixelFormatsDialog.h
+
+#include <rfbplayer/EditPixelFormatDialog.h>
+
+#define UPF_REGISTRY_PATH "Software\\TightVnc\\RfbPlayer\\UserDefinedPF"
+
+class UserPixelFormatsDialog : public rfb::win32::Dialog {
+public:
+ UserPixelFormatsDialog(PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), pfList(0) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_USERPF_LIST), parent);
+ }
+
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ pfList = GetDlgItem(handle, IDC_PF_LIST);
+ for (int i = supportedPF->getDefaultPFCount(); i < supportedPF->count(); i++) {
+ SendMessage(pfList, LB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(pfList, LB_SETCURSEL, 0, 0);
+ }
+ virtual bool onCommand(int item, int cmd) {
+ switch (item) {
+ case IDC_ADD_BUTTON:
+ {
+ char format_name[MAX_STR_LEN] = "";
+ PixelFormat pf(32, 24, 0, 1, 0, 0, 0, 0, 0, 0);
+ EditPixelFormatDialog edit(supportedPF, format_name, &pf);
+ if (edit.showDialog(handle)) {
+ supportedPF->add(format_name, pf);
+ SendMessage(pfList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)format_name);
+ }
+ }
+ break;
+ case IDC_REMOVE_BUTTON:
+ {
+ int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+ if (index == LB_ERR) {
+ MessageBox(handle, "You must select the pixel format for remove.",
+ "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ } else {
+ supportedPF->remove(supportedPF->getDefaultPFCount() + index);
+ SendMessage(pfList, LB_DELETESTRING, index, 0);
+ }
+ }
+ break;
+ case IDC_PF_LIST:
+ if (cmd != LBN_DBLCLK) break;
+ case IDC_EDIT_BUTTON:
+ {
+ int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+ if (index == LB_ERR) {
+ MessageBox(handle, "You must select the pixel format for remove.",
+ "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ }
+ PixelFormat *pf =
+ &(supportedPF->operator[](index + supportedPF->getDefaultPFCount())->PF);
+ char *format_name =
+ (supportedPF)->operator[](index + supportedPF->getDefaultPFCount())->format_name;
+ EditPixelFormatDialog edit(supportedPF, format_name, pf);
+ if (edit.showDialog(handle)) {
+ SendMessage(pfList, LB_DELETESTRING, index, 0);
+ SendMessage(pfList, LB_INSERTSTRING, index, (LPARAM)(LPCTSTR)format_name);
+ SendMessage(pfList, LB_SETCURSEL, index, 0);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ virtual bool onOk() {
+ supportedPF->writeUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ return true;
+ }
+
+ HWND pfList;
+ PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/buildTime.cxx b/win/rfbplayer/buildTime.cxx
new file mode 100644
index 0000000..bab2e13
--- /dev/null
+++ b/win/rfbplayer/buildTime.cxx
@@ -0,0 +1 @@
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
\ No newline at end of file
diff --git a/win/rfbplayer/resource.h b/win/rfbplayer/resource.h
new file mode 100644
index 0000000..90a057f
--- /dev/null
+++ b/win/rfbplayer/resource.h
@@ -0,0 +1,81 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by rfbplayer.rc
+//
+#define IDI_ICON 105
+#define IDR_MENU 128
+#define IDR_ACCELERATOR 131
+#define IDB_TOOLBAR 132
+#define IDD_GOTO 133
+#define IDD_PIXELFORMAT 134
+#define IDD_OPTIONS 137
+#define IDD_ABOUT 138
+#define IDD_USERPF_LIST 139
+#define IDD_UPF_EDIT 140
+#define IDD_INFO 141
+#define IDD_SESSION_INFO 142
+#define IDC_GOTO_EDIT 1003
+#define IDC_PIXELFORMAT 1004
+#define IDC_ASK_PF 1006
+#define IDC_DEFAULT 1008
+#define IDC_VERSION 1008
+#define IDC_ACCEPT_BELL 1009
+#define IDC_BUILDTIME 1009
+#define IDC_ACCEPT_CUT_TEXT 1010
+#define IDC_AUTO_STORE_PARAM 1011
+#define IDC_AUTOPLAY 1012
+#define IDC_BIG_ENDIAN 1013
+#define IDC_EDIT_UPF 1015
+#define IDC_PF_LIST 1016
+#define IDC_BPP_COMBO 1016
+#define IDC_ADD_BUTTON 1017
+#define IDC_NAME_EDIT 1017
+#define IDC_REMOVE_BUTTON 1018
+#define IDC_EDIT_BUTTON 1019
+#define IDC_COPYRIGHT 1021
+#define IDC_DEPTH_EDIT 1021
+#define IDC_DESCRIPTION 1022
+#define IDC_BIGENDIAN_COMBO 1022
+#define IDC_REDMAX_EDIT 1023
+#define IDC_GREENMAX_EDIT 1024
+#define IDC_BLUEMAX_EDIT 1025
+#define IDC_REDSHIFT_EDIT 1026
+#define IDC_DESKTOP_NAME 1026
+#define IDC_GREENSHIFT_EDIT 1027
+#define IDC_DESKTOP_SIZE 1027
+#define IDC_BLUESHIFT_EDIT 1028
+#define IDC_CURRENT_ENCODING 1029
+#define IDC_PIXEL_FORMAT 1030
+#define IDC_INFO_EDIT 1076
+#define ID_OPENFILE 40011
+#define ID_CLOSEFILE 40012
+#define ID_EXIT 40013
+#define ID_FULLSCREEN 40014
+#define ID_ZOOM_50 40015
+#define ID_ZOOM_100 40016
+#define ID_ZOOM_200 40017
+#define ID_PLAYPAUSE 40018
+#define ID_STOP 40019
+#define ID_GOTO 40020
+#define ID_LOOP 40022
+#define ID_COPYTOCLIPBOARD 40023
+#define ID_FRAMEEXTRACT 40024
+#define ID_HELP_HOMEPAGE 40025
+#define ID_HOMEPAGE 40025
+#define ID_HELP_COMMANDLINESWITCHES 40026
+#define ID_HELP_ABOUT 40027
+#define ID_ABOUT 40027
+#define ID_OPTIONS 40029
+#define ID_RETURN 40044
+#define ID_SESSION_INFO 40045
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 143
+#define _APS_NEXT_COMMAND_VALUE 40046
+#define _APS_NEXT_CONTROL_VALUE 1031
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/win/rfbplayer/rfbSessionReader.h b/win/rfbplayer/rfbSessionReader.h
new file mode 100644
index 0000000..31985bc
--- /dev/null
+++ b/win/rfbplayer/rfbSessionReader.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- rfbSessionReader.h
+
+#include <rfb/Threading.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+class rfbSessionReader : public Thread {
+public:
+ rfbSessionReader(RfbProto *_rfbSession) {
+ rfbSession = _rfbSession;
+ fStop = false;
+ rfbSession->interruptFrameDelay();
+ };
+
+ ~rfbSessionReader() {
+ }
+
+ virtual Thread* join() {
+ ((FbsInputStream*)(rfbSession->getInStream()))->resumePlayback();
+ fStop = true;
+ return Thread::join();
+ }
+
+ virtual void rfbSessionReader::run() {
+ // Process the rfb messages
+ while (!fStop) {
+ try {
+ rfbSession->processMsg();
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ break;
+ }
+ }
+ }
+
+protected:
+ bool fStop;
+ RfbProto *rfbSession;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/rfbplayer.cxx b/win/rfbplayer/rfbplayer.cxx
new file mode 100644
index 0000000..b304aec
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.cxx
@@ -0,0 +1,1294 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- RFB Player for Win32
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include <rfb/LogWriter.h>
+
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/Win32Util.h>
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/ChoosePixelFormatDialog.h>
+#include <rfbplayer/GotoPosDialog.h>
+#include <rfbplayer/InfoDialog.h>
+#include <rfbplayer/SessionInfoDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+// -=- Variables & consts
+
+static LogWriter vlog("RfbPlayer");
+
+TStr rfb::win32::AppName("RfbPlayer");
+extern const char* buildTime;
+HFONT hFont = 0;
+
+char wrong_cmd_msg[] =
+ "Wrong command-line parameters!\n"
+ "Use for help: rfbplayer -help";
+
+char usage_msg[] =
+ "usage: rfbplayer <options> <filename>\r\n"
+ "Command-line options:\r\n"
+ " -help \t- Provide usage information.\r\n"
+ " -pf <mode> \t- Forces the pixel format for the session.\r\n"
+ " \t <mode>=r<r_bits>g<g_bits>b<b_bits>[le|be],\r\n"
+ " \t r_bits - size the red component, in bits,\r\n"
+ " \t g_bits - size the green component, in bits,\r\n"
+ " \t b_bits - size the blue component, in bits,\r\n"
+ " \t le - little endian byte order (default),\r\n"
+ " \t be - big endian byte order.\r\n"
+ " \t The r, g, b component is in any order.\r\n"
+ " \t Default: auto detect the pixel format.\r\n"
+ " -upf <name> \t- Forces the user defined pixel format for\r\n"
+ " \t the session. If <name> is empty then application\r\n"
+ " \t shows the list of user defined pixel formats.\r\n"
+ " \t Don't use this option with -pf.\r\n"
+ " -speed <value>\t- Sets playback speed, where 1 is normal speed,\r\n"
+ " \t is double speed, 0.5 is half speed. Default: 1.0.\r\n"
+ " -pos <ms> \t- Sets initial time position in the session file,\r\n"
+ " \t in milliseconds. Default: 0.\r\n"
+ " -autoplay \t- Runs the player in the playback mode.\r\n"
+ " -loop \t- Replays the rfb session.";
+
+// -=- RfbPlayer's defines and consts
+
+#define strcasecmp _stricmp
+#define DEFAULT_PLAYER_WIDTH 640
+#define DEFAULT_PLAYER_HEIGHT 480
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+//
+// -=- RfbPlayerClass
+
+//
+// Window class used as the basis for RfbPlayer instance
+//
+
+class RfbPlayerClass {
+public:
+ RfbPlayerClass();
+ ~RfbPlayerClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK RfbPlayerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY) {
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ }
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processMainMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+};
+
+RfbPlayerClass::RfbPlayerClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = RfbPlayerProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (!wndClass.hIcon)
+ printf("unable to load icon:%ld", GetLastError());
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = HBRUSH(COLOR_WINDOW);
+ wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+ wndClass.lpszClassName = _T("RfbPlayerClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbPlayerClass::~RfbPlayerClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbPlayerClass baseClass;
+
+//
+// -=- RfbFrameClass
+
+//
+// Window class used to displaying the rfb data
+//
+
+class RfbFrameClass {
+public:
+ RfbFrameClass();
+ ~RfbFrameClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processFrameMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+}
+
+RfbFrameClass::RfbFrameClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = FrameProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = 0;
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = 0;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("RfbPlayerClass1");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbFrameClass::~RfbFrameClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbFrameClass frameClass;
+
+//
+// -=- RfbPlayer instance implementation
+//
+
+RfbPlayer::RfbPlayer(char *_fileName, PlayerOptions *_options)
+: RfbProto(_fileName), fileName(_fileName), buffer(0), client_size(0, 0, 32, 32),
+ window_size(0, 0, 32, 32), cutText(0), seekMode(false), lastPos(0),
+ rfbReader(0), sessionTimeMs(0), sliderStepMs(0), imageDataStartTime(0),
+ rewindFlag(false), stopped(false), currentEncoding(-1) {
+
+ // Save the player options
+ memcpy(&options, _options, sizeof(options));
+
+ // Reset the full session time
+ strcpy(fullSessionTime, "00m:00s");
+
+ // Load the user defined pixel formats from the registry
+ supportedPF.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+
+ // Create the main window
+ const TCHAR* name = _T("RfbPlayer");
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ mainHwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
+ x, y, DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 0, 0, baseClass.instance, this);
+ if (!mainHwnd) {
+ throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+ }
+ vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), getMainHandle());
+
+ // Create the backing buffer
+ buffer = new win32::DIBSectionBuffer(getFrameHandle());
+ setVisible(true);
+
+ // If run with command-line parameters,
+ // open the session file with default settings, otherwise
+ // restore player settings from the registry
+ if (fileName) {
+ openSessionFile(fileName);
+ if (options.initTime > 0) setPos(options.initTime);
+ setSpeed(options.playbackSpeed);
+ } else {
+ options.readFromRegistry();
+ disableTBandMenuItems();
+ setTitle("None");
+ }
+ init();
+}
+
+RfbPlayer::~RfbPlayer() {
+ vlog.debug("~RfbPlayer");
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ if (mainHwnd) {
+ setVisible(false);
+ DestroyWindow(mainHwnd);
+ mainHwnd = 0;
+ }
+ if (buffer) delete buffer;
+ if (cutText) delete [] cutText;
+ if (fileName) delete [] fileName;
+ if (hFont) DeleteObject(hFont);
+ vlog.debug("~RfbPlayer done");
+}
+
+LRESULT
+RfbPlayer::processMainMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+ switch (msg) {
+
+ // -=- Process standard window messages
+
+ case WM_CREATE:
+ {
+ tb.create(this, hwnd);
+
+ // Create the frame window
+ frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+ 0, WS_CHILD | WS_VISIBLE, 0, tb.getHeight(), 10, tb.getHeight() + 10,
+ hwnd, 0, frameClass.instance, this);
+
+ hMenu = GetMenu(hwnd);
+
+ return 0;
+ }
+
+ // Process the main menu and toolbar's messages
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+ case ID_OPENFILE:
+ {
+ char curDir[_MAX_DIR];
+ static char filename[_MAX_PATH];
+ OPENFILENAME ofn;
+ memset((void *) &ofn, 0, sizeof(OPENFILENAME));
+ GetCurrentDirectory(sizeof(curDir), curDir);
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = getMainHandle();
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename);
+ ofn.lpstrInitialDir = curDir;
+ ofn.lpstrFilter = "Rfb Session files (*.rfb, *.fbs)\0*.rfb;*.fbs\0" \
+ "All files (*.*)\0*.*\0";
+ ofn.lpstrDefExt = "rfb";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ if (GetOpenFileName(&ofn)) {
+ openSessionFile(filename);
+ }
+ }
+ break;
+ case ID_CLOSEFILE:
+ closeSessionFile();
+ break;
+ case ID_SESSION_INFO:
+ {
+ SessionInfoDialog sessionInfo(&cp, currentEncoding);
+ sessionInfo.showDialog(getMainHandle());
+ }
+ break;
+ case ID_PLAY:
+ setPaused(false);
+ break;
+ case ID_PAUSE:
+ setPaused(true);
+ break;
+ case ID_STOP:
+ stopPlayback();
+ break;
+ case ID_PLAYPAUSE:
+ if (rfbReader) {
+ if (isPaused()) {
+ setPaused(false);
+ } else {
+ setPaused(true);
+ }
+ }
+ break;
+ case ID_GOTO:
+ {
+ GotoPosDialog gotoPosDlg;
+ if (gotoPosDlg.showDialog(getMainHandle())) {
+ long gotoTime = min(gotoPosDlg.getPos(), sessionTimeMs);
+ setPos(gotoTime);
+ tb.updatePos(gotoTime);
+ setPaused(isPaused());;
+ }
+ }
+ break;
+ case ID_LOOP:
+ options.loopPlayback = !options.loopPlayback;
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+ break;
+ case ID_RETURN:
+ tb.processWM_COMMAND(wParam, lParam);
+ break;
+ case ID_OPTIONS:
+ {
+ OptionsDialog optionsDialog(&options, &supportedPF);
+ optionsDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_EXIT:
+ PostQuitMessage(0);
+ break;
+ case ID_HOMEPAGE:
+ ShellExecute(getMainHandle(), _T("open"), _T("http://www.tightvnc.com/"),
+ NULL, NULL, SW_SHOWDEFAULT);
+ break;
+ case ID_HELP_COMMANDLINESWITCHES:
+ {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ }
+ break;
+
+ // Update frame's window size and add scrollbars if required
+
+ case WM_SIZE:
+ {
+
+ Point old_offset = bufferToClient(Point(0, 0));
+
+ // Update the cached sizing information
+ RECT r;
+ GetClientRect(getMainHandle(), &r);
+ MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right - r.left,
+ r.bottom - r.top - tb.getHeight(), TRUE);
+
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Determine whether scrollbars are required
+ calculateScrollBars();
+
+ // Resize the ToolBar
+ tb.autoSize();
+
+ // Redraw if required
+ if (!old_offset.equals(bufferToClient(Point(0, 0))))
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ }
+ break;
+
+ case WM_HSCROLL:
+ tb.processWM_HSCROLL(wParam, lParam);
+ break;
+
+ case WM_NOTIFY:
+ return tb.processWM_NOTIFY(wParam, lParam);
+
+ case WM_CLOSE:
+ vlog.debug("WM_CLOSE %x", getMainHandle());
+ PostQuitMessage(0);
+ break;
+ }
+
+ return rfb::win32::SafeDefWindowProc(getMainHandle(), msg, wParam, lParam);
+}
+
+LRESULT RfbPlayer::processFrameMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ case WM_PAINT:
+ {
+ if (isSeeking() || rewindFlag) {
+ seekMode = true;
+ return 0;
+ } else {
+ if (seekMode) {
+ seekMode = false;
+ InvalidateRect(getFrameHandle(), 0, true);
+ UpdateWindow(getFrameHandle());
+ return 0;
+ }
+ }
+
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(getFrameHandle(), &ps);
+ if (!paintDC)
+ throw SystemException("unable to BeginPaint", GetLastError());
+ Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+ if (!pr.is_empty()) {
+
+ if (buffer->bitmap) {
+
+ // Get device context
+ BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+ // Blit the border if required
+ Rect bufpos = bufferToClient(buffer->getRect());
+ if (!pr.enclosed_by(bufpos)) {
+ vlog.debug("draw border");
+ HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ RECT r;
+ SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+ }
+
+ // Do the blit
+ Point buf_pos = clientToBuffer(pr.tl);
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+ throw SystemException("unable to BitBlt to window", GetLastError());
+
+ } else {
+ // Blit a load of black
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ 0, 0, 0, BLACKNESS))
+ throw SystemException("unable to BitBlt to blank window", GetLastError());
+ }
+ }
+ EndPaint(getFrameHandle(), &ps);
+ }
+ return 0;
+
+ // Process play/pause by the left mouse button
+ case WM_LBUTTONDOWN:
+ SendMessage(getMainHandle(), WM_COMMAND, ID_PLAYPAUSE, 0);
+ return 0;
+
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ Point delta;
+ int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+ switch (LOWORD(wParam)) {
+ case SB_PAGEUP: newpos -= 50; break;
+ case SB_PAGEDOWN: newpos += 50; break;
+ case SB_LINEUP: newpos -= 5; break;
+ case SB_LINEDOWN: newpos += 5; break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+ default: vlog.info("received unknown scroll message");
+ };
+
+ if (msg == WM_HSCROLL)
+ setViewportOffset(Point(newpos, scrolloffset.y));
+ else
+ setViewportOffset(Point(scrolloffset.x, newpos));
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = newpos;
+ SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void RfbPlayer::disableTBandMenuItems() {
+ // Disable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_GRAYED | MF_BYCOMMAND);
+
+ // Disable the toolbar buttons and child controls
+ tb.disable();
+}
+
+void RfbPlayer::enableTBandMenuItems() {
+ // Enable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_ENABLED | MF_BYCOMMAND);
+
+ // Enable the toolbar buttons and child controls
+ tb.enable();
+}
+
+void RfbPlayer::setVisible(bool visible) {
+ ShowWindow(getMainHandle(), visible ? SW_SHOW : SW_HIDE);
+ if (visible) {
+ // When the window becomes visible, make it active
+ SetForegroundWindow(getMainHandle());
+ SetActiveWindow(getMainHandle());
+ }
+}
+
+void RfbPlayer::setTitle(const char *title) {
+ char _title[256];
+ strcpy(_title, AppName);
+ strcat(_title, " - ");
+ strcat(_title, title);
+ SetWindowText(getMainHandle(), _title);
+}
+
+void RfbPlayer::setFrameSize(int width, int height) {
+ // Calculate and set required size for main window
+ RECT r = {0, 0, width, height};
+ AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), TRUE,
+ GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ r.bottom += tb.getHeight(); // Include RfbPlayr's controls area
+ AdjustWindowRect(&r, GetWindowLong(getMainHandle(), GWL_STYLE), FALSE);
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y, r.right-r.left, r.bottom-r.top,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+ // Enable/disable scrollbars as appropriate
+ calculateScrollBars();
+}
+
+void RfbPlayer::calculateScrollBars() {
+ // Calculate the required size of window
+ DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Work out whether scroll bars are required
+ do {
+ old_style = style;
+
+ if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+ style |= WS_HSCROLL;
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+ }
+ if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+ style |= WS_VSCROLL;
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ }
+ } while (style != old_style);
+
+ // Tell Windows to update the window style & cached settings
+ if (style != current_style) {
+ SetWindowLong(getFrameHandle(), GWL_STYLE, style);
+ SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+
+ // Update the scroll settings
+ SCROLLINFO si;
+ if (style & WS_VSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->height();
+ si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
+ maxscrolloffset.y = max(0, si.nMax-si.nPage);
+ scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+ si.nPos = scrolloffset.y;
+ SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
+ }
+ if (style & WS_HSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->width();
+ si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
+ maxscrolloffset.x = max(0, si.nMax-si.nPage);
+ scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+ si.nPos = scrolloffset.x;
+ SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
+ }
+
+ // Update the cached client size
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+bool RfbPlayer::setViewportOffset(const Point& tl) {
+/* ***
+ Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
+ max(0, min(maxscrolloffset.y, tl.y)));
+ */
+ Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+ max(0, min(tl.y, buffer->height()-client_size.height())));
+ Point delta = np.translate(scrolloffset.negate());
+ if (!np.equals(scrolloffset)) {
+ scrolloffset = np;
+ ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(getFrameHandle());
+ return true;
+ }
+ return false;
+}
+
+void RfbPlayer::close(const char* reason) {
+ setVisible(false);
+ if (reason) {
+ vlog.info("closing - %s", reason);
+ MessageBox(NULL, TStr(reason), "RfbPlayer", MB_ICONINFORMATION | MB_OK);
+ }
+ SendMessage(getFrameHandle(), WM_CLOSE, 0, 0);
+}
+
+void RfbPlayer::blankBuffer() {
+ fillRect(buffer->getRect(), 0);
+}
+
+void RfbPlayer::rewind() {
+ bool paused = isPaused();
+ blankBuffer();
+ newSession(fileName);
+ skipHandshaking();
+ is->setSpeed(options.playbackSpeed);
+ if (paused) is->pausePlayback();
+ else is->resumePlayback();
+}
+
+void RfbPlayer::processMsg() {
+ // Perform return if waitWhilePaused processed because
+ // rfbReader thread could receive the signal to close
+ if (waitWhilePaused()) return;
+
+ static long update_time = GetTickCount();
+ try {
+ if ((!isSeeking()) && ((GetTickCount() - update_time) > 250)
+ && (!tb.isPosSliderDragging())) {
+ // Update pos in the toolbar 4 times in 1 second
+ tb.updatePos(getTimeOffset());
+ update_time = GetTickCount();
+ }
+ RfbProto::processMsg();
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ rewind();
+ setPaused(!options.loopPlayback);
+ tb.updatePos(getTimeOffset());
+ return;
+ }
+ // It's a special exception to perform backward seeking.
+ // We only rewind the stream and seek the offset
+ if (strcmp(e.str(), "[REWIND]") == 0) {
+ rewindFlag = true;
+ long seekOffset = max(getSeekOffset(), imageDataStartTime);
+ rewind();
+ if (!stopped) setPos(seekOffset);
+ else stopped = false;
+ tb.updatePos(seekOffset);
+ rewindFlag = false;
+ return;
+ }
+ // It's a special exception which is used to terminate the playback
+ if (strcmp(e.str(), "[TERMINATE]") == 0) {
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ } else {
+ // Show the exception message and close the session playback
+ is->pausePlayback();
+ char message[256] = "\0";
+ strcat(message, e.str());
+ strcat(message, "\nMaybe you force wrong the pixel format for this session");
+ MessageBox(getMainHandle(), message, "RFB Player", MB_OK | MB_ICONERROR);
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ return;
+ }
+ }
+}
+
+long ChoosePixelFormatDialog::pfIndex = DEFAULT_PF_INDEX;
+bool ChoosePixelFormatDialog::bigEndian = false;
+
+void RfbPlayer::serverInit() {
+ RfbProto::serverInit();
+
+ // Save the image data start time
+ imageDataStartTime = is->getTimeOffset();
+
+ // Resize the backing buffer
+ buffer->setSize(cp.width, cp.height);
+
+ // Check on the true colour mode
+ if (!(cp.pf()).trueColour)
+ throw rdr::Exception("This version plays only true color session!");
+
+ // Set the session pixel format
+ if (options.askPixelFormat) {
+ ChoosePixelFormatDialog choosePixelFormatDialog(&supportedPF);
+ if (choosePixelFormatDialog.showDialog(getMainHandle())) {
+ long pixelFormatIndex = choosePixelFormatDialog.getPFIndex();
+ if (pixelFormatIndex < 0) {
+ options.autoDetectPF = true;
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.autoDetectPF = false;
+ options.setPF(&supportedPF[pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = choosePixelFormatDialog.isBigEndian();
+ }
+ } else {
+ is->pausePlayback();
+ throw rdr::Exception("[TERMINATE]");
+ }
+ } else {
+ if (!options.commandLineParam) {
+ if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.setPF(&supportedPF[options.pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = options.bigEndianFlag;
+ }
+ } else if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ }
+ }
+ cp.setPF(options.pixelFormat);
+ buffer->setPF(options.pixelFormat);
+
+ // If the window is not maximised then resize it
+ if (!(GetWindowLong(getMainHandle(), GWL_STYLE) & WS_MAXIMIZE))
+ setFrameSize(cp.width, cp.height);
+
+ // Set the window title and show it
+ setTitle(cp.name());
+
+ // Calculate the full session time and update posTrackBar control in toolbar
+ sessionTimeMs = calculateSessionTime(fileName);
+ tb.init(sessionTimeMs);
+ tb.updatePos(getTimeOffset());
+
+ setPaused(!options.autoPlay);
+ // Restore the parameters from registry,
+ // which was replaced by command-line parameters.
+ if (options.commandLineParam) {
+ options.readFromRegistry();
+ options.commandLineParam = false;
+ }
+}
+
+void RfbPlayer::setColourMapEntries(int first, int count, U16* rgbs) {
+ vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+ throw rdr::Exception("Can't handle SetColourMapEntries message");
+/* int i;
+ for (i=0;i<count;i++) {
+ buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+ }
+ // *** change to 0, 256?
+ refreshWindowPalette(first, count);
+ palette_changed = true;
+ InvalidateRect(getFrameHandle(), 0, FALSE);*/
+}
+
+void RfbPlayer::bell() {
+ if (options.acceptBell)
+ MessageBeep(-1);
+}
+
+void RfbPlayer::serverCutText(const char* str, int len) {
+ if (cutText != NULL)
+ delete [] cutText;
+ cutText = new char[len + 1];
+ memcpy(cutText, str, len);
+ cutText[len] = '\0';
+}
+
+void RfbPlayer::frameBufferUpdateEnd() {
+};
+
+void RfbPlayer::beginRect(const Rect& r, unsigned int encoding) {
+ currentEncoding = encoding;
+}
+
+void RfbPlayer::endRect(const Rect& r, unsigned int encoding) {
+}
+
+
+void RfbPlayer::fillRect(const Rect& r, Pixel pix) {
+ buffer->fillRect(r, pix);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::imageRect(const Rect& r, void* pixels) {
+ buffer->imageRect(r, pixels);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::copyRect(const Rect& r, int srcX, int srcY) {
+ buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ invalidateBufferRect(r);
+}
+
+bool RfbPlayer::invalidateBufferRect(const Rect& crect) {
+ Rect rect = bufferToClient(crect);
+ if (rect.intersect(client_size).is_empty()) return false;
+ RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+ InvalidateRect(getFrameHandle(), &invalid, FALSE);
+ return true;
+}
+
+bool RfbPlayer::waitWhilePaused() {
+ bool result = false;
+ while(isPaused() && !isSeeking()) {
+ Sleep(20);
+ result = true;
+ }
+ return result;
+}
+
+long RfbPlayer::calculateSessionTime(char *filename) {
+ FbsInputStream sessionFile(filename);
+ sessionFile.setTimeOffset(100000000);
+ try {
+ while (TRUE) {
+ sessionFile.skip(1024);
+ }
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ return sessionFile.getTimeOffset();
+ } else {
+ MessageBox(getMainHandle(), e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void RfbPlayer::init() {
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+}
+
+void RfbPlayer::closeSessionFile() {
+ DWORD dwStyle;
+ RECT r;
+
+ // Uncheck all toolbar buttons
+ if (tb.getHandle()) {
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.checkButton(ID_STOP, false);
+ }
+
+ // Stop playback and update the player state
+ disableTBandMenuItems();
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ delete [] fileName;
+ fileName = 0;
+ }
+ blankBuffer();
+ setTitle("None");
+ options.playbackSpeed = 1.0;
+ tb.init(0);
+
+ // Change the player window size and frame size to default
+ if ((dwStyle = GetWindowLong(getMainHandle(), GWL_STYLE)) & WS_MAXIMIZE) {
+ dwStyle &= ~WS_MAXIMIZE;
+ SetWindowLong(getMainHandle(), GWL_STYLE, dwStyle);
+ }
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y,
+ DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT,
+ SWP_NOZORDER | SWP_FRAMECHANGED);
+ buffer->setSize(32, 32);
+ calculateScrollBars();
+
+ // Update the cached sizing information and repaint the frame window
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ UpdateWindow(getFrameHandle());
+}
+
+void RfbPlayer::openSessionFile(char *_fileName) {
+ fileName = strDup(_fileName);
+
+ // Close the previous reading thread
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ blankBuffer();
+ newSession(fileName);
+ setSpeed(options.playbackSpeed);
+ rfbReader = new rfbSessionReader(this);
+ rfbReader->start();
+ tb.setTimePos(0);
+ enableTBandMenuItems();
+}
+
+void RfbPlayer::setPaused(bool paused) {
+ if (paused) {
+ is->pausePlayback();
+ tb.checkButton(ID_PAUSE, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_STOP, false);
+ } else {
+ if (is) is->resumePlayback();
+ tb.checkButton(ID_PLAY, true);
+ tb.checkButton(ID_STOP, false);
+ tb.checkButton(ID_PAUSE, false);
+ }
+ tb.enableButton(ID_PAUSE, true);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::stopPlayback() {
+ stopped = true;
+ setPos(0);
+ if (is) {
+ is->pausePlayback();
+ is->interruptFrameDelay();
+ }
+ tb.checkButton(ID_STOP, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.enableButton(ID_PAUSE, false);
+ tb.setTimePos(0);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::setSpeed(double speed) {
+ if (speed > 0) {
+ char speedStr[20] = "\0";
+ double newSpeed = min(speed, MAX_SPEED);
+ is->setSpeed(newSpeed);
+ options.playbackSpeed = newSpeed;
+ SendMessage(tb.getSpeedUpDownHwnd(), UDM_SETPOS,
+ 0, MAKELONG((short)(newSpeed / 0.5), 0));
+ sprintf(speedStr, "%.2f", newSpeed);
+ SetWindowText(tb.getSpeedEditHwnd(), speedStr);
+ }
+}
+
+double RfbPlayer::getSpeed() {
+ return is->getSpeed();
+}
+
+void RfbPlayer::setPos(long pos) {
+ is->setTimeOffset(max(pos, imageDataStartTime));
+}
+
+long RfbPlayer::getSeekOffset() {
+ return is->getSeekOffset();
+}
+
+bool RfbPlayer::isSeeking() {
+ if (is) return is->isSeeking();
+ else return false;
+}
+
+bool RfbPlayer::isSeekMode() {
+ return seekMode;
+}
+
+bool RfbPlayer::isPaused() {
+ return is->isPaused();
+}
+
+long RfbPlayer::getTimeOffset() {
+ return max(is->getTimeOffset(), is->getSeekOffset());
+}
+
+void RfbPlayer::skipHandshaking() {
+ int skipBytes = 12 + 4 + 24 + strlen(cp.name());
+ is->skip(skipBytes);
+ state_ = RFBSTATE_NORMAL;
+}
+
+void programInfo() {
+ win32::FileVersionInfo inf;
+ _tprintf(_T("%s - %s, Version %s\n"),
+ inf.getVerString(_T("ProductName")),
+ inf.getVerString(_T("FileDescription")),
+ inf.getVerString(_T("FileVersion")));
+ printf("%s\n", buildTime);
+ _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void programUsage() {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog();
+}
+
+char *fileName = 0;
+
+// playerOptions is the player options with default parameters values,
+// it is used only for run the player with command-line parameters
+PlayerOptions playerOptions;
+bool print_usage = false;
+bool print_upf_list = false;
+
+bool processParams(int argc, char* argv[]) {
+ playerOptions.commandLineParam = true;
+ for (int i = 1; i < argc; i++) {
+ if ((strcasecmp(argv[i], "-help") == 0) ||
+ (strcasecmp(argv[i], "--help") == 0) ||
+ (strcasecmp(argv[i], "/help") == 0) ||
+ (strcasecmp(argv[i], "-h") == 0) ||
+ (strcasecmp(argv[i], "/h") == 0) ||
+ (strcasecmp(argv[i], "/?") == 0) ||
+ (strcasecmp(argv[i], "-?") == 0)) {
+ print_usage = true;
+ return true;
+ }
+
+ if ((strcasecmp(argv[i], "-pf") == 0) ||
+ (strcasecmp(argv[i], "/pf") == 0) && (i < argc-1)) {
+ char *pf = argv[++i];
+ char rgb_order[4] = "\0";
+ int order = RGB_ORDER;
+ int r = -1, g = -1, b = -1;
+ bool big_endian = false;
+ if (strlen(pf) < 6) return false;
+ while (strlen(pf)) {
+ if ((pf[0] == 'r') || (pf[0] == 'R')) {
+ if (r >=0 ) return false;
+ r = atoi(++pf);
+ strcat(rgb_order, "r");
+ continue;
+ }
+ if ((pf[0] == 'g') || (pf[0] == 'G')) {
+ if (g >=0 ) return false;
+ g = atoi(++pf);
+ strcat(rgb_order, "g");
+ continue;
+ }
+ if (((pf[0] == 'b') || (pf[0] == 'B')) &&
+ (pf[1] != 'e') && (pf[1] != 'E')) {
+ if (b >=0 ) return false;
+ b = atoi(++pf);
+ strcat(rgb_order, "b");
+ continue;
+ }
+ if ((pf[0] == 'l') || (pf[0] == 'L') ||
+ (pf[0] == 'b') || (pf[0] == 'B')) {
+ if (strcasecmp(pf, "le") == 0) break;
+ if (strcasecmp(pf, "be") == 0) { big_endian = true; break;}
+ return false;
+ }
+ pf++;
+ }
+ if ((r < 0) || (g < 0) || (b < 0) || (r + g + b > 32)) return false;
+ if (strcasecmp(rgb_order, "rgb") == 0) { order = RGB_ORDER; }
+ else if (strcasecmp(rgb_order, "rbg") == 0) { order = RBG_ORDER; }
+ else if (strcasecmp(rgb_order, "grb") == 0) { order = GRB_ORDER; }
+ else if (strcasecmp(rgb_order, "gbr") == 0) { order = GBR_ORDER; }
+ else if (strcasecmp(rgb_order, "bgr") == 0) { order = BGR_ORDER; }
+ else if (strcasecmp(rgb_order, "brg") == 0) { order = BRG_ORDER; }
+ else return false;
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(order, r, g, b, big_endian);
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-upf") == 0) ||
+ (strcasecmp(argv[i], "/upf") == 0) && (i < argc-1)) {
+ if ((i == argc - 1) || (argv[++i][0] == '-')) {
+ print_upf_list = true;
+ return true;
+ }
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ int index = userPfList.getIndexByPFName(argv[i]);
+ if (index > 0) {
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(&userPfList[index]->PF);
+ } else {
+ return false;
+ }
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-speed") == 0) ||
+ (strcasecmp(argv[i], "/speed") == 0) && (i < argc-1)) {
+ double playbackSpeed = atof(argv[++i]);
+ if (playbackSpeed <= 0) {
+ return false;
+ }
+ playerOptions.playbackSpeed = playbackSpeed;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-pos") == 0) ||
+ (strcasecmp(argv[i], "/pos") == 0) && (i < argc-1)) {
+ long initTime = atol(argv[++i]);
+ if (initTime <= 0)
+ return false;
+ playerOptions.initTime = initTime;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-autoplay") == 0) ||
+ (strcasecmp(argv[i], "/autoplay") == 0) && (i < argc-1)) {
+ playerOptions.autoPlay = true;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-loop") == 0) ||
+ (strcasecmp(argv[i], "/loop") == 0) && (i < argc-1)) {
+ playerOptions.loopPlayback = true;
+ continue;
+ }
+
+ if (i != argc - 1)
+ return false;
+ }
+
+ fileName = strDup(argv[argc-1]);
+ if (fileName[0] == '-') return false;
+ else return true;
+}
+
+//
+// -=- WinMain
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+
+ // - Process the command-line
+
+ int argc = __argc;
+ char** argv = __argv;
+ if ((argc > 1) && (!processParams(argc, argv))) {
+ MessageBox(0, wrong_cmd_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return 0;
+ }
+
+ if (print_usage) {
+ programUsage();
+ return 0;
+ }
+ // Show the user defined pixel formats if required
+ if (print_upf_list) {
+ int list_size = 256;
+ char *upf_list = new char[list_size];
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ strcpy(upf_list, "The list of the user defined pixel formats:\r\n");
+ for (int i = userPfList.getDefaultPFCount(); i < userPfList.count(); i++) {
+ if ((list_size - strlen(upf_list) - 1) <
+ (strlen(userPfList[i]->format_name) + 2)) {
+ char *tmpStr = new char[list_size =
+ list_size + strlen(userPfList[i]->format_name) + 2];
+ strcpy(tmpStr, upf_list);
+ delete [] upf_list;
+ upf_list = new char[list_size];
+ strcpy(upf_list, tmpStr);
+ delete [] tmpStr;
+ }
+ strcat(upf_list, userPfList[i]->format_name);
+ strcat(upf_list, "\r\n");
+ }
+ InfoDialog upfInfoDialog(upf_list);
+ upfInfoDialog.showDialog();
+ delete [] upf_list;
+ return 0;
+ }
+
+ // Create the player
+ RfbPlayer *player = NULL;
+ try {
+ player = new RfbPlayer(fileName, &playerOptions);
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ delete player;
+ return 0;
+ }
+
+ // Run the player
+ HACCEL hAccel = LoadAccelerators(inst, MAKEINTRESOURCE(IDR_ACCELERATOR));
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ if(!TranslateAccelerator(player->getMainHandle(), hAccel, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Destroy the player
+ try{
+ if (player) delete player;
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+
+ return 0;
+};
diff --git a/win/rfbplayer/rfbplayer.dsp b/win/rfbplayer/rfbplayer.dsp
new file mode 100644
index 0000000..9068536
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.dsp
@@ -0,0 +1,207 @@
+# Microsoft Developer Studio Project File - Name="rfbplayer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=rfbplayer - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "rfbplayer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rfbplayer.mak" CFG="rfbplayer - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rfbplayer - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "rfbplayer - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "rfbplayer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\rfbplayer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 user32.lib gdi32.lib Advapi32.lib comctl32.lib shell32.lib comdlg32.lib version.lib /nologo /subsystem:windows /machine:I386
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\rfbplayer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "rfbplayer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\rfbplayer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\rfbplayer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "rfbplayer - Win32 Release"
+# Name "rfbplayer - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\buildTime.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FbsInputStream.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormatList.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerToolBar.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\RfbProto.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\ChoosePixelFormatDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\EditPixelFormatDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FbsInputStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GotoPosDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormatList.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerToolBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RfbProto.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbSessionReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SessionInfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPixelFormatsDialog.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\rfbplayer.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\toolbar.bmp
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win/rfbplayer/rfbplayer.h b/win/rfbplayer/rfbplayer.h
new file mode 100644
index 0000000..c5c5da8
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.h
@@ -0,0 +1,195 @@
+/* Copyright (C) 2004 TightVNC Team. 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,
+ * USA.
+ */
+
+// -=- RfbPlayer.h
+
+#include <windows.h>
+
+#include <rfb_win32/DIBSectionBuffer.h>
+
+#include <rfbplayer/resource.h>
+#include <rfbplayer/PixelFormatList.h>
+#include <rfbplayer/PlayerToolBar.h>
+#include <rfbplayer/OptionsDialog.h>
+#include <rfbplayer/rfbSessionReader.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+class PlayerToolBar;
+
+class RfbPlayer : public RfbProto {
+ public:
+ RfbPlayer(char *fileName, PlayerOptions *options);
+ ~RfbPlayer();
+
+ // -=- Window Message handling
+
+ LRESULT processMainMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ LRESULT processFrameMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // -=- Window interface
+
+ HWND getMainHandle() const {return mainHwnd;}
+ HWND getFrameHandle() const {return frameHwnd;}
+ void disableTBandMenuItems();
+ void enableTBandMenuItems();
+ void setFrameSize(int width, int height);
+ void setVisible(bool visible);
+ void setTitle(const char *title);
+ void calculateScrollBars();
+ void close(const char* reason=0);
+ void init();
+
+ // -=- Coordinate conversions
+
+ inline Point bufferToClient(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x += (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x -= scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y += (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y -= scrolloffset.y;
+ return pos;
+ }
+ inline Rect bufferToClient(const Rect& r) {
+ return Rect(bufferToClient(r.tl), bufferToClient(r.br));
+ }
+
+ inline Point clientToBuffer(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x -= (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x += scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y -= (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y += scrolloffset.y;
+ return pos;
+ }
+ inline Rect clientToBuffer(const Rect& r) {
+ return Rect(clientToBuffer(r.tl), clientToBuffer(r.br));
+ }
+
+ bool setViewportOffset(const Point& tl);
+
+ // -=- RfbProto interface overrides
+
+ virtual void processMsg();
+ virtual void serverInit();
+ virtual void frameBufferUpdateEnd();
+ virtual void setColourMapEntries(int first, int count, U16* rgbs);
+ virtual void serverCutText(const char* str, int len);
+ virtual void bell();
+
+ virtual void beginRect(const Rect& r, unsigned int encoding);
+ virtual void endRect(const Rect& r, unsigned int encoding);
+ virtual void fillRect(const Rect& r, Pixel pix);
+ virtual void imageRect(const Rect& r, void* pixels);
+ virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+ // -=- Player functions
+
+ // calculateSessionTime() calculates the full session time in sec
+ long calculateSessionTime(char *fileName);
+
+ // closeSessionFile() closes the session file and blanks the frame buffer
+ void closeSessionFile();
+
+ // openSessionFile() opens the new session file and starts play it
+ void openSessionFile(char *fileName);
+
+ // skipHandshaking() - is implemented to skip the initial handshaking when
+ // perform backward seeking OR replaying.
+ void skipHandshaking();
+
+ void blankBuffer();
+ void rewind();
+ void setPaused(bool paused);
+ void stopPlayback();
+ long getTimeOffset();
+ bool isSeekMode();
+ bool isSeeking();
+ bool isPaused();
+ long getSeekOffset();
+ void setPos(long pos);
+ void setSpeed(double speed);
+ double getSpeed();
+
+ protected:
+ bool seekMode;
+ bool stopped;
+ long lastPos;
+ long sliderStepMs;
+ char fullSessionTime[20];
+ int time_pos_m;
+ int time_pos_s;
+ char *fileName;
+
+ // rfbReader is a class which used to reading the rfb data from the file
+ rfbSessionReader *rfbReader;
+
+ // Returns true if part of the supplied rect is visible, false otherwise
+ bool invalidateBufferRect(const Rect& crect);
+
+ bool waitWhilePaused();
+
+ // rewindFlag is a flag wich disable the update of the frame buffer window
+ // while the rewind is performing.
+ bool rewindFlag;
+
+ // Local window state
+ HWND mainHwnd;
+ HWND frameHwnd;
+ HMENU hMenu;
+ Rect window_size;
+ Rect client_size;
+ Point scrolloffset;
+ Point maxscrolloffset;
+ char *cutText;
+ win32::DIBSectionBuffer* buffer;
+ PlayerToolBar tb;
+
+ // The player's parameters
+ PlayerOptions options;
+ PixelFormatList supportedPF;
+ long imageDataStartTime;
+ long sessionTimeMs;
+ int currentEncoding;
+};
+
+// -=- sessionTerminateThread class
+
+// It is a special thread class, wich is allow the rfbSessionReader class
+// terminate itself.
+
+class sessionTerminateThread : public rfb::Thread {
+public:
+ sessionTerminateThread(RfbPlayer *_player) : player(_player) {
+ setDeleteAfterRun();
+ }
+ virtual void run() {
+ player->closeSessionFile();
+ }
+protected:
+ RfbPlayer *player;
+};
diff --git a/win/rfbplayer/rfbplayer.ico b/win/rfbplayer/rfbplayer.ico
new file mode 100644
index 0000000..c9136bf
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.ico
Binary files differ
diff --git a/win/rfbplayer/rfbplayer.rc b/win/rfbplayer/rfbplayer.rc
new file mode 100644
index 0000000..169d850
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.rc
@@ -0,0 +1,466 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON DISCARDABLE "rfbplayer.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "TightVNC Team\0"
+ VALUE "FileDescription", "RFB Session Player for Win32\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "rfbplayer\0"
+ VALUE "LegalCopyright", "Copyright (C) 2004-2005 TightVNC Team.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "rfbplayer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Rfb Session Player 1.0\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "File"
+ BEGIN
+ MENUITEM "Open File...\tCtrl+O", ID_OPENFILE
+ MENUITEM "Close File...\tCtrl+Q", ID_CLOSEFILE
+ MENUITEM SEPARATOR
+ MENUITEM "Info...\tCtrl+I", ID_SESSION_INFO
+ MENUITEM SEPARATOR
+ MENUITEM "Exit\tAlt+X", ID_EXIT
+ END
+ POPUP "Play"
+ BEGIN
+ MENUITEM "Play/Pause\tSpace", ID_PLAYPAUSE
+ MENUITEM "Stop\tC", ID_STOP
+ MENUITEM "Go To...\tCtrl+G", ID_GOTO
+ MENUITEM SEPARATOR
+ MENUITEM "Loop\tCtrl+L", ID_LOOP
+ MENUITEM SEPARATOR
+ MENUITEM "Options...\tO", ID_OPTIONS
+ END
+ POPUP "Help"
+ BEGIN
+ MENUITEM "Home Page", ID_HOMEPAGE
+ MENUITEM "Command Line Switches", ID_HELP_COMMANDLINESWITCHES
+ MENUITEM SEPARATOR
+ MENUITEM "About RfbPlayer...", ID_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE
+BEGIN
+ "C", ID_STOP, VIRTKEY, NOINVERT
+ "C", ID_COPYTOCLIPBOARD, VIRTKEY, CONTROL, NOINVERT
+ "C", ID_FRAMEEXTRACT, VIRTKEY, ALT, NOINVERT
+ "G", ID_GOTO, VIRTKEY, CONTROL, NOINVERT
+ "I", ID_SESSION_INFO, VIRTKEY, CONTROL, NOINVERT
+ "L", ID_LOOP, VIRTKEY, CONTROL, NOINVERT
+ "O", ID_OPTIONS, VIRTKEY, NOINVERT
+ "O", ID_OPENFILE, VIRTKEY, CONTROL, NOINVERT
+ "P", ID_OPTIONS, VIRTKEY, CONTROL, NOINVERT
+ "Q", ID_CLOSEFILE, VIRTKEY, CONTROL, NOINVERT
+ VK_F5, ID_ZOOM_50, VIRTKEY, NOINVERT
+ VK_F6, ID_ZOOM_100, VIRTKEY, NOINVERT
+ VK_F7, ID_ZOOM_200, VIRTKEY, NOINVERT
+ VK_RETURN, ID_RETURN, VIRTKEY, NOINVERT
+ VK_RETURN, ID_FULLSCREEN, VIRTKEY, ALT, NOINVERT
+ VK_SPACE, ID_PLAYPAUSE, VIRTKEY, NOINVERT
+ "X", ID_EXIT, VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_GOTO DIALOG DISCARDABLE 0, 0, 153, 54
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Go to position"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_GOTO_EDIT,40,9,106,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,40,33,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,95,33,51,14
+ LTEXT "Pos (ms):",IDC_STATIC,7,9,33,15,SS_CENTERIMAGE
+END
+
+IDD_PIXELFORMAT DIALOG DISCARDABLE 0, 0, 144, 78
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Pixel Format"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_PIXELFORMAT,7,20,130,98,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,20,57,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,75,57,50,14
+ LTEXT "Choose the pixel format:",IDC_STATIC,7,7,130,13
+ CONTROL "Big endian flag",IDC_BIG_ENDIAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,40,63,12
+END
+
+IDD_OPTIONS DIALOG DISCARDABLE 0, 0, 187, 180
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_PIXELFORMAT,15,30,157,75,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Big endian flag",IDC_BIG_ENDIAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,52,60,10
+ CONTROL "Ask the pixel format before playing",IDC_ASK_PF,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,67,157,10
+ CONTROL "Accept the bells",IDC_ACCEPT_BELL,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,105,157,15
+ CONTROL "Accept the cut text",IDC_ACCEPT_CUT_TEXT,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,120,157,15
+ CONTROL "Start play the session when it is opened",IDC_AUTOPLAY,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,135,
+ 157,9
+ DEFPUSHBUTTON "OK",IDOK,20,161,50,13
+ PUSHBUTTON "Cancel",IDCANCEL,75,161,50,13
+ PUSHBUTTON "Default",IDC_DEFAULT,130,161,50,13
+ PUSHBUTTON "Edit User PF",IDC_EDIT_UPF,110,52,62,14
+ GROUPBOX "Pixel format",IDC_STATIC,7,6,173,79
+ LTEXT "Forces the pixel format for the rfb session:",
+ IDC_STATIC,15,17,157,13
+ GROUPBOX "Other",IDC_STATIC,7,90,173,65
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 251, 95
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Rfb Session Player for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,195,70,47,15
+ ICON IDI_ICON,IDC_STATIC,7,10,20,20
+ LTEXT ">appname<",IDC_DESCRIPTION,40,10,125,15
+ LTEXT ">version<",IDC_VERSION,165,10,77,15
+ LTEXT ">buildtime<",IDC_BUILDTIME,40,25,202,15
+ LTEXT ">copyright<",IDC_COPYRIGHT,40,40,202,15
+ LTEXT "See http://www.tightvnc.com for more information on TightVNC.",
+ IDC_STATIC,40,55,202,15
+END
+
+IDD_USERPF_LIST DIALOG DISCARDABLE 0, 0, 207, 162
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Add / Remove the user pixel formats"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LISTBOX IDC_PF_LIST,7,7,136,148,LBS_NOINTEGRALHEIGHT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Add",IDC_ADD_BUTTON,150,7,50,14
+ PUSHBUTTON "Remove",IDC_REMOVE_BUTTON,150,26,50,14
+ PUSHBUTTON "Edit",IDC_EDIT_BUTTON,150,45,50,14
+ PUSHBUTTON "Close",IDOK,150,64,50,14
+END
+
+IDD_UPF_EDIT DIALOG DISCARDABLE 0, 0, 204, 126
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit the user pixel format"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_NAME_EDIT,68,7,129,13,ES_AUTOHSCROLL
+ COMBOBOX IDC_BPP_COMBO,68,23,39,45,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ EDITTEXT IDC_DEPTH_EDIT,157,22,40,13,ES_AUTOHSCROLL | ES_NUMBER
+ COMBOBOX IDC_BIGENDIAN_COMBO,68,38,39,45,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_REDMAX_EDIT,68,54,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_GREENMAX_EDIT,68,70,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_BLUEMAX_EDIT,68,86,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_REDSHIFT_EDIT,157,54,39,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ EDITTEXT IDC_GREENSHIFT_EDIT,157,70,40,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ EDITTEXT IDC_BLUESHIFT_EDIT,157,86,40,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ PUSHBUTTON "OK",IDOK,93,105,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,147,105,50,14
+ LTEXT "Pixel format name:",IDC_STATIC,7,7,57,13,SS_CENTERIMAGE
+ LTEXT "Bit per pixel:",IDC_STATIC,7,23,38,12,SS_CENTERIMAGE
+ LTEXT "Big endian flag :",IDC_STATIC,7,38,53,13,SS_CENTERIMAGE
+ LTEXT "Red max :",IDC_STATIC,7,54,33,13,SS_CENTERIMAGE
+ LTEXT "Green max :",IDC_STATIC,7,70,38,13,SS_CENTERIMAGE
+ LTEXT "Blue max :",IDC_STATIC,7,86,38,13,SS_CENTERIMAGE
+ LTEXT "Depth:",IDC_STATIC,112,23,21,12,SS_CENTERIMAGE
+ LTEXT "Red shifts :",IDC_STATIC,112,54,36,13,SS_CENTERIMAGE
+ LTEXT "Green shifts :",IDC_STATIC,112,70,43,13,SS_CENTERIMAGE
+ LTEXT "Blue shifts :",IDC_STATIC,112,86,43,13,SS_CENTERIMAGE
+END
+
+IDD_INFO DIALOG DISCARDABLE 0, 0, 295, 207
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Information"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,122,186,50,14
+ EDITTEXT IDC_INFO_EDIT,7,7,281,172,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN |
+ WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_SESSION_INFO DIALOG DISCARDABLE 0, 0, 239, 106
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RFB Session Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,182,85,50,14
+ LTEXT "Desktop Name:",IDC_STATIC,7,10,73,15
+ LTEXT "Desktop Size:",IDC_STATIC,7,25,73,15
+ LTEXT "Pixel Format:",IDC_STATIC,7,40,73,15
+ LTEXT "Current Encoding:",IDC_STATIC,7,55,73,15
+ LTEXT "RFB Protocol Version:",IDC_STATIC,7,70,73,15
+ LTEXT "",IDC_DESKTOP_NAME,80,10,152,15
+ LTEXT "",IDC_DESKTOP_SIZE,80,25,152,15
+ LTEXT "",IDC_CURRENT_ENCODING,80,55,152,15
+ LTEXT "",IDC_VERSION,80,70,152,15
+ LTEXT "",IDC_PIXEL_FORMAT,80,40,152,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_GOTO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 146
+ VERTGUIDE, 40
+ VERTGUIDE, 90
+ VERTGUIDE, 95
+ TOPMARGIN, 9
+ BOTTOMMARGIN, 47
+ HORZGUIDE, 9
+ HORZGUIDE, 24
+ HORZGUIDE, 35
+ END
+
+ IDD_PIXELFORMAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 137
+ VERTGUIDE, 20
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ VERTGUIDE, 125
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 71
+ HORZGUIDE, 7
+ HORZGUIDE, 20
+ HORZGUIDE, 35
+ HORZGUIDE, 40
+ HORZGUIDE, 49
+ HORZGUIDE, 57
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 180
+ VERTGUIDE, 15
+ VERTGUIDE, 20
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ VERTGUIDE, 125
+ VERTGUIDE, 130
+ VERTGUIDE, 172
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 174
+ HORZGUIDE, 17
+ HORZGUIDE, 30
+ HORZGUIDE, 42
+ HORZGUIDE, 52
+ HORZGUIDE, 67
+ HORZGUIDE, 85
+ HORZGUIDE, 90
+ HORZGUIDE, 105
+ HORZGUIDE, 120
+ HORZGUIDE, 135
+ HORZGUIDE, 144
+ HORZGUIDE, 150
+ HORZGUIDE, 155
+ HORZGUIDE, 161
+ END
+
+ IDD_USERPF_LIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 155
+ HORZGUIDE, 21
+ HORZGUIDE, 26
+ HORZGUIDE, 40
+ HORZGUIDE, 45
+ HORZGUIDE, 59
+ HORZGUIDE, 64
+ END
+
+ IDD_UPF_EDIT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 119
+ END
+
+ IDD_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 288
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+
+ IDD_SESSION_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 99
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/win/rfbplayer/toolbar.bmp b/win/rfbplayer/toolbar.bmp
new file mode 100644
index 0000000..9347a73
--- /dev/null
+++ b/win/rfbplayer/toolbar.bmp
Binary files differ