Logo Search packages:      
Sourcecode: nawm version File versions  Download package

cache.c

/* cache.c: the window cache */

/* Copyright (C) 1999 by the Massachusetts Institute of Technology.
 *
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting
 * documentation, and that the name of M.I.T. not be used in
 * advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 */

#include "nawm.h"
#include "cache.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>

extern Display *dpy;
extern Window root;
extern int debug, window_manager;

cacheinfo *cachehead;
int cachedebug;
static Atom XA_WM_STATE;

int is_client_window(Window win);
Window client_window(Window win);
Window client_window_internal(Window win);
void cachewin(Window win);
void uncachewin(Window win);
void destroycache(void);

void initcache(void)
{
  Window rootret, parent, *children;
  unsigned int numchildren, n;

  cachehead = NULL;
  XA_WM_STATE = XInternAtom(dpy, "WM_STATE", False);

  XQueryTree(dpy, root, &rootret, &parent, &children, &numchildren);
  for (n = 0; n < numchildren; n++)
    {
      cachewin(client_window(children[n]));
      cachewin(children[n]);
    }
  XFree(children);
}

void destroycache(void)
{
  cacheinfo *ci, *cin;

  for (ci = cachehead; ci; ci = cin)
    {
      XFree(ci->names[0]);
      if (ci->numnames > 1)
      XFree(ci->names[1]);
      cin = ci->next;
      free(ci);
    }
}  

void cachewin(Window win)
{
  cacheinfo *new;
  unsigned long items, left;
  unsigned char *name, *prop;
  Atom type;
  int format, n;
  Window cwin;
  XWindowAttributes attr;

  XGetWindowAttributes(dpy, win, &attr);

  cwin = client_window(win);
  if (win != cwin)
    {
      cacheinfo *ci;
      for (ci = cachehead; ci; ci = ci->next)
      {
        if (ci->win == cwin)
          {
            ci->parent = win;
            ci->x = attr.x - attr.border_width;
            ci->y = attr.y - attr.border_width;
            ci->w = attr.width + 2 * attr.border_width;
            ci->h = attr.height + 2 * attr.border_width;
          }
      }
      return;
    }

  /* Select Enter/Leave events on this window */
  XSelectInput(dpy, win, attr.your_event_mask |
             EnterWindowMask | LeaveWindowMask);

  if (XGetWindowProperty(dpy, win, XA_WM_NAME, 0, 1000, False,
                   AnyPropertyType, &type, &format, &items,
                   &left, &name) != Success)
    return;
  if (!items)
    {
      XFree(name);
      return;
    }

  XGetWindowProperty(dpy, win, XA_WM_CLASS, 0, 1000, False, AnyPropertyType,
                 &type, &format, &items, &left, &prop);
  new = xmalloc(sizeof(cacheinfo) + (items * sizeof(char *)));
  new->next = cachehead;
  new->win = win;
  new->parent = (Window)0;
  new->x = attr.x - attr.border_width;
  new->y = attr.y - attr.border_width;
  new->w = attr.width + 2 * attr.border_width;
  new->h = attr.height + 2 * attr.border_width;
  new->mapped = attr.map_state == IsViewable;
  new->names[0] = (char *)name;
  if (items)
    {
      for (n = 1; *prop; n++)
      {
        new->names[n] = (char *)prop;
        prop = (unsigned char *)strchr((char *)prop, '\0') + 1;
      }
      new->numnames = n;
    }
  else
    {
      XFree(prop);
      new->numnames = 1;
    }
  cachehead = new;
}

void uncachewin(Window win)
{
  cacheinfo *ci, *prev;

  for (ci = cachehead, prev = NULL; ci; prev = ci, ci = ci->next)
    {
      if (ci->win == win || ci->parent == win)
      break;
    }

  if (!ci)
    return;
  if (!prev)
    cachehead = ci->next;
  else
    prev->next = ci->next;

  XFree(ci->names[0]);
  if (ci->numnames>1)
    XFree(ci->names[1]);
}

void update_cache(XEvent *ev)
{
  Window win = ev->xconfigure.window;
  cacheinfo *ci;

  if (ev->type == CreateNotify)
    {
      cachewin(win);
      return;
    }
  else if (ev->type == DestroyNotify)
    {
      uncachewin(win);
      return;
    }

  for (ci = cachehead; ci; ci = ci->next)
    {
      if (ci->win == win || ci->parent == win)
      break;
    }
  if (!ci)
    {
      cachewin(win);
      return;
    }

  if (ev->type == ConfigureNotify)
    {
      XConfigureEvent *xcev = (XConfigureEvent *)ev;

      ci->x = xcev->x - xcev->border_width;
      ci->y = xcev->y - xcev->border_width;
      ci->w = xcev->width + 2 * xcev->border_width;
      ci->h = xcev->height + 2 * xcev->border_width;
    }
  else if (ev->type == MapNotify)
    ci->mapped = 1;
  else if (ev->type == UnmapNotify)
    ci->mapped = 0;
}

Window client_window(Window win)
{
  if (window_manager != NAWM_WM_NAWM)
    {
      Window cw;
      cacheinfo ci;

      /* First try the cache. */
      ci.win = win;
      if (find_window(&ci, NAWM_CACHE_WINDOW))
      return ci.win;

      /* Now actually look for it. */
      cw = client_window_internal(win);
      if (cw)
      return cw;
    }
  return win;
}

Window client_window_internal(Window win)
{
  Window root, parent;
  Window *children;
  unsigned int nchildren;
  unsigned int i;
  Window inf = 0;

  if (is_client_window(win))
    return win;

  if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
    return 0;
  for (i = 0; !inf && (i < nchildren); i++)
    inf = client_window_internal(children[i]);

  if (children)
    XFree((char *)children);
  return inf ? inf : 0;
}

int is_client_window(Window win)
{
  Atom type = None;
  int format;
  unsigned long nitems, after;
  unsigned char *data = NULL;

  XGetWindowProperty(dpy, win, XA_WM_STATE, 0, 0, False, AnyPropertyType,
                 &type, &format, &nitems, &after, &data);
  if (data)
    XFree((char*)data);
  if (type)
    return 1;
  return 0;
}

Window manager_window(Window win)
{
  if (window_manager == NAWM_WM_NAWM)
    return win;
  else
    {
      Window root, parent, *children;
      unsigned int nchildren;
      cacheinfo ci;

      /* First try the cache */
      ci.win = win;
      if (find_window(&ci, NAWM_CACHE_WINDOW))
      return ci.parent ? ci.parent : ci.win;

      if (!is_client_window(win))
      return win;

      if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
      return win;
      if (children)
      XFree((char *)children);
      if (!parent || (parent == root))
      return win;
      return parent;
    }
}

int hasname(Window win, char *name)
{
  cacheinfo ci;
  int n;

  ci.win = win;
  ci.names[0] = name;
  return find_window(&ci, NAWM_CACHE_WINDOW | NAWM_CACHE_NAME);
}

int find_window(cacheinfo *match, long mask)
{
  cacheinfo *ci;
  int try = 1;

retry:
  for (ci = cachehead; ci; ci = ci->next)
    {
      if (mask & NAWM_CACHE_WINDOW)
      {
        if ((match->win != ci->win) && (match->win != ci->parent))
          continue;
      }
      else
      {
        if ((mask & NAWM_CACHE_CLIENT) && (match->win != ci->win))
          continue;

        if ((mask & NAWM_CACHE_PARENT) && (match->win != ci->parent))
          continue;
      }

      if (((mask & NAWM_CACHE_MAPPED) || (mask & NAWM_CACHE_LOCATION))
        && !ci->mapped)
      continue;
      if (mask & NAWM_CACHE_LOCATION)
      {
        if (match->x < ci->x || match->x > ci->x + ci->w)
          continue;
        if (match->y < ci->y || match->y > ci->y + ci->w)
          continue;
      }

      if (mask & NAWM_CACHE_NAME)
      {
        int n;
        for (n = 0; n < ci->numnames; n++)
          {
            if (!strcmp(match->names[0], ci->names[n]))
            break;
          }
        if (n == ci->numnames)
          continue;
      }

      break;
    }

  if (!ci)
    {
      if ((mask & NAWM_CACHE_RETRY) && (try == 1))
      {
        if (cachedebug)
          fprintf(stderr, "nawm: rebuilding cache\n");
        destroycache();
        initcache();
        try++;
        goto retry;
      }

      return 0;
    }

  memcpy(match, ci, sizeof(*ci));
  if (match->numnames)
    match->numnames = 1;
  return 1;
}

void dumpcache(void)
{
  cacheinfo *ci;
  int i;

  for (ci = cachehead; ci; ci = ci->next)
    {
      printf("Window 0x%lx (%ld) is %dx%d%s%d%s%d, %smapped, has parent "
           "0x%lx (%ld) and names ", (long)ci->win, (long)ci->win,
           ci->w, ci->h, ci->x >= 0 ? "+" : "", ci->x,
           ci->y >= 0 ? "+" : "", ci->y, ci->mapped ? "" : "un",
           (long)ci->parent, (long)ci->parent);
      for (i = 0; i < ci->numnames; i++)
      {
        printf("\"%s\"%s", ci->names[i],
             i == ci->numnames - 1 ? "\n" : ", ");
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index