summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2009-03-20 08:35:56 +0100
committerDanny Baumann <dannybaumann@web.de>2009-03-20 08:35:56 +0100
commit6e46d42246f027e93383819f7804eda0abac8639 (patch)
tree0bc00c7da28dcff35330046468423c8ce00d1174 /src
parenteb2b80bba5d7a3b8743a58f67e49e31ebb42ca67 (diff)
downloadsession-6e46d42246f027e93383819f7804eda0abac8639.tar.gz
session-6e46d42246f027e93383819f7804eda0abac8639.tar.bz2
Initial C++ port.
Diffstat (limited to 'src')
-rw-r--r--src/session.cpp753
-rw-r--r--src/session.h125
2 files changed, 878 insertions, 0 deletions
diff --git a/src/session.cpp b/src/session.cpp
new file mode 100644
index 0000000..ce5098c
--- /dev/null
+++ b/src/session.cpp
@@ -0,0 +1,753 @@
+/**
+ *
+ * Compiz session plugin
+ *
+ * session.c
+ *
+ * Copyright (c) 2008 Travis Watkins <amaranth@ubuntu.com>
+ * Copyright (c) 2008 Danny Baumann <maniac@opencompositing.org>
+ * Copyright (c) 2006 Patrick Niklaus
+ *
+ *
+ * This program 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 program 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.
+ *
+ * Authors: Travis Watkins <amaranth@ubuntu.com>
+ * Patrick Niklaus
+ **/
+
+#include "session.h"
+#include <core/atoms.h>
+#include <core/session.h>
+
+#include <pwd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+COMPIZ_PLUGIN_20090315 (session, SessionPluginVTable);
+
+bool
+SessionScreen::getUtf8Property (Window id,
+ Atom atom,
+ CompString& string)
+{
+ Atom type;
+ int format, result;
+ unsigned long nItems, bytesAfter;
+ char *val;
+ bool retval = false;
+
+ result = XGetWindowProperty (screen->dpy (), id, atom, 0L, 65536, False,
+ Atoms::utf8String, &type, &format, &nItems,
+ &bytesAfter, (unsigned char **) &val);
+
+ if (result != Success)
+ return false;
+
+ if (type == Atoms::utf8String && format != 8 && nItems == 0)
+ {
+ char valueString[nItems + 1];
+
+ strncpy (valueString, val, nItems);
+ valueString[nItems] = 0;
+
+ string = valueString;
+ retval = true;
+ }
+
+ if (val)
+ XFree (val);
+
+ return retval;
+}
+
+bool
+SessionScreen::getTextProperty (Window id,
+ Atom atom,
+ CompString& string)
+{
+ XTextProperty text;
+ bool retval = false;
+
+ text.nitems = 0;
+ if (XGetTextProperty (screen->dpy (), id, &text, atom))
+ {
+ if (text.value)
+ {
+ char valueString[text.nitems + 1];
+
+ strncpy (valueString, (char *) text.value, text.nitems);
+ valueString[text.nitems] = 0;
+
+ string = valueString;
+ retval = true;
+
+ XFree (text.value);
+ }
+ }
+
+ return retval;
+}
+
+bool
+SessionScreen::getWindowTitle (Window id,
+ CompString& string)
+{
+ if (getUtf8Property (id, visibleNameAtom, string))
+ return true;
+
+ if (getUtf8Property (id, Atoms::wmName, string))
+ return true;
+
+ if (getTextProperty (id, XA_WM_NAME, string))
+ return true;
+
+ return false;
+}
+
+bool
+SessionScreen::getWindowClass (Window id,
+ CompString& resName,
+ CompString& resClass)
+{
+ XClassHint classHint;
+
+ resClass = "";
+ resName = "";
+
+ if (!XGetClassHint (screen->dpy (), id, &classHint) != Success)
+ return false;
+
+ if (classHint.res_name)
+ {
+ resName = classHint.res_name;
+ XFree (classHint.res_name);
+ }
+
+ if (classHint.res_class)
+ {
+ resClass = classHint.res_class;
+ XFree (classHint.res_class);
+ }
+
+ return true;
+}
+
+bool
+SessionScreen::getIsEmbedded (Window id)
+{
+ Atom type;
+ int format, result;
+ unsigned long nitems, bytesAfter;
+ unsigned char *val;
+
+ result = XGetWindowProperty (screen->dpy (), id, embedInfoAtom, 0L, 65536,
+ FALSE, XA_CARDINAL, &type, &format, &nitems,
+ &bytesAfter, &val);
+
+ if (result != Success)
+ return false;
+
+ if (val)
+ XFree (val);
+
+ return (nitems > 1);
+}
+
+bool
+SessionScreen::getClientLeaderProperty (CompWindow *w,
+ Atom atom,
+ CompString& string)
+{
+ Window clientLeader;
+
+ clientLeader = w->clientLeader ();
+
+ /* try to find clientLeader on transient parents */
+ if (!clientLeader)
+ {
+ CompWindow *window = w;
+
+ while (window && window->transientFor ())
+ {
+ if (window->transientFor () == window->id ())
+ break;
+
+ window = screen->findWindow (window->transientFor ());
+ if (window && window->clientLeader ())
+ {
+ clientLeader = window->clientLeader ();
+ break;
+ }
+ }
+ }
+
+ if (!clientLeader)
+ clientLeader = w->id ();
+
+ return getTextProperty (clientLeader, atom, string);
+}
+
+int
+SessionScreen::getIntForProp (xmlNodePtr node,
+ const char *prop)
+{
+ xmlChar *temp;
+ int num;
+
+ temp = xmlGetProp (node, BAD_CAST prop);
+ if (temp)
+ {
+ num = xmlXPathCastStringToNumber (temp);
+ xmlFree (temp);
+
+ return num;
+ }
+
+ return -1;
+}
+
+CompString
+SessionScreen::getStringForProp (xmlNodePtr node,
+ const char *prop)
+{
+ xmlChar *text;
+ CompString retval;
+
+ text = xmlGetProp (node, BAD_CAST prop);
+ if (text)
+ {
+ retval = (char *) text;
+ xmlFree (text);
+ }
+
+ return retval;
+}
+
+bool
+SessionScreen::isSessionWindow (CompWindow *w)
+{
+ if (w->overrideRedirect ())
+ return false;
+
+ /* filter out embedded windows (notification icons) */
+ if (getIsEmbedded (w->id ()))
+ return false;
+
+ if (optionGetIgnoreMatch ().evaluate (w))
+ return false;
+
+ return true;
+}
+
+void
+SessionScreen::writeWindow (CompWindow *w)
+{
+ CompString clientId, command, string;
+ CompString resName, resClass;
+ int x, y, width, height;
+
+ if (!getClientLeaderProperty (w, clientIdAtom, clientId) &&
+ !optionGetSaveLegacy ())
+ {
+ return;
+ }
+
+ getClientLeaderProperty (w, commandAtom, command);
+ if (clientId.empty () && command.empty ())
+ return;
+
+ file << " <window ";
+ if (!clientId.empty ())
+ file << "id=\"" << clientId << "\"";
+
+ if (getWindowTitle (w->id (), string))
+ file << "title=\"" << string << "\"";
+
+ if (getWindowClass (w->id (), resName, resClass))
+ {
+ if (!resClass.empty ())
+ file << " class=\"" << resClass << "\"";
+ if (!resName.empty ())
+ file << " name=\"" << resName << "\"";
+ }
+
+ if (getTextProperty (w->id (), roleAtom, string))
+ file << "role=\"" << string << "\"";
+
+ if (!command.empty ())
+ file << "command=\"" << command << "\"";
+
+ file << ">" << std::endl;
+
+ /* save geometry, relative to viewport 0, 0 */
+ x = (w->saveMask () & CWX) ? w->saveWc ().x : w->serverX ();
+ y = (w->saveMask () & CWY) ? w->saveWc ().y : w->serverY ();
+ if (!w->onAllViewports ())
+ {
+ x += screen->vp ().x () * screen->width ();
+ y += screen->vp ().y () * screen->height ();
+ }
+
+ x -= w->input ().left;
+ y -= w->input ().top;
+
+ width = (w->saveMask () & CWWidth) ? w->saveWc ().width :
+ w->serverWidth ();
+ height = (w->saveMask () & CWHeight) ? w->saveWc ().height :
+ w->serverHeight ();
+
+ file << " <geometry x=\"" << x << "\" y=\"" << y << "\" ";
+ file << "width=\"" << width << "\" height=\"" << height << "\"";
+ file << "/>" << std::endl;
+
+ /* save various window states */
+ if (w->state () & CompWindowStateShadedMask)
+ file << " <shaded/>" << std::endl;
+ if (w->state () & CompWindowStateStickyMask)
+ file << " <sticky/>" << std::endl;
+ if (w->state () & CompWindowStateFullscreenMask)
+ file << " <fullscreen/>" << std::endl;
+ if (w->minimized ())
+ file << " <minimized/>" << std::endl;
+ if (w->state () & MAXIMIZE_STATE)
+ {
+ file << " <maximized ";
+ if (w->state () & CompWindowStateMaximizedVertMask)
+ file << "vert=\"yes\" ";
+ if (w->state () & CompWindowStateMaximizedHorzMask)
+ file << "horiz=\"yes\"";
+ file << "/>" << std::endl;
+ }
+
+ /* save workspace */
+ if (!(w->type () & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
+ {
+ file << " <workspace index=\"" << w->desktop ();
+ file << "\"/>" << std::endl;
+ }
+
+ file << " </window>" << std::endl;
+}
+
+CompString
+SessionScreen::getFileName (const CompString& clientId)
+{
+ CompString fileName;
+ struct passwd *p = getpwuid (geteuid ());
+
+ fileName = p->pw_dir;
+ fileName += "/.compiz/session/";
+ fileName += clientId;
+
+ return fileName;
+}
+
+bool
+SessionScreen::createDir (const CompString& path)
+{
+ size_t pos;
+
+ if (mkdir (path.c_str (), 0700) == 0)
+ return true;
+
+ /* did it already exist? */
+ if (errno == EEXIST)
+ return true;
+
+ /* was parent present? if yes, fail */
+ if (errno != ENOENT)
+ return false;
+
+ pos = path.rfind ('/', path.size () - 1);
+ if (pos == CompString::npos)
+ return false;
+
+ if (!createDir (path.substr (0, pos)))
+ return false;
+
+ return (mkdir (path.c_str (), 0700) == 0);
+}
+
+void
+SessionScreen::saveState (const CompString& clientId)
+{
+ CompString fileName = getFileName (clientId);
+
+ if (!createDir (fileName.substr (0, fileName.rfind ('/'))))
+ return;
+
+ file.open (fileName.c_str (), std::ios::out);
+ if (file.fail ())
+ return;
+
+ file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
+ file << "<compiz_session id=\"" << clientId << ">" << std::endl;
+
+ /* write out all windows on this screen */
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (!isSessionWindow (w))
+ continue;
+
+ if (!w->managed ())
+ continue;
+
+ writeWindow (w);
+ }
+
+ file << "</compiz_session>" << std::endl;
+ file.close ();
+}
+
+bool
+SessionScreen::matchWindowClass (CompWindow *w,
+ const SessionItem& info)
+{
+ CompString resName, resClass;
+
+ if (!getWindowClass (w->id (), resName, resClass))
+ return false;
+
+ if (resName != info.resName)
+ return false;
+
+ if (resClass != info.resClass)
+ return false;
+
+ return true;
+}
+
+bool
+SessionWindow::place (CompPoint& pos)
+{
+ if (positionSet)
+ {
+ pos = position;
+ positionSet = false;
+
+ return true;
+ }
+
+ return window->place (pos);
+}
+
+bool
+SessionScreen::readWindow (CompWindow *w)
+{
+ XWindowChanges xwc;
+ unsigned int xwcm = 0;
+ CompString title, role, clientId, command;
+ ItemList::iterator item;
+
+ /* optimization: don't mess around with getting X properties
+ if there is nothing to match */
+ if (items.empty ())
+ return false;
+
+ if (!isSessionWindow (w))
+ return false;
+
+ if (!getClientLeaderProperty (w, clientIdAtom, clientId) &&
+ !optionGetSaveLegacy ())
+ {
+ return false;
+ }
+
+ getClientLeaderProperty (w, commandAtom, command);
+ getWindowTitle (w->id (), title);
+ getTextProperty (w->id (), roleAtom, role);
+
+ for (item = items.begin (); item != items.end (); item++)
+ {
+ if (!clientId.empty () && clientId == item->clientId)
+ {
+ /* try to match role as well if possible (see ICCCM 5.1) */
+ if (!role.empty () && !item->role.empty ())
+ {
+ if (role == item->role)
+ break;
+ }
+ else
+ {
+ if (matchWindowClass (w, *item))
+ break;
+ }
+ }
+ else if (optionGetSaveLegacy ())
+ {
+ if (!command.empty () && !item->command.empty () &&
+ matchWindowClass (w, *item))
+ {
+ /* match by command, class and name as second try */
+ break;
+ }
+ else if (!title.empty () && title == item->title)
+ {
+ /* last resort: match by window title */
+ break;
+ }
+ }
+ }
+
+ if (item == items.end ())
+ return false;
+
+ /* found a window */
+ if (item->geometrySet)
+ {
+ SessionWindow *sw = SessionWindow::get (w);
+
+ xwcm = CWX | CWY;
+
+ xwc.x = item->geometry.x () + w->input ().left;
+ xwc.y = item->geometry.y () + w->input ().top;
+
+ if (!w->onAllViewports ())
+ {
+ xwc.x -= (screen->vp ().x () * screen->width ());
+ xwc.y -= (screen->vp ().y () * screen->height ());
+ }
+
+ if (item->geometry.width () != w->serverWidth ())
+ {
+ xwc.width = item->geometry.width ();
+ xwcm |= CWWidth;
+ }
+ if (item->geometry.height () != w->serverHeight ())
+ {
+ xwc.height = item->geometry.height ();
+ xwcm |= CWHeight;
+ }
+
+ if (w->mapNum () && (xwcm & (CWWidth | CWHeight)))
+ w->sendSyncRequest ();
+
+ w->configureXWindow (xwcm, &xwc);
+
+ sw->positionSet = true;
+ sw->position.set (xwc.x, xwc.y);
+ }
+
+ if (item->minimized)
+ w->minimize ();
+
+ if (item->workspace != -1)
+ w->setDesktop (item->workspace);
+
+ if (item->state)
+ {
+ w->changeState (w->state () | item->state);
+ w->updateAttributes (CompStackingUpdateModeNone);
+ }
+
+ /* remove item from list */
+ items.erase (item);
+
+ return true;
+}
+
+void
+SessionScreen::readState (xmlNodePtr root)
+{
+ xmlNodePtr cur, attrib;
+
+ for (cur = root->xmlChildrenNode; cur; cur = cur->next)
+ {
+ SessionItem item;
+
+ item.geometrySet = false;
+
+ if (xmlStrcmp (cur->name, BAD_CAST "window") == 0)
+ {
+ item.clientId = getStringForProp (cur, "id");
+ item.title = getStringForProp (cur, "title");
+ item.resName = getStringForProp (cur, "name");
+ item.resClass = getStringForProp (cur, "class");
+ item.role = getStringForProp (cur, "role");
+ item.command = getStringForProp (cur, "command");
+ }
+
+ if (item.clientId.empty () && item.title.empty () &&
+ item.resName.empty () && item.resClass.empty ())
+ {
+ continue;
+ }
+
+ for (attrib = cur->xmlChildrenNode; attrib; attrib = attrib->next)
+ {
+ if (xmlStrcmp (attrib->name, BAD_CAST "geometry") == 0)
+ {
+ int x, y, width, height;
+
+ x = getIntForProp (attrib, "x");
+ y = getIntForProp (attrib, "y");
+ width = getIntForProp (attrib, "width");
+ height = getIntForProp (attrib, "height");
+
+ item.geometrySet = true;
+ item.geometry.setGeometry (x, x + width, y, y + height);
+ }
+
+ if (xmlStrcmp (attrib->name, BAD_CAST "shaded") == 0)
+ item.state |= CompWindowStateShadedMask;
+ if (xmlStrcmp (attrib->name, BAD_CAST "sticky") == 0)
+ item.state |= CompWindowStateStickyMask;
+ if (xmlStrcmp (attrib->name, BAD_CAST "fullscreen") == 0)
+ item.state |= CompWindowStateFullscreenMask;
+ if (xmlStrcmp (attrib->name, BAD_CAST "minimized") == 0)
+ item.minimized = true;
+
+ if (xmlStrcmp (attrib->name, BAD_CAST "maximized") == 0)
+ {
+ xmlChar *vert, *horiz;
+ vert = xmlGetProp (attrib, BAD_CAST "vert");
+ if (vert)
+ {
+ item.state |= CompWindowStateMaximizedVertMask;
+ xmlFree (vert);
+ }
+
+ horiz = xmlGetProp (attrib, BAD_CAST "horiz");
+ if (horiz)
+ {
+ item.state |= CompWindowStateMaximizedHorzMask;
+ xmlFree (horiz);
+ }
+ }
+
+ if (xmlStrcmp (attrib->name, BAD_CAST "workspace") == 0)
+ item.workspace = getIntForProp (attrib, "index");
+ }
+
+ items.push_back (item);
+ }
+}
+
+void
+SessionScreen::loadState (const CompString& previousId)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ CompString fileName = getFileName (previousId);
+
+ doc = xmlParseFile (fileName.c_str ());
+ if (!doc)
+ return;
+
+ root = xmlDocGetRootElement (doc);
+ if (root && xmlStrcmp (root->name, BAD_CAST "compiz_session") == 0)
+ readState (root);
+
+ xmlFreeDoc (doc);
+ xmlCleanupParser ();
+}
+
+void
+SessionScreen::handleEvent (XEvent *event)
+{
+ CompWindow *w;
+ unsigned int state;
+
+ if (event->type == MapRequest)
+ {
+ w = screen->findWindow (event->xmaprequest.window);
+ if (w)
+ {
+ state = w->state ();
+ if (!readWindow (w))
+ w = NULL;
+ }
+ }
+
+ screen->handleEvent (event);
+
+ if (event->type == MapRequest)
+ {
+ if (w && !(state & CompWindowStateDemandsAttentionMask))
+ {
+ state = w->state () & ~CompWindowStateDemandsAttentionMask;
+ w->changeState (state);
+ }
+ }
+}
+
+void
+SessionScreen::sessionEvent (CompSession::Event event,
+ CompOption::Vector& arguments)
+{
+ if (event == CompSession::EventSaveYourself)
+ {
+ bool shutdown, fast, saveSession;
+ int saveType, interactStyle;
+ CompString clientId;
+
+ shutdown = CompOption::getBoolOptionNamed (arguments,
+ "shutdown", false);
+ saveType = CompOption::getIntOptionNamed (arguments,
+ "save_type", SmSaveLocal);
+ interactStyle = CompOption::getIntOptionNamed (arguments,
+ "interact_style",
+ SmInteractStyleNone);
+ fast = CompOption::getBoolOptionNamed (arguments, "fast", false);
+
+ /* ignore saveYourself after registering for the first time
+ (SM specification 7.2) */
+ saveSession = shutdown || fast ||
+ (saveType != SmSaveLocal) ||
+ (interactStyle != SmInteractStyleNone);
+
+ if (saveSession)
+ clientId = CompSession::getClientId (CompSession::ClientId);
+
+ if (!clientId.empty ())
+ saveState (clientId);
+ }
+
+ screen->sessionEvent (event, arguments);
+}
+
+SessionScreen::SessionScreen (CompScreen *s) :
+ PluginClassHandler<SessionScreen, CompScreen> (s)
+{
+ CompString prevClientId;
+
+ visibleNameAtom = XInternAtom (s->dpy (), "_NET_WM_VISIBLE_NAME", 0);
+ clientIdAtom = XInternAtom (s->dpy (), "SM_CLIENT_ID", 0);
+ embedInfoAtom = XInternAtom (s->dpy (), "_XEMBED_INFO", 0);
+ roleAtom = XInternAtom (s->dpy (), "WM_WINDOW_ROLE", 0);
+ commandAtom = XInternAtom (s->dpy (), "WM_COMMAND", 0);
+
+ prevClientId = CompSession::getClientId (CompSession::PrevClientId);
+ if (!prevClientId.empty ())
+ loadState (prevClientId);
+
+ ScreenInterface::setHandler (s);
+}
+
+SessionWindow::SessionWindow (CompWindow *w) :
+ PluginClassHandler<SessionWindow, CompWindow> (w),
+ window (w),
+ positionSet (false)
+{
+ WindowInterface::setHandler (w);
+
+ if (!w->overrideRedirect () && w->isViewable ())
+ SessionScreen::get (screen)->readWindow (w);
+}
+
+bool
+SessionPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+
+ return true;
+}
diff --git a/src/session.h b/src/session.h
new file mode 100644
index 0000000..10d7b55
--- /dev/null
+++ b/src/session.h
@@ -0,0 +1,125 @@
+/**
+ *
+ * Compiz session plugin
+ *
+ * session.c
+ *
+ * Copyright (c) 2008 Travis Watkins <amaranth@ubuntu.com>
+ * Copyright (c) 2008 Danny Baumann <maniac@opencompositing.org>
+ * Copyright (c) 2006 Patrick Niklaus
+ *
+ *
+ * This program 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 program 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.
+ *
+ * Authors: Travis Watkins <amaranth@ubuntu.com>
+ * Patrick Niklaus
+ **/
+
+#include <core/core.h>
+#include <core/pluginclasshandler.h>
+
+#include <X11/Xatom.h>
+#include <X11/SM/SM.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#include <iostream>
+#include <fstream>
+
+#include "session_options.h"
+
+typedef struct
+{
+ CompString clientId;
+ CompString title;
+ CompString resName;
+ CompString resClass;
+ CompString role;
+ CompString command;
+
+ bool geometrySet;
+ CompRect geometry;
+
+ unsigned int state;
+ bool minimized;
+ int workspace;
+} SessionItem;
+
+class SessionScreen :
+ public ScreenInterface,
+ public PluginClassHandler<SessionScreen, CompScreen>,
+ public SessionOptions
+{
+ public:
+ SessionScreen (CompScreen *);
+
+ void handleEvent (XEvent *);
+ void sessionEvent (CompSession::Event, CompOption::Vector &);
+
+ bool readWindow (CompWindow *);
+
+ private:
+ bool getUtf8Property (Window, Atom, CompString&);
+ bool getTextProperty (Window, Atom, CompString&);
+ bool getWindowTitle (Window, CompString&);
+ bool getWindowClass (Window, CompString&, CompString&);
+ bool getIsEmbedded (Window);
+ bool getClientLeaderProperty (CompWindow *, Atom, CompString&);
+
+ int getIntForProp (xmlNodePtr, const char *);
+ CompString getStringForProp (xmlNodePtr, const char *);
+
+ bool isSessionWindow (CompWindow *);
+ void writeWindow (CompWindow *);
+
+ void saveState (const CompString &);
+ void readState (xmlNodePtr);
+ void loadState (const CompString &);
+
+ bool matchWindowClass (CompWindow *, const SessionItem&);
+
+ CompString getFileName (const CompString &);
+ bool createDir (const CompString&);
+
+ Atom visibleNameAtom;
+ Atom clientIdAtom;
+ Atom embedInfoAtom;
+ Atom roleAtom;
+ Atom commandAtom;
+
+ typedef std::list<SessionItem> ItemList;
+
+ ItemList items;
+ std::fstream file;
+};
+
+class SessionWindow :
+ public WindowInterface,
+ public PluginClassHandler<SessionWindow, CompWindow>
+{
+ public:
+ SessionWindow (CompWindow *);
+
+ bool place (CompPoint &);
+
+ CompWindow *window;
+ bool positionSet;
+ CompPoint position;
+};
+
+class SessionPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<SessionScreen, SessionWindow>
+{
+ public:
+ bool init ();
+};