• Immutable Page
  • Info
  • Attachments

Handling Input

Input is handled in several different ways in Compiz. Use different input handling methods depending on the kind of function you want your plugin to provide. Each input handling mechanism has it's own advantages and disadvantages. Choose the input handling mechanism that is correct to your situation.


Compiz core automatically listens for X Events and will trigger callback functions if plugins have registered for them. Use an action if you want to trigger something in your plugin when the user presses a specific Key, Button or Edge combination. See BCOP for information on how to create and set a callback for an action in the XML file and in your plugin's code.

Action callbacks are constructed as so

static Bool
(CompDisplay     *d,
CompAction      *action,
CompActionState state,
CompOption      *option,
int             nOption)

The CompOption is the key to identifying which window and screen the action was triggered on. You can obtain a CompWindow *w and CompScreen *s by doing the following:

CompWindow *w = findWindowAtDisplay (d, getIntOptionNamed (option, nOption, "window", -1));
CompScreen *s = findScreenAtDisplay (s, getIntOptionNamed (option, nOption, "screen", -1));

(!) Remember to check the validity of these variables before continuing!

At the end of the action, if you choose, you can have a terminate callback called when the user releases the button that they were holding. If you do so, you will need to register a terminate callback (see BCOP) and have the following code in place in your initiate function

if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;

if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;

And in your terminate function:

action->state &= ~ (CompActionStateTermKey | CompActionStateTermButton);

Handling X Events

Core's handleEvent (CompDisplay *d, XEvent *event); function is wrappable, so once it has finished, it will pass control on to the first plugin that WRAP'd it. (See WRAPUNWRAP for more information of now this works)

On your initDisplay function, you should WRAP into handleEvent if you need to handle X Events directly. The constructor for your handleEvent function should look like this:

static void
(CompDisplay *d,
XEvent       *event)

When the function is called, you can switch (event->type) and handle X Event's directly. You should look at other plugins to see what kind of events you can use, but note that you can only get MotionNotify and ButtonRelease events if you push for a screen grab.

Screen Grabs

Compiz has a built in interface to handle the grabbing of the cursor and keyboard. The X Server will only give MotionNotify and ButtonRelease events to an application if the application is guaranteed all the input (grabbed). With compiz, you can manage grabbing with the following code:

int grabIndex = pushScreenGrab (CompScreen *s, CursorType, "pluginName");

This will allow you plugin the input. Note that if another plugin has already done this, then you usually don't need to worry about checking if you are pushing a grab when you get input. If you need to check which plugins have a grab, you can use this

Bool grabExists = otherScreenGrabExist (CompScreen *s, "pluginName", "pluginName2", 0);

Provide otherScreenGrabExist a null terminated list and it will return either FALSE if no screengrabs exist by those plugin names or TRUE if they do. Finally, if you want to remove your screengrab, use this:

removeScreenGrab (CompScreen *s, grabIndex, NULL);

grabIndex is the variable given to you by pushScreenGrab earlier, so you might want to save it in a screen structure so you can remove the grab. Remember to remove all pushed grabs otherwise you'll end up with a stale grab, which can require - at worst, a kernel sysrq-k request.

pointerX / pointer Y

You don't need to listen for MotionNotify events if you push a screengrab if all you want is the cusor position to update. To get the current cursor position at any time you have a screengrab, just read the extern int's pointerX and pointerY. They are updated when the core receives MotionNotify events.


One of the longstanding problems that compiz has had was that compiz needed to be guaranteed all input (grabbed) in order for it to receive cursor position updates. This is undesirable if you want to receive cursor position updates, but still want to be able to interact with other applications.

The solution to this problem is to use the functionality the plugins-main plugin mousepoll provides. However, before using mousepoll, be aware that there are some downsides

  • It causes wakeups every few milliseconds and is not good for notebook battery life
  • Pointer updates are not fluent - so you can get choppy updates with your plugin

(!) Only make sure that you register for pointer updates with mousepoll when needed in order to save on wakeups.

To register for pointer updates, you will first need to include the mousepoll headers

#include <compiz-mousepoll.h>

Then you will need to add a MousePollFunc *mpFunc and PositionPollingHandle pollHandle to your display and screen structure respectively.

Additionally, you need a callback function for mousepoll' to call with the updated mouse co-ordinates.

static void
(CompScreen *s,
int x,
int y)

(!) You can save the new co-ordinates to your screen structure.

To request position polling you can do:

pollHandle = (*pluginDisplay->mpFunc->addPositionPolling) (s, positionUpdate);

To remove position polling, do:

(*pluginDisplay->mpFunc->removePositionPolling) (s, pollHandle)

Development/ScreenGrabsInput (last edited 2008-10-11 10:57:20 by CPE-58-161-137-105)