better notification support; dock icon;
system tray icon;
notification is given when the new message is received
and the dialog is not active window;
notification requires growl in Mac OS X
icon also changes until the window is reactivated
diff --git a/.gitignore b/.gitignore
index 5cd902d..a8568fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 ui_*
 moc_*
 *.pb.*
+qrc*
diff --git a/chatdialog.cpp b/chatdialog.cpp
index 0f6e806..322c947 100644
--- a/chatdialog.cpp
+++ b/chatdialog.cpp
@@ -5,6 +5,7 @@
 #include <iostream>
 #include <QTimer>
 #include <QMetaType>
+#include <QMessageBox>
 
 #define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
 
@@ -67,12 +68,17 @@
       std::exit(1);
     }
   }
-
+  
+  createActions();
+  createTrayIcon();
   connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
   connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
   connect(this, SIGNAL(dataReceived(QString, const char *, size_t)), this, SLOT(processData(QString, const char *, size_t)));
   connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
-  //testDraw();
+  connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
+  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
+
+//testDraw();
 }
 
 ChatDialog::~ChatDialog()
@@ -84,6 +90,46 @@
   }
 }
 
+void 
+ChatDialog::setVisible(bool visible)
+{
+  minimizeAction->setEnabled(visible);
+  maximizeAction->setEnabled(!isMaximized());
+  restoreAction->setEnabled(isMaximized() || !visible);
+  QDialog::setVisible(visible);
+}
+
+void 
+ChatDialog::closeEvent(QCloseEvent *e)
+{
+  if (trayIcon->isVisible())
+  {
+    QMessageBox::information(this, tr("Sync-Demo"),
+			     tr("The program will keep running in the "
+				"system tray. To terminate the program"
+				"choose <b>Quit</b> in the context memu"
+				"of the system tray entry."));
+    hide();
+    e->ignore();
+  }
+}
+
+void 
+ChatDialog::changeEvent(QEvent *e)
+{
+  switch(e->type()) 
+  {
+  case QEvent::ActivationChange:
+    if (isActiveWindow()) 
+    {
+      trayIcon->setIcon(QIcon(":/images/icon_small.png"));
+    }
+    break;
+  default:
+    break;
+  }
+}
+
 void
 ChatDialog::appendMessage(const SyncDemo::ChatMessage msg) 
 {
@@ -111,6 +157,7 @@
   table->cellAt(0, 1).firstCursorPosition().insertText(msg.data().c_str());
   QScrollBar *bar = textEdit->verticalScrollBar();
   bar->setValue(bar->maximum());
+  showMessage(from, msg.data().c_str());
 }
 
 void
@@ -375,6 +422,74 @@
   }
 }
 
+void
+ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
+{
+  switch (reason)
+  {
+  case QSystemTrayIcon::Trigger:
+  case QSystemTrayIcon::DoubleClick:
+    break;
+  case QSystemTrayIcon::MiddleClick:
+    // showMessage();
+    break;
+  default:;
+  }
+}
+
+void
+ChatDialog::showMessage(QString from, QString data)
+{
+  //  std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
+  if (!isActiveWindow()) 
+  {
+    trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
+    trayIcon->setIcon(QIcon(":/images/note.png"));
+  }
+}
+
+void
+ChatDialog::messageClicked()
+{
+  this->showMaximized();
+}
+
+void
+ChatDialog::createActions()
+{
+  minimizeAction = new QAction(tr("Mi&nimize"), this);
+  connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
+  
+  maximizeAction = new QAction(tr("Ma&ximize"), this);
+  connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
+  
+  restoreAction = new QAction(tr("&Restore"), this);
+  connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
+  
+  quitAction = new QAction(tr("Quit"), this);
+  connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+}
+
+void
+ChatDialog::createTrayIcon()
+{
+  trayIconMenu = new QMenu(this);
+  trayIconMenu->addAction(minimizeAction);
+  trayIconMenu->addAction(maximizeAction);
+  trayIconMenu->addAction(restoreAction);
+  trayIconMenu->addSeparator();
+  trayIconMenu->addAction(quitAction);
+
+  trayIcon = new QSystemTrayIcon(this);
+  trayIcon->setContextMenu(trayIconMenu);
+
+  QIcon icon(":/images/icon_small.png");
+  trayIcon->setIcon(icon);
+  setWindowIcon(icon);
+  trayIcon->setToolTip("Sync-Demo System Tray Icon");
+  trayIcon->setVisible(true);
+}
+
 void 
 ChatDialog::resizeEvent(QResizeEvent *e)
 {
diff --git a/chatdialog.h b/chatdialog.h
index e5e0c34..116e20e 100644
--- a/chatdialog.h
+++ b/chatdialog.h
@@ -9,22 +9,31 @@
 #include <sync-app-socket.h>
 #include <sync-logic.h>
 #include <sync-seq-no.h>
+#include <QSystemTrayIcon>
 
 #define ORGANIZATION "IRL@UCLA"
 #define APPLICATION "SYNC-DEMO"
 
+class QAction;
+class QMenu;
+
 class ChatDialog : public QDialog,  private Ui::ChatDialog 
 {
 	Q_OBJECT
 
 public:
-	ChatDialog(QWidget *parent = 0);
+  ChatDialog(QWidget *parent = 0);
   ~ChatDialog();
+  void setVisible(bool visible);
   void processRemove(const std::string);
   void appendMessage(const SyncDemo::ChatMessage msg);
   void processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>, Sync::SyncAppSocket *);
   void processDataWrapper(std::string, const char *buf, size_t len);
 
+protected:
+  void closeEvent(QCloseEvent *e);
+  void changeEvent(QEvent *e);
+
 public slots:
   void processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
   void processData(QString name, const char *buf, size_t len);
@@ -38,6 +47,8 @@
   void showEvent(QShowEvent *);
   void fitView();
   void testDraw();
+  void createTrayIcon();
+  void createActions();
 
 private slots:
   void returnPressed();
@@ -45,6 +56,11 @@
   void checkSetting();
   void settingUpdated(QString, QString, QString);
 
+  // icon related
+  void iconActivated(QSystemTrayIcon::ActivationReason reason);
+  void showMessage(QString, QString);
+  void messageClicked();
+
 signals:
   void dataReceived(QString name, const char *buf, size_t len);
   void treeUpdated(const std::vector<Sync::MissingDataInfo>);
@@ -56,5 +72,13 @@
   DigestTreeScene *m_scene;
   boost::mutex m_msgMutex;
   boost::mutex m_sceneMutex;
+
+  // icon related
+  QAction *minimizeAction;
+  QAction *maximizeAction;
+  QAction *restoreAction;
+  QAction *quitAction;
+  QSystemTrayIcon *trayIcon;
+  QMenu *trayIconMenu;
 };
 #endif
diff --git a/demo.icns b/demo.icns
new file mode 100644
index 0000000..c3661e6
--- /dev/null
+++ b/demo.icns
Binary files differ
diff --git a/demo.qrc b/demo.qrc
new file mode 100644
index 0000000..b17d550
--- /dev/null
+++ b/demo.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+	   <file>images/icon_large.png</file>
+	   <file>images/icon_small.png</file>
+	   <file>images/note.png</file>
+</qresource>
+</RCC>
diff --git a/images/icon_large.png b/images/icon_large.png
new file mode 100644
index 0000000..b0bde46
--- /dev/null
+++ b/images/icon_large.png
Binary files differ
diff --git a/images/icon_small.png b/images/icon_small.png
new file mode 100644
index 0000000..a9630a8
--- /dev/null
+++ b/images/icon_small.png
Binary files differ
diff --git a/images/note.png b/images/note.png
new file mode 100644
index 0000000..2881ccd
--- /dev/null
+++ b/images/note.png
Binary files differ
diff --git a/main.cpp b/main.cpp
index 6b73923..c12375a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,10 +1,27 @@
 #include<QApplication>
 #include "chatdialog.h"
+#include <QMessageBox>
 
 int main(int argc, char *argv[]) 
 {
+
+  Q_INIT_RESOURCE(demo);
   QApplication app(argc, argv);
+
+  if (!QSystemTrayIcon::isSystemTrayAvailable()) {
+    QMessageBox::critical(0, QObject::tr("Systray"),
+			  QObject::tr("I couldn't detect any system tray "
+				      "on this system."));
+    return 1;
+  }
+  QApplication::setQuitOnLastWindowClosed(false);
   
+#ifdef __APPLE__
+	app.setWindowIcon(QIcon(":/demo.icns"));
+#else
+	app.setWindowIcon(QIcon(":/images/icon_large.png"));
+#endif
+
   ChatDialog dialog;
   dialog.show();
   dialog.activateWindow();
diff --git a/sync-demo.pro b/sync-demo.pro
index 7eb99d0..a12f970 100644
--- a/sync-demo.pro
+++ b/sync-demo.pro
@@ -12,6 +12,9 @@
           settingdialog.cpp \
           treelayout.cpp 
 
+RESOURCES = demo.qrc
+ICON = demo.icns
+QT += xml svg
 FORMS = chatdialog.ui \
         settingdialog.ui