Logo Search packages:      
Sourcecode: aewm++ version File versions  Download package

client.cc

/* 
 * frankhale@gmail.com
 * http://frankhale.org
 *
 * This code is released under the GPL license www.gnu.org
 */
#include "aewm.hh"

#include <string.h>

Client::Client(Display *d, Window new_client)
{
      initialize(d);
      wm->addClient(this);
      makeNewClient(new_client);
}

Client::~Client()
{
      removeClient();
}

void Client::initialize(Display *d)
{
      dpy               = d;

      belongs_to_desktop      = 0;

      name              = NULL;
            
      window                  = None;
      frame                   = None;
      title             = None;
      trans                   = None;

      window_menu             = NULL;
      
      x                       = 1; 
      y                       = 1;
      width                   = 1;
      height                  = 1;
      ignore_unmap            = 0;

      pointer_x         = 0;
      pointer_y         = 0;

      old_cx                  = 0;
      old_cy                  = 0;

      wire_move         = wm->getWireMove();

#ifdef SHAPE
      has_been_shaped   = false;
#endif
      
      has_title         = true;
      has_border        = true;
      has_focus         = false;

      is_iconified            = false;

      // Extra Window States
      is_shaded         = false;
      is_maximized            = false;
      is_visible        = false;
      
      is_being_dragged  = false;
      do_drawoutline_once     = false;
      is_being_resized  = false;
      
      last_button1_time       = 0;
      old_x             = 0;
      old_y             = 0;
      old_width         = 1;
      old_height        = 1;
      
      direction         = 0;
      ascent                  = 0;
      descent           = 0;
      text_width        = 0;
      text_justify            = 0;
      justify_style           = wm->getTextJustify();
      
      screen                  = DefaultScreen(dpy);
      root              = RootWindow(dpy, screen);
      
      xres              = WidthOfScreen(ScreenOfDisplay(dpy, screen));
      yres              = HeightOfScreen(ScreenOfDisplay(dpy, screen));
      
      button_pressed          = false;
}

void Client::getXClientName()
{
      if(name) XFree(name);
      
      XFetchName(dpy, window, &name);
            
      if(name==NULL) 
      {
            name = "no name";
      }
      else
      {
            XTextExtents(wm->getFont(), name , strlen(name), 
                  &direction, &ascent, 
                        &descent, &overall);
      
            text_width = overall.width;
      }
}

// Set up a client structure for the new (not-yet-mapped) window. The
// confusing bit is that we have to ignore 2 unmap events if the
// client was already mapped but has IconicState set (for instance,
// when we are the second window manager in a session).  That's
// because there's one for the reparent (which happens on all viewable
// windows) and then another for the unmapping itself. 
void Client::makeNewClient(Window w)
{
      XWindowAttributes attr;
      XWMHints *hints;
      MwmHints *mhints;

      long dummy;

      XGrabServer(dpy);

      window = w;

      getXClientName();

      XGetTransientForHint(dpy, window, &trans);

      XGetWindowAttributes(dpy, window, &attr);

      x = attr.x;
      y = attr.y;
      width = attr.width;
      height = attr.height;
      border_width = attr.border_width;
      cmap = attr.colormap;
      size = XAllocSizeHints();
      XGetWMNormalHints(dpy, window, size, &dummy);

      old_x       = x;
      old_y       = y;
      old_width   = width;
      old_height  = height;

      if ((mhints = wm->getMWMHints(window))) 
      {
            if (mhints->flags & MwmHintsDecorations && !(mhints->decorations & MwmDecorAll)) 
            {
                        has_title  = mhints->decorations & MwmDecorTitle;
                        has_border = mhints->decorations & MwmDecorBorder;
            }
        
            XFree(mhints);
      }

      if (attr.map_state == IsViewable) ignore_unmap++;
      {
            initPosition();
            
            if ((hints = XGetWMHints(dpy, w))) 
            {
                        if (hints->flags & StateHint) 
                        wm->setWMState(window, hints->initial_state);
                  else wm->setWMState(window, NormalState);

                        XFree(hints);
            }
      }

      window_menu = wm->getWindowMenu();

      gravitate(APPLY_GRAVITY);
      reparent();

      if(belongs_to_desktop == -1)
        {
            belongs_to_desktop = wm->getCurrentDesktop();
        }
      
      if (wm->getWMState(window) == IconicState) iconify();
      else //if (wm->getWMState(window) == NormalState || wm->getWMState(window) == WithdrawnState)
      {
            unhide();
      
            if(wm->getFocusModel() == FOCUS_CLICK) 
                  XSetInputFocus(dpy, window, RevertToNone, CurrentTime);
            } 
      
      XSync(dpy, False);
      XUngrabServer(dpy);
}

void Client::removeClient()
{
      XGrabServer(dpy);

      if(trans) XSetInputFocus(dpy, trans, RevertToNone, CurrentTime);

      XUngrabButton(dpy, AnyButton, AnyModifier, frame);

      gravitate(REMOVE_GRAVITY);
      
      XReparentWindow(dpy, window, root, x, y);
      
      XDestroyWindow(dpy, title);
      XDestroyWindow(dpy, frame);
      
      if (name) XFree(name);
      if (size) XFree(size);

      XSync(dpy, False);
      XUngrabServer(dpy);

      window_menu->hide();
            
      wm->removeClient(this);
}

// For a regular window, trans is None (false), and we include
// enough space to draw the title. For a transient window we just make
// a tiny strip. 
int Client::theight()
{
      if (!has_title) return 0;
      
      int title_size = wm->getFont()->ascent + wm->getFont()->descent + SPACE;
      
      if(trans) return TRANSIENT_WINDOW_HEIGHT; // size for transient titlebar heights not to big, not too small
      else
            return title_size;
      
}

// This is called whenever we update our Client stuff. 
void Client::sendConfig()
{
      XConfigureEvent ce;

      ce.type = ConfigureNotify;
      ce.event = window;
      ce.window = window;
      ce.x = x;
      ce.y = y;
      ce.width = width;
      ce.height = height;
      ce.border_width = border_width;
      //ce.above = (is_always_on_top) ? Above : Below;
      ce.override_redirect = False;

      XSendEvent(dpy, window, False, StructureNotifyMask, (XEvent *)&ce);
}

void Client::redraw()
{
      if (!has_title) return;
    
      GC gc;
      
      if(has_focus) gc = wm->getBorderGC();
      else gc = wm->getUnfocusedGC();

      XDrawLine(dpy, title, gc, 0, theight() - BW + BW/2, width, theight() - BW + BW/2);

      XDrawLine(dpy, title, gc,
                  width - theight()+ BW/2, 0,
                  width - theight()+ BW/2, theight());
      
      if(has_focus) gc = wm->getFocusedTitleGC();
      
      if (!trans && name)
      {
            switch(justify_style)
            {
                  case LEFT_JUSTIFY:
                        text_justify = SPACE;
                  break;
            
                  case CENTER_JUSTIFY:
                        text_justify = ( (width / 2) - (text_width / 2) );
                  break;
            
                  case RIGHT_JUSTIFY:
                        text_justify = width - text_width - 25;
                  break;
            }           
      
            if(name!=NULL)
            {
                  XDrawString(dpy, title, gc,
                        text_justify, wm->getFont()->ascent+1,
                        name, strlen(name));
            }
      }
}

// Window gravity is a mess to explain, but we don't need to do much
// about it since we're using X borders. For NorthWest et al, the top
// left corner of the window when there is no WM needs to match up
// with the top left of our fram once we manage it, and likewise with
// SouthWest and the bottom right (these are the only values I ever
// use, but the others should be obvious.) Our titlebar is on the top
// so we only have to adjust in the first case. 
void Client::gravitate(int multiplier)
{
      int dy = 0;
      int gravity = (size->flags & PWinGravity) ?
            size->win_gravity : NorthWestGravity;

      switch (gravity) {
            case NorthWestGravity:
            case NorthEastGravity:
            case NorthGravity: dy = theight(); break;
            case CenterGravity: dy = theight()/2; break;
      }

      y += multiplier * dy;
}

/* Well, the man pages for the shape extension say nothing, but I was
 * able to find a shape.PS.Z on the x.org FTP site. What we want to do
 * here is make the window shape be a boolean OR (or union, if you
 * prefer) of the client's shape and our titlebar. The titlebar
 * requires both a bound and a clip because it has a border -- the X
 * server will paint the border in the region between the two. (I knew
 * that using X borders would get me eventually... ;-)) */
#ifdef SHAPE
void Client::setShape()
{
      int n=0, order=0;
      XRectangle temp, *dummy;

      dummy = XShapeGetRectangles(dpy, window, ShapeBounding, &n, &order);
      
      if (n > 1) {
            XShapeCombineShape(dpy, frame, ShapeBounding,
                  0, theight(), window, ShapeBounding, ShapeSet);

            temp.x = -BW;
              temp.y = -BW;
            temp.width = width + 2*BW;
              temp.height = theight() + BW;
            
            XShapeCombineRectangles(dpy, frame, ShapeBounding,
                  0, 0, &temp, 1, ShapeUnion, YXBanded);
            
            temp.x = 0;
              temp.y = 0;
            temp.width = width;
              temp.height = theight() - BW;
            
            XShapeCombineRectangles(dpy, frame, ShapeClip,
                  0, theight(), &temp, 1, ShapeUnion, YXBanded);
            
            has_been_shaped = 1;
      } 
      else 
      if (has_been_shaped) 
      {
              // I can't find a 'remove all shaping' function... 
              temp.x = -BW;
            temp.y = -BW;
              temp.width = width + 2*BW;
            temp.height = height + theight() + 2*BW;
              
            XShapeCombineRectangles(dpy, frame, ShapeBounding,
                0, 0, &temp, 1, ShapeSet, YXBanded);
      }
    
      XFree(dummy);
}
#endif

void Client::iconify()
{
      if (!ignore_unmap) ignore_unmap++; 

      if(has_focus) setFocus(false);

      XUnmapWindow(dpy, window);
      XUnmapWindow(dpy, title);
      XUnmapWindow(dpy, frame);
            
      is_iconified=true;
      
      wm->setWMState(window, IconicState);

      if(!trans) 
      {
            wm->findTransientsToMapOrUnmap(window, true);
      }
      
      is_visible=false;
}

void Client::hide()
{
      if (!ignore_unmap) ignore_unmap++; 

      if(has_focus) setFocus(false);

      if(window_menu->isVisible()) window_menu->hide();

      XUnmapWindow(dpy, window);
      XUnmapWindow(dpy, title);
      XUnmapWindow(dpy, frame);
      
      wm->setWMState(window, WithdrawnState);

      is_visible=false;
}

void Client::unhide()
{
      if(belongs_to_desktop == wm->getCurrentDesktop())
      {
            XMapRaised(dpy, window);
            XMapRaised(dpy, title);
            XMapRaised(dpy, frame); 

            if(is_iconified)
            {
                  is_iconified=false;
            } 

            wm->setWMState(window, NormalState);

            if(!trans) wm->findTransientsToMapOrUnmap(window, false);
      
            if(wm->getFocusModel() == FOCUS_CLICK)
                  XSetInputFocus(dpy, window, RevertToNone, CurrentTime);
            
            is_visible=true;
      }     
}

// This function sets up the initial position of windows when they are mapped
// for the first time. It still needs some work done to it to make it more 
// aware of _NET_WM_STRUT's
// 
//
//    XSizeHints structure definition
// 
//    typedef struct {
//            long flags;
//            int x, y;
//            int width, height;
//            int min_width, min_height;
//            int max_width, max_height;
//            int width_inc, height_inc;
//            struct {
//                   int x;
//                   int y;
//            } min_aspect, max_aspect;
//            int base_width, base_height;
//            int win_gravity;
//
//       } XSizeHints;
//
void Client::initPosition()
{
      int mouse_x, mouse_y;

      unsigned int w, h;
      unsigned int border_width, depth;

      XWindowAttributes attr;

      XGetWindowAttributes(dpy, window, &attr);

      if (attr.map_state == IsViewable) return;

      XGetGeometry(dpy, window, &root, &x, &y, &w, &h, &border_width, &depth);
            
      width = (int)w;
      height = (int)h;

      if (size->flags & PPosition) 
      {
            if(!x) x = size->x;
            if(!y) y = size->y;
      } 
      else 
      {
            if (size->flags & USPosition) 
            {
                  if(!x) x = size->x;
                        if(!y) y = size->y;
            }
            else
            if ( (x==0) || (y==0)  )
            {
                  if( width>=xres && height>=yres     )
                  {
                        x=0;
                        y=0;
                        width=xres;
                        height=yres-theight();
                  }
                  else 
                  {
                        wm->getMousePosition(&mouse_x, &mouse_y);

                        if(mouse_x && mouse_y)
                        {

                              if (wm->getRandPlacement())
                              {
                                    x = (rand() % (unsigned int) ((xres - width) * 0.94)) + ((unsigned int) (xres * 0.03));
                                    y = (rand() % (unsigned int) ((yres - height) * 0.94)) + ((unsigned int) (yres * 0.03));
                              } else {
      
                                    x = (int) (((long) (xres - width) 
                                                * (long) mouse_x) / (long) xres);
                                    y = (int) (((long) (yres - height - theight()) 
                                                * (long) mouse_y) / (long) yres);
                                    y = (y<theight()) ? theight() : y;
                              }
                                                      
                              gravitate(REMOVE_GRAVITY);    
                        }
                  }
            } 
      }
}

void Client::maximize()
{
      if(trans) return;

      if(is_shaded) 
      {
            shade();
            return;
      }

      if(! is_maximized)
      {
            old_x=x;
            old_y=y;
            old_width=width;
            old_height=height;

            // Check to see if this client sets
            // its max size property. If so don't
            // maximize it past that size.
            if (size->flags & PMaxSize) {
                  
                  width = size->max_width;
                  height = size->max_height;
                  
                  XMoveResizeWindow(dpy, frame, x, y-theight(), width, height+theight());
                  
            } else {
      
                  x=0;
                  y=0;
                  width=xres;
                  height=yres;
            
                  XMoveResizeWindow(dpy, frame, x, y, width, height);

                  y = theight();
                  height -= theight();
            }
            
            is_maximized=true;
      } else {
      
            x=old_x;
            y=old_y;
            width=old_width;
            height=old_height;
      
            XMoveResizeWindow(dpy, frame,
                  old_x, old_y - theight(), old_width, old_height + theight());
      
            is_maximized=false;

            if(is_shaded) is_shaded=false;
      }

      XResizeWindow(dpy, title, width, theight());
      XResizeWindow(dpy, window, width, height);
      
      sendConfig();
}

void Client::handleMotionNotifyEvent(XMotionEvent *ev)
{
      int nx=0, ny=0;

      if((ev->state & Button1Mask) && (wm->getFocusedClient() == this))
      {
                  if(! do_drawoutline_once && wire_move) 
                  {
                        XGrabServer(dpy);
                        drawOutline();
                        do_drawoutline_once=true;
                        is_being_dragged=true;
                  }
            
                  if(wire_move) drawOutline();

                  nx = old_cx + (ev->x_root - pointer_x);
                  ny = old_cy + (ev->y_root - pointer_y);
            
                  if(wm->getEdgeSnap())
                  {
                        // Move beyond edges of screen
                        if(nx == xres - width) nx = xres - width + 1;         
                        else if(nx == 0) nx = -1;
            
                        if(ny == yres - SNAP) ny = yres - SNAP - 1;
                        else if(ny == theight()) ny = theight() - 1;
                        
                        // Snap to edges of screen
                        if( (nx + width >= xres - SNAP) && (nx + width <= xres) ) nx = xres - width;
                        else if( (nx <= SNAP) && (nx >= 0) ) nx = 0;

                        if(is_shaded)
                        {
                              if( (ny  >= yres - SNAP) && (ny  <= yres) ) ny = yres;
                              else if( (ny - theight() <= SNAP) && (ny - theight() >= 0)) ny = theight();
                        }
                        else
                        {
                              if( (ny + height >= yres - SNAP) && (ny + height <= yres) ) ny = yres - height;
                              else if( (ny - theight() <= SNAP) && (ny - theight() >= 0)) ny = theight();
                        }
                  }
            
                  x=nx; y=ny;
                  
                  if(!wire_move)
                  {
                        XMoveWindow(dpy, frame, nx, ny-theight());
                        sendConfig();
                  }
            
                  if(wire_move) drawOutline();
      }
      else 
      if(ev->state & Button2Mask)
      {
            if(! is_being_resized)
            {
                  int in_box = (ev->x >= width - theight()) && (ev->y <= theight());
                  
                  if(! in_box) return;
            }
            
            if(! do_drawoutline_once) 
            { 
                  XGrabServer(dpy);
                  is_being_resized=true;
                  do_drawoutline_once=true;
                  drawOutline();
                  setmouse(frame, width, height+theight());
            }
            else
            {
                  if((ev->x > 50) && (ev->y > 50))
                  {
                        drawOutline();

                        width =  ev->x;
                        height = ev->y - theight();

                        getIncsize(&width, &height, PIXELS);
        
                        if (size->flags & PMinSize) 
                        {
                              if (width < size->min_width) width = size->min_width;
                              if (height < size->min_height) height = size->min_height;
                              
                              if(width<100) width=100;
                              if(height<50) height=50;
                        }

                        if (size->flags & PMaxSize) 
                        {
                                    if (width > size->max_width) width = size->max_width;
                                    if (height > size->max_height) height = size->max_height;
                        
                              if(width>xres) width=xres;
                              if(height>yres) height=yres;
                        } 
                  
                        drawOutline();                
                  }
            }
      }
}

void Client::drawOutline()
{
      if(! is_shaded)
      {
            XDrawRectangle(dpy, root, wm->getInvertGC(),
                  x + BW/2, y - theight() + BW/2,
                  width + BW, height + theight() + BW);

            XDrawRectangle(dpy, root, wm->getInvertGC(),
                  x + BW/2 + 4, y - theight() + BW/2 + 4,
                  width + BW - 8, height + theight() + BW - 8);               
      } 
      else 
      {
            XDrawRectangle(dpy, root, wm->getInvertGC(),
                        x + BW/2, 
                        y - theight() + BW/2,
                        width + BW, 
                        theight() + BW);
      }
}

// If the window in question has a ResizeInc int, then it wants to be
// resized in multiples of some (x,y). Here we set x_ret and y_ret to
// the number of multiples (if mode == INCREMENTS) or the correct size
// in pixels for said multiples (if mode == PIXELS). 
int Client::getIncsize(int *x_ret, int *y_ret, int mode)
{
      int basex, basey;

      if (size->flags & PResizeInc) 
      {
            basex = (size->flags & PBaseSize) ? size->base_width :
                  (size->flags & PMinSize) ? size->min_width : 0;
            
            basey = (size->flags & PBaseSize) ? size->base_height :
                  (size->flags & PMinSize) ? size->min_height : 0;
                                
            if (mode == PIXELS) 
            {
                        *x_ret = width - ((width - basex) % size->width_inc);
                        *y_ret = height - ((height - basey) % size->height_inc);   
            } 
            else // INCREMENTS 
            {
                        *x_ret = (width - basex) / size->width_inc;
                        *y_ret = (height - basey) / size->height_inc;
            }
        
            return 1;
      } 

    return 0;
}

// This function makes it so only the titlebar shows.
void Client::shade()
{
      raise();
      
      if(! is_shaded)
      {
            XResizeWindow(dpy, frame, width, theight() - 1);
            is_shaded=true;
      } else {
            XResizeWindow(dpy, frame, width, height + theight());
            is_shaded=false;
      }
}

// Because we are redirecting the root window, we get ConfigureRequest
// events from both clients we're handling and ones that we aren't.
// For clients we manage, we need to fiddle with the frame and the
// client window, and for unmanaged windows we have to pass along
// everything unchanged. Thankfully, we can reuse (a) the
// XWindowChanges struct and () the code to configure the client
// window in both cases.
//
// Most of the assignments here are going to be garbage, but only the
// ones that are masked in by e->value_mask will be looked at by the X
// server. 
void Client::handleConfigureRequest(XConfigureRequestEvent *e)
{
      XWindowChanges wc;

        gravitate(REMOVE_GRAVITY);
        if (e->value_mask & CWX) x = e->x;
        if (e->value_mask & CWY) y = e->y;
        if (e->value_mask & CWWidth) width = e->width;
        if (e->value_mask & CWHeight) height = e->height;
        gravitate(APPLY_GRAVITY);

      wc.x = x;
        wc.y = y - theight();
            wc.width = width;
        wc.height = height + theight();
            wc.border_width = BW;
        wc.sibling = e->above;
            wc.stack_mode = e->detail;
        XConfigureWindow(dpy, frame, e->value_mask, &wc);

      if(! is_shaded) 
      {
            XMoveResizeWindow(dpy, frame,x,y-theight(), width, height+theight());
            XResizeWindow(dpy, title, width, theight());
            XMoveResizeWindow(dpy, window,0,theight(),width,height);
      }

      // If an app wants to place his window in a bogus position
      // like offscreen then fix its position. Lets see if this
      // works out okay. Warez and Porn sites have a bad habit
      // of trying to place the Mozilla browser window titlebar
      // just offscreen so you can't close the window. 
      // The bastards!
      if( (x + width > xres)        || 
          (height + theight() > yres) ||
          (x > xres)                || 
          (y > yres)                ||
          (x < 0)             ||
          (y < 0) 
          )
            initPosition();
      
#ifdef SHAPE
        if (e->value_mask & (CWWidth|CWHeight)) setShape();
#endif

      sendConfig();

      if (e->value_mask & CWY) wc.x = 0;
      if (e->value_mask & CWY) wc.y = theight();
      if (e->value_mask & CWWidth) wc.width = e->width;
      if (e->value_mask & CWHeight) wc.height = e->height;

      wc.sibling = e->above;
      wc.stack_mode = e->detail;
      XConfigureWindow(dpy, e->window, e->value_mask, &wc);
}

void Client::handleMapRequest(XMapRequestEvent *e)
{
      unhide();
}

void Client::handleUnmapEvent(XUnmapEvent *e)
{
      if (! ignore_unmap) 
            delete this;
}

// This happens when a window is iconified and destroys itself. An
// Unmap event wouldn't happen in that case because the window is
// already unmapped. 
void Client::handleDestroyEvent(XDestroyWindowEvent *e)
{
      delete this;
}

// If a client wants to iconify itself (boo! hiss!) it must send a
// special kind of ClientMessage. We might set up other handlers here
// but there's nothing else required by the ICCCM. 
void Client::handleClientMessage(XClientMessageEvent *e)
{     
      if (e->message_type == wm->atom_wm_change_state &&
            e->format == 32 && e->data.l[0] == IconicState) 
                  iconify();
}

void Client::handlePropertyChange(XPropertyEvent *e)
{
      long dummy;
      
      switch (e->atom) 
      {
            case XA_WM_NAME:
                  getXClientName();
                  wm->updateClientNameOnIconMenu(this);
                        XClearWindow(dpy, title);
                        redraw();
                  break;
            
            case XA_WM_NORMAL_HINTS:
                        XGetWMNormalHints(dpy, window, size, &dummy);
            break;
          
            case XA_WM_TRANSIENT_FOR:
                  if(!trans) XGetTransientForHint(dpy, window, &trans);
            break;
      }
}

void Client::reparent()
{
      XSetWindowAttributes pattr;

      XGrabServer(dpy);

      pattr.background_pixel = wm->getFCColor().pixel;
      pattr.border_pixel = wm->getBDColor().pixel;
      pattr.do_not_propagate_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask;
      pattr.override_redirect=False;
      pattr.event_mask = ButtonMotionMask       |
                     SubstructureRedirectMask   |
                     SubstructureNotifyMask     |     
                     ButtonPressMask            |
                     ButtonReleaseMask          |
                     ExposureMask               |
                     EnterWindowMask            |
                     LeaveWindowMask            ;

      int b_w = BW;
      
      if(border_width) { b_w = border_width; XSetWindowBorderWidth(dpy, window, 0); } else { b_w = BW; }
    
      frame = XCreateWindow(dpy, 
                        root,
                        x, 
                        y - theight(), 
                        width, 
                        height + theight(), 
                        b_w,
                        DefaultDepth(dpy, screen ), 
                        CopyFromParent, 
                        DefaultVisual(dpy, screen ),
                        CWOverrideRedirect|CWDontPropagate|CWBackPixel|CWBorderPixel|CWEventMask, 
                        &pattr);

      // This window is used to house the window title and title bar button
      title = XCreateWindow(dpy, 
                        frame,
                        0, 
                        0, 
                        width, 
                        theight(), 
                        0,
                        DefaultDepth(dpy,  screen ), 
                        CopyFromParent, 
                        DefaultVisual(dpy,  screen ),
                        CWOverrideRedirect|CWDontPropagate|CWBackPixel|CWBorderPixel|CWEventMask, 
                        &pattr);

      #ifdef SHAPE
      if (wm->getShape()) {
            XShapeSelectInput(dpy, window, ShapeNotifyMask);
            setShape();
      }
      #endif

      // We don't want these masks to be propagated down to the frame
      XChangeWindowAttributes(dpy, window, CWDontPropagate, &pattr);

      XSelectInput(dpy, window, FocusChangeMask|PropertyChangeMask);

      XReparentWindow(dpy, window, frame, 0, theight());

      XGrabButton(dpy, 
            Button1, 
            AnyModifier, 
            frame,
            1, 
            ButtonPressMask|ButtonReleaseMask,
            GrabModeSync, 
            GrabModeAsync, None, None);

      sendConfig();
      
      XSync(dpy, false);
      XUngrabServer(dpy);
}


// This function handles the button events.
// Remember this is designed for a 3 button mouse and to the way I like
// the buttons laid out. If you want something different then edit
// this until your heart is content.
void Client::handleButtonEvent(XButtonEvent *e)
{
      int in_box;
      
      // Formula to tell if the pointer is in the little
      // box on the right edge of the window. This box is
      // the iconify button, resize button and close button.
      in_box = (e->x >= width - theight()) && (e->y <= theight());

      // Used to compute the pointer position on click
      // used in the motion handler when doing a window move.
      old_cx = x;
      old_cy = y;
      pointer_x = e->x_root;
      pointer_y = e->y_root;

      // Allow us to get clicks from anywhere on the window
      // so click to raise works.
      XAllowEvents(dpy, ReplayPointer, CurrentTime);

      window_menu->hide();

      switch (e->button) 
      {
            case Button4:
            case Button5:
            {
                  if(is_being_resized)
                  {
                        drawOutline();
                        do_drawoutline_once=false;
                        is_being_resized=false;
                        
                        XResizeWindow(dpy, frame, width, height + theight());
                        XResizeWindow(dpy, title, width, theight());
                        XResizeWindow(dpy, window, width, height);

                        sendConfig(); 

                        XUngrabServer(dpy);
                        XSync(dpy, False);                        
                        
                        return;
                  }
            }
            break;
      
          case Button1:
          {
            if (e->type == ButtonPress) 
            {           
                  if(e->window == window || e->subwindow == window)
                  {
                        raise();
                  }
                  
                  if (e->window == title) 
                  {
                        window_menu->hideAllVisibleSubmenus();

                        if (in_box) 
                        {
                              if(!trans)
                              {
                                    window_menu->hide();
                                    iconify();
                              }
                        }
                        else
                              raise();
                  }                 
            }

            if (e->type == ButtonRelease) 
            {
                  if(is_being_dragged)
                  {
                        is_being_dragged=false;
                        do_drawoutline_once=false;
                        drawOutline(); 
                        XMoveWindow(dpy, frame, x, y-theight());
                        sendConfig();
                        
                        XUngrabServer(dpy);
                        XSync(dpy, False);
                  }

                  // Check for a double click then maximize 
                  // the window.
                  if(e->time-last_button1_time<250) 
                  {
                        maximize();
            
                        last_button1_time=0;
                        
                        return;
                  } else 
                        last_button1_time=e->time;
            }
            
          }
          break;
            
            case Button2:
          { 
                  if(e->window == title)
                  {
                        if(in_box) 
                        {
                              if(e->type == ButtonPress) 
                              {
                                    if(is_shaded) shade();

                                    raise();
                              }
                        }
                        }

                  if(e->type == ButtonRelease)
                  {
                        if(is_being_resized)
                        {
                              drawOutline();
                              do_drawoutline_once=false;
                              is_being_resized=false;

                              XResizeWindow(dpy, frame, width, height + theight());
                              XResizeWindow(dpy, title, width, theight());
                              XResizeWindow(dpy, window, width, height);
                              
                              sendConfig(); 

                              XUngrabServer(dpy);
                              XSync(dpy, False);
                              
                              return;
                        } 
                        
                        if( (e->window == title) && (!in_box) ) shade();
                  }     
          } 
          break;
            
            case Button3:
            {
                  if(e->window == title)
                  {
                        if (e->type == ButtonRelease)
                        {
                              if (in_box) 
                                    wm->sendWMDelete(window);
                              else {
                                    if(! trans)
                                    {
                                          window_menu->setThisClient(this);
                                          window_menu->show();
                                    }
                              }
                        }
                  }
            }
            break;
                        
            
        }
}

void Client::handleEnterEvent(XCrossingEvent *e)
{
      XSetInputFocus(dpy, window, RevertToNone, CurrentTime);
}

void Client::handleFocusInEvent(XFocusChangeEvent *e)
{
      wm->sendXMessage(window, wm->atom_wm_protos, SubstructureRedirectMask, wm->atom_wm_takefocus );
      XInstallColormap(dpy, cmap);
      setFocus(true);
}

void Client::setFocus(bool focus)
{
      has_focus=focus;
      
      if (has_title)
      {
            if(has_focus)
            {
                  XSetWindowBackground(dpy, title, wm->getBGColor().pixel);
                  XSetWindowBorder(dpy, frame, wm->getFocusedBorderColor().pixel);
            }
            else  {
                  XSetWindowBackground(dpy, title, wm->getFCColor().pixel);
                  XSetWindowBorder(dpy, frame, wm->getUnFocusedBorderColor().pixel);
            }
            
            XClearWindow(dpy, title);
            redraw();
      }           
}

void Client::handleColormapChange(XColormapEvent *e)
{
      if (e->c_new) {
            cmap = e->colormap;
            XInstallColormap(dpy, cmap);
      }
}

// If we were covered by multiple windows, we will usually get
// multiple expose events, so ignore them unless e->count (the number
// of outstanding exposes) is zero.
void Client::handleExposeEvent(XExposeEvent *e)
{
      if (e->count == 0) redraw();
}

#ifdef SHAPE
void Client::handleShapeChange(XShapeEvent *e)
{
      setShape();
}
#endif

void Client::setDesktop(int desk)
{
      belongs_to_desktop=desk;
      
      if(belongs_to_desktop != wm->getCurrentDesktop())
      {
            hide();
      }
}

void Client::raise()
{
      XWindowChanges wc;
      wc.stack_mode = Above;
      XConfigureWindow(dpy, frame, CWStackMode, &wc);
}

void Client::lower()
{
      XWindowChanges wc;
      wc.stack_mode = Below;
      XConfigureWindow(dpy, window, CWStackMode, &wc);
}

Generated by  Doxygen 1.6.0   Back to index