Added menu item on win32 tray icon to copy the last 1000 lines from
the log to the clipboard.
This commit is contained in:
parent
5a65e36c99
commit
7b58356fc7
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||
#include "CClient.h"
|
||||
#include "CMSWindowsClipboard.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchTaskBarWindows.h"
|
||||
|
@ -32,10 +34,11 @@ static const UINT g_stateToIconID[CMSWindowsClientTaskBarReceiver::kMaxState] =
|
|||
//
|
||||
|
||||
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
|
||||
HINSTANCE appInstance) :
|
||||
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
||||
CClientTaskBarReceiver(),
|
||||
m_appInstance(appInstance),
|
||||
m_window(NULL)
|
||||
m_window(NULL),
|
||||
m_logBuffer(logBuffer)
|
||||
{
|
||||
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||
m_icon[i] = loadIcon(g_stateToIconID[i]);
|
||||
|
@ -149,6 +152,10 @@ CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
|
|||
showStatus();
|
||||
break;
|
||||
|
||||
case IDC_TASKBAR_LOG:
|
||||
copyLog();
|
||||
break;
|
||||
|
||||
case IDC_TASKBAR_QUIT:
|
||||
quit();
|
||||
break;
|
||||
|
@ -167,6 +174,29 @@ CMSWindowsClientTaskBarReceiver::getIcon() const
|
|||
return reinterpret_cast<Icon>(m_icon[getState()]);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsClientTaskBarReceiver::copyLog() const
|
||||
{
|
||||
if (m_logBuffer != NULL) {
|
||||
// collect log buffer
|
||||
CString data;
|
||||
for (CBufferedLogOutputter::const_iterator index = m_logBuffer->begin();
|
||||
index != m_logBuffer->end(); ++index) {
|
||||
data += *index;
|
||||
data += "\n";
|
||||
}
|
||||
|
||||
// copy log to clipboard
|
||||
if (!data.empty()) {
|
||||
CMSWindowsClipboard clipboard(m_window);
|
||||
clipboard.open(0);
|
||||
clipboard.empty();
|
||||
clipboard.add(IClipboard::kText, data);
|
||||
clipboard.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsClientTaskBarReceiver::onStatusChanged()
|
||||
{
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include "CClientTaskBarReceiver.h"
|
||||
#include <windows.h>
|
||||
|
||||
class CBufferedLogOutputter;
|
||||
|
||||
//! Implementation of CClientTaskBarReceiver for Microsoft Windows
|
||||
class CMSWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
|
||||
public:
|
||||
CMSWindowsClientTaskBarReceiver(HINSTANCE);
|
||||
CMSWindowsClientTaskBarReceiver(HINSTANCE, const CBufferedLogOutputter*);
|
||||
virtual ~CMSWindowsClientTaskBarReceiver();
|
||||
|
||||
// IArchTaskBarReceiver overrides
|
||||
|
@ -33,6 +35,8 @@ public:
|
|||
virtual const Icon getIcon() const;
|
||||
|
||||
protected:
|
||||
void copyLog() const;
|
||||
|
||||
// CClientTaskBarReceiver overrides
|
||||
virtual void onStatusChanged();
|
||||
|
||||
|
@ -53,6 +57,7 @@ private:
|
|||
HWND m_window;
|
||||
HMENU m_menu;
|
||||
HICON m_icon[kMaxState];
|
||||
const CBufferedLogOutputter* m_logBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define IDC_TASKBAR_STATUS_STATUS 1000
|
||||
#define IDC_TASKBAR_QUIT 40003
|
||||
#define IDC_TASKBAR_STATUS 40004
|
||||
#define IDC_TASKBAR_LOG 40005
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
|
|
@ -649,9 +649,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
// send PRINT and FATAL output to a message box
|
||||
CLOG->insert(new CMessageBoxOutputter);
|
||||
|
||||
// save log messages
|
||||
CBufferedLogOutputter logBuffer(1000);
|
||||
CLOG->insert(&logBuffer, true);
|
||||
|
||||
// make the task bar receiver. the user can control this app
|
||||
// through the task bar.
|
||||
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance);
|
||||
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance,
|
||||
&logBuffer);
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
int result;
|
||||
|
@ -670,6 +675,9 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// done with log buffer
|
||||
CLOG->remove(&logBuffer);
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
|
|
|
@ -84,6 +84,7 @@ BEGIN
|
|||
POPUP "Synergy"
|
||||
BEGIN
|
||||
MENUITEM "Show Status", IDC_TASKBAR_STATUS
|
||||
MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Quit", IDC_TASKBAR_QUIT
|
||||
END
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "CMSWindowsServerTaskBarReceiver.h"
|
||||
#include "CServer.h"
|
||||
#include "CMSWindowsClipboard.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchTaskBarWindows.h"
|
||||
|
@ -32,10 +34,11 @@ static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
|
|||
//
|
||||
|
||||
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
|
||||
HINSTANCE appInstance) :
|
||||
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
||||
CServerTaskBarReceiver(),
|
||||
m_appInstance(appInstance),
|
||||
m_window(NULL)
|
||||
m_window(NULL),
|
||||
m_logBuffer(logBuffer)
|
||||
{
|
||||
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||
m_icon[i] = loadIcon(g_stateToIconID[i]);
|
||||
|
@ -169,6 +172,10 @@ CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
|
|||
showStatus();
|
||||
break;
|
||||
|
||||
case IDC_TASKBAR_LOG:
|
||||
copyLog();
|
||||
break;
|
||||
|
||||
case IDC_TASKBAR_QUIT:
|
||||
quit();
|
||||
break;
|
||||
|
@ -187,6 +194,29 @@ CMSWindowsServerTaskBarReceiver::getIcon() const
|
|||
return reinterpret_cast<Icon>(m_icon[getState()]);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsServerTaskBarReceiver::copyLog() const
|
||||
{
|
||||
if (m_logBuffer != NULL) {
|
||||
// collect log buffer
|
||||
CString data;
|
||||
for (CBufferedLogOutputter::const_iterator index = m_logBuffer->begin();
|
||||
index != m_logBuffer->end(); ++index) {
|
||||
data += *index;
|
||||
data += "\n";
|
||||
}
|
||||
|
||||
// copy log to clipboard
|
||||
if (!data.empty()) {
|
||||
CMSWindowsClipboard clipboard(m_window);
|
||||
clipboard.open(0);
|
||||
clipboard.empty();
|
||||
clipboard.add(IClipboard::kText, data);
|
||||
clipboard.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsServerTaskBarReceiver::onStatusChanged()
|
||||
{
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include "CServerTaskBarReceiver.h"
|
||||
#include <windows.h>
|
||||
|
||||
class CBufferedLogOutputter;
|
||||
|
||||
//! Implementation of CServerTaskBarReceiver for Microsoft Windows
|
||||
class CMSWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
|
||||
public:
|
||||
CMSWindowsServerTaskBarReceiver(HINSTANCE);
|
||||
CMSWindowsServerTaskBarReceiver(HINSTANCE, const CBufferedLogOutputter*);
|
||||
virtual ~CMSWindowsServerTaskBarReceiver();
|
||||
|
||||
// IArchTaskBarReceiver overrides
|
||||
|
@ -33,6 +35,8 @@ public:
|
|||
virtual const Icon getIcon() const;
|
||||
|
||||
protected:
|
||||
void copyLog() const;
|
||||
|
||||
// CServerTaskBarReceiver overrides
|
||||
virtual void onStatusChanged();
|
||||
|
||||
|
@ -53,6 +57,7 @@ private:
|
|||
HWND m_window;
|
||||
HMENU m_menu;
|
||||
HICON m_icon[kMaxState];
|
||||
const CBufferedLogOutputter* m_logBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
#define IDC_TASKBAR_STATUS_CLIENTS 1001
|
||||
#define IDC_TASKBAR_QUIT 40003
|
||||
#define IDC_TASKBAR_STATUS 40004
|
||||
#define IDC_TASKBAR_LOG 40005
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 109
|
||||
#define _APS_NEXT_COMMAND_VALUE 40005
|
||||
#define _APS_NEXT_COMMAND_VALUE 40006
|
||||
#define _APS_NEXT_CONTROL_VALUE 1003
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
|
|
|
@ -782,9 +782,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
// send PRINT and FATAL output to a message box
|
||||
CLOG->insert(new CMessageBoxOutputter);
|
||||
|
||||
// save log messages
|
||||
CBufferedLogOutputter logBuffer(1000);
|
||||
CLOG->insert(&logBuffer, true);
|
||||
|
||||
// make the task bar receiver. the user can control this app
|
||||
// through the task bar.
|
||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance);
|
||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
|
||||
&logBuffer);
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
int result;
|
||||
|
@ -803,6 +808,9 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// done with log buffer
|
||||
CLOG->remove(&logBuffer);
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
|
|
|
@ -70,6 +70,7 @@ BEGIN
|
|||
POPUP "Synergy"
|
||||
BEGIN
|
||||
MENUITEM "Show Status", IDC_TASKBAR_STATUS
|
||||
MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Quit", IDC_TASKBAR_QUIT
|
||||
END
|
||||
|
|
|
@ -91,6 +91,10 @@ CLog::~CLog()
|
|||
index != m_outputters.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
for (COutputterList::iterator index = m_alwaysOutputters.begin();
|
||||
index != m_alwaysOutputters.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
ARCH->closeMutex(m_mutex);
|
||||
s_log = NULL;
|
||||
}
|
||||
|
@ -189,13 +193,18 @@ CLog::printt(const char* file, int line, const char* fmt, ...) const
|
|||
}
|
||||
|
||||
void
|
||||
CLog::insert(ILogOutputter* outputter)
|
||||
CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
|
||||
{
|
||||
assert(outputter != NULL);
|
||||
assert(outputter->getNewline() != NULL);
|
||||
|
||||
CLogLock lock(m_mutex);
|
||||
m_outputters.push_front(outputter);
|
||||
if (alwaysAtHead) {
|
||||
m_alwaysOutputters.push_front(outputter);
|
||||
}
|
||||
else {
|
||||
m_outputters.push_front(outputter);
|
||||
}
|
||||
int newlineLength = strlen(outputter->getNewline());
|
||||
if (newlineLength > m_maxNewlineLength) {
|
||||
m_maxNewlineLength = newlineLength;
|
||||
|
@ -207,15 +216,17 @@ CLog::remove(ILogOutputter* outputter)
|
|||
{
|
||||
CLogLock lock(m_mutex);
|
||||
m_outputters.remove(outputter);
|
||||
m_alwaysOutputters.remove(outputter);
|
||||
}
|
||||
|
||||
void
|
||||
CLog::pop_front()
|
||||
CLog::pop_front(bool alwaysAtHead)
|
||||
{
|
||||
CLogLock lock(m_mutex);
|
||||
if (!m_outputters.empty()) {
|
||||
delete m_outputters.front();
|
||||
m_outputters.pop_front();
|
||||
COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
|
||||
if (!list->empty()) {
|
||||
delete list->front();
|
||||
list->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,6 +277,22 @@ CLog::output(int priority, char* msg) const
|
|||
|
||||
// write to each outputter
|
||||
CLogLock lock(m_mutex);
|
||||
for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
|
||||
index != m_alwaysOutputters.end();
|
||||
++index) {
|
||||
// get outputter
|
||||
ILogOutputter* outputter = *index;
|
||||
|
||||
// put an appropriate newline at the end
|
||||
strcat(msg + g_priorityPad, outputter->getNewline());
|
||||
|
||||
// open the outputter
|
||||
outputter->open(kApplication);
|
||||
|
||||
// write message
|
||||
outputter->write(static_cast<ILogOutputter::ELevel>(priority),
|
||||
msg + g_maxPriorityLength - n);
|
||||
}
|
||||
for (COutputterList::const_iterator index = m_outputters.begin();
|
||||
index != m_outputters.end(); ++index) {
|
||||
// get outputter
|
||||
|
|
|
@ -61,12 +61,15 @@ public:
|
|||
true then it also goes to the next outputter, as so on until an
|
||||
outputter returns false or there are no more outputters. Outputters
|
||||
still in the outputter list when the log is destroyed will be
|
||||
deleted.
|
||||
deleted. If \c alwaysAtHead is true then the outputter is always
|
||||
called before all outputters with \c alwaysAtHead false and the
|
||||
return value of the outputter is ignored.
|
||||
|
||||
By default, the logger has one outputter installed which writes to
|
||||
the console.
|
||||
*/
|
||||
void insert(ILogOutputter* adopted);
|
||||
void insert(ILogOutputter* adopted,
|
||||
bool alwaysAtHead = false);
|
||||
|
||||
//! Remove an outputter from the list
|
||||
/*!
|
||||
|
@ -79,9 +82,10 @@ public:
|
|||
//! Remove the outputter from the head of the list
|
||||
/*!
|
||||
Removes and deletes the outputter at the head of the outputter list.
|
||||
This does nothing if the outputter list is empty.
|
||||
This does nothing if the outputter list is empty. Only removes
|
||||
outputters that were inserted with the matching \c alwaysAtHead.
|
||||
*/
|
||||
void pop_front();
|
||||
void pop_front(bool alwaysAtHead = false);
|
||||
|
||||
//! Set the minimum priority filter.
|
||||
/*!
|
||||
|
@ -132,6 +136,7 @@ private:
|
|||
|
||||
CArchMutex m_mutex;
|
||||
COutputterList m_outputters;
|
||||
COutputterList m_alwaysOutputters;
|
||||
int m_maxNewlineLength;
|
||||
int m_maxPriority;
|
||||
};
|
||||
|
|
|
@ -179,3 +179,60 @@ CSystemLogger::~CSystemLogger()
|
|||
delete m_stop;
|
||||
delete m_syslog;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CBufferedLogOutputter
|
||||
//
|
||||
|
||||
CBufferedLogOutputter::CBufferedLogOutputter(UInt32 maxBufferSize) :
|
||||
m_maxBufferSize(maxBufferSize)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CBufferedLogOutputter::~CBufferedLogOutputter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CBufferedLogOutputter::const_iterator
|
||||
CBufferedLogOutputter::begin() const
|
||||
{
|
||||
return m_buffer.begin();
|
||||
}
|
||||
|
||||
CBufferedLogOutputter::const_iterator
|
||||
CBufferedLogOutputter::end() const
|
||||
{
|
||||
return m_buffer.end();
|
||||
}
|
||||
|
||||
void
|
||||
CBufferedLogOutputter::open(const char*)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CBufferedLogOutputter::close()
|
||||
{
|
||||
// remove all elements from the buffer
|
||||
m_buffer.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
CBufferedLogOutputter::write(ELevel, const char* message)
|
||||
{
|
||||
while (m_buffer.size() >= m_maxBufferSize) {
|
||||
m_buffer.pop_front();
|
||||
}
|
||||
m_buffer.push_back(CString(message));
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
CBufferedLogOutputter::getNewline() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -15,7 +15,10 @@
|
|||
#ifndef LOGOUTPUTTERS_H
|
||||
#define LOGOUTPUTTERS_H
|
||||
|
||||
#include "BasicTypes.h"
|
||||
#include "ILogOutputter.h"
|
||||
#include "CString.h"
|
||||
#include "stddeque.h"
|
||||
|
||||
//! Stop traversing log chain outputter
|
||||
/*!
|
||||
|
@ -86,4 +89,40 @@ private:
|
|||
ILogOutputter* m_stop;
|
||||
};
|
||||
|
||||
//! Save log history
|
||||
/*!
|
||||
This outputter records the last N log messages.
|
||||
*/
|
||||
class CBufferedLogOutputter : public ILogOutputter {
|
||||
private:
|
||||
typedef std::deque<CString> CBuffer;
|
||||
|
||||
public:
|
||||
typedef CBuffer::const_iterator const_iterator;
|
||||
|
||||
CBufferedLogOutputter(UInt32 maxBufferSize);
|
||||
virtual ~CBufferedLogOutputter();
|
||||
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get start of buffer
|
||||
const_iterator begin() const;
|
||||
|
||||
//! Get end of buffer
|
||||
const_iterator end() const;
|
||||
|
||||
//@}
|
||||
|
||||
// ILogOutputter overrides
|
||||
virtual void open(const char* title);
|
||||
virtual void close();
|
||||
virtual bool write(ELevel level, const char* message);
|
||||
virtual const char* getNewline() const;
|
||||
|
||||
private:
|
||||
UInt32 m_maxBufferSize;
|
||||
CBuffer m_buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -107,6 +107,10 @@ SOURCE=.\stdbitset.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stddeque.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stdfstream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package 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.
|
||||
*/
|
||||
|
||||
#include "stdpre.h"
|
||||
#include <deque>
|
||||
#include "stdpost.h"
|
Loading…
Reference in New Issue