/*
 * event.cc
 *
 * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai
 * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes
 *
 * 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 blwm; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifdef __EMX__
#include <sys/select.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/shape.h>
#ifdef USE_XSMP
#include <X11/ICE/ICElib.h>
#endif
#include "main.h"
#include "misc.h"
#include "blwm.h"
#include "event.h"
#include "taskbar.h"
#include "fbutton.h"
#include "tbutton.h"
#include "sbutton.h"
#include "startmenu.h"
#include "menu.h"
#include "util.h"
#include "icon.h"
#include "blwmrc.h"
#include "paging.h"
#include "pager.h"
#include "mini.h"
#include "key.h"
#include "indicator.h"
#include "timer.h"
#include "focus_mgr.h"
#include "desktop.h"
#include "gnome.h"
#include "tooltip.h"
#include "session.h"
#include "remote_cmd.h"


#if defined(sun) && !defined(__SVR4)
extern "C" int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 8
# else
extern "C" void bzero(char *, int);
# endif
#endif

Blwm*	Blwm::focusBlwm;

/*
 * MainLoop --
 *   Wait event and timeout.
 */
void Event::MainLoop()
{  
  XEvent ev;
  int fd = ConnectionNumber(display);
  fd_set fds;
  struct timeval tm, *timep;
  int fdMax;
#ifdef USE_XSMP
//  int s;
  int iceConnFd;
#endif

#ifdef ALLOW_RMTCMD
  int rmtCmdFd = -1;
#endif

  while (1) {
     while (XPending(display) != 0) {
       XNextEvent(display, &ev);
       DispatchEvent(ev);
 
       timer->CheckTimeout(&tm);
     }
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    fdMax = fd;

#ifdef USE_XSMP
    iceConnFd = session->GetIceConnFd();
    if (iceConnFd >= 0) {
      FD_SET(iceConnFd, &fds);
       if (iceConnFd > fdMax) {
	fdMax = iceConnFd;
      }
    }
#endif // USE_XSMP

#ifdef ALLOW_RMTCMD
     if (AllowRemoteCmd) {
       rmtCmdFd = remoteCmd->getRmtCmdFd();
       if (rmtCmdFd >= 0) {
 	FD_SET(rmtCmdFd, &fds);
 	if (rmtCmdFd > fdMax)
 	  fdMax = rmtCmdFd;
       }
}
#endif // ALLOW_RMTCMD

/* ???
#ifdef USE_XSMP
    // Why we should waitpid here, ...
    waitpid(-1, &s, WNOHANG);
#endif
*/

    /*
     * If next timeout does not exist, select blocks until next events.
     */
    if (!timer->CheckTimeout(&tm))
      timep = NULL;
    else
      timep = &tm;

    // Flush all requests before select, or some requests is not
    // flushed until select is returned.
    XFlush(display);

    if (XPending(display) > 0)
      continue;

#if defined(__hpux) && !defined(_XPG4_EXTENDED)
    if (select(fdMax + 1, (int *)&fds, 0, 0, timep) == 0) {    // timeout
#else
    if (select(fdMax + 1, &fds, 0, 0, timep) == 0) {    // timeout
#endif
      timer->CheckTimeout(&tm);
    }
#ifdef USE_XSMP
    else if (iceConnFd >=0 && FD_ISSET(iceConnFd, &fds)) {
      Bool res;
      IceProcessMessagesStatus rc;
      rc = IceProcessMessages(session->GetIceConn(), NULL, &res);
      if (rc == IceProcessMessagesIOError) {
	session->CloseConnection();
      }
      //else if (rc == IceProcessMessagesConnectionClosed) {
      //}
    }
#endif // USE_XSMP
#ifdef ALLOW_RMTCMD
     else if (rmtCmdFd >= 0 && FD_ISSET(rmtCmdFd, &fds)) {
      remoteCmd->process();
     }
#endif

  }
}

/*
 * DispatchEvent --
 *   Call the event procedure according to a event type.
 */
void Event::DispatchEvent(const XEvent& ev)
{
  switch (ev.type) {
  case Expose: {
    const XExposeEvent& xev = (const XExposeEvent &)ev;
    ExposeProc(xev);
    break;
  }

  case EnterNotify: {
    const XCrossingEvent& xev = (const XCrossingEvent &)ev;
    EnterNotifyProc(xev);
    break;
  }

  case LeaveNotify: {
    const XCrossingEvent& xev = (const XCrossingEvent &)ev;
    LeaveNotifyProc(xev);
    break;
  }

  case MotionNotify: {
    const XMotionEvent& xev = (const XMotionEvent &)ev;
    MotionNotifyProc(xev);
    break;
  }

  case MapRequest: {
    const XMapRequestEvent& xev = (const XMapRequestEvent &)ev;
    MapRequestProc(xev);
    break;
  }

  case MapNotify: {
    const XMapEvent& xev = (const XMapEvent &)ev;
    MapNotifyProc(xev);
    break;
  }

  case UnmapNotify: {
    if (ev.xany.window == root)
      return;
    const XUnmapEvent& xev = (const XUnmapEvent &)ev;
    UnmapNotifyProc(xev);
    break;
  }

  case DestroyNotify: {
    const XDestroyWindowEvent& xev = (const XDestroyWindowEvent &)ev;
    DestroyNotifyProc(xev);
    break;
  }

  case ButtonPress: {
    const XButtonEvent& xev = (const XButtonEvent &)ev;
    ButtonPressProc(xev);
    ptPrevRoot = Point(xev.x_root, xev.y_root);
    break;
  }

  case ButtonRelease: {
    const XButtonEvent& xev = (const XButtonEvent &)ev;
    ButtonReleaseProc(xev);
    break;
  }

  case KeyPress: {
    const XKeyEvent& xev = (const XKeyEvent &)ev;
    KeyPressProc(xev);
    break;
  }

  case ClientMessage: {
    const XClientMessageEvent& xev = (const XClientMessageEvent &)ev;
    ClientMessageProc(xev);
    break;
  }

  case ColormapNotify: {
    const XColormapEvent& xev = (const XColormapEvent &)ev;
    ColormapNotifyProc(xev);
    break;
  }

  case ConfigureRequest: {
    const XConfigureRequestEvent& xev = (const XConfigureRequestEvent &)ev;
    ConfigureRequestProc(xev);
    break;
  }

  case CirculateRequest: {
    const XCirculateRequestEvent& xev = (const XCirculateRequestEvent &)ev;
    CirculateRequestProc(xev);
    break;
  }

  case PropertyNotify: {
    const XPropertyEvent& xev = (const XPropertyEvent &)ev;
    PropertyNotifyProc(xev);
    break;
  }

  case FocusIn: {
    const XFocusChangeEvent& xev = (const XFocusChangeEvent &)ev;
    FocusInProc(xev);
    break;
  }

  case FocusOut:
    break;

  default:
    if (shapeSupport) {
      if (ev.type == shapeEventBase + ShapeNotify) {
	const XShapeEvent &xev = (const XShapeEvent &)ev;
	ShapeNotifyProc(xev);
      }
    }
    break;
  }
}

/*
 * ExposeProc --
 *   Process Expose event.
 */
void Event::ExposeProc(const XExposeEvent& ev)
{
  Blwm* blWm;
  Button* button;
  Menu* menu;
  Icon* icon;
  Miniature* mini;
  Tooltip* tt;
  XEvent xev;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    if (blWm == NULL)  /* XXX */
      return;
    blWm->Exposure(ev.window);
  }
  else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
	   == XCSUCCESS) {
    ASSERT(button);
    button->DrawButton();
  }
  else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
	   == XCSUCCESS) {
    ASSERT(menu);
    menu->DrawMenu(ev.window);
  }
  else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
	   == XCSUCCESS) {
    ASSERT(icon);
    icon->DrawIcon(icon == Icon::focusIcon);
  }
  else if (XFindContext(display, ev.window, Miniature::context,
			(caddr_t*)&mini) == XCSUCCESS) {
    ASSERT(mini);
    mini->DrawMiniature();
  }
  else if (XFindContext(display, ev.window, Tooltip::context, (caddr_t*)&tt)
	   == XCSUCCESS) {
    ASSERT(tt);
    tt->DrawTooltip();
  }
  else if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window)) {
    taskBar->Exposure(ev.window);
  }
  else if (UsePager && pager->IsPagerWindows(ev.window)) {
    pager->Exposure(ev.window);
  }
  else
    return;

  while (XCheckWindowEvent(display, ev.window, ExposureMask, &xev))
    ;
}

/*
 * EnterNotifyProc --
 *   Process EnterNotify event.
 */
void Event::EnterNotifyProc(const XCrossingEvent& ev)
{
  XEvent xev;
  Blwm* blWm;
  Menu* menu;
  Icon* icon;
  Button* button;
  Miniature* mini;

  /*
   * So that EnterNotify to taskbar is not canceled out by next LeaveNotify.
   */
  if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window)) {
    taskBar->Enter(ev.window, Point(ev.x_root, ev.y_root), ev.detail);
    return;
  }

  /*
   * Check if there is LeaveNotify event for the window and if so, return.
   */
  if (XCheckTypedWindowEvent(display, ev.window, LeaveNotify, &xev)) {
    if (xev.xcrossing.mode == NotifyNormal &&
	xev.xcrossing.detail != NotifyInferior)
      return;
  }

  ASSERT(paging);

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    blWm->Enter(ev.window, ev.state);
  }
  else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
      == XCSUCCESS) {
    ASSERT(menu);
    menu->Enter(ev.window);
  }
  else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
      == XCSUCCESS) {
    ASSERT(icon);
    icon->Enter();
  }
  else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
      == XCSUCCESS) {
    ASSERT(button);
    button->Enter();
  }
  else if (XFindContext(display, ev.window, Miniature::context,
			(caddr_t*)&mini) == XCSUCCESS) {
    ASSERT(mini);
    mini->Enter();
  }
}

/*
 * LeaveNotifyProc --
 *   Process LeaveNotify event.
 */
void Event::LeaveNotifyProc(const XCrossingEvent& ev)
{
  Blwm* blWm;
  Menu* menu;
  Icon* icon;
  Button* button;
  Miniature* mini;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    blWm->Leave(ev.window);
  }
  else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
      == XCSUCCESS) {
    ASSERT(menu);
    menu->Leave(ev.window);
  }
  else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
      == XCSUCCESS) {
    ASSERT(icon);
    icon->Leave();
  }
  else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
      == XCSUCCESS) {
    ASSERT(button);
    button->Leave();
  }
  else if (XFindContext(display, ev.window, Miniature::context,
			(caddr_t*)&mini) == XCSUCCESS) {
    ASSERT(mini);
    mini->Leave();
  }
  else if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window)) {
    taskBar->Leave(ev.window, Point(ev.x_root, ev.y_root), ev.detail);
  }
}

/*
 * MotionNotifyProc --
 *   Process MotionNotify event.
 */
void Event::MotionNotifyProc(const XMotionEvent& ev)
{
  Blwm* blWm;
  Menu* menu;
  Icon* icon;
  Button* button;
  Miniature* mini;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    if (ev.state & Button1Mask)
      blWm->Button1Motion(ev.window, ptPrevRoot);
    else if (ev.state & Button2Mask)
      blWm->Button2Motion(ev.window, ptPrevRoot);
    else
      blWm->PointerMotion(ev.window);
  }
  else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
	   == XCSUCCESS) {
    ASSERT(menu);
    menu->PointerMotion(ev.window);
  }
  else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
	   == XCSUCCESS) {
    ASSERT(icon);
    if (ev.state & Button1Mask)
      icon->Button1Motion(ptPrevRoot);
    else
      icon->PointerMotion();
  }
  else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
	   == XCSUCCESS) {
    ASSERT(button);
    button->PointerMotion();
  }
  else if (XFindContext(display, ev.window, Miniature::context,
			(caddr_t*)&mini) == XCSUCCESS) {
    ASSERT(mini);
    mini->PointerMotion();
  }
  else if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window)) {
    if (ev.state & Button1Mask)
      taskBar->Button1Motion(ev.window, ptPrevRoot);
    else
      taskBar->PointerMotion();
  }
}

/*
 * MapRequestProc --
 *   Process MapRequest event.
 */
void Event::MapRequestProc(const XMapRequestEvent& ev)
{
  /*
   * Check the window is valid.
   */
  Window junkRoot;
  Rect rcJunk;
  unsigned int junkBW, junkDepth;

  if (XGetGeometry(display, ev.window, &junkRoot, &rcJunk.x, &rcJunk.y,
		   (unsigned int *)&rcJunk.width,
		   (unsigned int *)&rcJunk.height,
		   &junkBW, &junkDepth) == 0)
    return;

  // Blwm deals with a window whose size is larger than 32768 as an invalid
  // window.  (This may be incorrect in some cases...)
  if ((short)rcJunk.width < 0 || (short)rcJunk.height < 0) {
    BlwmError("window size is probably invalid: %d(%d)x%d(%d)",
	      rcJunk.width, (short)rcJunk.width,
	      rcJunk.height, (short)rcJunk.height);
    return;
  }

  /*
   * If the name of the window is requested by Indicator, the window becomes
   * an indicator.
   */
  XTextProperty xtp;
  char** cl = NULL;
  int n;
  XClassHint classHints;
  Indicator* ind;
  char* title = "";

  if (XGetWMName(display, ev.window, &xtp) != 0) {
    XmbTextPropertyToTextList(display, &xtp, &cl, &n);
    if (cl)
      title = cl[0];
  }

  classHints.res_name = NULL;
  classHints.res_class = NULL;
  XGetClassHint(display, ev.window, &classHints);

  if ((ind = Indicator::LookInList(title, classHints))) {
    XFreeStringList(cl);
    if (classHints.res_name)
      XFree(classHints.res_name);
    if (classHints.res_class)
      XFree(classHints.res_class);

    ind->CreateIndicator(ev.window);
    return;
  }
  else {
    XFreeStringList(cl);
    if (classHints.res_name)
      XFree(classHints.res_name);
    if (classHints.res_class)
      XFree(classHints.res_class);
  }

  /*
   * Frame setup.
   */
  Blwm* blWm;
  XWMHints *wmHints;

  /*
   * If blWm has already created and is unmapped, need not create new blWm.
   */
  if ((blWm = desktop.LookInList(ev.window)) == NULL) {
    blWm = new Blwm(ev.window, False);
    desktop.GetBlwmList().InsertTail(blWm);
  }

  if (blWm->CheckFlags(CLOSE_SOON)) {
#ifdef DEBUG
    BlwmError("force to close a window: %s", blWm->GetName());
#endif
    XReparentWindow(display, ev.window, root,
		    rcScreen.x + rcScreen.width, rcScreen.y + rcScreen.height);
    blWm->CloseWindow();
    desktop.GetBlwmList().Remove(blWm);
    delete blWm;
    return;
  }

  wmHints = blWm->GetWMHints();

  if ((wmHints && (wmHints->flags & StateHint) && 
       wmHints->initial_state == IconicState) ||
      blWm->CheckFlags(INIT_MINIMIZE))
    blWm->MinimizeWindow(False);
  else if (blWm->CheckFlags(INIT_MAXIMIZE)) {
    blWm->fButton[1]->ChangeImage(FrameButton::RESTORE);
    blWm->MaximizeWindow(False, False);
  }
  else if (blWm->CheckStatus(MINIMIZE_WINDOW))
    blWm->RestoreWindow(False, False);
  else
    blWm->MapWindows();

  ASSERT(blWm->tButton);
  blWm->tButton->MapButton();

  if (!blWm->CheckStatus(MINIMIZE_WINDOW)) {
    if (ClickToFocus || FocusOnMap)
      blWm->SetFocus();
  }
  else
    focusMgr.InsertUnmapList(blWm);

  Gnome::ChangeClientList();

  XSync(display, 0);
}

/*
 * MapNotifyProc --
 *   Process MapNotify event.
 */
void Event::MapNotifyProc(const XMapEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);

    // WM should not interfere if override_redirect is True, but does
    // interfere when override_redirect is changed from False to True.
    // So reparent the window and return if override_redirect is True.
    if (ev.override_redirect) {
      XSelectInput(display, ev.window, 0);

      Window junkRoot;
      Rect rect;
      unsigned int junkBW, junkDepth;

      XGetGeometry(display, ev.window, &junkRoot, &rect.x, &rect.y,
		   (unsigned int *)&rect.width,
		   (unsigned int *)&rect.height,
		   &junkBW, &junkDepth);
      XReparentWindow(display, ev.window, root, rect.x, rect.y);
      desktop.GetBlwmList().Remove(blWm);
      delete blWm;
      return;
    }

    if (!blWm->CheckMapped()) {
      Menu::UnmapAllMenus();

      XGrabServer(display);

      if (blWm->CheckStatus(MINIMIZE_WINDOW))
	blWm->RestoreWindow(False, False);
      else {
	blWm->MapWindows();
	blWm->tButton->MapButton();
	XAddToSaveSet(display, blWm->GetWin());
      }

      if (ClickToFocus || FocusOnMap)
	blWm->SetFocus();

      XSync(display, 0);
      XUngrabServer(display);
    }
  }
}

/*
 * UnmapNotifyProc --
 *   Process UnmapNotify event.
 */
void Event::UnmapNotifyProc(const XUnmapEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);

    XGrabServer(display);

    blWm->SetStateProperty(WithdrawnState);

    Rect rcRoot = rootBlwm->GetRect();
    Rect rcOrig = blWm->GetOrigRect();

    Point pt;
    // adjust the position so that the window is in the real screen
    pt.x = rcOrig.x % rcRoot.width;
    if (pt.x < 0)
    pt.x += rcRoot.width;
    pt.y = rcOrig.y % rcRoot.height;
    if (pt.y < 0)
    pt.y += rcRoot.height;

    XReparentWindow(display, blWm->GetWin(), root, pt.x, pt.y);

    XUnmapWindow(display, blWm->GetWin());

    DestroyBlwm(blWm);

    XSync(display, 0);
    XUngrabServer(display);
  }
}

/*
 * DestroyNotifyProc --
 *   Process DestroyNotify event.
 */
void Event::DestroyNotifyProc(const XDestroyWindowEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);

    XGrabServer(display);
    DestroyBlwm(blWm);
    XUngrabServer(display);
  }
}

void Event::DestroyBlwm(Blwm* blWm)
{
  Bool yield = False;
   if (blWm == Blwm::focusBlwm) {
     yield = True;
     blWm->YieldFocus();
    }
 
   if (blWm->CheckMapped())
     blWm->UnmapWindows();

  focusMgr.RemoveUnmapList(blWm);
  focusMgr.Remove(blWm);

  XRemoveFromSaveSet(display, blWm->GetWin());
  desktop.GetBlwmList().Remove(blWm);
  blWm->tButton->UnmapButton();

  delete blWm;

  Gnome::ChangeClientList();

  if (yield && !ClickToFocus)
    desktop.ChangeFocusToCursor();
}

/*
 * ButtonPressProc --
 *   Process ButtonPress event.
 */
void Event::ButtonPressProc(const XButtonEvent& ev)
{
  Blwm* blWm;
  Button* button;
  Menu* menu;
  Icon* icon;
  Miniature* mini;

  if (ev.button == Button1) {
    /*
     * Left button.
     */
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button1Press(ev.window, ev.time, Point(ev.x_root, ev.y_root),
			 ev.state);
    }
    else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
	     == XCSUCCESS) {
      ASSERT(button);
      button->Button1Press();
    }
    else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
	     == XCSUCCESS) {
      ASSERT(menu);
      menu->Button1Press(ev.window);
    }
    else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
	     == XCSUCCESS) {
      ASSERT(icon);
      icon->Button1Press(ev.time, Point(ev.x_root, ev.y_root));
    }
    else if (XFindContext(display, ev.window, Miniature::context, (caddr_t*)&mini)
	     == XCSUCCESS) {
      ASSERT(mini);
      mini->Button1Press(Point(ev.x_root, ev.y_root));
    }
    else if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window))
      taskBar->Button1Press();
    else if (UsePager && pager->IsPagerWindows(ev.window))
      pager->Button1Press(ev.window, Point(ev.x_root, ev.y_root),
			  Point(ev.x, ev.y));
  }
  else if (ev.button == Button2) {
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button2Press(ev.window);
    }
    else if (XFindContext(display, ev.window, Miniature::context,
			  (caddr_t*)&mini) == XCSUCCESS) {
      ASSERT(mini);
      mini->Button2Press(Point(ev.x_root, ev.y_root));
    }
  }
  else if (ev.button == Button3) {
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button3Press();
    }
    else if (UsePager) {
      ASSERT(pager);
      if (ev.window == pager->GetVisualWin())
	pager->Button3Press(Point(ev.x_root, ev.y_root));
    }
  }

  XAllowEvents(display, ReplayPointer, CurrentTime);
}

/*
 * ButtonReleaseProc --
 *   Process ButtonRelease event.
 */
void Event::ButtonReleaseProc(const XButtonEvent& ev)
{
  Blwm* blWm;
  Button* button;
  Menu* menu;
  Icon* icon;

  if (ev.state & Button1Mask) {
    /*
     * Left button.
     */
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button1Release();
    }
    else if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
	     == XCSUCCESS) {
      ASSERT(menu);
      menu->Button1Release(ev.window);
    }
  }
  else if (ev.state & Button2Mask) {
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button2Release(ev.window);
    }
  }
  else if (ev.state & Button3Mask) {
    /*
     * Right button.
     */
    if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	== XCSUCCESS) {
      ASSERT(blWm);
      blWm->Button3Release(ev.window, Point(ev.x_root, ev.y_root));
    }
    else if (XFindContext(display, ev.window, Button::context, (caddr_t*)&button)
	     == XCSUCCESS) {
      ASSERT(button);
      button->Button3Release(Point(ev.x_root, ev.y_root));
    }
    else if (XFindContext(display, ev.window, Icon::context, (caddr_t*)&icon)
	     == XCSUCCESS) {
      ASSERT(icon);
      icon->Button3Release(Point(ev.x_root, ev.y_root));
    }
    else if (UseTaskbar && taskBar->IsTaskbarWindows(ev.window)) {
      taskBar->Button3Release(Point(ev.x_root, ev.y_root));
    }
  }
}

/*
 * KeyPressProc --
 *   Process KeyPress event.
 */
void Event::KeyPressProc(const XKeyEvent& ev)
{
  Menu* menu;
  Blwm* blWm;

  if (XFindContext(display, ev.window, Menu::context, (caddr_t*)&menu)
      == XCSUCCESS) {
    if (!menuKey->ExecShortCutKey(ev.keycode, ev.state, menu)) {
      char key;
      KeySym sym;
      if (XLookupString((XKeyEvent *)&ev, &key, 1, &sym, NULL) == 1)
	menu->ExecShortCutKey(key);
    }
  }
  else if (ev.window == root)
    scKey->ExecShortCutKey(ev.keycode, ev.state, rootBlwm->ctrlMenu);
  else if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
	   == XCSUCCESS) {
    ASSERT(blWm);
    ASSERT(blWm->ctrlMenu);
    blWm->ctrlMenu->SetBlwm(blWm);
    scKey->ExecShortCutKey(ev.keycode, ev.state, blWm->ctrlMenu);
  }
}

/*
 * ClientMessageProc --
 *   Process ClientMessageNotify event.
 */
void Event::ClientMessageProc(const XClientMessageEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    if (ev.message_type == _XA_WM_CHANGE_STATE &&
	ev.data.l[0] == IconicState)
      blWm->MinimizeWindow();
    else
      Gnome::SetProperty(blWm, ev.message_type, (long *)ev.data.l);
  }
}

/*
 * ColormapNotifyProc --
 *   Process ColormapNotify event.
 */
void Event::ColormapNotifyProc(const XColormapEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t *)&blWm)
      != XCSUCCESS)
    return;

  blWm->ChangeColormap(ev);
}

/*
 * ConfigureRequestProc --
 *   Process ConfigureRequest event.
 */
void Event::ConfigureRequestProc(const XConfigureRequestEvent& ev)
{
  Blwm* blWm;
  XWindowChanges xwc;
  unsigned long xwcm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCNOENT) {
    xwcm = ev.value_mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
    xwc.x = ev.x;
    xwc.y = ev.y;
    xwc.width = ev.width;
    xwc.height = ev.height;
    xwc.border_width = ev.border_width;

    XConfigureWindow(display, ev.window, xwcm, &xwc);
  }
  else {
    ASSERT(blWm);
    blWm->Configure(&ev);
  }
}

void Event::CirculateRequestProc(const XCirculateRequestEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    blWm->Circulate(ev.place);
  }
}

/*
 * PropertyNotifyProc --
 *   Process PropertyNotify event.
 */
void Event::PropertyNotifyProc(const XPropertyEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    blWm->SetProperty(ev.atom);
  }
}    

void Event::FocusInProc(const XFocusChangeEvent& ev)
{
  Blwm* blWm;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    if (ev.mode == NotifyUngrab)
      XSetInputFocus(display, blWm->GetWin(), RevertToParent, CurrentTime);
  }
}

/*
 * ShapeNotifyProc --
 *   Process ShapeNotify event.
 */
void Event::ShapeNotifyProc(const XShapeEvent& ev)
{
  Blwm* blWm;

  if (ev.kind != ShapeBounding)
    return;

  if (XFindContext(display, ev.window, Blwm::context, (caddr_t*)&blWm)
      == XCSUCCESS) {
    ASSERT(blWm);
    blWm->SetShape();
  }
}


syntax highlighted by Code2HTML, v. 0.9.1