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

client.cc

/*
 * Copyright (C) 1999,2000,2001 Frank Hale
 * frankhale@yahoo.com
 * http://sapphire.sourceforge.net/
 *
 * Updated: 3 Nov 2001
 *
 * 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 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "sapphire.hh"

Client::Client() 
{
      // One thing I cannot stand is fucking variables that are cryptic.
      // I gotta lay off the dope when I code, shit!
      
      shaped       = false;
      moving       = false;
      shaded       = false;
      maxsized = false;

      name     = "unknown";
      
      // Defaults for this Clients x, y position and width and height. 
      x     = 1;
      y     = 1;
      width = 1;
      height      = 1;

      oumx    = 1;
      oumy    = 1;
      oumwidth  = 1;
      oumheight = 1;

      old_width  = width;
      old_height = height;

      default_titlebar_height = wm->getIHeight() + DEFAULT_SPACE;
      default_client_name_x = DEFAULT_SPACE + 20;
      default_client_name_y = wm->getFontPosition(); //DEFAULT_SPACE + wm->getXFont()->ascent + 2;

      default_button_width= 13;
      default_button_height= 13;

      client_position[40]=0;
      text_width=0;

      right_sidebar_width=10;

      // These are set to there real defaults in the reparent function.
      default_close_button_x = 0;
      default_close_button_y = 0;
      default_shade_button_x = 0;
      default_shade_button_y = 0;
      default_minimize_button_x = 0;
      default_minimize_button_y = 0;      
      default_maximize_button_x = 0;
      default_maximize_button_y = 0;

      close_button_pressed=false;
      shade_button_pressed=false;
      minimize_button_pressed=false;
      maximize_button_pressed=false;

      // Mouse Button defaults
      button1=button2=button3=false;
      
      // Window Decorations
      //
      // The parent_window is the main parent. The titlebar is a child of the parent_window
      // all other button windows are childs of the titlebar.
      has_titlebar=true;
      has_close_button=true;
      has_minimize_button=true;
      has_maximize_button=true;
      has_shade_button=true;

      frame_pix=None;   // Pixmap used for the titlebar
      button_pix=None;// Pixmap used for titlebar buttons

      ignore_unmap=0;

      close.window = maximize.window 
                 = minimize.window 
                 = shadeButton.window
                 = window 
                 = parent 
                 = transient 
                 = title
                 = right_sidebar
                 = resize_win
                 = None;
}

Client::~Client() 
{
}

Window Client::createTopLevelWindow(int x, int y, 
      unsigned int width,unsigned int height,unsigned int borderwidth)
{
      XSetWindowAttributes attrib;

      unsigned long create_mask = CWOverrideRedirect | 
            CWBackPixmap | CWBackPixel | CWBorderPixel | CWCursor | 
            CWEventMask;

      attrib.background_pixmap = None;
      attrib.background_pixel = wm->getBackgroundColor().pixel;
      attrib.border_pixel = wm->getBorderColor().pixel;
      attrib.override_redirect = true;
      attrib.cursor = XCreateFontCursor(wm->getDisplay(), XC_left_ptr);
      attrib.event_mask =  StructureNotifyMask | SubstructureNotifyMask |
            SubstructureRedirectMask | ExposureMask | ButtonMotionMask | 
            ButtonPressMask | ButtonReleaseMask | FocusChangeMask;
      
      return (XCreateWindow(wm->getDisplay(), wm->getRootWindow(), x,y,width,height,borderwidth,
            DefaultDepth(wm->getDisplay(), wm->getScreen()), InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()),
            create_mask, &attrib));
}

Window Client::createChildWindow(Window parent, int x, int y, 
      unsigned int width,unsigned int height,unsigned int borderwidth)
{
      XSetWindowAttributes attrib;

      unsigned long create_mask = 
            CWBackPixmap | CWBackPixel | CWBorderPixel | CWCursor | 
            CWEventMask;

      attrib.background_pixmap = None;
      attrib.background_pixel = wm->getBackgroundColor().pixel;
      attrib.border_pixel = wm->getBorderColor().pixel;
      attrib.cursor = XCreateFontCursor(wm->getDisplay(), XC_left_ptr);
      attrib.event_mask = StructureNotifyMask | SubstructureNotifyMask |
            SubstructureRedirectMask | ExposureMask | EnterWindowMask |
            LeaveWindowMask | ButtonMotionMask | ButtonPressMask | 
            ButtonReleaseMask;
      
      return (XCreateWindow(wm->getDisplay(), parent, x,y,width,height,borderwidth,
            DefaultDepth(wm->getDisplay(), wm->getScreen()), InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()),
            create_mask, &attrib));
}

void Client::make_new_client(Window w)
{
      long dummy;
      XWMHints *hints;
      XWindowAttributes attr;

      // Populate the hints structure with the window hints (w) has.
      hints = XGetWMHints(wm->getDisplay(), w);

      // Create a new Client object.
      Client *c = new Client();
      // Insert the client into the window manager client list.
      wm->insertClient(c);

      // Assign the window (w) to c->window, c->window represents the application.
      c->window = w;
      c->ignore_unmap = 0;

      XGetWindowAttributes(wm->getDisplay(), c->window, &attr);

      c->x = attr.x;
      c->y = attr.y;
      c->width = attr.width;
      c->height = attr.height;
      c->cmap = attr.colormap;

      c->size = XAllocSizeHints();

      init_position(c);
      
      XGetWMNormalHints(wm->getDisplay(), c->window, c->size, &dummy);

      XSelectInput(wm->getDisplay(), c->window, ColormapChangeMask | PropertyChangeMask | EnterWindowMask );
      
      getTransients(c);

      if (XFetchName(wm->getDisplay(), c->window, &c->name)==0)
        c->name=NULL;

      if (isViewable(c)) c->ignore_unmap++;

      change_gravity(c, 1);

      // Determine if this client needs window decorations.
      setButtonPositionDefaults(c);
      determineWindowDecorations(c);
      
      if (hints) XFree(hints);
      
      // Do all the necessary reparenting for this client
      reparent(c);
      
      // If this client should be iconic on start then we won't map it.
      isIconic(c);
            
      XAddToSaveSet(wm->getDisplay(), c->window);           
      XSetWindowBorderWidth(wm->getDisplay(), c->window, 0);
}

void Client::init_position(Client *c)
{
      /* Adapted from aewm 1.1.2 */
      
      int xmax = wm->getXRes();
      int ymax = wm->getYRes();
      int mouse_x=0, mouse_y=0;

      if (c->size->flags & (USSize)) 
      {
            c->width = c->size->width;
              c->height = c->size->height;
      } else {
            /* we would check PSize here, if GTK didn't blow goats */
              /* make sure it's big enough to click at */
             if (c->width < 2 * theight(c)) c->width = 2 * theight(c);
                   if (c->height < theight(c)) c->height = theight(c);
      }

      if (c->size->flags & USPosition) 
      {
            c->x = c->size->x;
            c->y = c->size->y;
      } else {
            if (c->size->flags & PPosition) 
            {
                        c->x = c->size->x;
                        c->y = c->size->y;
            }

              if (c->x < 0) c->x = 0;
              if (c->y < 0) c->y = 0;
            if (c->x > xmax) c->x = xmax - 5;
              if (c->y > ymax) c->y = ymax - 5;
      }

      if (c->x == 0 && c->y == 0) 
      {
            get_mouse_position(&mouse_x, &mouse_y);

            if (c->width < xmax)
                  c->x = (mouse_x / 2);
   
            if (c->height + theight(c) < ymax)
                  c->y = (mouse_y / 2);

            c->y += theight(c);
            change_gravity(c, -1);
      }
}

void Client::remove_client(Client *c)
{
      XEvent foo;

      XGrabServer(wm->getDisplay());
      
      if(! XCheckTypedWindowEvent(wm->getDisplay(), c->window, DestroyNotify, &foo))
      {
            // Sets input focus back to the root window
            XSetInputFocus(wm->getDisplay(), wm->getRootWindow(), RevertToPointerRoot, CurrentTime);
            
            change_gravity(c, -1);
            
            XReparentWindow(wm->getDisplay(), c->window, wm->getRootWindow(), c->x, c->y);
            XRemoveFromSaveSet(wm->getDisplay(), c->window);
            
            XDestroyWindow(wm->getDisplay(), c->close.window);
            XDestroyWindow(wm->getDisplay(), c->maximize.window);
            XDestroyWindow(wm->getDisplay(), c->minimize.window);
            XDestroyWindow(wm->getDisplay(), c->shadeButton.window);
            XDestroyWindow(wm->getDisplay(), c->right_sidebar);
            XDestroyWindow(wm->getDisplay(), c->resize_win);
            XDestroyWindow(wm->getDisplay(), c->title);
            XDestroyWindow(wm->getDisplay(), c->parent);
                              
            if (c->name) XFree(c->name);
            if (c->size) XFree(c->size);

            wm->getImageControl()->removeImage(c->frame_pix);
            wm->getImageControl()->removeImage(c->right_pix);
            wm->getImageControl()->removeImage(c->button_pix);
            wm->getImageControl()->removeImage(c->resize_pix);

            wm->removeClient(c);
      
            delete c;
      } 
      
      XSync(wm->getDisplay(), false);     
      XUngrabServer(wm->getDisplay());
}

void Client::setButtonPositionDefaults(Client *c)
{
      c->default_close_button_x = 4;
      c->default_close_button_y = theight(c) / 2 - 7;
      
      c->default_shade_button_x = c->width - 44;
      c->default_shade_button_y = theight(c) / 2 - 7;
      
      c->default_minimize_button_x = c->width - 27;
      c->default_minimize_button_y = theight(c) / 2 - 7;    
      
      c->default_maximize_button_x = c->width - 10;
      c->default_maximize_button_y = theight(c) / 2 - 7;
}

void Client::reparent(Client *c)
{           
      createParentWindow(c);
      createTitlebarWindow(c);
      createRightSidebarWindow(c);
      createResizeWindow(c);
      createCloseButtonWindow(c);
      createMinimizeButtonWindow(c);
      createMaximizeButtonWindow(c);
      createShadeButtonWindow(c);

      if (wm->getShape()) {
            XShapeSelectInput(wm->getDisplay(), c->window, ShapeNotifyMask);
            set_shape(c);
      }
      
      // If this window doesn't request that it shouldn't be reparented
      // then we will go ahead an reparent it to c->parent which is the 
      // parent window which holds the client application window ( c->window ) aswell
      // as the titlebar window and the button windows.
      if (c->has_titlebar) 
      {
            int x, y;
            unsigned int width, height, border, depth;
            Window win;
            XGetGeometry(wm->getDisplay(), c->parent, &win, &x, &y, &width, &height, &border, &depth);

            XReparentWindow(wm->getDisplay(), c->window, c->parent, 0, theight(c));
      
            if(y <= theight(c)) 
            {
                  XMoveWindow(wm->getDisplay(), c->parent, x, y);
            
                  c->y = theight(c);
            }
            else {
            
                  XMoveWindow(wm->getDisplay(), c->parent, x, y - theight(c));
                  c->y = y;
            }
      }
      else 
      {
            // If we don't need to reparent it with window decorations then we
            // reparent it back to the root window and move it to where it wishes
            // to be when mapped.
            XReparentWindow(wm->getDisplay(), c->window, wm->getRootWindow(), 0, 0);
            XMoveWindow(wm->getDisplay(), c->window, c->x, c->y);
            
      }

      createButtonImage(c);   
      createResizeImage(c);

      send_config(c);
}

void Client::createParentWindow(Client *c)
{
      c->parent = createTopLevelWindow
                  (
                        c->x,
                        c->y - theight(c),
                        c->width + right_sidebar_width, 
                        c->height + theight(c), 
                        DEFAULT_BORDER_SIZE
                  );
      
}

void Client::createTitlebarWindow(Client *c)
{
      c->title = createChildWindow
                  (
                        c->parent, 
                        0, 
                        0, 
                        c->width + right_sidebar_width, 
                        theight(c),
                        0
                  );
}

void Client::createRightSidebarWindow(Client *c)
{
      c->right_sidebar = createChildWindow
                  (
                        c->parent, 
                        c->width, 
                        theight(c), 
                        right_sidebar_width, 
                        c->height - 10,
                        1
                  );
}

void Client::createResizeWindow(Client *c)
{
      c->resize_win = createChildWindow
                  (
                        c->parent, 
                        c->width, 
                        c->height + 10, 
                        right_sidebar_width, 
                        10,
                        1
                  );
}

void Client::createCloseButtonWindow(Client *c)
{
      c->close.x      = c->default_close_button_x;
      c->close.y      = c->default_close_button_y;
      c->close.width  = c->default_button_width;
      c->close.height = c->default_button_height;
      
      c->close.window = createChildWindow
                  (
                        c->title, 
                        c->close.x, 
                        c->close.y, 
                        c->close.width, 
                        c->close.height,
                        1
                  );
}

void Client::createMinimizeButtonWindow(Client *c)
{
      c->minimize.x = c->default_minimize_button_x;
      c->minimize.y = c->default_minimize_button_y;
      c->minimize.width =  c->default_button_width;
      c->minimize.height =  c->default_button_height;

      c->minimize.window = createChildWindow
                  (
                        c->title, 
                        c->minimize.x, 
                        c->minimize.y, 
                        c->minimize.width, 
                        c->minimize.height,
                        1
                  );
}

void Client::createMaximizeButtonWindow(Client *c)
{
      c->maximize.x      = c->default_maximize_button_x;
      c->maximize.y      = c->default_maximize_button_y;
      c->maximize.width  = c->default_button_width;
      c->maximize.height = c->default_button_height;

      c->maximize.window = createChildWindow
                  (
                        c->title, 
                        c->maximize.x, 
                        c->maximize.y,
                        c->maximize.width, 
                        c->maximize.height,
                        1
                  );
}

void Client::createShadeButtonWindow(Client *c)
{
      c->shadeButton.x      = c->default_shade_button_x;
      c->shadeButton.y      = c->default_shade_button_y;
      c->shadeButton.width  = c->default_button_height;
      c->shadeButton.height = c->default_button_height;

      c->shadeButton.window = createChildWindow
                  (
                        c->title, 
                        c->shadeButton.x, 
                        c->shadeButton.y,
                        c->shadeButton.width, 
                        c->shadeButton.height,
                        1
                  );    
}

int Client::theight(Client *c) const 
{ 
      //return ((c->transient ? 2*DEFAULT_SPACE : wm->iheight) + DEFAULT_SPACE); 

      // For now this function will pass a Client object. Even though we don't 
      // use it for much, I still might want to have transients have a different style
      // than there top level parents later on.
      //
      // For instance I could turn off some of the titlebar buttons, or I could change the
      // height of the client's titlebar and button width and height. 
      //
      // This is the reason why I am passing the Client object to this function. I simply
      // haven't made up my mind at this point.
      return c->default_titlebar_height; 
} 

void Client::getTransients(Client *c)
{
      Window trans;
      
      XGetTransientForHint(wm->getDisplay(), c->window, &trans);
      
      c->transient = trans;
}

void Client::determineWindowDecorations(Client *c)
{
      // This code was ripped from somewhere but since Client.cc
      // is coded so fucking badly it doesn't work for anything.

      int format;
      Atom atom_return;
      unsigned long num, len;
      
      if (XGetWindowProperty(wm->getDisplay(), c->window,
                         wm->getMotifWMHintsAtom(), 0,
                         PropMwmHintsElements, false,
                         wm->getMotifWMHintsAtom(), &atom_return,
                         &format, &num, &len,
                         (unsigned char **) &c->mwm_hint) == Success && c->mwm_hint)
      
      if (num == PropMwmHintsElements) {
            if (c->mwm_hint->flags & MwmHintsDecorations)
            {
                  if (c->mwm_hint->decorations & MwmDecorAll) 
                  {
                        c->has_titlebar=c->has_close_button=c->has_minimize_button=c->has_maximize_button=c->has_shade_button=true;
                  }
                  else {
                        c->has_titlebar=c->has_close_button=c->has_minimize_button=c->has_maximize_button=c->has_shade_button=false;
            
                              if (c->mwm_hint->decorations & MwmDecorTitle) c->has_titlebar = true;
                        
                        c->has_minimize_button = true;
                        c->has_maximize_button = true;
                  
                        c->has_shade_button=true;
                        c->has_close_button=true;
                  }
            }
      }}

Client *Client::find_client(Window w)
{
      if (w && w != wm->getRootWindow()) 
      {
            if(wm->getClientCount()) 
            {
                  LinkedListIterator<Client> it(wm->getClientListObject());
                  for(; it.current(); it++)
                  {
                        if (w == it.current()->parent ||
                            w == it.current()->title ||
                            w == it.current()->window ||
                            w == it.current()->close.window ||
                            w == it.current()->maximize.window ||
                            w == it.current()->minimize.window ||
                            w == it.current()->resize_win ||
                            w == it.current()->right_sidebar ||
                            w == it.current()->shadeButton.window )
                        {
                              return it.current();
                        } 
                  }
            }
      }

      return NULL;
}

int Client::isViewable(Client *c)
{
      XWindowAttributes attr;

      XGetWindowAttributes(wm->getDisplay(), c->window, &attr);
      
      return attr.map_state;
}

void Client::createTitleImage(Client* c)
{
      unsigned long style=0;

      style = wm->getTheme()->getTitlebarStyle();
                                    
      c->frame_pix = wm->getImageControl()->renderImage(
                  c->width+c->right_sidebar_width, 
                  theight(c), 
                  style, 
                        wm->getTheme()->getClientColorFrom(), 
                        wm->getTheme()->getClientColorTo());
                  
      XSetWindowBackgroundPixmap(wm->getDisplay(), c->title, c->frame_pix);
}

void Client::createRightSidebarImage(Client *c)
{
      unsigned long style=0;

      style = wm->getTheme()->getRightSidebarStyle();
            
      c->right_pix = wm->getImageControl()->renderImage(
                  10, 
                  c->height + theight(c) - 10, 
                  style, 
                        wm->getTheme()->getRightSidebarColorFrom(), 
                        wm->getTheme()->getRightSidebarColorTo());

      XSetWindowBackgroundPixmap(wm->getDisplay(), c->right_sidebar, c->right_pix);
}

void Client::createResizeImage(Client *c)
{
      unsigned long style=0;

      style = wm->getTheme()->getResizeStyle();
            
      c->resize_pix = wm->getImageControl()->renderImage(
                  10, 
                  10, 
                  style, 
                        wm->getTheme()->getResizeColorFrom(), 
                        wm->getTheme()->getResizeColorTo());

      XSetWindowBackgroundPixmap(wm->getDisplay(), c->resize_win, c->resize_pix);

}

void Client::createButtonImage(Client* c)
{
      unsigned long style=0;

      style = wm->getTheme()->getButtonStyle();       
      
      c->button_pix = wm->getImageControl()->renderImage(
                  c->default_button_width, 
                  c->default_button_height, 
                  style, 
                  wm->getTheme()->getButtonColorFrom(), 
                  wm->getTheme()->getButtonColorTo());
      
      
      XSetWindowBackgroundPixmap(wm->getDisplay(), c->shadeButton.window, c->button_pix);
      XSetWindowBackgroundPixmap(wm->getDisplay(), c->close.window, c->button_pix);
      XSetWindowBackgroundPixmap(wm->getDisplay(), c->minimize.window, c->button_pix);
      XSetWindowBackgroundPixmap(wm->getDisplay(), c->maximize.window, c->button_pix);
}

void Client::reconfigure(Client *c)
{     
      createTitleImage(c);
      createRightSidebarImage(c);
      
      redraw(c);
}

void Client::send_config(Client *c)
{
      XConfigureEvent ce;
      XEvent foo;
      
      ce.type = ConfigureNotify;
      ce.event = c->window;
      ce.window = c->window;
      ce.x = c->x;
      ce.y = c->y;
      ce.width = c->width;
      ce.height = c->height;
      ce.border_width = 0;
      ce.above = None;
      ce.override_redirect = 0;
      
      if(! XCheckTypedWindowEvent(wm->getDisplay(), c->window, DestroyNotify, &foo))
      {
            if(! moving) reconfigure(c);
      }
      
      XSendEvent(wm->getDisplay(), c->window, false, StructureNotifyMask, (XEvent *)&ce);
}

void Client::move(Client *c)
{
      if (c) {    
            moving=true;
            
            drag(c);
            XMoveWindow(wm->getDisplay(), c->parent, c->x, c->y -theight(c));
            send_config(c);
            
            moving=false;
      }
}

void Client::drag(Client *c)
{
      XEvent ev;
      int x1=c->x;
      int y1=c->y;
      int old_cx = c->x;
      int old_cy = c->y;

      wm->grabPointer(wm->getRootWindow(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, wm->getMoveCursor());
      
      XGrabServer(wm->getDisplay());
      
      get_mouse_position(&x1, &y1);

      draw_outline(c);
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &ev);
            switch (ev.type) {
                  case MotionNotify:
                        draw_outline(c); /* clear */
                        c->x = old_cx + (ev.xmotion.x_root - x1);
                        c->y = old_cy + (ev.xmotion.y_root - y1);
                        draw_outline(c);
                  break;
                        
                  case ButtonRelease:
                        draw_outline(c); /* clear */
                        XUngrabServer(wm->getDisplay());
                        wm->ungrabPointer();
                        return;
            }
      }
}

void Client::resize(Client *c)
{
      if (c) {
            sweep(c);
            
            if (c->maxsized) {
                  c->maxsized = false;
            }

            XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width+c->right_sidebar_width, c->height + theight(c));               
            XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c));
            XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);          
            XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, 10, 10);           
            XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
            XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
            XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
            XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height); 
            
            send_config(c);
      }
}

void Client::recalculate_sweep(Client *c, int x1, int y1, int x2, int y2)
{
      int basex=0;
      int basey=0;

      c->width  = abs(x1 - x2) - DEFAULT_BORDER_SIZE;
      c->height = abs(y1 - y2) - DEFAULT_BORDER_SIZE;

      if (c->size->flags & PResizeInc) {
      
            basex = (c->size->flags & PBaseSize) ? c->size->base_width :
                  (c->size->flags & PMinSize) ? c->size->min_width : c->x;
            basey = (c->size->flags & PBaseSize) ? c->size->base_height :
                  (c->size->flags & PMinSize) ? c->size->min_height : c->y;
            c->width -= (c->width - basex) % c->size->width_inc;
            c->height -= (c->height - basey) % c->size->height_inc;
      }
      
      if (c->size->flags & PMinSize) {
            if (c->width < c->size->min_width) c->width = c->size->min_width;
            if (c->height < c->size->min_height) c->height = c->size->min_height;
      }
      
      if (c->size->flags & PMaxSize) {
            if (c->width > c->size->max_width) c->width = c->size->max_width;
            if (c->height > c->size->max_height) c->height = c->size->max_height;
      }
      
      c->x = (x1 <= x2) ? x1 : x1 - c->width;
      c->y = (y1 <= y2) ? y1 : y1 - c->height;
}

void Client::sweep(Client *c)
{
      XEvent ev;
      int old_cx = c->x;
      int old_cy = c->y;

      wm->grabPointer(wm->getRootWindow(), ButtonReleaseMask | PointerMotionMask, wm->getResizeCursor());
      
      draw_outline(c);
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &ev);
            switch (ev.type) {
                  case MotionNotify:
                        draw_outline(c);                    
                        recalculate_sweep(c, old_cx, old_cy, ev.xmotion.x_root , ev.xmotion.y_root);                    
                        draw_outline(c);
                  break;
                        
                  case ButtonRelease:
                        draw_outline(c);
                        wm->ungrabPointer();
                  return;
            }
      }
}

void Client::draw_outline(Client *c)
{
      if(c->shaded)
      {
            XDrawRectangle(wm->getDisplay(), wm->getRootWindow(), wm->getInvertGC(),
                  c->x,                                           /* x */
                  c->y - theight(c) + DEFAULT_BORDER_SIZE/2,            /* y */
                  c->width+10,                                    /* width */
                  theight(c) + DEFAULT_BORDER_SIZE);              /* height */                  
                              
      } else {
            
            XDrawRectangle(wm->getDisplay(), wm->getRootWindow(), wm->getInvertGC(),
            c->x + DEFAULT_BORDER_SIZE/2,                         /* x */
            c->y - theight(c) + DEFAULT_BORDER_SIZE/2,            /* y */
            c->width + 10 + DEFAULT_BORDER_SIZE,                  /* width */
            c->height + theight(c) + DEFAULT_BORDER_SIZE);  /* height */

            sprintf(c->client_position, "%dx%d+%d+%d", 
                  c->width+c->right_sidebar_width, 
                  c->height+theight(c), 
                  c->x, 
                  c->y);
            
            c->text_width=XTextWidth(wm->getXFont(), c->client_position, strlen(c->client_position));
      
            XDrawString(wm->getDisplay(), 
                  wm->getRootWindow(), 
                  wm->getInvertGC(),
                  c->x + c->width - XTextWidth(wm->getXFont(), 
                  c->client_position, 
                  strlen(c->client_position)),
                  c->y + c->height - DEFAULT_SPACE,
                  c->client_position, strlen(c->client_position));
      
      
      }
}

void Client::maximumresize(Client *c)
{
      // Check to see if this window can be resized more
      // if its at its max size then lets leave it alone.
      if (c && !(c->size->flags & PMaxSize) ) {

            if (c->maxsized)
            {
                  c->x = c->oumx;
                  c->y = c->oumy;
                  c->width = c->oumwidth;
                  c->height = c->oumheight;
                  c->maxsized = false;
            } else {
                  c->oumx = c->x;
                  c->oumy = c->y;
                  c->oumwidth = c->width;
                  c->oumheight = c->height;

                  c->x = 1;

                  if (wm->getTheme()->getToolbarExtraStyle() & TOOLBAR_TOP)
                  {
                        c->y = 28 + theight(c);
                        c->width = wm->getXRes() - 14;
                        c->height = wm->getYRes() - theight(c) - 34;
                        c->maxsized = true;
                  
                  } else {
                        c->y = 0 + theight(c);

                        c->width = wm->getXRes() - 14;
                        c->height = wm->getYRes() - 28 - theight(c);
                        c->maxsized = true;
                  }
            }

            XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width + c->right_sidebar_width, c->height + theight(c));
            XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c)); 
            XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);
            XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, right_sidebar_width, 10);      
            XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
            XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
            XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
            XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height);
                  
            send_config(c);
      }
}

void Client::hide(Client *c)
{
      c->ignore_unmap++;
      
      if(c->has_titlebar)
      {
            XUnmapSubwindows(wm->getDisplay(), c->parent);
            XUnmapWindow(wm->getDisplay(), c->parent);
      } else {
            XUnmapWindow(wm->getDisplay(), c->window);
      }
      
      set_wm_state(c, IconicState);
      
      wm->getIconMenu()->addIcon(c->name, c);
}

void Client::unhide(Client *c)
{
      mapClient(c);
}

// This repaints the titlebar and buttons on it, It also paints the window title.
void Client::redraw(Client *c)
{
      if (c->has_titlebar)
      {           
            XClearWindow(wm->getDisplay(), c->title);

            XClearWindow(wm->getDisplay(), c->close.window);
            XClearWindow(wm->getDisplay(), c->minimize.window);         
            XClearWindow(wm->getDisplay(), c->maximize.window);
            XClearWindow(wm->getDisplay(), c->shadeButton.window);
            XClearWindow(wm->getDisplay(), c->right_sidebar);
            XClearWindow(wm->getDisplay(), c->resize_win);
            
            // Close Button         
            XDrawLine(wm->getDisplay(), c->close.window, wm->getBorderGC(), 2,2,c->close.width - 3,c->close.height-3);
            XDrawLine(wm->getDisplay(), c->close.window, wm->getBorderGC(), 2,c->close.height - 3,c->close.width-3,2);

            // Maximize Button
            XDrawRectangle(wm->getDisplay(), c->maximize.window,
                  wm->getBorderGC(), 2, 2, c->maximize.width - 5, c->maximize.height - 5);
            XDrawLine(wm->getDisplay(),  c->maximize.window,
                  wm->getBorderGC(), 2, 3, c->maximize.width - 3, 3);

            // Minimize Button
            XDrawRectangle(wm->getDisplay(), c->minimize.window,
                  wm->getBorderGC(), 2, c->minimize.height - 5, c->minimize.width - 5, 2);
                        
            draw_shade_button(c);
                        
            if (c->name) 
            {
                  XDrawString(wm->getDisplay(), 
                        c->title, 
                        wm->getStringGC(), 
                        c->default_client_name_x, 
                        c->default_client_name_y, 
                        c->name, 
                        strlen(c->name));       
            }
      }
}

void Client::draw_shade_button(Client *c)
{
      if (c->shaded)
      {           
            // Draws a triangle pointing down which indicates that this
            // window is shaded.
            //
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        2, 5, 11, 5);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        3, 6, 10, 6);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        4, 7, 9, 7);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        5, 8, 8, 8);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        6, 9, 7, 9);      
      } else {

            // Draws a triangle pointing up which indicates that this
            // window is not shaded.
            //
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        6, 5, 7, 5);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        5, 6, 8, 6);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        4, 7, 9, 7);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        3, 8, 10, 8);
            XDrawLine(wm->getDisplay(),  c->shadeButton.window,wm->getBorderGC(), 
                        2, 9, 11, 9);
      }
}

void Client::change_gravity(Client *c, int multiplier)
{
      int dy = 0;
      int gravity = (c->size->flags & PWinGravity) ?
            c->size->win_gravity : NorthWestGravity;

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

      c->y += multiplier * dy;
}

void Client::set_shape(Client *c)
{
      int n, order;
      XRectangle *rect;

      rect = XShapeGetRectangles(wm->getDisplay(), c->window, ShapeBounding, &n, &order);
      if (n > 1) XShapeCombineShape(wm->getDisplay(),
            c->parent, ShapeBounding, 0, theight(c),
            c->window, ShapeBounding, ShapeSet);
      XFree(rect);
}

void Client::get_mouse_position(int *x, int *y)
{
      Window dw1=None;
      Window dw2=None;
      int t1=0;
      int t2=0;
      unsigned int t3=0;

      XQueryPointer(wm->getDisplay(), wm->getRootWindow(), &dw1, &dw2, x, y, &t1, &t2, &t3);
}

void Client::shade(Client *c)
{
      if (c->shaded)
      {
            XResizeWindow(wm->getDisplay(), c->parent, c->width+10, c->height + theight(c));
            c->shaded=false;
      } else {
            XResizeWindow(wm->getDisplay(), c->parent, c->width+10, theight(c));
            c->shaded=true;
      }
}

void Client::closeButtonPressed(Client *c)
{
      XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 2);
      
      XEvent ev;
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
            switch (ev.type) 
            {
                  case LeaveNotify:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 1);
                        return;
                  }
                  
                  case ButtonRelease:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->close.window, 1);
                        send_wm_delete(c);
                        return;
                  }
            }
      }
}

void Client::shadeButtonPressed(Client *c)
{
      XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 2);

      XEvent ev;
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
            switch (ev.type) 
            {
                  case LeaveNotify:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 1);
                        return;
                  }
                  
                  case ButtonRelease:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->shadeButton.window, 1);
                        XRaiseWindow(wm->getDisplay(), c->parent);
                        shade(c);
                        return;
                  }
            }
      }
}

void Client::minimizeButtonPressed(Client *c)
{
      XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 2);
      
      XEvent ev;
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
            switch (ev.type) 
            {
                  case LeaveNotify:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 1);
                        return;
                  }
                  
                  case ButtonRelease:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->minimize.window, 1);
                        hide(c);
                        return;
                  }
            }
      }
}

void Client::maximizeButtonPressed(Client *c)
{
      XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 2);
      
      XEvent ev;
      
      for (;;) {
            XMaskEvent(wm->getDisplay(), ButtonReleaseMask | LeaveWindowMask, &ev);
            switch (ev.type) 
            {
                  case LeaveNotify:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 1);
                        return;
                  }
                  
                  case ButtonRelease:
                  {
                        XSetWindowBorderWidth(wm->getDisplay(), c->maximize.window, 1);
                        
                        switch(ev.xbutton.button)
                        {
                              case 1: 
                              {
                                    if(c->shaded)
                                    {
                                          shade(c);
                                          XRaiseWindow(wm->getDisplay(), c->parent);
                                    
                                          // Make sure it doesn't keep resizing if its already max resized
                                          if (! c->maxsized) maximumresize(c);
                                    
                                    } else {
                                          XRaiseWindow(wm->getDisplay(), c->parent);
                                          maximumresize(c);
                                    }
                              return;
                              }
                        }
                  }
            }
      }
}

void Client::send_wm_delete(Client *c)
{
      if (c) send_xmessage(c->window, wm->getWMProtocolsAtom(), wm->getWMDeleteAtom(), CurrentTime);
}

int Client::send_xmessage(Window w, Atom a, long x, long y)
{
      XEvent ev;
      long mask;

      memset(&ev, '\0', sizeof ev);
      ev.type = ClientMessage;
      ev.xclient.window = w;
      ev.xclient.message_type = a;
      ev.xclient.format = 32;
      ev.xclient.data.l[0] = x;
      ev.xclient.data.l[1] = y;
      mask = (w == wm->getRootWindow()) ? SubstructureRedirectMask : 0L;
      
      return XSendEvent(wm->getDisplay(), w, false, mask, &ev);
}

void Client::set_wm_state(Client *c, int state)
{
      long data[2];

      data[0] = (long) state;
      data[1] = (long) None; /* icon window */

      c->state = state;
      
      XChangeProperty(wm->getDisplay(), c->window, wm->getWMStateAtom(), wm->getWMStateAtom(),
            32, PropModeReplace, (unsigned char *)data, 2);
}

int Client::get_wm_state(Client *c)
{
      Atom real_type;
      int real_format, state;
      unsigned long n, extra;
      unsigned char *data;

      if ((XGetWindowProperty(wm->getDisplay(), c->window, wm->getWMStateAtom(), 0L, 2L, false,
                        AnyPropertyType, &real_type, &real_format, &n,
                        &extra, &data) == Success) && n) {
            state = *(int *)data;
            XFree(data);
            return state;
      } else return WithdrawnState;
}

void Client::handle_enter_event(XCrossingEvent *e)
{
      Client *c = find_client(e->window); 

      if(c) XSetInputFocus(wm->getDisplay(), c->window, RevertToPointerRoot, CurrentTime);
}

void Client::handle_button_press_event(XButtonEvent *e)
{
      Client *c = find_client(e->window);

      if (c) 
      {
            switch (e->button) 
            {
                  case Button1:
                  {
                        if(c->close.window == e->window)         closeButtonPressed(c);
                        else if (c->maximize.window == e->window)    maximizeButtonPressed(c);
                        else if (c->minimize.window == e->window)    minimizeButtonPressed(c);
                        else if (c->shadeButton.window == e->window) shadeButtonPressed(c);
                        else if (c->right_sidebar == e->window) 
                        {
                              XRaiseWindow(wm->getDisplay(), c->parent);
                              redraw(c);
                              move(c);
                        } 
                        else if (c->resize_win == e->window)
                        {
                              XRaiseWindow(wm->getDisplay(), c->parent);
                              resize(c);
                        } 
                        else if (c->title == e->window)
                        {
                              XRaiseWindow(wm->getDisplay(), c->parent);
                              redraw(c);
                              move(c);
                        } 
                  break;
                  }

                  case Button2:
                  {     
                        if (c->title == e->window) 
                        {
                              // Middle click also allows you to shade the window.
                              if(c->shaded)
                              {
                                    XRaiseWindow(wm->getDisplay(), c->parent);
                                    shade(c);
                                    redraw(c);
                              } else {
                                    XRaiseWindow(wm->getDisplay(), c->parent);
                                    shade(c);
                                    redraw(c);
                              }
                        }     
                  break;
                  }
            }
      }
}

void Client::handle_configure_request(XConfigureRequestEvent *e)
{
      Client *c = find_client(e->window);
      XWindowChanges wc;

      if (c) 
      {
            change_gravity(c, -1);
            
            if (e->value_mask & CWX) c->x = e->x;
            if (e->value_mask & CWY) c->y = e->y;
            if (e->value_mask & CWWidth) c->width = e->width;
            if (e->value_mask & CWHeight) c->height = e->height;
            
            change_gravity(c, 1);

            if (c->width != wc.width && c->height != wc.height)
            {
                  if (c->has_titlebar) XMoveResizeWindow(wm->getDisplay(), c->window, 0, theight(c), c->width, c->height);
                  if (c->has_titlebar) XMoveResizeWindow(wm->getDisplay(), c->parent, c->x, c->y - theight(c), c->width+c->right_sidebar_width, c->height + theight(c));      
                  XMoveResizeWindow(wm->getDisplay(), c->title, 0, 0, c->width+c->right_sidebar_width, theight(c));
                  XMoveResizeWindow(wm->getDisplay(), c->right_sidebar, c->width, theight(c), c->right_sidebar_width, c->height - 10);
                  XMoveResizeWindow(wm->getDisplay(), c->resize_win, c->width, c->height + 10, right_sidebar_width, 10);       
                  XMoveWindow(wm->getDisplay(), c->maximize.window, c->width - 10, c->maximize.y);
                  XMoveWindow(wm->getDisplay(), c->minimize.window, c->width - 27, c->minimize.y);
                  XMoveWindow(wm->getDisplay(), c->shadeButton.window, c->width - 44, c->shadeButton.y);
            }
            
            wc.x = c->x;
            wc.y = c->y - theight(c);
            wc.width = c->width + c->right_sidebar_width;
            wc.height = c->height + theight(c);       
            wc.border_width = DEFAULT_BORDER_SIZE;
            wc.sibling = e->above;
            wc.stack_mode = e->detail;
            
            XConfigureWindow(wm->getDisplay(), c->parent, e->value_mask, &wc);

            // If a window has been shaded and we get a configure request
            // we need to fix the shade button so it shows the correct state.
            // Otherwise the client will be mapped but show that its been 
            // shaded. If you try and move it, it will draw a shaded outline.
            if(c->shaded) shade(c);
            
            send_config(c);
      } 
            
      if(c && c->has_titlebar)
      {
            wc.x = 0;
            wc.y = theight(c);
      } else {
            wc.x = e->x;
            wc.y = e->y;
      }
      
      wc.width = e->width;
      wc.height = e->height;
      wc.sibling = e->above;
      wc.stack_mode = e->detail;

      XConfigureWindow(wm->getDisplay(), e->window, e->value_mask, &wc);
}

void Client::handle_map_request(XMapRequestEvent *e)
{
      Client *c = find_client(e->window);

      if (c) mapClient(c);
      else make_new_client(e->window);
}

void Client::handle_unmap_event(XUnmapEvent *e)
{
      Client *c = find_client(e->window);

      if (c) {
            if (c->ignore_unmap) c->ignore_unmap--;
            else 
            {                 
                  if (get_wm_state(c) == IconicState)
                        XMapWindow(wm->getDisplay(), c->window);
                  else 
                  {                   
                        set_wm_state(c, WithdrawnState);
                        remove_client(c);
                  }
            }
      } 
}

void Client::handle_client_message(XClientMessageEvent *e)
{
      Client *c = find_client(e->window);
      
      if (c)
      {
            if(e->message_type == wm->getWMChangeStateAtom())
                  if(e->format == 32 && e->data.l[0] == IconicState) hide(c);
      }
}

void Client::handle_colormap_change(XColormapEvent *e)
{
      Client *c =  find_client(e->window);

      if (c && e->c_new) 
      {
            c->cmap = e->colormap;
            installColorMap(c->cmap);
      }     
}

void Client::handle_property_change(XPropertyEvent *e)
{
      Client *c = find_client(e->window);
      long dummy;

      if (c) 
      {
            switch (e->atom) 
            {
                  case XA_WM_NAME:
                  {
                        if (c->name) XFree(c->name);
                        XFetchName(wm->getDisplay(), c->window, &c->name);
                        XClearWindow(wm->getDisplay(), c->title);
                        redraw(c);
                  }
                  break;
                  
                  case XA_WM_NORMAL_HINTS:
                  {
                        XGetWMNormalHints(wm->getDisplay(), c->window, c->size, &dummy);                    
                  }
                  break;
                                    
                  //case XA_WM_ICON_NAME:
                  //break;
                  
                  case XA_WM_TRANSIENT_FOR:
                        getTransients(c);
                  break;
            }
      }
}


void Client::handle_expose_event(XExposeEvent *e)
{
      Client *c = find_client(e->window);

      if (c && e->count == 0) redraw(c);  
}

void Client::handle_destroy_notify(XDestroyWindowEvent *e)
{
      Client *c = find_client(e->window);
      
      if(c) remove_client(c);             
}

void Client::handle_shape_change(XShapeEvent *e)
{
      Client *c = find_client(e->window);

      if (c) 
      {
            c->shaped=true;
            set_shape(c);
      }     
}

void Client::installColorMap(Colormap cmap)
{
      XInstallColormap(wm->getDisplay(), cmap);
}

void Client::isIconic(Client *c)
{
      // Determine if this client is already in its iconic state upon creation
      // if so then we won't map it, but just iconify it.
      if (get_wm_state(c) == IconicState) hide(c);
      else mapClient(c);
}

void Client::mapClient(Client *c)
{
      if (c->has_titlebar)
      {                       
            if(c->has_shade_button)    XMapWindow(wm->getDisplay(), c->shadeButton.window);
            if(c->has_close_button)    XMapWindow(wm->getDisplay(), c->close.window);
            if(c->has_minimize_button) XMapWindow(wm->getDisplay(), c->minimize.window);
            if(c->has_maximize_button) XMapWindow(wm->getDisplay(), c->maximize.window);
            
            XMapWindow(wm->getDisplay(), c->right_sidebar);
            XMapWindow(wm->getDisplay(), c->resize_win);
            
            XMapWindow(wm->getDisplay(), c->title);
            
            XMapWindow(wm->getDisplay(), c->window);
            XMapRaised(wm->getDisplay(), c->parent);

      } 
      else XMapWindow(wm->getDisplay(), c->window);
      
      set_wm_state(c, NormalState);       
}

void Client::themeChange(Client *c)
{     
      if (c->has_titlebar)
      {
            XFreePixmap(wm->getDisplay(), c->frame_pix);
            XFreePixmap(wm->getDisplay(), c->right_pix);
            XFreePixmap(wm->getDisplay(), c->button_pix);
            XFreePixmap(wm->getDisplay(), c->resize_pix);
      
            createTitleImage(c);
            createRightSidebarImage(c);
            createButtonImage(c);   
            createResizeImage(c);

            redraw(c);
      }
}

void Client::raise() 
{
      XRaiseWindow(wm->getDisplay(), parent);
      redraw(this);
}

Generated by  Doxygen 1.6.0   Back to index