Added menu item on win32 tray icon to copy the last 1000 lines from

the log to the clipboard.
This commit is contained in:
crs 2003-06-02 20:06:03 +00:00
parent 5a65e36c99
commit 7b58356fc7
16 changed files with 258 additions and 19 deletions

View File

@ -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()
{

View File

@ -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

View File

@ -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
//

View File

@ -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) {

View File

@ -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

View File

@ -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()
{

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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 "";
}

View File

@ -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

View File

@ -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

17
lib/common/stddeque.h Normal file
View 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"