Logo Search packages:      
Sourcecode: beryl-core version File versions

screen.c

/*
 * Copyright © 2005 Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#ifdef HAVE_CONFIG_H
#  include "../config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <dlfcn.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/shape.h>
#include <X11/cursorfont.h>

#include <X11/extensions/Xinerama.h>

#include <beryl.h>
#include <beryl-private.h>

#ifndef NUM_OPTIONS
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
#endif

#define OPACITY_STEP_DEFAULT  10
#define SATURATION_STEP_DEFAULT  5
#define BRIGHTNESS_STEP_DEFAULT  5
#define DEFAULT_REFRESH_RATE  60
#define SCREEN_SIZE_DEFAULT    4
#define SCREEN_VSIZE_DEFAULT   1
#define NUMBER_OF_DESKTOPS_DEFAULT 1

void compScreenInitOptions(CompScreen * screen);

static void updateOutputDevices(CompScreen * screen);

static inline Bool isClientListWindow(CompWindow * w) __attribute__((always_inline));
static inline void countClientListWindow(CompWindow * w, void *closure) __attribute__((always_inline));

static int reallocScreenPrivate(int size, void *closure)
{
      CompDisplay *d = (CompDisplay *) closure;
      CompScreen *s;
      void *privates;

      for (s = d->screens; s; s = s->next)
      {
            privates = realloc(s->privates, size * sizeof(CompPrivate));
            if (!privates)
                  return FALSE;

            s->privates = (CompPrivate *) privates;
      }

      return TRUE;
}

int allocateScreenPrivateIndex(CompDisplay * display)
{
      return allocatePrivateIndex(&display->screenPrivateLen,
                                                &display->screenPrivateIndices,
                                                reallocScreenPrivate, (void *)display);
}

void freeScreenPrivateIndex(CompDisplay * display, int index)
{
      freePrivateIndex(display->screenPrivateLen,
                               display->screenPrivateIndices, index);
}

static Bool
desktopHintEqual(CompScreen * s,
                         unsigned long *data, int size, int offset, int hintSize)
{
      if (size != s->desktopHintSize)
            return FALSE;

      if (memcmp(data + offset,
                     s->desktopHintData + offset,
                     hintSize * sizeof(unsigned long)) == 0)
            return TRUE;

      return FALSE;
}


/* Sets the screen projectionStyle in a mode signaling that a
 * recalculation of the projection matrix should take place.
 */
static void projectionRecalc(CompScreen * s)
{
      switch (s->projectionStyle)
      {
      case COMP_PERSPECTIVE_LOCAL:
      case COMP_PERSPECTIVE_LOCAL_REAL:
            s->projectionStyle = COMP_PERSPECTIVE_LOCAL;
            break;
      case COMP_PERSPECTIVE_GLOBAL:
      case COMP_PERSPECTIVE_GLOBAL_REAL:
            s->projectionStyle = COMP_PERSPECTIVE_GLOBAL;
            break;
      default:
            s->projectionStyle = COMP_PERSPECTIVE_LOCAL;
            break;
      }
}

static void setDesktopHints(CompScreen * s)
{
      CompDisplay *d = s->display;
      unsigned long *data;
      int size, offset, hintSize, i;

      size = s->nDesktop * 2 + s->nDesktop * 2 + s->nDesktop * 4 + 1;

      data = malloc(sizeof(unsigned long) * size);
      if (!data)
            return;

      offset = 0;
      hintSize = s->nDesktop * 2;

      for (i = 0; i < s->nDesktop; i++)
      {
            data[offset + i * 2 + 0] = s->x * s->width;
            data[offset + i * 2 + 1] = s->y * s->height;
      }

      if (!desktopHintEqual(s, data, size, offset, hintSize))
            XChangeProperty(d->display, s->root,
                                    d->desktopViewportAtom, XA_CARDINAL, 32,
                                    PropModeReplace,
                                    (unsigned char *)&data[offset], hintSize);

      offset += hintSize;

      for (i = 0; i < s->nDesktop; i++)
      {
            data[offset + i * 2 + 0] = s->width * s->hsize;
            data[offset + i * 2 + 1] = s->height * s->vsize;
      }

      if (!desktopHintEqual(s, data, size, offset, hintSize))
            XChangeProperty(d->display, s->root,
                                    d->desktopGeometryAtom, XA_CARDINAL, 32,
                                    PropModeReplace,
                                    (unsigned char *)&data[offset], hintSize);

      offset += hintSize;
      hintSize = s->nDesktop * 4;

      for (i = 0; i < s->nDesktop; i++)
      {
            data[offset + i * 4 + 0] = s->workArea.x;
            data[offset + i * 4 + 1] = s->workArea.y;
            data[offset + i * 4 + 2] = s->workArea.width;
            data[offset + i * 4 + 3] = s->workArea.height;
      }

      if (!desktopHintEqual(s, data, size, offset, hintSize))
            XChangeProperty(d->display, s->root, d->workareaAtom,
                                    XA_CARDINAL, 32, PropModeReplace,
                                    (unsigned char *)&data[offset], hintSize);

      offset += hintSize;

      data[offset] = s->nDesktop;
      hintSize = 1;

      if (!desktopHintEqual(s, data, size, offset, hintSize))
            XChangeProperty(d->display, s->root,
                                    d->numberOfDesktopsAtom, XA_CARDINAL, 32,
                                    PropModeReplace,
                                    (unsigned char *)&data[offset], hintSize);

      if (s->desktopHintData)
            free(s->desktopHintData);

      s->desktopHintData = data;
      s->desktopHintSize = size;
}

static void setVirtualScreenSize(CompScreen * screen, int hsize, int vsize)
{
      screen->hsize = hsize;
      screen->vsize = vsize;

      setDesktopHints(screen);
      (*screen->outputChangeNotify) (screen);
}

static void setRefreshRate(CompScreen * screen,int rate)
{
      screen->redrawTime = 1000 / rate;
      screen->optimalRedrawTime = screen->redrawTime;

}

static Bool
setScreenOption(CompScreen * screen, char *name, CompOptionValue * value)
{
      CompOption *o;
      int index;
      CompDisplay *d = screen->display;
      o = compFindOption(screen->opt, NUM_OPTIONS(screen), name, &index);
      if (!o)
            return FALSE;
        beryl_settings_context_comp_set_option_value(d->context,NULL,name,TRUE,value);
      beryl_settings_context_write(d->context);
      switch (index)
      {
      case COMP_SCREEN_OPTION_DETECT_REFRESH_RATE:
            if (compSetBoolOption(o, value))
            {
                  detectRefreshRateOfScreen(screen);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_LIGHTING:
      case COMP_SCREEN_OPTION_LEGACY_MAXIMIZE_FIX:
      case COMP_SCREEN_OPTION_UNREDIRECT_FS:
            //case COMP_SCREEN_OPTION_SLOWNESS_FIX:
      case COMP_SCREEN_OPTION_SYNC_TO_VBLANK:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      case COMP_SCREEN_OPTION_CUSTOM_OUTPUT_GRID:
            if (compSetBoolOption(o, value))
            {
                  updateOutputDevices(screen);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_OUTPUT_GRID_ROWS:
      case COMP_SCREEN_OPTION_OUTPUT_GRID_COLS:
            if (compSetIntOption(o, value))
            {
                  if (screen->opt[COMP_SCREEN_OPTION_CUSTOM_OUTPUT_GRID].value.b)
                        updateOutputDevices(screen);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_REFRESH_RATE:

            if (compSetIntOption(o, value))
            {
                  detectRefreshRateOfScreen(screen);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_HSIZE:
            if (compSetIntOption(o, value))
            {
                  CompOption *vsize = compFindOption(screen->opt,
                                                                     NUM_OPTIONS(screen), "vsize",
                                                                     NULL);

                  if (o->value.i * screen->width > MAXSHORT)
                        return FALSE;

                  setVirtualScreenSize(screen, o->value.i, vsize->value.i);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_VSIZE:
            if (compSetIntOption(o, value))
            {
                  CompOption *hsize = compFindOption(screen->opt,
                                                                     NUM_OPTIONS(screen), "size",
                                                                     NULL);

                  if (o->value.i * screen->height > MAXSHORT)
                        return FALSE;

                  setVirtualScreenSize(screen, hsize->value.i, o->value.i);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_NUMBER_OF_DESKTOPS:
            if (compSetIntOption(o, value) || (o->value.i != screen->nDesktop))
            {
                  setNumberOfDesktops(screen, o->value.i);
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_OPACITY_STEP:
            if (compSetIntOption(o, value))
            {
                  screen->opacityStep = o->value.i;
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_SATURATION_STEP:
            if (compSetIntOption(o, value))
            {
                  screen->saturationStep = o->value.i;
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_BRIGHTNESS_STEP:
            if (compSetIntOption(o, value))
            {
                  screen->brightnessStep = o->value.i;
                  return TRUE;
            }
            break;
      case COMP_SCREEN_OPTION_DEFAULT_ICON:
            if (compSetStringOption(o, value))
                  return updateDefaultIcon(screen);
      default:
            break;
      }

      return FALSE;
}

static Bool
setScreenOptionForPlugin(CompScreen * screen,
                                     char *plugin, char *name, CompOptionValue * value)
{
      CompPlugin *p;

      p = findActivePlugin(plugin);
      CompDisplay *d = screen->display;

      gboolean retval = FALSE;

      if (p && p->vTable->setScreenOption)
            retval=(*p->vTable->setScreenOption) (screen, name, value);
      if (retval)
      {
            beryl_settings_context_comp_set_option_value(d->context,plugin,name,TRUE,value);
            beryl_settings_context_write(d->context);
      }
      return retval;
}

static void updateStartupFeedback(CompScreen * s)
{
      if (s->startupSequences)
            XDefineCursor(s->display->display, s->root, s->busyCursor);
      else
            XDefineCursor(s->display->display, s->root, s->normalCursor);
}

#define STARTUP_TIMEOUT_DELAY 15000

static Bool startupSequenceTimeout(void *data)
{
      CompScreen *screen = data;
      CompStartupSequence *s;
      struct timeval now, active;
      double elapsed;

      gettimeofday(&now, NULL);

      for (s = screen->startupSequences; s; s = s->next)
      {
            sn_startup_sequence_get_last_active_time(s->sequence,
                                                                         &active.tv_sec,
                                                                         &active.tv_usec);

            elapsed =
                        ((((double)now.tv_sec - active.tv_sec) * 1000000.0 +
                          (now.tv_usec - active.tv_usec))) / 1000.0;

            if (elapsed > STARTUP_TIMEOUT_DELAY)
                  sn_startup_sequence_complete(s->sequence);
      }

      return TRUE;
}

static void addSequence(CompScreen * screen, SnStartupSequence * sequence)
{
      CompStartupSequence *s;

      s = malloc(sizeof(CompStartupSequence));
      if (!s)
            return;

      sn_startup_sequence_ref(sequence);

      s->next = screen->startupSequences;
      s->sequence = sequence;
      s->viewportX = screen->x;
      s->viewportY = screen->y;

      screen->startupSequences = s;

      if (!screen->startupSequenceTimeoutHandle)
            compAddTimeout(1000, startupSequenceTimeout, screen);

      updateStartupFeedback(screen);
}

static void removeSequence(CompScreen * screen, SnStartupSequence * sequence)
{
      CompStartupSequence *s, *p = NULL;

      for (s = screen->startupSequences; s; s = s->next)
      {
            if (s->sequence == sequence)
                  break;

            p = s;
      }

      if (!s)
            return;

      sn_startup_sequence_unref(sequence);

      if (p)
            p->next = s->next;
      else
            screen->startupSequences = NULL;

      free(s);

      if (!screen->startupSequences && screen->startupSequenceTimeoutHandle)
      {
            compRemoveTimeout(screen->startupSequenceTimeoutHandle);
            screen->startupSequenceTimeoutHandle = 0;
      }

      updateStartupFeedback(screen);
}

static void compScreenSnEvent(SnMonitorEvent * event, void *userData)
{
      CompScreen *screen = userData;
      SnStartupSequence *sequence;

      sequence = sn_monitor_event_get_startup_sequence(event);

      switch (sn_monitor_event_get_type(event))
      {
      case SN_MONITOR_EVENT_INITIATED:
            addSequence(screen, sequence);
            break;
      case SN_MONITOR_EVENT_COMPLETED:
            removeSequence(screen, sn_monitor_event_get_startup_sequence(event));
            break;
      case SN_MONITOR_EVENT_CHANGED:
      case SN_MONITOR_EVENT_CANCELED:
            break;
      }
}

static void updateScreenEdges(CompScreen * s)
{
      struct screenEdgeGeometry
      {
            int xw, x0;
            int yh, y0;
            int ww, w0;
            int hh, h0;
      } geometry[SCREEN_EDGE_NUM] = {
            { 0,  0,  0,  2,  0,  2,  1, -4},   /* left */
            { 1, -2,  0,  2,  0,  2,  1, -4},   /* right */
            { 0,  2,  0,  0,  1, -4,  0,  2},   /* top */
            { 0,  2,  1, -2,  1, -4,  0,  2},   /* bottom */
            { 0,  0,  0,  0,  0,  2,  0,  2},   /* top-left */
            { 1, -2,  0,  0,  0,  2,  0,  2},   /* top-right */
            { 0,  0,  1, -2,  0,  2,  0,  2},   /* bottom-left */
            { 1, -2,  1, -2,  0,  2,  0,  2}    /* bottom-right */
      };
      int i;

      for (i = 0; i < SCREEN_EDGE_NUM; i++)
      {
            if (s->screenEdge[i].id)
                  XMoveResizeWindow(s->display->display,
                                            s->screenEdge[i].id,
                                            geometry[i].xw * s->width +
                                            geometry[i].x0,
                                            geometry[i].yh * s->height +
                                            geometry[i].y0,
                                            geometry[i].ww * s->width +
                                            geometry[i].w0,
                                            geometry[i].hh * s->height + geometry[i].h0);
      }
}

static void updateOutputDevices(CompScreen * s)
{
      CompOutput *output;
      int nOutput, i;

      projectionRecalc(s);

      if (s->opt[COMP_SCREEN_OPTION_CUSTOM_OUTPUT_GRID].value.b)
      {
            int rows = s->opt[COMP_SCREEN_OPTION_OUTPUT_GRID_ROWS].value.i;
            int cols = s->opt[COMP_SCREEN_OPTION_OUTPUT_GRID_COLS].value.i;
            int row, col;

            nOutput = rows * cols;
            output = malloc(sizeof(CompOutput) * nOutput);

            for (i = 0; i < nOutput; i++)
            {
                  output[i].name = malloc(sizeof(char) * 10);
                  if (output[i].name)
                        snprintf(output[i].name, 10, "Output %d", i);

                  row = i % rows;
                  col = i / rows;

                  output[i].region.rects = &output[i].region.extents;
                  output[i].region.numRects = 1;

                  output[i].region.extents.x1 = (s->attrib.width / cols) * col;
                  output[i].region.extents.y1 = (s->attrib.height / rows) * row;
                  output[i].region.extents.x2 =
                              (s->attrib.width / cols) * (col + 1);
                  output[i].region.extents.y2 =
                              (s->attrib.height / rows) * (row + 1);

                  output[i].width = s->attrib.width / cols;
                  output[i].height = s->attrib.height / rows;

                  output[i].workRegion.rects = &output[i].workRegion.extents;
                  output[i].workRegion.numRects = 1;
                  output[i].workRegion.extents.x1 = output[i].region.extents.x1;
                  output[i].workRegion.extents.y1 = output[i].region.extents.y1;
                  output[i].workRegion.extents.x2 = output[i].region.extents.x2;
                  output[i].workRegion.extents.y2 = output[i].region.extents.y2;
            }
      }
      else if (s->display->screenInfo)
      {
            XineramaScreenInfo *screenInfo = s->display->screenInfo;
            int nScreenInfo = s->display->nScreenInfo;

            output = malloc(sizeof(CompOutput) * nScreenInfo);
            if (!output)
                  return;

            for (i = 0; i < nScreenInfo; i++)
            {
                  output[i].name = malloc(sizeof(char) * 10);
                  if (output[i].name)
                        snprintf(output[i].name, 10, "Output %d", i);

                  output[i].region.rects = &output[i].region.extents;
                  output[i].region.numRects = 1;

                  output[i].region.extents.x1 = screenInfo[i].x_org;
                  output[i].region.extents.y1 = screenInfo[i].y_org;
                  output[i].region.extents.x2 = screenInfo[i].x_org +
                              screenInfo[i].width;
                  output[i].region.extents.y2 = screenInfo[i].y_org +
                              screenInfo[i].height;

                  output[i].width = screenInfo[i].width;
                  output[i].height = screenInfo[i].height;

                  output[i].workRegion.rects = &output[i].workRegion.extents;
                  output[i].workRegion.numRects = 1;
                  output[i].workRegion.extents.x1 = output[i].region.extents.x1;
                  output[i].workRegion.extents.x2 = output[i].region.extents.x2;
                  output[i].workRegion.extents.y1 = output[i].region.extents.y1;
                  output[i].workRegion.extents.y2 = output[i].region.extents.y2;
            }

            nOutput = nScreenInfo;
      }
      else
      {
            output = malloc(sizeof(CompOutput));
            if (!output)
                  return;

            output->name = strdup("Output 0");

            output->region.rects = &output->region.extents;
            output->region.numRects = 1;

            output->region.extents.x1 = 0;
            output->region.extents.y1 = 0;
            output->region.extents.x2 = s->attrib.width;
            output->region.extents.y2 = s->attrib.height;

            output->width = s->attrib.width;
            output->height = s->attrib.height;

            output->workRegion.rects = &output->workRegion.extents;
            output->workRegion.numRects = 1;
            output->workRegion.extents.x1 = 0;
            output->workRegion.extents.y1 = 0;
            output->workRegion.extents.x2 = s->attrib.width;
            output->workRegion.extents.y2 = s->attrib.height;

            nOutput = 1;
      }

      if (s->outputDev)
      {
            for (i = 0; i < s->nOutputDev; i++)
                  if (s->outputDev[i].name)
                        free(s->outputDev[i].name);

            free(s->outputDev);
      }

      s->outputDev = output;
      s->nOutputDev = nOutput;

      setDefaultViewport(s);
      damageScreen(s);

      (*s->outputChangeNotify) (s);
}

void setCurrentOutput(CompScreen * s, int outputNum)
{
      if (outputNum >= s->nOutputDev)
            outputNum = 0;

      s->currentOutputDev = outputNum;
}

static void reshape(CompScreen * s, int w, int h)
{
#if XCOMPOSITE_MINOR >= 3 || XCOMPOSITE_MAJOR > 0
      if (useCow)
            XMoveResizeWindow (s->display->display, s->overlay, 0, 0, w, h);
#endif

      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glDepthRange(0, 1);
      glViewport(-1, -1, 2, 2);
      glRasterPos2f(0, 0);

      s->rasterX = s->rasterY = 0;

      glViewport(0, 0, w, h);

      s->region.rects = &s->region.extents;
      s->region.numRects = 1;
      s->region.extents.x1 = 0;
      s->region.extents.y1 = 0;
      s->region.extents.x2 = w;
      s->region.extents.y2 = h;
      s->region.size = 1;

      s->width = w;
      s->height = h;

      updateOutputDevices(s);

      setCurrentOutput(s, s->currentOutputDev);

      updateScreenEdges(s);
      updateWorkareaForScreen(s);
}

void configureScreen(CompScreen * s, XConfigureEvent * ce)
{
      if (s->attrib.width != ce->width || s->attrib.height != ce->height)
      {
            s->attrib.width = ce->width;
            s->attrib.height = ce->height;

            reshape(s, ce->width, ce->height);

            damageScreen(s);
      }
}

static FuncPtr getProcAddress(CompScreen * s, const char *name)
{
      static void *dlhand = NULL;
      FuncPtr funcPtr = NULL;

      if (s->getProcAddress)
            funcPtr = s->getProcAddress((GLubyte *) name);

      if (!funcPtr)
      {
            if (!dlhand)
                  dlhand = dlopen(NULL, RTLD_LAZY);

            if (dlhand)
            {
                  dlerror();
                  funcPtr = (FuncPtr) dlsym(dlhand, name);
                  if (dlerror() != NULL)
                        funcPtr = NULL;
            }
      }

      return funcPtr;
}

void updateScreenBackground(CompScreen * screen, CompTexture * texture)
{
      Display *dpy = screen->display->display;
      Atom pixmapAtom, actualType;
      int actualFormat, i, status;
      unsigned int width = 1, height = 1, depth = 0;
      unsigned long nItems;
      unsigned long bytesAfter;
      unsigned char *prop;
      Pixmap pixmap = 0;

      pixmapAtom = XInternAtom(dpy, "PIXMAP", FALSE);

      for (i = 0; pixmap == 0 && i < 2; i++)
      {
            status = XGetWindowProperty(dpy, screen->root,
                                                      screen->display->
                                                      xBackgroundAtom[i], 0, 4,
                                                      FALSE, AnyPropertyType,
                                                      &actualType, &actualFormat,
                                                      &nItems, &bytesAfter, &prop);

            if (status == Success && nItems && prop)
            {
                  if (actualType == pixmapAtom && actualFormat == 32 && nItems == 1)
                  {
                        Pixmap p;

                        memcpy(&p, prop, 4);

                        if (p)
                        {
                              unsigned int ui;
                              int i;
                              Window w;

                              if (XGetGeometry
                                    (dpy, p, &w, &i, &i, &width, &height, &ui, &depth))
                              {
                                    if (depth == screen->attrib.depth)
                                          pixmap = p;
                              }
                        }
                  }

                  XFree(prop);
            }
      }

      if (pixmap)
      {
            if (pixmap == texture->pixmap)
                  return;

            finiTexture(screen, texture);
            initTexture(screen, texture);

            if (!bindPixmapToTexture(screen, texture, pixmap,
                                                 width, height, depth))
            {
                  fprintf(stderr,
                              "%s: Couldn't bind background pixmap 0x%x to "
                              "texture\n", programName, (int)pixmap);
            }
      }
      else
      {
            finiTexture(screen, texture);
            initTexture(screen, texture);
      }

      if (!texture->name)
            readImageToTexture(screen, texture, backgroundImage, &width, &height);

      if (texture->target == GL_TEXTURE_2D)
      {
            glBindTexture(texture->target, texture->name);
            glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glBindTexture(texture->target, 0);
      }
}

void detectRefreshRateOfScreen(CompScreen * s)
{
      if (s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b)
      {
            XRRScreenConfiguration *config;

            config = XRRGetScreenInfo(s->display->display, s->root);
            setRefreshRate(s,(int)XRRConfigCurrentRate(config));

            XRRFreeScreenConfigInfo(config);
      }
      else
            setRefreshRate(s,
                        s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].value.i);
}

#define MYNAME "beryl"

static void setSupportingWmCheck(CompScreen * s)
{
      CompDisplay *d = s->display;

      XChangeProperty(d->display, s->grabWindow,
                              d->supportingWmCheckAtom, XA_WINDOW, 32,
                              PropModeReplace, (unsigned char *)&s->grabWindow, 1);

      XChangeProperty(d->display, s->grabWindow, d->wmNameAtom,
                              d->utf8StringAtom, 8, PropModeReplace,
                              (unsigned char *)MYNAME, strlen(MYNAME));
      XChangeProperty(d->display, s->grabWindow, d->winStateAtom,
                              XA_ATOM, 32, PropModeReplace,
                              (unsigned char *)&d->winStateSkipTaskbarAtom, 1);
      XChangeProperty(d->display, s->grabWindow, d->winStateAtom,
                              XA_ATOM, 32, PropModeAppend,
                              (unsigned char *)&d->winStateSkipPagerAtom, 1);
      XChangeProperty(d->display, s->grabWindow, d->winStateAtom,
                              XA_ATOM, 32, PropModeAppend,
                              (unsigned char *)&d->winStateHiddenAtom, 1);

      XChangeProperty(d->display, s->root, d->supportingWmCheckAtom,
                              XA_WINDOW, 32, PropModeReplace,
                              (unsigned char *)&s->grabWindow, 1);
}

static void setSupported(CompScreen * s)
{
      CompDisplay *d = s->display;
      Atom data[256];
      int i = 0;

      data[i++] = d->supportedAtom;
      data[i++] = d->supportingWmCheckAtom;

      data[i++] = d->utf8StringAtom;

      data[i++] = d->clientListAtom;
      data[i++] = d->clientListStackingAtom;

      data[i++] = d->winActiveAtom;

      data[i++] = d->desktopViewportAtom;
      data[i++] = d->desktopGeometryAtom;
      data[i++] = d->currentDesktopAtom;
      data[i++] = d->numberOfDesktopsAtom;
      data[i++] = d->showingDesktopAtom;

      data[i++] = d->workareaAtom;

      data[i++] = d->wmNameAtom;
      /*
         data[i++] = d->wmVisibleNameAtom;
       */

      data[i++] = d->wmStrutAtom;
      data[i++] = d->wmStrutPartialAtom;

      /*
         data[i++] = d->wmPidAtom;
       */

      data[i++] = d->wmUserTimeAtom;
      data[i++] = d->frameExtentsAtom;
      data[i++] = d->frameWindowAtom;

      data[i++] = d->winStateModalAtom;
      data[i++] = d->winStateStickyAtom;
      data[i++] = d->winStateMaximizedVertAtom;
      data[i++] = d->winStateMaximizedHorzAtom;
      data[i++] = d->winStateShadedAtom;
      data[i++] = d->winStateSkipTaskbarAtom;
      data[i++] = d->winStateSkipPagerAtom;
      data[i++] = d->winStateHiddenAtom;
      data[i++] = d->winStateFullscreenAtom;
      data[i++] = d->winStateAboveAtom;
      data[i++] = d->winStateBelowAtom;
      data[i++] = d->winStateDemandsAttentionAtom;
      data[i++] = d->winStateNoFocusAtom;

      data[i++] = d->winOpacityAtom;
      data[i++] = d->winBrightnessAtom;

      if (s->canDoSaturated)
      {
            data[i++] = d->winSaturationAtom;
            data[i++] = d->winStateDisplayModalAtom;
      }

      data[i++] = d->wmAllowedActionsAtom;

      data[i++] = d->winActionMoveAtom;
      data[i++] = d->winActionResizeAtom;
      data[i++] = d->winActionStickAtom;
      data[i++] = d->winActionMinimizeAtom;
      data[i++] = d->winActionMaximizeHorzAtom;
      data[i++] = d->winActionMaximizeVertAtom;
      data[i++] = d->winActionFullscreenAtom;
      data[i++] = d->winActionCloseAtom;
      data[i++] = d->winActionShadeAtom;

      data[i++] = d->winTypeAtom;
      data[i++] = d->winTypeDesktopAtom;
      data[i++] = d->winTypeDockAtom;
      data[i++] = d->winTypeToolbarAtom;
      data[i++] = d->winTypeMenuAtom;
      data[i++] = d->winTypeSplashAtom;
      data[i++] = d->winTypeDialogAtom;
      data[i++] = d->winTypeUtilAtom;
      data[i++] = d->winTypeNormalAtom;

      data[i++] = d->wmDeleteWindowAtom;
      data[i++] = d->wmPingAtom;

      data[i++] = d->wmMoveResizeAtom;
      data[i++] = d->moveResizeWindowAtom;
      data[i++] = d->restackWindowAtom;
      data[i++] = d->berylDesktopManaged;

      XChangeProperty(d->display, s->root, d->supportedAtom, XA_ATOM, 32,
                              PropModeReplace, (unsigned char *)data, i);
}

static void getDesktopHints(CompScreen * s)
{
      CompDisplay *d = s->display;
      unsigned long data[2];
      Atom actual;
      int result, format;
      unsigned long n, left;
      unsigned char *propData;

      result = XGetWindowProperty(s->display->display, s->root,
                                                d->berylDesktopManaged, 0L, 1L, FALSE,
                                                XA_CARDINAL, &actual, &format,
                                                &n, &left, &propData);

      if (result == Success && n && propData)
      {
            memcpy(data, propData, sizeof(unsigned long));
            XFree(propData);

            if (data[0] > 0 && data[0] < 0xffffffff)
                  s->berylDesktopManaged = True;
            else
                  s->berylDesktopManaged = False;
      }


      result = XGetWindowProperty(s->display->display, s->root,
                                                d->numberOfDesktopsAtom, 0L, 1L, FALSE,
                                                XA_CARDINAL, &actual, &format,
                                                &n, &left, &propData);

      if (result == Success && n && propData)
      {
            memcpy(data, propData, sizeof(unsigned long));
            XFree(propData);

            if (data[0] > 0 && data[0] < 0xffffffff)
                  s->nDesktop = data[0];
      }

      result = XGetWindowProperty(s->display->display, s->root,
                                                d->desktopViewportAtom, 0L, 2L,
                                                FALSE, XA_CARDINAL, &actual, &format,
                                                &n, &left, &propData);

      if (result == Success && n && propData)
      {
            if (n == 2)
            {
                  memcpy(data, propData, sizeof(unsigned long) * 2);

                  if (data[0] / s->width < s->hsize - 1)
                        s->x = data[0] / s->width;

                  if (data[1] / s->height < s->vsize - 1)
                        s->y = data[1] / s->height;
            }

            XFree(propData);
      }

      result = XGetWindowProperty(s->display->display, s->root,
                                                d->currentDesktopAtom, 0L, 1L, FALSE,
                                                XA_CARDINAL, &actual, &format,
                                                &n, &left, &propData);

      if (result == Success && n && propData)
      {
            memcpy(data, propData, sizeof(unsigned long));
            XFree(propData);

            data[0] = 0;
            if (data[0] < s->nDesktop)
                  s->currentDesktop = data[0];
      }

      result = XGetWindowProperty(s->display->display, s->root,
                                                d->showingDesktopAtom, 0L, 1L, FALSE,
                                                XA_CARDINAL, &actual, &format,
                                                &n, &left, &propData);

      if (result == Success && n && propData)
      {
            memcpy(data, propData, sizeof(unsigned long));
            XFree(propData);

            if (data[0])
                  enterShowDesktopMode(s);
      }

      data[0] = s->currentDesktop;

      XChangeProperty(d->display, s->root, d->currentDesktopAtom,
                              XA_CARDINAL, 32, PropModeReplace,
                              (unsigned char *)data, 1);

      data[0] = s->showingDesktopMask ? TRUE : FALSE;

      XChangeProperty(d->display, s->root, d->showingDesktopAtom,
                              XA_CARDINAL, 32, PropModeReplace,
                              (unsigned char *)data, 1);
}

/*
#if XCOMPOSITE_MINOR >= 3 || XCOMPOSITE_MAJOR > 0
static void makeOutputWindow(CompScreen * s)
{
      Display *dpy = s->display->display;
      XserverRegion region;

      s->overlay = XCompositeGetOverlayWindow(dpy, s->root);
      s->output = s->overlay;

      region = XFixesCreateRegion(dpy, NULL, 0);

      XFixesSetWindowShapeRegion(dpy, s->output, ShapeInput, 0, 0, region);

      XFixesDestroyRegion(dpy, region);
}
#endif
*/

void showOutputWindow (CompScreen *s)
{
#if XCOMPOSITE_MINOR >= 3 || XCOMPOSITE_MAJOR > 0
    if (useCow)
    {
        Display       *dpy = s->display->display;
        XserverRegion region;

        region = XFixesCreateRegion (dpy, NULL, 0);

        XFixesSetWindowShapeRegion (dpy,
                                    s->output,
                                    ShapeBounding,
                                    0, 0, 0);
        XFixesSetWindowShapeRegion (dpy,
                                    s->output,
                                    ShapeInput,
                                    0, 0, region);

        XFixesDestroyRegion (dpy, region);

        damageScreen (s);
    }
#endif
}

void hideOutputWindow (CompScreen *s)
{
#if XCOMPOSITE_MINOR >= 3 || XCOMPOSITE_MAJOR > 0
    if (useCow)
    {
        Display       *dpy = s->display->display;
        XserverRegion region;
        region = XFixesCreateRegion (dpy, NULL, 0);
        XFixesSetWindowShapeRegion (dpy,
                                    s->output,
                                    ShapeBounding,
                                    0, 0, region);

        XFixesDestroyRegion (dpy, region);
    }
#endif
}

static void makeOutputWindow (CompScreen *s)
{
#if XCOMPOSITE_MINOR >= 3 || XCOMPOSITE_MAJOR > 0
    if (useCow)
    {
        s->overlay = XCompositeGetOverlayWindow (s->display->display, s->root);
        s->output  = s->overlay;
    }
    else
        s->output = s->overlay = s->root;

    showOutputWindow (s);
#endif
}

void releaseScreen(CompScreen * s)
{

      while (s->windows)
            removeWindow(s->windows);

      XDestroyRegion(s->damage);
      compFreeScreenOptions(s);
      if (s->defaultIcon)
            free(s->defaultIcon);
      screenFiniPlugins(s);
      free(s->privates);

      XDeleteProperty(s->display->display, s->root,
                  s->display->desktopGeometryAtom);
      XDeleteProperty(s->display->display, s->root,
                  s->display->desktopViewportAtom);

      XFreeCursor(s->display->display, s->invisibleCursor);
      XFreeCursor(s->display->display, s->normalCursor);
      XFreeCursor(s->display->display, s->busyCursor);

      /* Only called for the first screen */
      s->display->screens = s->next;
      free(s);
}

Bool
addScreen(CompDisplay * display,
              int screenNum,
              Window wmSnSelectionWindow, Atom wmSnAtom, Time wmSnTimestamp)
{
      CompScreen *s;
      Display *dpy = display->display;
      static char data = 0;
      XColor black;
      Pixmap bitmap;
      XVisualInfo templ;
      XVisualInfo *visinfo;
      GLXFBConfig *fbConfigs;
      VisualID visualIDs[MAX_DEPTH + 1];
      Window rootReturn, parentReturn;
      Window *children;
      unsigned int nchildren;
      int defaultDepth, nvisinfo, nElements, value, i;
      const char *glxExtensions, *glExtensions;
      XSetWindowAttributes attrib;
      GLfloat globalAmbient[] = { 0.1f, 0.1f, 0.1f, 0.1f };
      GLfloat ambientLight[] = { 0.0f, 0.0f, 0.0f, 0.0f };
      GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.9f, 0.9f };
      GLfloat light0Position[] = { -0.5f, 0.5f, -9.0f, 1.0f };
      CompWindow *w;
      GLXContext shareList = 0;

      s = malloc(sizeof(CompScreen));
      if (!s)
            return FALSE;
      IPCS_INITOBJ(s);

      s->windowPrivateIndices = 0;
      s->windowPrivateLen = 0;

      if (display->screenPrivateLen)
      {
            s->privates = malloc(display->screenPrivateLen * sizeof(CompPrivate));
            if (!s->privates)
            {
                  free(s);
                  return FALSE;
            }
      }
      else
            s->privates = 0;

      s->display = display;

      compScreenInitOptions(s);

      s->damage = XCreateRegion();
      if (!s->damage)
      {
            free(s);
            return FALSE;
      }

      s->x = 0;
      s->y = 0;
      s->hsize = SCREEN_SIZE_DEFAULT;
      s->vsize = SCREEN_VSIZE_DEFAULT;

      s->nDesktop = 0;
      s->currentDesktop = 0;
      projectionRecalc(s);

      for (i = 0; i < SCREEN_EDGE_NUM; i++)
      {
            s->screenEdge[i].id = None;
            s->screenEdge[i].count = 0;
      }

      s->buttonGrab = 0;
      s->nButtonGrab = 0;
      s->keyGrab = 0;
      s->nKeyGrab = 0;

      s->grabs = 0;
      s->grabSize = 0;
      s->maxGrab = 0;

      s->pendingDestroys = 0;

      s->clientList = 0;
      s->nClientList = 0;

      s->screenNum = screenNum;
      s->colormap = DefaultColormap(dpy, screenNum);
      s->root = XRootWindow(dpy, screenNum);

      s->mapNum = 1;
      s->activeNum = 1;

      s->groups = NULL;

      s->berylDesktopManaged = FALSE;

      s->snContext = sn_monitor_context_new(display->snDisplay,
                                                              screenNum,
                                                              compScreenSnEvent, s, NULL);

      s->startupSequences = NULL;
      s->startupSequenceTimeoutHandle = 0;

      s->wmSnSelectionWindow = wmSnSelectionWindow;
      s->wmSnAtom = wmSnAtom;
      s->wmSnTimestamp = wmSnTimestamp;

      s->damageMask = COMP_SCREEN_DAMAGE_ALL_MASK;
      s->next = 0;
      s->exposeRects = 0;
      s->sizeExpose = 0;
      s->nExpose = 0;

      s->rasterX = 0;
      s->rasterY = 0;

      s->outputDev = NULL;
      s->nOutputDev = 0;
      s->currentOutputDev = 0;

      s->windows = 0;
      s->reverseWindows = 0;

      s->opacityStep = OPACITY_STEP_DEFAULT;
      s->saturationStep = SATURATION_STEP_DEFAULT;
      s->brightnessStep = BRIGHTNESS_STEP_DEFAULT;

      s->nextRedraw = 0;
      s->frameStatus = 0;
      s->timeMult = 1;
      s->idle = TRUE;
      s->timeLeft = 0;

      s->pendingCommands = TRUE;

      s->showingDesktopMask = 0;

      s->overlayWindowCount = 0;

      s->desktopHintData = NULL;
      s->desktopHintSize = 0;

      gettimeofday(&s->lastRedraw, 0);

      s->setScreenOption = setScreenOption;
      s->setScreenOptionForPlugin = setScreenOptionForPlugin;

      s->initPluginForScreen = initPluginForScreen;
      s->finiPluginForScreen = finiPluginForScreen;

      s->preparePaintScreen = preparePaintScreen;
      s->donePaintScreen = donePaintScreen;
      s->paintScreen = paintScreen;
      s->paintTransformedScreen = paintTransformedScreen;
      s->applyScreenTransform = applyScreenTransform;
      s->paintBackground = paintBackground;
      s->paintWindow = paintWindow;
      s->drawWindow = drawWindow;
      s->addWindowGeometry = addWindowGeometry;
      s->drawWindowTexture = drawWindowTexture;
      s->drawWindowGeometry = drawWindowGeometry;
      s->damageWindowRect = damageWindowRect;
      s->getOutputExtentsForWindow = getOutputExtentsForWindow;
      s->focusWindow = focusWindow;
      s->setClipPlanes = setClipPlanes;

      s->windowResizeNotify = windowResizeNotify;
      s->windowMoveNotify = windowMoveNotify;
      s->windowGrabNotify = windowGrabNotify;
      s->windowUngrabNotify = windowUngrabNotify;

      s->windowStateChangeNotify = windowStateChangeNotify;

      s->outputChangeNotify = outputChangeNotify;

      s->getProcAddress = 0;

      if (!XGetWindowAttributes(dpy, s->root, &s->attrib))
            return FALSE;

      s->workArea.x = 0;
      s->workArea.y = 0;
      s->workArea.width = s->attrib.width;
      s->workArea.height = s->attrib.height;

      s->grabWindow = None;

    makeOutputWindow(s);

      templ.visualid = XVisualIDFromVisual(s->attrib.visual);

      visinfo = XGetVisualInfo(dpy, VisualIDMask, &templ, &nvisinfo);
      if (!nvisinfo)
      {
            fprintf(stderr,
                        _
                        ("%s: Couldn't get visual info for default visual\n"),
                        programName);
            return FALSE;
      }

      defaultDepth = visinfo->depth;

      black.red = black.green = black.blue = 0;

      if (!XAllocColor(dpy, s->colormap, &black))
      {
            fprintf(stderr, _("%s: Couldn't allocate color\n"), programName);
            return FALSE;
      }

      bitmap = XCreateBitmapFromData(dpy, s->root, &data, 1, 1);
      if (!bitmap)
      {
            fprintf(stderr, _("%s: Couldn't create bitmap\n"), programName);
            return FALSE;
      }

      s->invisibleCursor = XCreatePixmapCursor(dpy, bitmap, bitmap,
                                                                   &black, &black, 0, 0);
      if (!s->invisibleCursor)
      {
            fprintf(stderr,
                        _("%s: Couldn't create invisible cursor\n"), programName);
            return FALSE;
      }

      XFreePixmap(dpy, bitmap);
      XFreeColors(dpy, s->colormap, &black.pixel, 1, 0);

      glXGetConfig(dpy, visinfo, GLX_USE_GL, &value);
      if (!value)
      {
            fprintf(stderr, _("%s: Root visual is not a GL visual\n"),
                        programName);
            return FALSE;
      }

      glXGetConfig(dpy, visinfo, GLX_DOUBLEBUFFER, &value);
      if (!value)
      {
            fprintf(stderr,
                        _
                        ("%s: Root visual is not a double buffered GL visual\n"),
                        programName);
            return FALSE;
      }

      if (display->screens && !noContextShare)
            shareList = display->screens->ctx;

      XUngrabServer(dpy);
      s->ctx = glXCreateContext(dpy, visinfo, shareList, !indirectRendering);

      if (!s->ctx)
      {
            fprintf(stderr, _("%s: glXCreateContext failed\n"), programName);
            return FALSE;
      }

      XFree(visinfo);
      if (!indirectRendering)
            glxExtensions =
                        glXQueryExtensionsString(s->display->display, screenNum);
      else
            glxExtensions =
                        glXQueryServerString(s->display->display, screenNum,
                                                       GLX_EXTENSIONS);
      if (!copyTexture)
      {
            if (!strstr(glxExtensions, "GLX_EXT_texture_from_pixmap"))
            {
                  fprintf(stderr,
                              _
                              ("%s: GLX_EXT_texture_from_pixmap is missing\n"),
                              programName);
                  fprintf(stderr, _("%s: Using non-tfp mode\n"), programName);
                  copyTexture = TRUE;
            }
      }

      if (!strstr(glxExtensions, "GLX_SGIX_fbconfig"))
      {
            fprintf(stderr, _("%s: GLX_SGIX_fbconfig is missing\n"), programName);
            return FALSE;
      }

      s->getProcAddress = (GLXGetProcAddressProc)
                  getProcAddress(s, "glXGetProcAddressARB");
      if (!copyTexture)
      {
            s->bindTexImage = (GLXBindTexImageProc)
                        getProcAddress(s, "glXBindTexImageEXT");
            s->releaseTexImage = (GLXReleaseTexImageProc)
                        getProcAddress(s, "glXReleaseTexImageEXT");
      }
      s->queryDrawable = (GLXQueryDrawableProc)
                  getProcAddress(s, "glXQueryDrawable");
      s->getFBConfigs = (GLXGetFBConfigsProc)
                  getProcAddress(s, "glXGetFBConfigs");
      s->getFBConfigAttrib = (GLXGetFBConfigAttribProc)
                  getProcAddress(s, "glXGetFBConfigAttrib");
      s->createPixmap = (GLXCreatePixmapProc)
                  getProcAddress(s, "glXCreatePixmap");


      if (!copyTexture)
      {
            if (!s->bindTexImage)
            {
                  fprintf(stderr,
                              _("%s: glXBindTexImageEXT is missing\n"), programName);
                  return FALSE;
            }

            if (!s->releaseTexImage)
            {
                  fprintf(stderr,
                              _("%s: glXReleaseTexImageEXT is missing\n"), programName);
                  return FALSE;
            }
      }

      if (!s->queryDrawable ||
            !s->getFBConfigs || !s->getFBConfigAttrib || !s->createPixmap)
      {
            fprintf(stderr, _("%s: fbconfig functions missing\n"), programName);
            return FALSE;
      }

      s->copySubBuffer = NULL;
      if (strstr(glxExtensions, "GLX_MESA_copy_sub_buffer"))
            s->copySubBuffer = (GLXCopySubBufferProc)
                        getProcAddress(s, "glXCopySubBufferMESA");

      s->getVideoSync = NULL;
      s->waitVideoSync = NULL;
      if (strstr(glxExtensions, "GLX_SGI_video_sync"))
      {
            s->getVideoSync = (GLXGetVideoSyncProc)
                        getProcAddress(s, "glXGetVideoSyncSGI");

            s->waitVideoSync = (GLXWaitVideoSyncProc)
                        getProcAddress(s, "glXWaitVideoSyncSGI");
      }

      glXMakeCurrent(dpy, s->output, s->ctx);
      currentRoot = s->root;

      glExtensions = (const char *)glGetString(GL_EXTENSIONS);

      s->textureNonPowerOfTwo = 0;
      if (strstr(glExtensions, "GL_ARB_texture_non_power_of_two"))
            s->textureNonPowerOfTwo = 1;

      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s->maxTextureSize);

      s->textureRectangle = 0;
      if (strstr(glExtensions, "GL_NV_texture_rectangle") ||
            strstr(glExtensions, "GL_EXT_texture_rectangle") ||
            strstr(glExtensions, "GL_ARB_texture_rectangle"))
      {
            s->textureRectangle = 1;

            if (!s->textureNonPowerOfTwo)
            {
                  GLint maxTextureSize;

                  glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &maxTextureSize);
                  if (maxTextureSize > s->maxTextureSize)
                        s->maxTextureSize = maxTextureSize;
            }
      }

      if (!(s->textureRectangle || s->textureNonPowerOfTwo))
      {
            fprintf(stderr,
                        _
                        ("%s: Support for non power of two textures missing\n"),
                        programName);
            return FALSE;
      }

      s->textureEnvCombine = s->textureEnvCrossbar = 0;
      if (strstr(glExtensions, "GL_ARB_texture_env_combine"))
      {
            s->textureEnvCombine = 1;

            /* XXX: GL_NV_texture_env_combine4 need special code but it seams to
               be working anyway for now... */
            if (strstr(glExtensions, "GL_ARB_texture_env_crossbar") ||
                  strstr(glExtensions, "GL_NV_texture_env_combine4"))
                  s->textureEnvCrossbar = 1;
      }

      s->textureBorderClamp = 0;
      if (strstr(glExtensions, "GL_ARB_texture_border_clamp") ||
            strstr(glExtensions, "GL_SGIS_texture_border_clamp"))
            s->textureBorderClamp = 1;

      s->maxTextureUnits = 1;
      if (strstr(glExtensions, "GL_ARB_multitexture"))
      {
            s->activeTexture = (GLActiveTextureProc)
                        getProcAddress(s, "glActiveTexture");
            s->clientActiveTexture = (GLClientActiveTextureProc)
                        getProcAddress(s, "glClientActiveTexture");

            if (s->activeTexture && s->clientActiveTexture)
                  glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &s->maxTextureUnits);
      }

      s->fragmentProgram = 0;
      if (strstr(glExtensions, "GL_ARB_fragment_program"))
      {
            s->genPrograms = (GLGenProgramsProc)
                        getProcAddress(s, "glGenProgramsARB");
            s->deletePrograms = (GLDeleteProgramsProc)
                        getProcAddress(s, "glDeleteProgramsARB");
            s->bindProgram = (GLBindProgramProc)
                        getProcAddress(s, "glBindProgramARB");
            s->programString = (GLProgramStringProc)
                        getProcAddress(s, "glProgramStringARB");
            s->programLocalParameter4f =
                        (GLProgramLocalParameter4fProc)
                        getProcAddress(s, "glProgramLocalParameter4fARB");

            if (s->genPrograms &&
                  s->deletePrograms &&
                  s->bindProgram && s->programString && s->programLocalParameter4f)
                  s->fragmentProgram = 1;
      }

      s->fbo = 0;
      if (strstr(glExtensions, "GL_EXT_framebuffer_object"))
      {
            s->genFramebuffers = (GLGenFramebuffersProc)
                        getProcAddress(s, "glGenFramebuffersEXT");
            s->deleteFramebuffers = (GLDeleteFramebuffersProc)
                        getProcAddress(s, "glDeleteFramebuffersEXT");
            s->bindFramebuffer = (GLBindFramebufferProc)
                        getProcAddress(s, "glBindFramebufferEXT");
            s->checkFramebufferStatus = (GLCheckFramebufferStatusProc)
                        getProcAddress(s, "glCheckFramebufferStatusEXT");
            s->framebufferTexture2D = (GLFramebufferTexture2DProc)
                        getProcAddress(s, "glFramebufferTexture2DEXT");
            s->generateMipmap = (GLGenerateMipmapProc)
                        getProcAddress(s, "glGenerateMipmapEXT");
            s->genRenderbuffers = (GLGenRenderbuffersProc)
                        getProcAddress(s, "glGenRenderbuffersEXT");
            s->deleteRenderbuffers = (GLDeleteRenderbuffersProc)
                        getProcAddress(s, "glDeleteRenderbuffersEXT");
            s->bindRenderbuffer = (GLBindRenderbufferProc)
                        getProcAddress(s, "glBindRenderbufferEXT");
            s->renderbufferStorage = (GLRenderbufferStorageProc)
                        getProcAddress(s, "glRenderbufferStorageEXT");
            s->framebufferRenderbuffer =
                        (GLFramebufferRenderbufferProc)
                        getProcAddress(s, "glFramebufferRenderbufferEXT");

            if (s->genFramebuffers &&
                  s->deleteFramebuffers &&
                  s->bindFramebuffer &&
                  s->checkFramebufferStatus &&
                  s->framebufferTexture2D &&
                  s->generateMipmap &&
                  s->genRenderbuffers &&
                  s->deleteRenderbuffers &&
                  s->bindRenderbuffer &&
                  s->renderbufferStorage && s->framebufferRenderbuffer)
                  s->fbo = 1;
      }

      fbConfigs = (*s->getFBConfigs) (dpy, screenNum, &nElements);

      for (i = 0; i <= MAX_DEPTH; i++)
      {
            int j, db, stencil, depth, alpha, mipmap, rgba;

            s->glxPixmapFBConfigs[i].fbConfig = NULL;
            s->glxPixmapFBConfigs[i].mipmap = 0;
            s->glxPixmapFBConfigs[i].yInverted = 0;
            s->glxPixmapFBConfigs[i].textureFormat = 0;

            db = MAXSHORT;
            stencil = MAXSHORT;
            depth = MAXSHORT;
            mipmap = 0;
            rgba = 0;

            for (j = 0; j < nElements; j++)
            {
                  XVisualInfo *vi;
                  int visual_depth;

                  vi = glXGetVisualFromFBConfig(dpy, fbConfigs[j]);
                  if (vi == NULL)
                        continue;

                  visual_depth = vi->depth;

                  XFree(vi);

                  if (visual_depth != i)
                        continue;

                  (*s->getFBConfigAttrib) (dpy,
                                                       fbConfigs[j], GLX_ALPHA_SIZE, &alpha);
                  (*s->getFBConfigAttrib) (dpy, fbConfigs[j],
                                                       GLX_BUFFER_SIZE, &value);
                  if (value != i && (value - alpha) != i)
                        continue;

                  value = 0;
                  if (i == 32)
                  {
                        (*s->getFBConfigAttrib) (dpy,
                                                             fbConfigs[j],
                                                             GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                                             &value);

                        if (value)
                        {
                              rgba = 1;

                              s->glxPixmapFBConfigs[i].
                                          textureFormat = GLX_TEXTURE_FORMAT_RGBA_EXT;
                        }
                  }

                  if (!value)
                  {
                        if (rgba)
                              continue;

                        (*s->getFBConfigAttrib) (dpy,
                                                             fbConfigs[j],
                                                             GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
                        if (!value)
                              continue;

                        s->glxPixmapFBConfigs[i].textureFormat =
                                    GLX_TEXTURE_FORMAT_RGB_EXT;
                  }
#ifdef GLX_EXT_visual_rating
                  (*s->getFBConfigAttrib) (dpy, fbConfigs[j],
                                                       GLX_VISUAL_CAVEAT_EXT, &value);
                  if (value == GLX_SLOW_VISUAL_EXT)
                        continue;
#endif


                  (*s->getFBConfigAttrib) (dpy,
                                                       fbConfigs[j], GLX_DOUBLEBUFFER, &value);
                  if (value > db)
                        continue;

                  db = value;

                  (*s->getFBConfigAttrib) (dpy,
                                                       fbConfigs[j], GLX_STENCIL_SIZE, &value);
                  if (value > stencil)
                        continue;

                  stencil = value;

                  (*s->getFBConfigAttrib) (dpy,
                                                       fbConfigs[j], GLX_DEPTH_SIZE, &value);
                  if (value > depth)
                        continue;

                  depth = value;

                  if (s->fbo)
                  {
                        (*s->getFBConfigAttrib) (dpy,
                                                             fbConfigs[j],
                                                             GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
                                                             &value);
                        if (value < mipmap)
                              continue;

                        mipmap = value;
                  }

                  (*s->getFBConfigAttrib) (dpy,
                                                       fbConfigs[j],
                                                       GLX_Y_INVERTED_EXT, &value);

                  s->glxPixmapFBConfigs[i].yInverted = value;
                  s->glxPixmapFBConfigs[i].fbConfig = fbConfigs[j];
                  s->glxPixmapFBConfigs[i].mipmap = mipmap;
            }
      }

      if (nElements)
            XFree(fbConfigs);

      s->useFBConfig = True;

      if (!s->glxPixmapFBConfigs[defaultDepth].fbConfig)
      {
            fprintf(stderr, _("%s: No GLXFBConfig for default depth, "
                                      "falling back on visinfo.\n"), programName);
            //return FALSE;
            s->useFBConfig = False;
            /* we don't want to allocate back, stencil or depth buffers for pixmaps
               so lets see if we can find an approriate visual without these buffers */
            for (i = 0; i <= MAX_DEPTH; i++)
            {
                  int j, db, stencil, depth;

                  visualIDs[i] = 0;

                  db = MAXSHORT;
                  stencil = MAXSHORT;
                  depth = MAXSHORT;

                  templ.depth = i;

                  visinfo = XGetVisualInfo(dpy, VisualDepthMask, &templ, &nvisinfo);
                  for (j = 0; j < nvisinfo; j++)
                  {
                        glXGetConfig(dpy, &visinfo[j], GLX_USE_GL, &value);
                        if (!value)
                              continue;

#ifdef GLX_EXT_visual_rating
                        glXGetConfig(dpy, &visinfo[j], GLX_VISUAL_CAVEAT_EXT, &value);
                        if (value == GLX_SLOW_VISUAL_EXT)
                              continue;
#endif

                        glXGetConfig(dpy, &visinfo[j], GLX_DOUBLEBUFFER, &value);
                        if (value > db)
                              continue;

                        db = value;
                        glXGetConfig(dpy, &visinfo[j], GLX_STENCIL_SIZE, &value);
                        if (value > stencil)
                              continue;

                        stencil = value;
                        glXGetConfig(dpy, &visinfo[j], GLX_DEPTH_SIZE, &value);
                        if (value > depth)
                              continue;

                        depth = value;
                        visualIDs[i] = visinfo[j].visualid;
                  }

                  if (nvisinfo)
                        XFree(visinfo);
            }

            /* create contexts for supported depths */
            for (i = 0; i <= MAX_DEPTH; i++)
            {
                  templ.visualid = visualIDs[i];
                  s->glxPixmapVisuals[i] = XGetVisualInfo(dpy,
                                                                              VisualIDMask,
                                                                              &templ, &nvisinfo);
            }

            if (!s->glxPixmapVisuals[defaultDepth])
            {
                  fprintf(stderr,
                              _("%s: No GL visual for default depth, "
                                "this isn't going to work.\n"), programName);
                  return FALSE;
            }

      }

      initTexture(s, &s->backgroundTexture);

      s->defaultIcon = NULL;

      s->desktopWindowCount = 0;

      glClearColor(0.0, 0.0, 0.0, 1.0);
      glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
      glEnable(GL_CULL_FACE);
      glDisable(GL_BLEND);
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      glColor4usv(defaultColor);
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);

      s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
      if (s->textureEnvCombine && s->maxTextureUnits >= 2)
      {
            s->canDoSaturated = TRUE;
            if (s->textureEnvCrossbar && s->maxTextureUnits >= 4)
                  s->canDoSlightlySaturated = TRUE;
      }

      s->redrawTime = 1000 / DEFAULT_REFRESH_RATE;
      s->optimalRedrawTime = s->redrawTime;

      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbient);

      glEnable(GL_LIGHT0);
      glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
      glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
      glLightfv(GL_LIGHT0, GL_POSITION, light0Position);

      glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

      glNormal3f(0.0f, 0.0f, -1.0f);

      s->lighting = FALSE;
      s->slowAnimations = FALSE;

      reshape(s, s->attrib.width, s->attrib.height);

      addScreenToDisplay(display, s);

      getDesktopHints(s);

      screenInitPlugins(s);

      reload_all(s->display);

      detectRefreshRateOfScreen(s);

      XQueryTree(dpy, s->root,
                     &rootReturn, &parentReturn, &children, &nchildren);

      for (i = 0; i < nchildren; i++)
            addWindow(s, children[i], i ? children[i - 1] : 0);

      for (w = s->windows; w; w = w->next)
      {
            if (w->attrib.map_state == IsViewable)
            {
                  w->activeNum = s->activeNum++;
                  w->damaged = TRUE;
                  w->placed = TRUE;
                  w->invisible = WINDOW_INVISIBLE(w);
            }
            else if (w->state & (CompWindowStateHiddenMask | CompWindowStateOffscreenMask))
            {
                  w->placed = TRUE;
            }
      }

      XFree(children);

      attrib.override_redirect = 1;
      attrib.event_mask = PropertyChangeMask;

      s->grabWindow = XCreateWindow(dpy, s->root, -100, -100, 1, 1, 0,
                                                  CopyFromParent, InputOnly, CopyFromParent,
                                                  CWOverrideRedirect | CWEventMask, &attrib);
      XMapWindow(dpy, s->grabWindow);

      Atom state[4];
      int nState=0;
      state[nState++] = s->display->winStateAboveAtom;
      state[nState++] = s->display->winStateStickyAtom;
      state[nState++] = s->display->winStateSkipTaskbarAtom;
      state[nState++] = s->display->winStateSkipPagerAtom;

      for (i = 0; i < SCREEN_EDGE_NUM; i++)
      {
            long xdndVersion = 3;

            Atom type = XInternAtom(dpy,"_NET_WM_WINDOW_TYPE_DOCK",0);

            s->screenEdge[i].id =
                        XCreateWindow(dpy, s->root, -100, -100, 1, 1, 0,
                                            CopyFromParent, InputOnly,
                                            CopyFromParent, CWOverrideRedirect, &attrib);

            XChangeProperty(dpy, s->screenEdge[i].id,
                                    XInternAtom(dpy, "_NET_WM_STATE",
                                                      0), XA_ATOM, 32,
                                    PropModeReplace, (unsigned char *)state, nState);

            XChangeProperty(dpy, s->screenEdge[i].id,
                                    display->xdndAwareAtom, XA_ATOM, 32,
                                    PropModeReplace, (unsigned char *)&xdndVersion, 1);

            XChangeProperty(dpy, s->screenEdge[i].id,
                                    XInternAtom(dpy,"_NET_WM_WINDOW_TYPE",0),XA_ATOM,32,
                                    PropModeReplace, (unsigned char *)&type, 1);

            XSelectInput(dpy, s->screenEdge[i].id,
                               EnterWindowMask |
                               LeaveWindowMask |
                               ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
      }

      updateScreenEdges(s);

      setDesktopHints(s);
      setSupportingWmCheck(s);
      setSupported(s);

      s->normalCursor = XCreateFontCursor(dpy, XC_left_ptr);
      s->busyCursor = XCreateFontCursor(dpy, XC_watch);

      XDefineCursor(dpy, s->root, s->normalCursor);

      s->filter[NOTHING_TRANS_FILTER] = COMP_TEXTURE_FILTER_FAST;
      s->filter[SCREEN_TRANS_FILTER] = COMP_TEXTURE_FILTER_GOOD;
      s->filter[WINDOW_TRANS_FILTER] = COMP_TEXTURE_FILTER_GOOD;

      CompOption *option;
      int nOption;
      nOption=0;
      beryl_settings_context_read(display->context);
      option=compGetScreenOptions(s,&nOption);
        while (nOption--)
      {
            CompOptionValue value;
            memcpy(&value,&option->value,sizeof(CompOptionValue));
            if (beryl_settings_context_comp_get_option_value(display->context,NULL,option->name,TRUE,&value))
            {
                  s->setScreenOption(s,option->name,&value);
            }
            option++;
      }
      return TRUE;
}

int screenGetOutputDev(CompScreen * s, int x, int y, int w, int h)
{
      if (s->nOutputDev == 0)
            return 0;
      int i;

      for (i = 0; i < s->nOutputDev; i++)
      {
            if (x >= s->outputDev[i].region.extents.x1 &&
                  x + w < s->outputDev[i].region.extents.x2 &&
                  y >= s->outputDev[i].region.extents.y1 &&
                  y + h < s->outputDev[i].region.extents.y2)
                  return i;
      }

      if (w != 0 || h != 0)
      {
            int bestOutputDev, maxArea, currentArea;
            int windowLeftX, windowRightX, windowTopY, windowBottomY;
            int areaLeftX, areaRightX, areaTopY, areaBottomY;

            w = MAX(1,w);
            h = MAX(1,h);

            windowLeftX = x;
            windowRightX = x + w;
            windowTopY = y;
            windowBottomY = y + h;
            bestOutputDev = maxArea = currentArea = 0;
            for (i = 0; i < s->nOutputDev; i++)
            {
                  if (windowLeftX >
                        (s->outputDev[i].region.extents.x2)
                        || windowTopY >
                        (s->outputDev[i].region.extents.y2)
                        || windowRightX <
                        s->outputDev[i].region.extents.x1
                        || windowBottomY < s->outputDev[i].region.extents.y1)
                        continue;
                  if (windowLeftX <= s->outputDev[i].region.extents.x1)
                        areaLeftX = s->outputDev[i].region.extents.x1;
                  else
                        areaLeftX = windowLeftX;
                  if (windowRightX >= s->outputDev[i].region.extents.x2)
                        areaRightX = s->outputDev[i].region.extents.x2;
                  else
                        areaRightX = windowRightX;
                  if (windowTopY <= s->outputDev[i].region.extents.y1)
                        areaTopY = s->outputDev[i].region.extents.y1;
                  else
                        areaTopY = windowTopY;
                  if (windowBottomY >= s->outputDev[i].region.extents.y2)
                        areaBottomY = s->outputDev[i].region.extents.y2;
                  else
                        areaBottomY = windowBottomY;
                  currentArea = (areaRightX - areaLeftX) * (areaBottomY - areaTopY);
                  if (currentArea > maxArea)
                  {
                        maxArea = currentArea;
                        bestOutputDev = i;
                  }
            }
            if (bestOutputDev > 0)
                  return bestOutputDev;
      }
      return 0;
}

int screenGetOutputDevForWindow(CompWindow * w)
{
      if (w->screen->nOutputDev == 1)
            return 0;
      return screenGetOutputDev(w->screen, w->serverX,
                                            w->serverY, w->width,
                                            w->height);
}

int screenGetCurrentOutputDev(CompScreen * s)
{
      if (s->nOutputDev == 1)
            return 0;
      int root_x = 0, root_y = 0;
      int ignore_i;
      unsigned int ignore_ui;

      Window ignore_w;

      XQueryPointer(s->display->display,
                          s->root, &ignore_w,
                          &ignore_w, &root_x, &root_y,
                          &ignore_i, &ignore_i, &ignore_ui);
      return screenGetOutputDev(s, root_x, root_y, 0, 0);
}

void
screenGetOutputDevRect(CompScreen * s, int outputDev, XRectangle * outputRect)
{
      if (!outputRect)
            return;

      if (outputDev >= s->nOutputDev)
            outputDev = 0;

      outputRect->x = s->outputDev[outputDev].region.extents.x1;
      outputRect->y = s->outputDev[outputDev].region.extents.y1;
      outputRect->width =
                  s->outputDev[outputDev].region.extents.x2 -
                  s->outputDev[outputDev].region.extents.x1;
      outputRect->height =
                  s->outputDev[outputDev].region.extents.y2 -
                  s->outputDev[outputDev].region.extents.y1;
}

void
screenGetOutputDevWorkArea(CompScreen * s, int outputDev,
                                       XRectangle * workArea)
{
      if (!workArea)
            return;

      if (outputDev >= s->nOutputDev)
            outputDev = 0;

      workArea->x = s->outputDev[outputDev].workRegion.extents.x1;
      workArea->y = s->outputDev[outputDev].workRegion.extents.y1;
      workArea->width =
                  s->outputDev[outputDev].workRegion.extents.x2 -
                  s->outputDev[outputDev].workRegion.extents.x1;
      workArea->height =
                  s->outputDev[outputDev].workRegion.extents.y2 -
                  s->outputDev[outputDev].workRegion.extents.y1;
}

void damageScreenRegion(CompScreen * screen, Region region)
{
      if (screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
            return;

      XUnionRegion(screen->damage, region, screen->damage);

      screen->damageMask |= COMP_SCREEN_DAMAGE_REGION_MASK;
}

void damageScreen(CompScreen * s)
{
      s->damageMask |= COMP_SCREEN_DAMAGE_ALL_MASK;
      s->damageMask &= ~COMP_SCREEN_DAMAGE_REGION_MASK;
}

void damagePendingOnScreen(CompScreen * s)
{
      s->damageMask |= COMP_SCREEN_DAMAGE_PENDING_MASK;
}

void
forEachWindowOnScreen(CompScreen * screen,
                                ForEachWindowProc proc, void *closure)
{
      CompWindow *w;

      for (w = screen->windows; w; w = w->next)
            (*proc) (w, closure);
}

CompWindow *findWindowAtScreen(CompScreen * s, Window id)
{
      if (lastFoundWindow && lastFoundWindow->id == id)
      {
            return lastFoundWindow;
      }
      else
      {
            CompWindow *w;

            for (w = s->windows; w; w = w->next)
                  if (w->id == id)
                        return (lastFoundWindow = w);
      }

      return 0;
}

Bool pointerOnlyOnDesktop(CompScreen * s, int pointerX, int pointerY)
{
      CompWindow *w;

      for (w = s->windows; w; w = w->next)
      {
            if ((w->invisible && !w->shaded) || w->id == s->root
                  || w->type & CompWindowTypeDesktopMask)
                  continue;
            if (w->shaded)
            {
                  if (pointerX >= (w->attrib.x - w->input.left)
                        && pointerX <=
                        (w->attrib.x + w->attrib.width +
                         w->input.right)
                        && pointerY >= (w->attrib.y - w->input.top)
                        && pointerY <= (w->attrib.y + w->input.bottom))
                        return FALSE;
            }
            else
            {
                  if (pointerX >= (w->attrib.x - w->input.left)
                        && pointerX <=
                        (w->attrib.x + w->attrib.width +
                         w->input.right)
                        && pointerY >= (w->attrib.y - w->input.top)
                        && pointerY <=
                        (w->attrib.y + w->attrib.height + w->input.bottom))
                        return FALSE;
            }
      }

      return TRUE;
}

CompWindow *findTopLevelWindowAtScreen(CompScreen * s, Window id)
{
      CompWindow *found = NULL;

      if (lastFoundWindow && lastFoundWindow->id == id)
      {
            found = lastFoundWindow;
      }
      else
      {
            CompWindow *w;

            for (w = s->windows; w; w = w->next)
            {
                  if (w->id == id)
                  {
                        found = (lastFoundWindow = w);
                        break;
                  }
            }
      }

      if (!found)
            return NULL;

      if (found->attrib.override_redirect)
      {
            /* likely a frame window */
            if (found->attrib.class == InputOnly) {
                CompWindow *w;

                for (w = s->windows; w; w = w->next)
                  if (w->frame == id)
                      return w;
            }
            return NULL;
      }

      return found;
}

void insertWindowIntoScreen(CompScreen * s, CompWindow * w, Window aboveId)
{
      CompWindow *p;

      if (s->windows)
      {
            if (!aboveId)
            {
                  w->next = s->windows;
                  w->prev = NULL;
                  s->windows->prev = w;
                  s->windows = w;
            }
            else
            {
                  for (p = s->windows; p; p = p->next)
                  {
                        if (p->id == aboveId)
                        {
                              if (p->next)
                              {
                                    w->next = p->next;
                                    w->prev = p;
                                    p->next->prev = w;
                                    p->next = w;
                              }
                              else
                              {
                                    p->next = w;
                                    w->next = NULL;
                                    w->prev = p;
                                    s->reverseWindows = w;
                              }
                              break;
                        }
                  }

#ifdef DEBUG
                  if (!p)
                        abort();
#endif

            }
      }
      else
      {
            s->reverseWindows = s->windows = w;
            w->prev = w->next = NULL;
      }
}

void unhookWindowFromScreen(CompScreen * s, CompWindow * w)
{
      CompWindow *next, *prev;

      next = w->next;
      prev = w->prev;

      if (next || prev)
      {
            if (next)
            {
                  if (prev)
                  {
                        next->prev = prev;
                  }
                  else
                  {
                        s->windows = next;
                        next->prev = NULL;
                  }
            }

            if (prev)
            {
                  if (next)
                  {
                        prev->next = next;
                  }
                  else
                  {
                        s->reverseWindows = prev;
                        prev->next = NULL;
                  }
            }
      }
      else
      {
            s->windows = s->reverseWindows = NULL;
      }

      if (w == lastFoundWindow)
            lastFoundWindow = NULL;
      if (w == lastDamagedWindow)
            lastDamagedWindow = NULL;
}

#define POINTER_GRAB_MASK (ButtonReleaseMask | \
        ButtonPressMask   | \
        PointerMotionMask)
int pushScreenGrab(CompScreen * s, Cursor cursor, const char *name)
{
      return pushScreenGrabKeyboardOptional(s, cursor, name, TRUE);
}

int
pushScreenGrabKeyboardOptional(CompScreen * s, Cursor cursor,
                                             const char *name, Bool keyboardAlso)
{
      if (s->maxGrab == 0)
      {
            int status;

            status = XGrabPointer(s->display->display, s->grabWindow, TRUE,
                                            POINTER_GRAB_MASK, GrabModeAsync,
                                            GrabModeAsync, s->root, cursor, CurrentTime);

            if (status == GrabSuccess)
            {
                  if (keyboardAlso)
                  {
                        status = XGrabKeyboard(s->display->display,
                                                         s->grabWindow, TRUE,
                                                         GrabModeAsync,
                                                         GrabModeAsync, CurrentTime);
                        if (status != GrabSuccess)
                        {
                              XUngrabPointer(s->display->display, CurrentTime);
                              return 0;
                        }
                  }
            }
            else
                  return 0;
      }
      else
      {
            XChangeActivePointerGrab(s->display->display,
                                                 POINTER_GRAB_MASK, cursor, CurrentTime);
      }

      if (s->grabSize <= s->maxGrab)
      {
            s->grabs = realloc(s->grabs, sizeof(CompGrab) * (s->maxGrab + 1));
            if (!s->grabs)
                  return 0;

            s->grabSize = s->maxGrab + 1;
      }

      s->grabs[s->maxGrab].cursor = cursor;
      s->grabs[s->maxGrab].active = TRUE;
      s->grabs[s->maxGrab].name = name;

      s->maxGrab++;

      return s->maxGrab;
}

void updateScreenGrab(CompScreen * s, int index, Cursor cursor)
{
      index--;

#ifdef DEBUG
      if (index < 0 || index >= s->maxGrab)
            abort();
#endif

      XChangeActivePointerGrab(s->display->display, POINTER_GRAB_MASK,
                                           cursor, CurrentTime);

      s->grabs[index].cursor = cursor;
}

void removeScreenGrab(CompScreen * s, int index, XPoint * restorePointer)
{
      removeScreenGrabKeyboardOptional(s, index, restorePointer, TRUE);
}

void
removeScreenGrabKeyboardOptional(CompScreen * s, int index,
                                                 XPoint * restorePointer, Bool keyboardAlso)
{
      int maxGrab;

      index--;

#ifdef DEBUG
      if (index < 0 || index >= s->maxGrab)
            abort();
#endif

      s->grabs[index].cursor = None;
      s->grabs[index].active = FALSE;

      for (maxGrab = s->maxGrab; maxGrab; maxGrab--)
            if (s->grabs[maxGrab - 1].active)
                  break;

      if (maxGrab != s->maxGrab)
      {
            if (maxGrab)
            {
                  XChangeActivePointerGrab(s->display->display,
                                                       POINTER_GRAB_MASK,
                                                       s->grabs[maxGrab -
                                                                    1].cursor, CurrentTime);
            }
            else
            {
                  if (restorePointer)
                        warpPointer(s->display,
                                          restorePointer->x -
                                          s->display->pointerX,
                                          restorePointer->y - s->display->pointerY);

                  XUngrabPointer(s->display->display, CurrentTime);
                  if (keyboardAlso)
                        XUngrabKeyboard(s->display->display, CurrentTime);
            }

            s->maxGrab = maxGrab;
      }
}

static Bool checkScreenGrabExist(CompScreen * s, Bool whiteList, va_list ap)
{
      va_list aq;
      char *name;
      int i;

      for (i = 0; i < s->maxGrab; i++)
      {
            if (s->grabs[i].active)
            {
                  va_copy(aq, ap);

                  name = va_arg(aq, char *);

                  while (name)
                  {
                        if (strcmp(name, s->grabs[i].name) == 0)
                              break;

                        name = va_arg(aq, char *);
                  }

                  va_end(aq);

                  if ((whiteList && !name) || (!whiteList && name))
                        return TRUE;
            }
      }

      return FALSE;
}

Bool screenGrabExist(CompScreen * s, ...)
{
      va_list ap;
      Bool ret;

      va_start(ap, s);
      ret = checkScreenGrabExist(s, FALSE, ap);
      va_end(ap);

      return ret;
}

Bool otherScreenGrabExist(CompScreen * s, ...)
{
      va_list ap;
      Bool ret;

      va_start(ap, s);
      ret = checkScreenGrabExist(s, TRUE, ap);
      va_end(ap);

      return ret;
}

static void
grabUngrabOneKey(CompScreen * s,
                         unsigned int modifiers, int keycode, Bool grab)
{
      if (grab)
      {
            XGrabKey(s->display->display,
                         keycode,
                         modifiers, s->root, TRUE, GrabModeAsync, GrabModeAsync);
      }
      else
      {
            XUngrabKey(s->display->display, keycode, modifiers, s->root);
      }
}

static Bool
grabUngrabKeys(CompScreen * s, unsigned int modifiers, int keycode, Bool grab)
{
      XModifierKeymap *modMap = s->display->modMap;
      int ignore, mod, k;

      compCheckForError(s->display->display);

      for (ignore = 0; ignore <= s->display->ignoredModMask; ignore++)
      {
            if (ignore & ~s->display->ignoredModMask)
                  continue;

            if (keycode != 0)
            {
                  grabUngrabOneKey(s, modifiers | ignore, keycode, grab);
            }
            else
            {
                  for (mod = 0; mod < 8; mod++)
                  {
                        if (modifiers & (1 << mod))
                        {
                              for (k =
                                     mod * modMap->max_keypermod;
                                     k < (mod + 1) * modMap->max_keypermod; k++)
                              {
                                    if (modMap->modifiermap[k])
                                    {
                                          grabUngrabOneKey(s,
                                                                   (modifiers
                                                                    &
                                                                    ~
                                                                    (1
                                                                     <<
                                                                     mod))
                                                                   |
                                                                   ignore,
                                                                   modMap->modifiermap[k], grab);
                                    }
                              }
                        }
                  }
            }

            if (compCheckForError(s->display->display))
                  return FALSE;
      }

      return TRUE;
}

static Bool addPassiveKeyGrab(CompScreen * s, CompKeyBinding * key)
{
      CompKeyGrab *keyGrab;
      unsigned int mask;
      int keycode;
      int i;

      mask = virtualToRealModMask(s->display, key->modifiers);
      keycode = XKeysymToKeycode(s->display->display, key->keysym);

      for (i = 0; i < s->nKeyGrab; i++)
      {
            if (keycode == s->keyGrab[i].keycode &&
                  mask == s->keyGrab[i].modifiers)
            {
                  s->keyGrab[i].count++;
                  return TRUE;
            }
      }

      keyGrab = realloc(s->keyGrab, sizeof(CompKeyGrab) * (s->nKeyGrab + 1));
      if (!keyGrab)
            return FALSE;

      s->keyGrab = keyGrab;

      if (!(mask & CompNoMask))
      {
            if (!grabUngrabKeys(s, mask, keycode, TRUE))
                  return FALSE;
      }

      s->keyGrab[s->nKeyGrab].keycode = keycode;
      s->keyGrab[s->nKeyGrab].modifiers = mask;
      s->keyGrab[s->nKeyGrab].count = 1;

      s->nKeyGrab++;

      return TRUE;
}

static void removePassiveKeyGrab(CompScreen * s, CompKeyBinding * key)
{
      unsigned int mask;
      int i;
      int keycode;

      keycode = XKeysymToKeycode(s->display->display, key->keysym);

      for (i = 0; i < s->nKeyGrab; i++)
      {
            mask = virtualToRealModMask(s->display, key->modifiers);
            if (keycode == s->keyGrab[i].keycode &&
                  mask == s->keyGrab[i].modifiers)
            {
                  s->keyGrab[i].count--;
                  if (s->keyGrab[i].count)
                        return;

                  memmove(s->keyGrab + i, s->keyGrab + i + 1,
                              (s->nKeyGrab - (i + 1)) * sizeof(CompKeyGrab));

                  s->nKeyGrab--;
                  s->keyGrab = realloc(s->keyGrab,
                                                 sizeof(CompKeyGrab) * s->nKeyGrab);

                  if (!(mask & CompNoMask))
                        grabUngrabKeys(s, mask, keycode, FALSE);
            }
      }
}

static void updatePassiveKeyGrabs(CompScreen * s)
{
      int i;

      XUngrabKey(s->display->display, AnyKey, AnyModifier, s->root);

      for (i = 0; i < s->nKeyGrab; i++)
      {
            if (!(s->keyGrab[i].modifiers & CompNoMask))
            {
                  grabUngrabKeys(s, s->keyGrab[i].modifiers,
                                       s->keyGrab[i].keycode, TRUE);
            }
      }
}

static Bool addPassiveButtonGrab(CompScreen * s, CompButtonBinding * button)
{
      CompButtonGrab *buttonGrab;
      int i;

      for (i = 0; i < s->nButtonGrab; i++)
      {
            if (button->button == s->buttonGrab[i].button &&
                  button->modifiers == s->buttonGrab[i].modifiers)
            {
                  s->buttonGrab[i].count++;
                  return TRUE;
            }
      }

      buttonGrab = realloc(s->buttonGrab,
                                     sizeof(CompButtonGrab) * (s->nButtonGrab + 1));
      if (!buttonGrab)
            return FALSE;

      s->buttonGrab = buttonGrab;

      s->buttonGrab[s->nButtonGrab].button = button->button;
      s->buttonGrab[s->nButtonGrab].modifiers = button->modifiers;
      s->buttonGrab[s->nButtonGrab].count = 1;

      s->nButtonGrab++;

      return TRUE;
}

static void
removePassiveButtonGrab(CompScreen * s, CompButtonBinding * button)
{
      int i;

      for (i = 0; i < s->nButtonGrab; i++)
      {
            if (button->button == s->buttonGrab[i].button &&
                  button->modifiers == s->buttonGrab[i].modifiers)
            {
                  s->buttonGrab[i].count--;
                  if (s->buttonGrab[i].count)
                        return;

                  memmove(s->buttonGrab + i, s->buttonGrab + i + 1,
                              (s->nButtonGrab - (i + 1)) * sizeof(CompButtonGrab));

                  s->nButtonGrab--;
                  s->buttonGrab = realloc(s->buttonGrab,
                                                      sizeof(CompButtonGrab) * s->nButtonGrab);
            }
      }
}

Bool addScreenAction(CompScreen * s, CompAction * action)
{
      if (action->type & CompBindingTypeKey)
      {
            addPassiveKeyGrab(s, &action->key);
            /*if (!addPassiveKeyGrab (s, &action->key))
               {
               puts("failing on keygrab");
               return FALSE;
               } */
      }

      if (action->type & CompBindingTypeButton)
      {
            addPassiveButtonGrab(s, &action->button);
            /*if (!addPassiveButtonGrab (s, &action->button))
               {
               puts("failing on button");
               if (action->type & CompBindingTypeKey)
               removePassiveKeyGrab (s, &action->key);

               return FALSE;
               } */
      }

      if (action->edgeMask)
      {
            int i;

            for (i = 0; i < SCREEN_EDGE_NUM; i++)
                  if (action->edgeMask & (1 << i))
                        enableScreenEdge(s, i);
      }

      return TRUE;
}

void removeScreenAction(CompScreen * s, CompAction * action)
{
      if (action->type & CompBindingTypeKey)
            removePassiveKeyGrab(s, &action->key);

      if (action->type & CompBindingTypeButton)
            removePassiveButtonGrab(s, &action->button);

      if (action->edgeMask)
      {
            int i;

            for (i = 0; i < SCREEN_EDGE_NUM; i++)
                  if (action->edgeMask & (1 << i))
                        disableScreenEdge(s, i);
      }
}

void updatePassiveGrabs(CompScreen * s)
{
      updatePassiveKeyGrabs(s);
}

/* Finds the output devs for the x/y/w/h, starting at 'start' outputdev.
 * This is meant to find all output devs for a given area.
 * NOTE:  Unlike screenGetOuputDev(), this returns the s->outputDev
 * reference without +1. Returns -1 when no more output devs are found.
 */

static int screenGetOutputDev_multi(CompScreen * s, int start, int x,
                                                      int y, int w, int h)
{
      int i;

      if (start > s->nOutputDev)
            return -1;

      if (s->nOutputDev == 1)
            return 0;
      h--;
      w--;                                // if width == resolution we're NOT in the next head.
      for (i = start; i < s->nOutputDev; i++)
      {
            if (x >= s->outputDev[i].region.extents.x1 &&
                  x < s->outputDev[i].region.extents.x2
                  && y >= s->outputDev[i].region.extents.y1 &&
                  y < s->outputDev[i].region.extents.y2)
                  return i;
            if (x + w >= s->outputDev[i].region.extents.x1 &&
                  x + w < s->outputDev[i].region.extents.x2
                  && y >= s->outputDev[i].region.extents.y1 &&
                  y < s->outputDev[i].region.extents.y2)
                  return i;
            if (x >= s->outputDev[i].region.extents.x1 &&
                  x < s->outputDev[i].region.extents.x2
                  && y + h >= s->outputDev[i].region.extents.y1 &&
                  y + h < s->outputDev[i].region.extents.y2)
                  return i;
            if (x + w >= s->outputDev[i].region.extents.x1 &&
                  x + w < s->outputDev[i].region.extents.x2
                  && y + h >= s->outputDev[i].region.extents.y1 &&
                  y + h < s->outputDev[i].region.extents.y2)
                  return i;
      }
      return -1;
}


/* Applies struts to all output devices a given window is in.
 * (Ie: handles struts for panels stretching multiple heads)
 * FIXME: Above layout needs work.
 */

static void updateWorkareaForScreen_outputWindow(CompScreen * s,
                                                                         CompWindow * w)
{
      int outputDev = 0;
      int size;
      CompOutput *device;

      while ((outputDev = screenGetOutputDev_multi(s, outputDev,
                                                                         w->serverX,
                                                                         w->serverY, w->width,
                                                                         w->height)) != -1)
      {
            device = &s->outputDev[outputDev];
            if (w->struts->left.width > device->workRegion.extents.x1)
            {
                  device->workRegion.extents.x1 =
                              device->region.extents.x1 + w->struts->left.width;
                  device->workRegion.extents.x1 += device->region.extents.x1;
            }

            if (w->struts->top.height > device->workRegion.extents.y1)
            {
                  device->workRegion.extents.y1 = w->struts->top.height;
            }

            size = device->region.extents.x2 - device->workRegion.extents.x2;
            if (w->struts->right.width > size)
            {
                  device->workRegion.extents.x2 =
                              device->region.extents.x2 - w->struts->right.width;
                  device->workRegion.extents.x2 +=
                              s->width - device->region.extents.x2;
            }

            size = device->region.extents.y2 - device->workRegion.extents.y2;
            if (w->struts->bottom.height > size)
            {
                  device->workRegion.extents.y2 =
                              device->region.extents.y2 - w->struts->bottom.height;
                  device->workRegion.extents.y2 += s->height - device->height;
            }
            outputDev++;
      }
}

void updateWorkareaForScreen(CompScreen * s)
{
      CompWindow *w;
      int leftStrut, rightStrut, topStrut, bottomStrut, outputDev;
      CompOutput *device;
      XRectangle workArea;

      // This will be used for struts sizes
      int size;

      leftStrut = 0;
      rightStrut = 0;
      topStrut = 0;
      bottomStrut = 0;
      outputDev = 0;
      size = 0;

      // reset workarea for each output device
      for (outputDev = 0; outputDev < s->nOutputDev; outputDev++)
      {
            device = &s->outputDev[outputDev];
            device->workRegion.extents.x1 = device->region.extents.x1;
            device->workRegion.extents.x2 = device->region.extents.x2;
            device->workRegion.extents.y1 = device->region.extents.y1;
            device->workRegion.extents.y2 = device->region.extents.y2;
      }

      for (w = s->windows; w; w = w->next)
      {
            if (w->attrib.map_state == IsUnmapped)
                  continue;

            if (w->struts)
            {
                  /* Temporary sanity test to  provoke xprop feedback where
                   * struts mess up.
                   */
                  if ((w->struts->left.width > s->width / 2)
                        || (w->struts->right.width >
                              s->width / 2)
                        || (w->struts->top.height >
                              s->height / 2)
                        || (w->struts->bottom.height > s->height / 2))
                  {
                        fprintf(stderr, "Window reported insane struts!\n");
                        fprintf(stderr,
                                    "Please run xprop on all your panels "
                                    "and post a bugreport to solve this.\n");
                  }
                  else
                  {
                        if (s->nOutputDev > 1)
                              updateWorkareaForScreen_outputWindow(s, w);

                        if (w->struts->left.width > leftStrut)
                              leftStrut = w->struts->left.width;

                        if (w->struts->right.width > rightStrut)
                              rightStrut = w->struts->right.width;

                        if (w->struts->top.height > topStrut)
                              topStrut = w->struts->top.height;

                        if (w->struts->bottom.height > bottomStrut)
                              bottomStrut = w->struts->bottom.height;
                  }
            }
      }

#define MIN_SANE_AREA 100

      if ((leftStrut + rightStrut) > (s->width - MIN_SANE_AREA))
      {
            leftStrut = (s->width - MIN_SANE_AREA) / 2;
            rightStrut = leftStrut;
      }

      if ((topStrut + bottomStrut) > (s->height - MIN_SANE_AREA))
      {
            topStrut = (s->height - MIN_SANE_AREA) / 2;
            bottomStrut = topStrut;
      }

      workArea.x = leftStrut;
      workArea.y = topStrut;
      workArea.width = s->width - leftStrut - rightStrut;
      workArea.height = s->height - topStrut - bottomStrut;

      if (s->nOutputDev == 1)
      {
            s->outputDev->workRegion.extents.x1 = leftStrut;
            s->outputDev->workRegion.extents.y1 = topStrut;
            s->outputDev->workRegion.extents.x2 = s->width - rightStrut;
            s->outputDev->workRegion.extents.y2 = s->height - bottomStrut;
      }

      if (memcmp(&workArea, &s->workArea, sizeof(XRectangle)))
      {
            s->workArea = workArea;

            setDesktopHints(s);
      }
}

static inline Bool isClientListWindow(CompWindow * w)
{
      /* windows with client id less than 2 have been destroyed and only exists
         because some plugin keeps a reference to them. they should not be in
         client lists */
      if (w->id < 2)
            return FALSE;

      if (w->attrib.override_redirect)
            return FALSE;

      if (w->attrib.map_state != IsViewable)
      {
            if (!(w->state & CompWindowStateHiddenMask))
                  return FALSE;
      }

      return TRUE;
}

static inline void countClientListWindow(CompWindow * w, void *closure)
{
      if (isClientListWindow(w))
      {
            int *num = (int *)closure;

            *num = *num + 1;
      }
}

static void addClientListWindow(CompWindow * w, void *closure)
{
      if (isClientListWindow(w))
      {
            int *num = (int *)closure;

            w->screen->clientList[*num] = w;
            *num = *num + 1;
      }
}

static int compareMappingOrder(const void *w1, const void *w2)
{
      return (*((CompWindow **) w1))->mapNum - (*((CompWindow **) w2))->mapNum;
}

void updateClientListForScreen(CompScreen * s)
{
      Window *clientList;
      Window *clientListStacking;
      Bool updateClientList = FALSE;
      Bool updateClientListStacking = FALSE;
      int i, n = 0;

      forEachWindowOnScreen(s, countClientListWindow, (void *)&n);

      if (n == 0)
      {
            if (n != s->nClientList)
            {
                  free(s->clientList);

                  s->clientList = NULL;
                  s->nClientList = 0;

                  XChangeProperty(s->display->display, s->root,
                                          s->display->clientListAtom,
                                          XA_WINDOW, 32, PropModeReplace,
                                          (unsigned char *)&s->grabWindow, 1);
                  XChangeProperty(s->display->display, s->root,
                                          s->display->clientListStackingAtom,
                                          XA_WINDOW, 32, PropModeReplace,
                                          (unsigned char *)&s->grabWindow, 1);
            }

            return;
      }

      if (n != s->nClientList)
      {
            CompWindow **list;

            list = realloc(s->clientList,
                                 (sizeof(CompWindow *) + sizeof(Window) * 2) * n);
            if (!list)
                  return;

            s->clientList = list;
            s->nClientList = n;

            updateClientList = updateClientListStacking = TRUE;
      }

      clientList = (Window *) (s->clientList + n);
      clientListStacking = clientList + n;

      i = 0;
      forEachWindowOnScreen(s, addClientListWindow, (void *)&i);

      for (i = 0; i < n; i++)
      {
            if (!updateClientListStacking)
            {
                  if (clientListStacking[i] != s->clientList[i]->id)
                        updateClientListStacking = TRUE;
            }

            clientListStacking[i] = s->clientList[i]->id;
      }

      /* sort window list in mapping order */
      qsort(s->clientList, n, sizeof(CompWindow *), compareMappingOrder);

      for (i = 0; i < n; i++)
      {
            if (!updateClientList)
            {
                  if (clientList[i] != s->clientList[i]->id)
                        updateClientList = TRUE;
            }

            clientList[i] = s->clientList[i]->id;
      }

      if (updateClientList)
            XChangeProperty(s->display->display, s->root,
                                    s->display->clientListAtom,
                                    XA_WINDOW, 32, PropModeReplace,
                                    (unsigned char *)clientList, s->nClientList);

      if (updateClientListStacking)
            XChangeProperty(s->display->display, s->root,
                                    s->display->clientListStackingAtom,
                                    XA_WINDOW, 32, PropModeReplace,
                                    (unsigned char *)clientListStacking, s->nClientList);
}

Window getActiveWindow(CompDisplay * display, Window root)
{
      Atom actual;
      int result, format;
      unsigned long n, left;
      unsigned char *data;
      Window w = None;

      result = XGetWindowProperty(display->display, root,
                                                display->winActiveAtom, 0L, 1L, FALSE,
                                                XA_WINDOW, &actual, &format,
                                                &n, &left, &data);

      if (result == Success && n && data)
      {
            memcpy(&w, data, sizeof(Window));
            XFree(data);
      }

      return w;
}

void
toolkitAction(CompScreen * s,
                    Atom toolkitAction,
                    Time eventTime,
                    Window window, long data0, long data1, long data2)
{
      XEvent ev;

      ev.type = ClientMessage;
      ev.xclient.window = window;
      ev.xclient.message_type = s->display->toolkitActionAtom;
      ev.xclient.format = 32;
      ev.xclient.data.l[0] = toolkitAction;
      ev.xclient.data.l[1] = eventTime;
      ev.xclient.data.l[2] = data0;
      ev.xclient.data.l[3] = data1;
      ev.xclient.data.l[4] = data2;

      XUngrabPointer(s->display->display, CurrentTime);
      XUngrabKeyboard(s->display->display, CurrentTime);

      XSendEvent(s->display->display, s->root, FALSE, StructureNotifyMask, &ev);
}

void runCommand(CompScreen * s, const char *command)
{
      if (*command == '\0')
            return;

      if (fork() == 0)
      {
            setsid();
            putenv(s->display->displayString);
            execl("/bin/sh", "/bin/sh", "-c", command, NULL);
            exit(0);
      }
}

void moveScreenViewport(CompScreen * s, int tx, int ty, Bool sync)
{
      CompWindow *w;
      int m, wx, wy, vWidth, vHeight;

      tx = s->x - tx;
      tx = MOD(tx, s->hsize);
      tx -= s->x;

      ty = s->y - ty;
      ty = MOD(ty, s->vsize);
      ty -= s->y;

      if (!tx && !ty)
            return;

      s->x += tx;
      s->y += ty;

      tx *= -s->width;
      ty *= -s->height;

      vWidth = s->width * s->hsize;
      vHeight = s->height * s->vsize;

      for (w = s->windows; w; w = w->next)
      {
            if (w->attrib.override_redirect)
                  continue;

            if (!w->managed && w->attrib.map_state != IsViewable)
                  continue;

            if (w->type &  (CompWindowTypeDockMask))
                  continue;

            if (w->wmType &  (CompWindowTypeDockMask))
                  continue;

            if ((w->type & (CompWindowTypeDesktopMask)) && (!s->display->opt[COMP_DISPLAY_OPTION_BIG_VIEWPORT_MANAGER].value.b && !s->berylDesktopManaged))
                  continue;

            if (w->state & (CompWindowStateStickyMask | CompWindowStateOffscreenMask))
                  continue;

            /* x */
            m = w->attrib.x + tx;
            if (m - w->input.left < s->width - vWidth)
                  wx = tx + vWidth;
            else if (m + w->width + w->input.right > vWidth)
                  wx = tx - vWidth;
            else
                  wx = tx;

            if (w->saveMask & CWX)
                  w->saveWc.x += wx;


            /* y */
            if (s->vsize > 1)
            {
                  m = w->attrib.y + ty;
                  if (m - w->input.top < s->height - vHeight)
                        wy = ty + vHeight;
                  else if (m + w->height + w->input.bottom > vHeight)
                        wy = ty - vHeight;
                  else
                        wy = ty;
            }
            else
                  wy = ty;

            if (w->saveMask & CWY)
                  w->saveWc.y += wy;

            /* move */

            moveWindow(w, wx, wy, sync, TRUE);

            if (sync)
                  syncWindowPosition(w);
      }

      if (sync)
            setDesktopHints(s);
}

void moveWindowToViewportPosition(CompWindow * w, int x, Bool sync)
{
      int tx, vWidth = w->screen->width * w->screen->hsize;

      x += w->screen->x * w->screen->width;
      x = MOD(x, vWidth);
      x -= w->screen->x * w->screen->width;

      tx = x - w->attrib.x;
      if (tx)
      {
            int m, wx;

            if (!w->managed)
                  return;

            if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
                  return;

            if (w->state & CompWindowStateStickyMask)
                  return;

            m = w->attrib.x + tx;
            if (m - w->output.left < w->screen->width - vWidth)
                  wx = tx + vWidth;
            else if (m + w->width + w->output.right > vWidth)
                  wx = tx - vWidth;
            else
                  wx = tx;

            if (w->saveMask & CWX)
                  w->saveWc.x += wx;

            moveWindow(w, wx, 0, sync, TRUE);

            if (sync)
                  syncWindowPosition(w);
      }
}

CompGroup *addGroupToScreen(CompScreen * s, Window id)
{
      CompGroup *group;

      group = malloc(sizeof(CompGroup));
      if (!group)
            return NULL;

      group->next = s->groups;
      group->refCnt = 1;
      group->id = id;

      s->groups = group;

      return group;
}

void removeGroupFromScreen(CompScreen * s, CompGroup * group)
{
      group->refCnt--;
      if (group->refCnt)
            return;

      if (group == s->groups)
      {
            s->groups = group->next;
      }
      else
      {
            CompGroup *g;

            for (g = s->groups; g; g = g->next)
            {
                  if (g->next == group)
                  {
                        g->next = group->next;
                        break;
                  }
            }
      }

      free(group);
}

CompGroup *findGroupAtScreen(CompScreen * s, Window id)
{
      CompGroup *g;

      for (g = s->groups; g; g = g->next)
            if (g->id == id)
                  return g;

      return NULL;
}

void applyStartupProperties(CompScreen * screen, CompWindow * window)
{
      CompStartupSequence *s;
      const char *startupId = window->startupId;

      if (!startupId)
      {
            CompWindow *leader;

            leader = findWindowAtScreen(screen, window->clientLeader);
            if (leader)
                  startupId = leader->startupId;

            if (!startupId)
                  return;
      }

      for (s = screen->startupSequences; s; s = s->next)
      {
            const char *id;

            id = sn_startup_sequence_get_id(s->sequence);
            if (strcmp(id, startupId) == 0)
                  break;
      }

      if (s)
      {
            window->initialViewportX = s->viewportX;
            window->initialViewportY = s->viewportY;

            window->desktop = sn_startup_sequence_get_workspace(s->sequence);

            window->initialTimestamp =
                  sn_startup_sequence_get_timestamp (s->sequence);
            window->initialTimestampSet = TRUE;

            if (window->desktop == (unsigned int)-1)
            {
                  /*   0xffffffff == -1
                     We should make ->desktop unsigned
                     Check also done in openbox 3.0 WM,
                     but there the result is invalidated
                   */
                  window->desktop = screen->currentDesktop;
            }
      }
}

void enterShowDesktopMode(CompScreen * s)
{
      CompDisplay *d = s->display;
      CompWindow *w;
      unsigned long data = 1;
      int count = 0;
      CompOption *st = &d->opt[COMP_DISPLAY_OPTION_HIDE_SKIP_TASKBAR_WINDOWS];

      s->showingDesktopMask = ~(CompWindowTypeDesktopMask |
                                            CompWindowTypeDockMask);

      for (w = s->windows; w; w = w->next)
      {
            if ((s->showingDesktopMask & w->type) &&
                  (!(w->state & CompWindowStateSkipTaskbarMask) || st->value.b))
            {
                  if ((*s->focusWindow) (w))
                  {
                        w->inShowDesktopMode = TRUE;
                        hideWindow(w);
                  }
            }

            if (w->inShowDesktopMode)
                  count++;
      }

      if (!count)
      {
            s->showingDesktopMask = 0;
            data = 0;
      }

      XChangeProperty(s->display->display, s->root,
                              s->display->showingDesktopAtom,
                              XA_CARDINAL, 32, PropModeReplace,
                              (unsigned char *)&data, 1);
}

void leaveShowDesktopMode(CompScreen * s, CompWindow * window)
{
      CompWindow *w;
      unsigned long data = 0;

      if (window)
      {
            if (!window->inShowDesktopMode)
                  return;

            window->inShowDesktopMode = FALSE;
            showWindow(window);

            /* return if some other window is still in show desktop mode */
            for (w = s->windows; w; w = w->next)
                  if (w->inShowDesktopMode)
                        return;

            s->showingDesktopMask = 0;
      }
      else
      {
            s->showingDesktopMask = 0;

            for (w = s->windows; w; w = w->next)
            {
                  if (!w->inShowDesktopMode)
                        continue;

                  w->inShowDesktopMode = FALSE;
                  showWindow(w);
            }
      }

      XChangeProperty(s->display->display, s->root,
                              s->display->showingDesktopAtom,
                              XA_CARDINAL, 32, PropModeReplace,
                              (unsigned char *)&data, 1);
}

void sendWindowActivationRequest(CompScreen * s, Window id)
{
      XEvent xev;

      xev.xclient.type = ClientMessage;
      xev.xclient.display = s->display->display;
      xev.xclient.format = 32;

      xev.xclient.message_type = s->display->winActiveAtom;
      xev.xclient.window = id;

      xev.xclient.data.l[0] = 2;
      xev.xclient.data.l[1] = 0;
      xev.xclient.data.l[2] = 0;
      xev.xclient.data.l[3] = 0;
      xev.xclient.data.l[4] = 0;

      XSendEvent(s->display->display,
                     s->root,
                     FALSE,
                     SubstructureRedirectMask | SubstructureNotifyMask, &xev);
}

void changeToWindowViewport(CompScreen * s, Window id, CompWindow * w)
{
      XEvent xev;
      int i, j;

      defaultViewportForWindow(w, &i, &j);

      xev.xclient.type = ClientMessage;
      xev.xclient.display = s->display->display;
      xev.xclient.format = 32;

      xev.xclient.message_type = s->display->desktopViewportAtom;
      xev.xclient.window = s->root;

      xev.xclient.data.l[0] = i * s->width;
      xev.xclient.data.l[1] = j * s->height;
      xev.xclient.data.l[2] = 0;
      xev.xclient.data.l[3] = 0;
      xev.xclient.data.l[4] = 0;

      XSendEvent(s->display->display,
                     s->root,
                     FALSE,
                     SubstructureRedirectMask | SubstructureNotifyMask, &xev);
}

void screenTexEnvMode(CompScreen * s, GLenum mode)
{
      if (s->lighting)
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
      else
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode);
}

void screenLighting(CompScreen * s, Bool lighting)
{
      if (s->lighting != lighting)
      {
            if (!s->opt[COMP_SCREEN_OPTION_LIGHTING].value.b)
                  lighting = FALSE;

            if (lighting)
            {
                  glEnable(GL_COLOR_MATERIAL);
                  glEnable(GL_LIGHTING);
            }
            else
            {
                  glDisable(GL_COLOR_MATERIAL);
                  glDisable(GL_LIGHTING);
            }

            s->lighting = lighting;

            screenTexEnvMode(s, GL_REPLACE);
      }
}

void enableScreenEdge(CompScreen * s, int edge)
{
      s->screenEdge[edge].count++;
      if (s->screenEdge[edge].count == 1)
            XMapRaised(s->display->display, s->screenEdge[edge].id);
}

void disableScreenEdge(CompScreen * s, int edge)
{
      s->screenEdge[edge].count--;
      if (s->screenEdge[edge].count == 0)
            XUnmapWindow(s->display->display, s->screenEdge[edge].id);
}

Window getTopWindow(CompScreen * s)
{
      CompWindow *w;

      /* return first window that has not been destroyed */
      for (w = s->reverseWindows; w; w = w->prev)
      {
            if (w->id > 1)
                  return w->id;
      }

      return None;
}

void makeScreenCurrent(CompScreen * s)
{
      if (currentRoot != s->root)
      {
            glXMakeCurrent(s->display->display, s->output, s->ctx);
            currentRoot = s->root;
      }
      s->pendingCommands = TRUE;
}

void finishScreenDrawing(CompScreen * s)
{
      if (s->pendingCommands)
      {
            makeScreenCurrent(s);
            glFinish();

            s->pendingCommands = FALSE;
      }
}

int outputDeviceForPoint(CompScreen * s, int x, int y)
{
      int i, x1, y1, x2, y2;

      for (i = 0; i < s->nOutputDev; i++)
      {
            x1 = s->outputDev[i].region.extents.x1;
            y1 = s->outputDev[i].region.extents.y1;
            x2 = s->outputDev[i].region.extents.x2;
            y2 = s->outputDev[i].region.extents.y2;

            if (x1 <= x && x2 > x && y1 <= y && y2 > y)
                  return i;
      }

      return s->currentOutputDev;
}

void setNumberOfDesktops(CompScreen * s, unsigned int nDesktop)
{
      CompWindow *w;

      if (nDesktop < 1 || nDesktop >= 0xffffffff)
            return;

      if (nDesktop == s->nDesktop)
            return;

      if (s->currentDesktop >= nDesktop)
            s->currentDesktop = nDesktop - 1;

      for (w = s->windows; w; w = w->next)
      {
            if (w->desktop == 0xffffffff)
                  continue;

            if (w->desktop >= nDesktop)
                  setDesktopForWindow(w, nDesktop - 1);
      }

      s->nDesktop = nDesktop;

      setDesktopHints(s);
}

void setCurrentDesktop(CompScreen * s, unsigned int desktop)
{
      unsigned long data;
      CompWindow *w;

      if (desktop >= s->nDesktop)
            return;

      if (desktop == s->currentDesktop)
            return;

      s->currentDesktop = desktop;

      for (w = s->windows; w; w = w->next)
      {
            if (w->desktop == 0xffffffff)
                  continue;

            if (w->desktop == desktop)
                  showWindow(w);
            else
                  hideWindow(w);
      }

      data = desktop;

      XChangeProperty(s->display->display, s->root,
                              s->display->currentDesktopAtom,
                              XA_CARDINAL, 32, PropModeReplace,
                              (unsigned char *)&data, 1);
}

void
getCurrentOutputExtents(CompScreen * s, int *x1, int *y1, int *x2, int *y2)
{
      if (x1)
            *x1 = s->outputDev[s->currentOutputDev].region.extents.x1;

      if (y1)
            *y1 = s->outputDev[s->currentOutputDev].region.extents.y1;

      if (x2)
            *x2 = s->outputDev[s->currentOutputDev].region.extents.x2;

      if (y2)
            *y2 = s->outputDev[s->currentOutputDev].region.extents.y2;
}

void setDefaultViewport(CompScreen * s)
{
      glViewport(s->outputDev[0].region.extents.x1,
                     s->height - s->outputDev[0].region.extents.y2,
                     s->outputDev[0].width, s->outputDev[0].height);
}

void outputChangeNotify(CompScreen * s)
{
}

void clearScreenOutput(CompScreen * s, int output, unsigned int mask)
{
      BoxPtr pBox = &s->outputDev[output].region.extents;

      if (pBox->x1 != 0 ||
            pBox->y1 != 0 || pBox->x2 != s->width || pBox->y2 != s->height)
      {
            glPushAttrib(GL_SCISSOR_BIT);

            glEnable(GL_SCISSOR_TEST);
            glScissor(pBox->x1,
                          s->height - pBox->y2,
                          pBox->x2 - pBox->x1, pBox->y2 - pBox->y1);
            glClear(mask);

            glPopAttrib();
      }
      else
      {
            glClear(mask);
      }
}

Bool updateDefaultIcon(CompScreen * screen)
{
      CompIcon *icon;
      char *file = screen->opt[COMP_SCREEN_OPTION_DEFAULT_ICON].value.s;
      void *data;
      int width, height;

      if (screen->defaultIcon)
      {
            finiTexture(screen, &screen->defaultIcon->texture);
            free(screen->defaultIcon);
            screen->defaultIcon = NULL;
      }

      if (!readImageFromFile(screen->display, file, &width, &height, &data))
            return FALSE;

      icon = malloc(sizeof(CompIcon) + width * height * sizeof(CARD32));
      if (!icon)
      {
            free(data);
            return FALSE;
      }

      initTexture(screen, &icon->texture);

      icon->width = width;
      icon->height = height;

      memcpy(icon + 1, data, +width * height * sizeof(CARD32));

      screen->defaultIcon = icon;

      free(data);

      return TRUE;
}

void setClipPlanes (CompScreen   *screen, int output)
{
      static GLdouble clipPlane0[] = {  0.0, -1.0, 0.0, 0.5 };
      static GLdouble clipPlane1[] = {  0.0,  1.0, 0.0, 0.5 };
      static GLdouble clipPlane2[] = {  1.0,  0.0, 0.0, 0.5 };
      static GLdouble clipPlane3[] = { -1.0,  0.0, 0.0, 0.5 };

      glClipPlane (GL_CLIP_PLANE0, clipPlane0);
      glClipPlane (GL_CLIP_PLANE1, clipPlane1);
      glClipPlane (GL_CLIP_PLANE2, clipPlane2);
      glClipPlane (GL_CLIP_PLANE3, clipPlane3);
}

Generated by  Doxygen 1.6.0   Back to index