mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
710 lines
18 KiB
C++
710 lines
18 KiB
C++
|
//
|
||
|
// PScreen.cc for pekwm
|
||
|
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
|
||
|
//
|
||
|
// This program is licensed under the GNU GPL.
|
||
|
// See the LICENSE file for more information.
|
||
|
//
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif // HAVE_CONFIG_H
|
||
|
|
||
|
#include <string>
|
||
|
#include <iostream>
|
||
|
#include <cassert>
|
||
|
#include <cstring> // required for memset in FD_ZERO
|
||
|
|
||
|
#ifdef HAVE_LIMITS
|
||
|
#include <limits>
|
||
|
using std::numeric_limits;
|
||
|
#endif // HAVE_LIMITS
|
||
|
|
||
|
extern "C" {
|
||
|
#include <X11/Xlib.h>
|
||
|
#ifdef HAVE_SHAPE
|
||
|
#include <X11/Xutil.h>
|
||
|
#include <X11/extensions/shape.h>
|
||
|
#endif // HAVE_SHAPE
|
||
|
#ifdef HAVE_XRANDR
|
||
|
#include <X11/extensions/Xrandr.h>
|
||
|
#endif // HAVE_XRANDR
|
||
|
#include <X11/keysym.h> // For XK_ entries
|
||
|
#include <sys/select.h>
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
bool xerrors_ignore = false;
|
||
|
#endif // DEBUG
|
||
|
|
||
|
unsigned int xerrors_count = 0;
|
||
|
}
|
||
|
|
||
|
#include "PScreen.hh"
|
||
|
// FIXME: Remove when strut handling is moved away from here.
|
||
|
#include "PWinObj.hh"
|
||
|
#include "ManagerWindows.hh"
|
||
|
|
||
|
using std::cerr;
|
||
|
using std::endl;
|
||
|
using std::vector;
|
||
|
using std::list;
|
||
|
using std::map;
|
||
|
using std::string;
|
||
|
using std::memset; // required for FD_ZERO
|
||
|
|
||
|
const uint PScreen::MODIFIER_TO_MASK[] = {
|
||
|
ShiftMask, LockMask, ControlMask,
|
||
|
Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
|
||
|
};
|
||
|
const uint PScreen::MODIFIER_TO_MASK_NUM = sizeof(PScreen::MODIFIER_TO_MASK) / sizeof(PScreen::MODIFIER_TO_MASK[0]);
|
||
|
|
||
|
PScreen* PScreen::_instance = 0;
|
||
|
|
||
|
|
||
|
extern "C" {
|
||
|
/**
|
||
|
* XError handler, prints error.
|
||
|
*/
|
||
|
static int
|
||
|
handleXError(Display *dpy, XErrorEvent *ev)
|
||
|
{
|
||
|
++xerrors_count;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (xerrors_ignore) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
char error_buf[256];
|
||
|
XGetErrorText(dpy, ev->error_code, error_buf, 256);
|
||
|
cerr << "XError: " << error_buf << " id: " << ev->resourceid << endl;
|
||
|
#endif // DEBUG
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief PScreen::Visual constructor.
|
||
|
//! @param x_visual X Visual to wrap.
|
||
|
PScreen::PVisual::PVisual(Visual *x_visual) : _x_visual(x_visual),
|
||
|
_r_shift(0), _r_prec(0),
|
||
|
_g_shift(0), _g_prec(0),
|
||
|
_b_shift(0), _b_prec(0)
|
||
|
{
|
||
|
getShiftPrecFromMask(_x_visual->red_mask, _r_shift, _r_prec);
|
||
|
getShiftPrecFromMask(_x_visual->green_mask, _g_shift, _g_prec);
|
||
|
getShiftPrecFromMask(_x_visual->blue_mask, _b_shift, _b_prec);
|
||
|
}
|
||
|
|
||
|
//! @brief PScreen::Visual destructor.
|
||
|
PScreen::PVisual::~PVisual(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//! @brief Gets shift and prec from mask.
|
||
|
//! @param mask red,green,blue mask of Visual.
|
||
|
//! @param shift Set to the shift of mask.
|
||
|
//! @param prec Set to the prec of mask.
|
||
|
void
|
||
|
PScreen::PVisual::getShiftPrecFromMask(ulong mask, int &shift, int &prec)
|
||
|
{
|
||
|
for (shift = 0; ! (mask&0x1); ++shift) {
|
||
|
mask >>= 1;
|
||
|
}
|
||
|
|
||
|
for (prec = 0; (mask&0x1); ++prec) {
|
||
|
mask >>= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief PScreen constructor
|
||
|
PScreen::PScreen(Display *dpy, bool honour_randr)
|
||
|
: _honour_randr(honour_randr), _fd(-1),
|
||
|
_screen(-1), _depth(-1),
|
||
|
_root(None), _visual(0), _colormap(None),
|
||
|
_modifier_map(0),
|
||
|
_has_extension_shape(false), _event_shape(-1),
|
||
|
_has_extension_xinerama(false),
|
||
|
_has_extension_xrandr(false), _event_xrandr(-1),
|
||
|
_server_grabs(0), _last_event_time(0), _last_click_id(None)
|
||
|
{
|
||
|
if (_instance) {
|
||
|
throw string("PScreen, trying to create multiple instances");
|
||
|
}
|
||
|
_instance = this;
|
||
|
|
||
|
XSetErrorHandler(handleXError);
|
||
|
|
||
|
_dpy = dpy;
|
||
|
|
||
|
XGrabServer(_dpy);
|
||
|
|
||
|
_fd = ConnectionNumber(dpy);
|
||
|
_screen = DefaultScreen(_dpy);
|
||
|
_root = RootWindow(_dpy, _screen);
|
||
|
|
||
|
_depth = DefaultDepth(_dpy, _screen);
|
||
|
_visual = new PScreen::PVisual(DefaultVisual(_dpy, _screen));
|
||
|
_colormap = DefaultColormap(_dpy, _screen);
|
||
|
_modifier_map = XGetModifierMapping(_dpy);
|
||
|
|
||
|
_screen_gm.width = WidthOfScreen(ScreenOfDisplay(_dpy, _screen));
|
||
|
_screen_gm.height = HeightOfScreen(ScreenOfDisplay(_dpy, _screen));
|
||
|
|
||
|
#ifdef HAVE_SHAPE
|
||
|
{
|
||
|
int dummy_error;
|
||
|
_has_extension_shape = XShapeQueryExtension(_dpy, &_event_shape, &dummy_error);
|
||
|
}
|
||
|
#endif // HAVE_SHAPE
|
||
|
|
||
|
#ifdef HAVE_XRANDR
|
||
|
{
|
||
|
int dummy_error;
|
||
|
_has_extension_xrandr = XRRQueryExtension(_dpy, &_event_xrandr, &dummy_error);
|
||
|
}
|
||
|
#endif // HAVE_XRANDR
|
||
|
|
||
|
// Now screen geometry has been read and extensions have been
|
||
|
// looked for, read head information.
|
||
|
initHeads();
|
||
|
|
||
|
// initialize array values
|
||
|
for (uint i = 0; i < (BUTTON_NO - 1); ++i) {
|
||
|
_last_click_time[i] = 0;
|
||
|
}
|
||
|
|
||
|
// Figure out what keys the Num and Scroll Locks are
|
||
|
setLockKeys();
|
||
|
|
||
|
XSync(_dpy, false);
|
||
|
XUngrabServer(_dpy);
|
||
|
}
|
||
|
|
||
|
//! @brief PScreen destructor
|
||
|
PScreen::~PScreen(void) {
|
||
|
delete _visual;
|
||
|
|
||
|
if (_modifier_map) {
|
||
|
XFreeModifiermap(_modifier_map);
|
||
|
}
|
||
|
|
||
|
_instance = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Figure out what keys the Num and Scroll Locks are
|
||
|
*/
|
||
|
void
|
||
|
PScreen::setLockKeys(void)
|
||
|
{
|
||
|
_num_lock = getMaskFromKeycode(XKeysymToKeycode(_dpy, XK_Num_Lock));
|
||
|
_scroll_lock = getMaskFromKeycode(XKeysymToKeycode(_dpy, XK_Scroll_Lock));
|
||
|
}
|
||
|
|
||
|
//! @brief Get next event using select to avoid signal blocking
|
||
|
//! @param ev Event to fill in.
|
||
|
//! @return true if event was fetched, else false.
|
||
|
bool
|
||
|
PScreen::getNextEvent(XEvent &ev)
|
||
|
{
|
||
|
if (XPending(_dpy) > 0) {
|
||
|
XNextEvent(_dpy, &ev);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int ret;
|
||
|
fd_set rfds;
|
||
|
|
||
|
XFlush(_dpy);
|
||
|
|
||
|
FD_ZERO(&rfds);
|
||
|
FD_SET(_fd, &rfds);
|
||
|
|
||
|
ret = select(_fd + 1, &rfds, 0, 0, 0);
|
||
|
if (ret > 0) {
|
||
|
XNextEvent(_dpy, &ev);
|
||
|
}
|
||
|
|
||
|
return ret > 0;
|
||
|
}
|
||
|
|
||
|
//! @brief Grabs the server, counting number of grabs
|
||
|
bool
|
||
|
PScreen::grabServer(void)
|
||
|
{
|
||
|
if (_server_grabs == 0) {
|
||
|
XGrabServer(_dpy);
|
||
|
}
|
||
|
|
||
|
++_server_grabs;
|
||
|
return (_server_grabs == 1); // was actually grabbed
|
||
|
}
|
||
|
|
||
|
//! @brief Ungrabs the server, counting number of grabs
|
||
|
bool
|
||
|
PScreen::ungrabServer(bool sync)
|
||
|
{
|
||
|
if (_server_grabs > 0) {
|
||
|
--_server_grabs;
|
||
|
|
||
|
if (_server_grabs == 0) { // no more grabs left
|
||
|
if (sync) {
|
||
|
XSync(_dpy, false);
|
||
|
}
|
||
|
XUngrabServer(_dpy);
|
||
|
}
|
||
|
}
|
||
|
return (_server_grabs == 0); // is actually ungrabbed
|
||
|
}
|
||
|
|
||
|
//! @brief Grabs the keyboard
|
||
|
bool
|
||
|
PScreen::grabKeyboard(Window win)
|
||
|
{
|
||
|
if (XGrabKeyboard(_dpy, win, false, GrabModeAsync, GrabModeAsync,
|
||
|
CurrentTime) == GrabSuccess) {
|
||
|
return true;
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": "
|
||
|
<< "PScreen(" << this << ")::grabKeyboard(" << win << ")" << endl
|
||
|
<< " *** unable to grab keyboard." << endl;
|
||
|
#endif // DEBUG
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief Ungrabs the keyboard
|
||
|
bool
|
||
|
PScreen::ungrabKeyboard(void)
|
||
|
{
|
||
|
XUngrabKeyboard(_dpy, CurrentTime);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! @brief Grabs the pointer
|
||
|
bool
|
||
|
PScreen::grabPointer(Window win, uint event_mask, Cursor cursor)
|
||
|
{
|
||
|
if (XGrabPointer(_dpy, win, false, event_mask, GrabModeAsync, GrabModeAsync,
|
||
|
None, cursor, CurrentTime) == GrabSuccess) {
|
||
|
return true;
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": "
|
||
|
<< "PScreen(" << this << ")::grabPointer(" << win << ","
|
||
|
<< event_mask << "," << cursor << ")" << endl
|
||
|
<< " *** unable to grab pointer." << endl;
|
||
|
#endif // DEBUG
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief Ungrabs the pointer
|
||
|
bool
|
||
|
PScreen::ungrabPointer(void)
|
||
|
{
|
||
|
XUngrabPointer(_dpy, CurrentTime);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! @brief Refetches the root-window size.
|
||
|
void
|
||
|
PScreen::updateGeometry(uint width, uint height)
|
||
|
{
|
||
|
#ifdef HAVE_XRANDR
|
||
|
if (! _honour_randr || ! _has_extension_xrandr) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// The screen has changed geometry in some way. To handle this the
|
||
|
// head information is read once again, the root window is re sized
|
||
|
// and strut information is updated.
|
||
|
initHeads();
|
||
|
|
||
|
_screen_gm.width = width;
|
||
|
_screen_gm.height = height;
|
||
|
PWinObj::getRootPWinObj()->resize(width, height);
|
||
|
|
||
|
updateStrut();
|
||
|
#endif // HAVE_XRANDR
|
||
|
}
|
||
|
|
||
|
//! @brief Searches for the head closest to the coordinates x,y.
|
||
|
//! @return The nearest head. Head numbers are indexed from 0.
|
||
|
uint
|
||
|
PScreen::getNearestHead(int x, int y)
|
||
|
{
|
||
|
if(_heads.size() > 1) {
|
||
|
// set distance to the highest uint value
|
||
|
#ifdef HAVE_LIMITS
|
||
|
uint min_distance = numeric_limits<uint>::max();
|
||
|
#else //! HAVE_LIMITS
|
||
|
uint min_distance = ~0;
|
||
|
#endif // HAVE_LIMITS
|
||
|
uint nearest_head = 0;
|
||
|
|
||
|
uint distance;
|
||
|
int head_t, head_b, head_l, head_r;
|
||
|
for(uint head = 0; head < _heads.size(); ++head) {
|
||
|
head_t = _heads[head].y;
|
||
|
head_b = _heads[head].y + _heads[head].height;
|
||
|
head_l = _heads[head].x;
|
||
|
head_r = _heads[head].x + _heads[head].width;
|
||
|
|
||
|
if(x > head_r) {
|
||
|
if(y < head_t) {
|
||
|
// above and right of the head
|
||
|
distance = calcDistance(x, y, head_r, head_t);
|
||
|
} else if(y > head_b) {
|
||
|
// below and right of the head
|
||
|
distance = calcDistance(x, y, head_r, head_b);
|
||
|
} else {
|
||
|
// right of the head
|
||
|
distance = calcDistance(x, head_r);
|
||
|
}
|
||
|
} else if(x < head_l) {
|
||
|
if(y < head_t) {
|
||
|
// above and left of the head
|
||
|
distance = calcDistance(x, y, head_l, head_t);
|
||
|
} else if(y > head_b) {
|
||
|
// below and left of the head
|
||
|
distance = calcDistance(x, y, head_l, head_b);
|
||
|
} else {
|
||
|
// left of the head
|
||
|
distance = calcDistance(x, head_l);
|
||
|
}
|
||
|
} else {
|
||
|
if(y < head_t) {
|
||
|
// above the head
|
||
|
distance = calcDistance(y, head_t);
|
||
|
} else if(y > head_b) {
|
||
|
// below the head
|
||
|
distance = calcDistance(y, head_b);
|
||
|
} else {
|
||
|
// on the head
|
||
|
return head;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": PScreen::getNearestHead( " << x << "," << y << ") "
|
||
|
<< "head boundaries " << head_t << "," << head_b << "," << head_l << "," << head_r << " "
|
||
|
<< "distance " << distance << " min_distance " << min_distance << endl;
|
||
|
#endif // DEBUG
|
||
|
|
||
|
if(distance < min_distance) {
|
||
|
min_distance = distance;
|
||
|
nearest_head = head;
|
||
|
}
|
||
|
}
|
||
|
return nearest_head;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief Searches for the head that the pointer currently is on.
|
||
|
//! @return Active head number
|
||
|
uint
|
||
|
PScreen::getCurrHead(void)
|
||
|
{
|
||
|
uint head = 0;
|
||
|
|
||
|
if (_heads.size() > 1) {
|
||
|
int x = 0, y = 0;
|
||
|
getMousePosition(x, y);
|
||
|
head = getNearestHead(x, y);
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": PScreen::getCurrHead() got head "
|
||
|
<< head << " from mouse position " << x << "," << y << endl;
|
||
|
#endif // DEBUG
|
||
|
}
|
||
|
|
||
|
return head;
|
||
|
}
|
||
|
|
||
|
//! @brief Fills head_info with info about head nr head
|
||
|
//! @param head Head number to examine
|
||
|
//! @param head_info Returning info about the head
|
||
|
//! @return true if xinerama is off or head exists.
|
||
|
bool
|
||
|
PScreen::getHeadInfo(uint head, Geometry &head_info)
|
||
|
{
|
||
|
if (head < _heads.size()) {
|
||
|
head_info.x = _heads[head].x;
|
||
|
head_info.y = _heads[head].y;
|
||
|
head_info.width = _heads[head].width;
|
||
|
head_info.height = _heads[head].height;
|
||
|
return true;
|
||
|
} else {
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": Head: " << head << " doesn't exist!" << endl;
|
||
|
#endif // DEBUG
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as getHeadInfo but returns Geometry instead of filling it in.
|
||
|
*/
|
||
|
Geometry
|
||
|
PScreen::getHeadGeometry(uint head)
|
||
|
{
|
||
|
Geometry gm(_screen_gm);
|
||
|
getHeadInfo(head, gm);
|
||
|
return gm;
|
||
|
}
|
||
|
|
||
|
//! @brief Fill information about head and the strut.
|
||
|
void
|
||
|
PScreen::getHeadInfoWithEdge(uint num, Geometry &head)
|
||
|
{
|
||
|
if (! getHeadInfo(num, head)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int strut_val;
|
||
|
Strut strut(_heads[num].strut); // Convenience
|
||
|
|
||
|
// Remove the strut area from the head info
|
||
|
strut_val = (head.x == 0) ? std::max(_strut.left, strut.left) : strut.left;
|
||
|
head.x += strut_val;
|
||
|
head.width -= strut_val;
|
||
|
|
||
|
strut_val = ((head.x + head.width) == _screen_gm.width) ? std::max(_strut.right, strut.right) : strut.right;
|
||
|
head.width -= strut_val;
|
||
|
|
||
|
strut_val = (head.y == 0) ? std::max(_strut.top, strut.top) : strut.top;
|
||
|
head.y += strut_val;
|
||
|
head.height -= strut_val;
|
||
|
|
||
|
strut_val = (head.y + head.height == _screen_gm.height) ? std::max(_strut.bottom, strut.bottom) : strut.bottom;
|
||
|
head.height -= strut_val;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
PScreen::getMousePosition(int &x, int &y)
|
||
|
{
|
||
|
Window d_root, d_win;
|
||
|
int win_x, win_y;
|
||
|
uint mask;
|
||
|
|
||
|
XQueryPointer(_dpy, _root, &d_root, &d_win, &x, &y, &win_x, &win_y, &mask);
|
||
|
}
|
||
|
|
||
|
uint
|
||
|
PScreen::getButtonFromState(uint state)
|
||
|
{
|
||
|
uint button = 0;
|
||
|
|
||
|
if (state&Button1Mask)
|
||
|
button = BUTTON1;
|
||
|
else if (state&Button2Mask)
|
||
|
button = BUTTON2;
|
||
|
else if (state&Button3Mask)
|
||
|
button = BUTTON3;
|
||
|
else if (state&Button4Mask)
|
||
|
button = BUTTON4;
|
||
|
else if (state&Button5Mask)
|
||
|
button = BUTTON5;
|
||
|
|
||
|
return button;
|
||
|
}
|
||
|
|
||
|
//! @brief Adds a strut to the strut list, updating max strut sizes
|
||
|
void
|
||
|
PScreen::addStrut(Strut *strut)
|
||
|
{
|
||
|
assert(strut);
|
||
|
_strut_list.push_back(strut);
|
||
|
|
||
|
updateStrut();
|
||
|
}
|
||
|
|
||
|
//! @brief Removes a strut from the strut list
|
||
|
void
|
||
|
PScreen::removeStrut(Strut *strut)
|
||
|
{
|
||
|
assert(strut);
|
||
|
_strut_list.remove(strut);
|
||
|
|
||
|
updateStrut();
|
||
|
}
|
||
|
|
||
|
//! @brief Updates strut max size.
|
||
|
void
|
||
|
PScreen::updateStrut(void)
|
||
|
{
|
||
|
// Reset strut data.
|
||
|
_strut.left = 0;
|
||
|
_strut.right = 0;
|
||
|
_strut.top = 0;
|
||
|
_strut.bottom = 0;
|
||
|
|
||
|
for (vector<Head>::iterator it(_heads.begin()); it != _heads.end(); ++it) {
|
||
|
it->strut.left = 0;
|
||
|
it->strut.right = 0;
|
||
|
it->strut.top = 0;
|
||
|
it->strut.bottom = 0;
|
||
|
}
|
||
|
|
||
|
Strut *strut;
|
||
|
for(list<Strut*>::iterator it(_strut_list.begin()); it != _strut_list.end(); ++it) {
|
||
|
if ((*it)->head < 0) {
|
||
|
strut = &_strut;
|
||
|
} else if (static_cast<uint>((*it)->head) < _heads.size()) {
|
||
|
strut = &(_heads[(*it)->head].strut);
|
||
|
} else {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (strut->left < (*it)->left) {
|
||
|
strut->left = (*it)->left;
|
||
|
}
|
||
|
if (strut->right < (*it)->right) {
|
||
|
strut->right = (*it)->right;
|
||
|
}
|
||
|
if (strut->top < (*it)->top) {
|
||
|
strut->top = (*it)->top;
|
||
|
}
|
||
|
if (strut->bottom < (*it)->bottom) {
|
||
|
strut->bottom = (*it)->bottom;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update hints on the root window
|
||
|
Geometry workarea(_strut.left, _strut.top,
|
||
|
_screen_gm.width - _strut.left - _strut.right, _screen_gm.height - _strut.top - _strut.bottom);
|
||
|
|
||
|
static_cast<RootWO*>(PWinObj::getRootPWinObj())->setEwmhWorkarea(workarea);
|
||
|
}
|
||
|
|
||
|
//! @brief Initialize head information
|
||
|
void
|
||
|
PScreen::initHeads(void)
|
||
|
{
|
||
|
_heads.clear();
|
||
|
|
||
|
// Read head information, randr has priority over xinerama then
|
||
|
// comes ordinary X11 information.
|
||
|
|
||
|
initHeadsRandr();
|
||
|
if (! _heads.size()) {
|
||
|
initHeadsXinerama();
|
||
|
|
||
|
if (! _heads.size()) {
|
||
|
_heads.push_back(Head(0, 0, _screen_gm.width, _screen_gm.height));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief Initialize head information from Xinerama
|
||
|
void
|
||
|
PScreen::initHeadsXinerama(void)
|
||
|
{
|
||
|
#ifdef HAVE_XINERAMA
|
||
|
// Check if there are heads already initialized from example Randr
|
||
|
if (! XineramaIsActive(_dpy)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int num_heads = 0;
|
||
|
XineramaScreenInfo *infos = XineramaQueryScreens(_dpy, &num_heads);
|
||
|
|
||
|
for (int i = 0; i < num_heads; ++i) {
|
||
|
_heads.push_back(Head(infos[i].x_org, infos[i].y_org, infos[i].width, infos[i].height));
|
||
|
}
|
||
|
|
||
|
XFree(infos);
|
||
|
#endif // HAVE_XINERAMA
|
||
|
}
|
||
|
|
||
|
//! @brief Initialize head information from RandR
|
||
|
void
|
||
|
PScreen::initHeadsRandr(void)
|
||
|
{
|
||
|
#ifdef HAVE_XRANDR
|
||
|
if (! _honour_randr || ! _has_extension_xrandr) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
XRRScreenResources *resources = XRRGetScreenResources(_dpy, _root);
|
||
|
if (! resources) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < resources->noutput; ++i) {
|
||
|
XRROutputInfo *output = XRRGetOutputInfo(_dpy, resources, resources->outputs[i]);
|
||
|
|
||
|
if (output->crtc) {
|
||
|
XRRCrtcInfo *crtc = XRRGetCrtcInfo(_dpy, resources, output->crtc);
|
||
|
|
||
|
_heads.push_back(Head(crtc->x, crtc->y, crtc->width, crtc->height));
|
||
|
#ifdef DEBUG
|
||
|
cerr << __FILE__ << "@" << __LINE__ << ": PScreen::initHeadsRandr() added head "
|
||
|
<< crtc->x << "," << crtc->y << "," << crtc->width << "," << crtc->height << endl;
|
||
|
#endif // DEBUG
|
||
|
|
||
|
XRRFreeCrtcInfo (crtc);
|
||
|
}
|
||
|
|
||
|
XRRFreeOutputInfo (output);
|
||
|
}
|
||
|
|
||
|
XRRFreeScreenResources (resources);
|
||
|
#endif // HAVE_XRANDR
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Lookup mask from keycode.
|
||
|
*
|
||
|
* @param keycode KeyCode to lookup.
|
||
|
* @return Mask for keycode, 0 if something fails.
|
||
|
*/
|
||
|
uint
|
||
|
PScreen::getMaskFromKeycode(KeyCode keycode)
|
||
|
{
|
||
|
// Make sure modifier mappings were looked up ok
|
||
|
if (! _modifier_map || _modifier_map->max_keypermod < 1) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// .h files states that modifiermap is an 8 * max_keypermod array.
|
||
|
int max_info = _modifier_map->max_keypermod * 8;
|
||
|
for (int i = 0; i < max_info; ++i) {
|
||
|
if (_modifier_map->modifiermap[i] == keycode) {
|
||
|
return MODIFIER_TO_MASK[i / _modifier_map->max_keypermod];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Figure out what key you can press to generate mask
|
||
|
*
|
||
|
* @param mask Modifier mask to get keycode for.
|
||
|
* @return KeyCode for mask, 0 if failing.
|
||
|
*/
|
||
|
KeyCode
|
||
|
PScreen::getKeycodeFromMask(uint mask)
|
||
|
{
|
||
|
// Make sure modifier mappings were looked up ok
|
||
|
if (! _modifier_map || _modifier_map->max_keypermod < 1) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < 8; ++i) {
|
||
|
if (MODIFIER_TO_MASK[i] == mask) {
|
||
|
// FIXME: Is iteration over the range required?
|
||
|
return _modifier_map->modifiermap[i * _modifier_map->max_keypermod];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
Display *PScreen::_dpy;
|
||
|
uint PScreen::_num_lock = 0;
|
||
|
uint PScreen::_scroll_lock = 0;
|