summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt62
-rw-r--r--src/action.cpp644
-rw-r--r--src/actions.cpp289
-rw-r--r--src/atoms.cpp324
-rw-r--r--src/event.cpp1759
-rw-r--r--src/icon.cpp46
-rw-r--r--src/main.cpp242
-rw-r--r--src/match.cpp744
-rw-r--r--src/modifierhandler.cpp204
-rw-r--r--src/option.cpp964
-rw-r--r--src/output.cpp90
-rw-r--r--src/plugin.cpp700
-rw-r--r--src/pluginclasses.cpp74
-rw-r--r--src/point.cpp100
-rw-r--r--src/privateaction.h53
-rw-r--r--src/privatematch.h88
-rw-r--r--src/privateoption.h95
-rw-r--r--src/privateregion.h44
-rw-r--r--src/privatescreen.h427
-rw-r--r--src/privatewindow.h296
-rw-r--r--src/propertywriter.cpp227
-rw-r--r--src/rect.cpp285
-rw-r--r--src/region.cpp449
-rw-r--r--src/screen.cpp4636
-rw-r--r--src/session.cpp427
-rw-r--r--src/size.cpp50
-rw-r--r--src/string.cpp88
-rw-r--r--src/timer.cpp140
-rw-r--r--src/window.cpp5615
-rw-r--r--src/windowgeometry.cpp206
30 files changed, 19368 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..17cad68
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,62 @@
+include (CompizBcop)
+
+compiz_add_bcop_targets (
+ core
+ ${compiz_BINARY_DIR}/generated/core.xml.in
+ _bcop_sources
+)
+
+include_directories (
+ ${compiz_SOURCE_DIR}/include
+ ${compiz_BINARY_DIR}
+ ${compiz_BINARY_DIR}/generated
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${COMPIZ_INCLUDE_DIRS}
+)
+
+add_definitions (
+ -DHAVE_CONFIG_H
+ -DPLUGINDIR=\\\"${compiz_plugindir}\\\"
+ -DIMAGEDIR=\\\"${compiz_imagedir}\\\"
+ -DMETADATADIR=\\\"${compiz_metadatadir}\\\"
+)
+
+link_directories (
+ ${COMPIZ_LINK_DIRS}
+)
+
+add_executable (compiz
+ region.cpp
+ atoms.cpp
+ timer.cpp
+ main.cpp
+ actions.cpp
+ screen.cpp
+ window.cpp
+ action.cpp
+ option.cpp
+ string.cpp
+ match.cpp
+ pluginclasses.cpp
+ event.cpp
+ plugin.cpp
+ session.cpp
+ output.cpp
+ rect.cpp
+ size.cpp
+ point.cpp
+ windowgeometry.cpp
+ icon.cpp
+ modifierhandler.cpp
+ propertywriter.cpp
+ ${_bcop_sources}
+)
+
+target_link_libraries (
+ compiz ${COMPIZ_LIBRARIES} m pthread dl
+)
+
+install (
+ TARGETS compiz
+ DESTINATION ${COMPIZ_DESTDIR}${exec_prefix}
+)
diff --git a/src/action.cpp b/src/action.cpp
new file mode 100644
index 0000000..f487ec9
--- /dev/null
+++ b/src/action.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <compiz.h>
+
+#include <core/option.h>
+#include <core/action.h>
+#include <core/screen.h>
+#include "privateaction.h"
+#include "privatescreen.h"
+
+struct _Modifier {
+ const char *name;
+ int modifier;
+} modifiers[] = {
+ { "<Shift>", ShiftMask },
+ { "<Control>", ControlMask },
+ { "<Mod1>", Mod1Mask },
+ { "<Mod2>", Mod2Mask },
+ { "<Mod3>", Mod3Mask },
+ { "<Mod4>", Mod4Mask },
+ { "<Mod5>", Mod5Mask },
+ { "<Alt>", CompAltMask },
+ { "<Meta>", CompMetaMask },
+ { "<Super>", CompSuperMask },
+ { "<Hyper>", CompHyperMask },
+ { "<ModeSwitch>", CompModeSwitchMask }
+};
+
+#define N_MODIFIERS (sizeof (modifiers) / sizeof (struct _Modifier))
+
+struct _Edge {
+ const char *name;
+ const char *modifierName;
+} edges[] = {
+ { "Left", "<LeftEdge>" },
+ { "Right", "<RightEdge>" },
+ { "Top", "<TopEdge>" },
+ { "Bottom", "<BottomEdge>" },
+ { "TopLeft", "<TopLeftEdge>" },
+ { "TopRight", "<TopRightEdge>" },
+ { "BottomLeft", "<BottomLeftEdge>" },
+ { "BottomRight", "<BottomRightEdge>" }
+};
+
+static CompString
+modifiersToString (unsigned int modMask)
+{
+ CompString binding;
+
+ for (unsigned int i = 0; i < N_MODIFIERS; i++)
+ {
+ if (modMask & modifiers[i].modifier)
+ binding += modifiers[i].name;
+ }
+
+ return binding;
+}
+
+static unsigned int
+stringToModifiers (CompString str)
+{
+ unsigned int mods = 0;
+
+ for (unsigned int i = 0; i < N_MODIFIERS; i++)
+ {
+ if (str.find (modifiers[i].name) != std::string::npos)
+ mods |= modifiers[i].modifier;
+ }
+
+ return mods;
+}
+
+static unsigned int
+bindingStringToEdgeMask (CompString str)
+{
+ unsigned int edgeMask = 0;
+
+ for (int i = 0; i < SCREEN_EDGE_NUM; i++)
+ if (str.find (edges[i].modifierName) != std::string::npos)
+ edgeMask |= 1 << i;
+
+ return edgeMask;
+}
+
+static CompString
+edgeMaskToBindingString (unsigned int edgeMask)
+{
+ CompString binding;
+ int i;
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ if (edgeMask & (1 << i))
+ binding += edges[i].modifierName;
+
+ return binding;
+}
+
+CompAction::KeyBinding::KeyBinding () :
+ mModifiers (0),
+ mKeycode (0)
+{
+}
+
+CompAction::KeyBinding::KeyBinding (const KeyBinding& k) :
+ mModifiers (k.mModifiers),
+ mKeycode (k.mKeycode)
+{
+}
+
+CompAction::KeyBinding::KeyBinding (int keycode, unsigned int modifiers) :
+ mModifiers (modifiers),
+ mKeycode (keycode)
+{
+}
+
+unsigned int
+CompAction::KeyBinding::modifiers () const
+{
+ return mModifiers;
+}
+
+int
+CompAction::KeyBinding::keycode () const
+{
+ return mKeycode;
+}
+
+bool
+CompAction::KeyBinding::fromString (const CompString &str)
+{
+ CompString sStr;
+ unsigned int mods;
+ size_t pos, start = 0;
+ KeySym keysym;
+
+ if (!screen)
+ return false;
+
+ mods = stringToModifiers (str);
+
+ pos = str.rfind ('>');
+ if (pos != std::string::npos)
+ start = pos + 1;
+
+ while (start < str.size () && !isalnum (str[start]))
+ start++;
+
+ if (start == str.size ())
+ {
+ if (mods)
+ {
+ mKeycode = 0;
+ mModifiers = mods;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ sStr = str.substr (start);
+ keysym = XStringToKeysym (sStr.c_str ());
+
+ if (keysym != NoSymbol)
+ {
+ KeyCode keycode;
+
+ keycode = XKeysymToKeycode (screen->dpy (), keysym);
+ if (keycode)
+ {
+ mKeycode = keycode;
+ mModifiers = mods;
+
+ return true;
+ }
+ }
+
+ if (sStr.compare (0, 2, "0x") == 0)
+ {
+ mKeycode = strtol (sStr.c_str (), NULL, 0);
+ mModifiers = mods;
+
+ return true;
+ }
+
+ return false;
+}
+
+CompString
+CompAction::KeyBinding::toString () const
+{
+ CompString binding;
+
+ if (!screen)
+ return "";
+
+ binding = modifiersToString (mModifiers);
+
+ if (mKeycode != 0)
+ {
+ KeySym keysym;
+ char *keyname;
+
+ keysym = XKeycodeToKeysym (screen->dpy (), mKeycode, 0);
+ keyname = XKeysymToString (keysym);
+
+ if (keyname)
+ binding += keyname;
+ else
+ binding += compPrintf ("0x%x", mKeycode);
+ }
+
+ return binding;
+}
+
+CompAction::ButtonBinding::ButtonBinding () :
+ mModifiers (0),
+ mButton (0)
+{
+}
+
+CompAction::ButtonBinding::ButtonBinding (const ButtonBinding& b) :
+ mModifiers (b.mModifiers),
+ mButton (b.mButton)
+{
+}
+
+CompAction::ButtonBinding::ButtonBinding (int button, unsigned int modifiers) :
+ mModifiers (modifiers),
+ mButton (button)
+{
+}
+
+unsigned int
+CompAction::ButtonBinding::modifiers () const
+{
+ return mModifiers;
+}
+
+int
+CompAction::ButtonBinding::button () const
+{
+ return mButton;
+}
+
+bool
+CompAction::ButtonBinding::fromString (const CompString &str)
+{
+ unsigned int mods;
+ size_t pos, start = 0;
+
+ mods = stringToModifiers (str);
+
+ pos = str.rfind ('>');
+ if (pos != std::string::npos)
+ start = pos + 1;
+
+ while (start < str.size () && !isalnum (str[start]))
+ start++;
+
+ if (start != str.size () && str.compare (start, 6, "Button") == 0)
+ {
+ int buttonNum;
+
+ if (sscanf (str.substr (start + 6).c_str (), "%d", &buttonNum) == 1)
+ {
+ mButton = buttonNum;
+ mModifiers = mods;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+CompString
+CompAction::ButtonBinding::toString () const
+{
+ CompString binding;
+
+ if (!mModifiers && !mButton)
+ return "";
+
+ binding = modifiersToString (mModifiers);
+ binding += compPrintf ("Button%d", mButton);
+
+ return binding;
+}
+
+CompAction::CompAction () :
+ priv (new PrivateAction ())
+{
+}
+
+CompAction::CompAction (const CompAction & a) :
+ priv (new PrivateAction (*a.priv))
+{
+}
+
+CompAction::~CompAction ()
+{
+ delete priv;
+}
+
+CompAction::CallBack
+CompAction::initiate ()
+{
+ return priv->initiate;
+}
+
+CompAction::CallBack
+CompAction::terminate ()
+{
+ return priv->terminate;
+}
+
+void
+CompAction::setInitiate (const CompAction::CallBack &initiate)
+{
+ priv->initiate = initiate;
+}
+
+void
+CompAction::setTerminate (const CompAction::CallBack &terminate)
+{
+ priv->terminate = terminate;
+}
+
+CompAction::State
+CompAction::state ()
+{
+ return priv->state;
+}
+
+CompAction::BindingType
+CompAction::type ()
+{
+ return priv->type;
+}
+
+CompAction::KeyBinding &
+CompAction::key ()
+{
+ return priv->key;
+}
+
+void
+CompAction::setKey (const CompAction::KeyBinding &key)
+{
+ priv->key = key;
+
+ if (key.modifiers () || key.keycode ())
+ priv->type = CompAction::BindingTypeKey;
+ else
+ priv->type = CompAction::BindingTypeNone;
+}
+
+CompAction::ButtonBinding &
+CompAction::button ()
+{
+ return priv->button;
+}
+
+void
+CompAction::setButton (const CompAction::ButtonBinding &button)
+{
+ priv->button = button;
+
+ if (button.modifiers () || button.button ())
+ {
+ if (priv->edgeMask)
+ priv->type = CompAction::BindingTypeEdgeButton;
+ else
+ priv->type = CompAction::BindingTypeButton;
+ }
+ else
+ {
+ priv->type = CompAction::BindingTypeNone;
+ }
+}
+
+unsigned int
+CompAction::edgeMask ()
+{
+ return priv->edgeMask;
+}
+
+void
+CompAction::setEdgeMask (unsigned int edge)
+{
+ priv->edgeMask = edge;
+
+ if (priv->type == CompAction::BindingTypeEdgeButton ||
+ priv->type == CompAction::BindingTypeButton)
+ {
+ if (priv->edgeMask)
+ priv->type = CompAction::BindingTypeEdgeButton;
+ else
+ priv->type = CompAction::BindingTypeButton;
+ }
+}
+
+bool
+CompAction::bell ()
+{
+ return priv->bell;
+}
+
+void
+CompAction::setBell (bool bell)
+{
+ priv->bell = bell;
+}
+
+void
+CompAction::setState (CompAction::State state)
+{
+ priv->state = state;
+}
+
+void
+CompAction::copyState (const CompAction &action)
+{
+ priv->initiate = action.priv->initiate;
+ priv->terminate = action.priv->terminate;
+ priv->state = action.priv->state;
+
+ memcpy (&priv->priv, &action.priv->priv, sizeof (CompPrivate));
+}
+
+bool
+CompAction::operator== (const CompAction& val)
+{
+ if (priv->state != val.priv->state)
+ return false;
+ if (priv->type != val.priv->type)
+ return false;
+ if (priv->key.modifiers () != val.priv->key.modifiers ())
+ return false;
+ if (priv->key.keycode () != val.priv->key.keycode ())
+ return false;
+ if (priv->button.modifiers () != val.priv->button.modifiers ())
+ return false;
+ if (priv->button.button () != val.priv->button.button ())
+ return false;
+ if (priv->bell != val.priv->bell)
+ return false;
+ if (priv->edgeMask != val.priv->edgeMask)
+ return false;
+ if (memcmp (&priv->priv, &val.priv->priv, sizeof (CompPrivate)) != 0)
+ return false;
+
+ return true;
+}
+
+CompAction &
+CompAction::operator= (const CompAction &action)
+{
+ delete priv;
+ priv = new PrivateAction (*action.priv);
+
+ return *this;
+}
+
+bool
+CompAction::keyFromString (const CompString &str)
+{
+ bool retval = priv->key.fromString (str);
+
+ if (retval)
+ {
+ priv->type = CompAction::BindingTypeKey;
+ }
+ else
+ {
+ priv->type = CompAction::BindingTypeNone;
+ if (str == "Disabled")
+ retval = true;
+ }
+
+ return retval;
+}
+
+bool
+CompAction::buttonFromString (const CompString &str)
+{
+ bool retval = priv->button.fromString (str);
+
+ if (retval)
+ {
+ priv->edgeMask = bindingStringToEdgeMask (str);
+ if (priv->edgeMask)
+ priv->type = CompAction::BindingTypeEdgeButton;
+ else
+ priv->type = CompAction::BindingTypeButton;
+ }
+ else
+ {
+ priv->type = CompAction::BindingTypeNone;
+ if (str == "Disabled")
+ retval = true;
+ }
+
+ return retval;
+}
+
+bool
+CompAction::edgeMaskFromString (const CompString &str)
+{
+ unsigned int edgeMask = 0;
+ size_t pos;
+
+ for (int i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ pos = 0;
+ while ((pos = str.find (edgeToString (i), pos)) != std::string::npos)
+ {
+ if (pos > 0 && isalnum (str[pos - 1]))
+ {
+ pos++;
+ continue;
+ }
+
+ pos += edgeToString (i).size ();
+
+ if (pos < str.size () && isalnum (str[pos]))
+ continue;
+
+ edgeMask |= 1 << i;
+ }
+ }
+
+ priv->edgeMask = edgeMask;
+
+ return (edgeMask != 0 || str.empty ());
+}
+
+CompString
+CompAction::keyToString ()
+{
+ CompString binding;
+
+ binding = priv->key.toString ();
+ if (!binding.size ())
+ return "Disabled";
+
+ return binding;
+}
+
+CompString
+CompAction::buttonToString ()
+{
+ CompString binding, edge;
+
+ binding = modifiersToString (priv->button.modifiers ());
+ binding += edgeMaskToBindingString (priv->edgeMask);
+
+ binding += compPrintf ("Button%d", priv->button.button ());
+
+ if (!priv->button.button ())
+ return "Disabled";
+
+ return binding;
+}
+
+CompString
+CompAction::edgeMaskToString ()
+{
+ CompString edge;
+
+ for (int i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (priv->edgeMask & (1 << i))
+ {
+ if (!edge.empty ())
+ edge += " | ";
+
+ edge += edgeToString (i);
+ }
+ }
+
+ return edge;
+}
+
+
+CompString
+CompAction::edgeToString (unsigned int edge)
+{
+ return edges[edge].name;
+}
+
+PrivateAction::PrivateAction () :
+ initiate (),
+ terminate (),
+ state (0),
+ type (0),
+ key (),
+ button (),
+ bell (false),
+ edgeMask (0)
+{
+ memset (&priv, 0, sizeof (CompPrivate));
+}
+
+PrivateAction::PrivateAction (const PrivateAction& a) :
+ initiate (a.initiate),
+ terminate (a.terminate),
+ state (a.state),
+ type (a.type),
+ key (a.key),
+ button (a.button),
+ bell (a.bell),
+ edgeMask (a.edgeMask)
+{
+ memcpy (&priv, &a.priv, sizeof (CompPrivate));
+}
diff --git a/src/actions.cpp b/src/actions.cpp
new file mode 100644
index 0000000..8ede0cf
--- /dev/null
+++ b/src/actions.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/screen.h>
+#include <core/window.h>
+#include <core/atoms.h>
+#include "privatescreen.h"
+#include "privatewindow.h"
+
+bool
+CompScreen::closeWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+ unsigned int time;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+ time = CompOption::getIntOptionNamed (options, "time", CurrentTime);
+
+ w = screen->findTopLevelWindow (xid);
+ if (w && (w->priv->actions & CompWindowActionCloseMask))
+ w->close (time);
+
+ return true;
+}
+
+bool
+CompScreen::unmaximizeWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (0);
+
+ return true;
+}
+
+bool
+CompScreen::minimizeWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w && (w->actions () & CompWindowActionMinimizeMask))
+ w->minimize ();
+
+ return true;
+}
+
+bool
+CompScreen::maximizeWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (MAXIMIZE_STATE);
+
+ return true;
+}
+
+bool
+CompScreen::maximizeWinHorizontally (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (w->state () | CompWindowStateMaximizedHorzMask);
+
+ return true;
+}
+
+bool
+CompScreen::maximizeWinVertically (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (w->state () | CompWindowStateMaximizedVertMask);
+
+ return true;
+}
+
+bool
+CompScreen::showDesktop (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ if (screen->priv->showingDesktopMask == 0)
+ screen->enterShowDesktopMode ();
+ else
+ screen->leaveShowDesktopMode (NULL);
+
+ return true;
+}
+
+bool
+CompScreen::raiseWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->raise ();
+
+ return true;
+}
+
+bool
+CompScreen::lowerWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->lower ();
+
+ return true;
+}
+
+bool
+CompScreen::windowMenu (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w && screen->priv->grabs.empty ())
+ {
+ int x, y, button;
+ Time time;
+
+ time = CompOption::getIntOptionNamed (options, "time", CurrentTime);
+ button = CompOption::getIntOptionNamed (options, "button", 0);
+ x = CompOption::getIntOptionNamed (options, "x",
+ w->geometry ().x ());
+ y = CompOption::getIntOptionNamed (options, "y",
+ w->geometry ().y ());
+
+ screen->toolkitAction (Atoms::toolkitActionWindowMenu,
+ time, w->id (), button, x, y);
+ }
+
+ return true;
+}
+
+bool
+CompScreen::toggleWinMaximized (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ {
+ if ((w->priv->state & MAXIMIZE_STATE) == MAXIMIZE_STATE)
+ w->maximize (0);
+ else
+ w->maximize (MAXIMIZE_STATE);
+ }
+
+ return true;
+}
+
+bool
+CompScreen::toggleWinMaximizedHorizontally (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (w->priv->state ^ CompWindowStateMaximizedHorzMask);
+
+ return true;
+}
+
+bool
+CompScreen::toggleWinMaximizedVertically (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w)
+ w->maximize (w->priv->state ^ CompWindowStateMaximizedVertMask);
+
+ return true;
+}
+
+bool
+CompScreen::shadeWin (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window");
+
+ w = screen->findTopLevelWindow (xid);
+ if (w && (w->priv->actions & CompWindowActionShadeMask))
+ {
+ w->priv->state ^= CompWindowStateShadedMask;
+ w->updateAttributes (CompStackingUpdateModeNone);
+ }
+
+ return true;
+}
diff --git a/src/atoms.cpp b/src/atoms.cpp
new file mode 100644
index 0000000..6c7310e
--- /dev/null
+++ b/src/atoms.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/atoms.h>
+
+namespace Atoms {
+ Atom supported;
+ Atom supportingWmCheck;
+
+ Atom utf8String;
+
+ Atom wmName;
+
+ Atom winType;
+ Atom winTypeDesktop;
+ Atom winTypeDock;
+ Atom winTypeToolbar;
+ Atom winTypeMenu;
+ Atom winTypeUtil;
+ Atom winTypeSplash;
+ Atom winTypeDialog;
+ Atom winTypeNormal;
+ Atom winTypeDropdownMenu;
+ Atom winTypePopupMenu;
+ Atom winTypeTooltip;
+ Atom winTypeNotification;
+ Atom winTypeCombo;
+ Atom winTypeDnd;
+
+ Atom winOpacity;
+ Atom winBrightness;
+ Atom winSaturation;
+ Atom winActive;
+ Atom winDesktop;
+
+ Atom workarea;
+
+ Atom desktopViewport;
+ Atom desktopGeometry;
+ Atom currentDesktop;
+ Atom numberOfDesktops;
+
+ Atom winState;
+ Atom winStateModal;
+ Atom winStateSticky;
+ Atom winStateMaximizedVert;
+ Atom winStateMaximizedHorz;
+ Atom winStateShaded;
+ Atom winStateSkipTaskbar;
+ Atom winStateSkipPager;
+ Atom winStateHidden;
+ Atom winStateFullscreen;
+ Atom winStateAbove;
+ Atom winStateBelow;
+ Atom winStateDemandsAttention;
+ Atom winStateDisplayModal;
+
+ Atom winActionMove;
+ Atom winActionResize;
+ Atom winActionStick;
+ Atom winActionMinimize;
+ Atom winActionMaximizeHorz;
+ Atom winActionMaximizeVert;
+ Atom winActionFullscreen;
+ Atom winActionClose;
+ Atom winActionShade;
+ Atom winActionChangeDesktop;
+ Atom winActionAbove;
+ Atom winActionBelow;
+
+ Atom wmAllowedActions;
+
+ Atom wmStrut;
+ Atom wmStrutPartial;
+
+ Atom wmUserTime;
+
+ Atom wmIcon;
+ Atom wmIconGeometry;
+
+ Atom clientList;
+ Atom clientListStacking;
+
+ Atom frameExtents;
+ Atom frameWindow;
+
+ Atom wmState;
+ Atom wmChangeState;
+ Atom wmProtocols;
+ Atom wmClientLeader;
+
+ Atom wmDeleteWindow;
+ Atom wmTakeFocus;
+ Atom wmPing;
+ Atom wmSyncRequest;
+
+ Atom wmSyncRequestCounter;
+
+ Atom wmFullscreenMonitors;
+
+ Atom closeWindow;
+ Atom wmMoveResize;
+ Atom moveResizeWindow;
+ Atom restackWindow;
+
+ Atom showingDesktop;
+
+ Atom xBackground[2];
+
+ Atom toolkitAction;
+ Atom toolkitActionWindowMenu;
+ Atom toolkitActionForceQuitDialog;
+
+ Atom mwmHints;
+
+ Atom xdndAware;
+ Atom xdndEnter;
+ Atom xdndLeave;
+ Atom xdndPosition;
+ Atom xdndStatus;
+ Atom xdndDrop;
+
+ Atom manager;
+ Atom targets;
+ Atom multiple;
+ Atom timestamp;
+ Atom version;
+ Atom atomPair;
+
+ Atom startupId;
+
+ void init (Display *dpy)
+ {
+ supported = XInternAtom (dpy, "_NET_SUPPORTED", 0);
+ supportingWmCheck = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0);
+
+ utf8String = XInternAtom (dpy, "UTF8_STRING", 0);
+
+ wmName = XInternAtom (dpy, "_NET_WM_NAME", 0);
+
+ winType = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
+ winTypeDesktop = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP",
+ 0);
+ winTypeDock = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
+ winTypeToolbar = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ 0);
+ winTypeMenu = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
+ winTypeUtil = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY",
+ 0);
+ winTypeSplash = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
+ winTypeDialog = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
+ winTypeNormal = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
+
+ winTypeDropdownMenu =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", 0);
+ winTypePopupMenu =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", 0);
+ winTypeTooltip =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", 0);
+ winTypeNotification =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", 0);
+ winTypeCombo =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_COMBO", 0);
+ winTypeDnd =
+ XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DND", 0);
+
+ winOpacity = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
+ winBrightness = XInternAtom (dpy, "_NET_WM_WINDOW_BRIGHTNESS", 0);
+ winSaturation = XInternAtom (dpy, "_NET_WM_WINDOW_SATURATION", 0);
+
+ winActive = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
+ winDesktop = XInternAtom (dpy, "_NET_WM_DESKTOP", 0);
+ workarea = XInternAtom (dpy, "_NET_WORKAREA", 0);
+
+ desktopViewport = XInternAtom (dpy, "_NET_DESKTOP_VIEWPORT", 0);
+ desktopGeometry = XInternAtom (dpy, "_NET_DESKTOP_GEOMETRY", 0);
+ currentDesktop = XInternAtom (dpy, "_NET_CURRENT_DESKTOP", 0);
+ numberOfDesktops = XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", 0);
+
+ winState = XInternAtom (dpy, "_NET_WM_STATE", 0);
+ winStateModal =
+ XInternAtom (dpy, "_NET_WM_STATE_MODAL", 0);
+ winStateSticky =
+ XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0);
+ winStateMaximizedVert =
+ XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
+ winStateMaximizedHorz =
+ XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
+ winStateShaded =
+ XInternAtom (dpy, "_NET_WM_STATE_SHADED", 0);
+ winStateSkipTaskbar =
+ XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0);
+ winStateSkipPager =
+ XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0);
+ winStateHidden =
+ XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", 0);
+ winStateFullscreen =
+ XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0);
+ winStateAbove =
+ XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0);
+ winStateBelow =
+ XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0);
+ winStateDemandsAttention =
+ XInternAtom (dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
+ winStateDisplayModal =
+ XInternAtom (dpy, "_NET_WM_STATE_DISPLAY_MODAL", 0);
+
+ winActionMove = XInternAtom (dpy, "_NET_WM_ACTION_MOVE", 0);
+ winActionResize =
+ XInternAtom (dpy, "_NET_WM_ACTION_RESIZE", 0);
+ winActionStick =
+ XInternAtom (dpy, "_NET_WM_ACTION_STICK", 0);
+ winActionMinimize =
+ XInternAtom (dpy, "_NET_WM_ACTION_MINIMIZE", 0);
+ winActionMaximizeHorz =
+ XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_HORZ", 0);
+ winActionMaximizeVert =
+ XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_VERT", 0);
+ winActionFullscreen =
+ XInternAtom (dpy, "_NET_WM_ACTION_FULLSCREEN", 0);
+ winActionClose =
+ XInternAtom (dpy, "_NET_WM_ACTION_CLOSE", 0);
+ winActionShade =
+ XInternAtom (dpy, "_NET_WM_ACTION_SHADE", 0);
+ winActionChangeDesktop =
+ XInternAtom (dpy, "_NET_WM_ACTION_CHANGE_DESKTOP", 0);
+ winActionAbove =
+ XInternAtom (dpy, "_NET_WM_ACTION_ABOVE", 0);
+ winActionBelow =
+ XInternAtom (dpy, "_NET_WM_ACTION_BELOW", 0);
+
+ wmAllowedActions = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0);
+
+ wmStrut = XInternAtom (dpy, "_NET_WM_STRUT", 0);
+ wmStrutPartial = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0);
+
+ wmUserTime = XInternAtom (dpy, "_NET_WM_USER_TIME", 0);
+
+ wmIcon = XInternAtom (dpy,"_NET_WM_ICON", 0);
+ wmIconGeometry = XInternAtom (dpy, "_NET_WM_ICON_GEOMETRY", 0);
+
+ clientList = XInternAtom (dpy, "_NET_CLIENT_LIST", 0);
+ clientListStacking =
+ XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0);
+
+ frameExtents = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0);
+ frameWindow = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0);
+
+ wmState = XInternAtom (dpy, "WM_STATE", 0);
+ wmChangeState = XInternAtom (dpy, "WM_CHANGE_STATE", 0);
+ wmProtocols = XInternAtom (dpy, "WM_PROTOCOLS", 0);
+ wmClientLeader = XInternAtom (dpy, "WM_CLIENT_LEADER", 0);
+
+ wmDeleteWindow = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
+ wmTakeFocus = XInternAtom (dpy, "WM_TAKE_FOCUS", 0);
+ wmPing = XInternAtom (dpy, "_NET_WM_PING", 0);
+ wmSyncRequest = XInternAtom (dpy, "_NET_WM_SYNC_REQUEST", 0);
+
+ wmSyncRequestCounter =
+ XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0);
+
+ wmFullscreenMonitors =
+ XInternAtom (dpy, "_NET_WM_FULLSCREEN_MONITORS", 0);
+
+ closeWindow = XInternAtom (dpy, "_NET_CLOSE_WINDOW", 0);
+ wmMoveResize = XInternAtom (dpy, "_NET_WM_MOVERESIZE", 0);
+ moveResizeWindow = XInternAtom (dpy, "_NET_MOVERESIZE_WINDOW", 0);
+ restackWindow = XInternAtom (dpy, "_NET_RESTACK_WINDOW", 0);
+
+ showingDesktop = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0);
+
+ xBackground[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
+ xBackground[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
+
+ toolkitAction =
+ XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION", 0);
+ toolkitActionWindowMenu =
+ XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_WINDOW_MENU", 0);
+ toolkitActionForceQuitDialog =
+ XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_FORCE_QUIT_DIALOG", 0);
+
+ mwmHints = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0);
+
+ xdndAware = XInternAtom (dpy, "XdndAware", 0);
+ xdndEnter = XInternAtom (dpy, "XdndEnter", 0);
+ xdndLeave = XInternAtom (dpy, "XdndLeave", 0);
+ xdndPosition = XInternAtom (dpy, "XdndPosition", 0);
+ xdndStatus = XInternAtom (dpy, "XdndStatus", 0);
+ xdndDrop = XInternAtom (dpy, "XdndDrop", 0);
+
+ manager = XInternAtom (dpy, "MANAGER", 0);
+ targets = XInternAtom (dpy, "TARGETS", 0);
+ multiple = XInternAtom (dpy, "MULTIPLE", 0);
+ timestamp = XInternAtom (dpy, "TIMESTAMP", 0);
+ version = XInternAtom (dpy, "VERSION", 0);
+ atomPair = XInternAtom (dpy, "ATOM_PAIR", 0);
+
+ startupId = XInternAtom (dpy, "_NET_STARTUP_ID", 0);
+ }
+};
diff --git a/src/event.cpp b/src/event.cpp
new file mode 100644
index 0000000..f764a13
--- /dev/null
+++ b/src/event.cpp
@@ -0,0 +1,1759 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xfixes.h>
+
+#include <core/core.h>
+#include <core/atoms.h>
+#include "privatescreen.h"
+#include "privatewindow.h"
+
+static Window xdndWindow = None;
+static Window edgeWindow = None;
+
+
+
+bool
+PrivateWindow::handleSyncAlarm ()
+{
+ if (priv->syncWait)
+ {
+ priv->syncWait = false;
+
+ if (window->resize (priv->syncGeometry))
+ {
+ window->windowNotify (CompWindowNotifySyncAlarm);
+ }
+ else
+ {
+ /* resizeWindow failing means that there is another pending
+ resize and we must send a new sync request to the client */
+ window->sendSyncRequest ();
+ }
+ }
+
+ return false;
+}
+
+
+static bool
+autoRaiseTimeout (CompScreen *screen)
+{
+ CompWindow *w = screen->findWindow (screen->activeWindow ());
+
+ if (screen->autoRaiseWindow () == screen->activeWindow () ||
+ (w && (screen->autoRaiseWindow () == w->transientFor ())))
+ {
+ w = screen->findWindow (screen->autoRaiseWindow ());
+ if (w)
+ w->updateAttributes (CompStackingUpdateModeNormal);
+ }
+
+ return false;
+}
+
+#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
+ Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
+
+static bool
+isCallBackBinding (CompOption &option,
+ CompAction::BindingType type,
+ CompAction::State state)
+{
+ if (!option.isAction ())
+ return false;
+
+ if (!(option.value ().action ().type () & type))
+ return false;
+
+ if (!(option.value ().action ().state () & state))
+ return false;
+
+ return true;
+}
+
+static bool
+isInitiateBinding (CompOption &option,
+ CompAction::BindingType type,
+ CompAction::State state,
+ CompAction **action)
+{
+ if (!isCallBackBinding (option, type, state))
+ return false;
+
+ if (option.value ().action ().initiate ().empty ())
+ return false;
+
+ *action = &option.value ().action ();
+
+ return true;
+}
+
+static bool
+isTerminateBinding (CompOption &option,
+ CompAction::BindingType type,
+ CompAction::State state,
+ CompAction **action)
+{
+ if (!isCallBackBinding (option, type, state))
+ return false;
+
+ if (option.value ().action ().terminate ().empty ())
+ return false;
+
+ *action = &option.value ().action ();
+
+ return true;
+}
+
+bool
+PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options,
+ XButtonEvent *event,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state = CompAction::StateInitButton;
+ CompAction *action;
+ unsigned int ignored = modHandler->ignoredModMask ();
+ unsigned int modMask = REAL_MOD_MASK & ~ignored;
+ unsigned int bindMods;
+ unsigned int edge = 0;
+
+ if (edgeWindow)
+ {
+ unsigned int i;
+
+ if (event->root != root)
+ return false;
+
+ if (event->window != edgeWindow)
+ {
+ if (grabs.empty () || event->window != root)
+ return false;
+ }
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (edgeWindow == screenEdge[i].id)
+ {
+ edge = 1 << i;
+ arguments[1].value ().set ((int) activeWindow);
+ break;
+ }
+ }
+ }
+
+ foreach (CompOption &option, options)
+ {
+ if (isInitiateBinding (option, CompAction::BindingTypeButton, state,
+ &action))
+ {
+ if (action->button ().button () == (int) event->button)
+ {
+ bindMods = modHandler->virtualToRealModMask (
+ action->button ().modifiers ());
+
+ if ((bindMods & modMask) == (event->state & modMask))
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ }
+
+ if (edge)
+ {
+ if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton,
+ state | CompAction::StateInitEdge, &action))
+ {
+ if ((action->button ().button () == (int) event->button) &&
+ (action->edgeMask () & edge))
+ {
+ bindMods = modHandler->virtualToRealModMask (
+ action->button ().modifiers ());
+
+ if ((bindMods & modMask) == (event->state & modMask))
+ if (action->initiate () (action, state |
+ CompAction::StateInitEdge,
+ arguments))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options,
+ XButtonEvent *event,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state = CompAction::StateTermButton;
+ CompAction::BindingType type = CompAction::BindingTypeButton |
+ CompAction::BindingTypeEdgeButton;
+ CompAction *action;
+
+ foreach (CompOption &option, options)
+ {
+ if (isTerminateBinding (option, type, state, &action))
+ {
+ if (action->button ().button () == (int) event->button)
+ {
+ if (action->terminate () (action, state, arguments))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options,
+ XKeyEvent *event,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state = 0;
+ CompAction *action;
+ unsigned int modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask ();
+ unsigned int bindMods;
+
+ if (event->keycode == escapeKeyCode)
+ state = CompAction::StateCancel;
+ else if (event->keycode == returnKeyCode)
+ state = CompAction::StateCommit;
+
+ if (state)
+ {
+ foreach (CompOption &o, options)
+ {
+ if (o.isAction ())
+ {
+ if (!o.value ().action ().terminate ().empty ())
+ o.value ().action ().terminate () (&o.value ().action (),
+ state, noOptions);
+ }
+ }
+
+ if (state == CompAction::StateCancel)
+ return false;
+ }
+
+ state = CompAction::StateInitKey;
+ foreach (CompOption &option, options)
+ {
+ if (isInitiateBinding (option, CompAction::BindingTypeKey,
+ state, &action))
+ {
+ bindMods = modHandler->virtualToRealModMask (
+ action->key ().modifiers ());
+
+ if (action->key ().keycode () == (int) event->keycode)
+ {
+ if ((bindMods & modMask) == (event->state & modMask))
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ else if (!xkbEvent && action->key ().keycode () == 0)
+ {
+ if (bindMods == (event->state & modMask))
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options,
+ XKeyEvent *event,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state = CompAction::StateTermKey;
+ CompAction *action;
+ unsigned int ignored = modHandler->ignoredModMask ();
+ unsigned int modMask = REAL_MOD_MASK & ~ignored;
+ unsigned int bindMods;
+ unsigned int mods;
+
+ mods = modHandler->keycodeToModifiers (event->keycode);
+ if (!xkbEvent && !mods)
+ return false;
+
+ foreach (CompOption &option, options)
+ {
+ if (isTerminateBinding (option, CompAction::BindingTypeKey,
+ state, &action))
+ {
+ bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
+
+ if ((bindMods & modMask) == 0)
+ {
+ if ((unsigned int) action->key ().keycode () ==
+ (unsigned int) event->keycode)
+ {
+ if (action->terminate () (action, state, arguments))
+ return true;
+ }
+ }
+ else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods))
+ {
+ if (action->terminate () (action, state, arguments))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+PrivateScreen::triggerStateNotifyBindings (CompOption::Vector &options,
+ XkbStateNotifyEvent *event,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state;
+ CompAction *action;
+ unsigned int ignored = modHandler->ignoredModMask ();
+ unsigned int modMask = REAL_MOD_MASK & ~ignored;
+ unsigned int bindMods;
+
+ if (event->event_type == KeyPress)
+ {
+ state = CompAction::StateInitKey;
+
+ foreach (CompOption &option, options)
+ {
+ if (isInitiateBinding (option, CompAction::BindingTypeKey,
+ state, &action))
+ {
+ if (action->key ().keycode () == 0)
+ {
+ bindMods =
+ modHandler->virtualToRealModMask (action->key ().modifiers ());
+
+ if ((event->mods & modMask & bindMods) == bindMods)
+ {
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ state = CompAction::StateTermKey;
+
+ foreach (CompOption &option, options)
+ {
+ if (isTerminateBinding (option, CompAction::BindingTypeKey,
+ state, &action))
+ {
+ bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
+
+ if ((event->mods & modMask & bindMods) != bindMods)
+ {
+ if (action->terminate () (action, state, arguments))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool
+isBellAction (CompOption &option,
+ CompAction::State state,
+ CompAction **action)
+{
+ if (option.type () != CompOption::TypeAction &&
+ option.type () != CompOption::TypeBell)
+ return false;
+
+ if (!option.value ().action ().bell ())
+ return false;
+
+ if (!(option.value ().action ().state () & state))
+ return false;
+
+ if (option.value ().action ().initiate ().empty ())
+ return false;
+
+ *action = &option.value ().action ();
+
+ return true;
+}
+
+static bool
+triggerBellNotifyBindings (CompOption::Vector &options,
+ CompOption::Vector &arguments)
+{
+ CompAction::State state = CompAction::StateInitBell;
+ CompAction *action;
+
+ foreach (CompOption &option, options)
+ {
+ if (isBellAction (option, state, &action))
+ {
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+isEdgeAction (CompOption &option,
+ CompAction::State state,
+ unsigned int edge)
+{
+ if (option.type () != CompOption::TypeAction &&
+ option.type () != CompOption::TypeButton &&
+ option.type () != CompOption::TypeEdge)
+ return false;
+
+ if (!(option.value ().action ().edgeMask () & edge))
+ return false;
+
+ if (!(option.value ().action ().state () & state))
+ return false;
+
+ return true;
+}
+
+static bool
+isEdgeEnterAction (CompOption &option,
+ CompAction::State state,
+ CompAction::State delayState,
+ unsigned int edge,
+ CompAction **action)
+{
+ if (!isEdgeAction (option, state, edge))
+ return false;
+
+ if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton)
+ return false;
+
+ if (option.value ().action ().initiate ().empty ())
+ return false;
+
+ if (delayState)
+ {
+ if ((option.value ().action ().state () &
+ CompAction::StateNoEdgeDelay) !=
+ (delayState & CompAction::StateNoEdgeDelay))
+ {
+ /* ignore edge actions which shouldn't be delayed when invoking
+ undelayed edges (or vice versa) */
+ return false;
+ }
+ }
+
+
+ *action = &option.value ().action ();
+
+ return true;
+}
+
+static bool
+isEdgeLeaveAction (CompOption &option,
+ CompAction::State state,
+ unsigned int edge,
+ CompAction **action)
+{
+ if (!isEdgeAction (option, state, edge))
+ return false;
+
+ if (option.value ().action ().terminate ().empty ())
+ return false;
+
+ *action = &option.value ().action ();
+
+ return true;
+}
+
+static bool
+triggerEdgeEnterBindings (CompOption::Vector &options,
+ CompAction::State state,
+ CompAction::State delayState,
+ unsigned int edge,
+ CompOption::Vector &arguments)
+{
+ CompAction *action;
+
+ foreach (CompOption &option, options)
+ {
+ if (isEdgeEnterAction (option, state, delayState, edge, &action))
+ {
+ if (action->initiate () (action, state, arguments))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+triggerEdgeLeaveBindings (CompOption::Vector &options,
+ CompAction::State state,
+ unsigned int edge,
+ CompOption::Vector &arguments)
+{
+ CompAction *action;
+
+ foreach (CompOption &option, options)
+ {
+ if (isEdgeLeaveAction (option, state, edge, &action))
+ {
+ if (action->terminate () (action, state, arguments))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+triggerAllEdgeEnterBindings (CompAction::State state,
+ CompAction::State delayState,
+ unsigned int edge,
+ CompOption::Vector &arguments)
+{
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerEdgeEnterBindings (options, state, delayState, edge,
+ arguments))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+delayedEdgeTimeout (CompDelayedEdgeSettings *settings)
+{
+ triggerAllEdgeEnterBindings (settings->state,
+ ~CompAction::StateNoEdgeDelay,
+ settings->edge,
+ settings->options);
+
+ return false;
+}
+
+bool
+PrivateScreen::triggerEdgeEnter (unsigned int edge,
+ CompAction::State state,
+ CompOption::Vector &arguments)
+{
+ int delay;
+
+ delay = optionGetEdgeDelay ();
+
+ if (delay > 0)
+ {
+ CompAction::State delayState;
+ edgeDelaySettings.edge = edge;
+ edgeDelaySettings.state = state;
+ edgeDelaySettings.options = arguments;
+
+ edgeDelayTimer.start (
+ boost::bind (delayedEdgeTimeout, &edgeDelaySettings),
+ delay, (unsigned int) ((float) delay * 1.2));
+
+ delayState = CompAction::StateNoEdgeDelay;
+ if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments))
+ return true;
+ }
+ else
+ {
+ if (triggerAllEdgeEnterBindings (state, 0, edge, arguments))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+PrivateScreen::handleActionEvent (XEvent *event)
+{
+ static CompOption::Vector o (8);
+ Window xid;
+ o.resize (8);
+
+ o[0].setName ("event_window", CompOption::TypeInt);
+ o[1].setName ("window", CompOption::TypeInt);
+ o[2].setName ("modifiers", CompOption::TypeInt);
+ o[3].setName ("x", CompOption::TypeInt);
+ o[4].setName ("y", CompOption::TypeInt);
+ o[5].setName ("root", CompOption::TypeInt);
+
+ switch (event->type) {
+ case ButtonPress:
+ /* We need to determine if we clicked on a parent frame
+ * window, if so, pass the appropriate child window as
+ * "window" and the frame as "event_window"
+ */
+
+ xid = event->xbutton.window;
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (w->frame () == xid)
+ xid = w->id ();
+ }
+
+ o[0].value ().set ((int) event->xbutton.window);
+ o[1].value ().set ((int) xid);
+ o[2].value ().set ((int) event->xbutton.state);
+ o[3].value ().set ((int) event->xbutton.x_root);
+ o[4].value ().set ((int) event->xbutton.y_root);
+ o[5].value ().set ((int) event->xbutton.root);
+
+ o[6].setName ("button", CompOption::TypeInt);
+ o[7].setName ("time", CompOption::TypeInt);
+
+ o[6].value ().set ((int) event->xbutton.button);
+ o[7].value ().set ((int) event->xbutton.time);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerButtonPressBindings (options, &event->xbutton, o))
+ return true;
+ }
+ break;
+ case ButtonRelease:
+ o[0].value ().set ((int) event->xbutton.window);
+ o[1].value ().set ((int) event->xbutton.window);
+ o[2].value ().set ((int) event->xbutton.state);
+ o[3].value ().set ((int) event->xbutton.x_root);
+ o[4].value ().set ((int) event->xbutton.y_root);
+ o[5].value ().set ((int) event->xbutton.root);
+
+ o[6].setName ("button", CompOption::TypeInt);
+ o[7].setName ("time", CompOption::TypeInt);
+
+ o[6].value ().set ((int) event->xbutton.button);
+ o[7].value ().set ((int) event->xbutton.time);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerButtonReleaseBindings (options, &event->xbutton, o))
+ return true;
+ }
+ break;
+ case KeyPress:
+ o[0].value ().set ((int) event->xkey.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) event->xkey.state);
+ o[3].value ().set ((int) event->xkey.x_root);
+ o[4].value ().set ((int) event->xkey.y_root);
+ o[5].value ().set ((int) event->xkey.root);
+
+ o[6].setName ("keycode", CompOption::TypeInt);
+ o[7].setName ("time", CompOption::TypeInt);
+
+ o[6].value ().set ((int) event->xkey.keycode);
+ o[7].value ().set ((int) event->xkey.time);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerKeyPressBindings (options, &event->xkey, o))
+ return true;
+ }
+ break;
+ case KeyRelease:
+ o[0].value ().set ((int) event->xkey.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) event->xkey.state);
+ o[3].value ().set ((int) event->xkey.x_root);
+ o[4].value ().set ((int) event->xkey.y_root);
+ o[5].value ().set ((int) event->xkey.root);
+
+ o[6].setName ("keycode", CompOption::TypeInt);
+ o[7].setName ("time", CompOption::TypeInt);
+
+ o[6].value ().set ((int) event->xkey.keycode);
+ o[7].value ().set ((int) event->xkey.time);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerKeyReleaseBindings (options, &event->xkey, o))
+ return true;
+ }
+ break;
+ case EnterNotify:
+ if (event->xcrossing.mode != NotifyGrab &&
+ event->xcrossing.mode != NotifyUngrab &&
+ event->xcrossing.detail != NotifyInferior)
+ {
+ unsigned int edge, i;
+ CompAction::State state;
+
+ if (event->xcrossing.root != root)
+ return false;
+
+ if (edgeDelayTimer.active ())
+ edgeDelayTimer.stop ();
+
+ if (edgeWindow && edgeWindow != event->xcrossing.window)
+ {
+ state = CompAction::StateTermEdge;
+ edge = 0;
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (edgeWindow == screenEdge[i].id)
+ {
+ edge = 1 << i;
+ break;
+ }
+ }
+
+ edgeWindow = None;
+
+ o[0].value ().set ((int) event->xcrossing.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) event->xcrossing.state);
+ o[3].value ().set ((int) event->xcrossing.x_root);
+ o[4].value ().set ((int) event->xcrossing.y_root);
+ o[5].value ().set ((int) event->xcrossing.root);
+
+ o[6].setName ("time", CompOption::TypeInt);
+ o[6].value ().set ((int) event->xcrossing.time);
+
+ o.resize (7);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerEdgeLeaveBindings (options, state, edge, o))
+ return true;
+ }
+ }
+
+ edge = 0;
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (event->xcrossing.window == screenEdge[i].id)
+ {
+ edge = 1 << i;
+ break;
+ }
+ }
+
+ if (edge)
+ {
+ state = CompAction::StateInitEdge;
+
+ edgeWindow = event->xcrossing.window;
+
+ o[0].value ().set ((int) event->xcrossing.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) event->xcrossing.state);
+ o[3].value ().set ((int) event->xcrossing.x_root);
+ o[4].value ().set ((int) event->xcrossing.y_root);
+ o[5].value ().set ((int) event->xcrossing.root);
+
+ o[6].setName ("time", CompOption::TypeInt);
+ o[6].value ().set ((int) event->xcrossing.time);
+
+ o.resize (7);
+
+ if (triggerEdgeEnter (edge, state, o))
+ return true;
+ }
+ }
+ break;
+ case ClientMessage:
+ if (event->xclient.message_type == Atoms::xdndEnter)
+ {
+ xdndWindow = event->xclient.window;
+ }
+ else if (event->xclient.message_type == Atoms::xdndLeave)
+ {
+ unsigned int edge = 0;
+ CompAction::State state;
+
+ if (!xdndWindow)
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned int i;
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (event->xclient.window == screenEdge[i].id)
+ {
+ edge = 1 << i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (edge)
+ {
+ state = CompAction::StateTermEdgeDnd;
+
+ o[0].value ().set ((int) event->xclient.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) 0); /* fixme */
+ o[3].value ().set ((int) 0); /* fixme */
+ o[4].value ().set ((int) 0); /* fixme */
+ o[5].value ().set ((int) root);
+
+ o.resize (6);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerEdgeLeaveBindings (options, state, edge, o))
+ return true;
+ }
+ }
+ }
+ else if (event->xclient.message_type == Atoms::xdndPosition)
+ {
+ unsigned int edge = 0;
+ CompAction::State state;
+
+ if (xdndWindow == event->xclient.window)
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned int i;
+
+ for (i = 0; i < SCREEN_EDGE_NUM; i++)
+ {
+ if (xdndWindow == screenEdge[i].id)
+ {
+ edge = 1 << i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (edge)
+ {
+ state = CompAction::StateInitEdgeDnd;
+
+ o[0].value ().set ((int) event->xclient.window);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) 0); /* fixme */
+ o[3].value ().set ((int) event->xclient.data.l[2] >> 16);
+ o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff);
+ o[5].value ().set ((int) root);
+
+ o.resize (6);
+
+ if (triggerEdgeEnter (edge, state, o))
+ return true;
+ }
+
+ xdndWindow = None;
+ }
+ break;
+ default:
+ if (event->type == xkbEvent)
+ {
+ XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
+
+ if (xkbEvent->xkb_type == XkbStateNotify)
+ {
+ XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
+
+ o[0].value ().set ((int) activeWindow);
+ o[1].value ().set ((int) activeWindow);
+ o[2].value ().set ((int) stateEvent->mods);
+
+ o[3] = CompOption ("time", CompOption::TypeInt);
+ o[3].value ().set ((int) xkbEvent->time);
+
+ o.resize (4);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerStateNotifyBindings (options, stateEvent, o))
+ return true;
+ }
+ }
+ else if (xkbEvent->xkb_type == XkbBellNotify)
+ {
+ o[0].value ().set ((int) activeWindow);
+ o[1].value ().set ((int) activeWindow);
+
+ o[2] = CompOption ("time", CompOption::TypeInt);
+ o[2].value ().set ((int) xkbEvent->time);
+
+ o.resize (3);
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ if (triggerBellNotifyBindings (options, o))
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ return false;
+}
+
+void
+CompScreen::handleCompizEvent (const char *plugin,
+ const char *event,
+ CompOption::Vector &options)
+ WRAPABLE_HND_FUNC (7, handleCompizEvent, plugin, event, options)
+
+void
+CompScreen::handleEvent (XEvent *event)
+{
+ WRAPABLE_HND_FUNC (6, handleEvent, event)
+
+ CompWindow *w;
+
+ switch (event->type) {
+ case ButtonPress:
+ if (event->xbutton.root == priv->root)
+ priv->setCurrentOutput (
+ outputDeviceForPoint (event->xbutton.x_root,
+ event->xbutton.y_root));
+ break;
+ case MotionNotify:
+ if (event->xmotion.root == priv->root)
+ priv->setCurrentOutput (
+ outputDeviceForPoint (event->xmotion.x_root,
+ event->xmotion.y_root));
+ break;
+ case KeyPress:
+ w = findWindow (priv->activeWindow);
+ if (w)
+ priv->setCurrentOutput (w->outputDevice ());
+ default:
+ break;
+ }
+
+ if (priv->handleActionEvent (event))
+ {
+ if (priv->grabs.empty ())
+ XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time);
+
+ return;
+ }
+
+ switch (event->type) {
+ case SelectionRequest:
+ priv->handleSelectionRequest (event);
+ break;
+ case SelectionClear:
+ priv->handleSelectionClear (event);
+ break;
+ case ConfigureNotify:
+ w = findWindow (event->xconfigure.window);
+ if (w && !w->frame ())
+ {
+ w->priv->configure (&event->xconfigure);
+ }
+ else
+ {
+ w = findTopLevelWindow (event->xconfigure.window);
+
+ if (w && w->frame () == event->xconfigure.window)
+ {
+ w->priv->configureFrame (&event->xconfigure);
+ }
+ else
+ {
+ if (event->xconfigure.window == priv->root)
+ priv->configure (&event->xconfigure);
+ }
+ }
+ break;
+ case CreateNotify:
+ w = findTopLevelWindow (event->xcreatewindow.window, true);
+
+ if (event->xcreatewindow.parent == priv->root &&
+ (!w || w->frame () != event->xcreatewindow.window))
+ {
+ new CompWindow (event->xcreatewindow.window, priv->getTopWindow ());
+ }
+ break;
+ case DestroyNotify:
+ w = findWindow (event->xdestroywindow.window);
+ if (w)
+ {
+ w->moveInputFocusToOtherWindow ();
+ w->destroy ();
+ }
+ break;
+ case MapNotify:
+ w = findWindow (event->xmap.window);
+ if (w)
+ {
+ if (w->priv->pendingMaps || zcomp)
+ {
+ if (!w->priv->frame)
+ w->priv->reparent ();
+ w->priv->managed = true;
+ }
+
+ /* been shaded */
+ if (w->priv->height == 0)
+ {
+ if (w->id () == priv->activeWindow)
+ w->moveInputFocusTo ();
+ }
+
+ w->map ();
+ }
+ break;
+ case UnmapNotify:
+ w = findWindow (event->xunmap.window);
+ if (w)
+ {
+ /* Normal -> Iconic */
+ if (w->pendingUnmaps ())
+ {
+ priv->setWmState (IconicState, w->id ());
+ w->priv->pendingUnmaps--;
+ }
+ else /* X -> Withdrawn */
+ {
+ /* Iconic -> Withdrawn */
+ if (w->state () & CompWindowStateHiddenMask)
+ {
+ w->priv->minimized = false;
+
+ w->changeState (w->state () & ~CompWindowStateHiddenMask);
+
+ priv->updateClientList ();
+ }
+ else /* Closing */
+ w->windowNotify (CompWindowNotifyClose);
+
+ if (!w->overrideRedirect ())
+ priv->setWmState (WithdrawnState, w->id ());
+
+ w->priv->placed = false;
+ w->priv->managed = false;
+ if (w->priv->frame)
+ {
+ w->priv->unreparent ();
+ }
+ }
+
+ w->unmap ();
+
+ if (!w->shaded () && !w->priv->pendingMaps)
+ w->moveInputFocusToOtherWindow ();
+ }
+ break;
+ case ReparentNotify:
+ w = findWindow (event->xreparent.window);
+ if (!w && event->xreparent.parent == priv->root)
+ {
+ new CompWindow (event->xreparent.window, priv->getTopWindow ());
+ }
+ else if (w && !(event->xreparent.parent == w->priv->wrapper ||
+ event->xreparent.parent == priv->root))
+ {
+ /* This is the only case where a window is removed but not
+ destroyed. We must remove our event mask and all passive
+ grabs. */
+ XSelectInput (priv->dpy, w->id (), NoEventMask);
+ XShapeSelectInput (priv->dpy, w->id (), NoEventMask);
+ XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ());
+
+ w->moveInputFocusToOtherWindow ();
+
+ w->destroy ();
+ }
+ break;
+ case CirculateNotify:
+ w = findWindow (event->xcirculate.window);
+ if (w)
+ w->priv->circulate (&event->xcirculate);
+ break;
+ case ButtonPress:
+ if (event->xbutton.root == priv->root)
+ {
+ if (event->xbutton.button == Button1 ||
+ event->xbutton.button == Button2 ||
+ event->xbutton.button == Button3)
+ {
+ w = findTopLevelWindow (event->xbutton.window);
+ if (w)
+ {
+ if (priv->optionGetRaiseOnClick ())
+ w->updateAttributes (
+ CompStackingUpdateModeAboveFullscreen);
+
+ if (w->id () != priv->activeWindow)
+ if (!(w->type () & CompWindowTypeDockMask))
+ w->moveInputFocusTo ();
+ }
+ }
+
+ if (priv->grabs.empty ())
+ XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time);
+ }
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == Atoms::winType)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ {
+ unsigned int type;
+
+ type = priv->getWindowType (w->id ());
+
+ if (type != w->wmType ())
+ {
+ if (w->isViewable ())
+ {
+ if (w->type () == CompWindowTypeDesktopMask)
+ priv->desktopWindowCount--;
+ else if (type == CompWindowTypeDesktopMask)
+ priv->desktopWindowCount++;
+ }
+
+ w->wmType () = type;
+
+ w->recalcType ();
+ w->recalcActions ();
+
+ if (type & (CompWindowTypeDockMask |
+ CompWindowTypeDesktopMask))
+ w->setDesktop (0xffffffff);
+
+ priv->updateClientList ();
+
+ matchPropertyChanged (w);
+ }
+ }
+ }
+ else if (event->xproperty.atom == Atoms::winState)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w && !w->managed ())
+ {
+ unsigned int state;
+
+ state = priv->getWindowState (w->id ());
+ state = CompWindow::constrainWindowState (state, w->actions ());
+
+ /* EWMH suggests that we ignore changes
+ to _NET_WM_STATE_HIDDEN */
+ if (w->state () & CompWindowStateHiddenMask)
+ state |= CompWindowStateHiddenMask;
+ else
+ state &= ~CompWindowStateHiddenMask;
+
+ w->changeState (state);
+ }
+ }
+ else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ {
+ w->priv->updateNormalHints ();
+ w->recalcActions ();
+ }
+ }
+ else if (event->xproperty.atom == XA_WM_HINTS)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->updateWmHints ();
+ }
+ else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ {
+ w->priv->updateTransientHint ();
+ w->recalcActions ();
+ }
+ }
+ else if (event->xproperty.atom == Atoms::wmClientLeader)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->clientLeader = w->priv->getClientLeader ();
+ }
+ else if (event->xproperty.atom == Atoms::wmIconGeometry)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->updateIconGeometry ();
+ }
+ else if (event->xproperty.atom == Atoms::wmStrut ||
+ event->xproperty.atom == Atoms::wmStrutPartial)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ {
+ if (w->updateStruts ())
+ updateWorkarea ();
+ }
+ }
+ else if (event->xproperty.atom == Atoms::mwmHints)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->updateMwmHints ();
+ }
+ else if (event->xproperty.atom == Atoms::wmProtocols)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->protocols = priv->getProtocols (w->id ());
+ }
+ else if (event->xproperty.atom == Atoms::wmIcon)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->freeIcons ();
+ }
+ else if (event->xproperty.atom == Atoms::startupId)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->updateStartupId ();
+ }
+ else if (event->xproperty.atom == XA_WM_CLASS)
+ {
+ w = findWindow (event->xproperty.window);
+ if (w)
+ w->priv->updateClassHints ();
+ }
+ break;
+ case MotionNotify:
+ break;
+ case ClientMessage:
+ if (event->xclient.message_type == Atoms::winActive)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ /* use focus stealing prevention if request came
+ from an application */
+ if (event->xclient.data.l[0] != ClientTypeApplication ||
+ w->priv->allowWindowFocus (0, event->xclient.data.l[1]))
+ {
+ w->activate ();
+ }
+ }
+ }
+ else if (event->xclient.message_type == Atoms::winState)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned long wState, state;
+ int i;
+
+ wState = w->state ();
+
+ for (i = 1; i < 3; i++)
+ {
+ state = priv->windowStateMask (event->xclient.data.l[i]);
+ if (state & ~CompWindowStateHiddenMask)
+ {
+
+#define _NET_WM_STATE_REMOVE 0
+#define _NET_WM_STATE_ADD 1
+#define _NET_WM_STATE_TOGGLE 2
+
+ switch (event->xclient.data.l[0]) {
+ case _NET_WM_STATE_REMOVE:
+ wState &= ~state;
+ break;
+ case _NET_WM_STATE_ADD:
+ wState |= state;
+ break;
+ case _NET_WM_STATE_TOGGLE:
+ wState ^= state;
+ break;
+ }
+ }
+ }
+
+ wState = CompWindow::constrainWindowState (wState,
+ w->actions ());
+ if (w->id () == priv->activeWindow)
+ wState &= ~CompWindowStateDemandsAttentionMask;
+
+ if (wState != w->state ())
+ {
+ CompStackingUpdateMode stackingUpdateMode;
+ unsigned long dState = wState ^ w->state ();
+
+ stackingUpdateMode = CompStackingUpdateModeNone;
+
+ /* raise the window whenever its fullscreen state,
+ above/below state or maximization state changed */
+ if (dState & (CompWindowStateFullscreenMask |
+ CompWindowStateAboveMask |
+ CompWindowStateBelowMask |
+ CompWindowStateMaximizedHorzMask |
+ CompWindowStateMaximizedVertMask))
+ stackingUpdateMode = CompStackingUpdateModeNormal;
+
+ w->changeState (wState);
+
+ w->updateAttributes (stackingUpdateMode);
+ }
+ }
+ }
+ else if (event->xclient.message_type == Atoms::wmProtocols)
+ {
+ if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing)
+ {
+ w = findWindow (event->xclient.data.l[2]);
+ if (w)
+ w->priv->handlePing (priv->lastPing);
+ }
+ }
+ else if (event->xclient.message_type == Atoms::closeWindow)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ w->close (event->xclient.data.l[0]);
+ }
+ else if (event->xclient.message_type == Atoms::desktopGeometry)
+ {
+ if (event->xclient.window == priv->root)
+ {
+ CompOption::Value value;
+
+ value.set ((int) (event->xclient.data.l[0] /
+ width ()));
+
+ setOptionForPlugin ("core", "hsize", value);
+
+ value.set ((int) (event->xclient.data.l[1] /
+ height ()));
+
+ setOptionForPlugin ("core", "vsize", value);
+ }
+ }
+ else if (event->xclient.message_type == Atoms::moveResizeWindow)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned int xwcm = 0;
+ XWindowChanges xwc;
+ int gravity;
+ unsigned int source;
+
+ memset (&xwc, 0, sizeof (xwc));
+
+ if (event->xclient.data.l[0] & (1 << 8))
+ {
+ xwcm |= CWX;
+ xwc.x = event->xclient.data.l[1];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 9))
+ {
+ xwcm |= CWY;
+ xwc.y = event->xclient.data.l[2];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 10))
+ {
+ xwcm |= CWWidth;
+ xwc.width = event->xclient.data.l[3];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 11))
+ {
+ xwcm |= CWHeight;
+ xwc.height = event->xclient.data.l[4];
+ }
+
+ gravity = event->xclient.data.l[0] & 0xFF;
+ source = (event->xclient.data.l[0] >> 12) & 0xF;
+
+ w->moveResize (&xwc, xwcm, gravity, source);
+ }
+ }
+ else if (event->xclient.message_type == Atoms::restackWindow)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ /* TODO: other stack modes than Above and Below */
+ if (event->xclient.data.l[1])
+ {
+ CompWindow *sibling;
+
+ sibling = findWindow (event->xclient.data.l[1]);
+ if (sibling)
+ {
+ if (event->xclient.data.l[2] == Above)
+ w->restackAbove (sibling);
+ else if (event->xclient.data.l[2] == Below)
+ w->restackBelow (sibling);
+ }
+ }
+ else
+ {
+ if (event->xclient.data.l[2] == Above)
+ w->raise ();
+ else if (event->xclient.data.l[2] == Below)
+ w->lower ();
+ }
+ }
+ }
+ else if (event->xclient.message_type == Atoms::wmChangeState)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ if (event->xclient.data.l[0] == IconicState)
+ {
+ if (w->actions () & CompWindowActionMinimizeMask)
+ w->minimize ();
+ }
+ else if (event->xclient.data.l[0] == NormalState)
+ w->unminimize ();
+ }
+ }
+ else if (event->xclient.message_type == Atoms::showingDesktop)
+ {
+ if (event->xclient.window == priv->root ||
+ event->xclient.window == None)
+ {
+ if (event->xclient.data.l[0])
+ enterShowDesktopMode ();
+ else
+ leaveShowDesktopMode (NULL);
+ }
+ }
+ else if (event->xclient.message_type == Atoms::numberOfDesktops)
+ {
+ if (event->xclient.window == priv->root)
+ {
+ CompOption::Value value;
+
+ value.set ((int) event->xclient.data.l[0]);
+
+ setOptionForPlugin ("core", "number_of_desktops", value);
+ }
+ }
+ else if (event->xclient.message_type == Atoms::currentDesktop)
+ {
+ if (event->xclient.window == priv->root)
+ priv->setCurrentDesktop (event->xclient.data.l[0]);
+ }
+ else if (event->xclient.message_type == Atoms::winDesktop)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ w->setDesktop (event->xclient.data.l[0]);
+ }
+ else if (event->xclient.message_type == Atoms::wmFullscreenMonitors)
+ {
+ w = findWindow (event->xclient.window);
+ if (w)
+ {
+ CompFullscreenMonitorSet monitors;
+
+ monitors.top = event->xclient.data.l[0];
+ monitors.bottom = event->xclient.data.l[1];
+ monitors.left = event->xclient.data.l[2];
+ monitors.right = event->xclient.data.l[3];
+
+ w->priv->setFullscreenMonitors (&monitors);
+ }
+ }
+ break;
+ case MappingNotify:
+ modHandler->updateModifierMappings ();
+ break;
+ case MapRequest:
+ w = findWindow (event->xmaprequest.window);
+ if (w)
+ {
+ XWindowAttributes attr;
+ bool doMapProcessing = true;
+
+ /* We should check the override_redirect flag here, because the
+ client might have changed it while being unmapped. */
+ if (XGetWindowAttributes (priv->dpy, w->id (), &attr))
+ w->priv->setOverrideRedirect (attr.override_redirect != 0);
+
+ if (w->state () & CompWindowStateHiddenMask)
+ if (!w->minimized () && !w->inShowDesktopMode ())
+ doMapProcessing = false;
+
+ if (doMapProcessing)
+ w->priv->processMap ();
+
+ w->priv->managed = true;
+
+ setWindowProp (w->id (), Atoms::winDesktop, w->desktop ());
+ }
+ else
+ {
+ XMapWindow (priv->dpy, event->xmaprequest.window);
+ }
+ break;
+ case ConfigureRequest:
+ w = findWindow (event->xconfigurerequest.window);
+ if (w && w->managed ())
+ {
+ XWindowChanges xwc;
+
+ memset (&xwc, 0, sizeof (xwc));
+
+ xwc.x = event->xconfigurerequest.x;
+ xwc.y = event->xconfigurerequest.y;
+ xwc.width = event->xconfigurerequest.width;
+ xwc.height = event->xconfigurerequest.height;
+ xwc.border_width = event->xconfigurerequest.border_width;
+
+ w->moveResize (&xwc, event->xconfigurerequest.value_mask,
+ 0, ClientTypeUnknown);
+
+ if (event->xconfigurerequest.value_mask & CWStackMode)
+ {
+ Window above = None;
+ CompWindow *sibling = NULL;
+
+ if (event->xconfigurerequest.value_mask & CWSibling)
+ {
+ above = event->xconfigurerequest.above;
+ sibling = findTopLevelWindow (above);
+ }
+
+ switch (event->xconfigurerequest.detail) {
+ case Above:
+ if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0))
+ {
+ if (above)
+ {
+ if (sibling)
+ w->restackAbove (sibling);
+ }
+ else
+ w->raise ();
+ }
+ break;
+ case Below:
+ if (above)
+ {
+ if (sibling)
+ w->restackBelow (sibling);
+ }
+ else
+ w->lower ();
+ break;
+ default:
+ /* no handling of the TopIf, BottomIf, Opposite cases -
+ there will hardly be any client using that */
+ break;
+ }
+ }
+ }
+ else
+ {
+ XWindowChanges xwc;
+ unsigned int xwcm;
+
+ xwcm = event->xconfigurerequest.value_mask &
+ (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
+
+ xwc.x = event->xconfigurerequest.x;
+ xwc.y = event->xconfigurerequest.y;
+ xwc.width = event->xconfigurerequest.width;
+ xwc.height = event->xconfigurerequest.height;
+ xwc.border_width = event->xconfigurerequest.border_width;
+
+ if (w)
+ w->configureXWindow (xwcm, &xwc);
+ else
+ XConfigureWindow (priv->dpy, event->xconfigurerequest.window,
+ xwcm, &xwc);
+ }
+ break;
+ case CirculateRequest:
+ break;
+ case FocusIn:
+ if (event->xfocus.mode != NotifyGrab)
+ {
+ w = findTopLevelWindow (event->xfocus.window);
+ if (w && w->managed ())
+ {
+ unsigned int state = w->state ();
+
+ if (w->id () != priv->activeWindow)
+ {
+ w->windowNotify (CompWindowNotifyFocusChange);
+
+ priv->activeWindow = w->id ();
+ w->priv->activeNum = priv->activeNum++;
+
+ priv->addToCurrentActiveWindowHistory (w->id ());
+
+ XChangeProperty (priv->dpy , priv->root,
+ Atoms::winActive,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &priv->activeWindow, 1);
+ }
+
+ state &= ~CompWindowStateDemandsAttentionMask;
+ w->changeState (state);
+ }
+ }
+ break;
+ case EnterNotify:
+ if (event->xcrossing.root == priv->root)
+ w = findTopLevelWindow (event->xcrossing.window);
+ else
+ w = NULL;
+
+ if (w && w->id () != priv->below)
+ {
+ priv->below = w->id ();
+
+ if (!priv->optionGetClickToFocus () &&
+ priv->grabs.empty () &&
+ event->xcrossing.mode != NotifyGrab &&
+ event->xcrossing.detail != NotifyInferior)
+ {
+ bool raise;
+ int delay;
+
+ raise = priv->optionGetAutoraise ();
+ delay = priv->optionGetAutoraiseDelay ();
+
+ if (priv->autoRaiseTimer.active () &&
+ priv->autoRaiseWindow != w->id ())
+ {
+ priv->autoRaiseTimer.stop ();
+ }
+
+ if (w->type () & ~(CompWindowTypeDockMask |
+ CompWindowTypeDesktopMask))
+ {
+ w->moveInputFocusTo ();
+
+ if (raise)
+ {
+ if (delay > 0)
+ {
+ priv->autoRaiseWindow = w->id ();
+ priv->autoRaiseTimer.start (
+ boost::bind (autoRaiseTimeout, this),
+ delay, (unsigned int) ((float) delay * 1.2));
+ }
+ else
+ {
+ CompStackingUpdateMode mode =
+ CompStackingUpdateModeNormal;
+
+ w->updateAttributes (mode);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case LeaveNotify:
+ if (event->xcrossing.detail != NotifyInferior)
+ {
+ if (event->xcrossing.window == priv->below)
+ priv->below = None;
+ }
+ break;
+ default:
+ if (priv->shapeExtension &&
+ event->type == priv->shapeEvent + ShapeNotify)
+ {
+ w = findWindow (((XShapeEvent *) event)->window);
+ if (w)
+ {
+ if (w->mapNum ())
+ w->priv->updateRegion ();
+ }
+ }
+ else if (event->type == priv->syncEvent + XSyncAlarmNotify)
+ {
+ XSyncAlarmNotifyEvent *sa;
+
+ sa = (XSyncAlarmNotifyEvent *) event;
+
+
+ foreach (w, priv->windows)
+ {
+ if (w->priv->syncAlarm == sa->alarm)
+ {
+ w->priv->handleSyncAlarm ();
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
diff --git a/src/icon.cpp b/src/icon.cpp
new file mode 100644
index 0000000..3118db0
--- /dev/null
+++ b/src/icon.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/icon.h>
+
+CompIcon::CompIcon (CompScreen *screen, unsigned int width,
+ unsigned int height) :
+ CompSize (width, height),
+ mData (new unsigned char[width * height * 4])
+{
+}
+
+CompIcon::~CompIcon ()
+{
+ delete [] mData;
+}
+
+unsigned char*
+CompIcon::data ()
+{
+ return mData;
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..bfbfc81
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <compiz.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <core/core.h>
+#include "privatescreen.h"
+
+char *programName;
+char **programArgv;
+int programArgc;
+
+char *backgroundImage = NULL;
+
+bool shutDown = false;
+bool restartSignal = false;
+
+CompWindow *lastFoundWindow = 0;
+
+bool replaceCurrentWm = false;
+bool indirectRendering = false;
+bool noDetection = false;
+bool useDesktopHints = false;
+bool debugOutput = false;
+bool useCow = true;
+bool zcomp = false;
+
+unsigned int pluginClassHandlerIndex = 0;
+
+static void
+usage (void)
+{
+ printf ("Usage: %s "
+ "[--replace] "
+ "[--display DISPLAY]\n "
+ "[--indirect-rendering] "
+ "[--sm-disable] "
+ "[--sm-client-id ID]\n "
+ "[--bg-image PNG] "
+ "[--no-detection] "
+ "[--keep-desktop-hints]\n "
+ "[--use-root-window] "
+ "[--debug] "
+ "[--zcomp] "
+ "[--version] "
+ "[--help] "
+ "[PLUGIN]...\n",
+ programName);
+}
+
+static void
+signalHandler (int sig)
+{
+ int status;
+
+ switch (sig) {
+ case SIGCHLD:
+ waitpid (-1, &status, WNOHANG | WUNTRACED);
+ break;
+ case SIGHUP:
+ restartSignal = true;
+ break;
+ case SIGINT:
+ case SIGTERM:
+ shutDown = true;
+ default:
+ break;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ char *displayName = 0;
+ std::vector<CompString> plugins;
+ int i;
+ bool disableSm = false;
+ char *clientId = NULL;
+
+ programName = argv[0];
+ programArgc = argc;
+ programArgv = argv;
+
+ signal (SIGHUP, signalHandler);
+ signal (SIGCHLD, signalHandler);
+ signal (SIGINT, signalHandler);
+ signal (SIGTERM, signalHandler);
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "--help"))
+ {
+ usage ();
+ return 0;
+ }
+ else if (!strcmp (argv[i], "--version"))
+ {
+ printf (PACKAGE_STRING "\n");
+ return 0;
+ }
+ else if (!strcmp (argv[i], "--debug"))
+ {
+ debugOutput = true;
+ }
+ else if (!strcmp (argv[i], "--display"))
+ {
+ if (i + 1 < argc)
+ displayName = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--indirect-rendering"))
+ {
+ indirectRendering = true;
+ }
+ else if (!strcmp (argv[i], "--keep-desktop-hints"))
+ {
+ useDesktopHints = true;
+ }
+ else if (!strcmp (argv[i], "--use-root-window"))
+ {
+ useCow = false;
+ }
+ else if (!strcmp (argv[i], "--replace"))
+ {
+ replaceCurrentWm = true;
+ }
+ else if (!strcmp (argv[i], "--sm-disable"))
+ {
+ disableSm = true;
+ }
+ else if (!strcmp (argv[i], "--sm-client-id"))
+ {
+ if (i + 1 < argc)
+ clientId = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--no-detection"))
+ {
+ noDetection = true;
+ }
+ else if (!strcmp (argv[i], "--bg-image"))
+ {
+ if (i + 1 < argc)
+ backgroundImage = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--zcomp"))
+ {
+ zcomp = true;
+ }
+ else if (*argv[i] == '-')
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Unknown option '%s'\n", argv[i]);
+ }
+ else
+ {
+ plugins.push_back (argv[i]);
+ }
+ }
+
+ screen = new CompScreen ();
+ if (!screen)
+ return 1;
+
+ modHandler = new ModifierHandler ();
+
+ if (!modHandler)
+ return 1;
+
+ if (!plugins.empty ())
+ {
+ CompOption::Value::Vector list;
+ CompOption::Value value;
+ CompOption *o = screen->getOption ("active_plugins");
+
+ foreach (CompString &str, plugins)
+ {
+ value.set (str);
+ list.push_back (value);
+ }
+
+ value.set (CompOption::TypeString, list);
+
+ if (o)
+ o->set (value);
+ }
+
+ if (!screen->init (displayName))
+ return 1;
+
+ modHandler->updateModifierMappings ();
+
+ if (!disableSm)
+ CompSession::init (clientId);
+
+ screen->eventLoop ();
+
+ if (!disableSm)
+ CompSession::close ();
+
+ delete screen;
+ delete modHandler;
+
+ if (restartSignal)
+ {
+ execvp (programName, programArgv);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/match.cpp b/src/match.cpp
new file mode 100644
index 0000000..ff46aae
--- /dev/null
+++ b/src/match.cpp
@@ -0,0 +1,744 @@
+/*
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <core/core.h>
+
+#include <core/screen.h>
+#include <core/match.h>
+#include <core/window.h>
+#include <core/plugin.h>
+#include "privatematch.h"
+#include "privatescreen.h"
+#include "privatewindow.h"
+
+const CompMatch CompMatch::emptyMatch;
+
+class CoreExp : public CompMatch::Expression {
+ public:
+ virtual ~CoreExp () {};
+
+ typedef enum {
+ TypeXid,
+ TypeState,
+ TypeOverride,
+ TypeRGBA,
+ TypeType
+ } Type;
+
+ CoreExp (const CompString& str)
+ {
+ if (str.compare (0, 4, "xid=") == 0)
+ {
+ mType = TypeXid;
+ priv.val = strtol (str.substr (4).c_str (), NULL, 0);
+ }
+ else if (str.compare (0, 6, "state=") == 0)
+ {
+ mType = TypeState;
+ priv.uval = PrivateScreen::windowStateFromString
+ (str.substr (6).c_str ());
+ }
+ else if (str.compare (0, 18, "override_redirect=") == 0)
+ {
+ mType = TypeOverride;
+ priv.val = strtol (str.substr (18).c_str (), NULL, 0);
+ }
+ else if (str.compare (0, 5, "rgba=") == 0)
+ {
+ mType = TypeRGBA;
+ priv.val = strtol (str.substr (5).c_str (), NULL, 0);
+ }
+ else
+ {
+ size_t offset = (str.compare (0, 5, "type=") == 0) ? 5 : 0;
+
+ mType = TypeType;
+ priv.uval = PrivateWindow::windowTypeFromString (
+ str.substr (offset).c_str ());
+ }
+ }
+
+ bool evaluate (CompWindow *w)
+ {
+ switch (mType)
+ {
+ case TypeXid:
+ return ((unsigned int) priv.val == w->id ());
+ case TypeState:
+ return (priv.uval & w->state ());
+ case TypeOverride:
+ {
+ bool overrideRedirect = w->overrideRedirect ();
+ return ((priv.val == 1 && overrideRedirect) ||
+ (priv.val == 0 && !overrideRedirect));
+ }
+ case TypeRGBA:
+ return ((priv.val && w->alpha ()) ||
+ (!priv.val && !w->alpha ()));
+ case TypeType:
+ return (priv.uval & w->wmType ());
+ }
+ return true;
+ }
+
+ Type mType;
+ CompPrivate priv;
+};
+
+CompMatch::Expression *
+CompScreen::matchInitExp (const CompString& str)
+{
+ WRAPABLE_HND_FUNC_RETURN (10, CompMatch::Expression *, matchInitExp, str)
+
+ return new CoreExp (str);
+}
+
+static void
+matchUpdateMatchOptions (CompOption::Vector& options)
+{
+ foreach (CompOption &option, options)
+ {
+ switch (option.type ()) {
+ case CompOption::TypeMatch:
+ option.value ().match ().update ();
+ break;
+ case CompOption::TypeList:
+ if (option.value ().listType () == CompOption::TypeMatch)
+ {
+ foreach (CompOption::Value &value, option.value ().list ())
+ value.match ().update ();
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void
+CompScreen::matchExpHandlerChanged ()
+{
+ WRAPABLE_HND_FUNC (11, matchExpHandlerChanged)
+
+ foreach (CompPlugin *p, CompPlugin::getPlugins ())
+ {
+ CompOption::Vector &options = p->vTable->getOptions ();
+ matchUpdateMatchOptions (options);
+ }
+}
+
+void
+CompScreen::matchPropertyChanged (CompWindow *w)
+{
+ WRAPABLE_HND_FUNC (12, matchPropertyChanged, w)
+}
+
+static void
+matchResetOps (MatchOp::List &list)
+{
+ MatchExpOp *exp;
+ foreach (MatchOp *op, list)
+ {
+ switch (op->type ()) {
+ case MatchOp::TypeGroup:
+ matchResetOps (dynamic_cast <MatchGroupOp *> (op)->op);
+ break;
+ case MatchOp::TypeExp:
+ exp = dynamic_cast <MatchExpOp *> (op);
+ if (exp && exp->e)
+ exp->e.reset ();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static bool
+matchOpsEqual (MatchOp::List &list1,
+ MatchOp::List &list2)
+{
+ MatchGroupOp *g1, *g2;
+ MatchExpOp *e1, *e2;
+ MatchOp::List::iterator it1 = list1.begin (), it2 = list2.begin ();
+
+ if (list1.size () != list2.size ())
+ return false;
+
+ while (it1 != list1.end ())
+ {
+ if ((*it1)->type () != (*it2)->type ())
+ return false;
+
+ if ((*it1)->flags != (*it2)->flags)
+ return false;
+
+ switch ((*it1)->type ()) {
+ case MatchOp::TypeGroup:
+ g1 = dynamic_cast<MatchGroupOp *> (*it1);
+ g2 = dynamic_cast<MatchGroupOp *> (*it2);
+
+ if (!matchOpsEqual (g1->op, g2->op))
+ return false;
+
+ break;
+ case MatchOp::TypeExp:
+ e1 = dynamic_cast<MatchExpOp *> (*it1);
+ e2 = dynamic_cast<MatchExpOp *> (*it2);
+
+ if (e1->value != e2->value)
+ return false;
+
+ break;
+ default:
+ break;
+ }
+
+ it1++;
+ it2++;
+ }
+
+ return true;
+}
+
+static unsigned int
+nextIndex (CompString &str,
+ unsigned int i)
+{
+ while (str[i] == '\\')
+ if (str[++i] != '\0')
+ i++;
+
+ return i;
+}
+
+static CompString
+strndupValue (CompString str)
+{
+ CompString value;
+
+ unsigned int i, j, n = str.length ();
+
+ /* count trialing white spaces */
+ i = j = 0;
+ while (i < n)
+ {
+ if (str[i] != ' ')
+ {
+ j = 0;
+ if (str[i] == '\\')
+ i++;
+ }
+ else
+ {
+ j++;
+ }
+
+ i++;
+ }
+
+ /* remove trialing white spaces */
+ n -= j;
+
+ i = j = 0;
+ for (;;)
+ {
+ if (str[i] == '\\')
+ i++;
+
+ value += str[i++];
+
+ if (i >= n)
+ {
+ return value;
+ }
+ }
+}
+
+/*
+ Add match expressions from string. Special characters are
+ '(', ')', '!', '&', '|'. Escape character is '\'.
+
+ Example:
+
+ "type=desktop | !type=dock"
+ "!type=dock & (state=fullscreen | state=shaded)"
+*/
+
+static void
+matchAddFromString (MatchOp::List &list,
+ CompString str)
+{
+ CompString value;
+ int j, i = 0;
+ int flags = 0;
+
+ str += "\0";
+
+ while (str[i] != '\0')
+ {
+ while (str[i] == ' ')
+ i++;
+
+ if (str[i] == '!')
+ {
+ flags |= MATCH_OP_NOT_MASK;
+
+ i++;
+ while (str[i] == ' ')
+ i++;
+ }
+
+ if (str[i] == '(')
+ {
+ int level = 1;
+ int length;
+
+ j = ++i;
+
+ while (str[j] != '\0')
+ {
+ if (str[j] == '(')
+ {
+ level++;
+ }
+ else if (str[j] == ')')
+ {
+ level--;
+ if (level == 0)
+ break;
+ }
+
+ j = nextIndex (str, ++j);
+ }
+
+ length = j - i;
+
+ MatchGroupOp *group = new MatchGroupOp ();
+ matchAddFromString (group->op, str.substr (i, length));
+ group->flags = flags;
+ list.push_back (group);
+
+ while (str[j] != '\0' && str[j] != '|' && str[j] != '&')
+ j++;
+ }
+ else
+ {
+ j = i;
+
+ while (str[j] != '\0' && str[j] != '|' && str[j] != '&')
+ j = nextIndex (str, ++j);
+
+ if (j > i)
+ {
+ MatchExpOp *exp = new MatchExpOp ();
+ exp->value = strndupValue (str.substr (i, j - i));
+ exp->flags = flags;
+ list.push_back (exp);
+ }
+ }
+
+ i = j;
+
+ if (str[i] != '\0')
+ {
+ if (str[i] == '&')
+ flags = MATCH_OP_AND_MASK;
+
+ i++;
+ }
+ }
+
+ if (list.size ())
+ list.front ()->flags &= ~MATCH_OP_AND_MASK;
+
+}
+
+static CompString
+matchOpsToString (MatchOp::List &list)
+{
+ CompString value (""), group;
+
+ foreach (MatchOp *op, list)
+ {
+ switch (op->type ()) {
+ case MatchOp::TypeGroup:
+ group =
+ matchOpsToString (dynamic_cast <MatchGroupOp *> (op)->op);
+
+ if (group.length ())
+ {
+ if (value.length ())
+ {
+ value += ((op->flags & MATCH_OP_AND_MASK) ?
+ "& " : "| ");
+ }
+ if (op->flags & MATCH_OP_NOT_MASK)
+ value += "!";
+ value += "(" + group + ") ";
+ }
+ break;
+ case MatchOp::TypeExp:
+ if (value.length ())
+ value += ((op->flags & MATCH_OP_AND_MASK) ? "& " : "| ");
+
+ if (op->flags & MATCH_OP_NOT_MASK)
+ value += "!";
+
+ value += dynamic_cast <MatchExpOp *> (op)->value;
+ value += " ";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!value.empty ())
+ value.erase (value.length () - 1);
+
+ return value;
+}
+
+static void
+matchUpdateOps (MatchOp::List &list)
+{
+ MatchExpOp *exp;
+ foreach (MatchOp *op, list)
+ {
+ switch (op->type ()) {
+ case MatchOp::TypeGroup:
+ matchUpdateOps (dynamic_cast <MatchGroupOp *> (op)->op);
+ break;
+ case MatchOp::TypeExp:
+ exp = dynamic_cast <MatchExpOp *> (op);
+ if (exp && screen)
+ exp->e.reset (screen->matchInitExp (exp->value));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static bool
+matchEvalOps (MatchOp::List &list,
+ CompWindow *w)
+{
+ bool value, result = false;
+ MatchExpOp *exp;
+
+ foreach (MatchOp *op, list)
+ {
+ /* fast evaluation */
+ if (op->flags & MATCH_OP_AND_MASK)
+ {
+ /* result will never be true */
+ if (!result)
+ return false;
+ }
+ else
+ {
+ /* result will always be true */
+ if (result)
+ return true;
+ }
+
+ switch (op->type ()) {
+ case MatchOp::TypeGroup:
+ value =
+ matchEvalOps (dynamic_cast <MatchGroupOp *> (op)->op, w);
+ break;
+ case MatchOp::TypeExp:
+ exp = dynamic_cast <MatchExpOp *> (op);
+ if (exp->e.get ())
+ value = exp->e->evaluate (w);
+ else
+ value = true;
+ break;
+ default:
+ value = true;
+ break;
+ }
+
+ if (op->flags & MATCH_OP_NOT_MASK)
+ value = !value;
+
+ if (op->flags & MATCH_OP_AND_MASK)
+ result = (result && value);
+ else
+ result = (result || value);
+ }
+
+ return result;
+}
+
+MatchOp::MatchOp () :
+ flags (0)
+{
+}
+
+MatchOp::~MatchOp ()
+{
+}
+
+MatchExpOp::MatchExpOp () :
+ value (""),
+ e ()
+{
+}
+
+MatchExpOp::MatchExpOp (const MatchExpOp &ex) :
+ value (ex.value),
+ e (ex.e)
+{
+ flags = ex.flags;
+}
+
+MatchGroupOp::MatchGroupOp () :
+ op (0)
+{
+}
+
+MatchGroupOp::MatchGroupOp (const MatchGroupOp &gr) :
+ op (0)
+{
+ *this = gr;
+ flags = gr.flags;
+}
+
+MatchGroupOp::~MatchGroupOp ()
+{
+ foreach (MatchOp *o, op)
+ delete o;
+}
+
+MatchGroupOp &
+MatchGroupOp::operator= (const MatchGroupOp &gr)
+{
+ MatchGroupOp *gop;
+ MatchExpOp *eop;
+
+ foreach (MatchOp *o, op)
+ delete o;
+
+ op.clear ();
+
+ foreach (MatchOp *o, gr.op)
+ {
+ switch (o->type ())
+ {
+ case MatchOp::TypeGroup:
+ gop = new MatchGroupOp (dynamic_cast <MatchGroupOp &> (*o));
+ op.push_back (gop);
+ break;
+ case MatchOp::TypeExp:
+ eop = new MatchExpOp (dynamic_cast <MatchExpOp &> (*o));
+ op.push_back (eop);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return *this;
+}
+
+PrivateMatch::PrivateMatch () :
+ op ()
+{
+}
+
+
+CompMatch::CompMatch () :
+ priv (new PrivateMatch ())
+{
+}
+
+CompMatch::CompMatch (const CompString str) :
+ priv (new PrivateMatch ())
+{
+ matchAddFromString (priv->op.op, str);
+ update ();
+}
+
+CompMatch::CompMatch (const CompMatch &match) :
+ priv (new PrivateMatch ())
+{
+ priv->op = match.priv->op;
+ update ();
+}
+
+CompMatch::~CompMatch ()
+{
+ delete priv;
+}
+
+void
+CompMatch::update ()
+{
+ matchResetOps (priv->op.op);
+ matchUpdateOps (priv->op.op);
+}
+
+bool
+CompMatch::evaluate (CompWindow *window)
+{
+ return matchEvalOps (priv->op.op, window);
+}
+
+CompString
+CompMatch::toString () const
+{
+ return matchOpsToString (priv->op.op);
+}
+
+bool
+CompMatch::isEmpty () const
+{
+ return (*this == emptyMatch);
+}
+
+CompMatch &
+CompMatch::operator= (const CompMatch &match)
+{
+ priv->op = match.priv->op;
+ update ();
+
+ return *this;
+}
+
+CompMatch &
+CompMatch::operator&= (const CompMatch &match)
+{
+ MatchGroupOp *g1 = new MatchGroupOp (priv->op);
+ MatchGroupOp *g2 = new MatchGroupOp (match.priv->op);
+
+ g2->flags = MATCH_OP_AND_MASK;
+
+ priv->op = MatchGroupOp ();
+ priv->op.op.push_back (g1);
+ priv->op.op.push_back (g2);
+ update ();
+
+ return *this;
+}
+
+CompMatch &
+CompMatch::operator|= (const CompMatch &match)
+{
+ MatchGroupOp *g1 = new MatchGroupOp (priv->op);
+ MatchGroupOp *g2 = new MatchGroupOp (match.priv->op);
+
+ priv->op = MatchGroupOp ();
+ priv->op.op.push_back (g1);
+ priv->op.op.push_back (g2);
+ update ();
+
+ return *this;
+}
+
+const CompMatch &
+CompMatch::operator& (const CompMatch &match)
+{
+ return CompMatch (*this) &= match;
+}
+
+const CompMatch &
+CompMatch::operator| (const CompMatch &match)
+{
+ return CompMatch (*this) |= match;
+}
+
+const CompMatch &
+CompMatch::operator! ()
+{
+ MatchGroupOp *g = new MatchGroupOp (priv->op);
+
+ g->flags ^= MATCH_OP_NOT_MASK;
+ priv->op = MatchGroupOp ();
+ priv->op.op.push_back (g);
+ update ();
+
+ return *this;
+}
+
+CompMatch &
+CompMatch::operator= (const CompString &str)
+{
+ priv->op = MatchGroupOp ();
+ matchAddFromString (priv->op.op, str);
+ update ();
+
+ return *this;
+}
+
+CompMatch &
+CompMatch::operator&= (const CompString &str)
+{
+ *this &= CompMatch (str);
+
+ return *this;
+}
+
+CompMatch &
+CompMatch::operator|= (const CompString &str)
+{
+ *this |= CompMatch (str);
+
+ return *this;
+}
+
+const CompMatch &
+CompMatch::operator& (const CompString &str)
+{
+ *this &= str;
+
+ return *this;
+}
+
+const CompMatch &
+CompMatch::operator| (const CompString &str)
+{
+ *this |= str;
+
+ return *this;
+}
+
+bool
+CompMatch::operator== (const CompMatch &match) const
+{
+ return matchOpsEqual (priv->op.op, match.priv->op.op);
+}
+
+bool
+CompMatch::operator!= (const CompMatch &match) const
+{
+ return !(*this == match);
+}
diff --git a/src/modifierhandler.cpp b/src/modifierhandler.cpp
new file mode 100644
index 0000000..3e7c480
--- /dev/null
+++ b/src/modifierhandler.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ * Sam Spilsbury <smspillaz@gmail.com>
+ */
+
+#include <core/screen.h>
+#include "privatescreen.h"
+
+const unsigned int ModifierHandler::virtualModMask[7] = {
+ CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
+ CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
+};
+
+const int ModifierHandler::maskTable[8] = {
+ ShiftMask, LockMask, ControlMask, Mod1Mask,
+ Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+};
+
+unsigned int
+ModifierHandler::ignoredModMask ()
+{
+ return mIgnoredModMask;
+}
+
+const XModifierKeymap *
+ModifierHandler::modMap ()
+{
+ return mModMap;
+}
+
+void
+ModifierHandler::updateModifierMappings ()
+{
+ unsigned int modMask[CompModNum];
+ int i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
+ KeySym* key;
+
+ for (i = 0; i < CompModNum; i++)
+ modMask[i] = 0;
+
+ XDisplayKeycodes (screen->dpy (), &minKeycode, &maxKeycode);
+ key = XGetKeyboardMapping (screen->dpy (),
+ minKeycode, (maxKeycode - minKeycode + 1),
+ &keysymsPerKeycode);
+
+ if (mModMap)
+ XFreeModifiermap (mModMap);
+
+ mModMap = XGetModifierMapping (screen->dpy ());
+ if (mModMap && mModMap->max_keypermod > 0)
+ {
+ KeySym keysym;
+ int index, size, mask;
+
+ size = maskTableSize * mModMap->max_keypermod;
+
+ for (i = 0; i < size; i++)
+ {
+ if (!mModMap->modifiermap[i])
+ continue;
+
+ index = 0;
+ do
+ {
+ keysym = XKeycodeToKeysym (screen->dpy (),
+ mModMap->modifiermap[i],
+ index++);
+ } while (!keysym && index < keysymsPerKeycode);
+
+ if (keysym)
+ {
+ mask = maskTable[i / mModMap->max_keypermod];
+
+ if (keysym == XK_Alt_L ||
+ keysym == XK_Alt_R)
+ {
+ modMask[CompModAlt] |= mask;
+ }
+ else if (keysym == XK_Meta_L ||
+ keysym == XK_Meta_R)
+ {
+ modMask[CompModMeta] |= mask;
+ }
+ else if (keysym == XK_Super_L ||
+ keysym == XK_Super_R)
+ {
+ modMask[CompModSuper] |= mask;
+ }
+ else if (keysym == XK_Hyper_L ||
+ keysym == XK_Hyper_R)
+ {
+ modMask[CompModHyper] |= mask;
+ }
+ else if (keysym == XK_Mode_switch)
+ {
+ modMask[CompModModeSwitch] |= mask;
+ }
+ else if (keysym == XK_Scroll_Lock)
+ {
+ modMask[CompModScrollLock] |= mask;
+ }
+ else if (keysym == XK_Num_Lock)
+ {
+ modMask[CompModNumLock] |= mask;
+ }
+ }
+ }
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (!modMask[i])
+ modMask[i] = CompNoMask;
+ }
+
+ if (memcmp (modMask, mModMask, sizeof (modMask)))
+ {
+ memcpy (mModMask, modMask, sizeof (modMask));
+
+ mIgnoredModMask = LockMask |
+ (modMask[CompModNumLock] & ~CompNoMask) |
+ (modMask[CompModScrollLock] & ~CompNoMask);
+
+ screen->priv->updatePassiveKeyGrabs ();
+ }
+ }
+
+ if (key)
+ XFree (key);
+}
+
+unsigned int
+ModifierHandler::virtualToRealModMask (unsigned int modMask)
+{
+ int i;
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (modMask & virtualModMask[i])
+ {
+ modMask &= ~virtualModMask[i];
+ modMask |= mModMask[i];
+ }
+ }
+
+ return modMask;
+}
+
+unsigned int
+ModifierHandler::keycodeToModifiers (int keycode)
+{
+ unsigned int mods = 0;
+ int mod, k;
+
+ for (mod = 0; mod < maskTableSize; mod++)
+ {
+ for (k = 0; k < mModMap->max_keypermod; k++)
+ {
+ if (mModMap->modifiermap[mod *
+ mModMap->max_keypermod + k] == keycode)
+ mods |= maskTable[mod];
+ }
+ }
+
+ return mods;
+}
+
+ModifierHandler::ModifierHandler () :
+ mIgnoredModMask (LockMask),
+ mModMap (0)
+{
+ for (int i = 0; i < ModNum; i++)
+ mModMask[i] = NoMask;
+}
+
+ModifierHandler::~ModifierHandler ()
+{
+ if (mModMap)
+ XFreeModifiermap (mModMap);
+
+ mModMap = NULL;
+}
diff --git a/src/option.cpp b/src/option.cpp
new file mode 100644
index 0000000..1fb69f0
--- /dev/null
+++ b/src/option.cpp
@@ -0,0 +1,964 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <core/core.h>
+#include <core/option.h>
+#include "privateoption.h"
+
+CompOption::Vector noOptions (0);
+
+CompOption::Value::Value () :
+ priv (new PrivateValue ())
+{
+}
+
+CompOption::Value::Value (const Value &v) :
+ priv (new PrivateValue (*v.priv))
+{
+}
+
+CompOption::Value::~Value ()
+{
+ delete priv;
+}
+
+CompOption::Value::Value (const bool b) :
+ priv (new PrivateValue ())
+{
+ set (b);
+}
+
+CompOption::Value::Value (const int i) :
+ priv (new PrivateValue ())
+{
+ set (i);
+}
+
+CompOption::Value::Value (const float f) :
+ priv (new PrivateValue ())
+{
+ set (f);
+}
+
+CompOption::Value::Value (const unsigned short *color) :
+ priv (new PrivateValue ())
+{
+ set (color);
+}
+
+CompOption::Value::Value (const CompString& s) :
+ priv (new PrivateValue ())
+{
+ set (s);
+}
+
+CompOption::Value::Value (const char *s) :
+ priv (new PrivateValue ())
+{
+ set (s);
+}
+
+
+CompOption::Value::Value (const CompMatch& m) :
+ priv (new PrivateValue ())
+{
+ set (m);
+}
+
+CompOption::Value::Value (const CompAction& a) :
+ priv (new PrivateValue ())
+{
+ set (a);
+}
+
+CompOption::Value::Value (CompOption::Type type, const Vector& l) :
+ priv (new PrivateValue ())
+{
+ set (type, l);
+}
+
+CompOption::Type
+CompOption::Value::type () const
+{
+ return priv->type;
+}
+
+void
+CompOption::Value::set (const bool b)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeBool;
+ priv->value.b = b;
+}
+
+void
+CompOption::Value::set (const int i)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeInt;
+ priv->value.i = i;
+}
+
+void
+CompOption::Value::set (const float f)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeFloat;
+ priv->value.f = f;
+}
+
+void
+CompOption::Value::set (const unsigned short *color)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeColor;
+ priv->value.c[0] = color[0];
+ priv->value.c[1] = color[1];
+ priv->value.c[2] = color[2];
+ priv->value.c[3] = color[3];
+}
+
+void
+CompOption::Value::set (const CompString& s)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeString;
+ priv->string = s;
+}
+
+void
+CompOption::Value::set (const char *s)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeString;
+ priv->string = CompString (s);
+}
+
+void
+CompOption::Value::set (const CompMatch& m)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeMatch;
+ priv->match = m;
+}
+
+void
+CompOption::Value::set (const CompAction& a)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeAction;
+ priv->action = a;
+}
+
+void
+CompOption::Value::set (CompOption::Type type, const Vector& l)
+{
+ priv->reset ();
+ priv->type = CompOption::TypeList;
+ priv->list = l;
+ priv->listType = type;
+}
+
+static bool
+checkIsAction (CompOption::Type type)
+{
+ switch (type) {
+ case CompOption::TypeAction:
+ case CompOption::TypeKey:
+ case CompOption::TypeButton:
+ case CompOption::TypeEdge:
+ case CompOption::TypeBell:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool
+CompOption::Value::b ()
+{
+ if (!priv->checkType (CompOption::TypeBool))
+ return false;
+
+ return priv->value.b;
+}
+
+int
+CompOption::Value::i ()
+{
+ if (!priv->checkType (CompOption::TypeInt))
+ return 0;
+
+ return priv->value.i;
+}
+
+float
+CompOption::Value::f ()
+{
+ if (!priv->checkType (CompOption::TypeFloat))
+ return 0.0;
+
+ return priv->value.f;
+}
+
+static unsigned short defaultColor[4] = { 0x0, 0x0, 0x0, 0xffff};
+
+unsigned short *
+CompOption::Value::c ()
+{
+ if (!priv->checkType (CompOption::TypeColor))
+ return reinterpret_cast<unsigned short *> (defaultColor);
+
+ return priv->value.c;
+}
+
+CompString
+CompOption::Value::s ()
+{
+ if (!priv->checkType (CompOption::TypeString))
+ return "";
+
+ return priv->string;
+}
+
+CompMatch &
+CompOption::Value::match ()
+{
+ priv->checkType (CompOption::TypeMatch);
+
+ return priv->match;
+}
+
+CompAction &
+CompOption::Value::action ()
+{
+ priv->checkType (priv->type);
+
+ if (!checkIsAction (priv->type))
+ compLogMessage ("core", CompLogLevelWarn,
+ "CompOption::Value not an action");
+
+ return priv->action;
+}
+
+CompOption::Type
+CompOption::Value::listType ()
+{
+ priv->checkType (CompOption::TypeList);
+
+ return priv->listType;
+}
+
+CompOption::Value::Vector &
+CompOption::Value::list ()
+{
+ priv->checkType (CompOption::TypeList);
+
+ return priv->list;
+}
+
+CompOption::Value::operator bool ()
+{
+ return b ();
+}
+
+CompOption::Value::operator int ()
+{
+ return i ();
+}
+
+CompOption::Value::operator float ()
+{
+ return f ();
+}
+
+CompOption::Value::operator unsigned short * ()
+{
+ return c ();
+}
+
+CompOption::Value::operator CompString ()
+{
+ return s ();
+}
+
+CompOption::Value::operator CompMatch & ()
+{
+ return match ();
+}
+
+CompOption::Value::operator CompAction & ()
+{
+ return action ();
+}
+
+CompOption::Value::operator CompAction * ()
+{
+ return &action ();
+}
+
+CompOption::Value::operator Type ()
+{
+ return listType ();
+}
+
+CompOption::Value::operator Vector & ()
+{
+ return list ();
+}
+
+bool
+CompOption::Value::operator== (const CompOption::Value &val)
+{
+ if (priv->type != val.priv->type)
+ return false;
+
+ switch (priv->type)
+ {
+ case CompOption::TypeBool:
+ return priv->value.b == val.priv->value.b;
+ break;
+
+ case CompOption::TypeInt:
+ return priv->value.i == val.priv->value.i;
+ break;
+
+ case CompOption::TypeFloat:
+ return priv->value.f == val.priv->value.f;
+ break;
+
+ case CompOption::TypeColor:
+ return (priv->value.c[0] == val.priv->value.c[0]) &&
+ (priv->value.c[1] == val.priv->value.c[1]) &&
+ (priv->value.c[2] == val.priv->value.c[2]) &&
+ (priv->value.c[3] == val.priv->value.c[3]);
+ break;
+
+ case CompOption::TypeString:
+ return priv->string.compare (val.priv->string) == 0;
+ break;
+
+ case CompOption::TypeMatch:
+ return priv->match == val.priv->match;
+ break;
+
+ case CompOption::TypeAction:
+ return priv->action == val.priv->action;
+ break;
+
+ case CompOption::TypeList:
+ if (priv->listType != val.priv->listType)
+ return false;
+
+ if (priv->list.size () != val.priv->list.size ())
+ return false;
+
+ for (unsigned int i = 0; i < priv->list.size (); i++)
+ if (priv->list[i] != val.priv->list[i])
+ return false;
+
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool
+CompOption::Value::operator!= (const CompOption::Value &val)
+{
+ return !(*this == val);
+}
+
+CompOption::Value &
+CompOption::Value::operator= (const CompOption::Value &val)
+{
+ delete priv;
+ priv = new PrivateValue (*val.priv);
+
+ return *this;
+}
+
+PrivateValue::PrivateValue () :
+ type (CompOption::TypeUnset),
+ string (""),
+ action (),
+ match (),
+ listType (CompOption::TypeUnset),
+ list ()
+{
+ memset (&value, 0, sizeof (ValueUnion));
+}
+
+PrivateValue::PrivateValue (const PrivateValue& p) :
+ type (p.type),
+ string (p.string),
+ action (p.action),
+ match (p.match),
+ listType (p.listType),
+ list (p.list)
+{
+ memcpy (&value, &p.value, sizeof (ValueUnion));
+}
+
+bool
+PrivateValue::checkType (CompOption::Type refType)
+{
+ if (type == CompOption::TypeUnset)
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Value type is not yet set");
+ return false;
+ }
+
+ if (type != refType)
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Value type does not match (is %d, expected %d)",
+ type, refType);
+ return false;
+ }
+
+ return true;
+}
+
+void
+PrivateValue::reset ()
+{
+ switch (type) {
+ case CompOption::TypeString:
+ string = "";
+ break;
+ case CompOption::TypeMatch:
+ match = CompMatch ();
+ break;
+ case CompOption::TypeAction:
+ action = CompAction ();
+ break;
+ case CompOption::TypeList:
+ list.clear ();
+ listType = CompOption::TypeBool;
+ break;
+ default:
+ break;
+ }
+ type = CompOption::TypeBool;
+}
+
+CompOption::Restriction::Restriction () :
+ priv (new PrivateRestriction ())
+{
+}
+
+CompOption::Restriction::Restriction (const CompOption::Restriction &r) :
+ priv (new PrivateRestriction (*r.priv))
+{
+}
+
+CompOption::Restriction::~Restriction ()
+{
+ delete priv;
+}
+
+int
+CompOption::Restriction::iMin ()
+{
+ if (priv->type == CompOption::TypeInt)
+ return priv->rest.i.min;
+ return MINSHORT;
+}
+
+int
+CompOption::Restriction::iMax ()
+{
+ if (priv->type == CompOption::TypeInt)
+ return priv->rest.i.max;
+ return MAXSHORT;
+}
+
+float
+CompOption::Restriction::fMin ()
+{
+ if (priv->type == CompOption::TypeFloat)
+ return priv->rest.f.min;
+ return MINSHORT;
+}
+
+float
+CompOption::Restriction::fMax ()
+{
+ if (priv->type == CompOption::TypeFloat)
+ return priv->rest.f.min;
+ return MINSHORT;
+}
+
+float
+CompOption::Restriction::fPrecision ()
+{
+ if (priv->type == CompOption::TypeFloat)
+ return priv->rest.f.precision;
+ return 0.1f;
+}
+
+
+void
+CompOption::Restriction::set (int min, int max)
+{
+ priv->type = CompOption::TypeInt;
+ priv->rest.i.min = min;
+ priv->rest.i.max = max;
+}
+
+void
+CompOption::Restriction::set (float min, float max, float precision)
+{
+ priv->type = CompOption::TypeFloat;
+ priv->rest.f.min = min;
+ priv->rest.f.max = max;
+ priv->rest.f.precision = precision;
+}
+
+bool
+CompOption::Restriction::inRange (int i)
+{
+ if (priv->type != CompOption::TypeInt)
+ return true;
+ if (i < priv->rest.i.min)
+ return false;
+ if (i > priv->rest.i.max)
+ return false;
+ return true;
+}
+
+bool
+CompOption::Restriction::inRange (float f)
+{
+ if (priv->type != CompOption::TypeFloat)
+ return true;
+ if (f < priv->rest.f.min)
+ return false;
+ if (f > priv->rest.f.max)
+ return false;
+ return true;
+}
+
+CompOption::Restriction &
+CompOption::Restriction::operator= (const CompOption::Restriction &rest)
+{
+ delete priv;
+ priv = new PrivateRestriction (*rest.priv);
+ return *this;
+}
+
+CompOption *
+CompOption::Class::getOption (const CompString &name)
+{
+ CompOption *o = CompOption::findOption (getOptions (), name);
+ return o;
+}
+
+CompOption *
+CompOption::findOption (CompOption::Vector &options,
+ CompString name,
+ unsigned int *index)
+{
+ unsigned int i;
+
+ for (i = 0; i < options.size (); i++)
+ {
+ if (options[i].priv->name == name)
+ {
+ if (index)
+ *index = i;
+
+ return &options[i];
+ }
+ }
+
+ return NULL;
+}
+
+CompOption::CompOption () :
+ priv (new PrivateOption ())
+{
+}
+
+CompOption::CompOption (const CompOption &o) :
+ priv (new PrivateOption (*o.priv))
+{
+}
+
+CompOption::CompOption (CompString name, CompOption::Type type) :
+ priv (new PrivateOption ())
+{
+ setName (name, type);
+}
+
+static void
+finiScreenOptionValue (CompScreen *s,
+ CompOption::Value &v,
+ CompOption::Type type)
+{
+ switch (type) {
+ case CompOption::TypeAction:
+ case CompOption::TypeKey:
+ case CompOption::TypeButton:
+ case CompOption::TypeEdge:
+ case CompOption::TypeBell:
+ if (v.action ().state () & CompAction::StateAutoGrab)
+ s->removeAction (&v.action ());
+ break;
+
+ case CompOption::TypeList:
+ foreach (CompOption::Value &val, v.list ())
+ finiScreenOptionValue (s, val, v.listType ());
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+finiOptionValue (CompOption::Value &v,
+ CompOption::Type type)
+{
+ switch (type) {
+ case CompOption::TypeAction:
+ case CompOption::TypeKey:
+ case CompOption::TypeButton:
+ case CompOption::TypeEdge:
+ case CompOption::TypeBell:
+ if (v.action ().state () & CompAction::StateAutoGrab && screen)
+ screen->removeAction (&v.action ());
+ break;
+
+ case CompOption::TypeList:
+ foreach (CompOption::Value &val, v.list ())
+ finiOptionValue (val, v.listType ());
+ break;
+
+ default:
+ break;
+ }
+}
+
+CompOption::~CompOption ()
+{
+ finiOptionValue (priv->value, priv->type);
+ delete priv;
+}
+
+void
+CompOption::setName (CompString name, CompOption::Type type)
+{
+ priv->name = name;
+ priv->type = type;
+}
+
+CompString
+CompOption::name ()
+{
+ return priv->name;
+}
+
+CompOption::Type
+CompOption::type ()
+{
+ return priv->type;
+}
+
+CompOption::Value &
+CompOption::value ()
+{
+ return priv->value;
+}
+
+CompOption::Restriction &
+CompOption::rest ()
+{
+ return priv->rest;
+}
+
+bool
+CompOption::set (CompOption::Value &val)
+{
+ if (isAction () && priv->type != CompOption::TypeAction)
+ val.action ().copyState (priv->value.action ());
+
+ if (priv->type != val.type () &&
+ (!isAction () || !checkIsAction (val.type ())))
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Can't set Value with type %d to "
+ "option \"%s\" with type %d",
+ val.type (), priv->name.c_str (), priv->type);
+ return false;
+ }
+
+ if (priv->value == val)
+ return false;
+
+ if (isAction () &&
+ priv->value.action ().state () & CompAction::StateAutoGrab && screen)
+ {
+ if (!screen->addAction (&val.action ()))
+ return false;
+ else
+ screen->removeAction (&priv->value.action ());
+ }
+
+ switch (priv->type)
+ {
+ case CompOption::TypeInt:
+ if (!priv->rest.inRange (val.i ()))
+ return false;
+ break;
+
+ case CompOption::TypeFloat:
+ {
+ float v, p;
+ int sign = (val.f () < 0 ? -1 : 1);
+
+ if (!priv->rest.inRange (val.f ()))
+ return false;
+
+ p = 1.0f / priv->rest.fPrecision ();
+ v = ((int) (val.f () * p + sign * 0.5f)) / p;
+
+ priv->value.set (v);
+ return true;
+ }
+
+ case CompOption::TypeAction:
+ return false;
+
+ case CompOption::TypeKey:
+ if (val.action ().type () == value().action ().type () &&
+ !(val.action ().type () & CompAction::BindingTypeKey))
+ return false;
+ break;
+
+ case CompOption::TypeButton:
+ if (val.action ().type () == value().action ().type () &&
+ !(val.action ().type () & (CompAction::BindingTypeButton |
+ CompAction::BindingTypeEdgeButton)))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+
+ priv->value = val;
+
+ return true;
+}
+
+bool
+CompOption::isAction ()
+{
+ return checkIsAction (priv->type);
+}
+
+CompOption &
+CompOption::operator= (const CompOption &option)
+{
+ delete priv;
+ priv = new PrivateOption (*option.priv);
+ return *this;
+}
+
+bool
+CompOption::getBoolOptionNamed (const Vector& options,
+ const CompString& name,
+ bool defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeBool && o.priv->name == name)
+ return o.priv->value.b ();
+
+ return defaultValue;
+}
+
+int
+CompOption::getIntOptionNamed (const Vector& options,
+ const CompString& name,
+ int defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeInt && o.priv->name == name)
+ return o.priv->value.i ();
+
+ return defaultValue;
+}
+
+float
+CompOption::getFloatOptionNamed (const Vector& options,
+ const CompString& name,
+ const float& defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeFloat && o.priv->name == name)
+ return o.priv->value.f ();
+
+ return defaultValue;
+}
+
+CompString
+CompOption::getStringOptionNamed (const Vector& options,
+ const CompString& name,
+ const CompString& defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeString && o.priv->name == name)
+ return o.priv->value.s ();
+
+ return defaultValue;
+}
+
+unsigned short *
+CompOption::getColorOptionNamed (const Vector& options,
+ const CompString& name,
+ unsigned short *defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeColor && o.priv->name == name)
+ return o.priv->value.c ();
+
+ return defaultValue;
+}
+
+CompMatch
+CompOption::getMatchOptionNamed (const Vector& options,
+ const CompString& name,
+ const CompMatch& defaultValue)
+{
+ foreach (const CompOption &o, options)
+ if (o.priv->type == CompOption::TypeMatch && o.priv->name == name)
+ return o.priv->value.match ();
+
+ return defaultValue;
+}
+
+bool
+CompOption::stringToColor (CompString color,
+ unsigned short *rgba)
+{
+ int c[4];
+
+ if (sscanf (color.c_str (), "#%2x%2x%2x%2x",
+ &c[0], &c[1], &c[2], &c[3]) == 4)
+ {
+ rgba[0] = c[0] << 8 | c[0];
+ rgba[1] = c[1] << 8 | c[1];
+ rgba[2] = c[2] << 8 | c[2];
+ rgba[3] = c[3] << 8 | c[3];
+
+ return true;
+ }
+
+ return false;
+}
+
+CompString
+CompOption::colorToString (unsigned short *rgba)
+{
+ return compPrintf ("#%.2x%.2x%.2x%.2x", rgba[0] / 256, rgba[1] / 256,
+ rgba[2] / 256, rgba[3] / 256);
+}
+
+CompString
+CompOption::typeToString (CompOption::Type type)
+{
+ switch (type) {
+ case CompOption::TypeBool:
+ return "bool";
+ case CompOption::TypeInt:
+ return "int";
+ case CompOption::TypeFloat:
+ return "float";
+ case CompOption::TypeString:
+ return "string";
+ case CompOption::TypeColor:
+ return "color";
+ case CompOption::TypeAction:
+ return "action";
+ case CompOption::TypeKey:
+ return "key";
+ case CompOption::TypeButton:
+ return "button";
+ case CompOption::TypeEdge:
+ return "edge";
+ case CompOption::TypeBell:
+ return "bell";
+ case CompOption::TypeMatch:
+ return "match";
+ case CompOption::TypeList:
+ return "list";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+bool
+CompOption::setOption (CompOption &o,
+ CompOption::Value &value)
+{
+ return o.set (value);
+}
+
+PrivateOption::PrivateOption () :
+ name (""),
+ type (CompOption::TypeUnset),
+ value (),
+ rest ()
+{
+}
+
+PrivateOption::PrivateOption (const PrivateOption &p) :
+ name (p.name),
+ type (p.type),
+ value (p.value),
+ rest (p.rest)
+{
+}
+
diff --git a/src/output.cpp b/src/output.cpp
new file mode 100644
index 0000000..a1d1940
--- /dev/null
+++ b/src/output.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/core.h>
+#include <core/output.h>
+
+CompOutput::CompOutput ()
+{
+ mName = "";
+ mId = ~0;
+}
+
+CompString
+CompOutput::name () const
+{
+ return mName;
+}
+
+unsigned int
+CompOutput::id () const
+{
+ return mId;
+}
+
+const CompRect&
+CompOutput::workArea () const
+{
+ return mWorkArea;
+}
+
+void
+CompOutput::setWorkArea (const CompRect& workarea)
+{
+ mWorkArea = workarea;
+
+ if (workarea.x () < (int) x1 ())
+ mWorkArea.setX (x1 ());
+
+ if (workarea.y () < (int) y1 ())
+ mWorkArea.setY (y1 ());
+
+ if (workarea.x2 () > (int) x2 ())
+ mWorkArea.setWidth (x2 () - mWorkArea.x ());
+
+ if (workarea.y2 () > (int) y2 ())
+ mWorkArea.setHeight (y2 () - mWorkArea.y ());
+}
+
+void
+CompOutput::setGeometry (int x,
+ int y,
+ int width,
+ int height)
+{
+ CompRect::setGeometry (x, y, width, height);
+
+ mWorkArea = *this;
+}
+
+void
+CompOutput::setId (CompString name, unsigned int id)
+{
+ mName = name;
+ mId = id;
+}
+
diff --git a/src/plugin.cpp b/src/plugin.cpp
new file mode 100644
index 0000000..f9d8954
--- /dev/null
+++ b/src/plugin.cpp
@@ -0,0 +1,700 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <list>
+
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <core/core.h>
+#include "privatescreen.h"
+
+CompPlugin::Map pluginsMap;
+CompPlugin::List plugins;
+
+class CorePluginVTable : public CompPlugin::VTable
+{
+ public:
+
+ bool init ();
+
+ CompOption::Vector & getOptions ();
+
+ bool setOption (const CompString &name,
+ CompOption::Value &value);
+};
+
+COMPIZ_PLUGIN_20090315 (core, CorePluginVTable)
+
+CompPlugin::VTable * getCoreVTable ()
+{
+ if (!coreVTable)
+ {
+ return getCompPluginVTable20090315_core ();
+ }
+
+ return coreVTable;
+}
+
+bool
+CorePluginVTable::init ()
+{
+ return true;
+}
+
+CompOption::Vector &
+CorePluginVTable::getOptions ()
+{
+ return screen->getOptions ();
+}
+
+bool
+CorePluginVTable::setOption (const CompString &name,
+ CompOption::Value &value)
+{
+ return screen->setOption (name, value);
+}
+
+static bool
+cloaderLoadPlugin (CompPlugin *p,
+ const char *path,
+ const char *name)
+{
+ if (path)
+ return false;
+
+ if (strcmp (name, getCoreVTable ()->name ().c_str ()))
+ return false;
+
+ p->vTable = getCoreVTable ();
+ p->devPrivate.ptr = NULL;
+ p->devType = "cloader";
+
+ return true;
+}
+
+static void
+cloaderUnloadPlugin (CompPlugin *p)
+{
+ delete p->vTable;
+}
+
+static CompStringList
+cloaderListPlugins (const char *path)
+{
+ CompStringList rv;
+
+ if (path)
+ return CompStringList ();
+
+ rv.push_back (CompString (getCoreVTable ()->name ()));
+
+ return rv;
+}
+
+static bool
+dlloaderLoadPlugin (CompPlugin *p,
+ const char *path,
+ const char *name)
+{
+ CompString file;
+ void *dlhand;
+ bool loaded = false;
+ struct stat fileInfo;
+
+ if (cloaderLoadPlugin (p, path, name))
+ return true;
+
+ if (path)
+ {
+ file = path;
+ file += "/";
+ }
+
+ file += "lib";
+ file += name;
+ file += ".so";
+
+ if (stat (file.c_str (), &fileInfo) != 0)
+ {
+ /* file likely not present */
+ compLogMessage ("core", CompLogLevelDebug,
+ "Could not stat() file %s : %s",
+ file.c_str (), strerror (errno));
+ return false;
+ }
+
+ dlhand = dlopen (file.c_str (), RTLD_LAZY);
+ if (dlhand)
+ {
+ PluginGetInfoProc getInfo;
+ char *error;
+ char sym[1024];
+
+ dlerror ();
+
+ snprintf (sym, 1024, "getCompPluginVTable20090315_%s", name);
+ getInfo = (PluginGetInfoProc) dlsym (dlhand, sym);
+
+ error = dlerror ();
+ if (error)
+ {
+ compLogMessage ("core", CompLogLevelError, "dlsym: %s", error);
+ getInfo = 0;
+ }
+
+ if (getInfo)
+ {
+ p->vTable = (*getInfo) ();
+ if (!p->vTable)
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Couldn't get vtable from '%s' plugin",
+ file.c_str ());
+ }
+ else
+ {
+ p->devPrivate.ptr = dlhand;
+ p->devType = "dlloader";
+ loaded = true;
+ }
+ }
+ }
+ else
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Couldn't load plugin '%s' : %s",
+ file.c_str (), dlerror ());
+ }
+
+ if (!loaded && dlhand)
+ dlclose (dlhand);
+
+ return loaded;
+}
+
+static void
+dlloaderUnloadPlugin (CompPlugin *p)
+{
+ if (p->devType == "dlloader")
+ {
+ delete p->vTable;
+ dlclose (p->devPrivate.ptr);
+ }
+ else
+ cloaderUnloadPlugin (p);
+}
+
+static int
+dlloaderFilter (const struct dirent *name)
+{
+ int length = strlen (name->d_name);
+
+ if (length < 7)
+ return 0;
+
+ if (strncmp (name->d_name, "lib", 3) ||
+ strncmp (name->d_name + length - 3, ".so", 3))
+ return 0;
+
+ return 1;
+}
+
+static CompStringList
+dlloaderListPlugins (const char *path)
+{
+ struct dirent **nameList;
+ char name[1024];
+ int length, nFile, i;
+
+ CompStringList rv = cloaderListPlugins (path);
+
+ if (!path)
+ path = ".";
+
+ nFile = scandir (path, &nameList, dlloaderFilter, alphasort);
+ if (!nFile)
+ return rv;
+
+ for (i = 0; i < nFile; i++)
+ {
+ length = strlen (nameList[i]->d_name);
+
+ strncpy (name, nameList[i]->d_name + 3, length - 6);
+ name[length - 6] = '\0';
+
+ rv.push_back (CompString (name));
+ }
+
+ return rv;
+}
+
+LoadPluginProc loaderLoadPlugin = dlloaderLoadPlugin;
+UnloadPluginProc loaderUnloadPlugin = dlloaderUnloadPlugin;
+ListPluginsProc loaderListPlugins = dlloaderListPlugins;
+
+
+static bool
+initPlugin (CompPlugin *p)
+{
+
+ if (!p->vTable->init ())
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "InitPlugin '%s' failed", p->vTable->name ().c_str ());
+ return false;
+ }
+
+ if (screen)
+ {
+ if (!p->vTable->initScreen (screen))
+ {
+ compLogMessage (p->vTable->name ().c_str (), CompLogLevelError,
+ "initScreen failed");
+ p->vTable->fini ();
+ return false;
+ }
+ if (!screen->initPluginForScreen (p))
+ {
+ p->vTable->fini ();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void
+finiPlugin (CompPlugin *p)
+{
+
+ if (screen)
+ {
+ screen->finiPluginForScreen (p);
+ p->vTable->finiScreen (screen);
+ }
+
+ p->vTable->fini ();
+}
+
+bool
+CompScreen::initPluginForScreen (CompPlugin *p)
+{
+ WRAPABLE_HND_FUNC_RETURN (2, bool, initPluginForScreen, p)
+
+ bool status = true;
+ CompWindowList::iterator it, fail;
+ CompWindow *w;
+
+ it = fail = priv->windows.begin ();
+ for (;it != priv->windows.end (); it++)
+ {
+ w = *it;
+ if (!p->vTable->initWindow (w))
+ {
+ compLogMessage (p->vTable->name ().c_str (), CompLogLevelError,
+ "initWindow failed");
+ fail = it;
+ status = false;
+ }
+ }
+
+ it = priv->windows.begin ();
+ for (;it != fail; it++)
+ {
+ w = *it;
+ p->vTable->finiWindow (w);
+ }
+
+ return status;
+}
+
+void
+CompScreen::finiPluginForScreen (CompPlugin *p)
+{
+ WRAPABLE_HND_FUNC (3, finiPluginForScreen, p)
+
+ foreach (CompWindow *w, priv->windows)
+ p->vTable->finiWindow (w);
+}
+
+bool
+CompPlugin::screenInitPlugins (CompScreen *s)
+{
+ CompPlugin::List::reverse_iterator rit = plugins.rbegin ();
+
+ CompPlugin *p = NULL;
+
+ while (rit != plugins.rend ())
+ {
+ p = (*rit);
+
+ if (p->vTable->initScreen (s))
+ s->initPluginForScreen (p);
+
+ rit++;
+ }
+
+ return true;
+}
+
+void
+CompPlugin::screenFiniPlugins (CompScreen *s)
+{
+ foreach (CompPlugin *p, plugins)
+ {
+ s->finiPluginForScreen (p);
+ p->vTable->finiScreen (s);
+ }
+
+}
+
+bool
+CompPlugin::windowInitPlugins (CompWindow *w)
+{
+ bool status = true;
+
+ CompPlugin::List::reverse_iterator rit = plugins.rbegin ();
+
+ CompPlugin *p = NULL;
+
+ while (rit != plugins.rend ())
+ {
+ p = (*rit);
+
+ status &= p->vTable->initWindow (w);
+
+ rit++;
+ }
+
+ return status;
+}
+
+void
+CompPlugin::windowFiniPlugins (CompWindow *w)
+{
+ foreach (CompPlugin *p, plugins)
+ {
+ p->vTable->finiWindow (w);
+ }
+}
+
+
+CompPlugin *
+CompPlugin::find (const char *name)
+{
+ CompPlugin::Map::iterator it = pluginsMap.find (name);
+
+ if (it != pluginsMap.end ())
+ return it->second;
+
+ return NULL;
+}
+
+void
+CompPlugin::unload (CompPlugin *p)
+{
+ (*loaderUnloadPlugin) (p);
+ delete p;
+}
+
+CompPlugin *
+CompPlugin::load (const char *name)
+{
+ CompPlugin *p;
+ char *home, *plugindir;
+ bool status;
+
+ p = new CompPlugin ();
+ if (!p)
+ return 0;
+
+ p->devPrivate.uval = 0;
+ p->devType = "";
+ p->vTable = 0;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
+ status = (*loaderLoadPlugin) (p, plugindir, name);
+ free (plugindir);
+
+ if (status)
+ return p;
+ }
+ }
+
+ status = (*loaderLoadPlugin) (p, PLUGINDIR, name);
+ if (status)
+ return p;
+
+ status = (*loaderLoadPlugin) (p, NULL, name);
+ if (status)
+ return p;
+
+ compLogMessage ("core", CompLogLevelError,
+ "Couldn't load plugin '%s'", name);
+
+ return 0;
+}
+
+bool
+CompPlugin::push (CompPlugin *p)
+{
+ const char *name = p->vTable->name ().c_str ();
+
+ std::pair<CompPlugin::Map::iterator, bool> insertRet =
+ pluginsMap.insert (std::pair<const char *, CompPlugin *> (name, p));
+
+ if (!insertRet.second)
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Plugin '%s' already active",
+ p->vTable->name ().c_str ());
+
+ return false;
+ }
+
+ plugins.push_front (p);
+
+ if (!initPlugin (p))
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Couldn't activate plugin '%s'", name);
+
+ pluginsMap.erase (name);
+ plugins.pop_front ();
+
+ return false;
+ }
+
+ return true;
+}
+
+CompPlugin *
+CompPlugin::pop (void)
+{
+ if (plugins.empty ())
+ return NULL;
+
+ CompPlugin *p = plugins.front ();
+
+ if (!p)
+ return 0;
+
+ pluginsMap.erase (p->vTable->name ().c_str ());
+
+ finiPlugin (p);
+
+ plugins.pop_front ();
+
+ return p;
+}
+
+CompPlugin::List &
+CompPlugin::getPlugins (void)
+{
+ return plugins;
+}
+
+static bool
+stringExist (CompStringList &list,
+ CompString s)
+{
+ foreach (CompString &l, list)
+ if (s.compare (l) == 0)
+ return true;
+
+ return false;
+}
+
+CompStringList
+CompPlugin::availablePlugins ()
+{
+ char *home, *plugindir;
+ CompStringList list, currentList, pluginList, homeList;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
+ homeList = (*loaderListPlugins) (plugindir);
+ free (plugindir);
+ }
+ }
+
+ pluginList = (*loaderListPlugins) (PLUGINDIR);
+ currentList = (*loaderListPlugins) (NULL);
+
+ if (!homeList.empty ())
+ {
+ foreach (CompString &s, homeList)
+ if (!stringExist (list, s))
+ list.push_back (s);
+ }
+
+ if (!pluginList.empty ())
+ {
+ foreach (CompString &s, pluginList)
+ if (!stringExist (list, s))
+ list.push_back (s);
+ }
+
+ if (!currentList.empty ())
+ {
+ foreach (CompString &s, currentList)
+ if (!stringExist (list, s))
+ list.push_back (s);
+ }
+
+ return list;
+}
+
+int
+CompPlugin::getPluginABI (const char *name)
+{
+ CompPlugin *p = find (name);
+ CompString s = name;
+
+ if (!p)
+ return 0;
+
+ s += "_ABI";
+
+ if (!screen->hasValue (s))
+ return 0;
+
+ return screen->getValue (s).uval;
+}
+
+bool
+CompPlugin::checkPluginABI (const char *name,
+ int abi)
+{
+ int pluginABI;
+
+ pluginABI = getPluginABI (name);
+ if (!pluginABI)
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Plugin '%s' not loaded.\n", name);
+ return false;
+ }
+ else if (pluginABI != abi)
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Plugin '%s' has ABI version '%d', expected "
+ "ABI version '%d'.\n",
+ name, pluginABI, abi);
+ return false;
+ }
+
+ return true;
+}
+
+CompPlugin::V