Logo Search packages:      
Sourcecode: beryl-plugins-unsupported version File versions

group.c

#include "group.h"

/**
 *
 * Beryl group plugin
 *
 * group.c
 *
 * Copyright : (C) 2006 by Patrick Niklaus, Roi Cohen, Danny Baumann
 * Authors: Patrick Niklaus <patrick.niklaus@googlemail.com>
 *          Roi Cohen       <roico@beryl-project.org>
 *          Danny Baumann   <maniac@beryl-project.org>
 *
 *
 * 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.
 *
 **/

/* helper for activating a window after a certain time a slot has dragged over it */

static Bool
groupDragHoverTimeout(void* closure)
{
      CompWindow *w = (CompWindow *) closure;

      if (!w)
            return FALSE;

      GROUP_SCREEN(w->screen);

      activateWindow(w);
      gs->dragHoverTimeoutHandle = 0;

      return FALSE;
}

/*
 * groupFindWindowIndex
 *
 */
int
groupFindWindowIndex(CompWindow *w, GroupSelection *g)
{
      int i;

      for(i = 0; i < g->nWins; i++)
      {
            if(g->windows[i]->id == w->id)
                  return i;
      }

      return -1;
}

/*
 * groupGrabScreen
 *
 */
void groupGrabScreen(CompScreen * s, GroupScreenGrabState newState)
{
      GROUP_SCREEN(s);

      if ((gs->grabState != newState) && gs->grabIndex) {
            removeScreenGrab(s, gs->grabIndex, NULL);
            gs->grabIndex = 0;
      }

      if (newState == ScreenGrabSelect) {
            gs->grabIndex = pushScreenGrab(s, None, "group");
      } else if (newState == ScreenGrabTabDrag) {
            gs->grabIndex = pushScreenGrab(s, None, "group-drag");
      }

      gs->grabState = newState;
}

/*
 * groupSyncWindows
 *
 */
void groupSyncWindows(GroupSelection *group)
{
       int i;
       for (i = 0; i < group->nWins; i++) {
               CompWindow *w = group->windows[i];
               syncWindowPosition(w);
       }
}

/*
 * groupRaiseWindows
 *
 */
void
groupRaiseWindows(CompWindow * top, GroupSelection *group)
{
      int i;
      for (i = 0; i < group->nWins; i++) {
            CompWindow *w = group->windows[i];
            if (w->id == top->id)
                  continue;
            restackWindowBelow(w, top);
      }
}

/*
 * groupMinimizeWindows
 *
 */
static void
groupMinimizeWindows(CompWindow *top, GroupSelection *group, Bool minimize)
{
      int i;
      for (i = 0; i < group->nWins; i++) {
            CompWindow *w = group->windows[i];
            if (w->id == top->id)
                  continue;

            if (minimize)
                  minimizeWindow(w);
            else
                  unminimizeWindow(w);
      }
}

/*
 * groupShadeWindows
 *
 */
static void
groupShadeWindows(CompWindow *top, GroupSelection *group, Bool shade)
{
      int i;
      for (i = 0; i < group->nWins; i++) {
            CompWindow *w = group->windows[i];
            if (w->id == top->id)
                  continue;

            if (shade)
                  w->state |= CompWindowStateShadedMask;
            else
                  w->state &= ~CompWindowStateShadedMask;

            updateWindowAttributes(w, FALSE);
      }
}

/*
 * groupDeleteGroupWindow
 *
 * Note: allowRegroup is need for a special case when groupAddWindowToGroup
 *       calls this function.
 *
 */
void groupDeleteGroupWindow(CompWindow * w, Bool allowRegroup)
{
      GROUP_WINDOW(w);
      GROUP_SCREEN(w->screen);
      GroupSelection *group = gw->group;

      if (!group)
            return;

      if (group->tabBar) {
            if (gw->slot)
            {
                  if (gs->draggedSlot && gs->dragged && gs->draggedSlot->window->id == w->id)
                        groupUnhookTabBarSlot(group->tabBar, gw->slot, FALSE);
                  else 
                  groupDeleteTabBarSlot(group->tabBar, gw->slot);
            }
            
            if(!gw->ungroup && group->nWins > 1)
            {
                  if(HAS_TOP_WIN(group))
                  {
                        // TODO: maybe add the IS_ANIMATED to the topTab for better constraining...
                  
                        CompWindow *topTab = TOP_TAB(group);
                        GroupWindow *gtw = GET_GROUP_WINDOW(topTab, gs);
                        int oldX = gw->orgPos.x;
                        int oldY = gw->orgPos.y;
                        
                        gw->orgPos.x = group->oldTopTabCenterX - WIN_WIDTH(w) / 2;
                        gw->orgPos.y = group->oldTopTabCenterY - WIN_HEIGHT(w) / 2;
                                              
                        gw->destination.x = group->oldTopTabCenterX - WIN_WIDTH(w)/2 + gw->mainTabOffset.x - 
                              gtw->mainTabOffset.x; 
                        gw->destination.y = group->oldTopTabCenterY - WIN_HEIGHT(w)/2 + gw->mainTabOffset.y - 
                              gtw->mainTabOffset.y;

                        gw->mainTabOffset.x = oldX;
                        gw->mainTabOffset.y = oldY;

                        gw->animateState |= IS_ANIMATED;

                        gw->tx = gw->ty = gw->xVelocity = gw->yVelocity = 0.0f;
                  }
                  
                  // Although when there is no top-tab, it will never really animate anything,
                  // if we don't start the animation, the window will never get remvoed.
                  groupStartTabbingAnimation(group, FALSE);

                  group->ungroupState = UngroupSingle;
                  gw->ungroup = TRUE;
                  
                  return;
            }
      }

      if (group->nWins && group->windows) {
            CompWindow **buf = group->windows;

            group->windows = (CompWindow **) calloc(group->nWins - 1, sizeof(CompWindow *));

            int counter = 0;
            int i;
            for (i = 0; i < group->nWins; i++) {
                  if (buf[i]->id == w->id)
                        continue;
                  group->windows[counter++] = buf[i];
            }
            group->nWins = counter;

            if (group->nWins == 1)
            {
                  damageWindowOutputExtents(group->windows[0]);   // Glow was removed from this window too.
                  updateWindowOutputExtents(group->windows[0]);
            }
            
            if (group->nWins == 1 &&
                gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b) {
                  if (group->changeTab) {
                        /* a change animation is pending: this most
                           likely means that a window must be moved
                           back onscreen, so we do that here */
                        CompWindow *lw = group->windows[0];

                        gs->queued = TRUE;
                        moveWindowOnscreen(lw);
                        moveWindow(lw, group->oldTopTabCenterX - WIN_X(lw) - WIN_WIDTH(lw) / 2, 
                              group->oldTopTabCenterY - WIN_Y(lw) - WIN_HEIGHT(lw) / 2, TRUE, TRUE);
                        syncWindowPosition(lw);
                        gs->queued = FALSE;
                  }
                  groupDeleteGroup(group);
            } else if (group->nWins <= 0) {
                  free(group->windows);
                  group->windows = NULL;
                  groupDeleteGroup(group);
            }

            free(buf);

            damageWindowOutputExtents(w);
            gw->group = NULL;
            updateWindowOutputExtents(w);
            
            if (allowRegroup && gs->opt[GROUP_SCREEN_OPTION_AUTOTAB].value.b && (w->type & gs->wMask)) {
                  groupAddWindowToGroup(w, NULL);
                  groupTabGroup(w);
            }
      }
}

/*
 * groupDeleteGroup
 *
 */
void groupDeleteGroup(GroupSelection *group)
{
      GROUP_SCREEN(group->screen);

      if (group->windows != NULL) {
            if (group->tabBar) {
                  groupUntabGroup(group);
                  group->ungroupState = UngroupAll;
                  return;
            }

            int i;
            for (i = 0; i < group->nWins; i++) {
                  CompWindow *cw = group->windows[i];
                  GROUP_WINDOW(cw);
                  GROUP_SCREEN(cw->screen);

                  damageWindowOutputExtents(cw);
                  gw->group = NULL;
                  updateWindowOutputExtents(cw);
                  
                  if (gs->opt[GROUP_SCREEN_OPTION_AUTOTAB].value.b && (cw->type & gs->wMask)) {
                        groupAddWindowToGroup(cw, NULL);
                        groupTabGroup(cw);
                  }
            }
            free(group->windows);
            group->windows = NULL;
      } else if (group->tabBar)
            groupDeleteTabBar(group);

      GroupSelection *prev = group->prev;
      GroupSelection *next = group->next;

      // relink stack
      if (prev || next) {
            if (prev) {
                  if (next)
                        prev->next = next;
                  else {
                        prev->next = NULL;
                  }
            }
            if (next) {
                  if (prev)
                        next->prev = prev;
                  else {
                        next->prev = NULL;
                        gs->groups = next;
                  }
            }
      } else {
            gs->groups = NULL;
      }
      free(group);
}

/*
 * groupAddWindowToGroup
 *
 */
void
groupAddWindowToGroup(CompWindow * w, GroupSelection *group)
{
      GROUP_SCREEN(w->screen);
      GROUP_WINDOW(w);

      if(group && (gw->group == group))
            return;

      if (gw->group)
      {
            gw->ungroup = TRUE;     //This will prevent setting up animations on the previous group.
            groupDeleteGroupWindow(w, FALSE);
            gw->ungroup = FALSE;
      }
      
      if (group) {
            group->windows = (CompWindow **) realloc(group->windows, sizeof(CompWindow *) * (group->nWins + 1));
            group->windows[group->nWins] = w;
            group->nWins++;

            gw->group = group;
            updateWindowOutputExtents(w);
            
            if(group->nWins == 2)
                  updateWindowOutputExtents(group->windows[0]);   // First window in the group got its glow too...

            if (group->tabBar && group->topTab)
            {
                  CompWindow *topTab = TOP_TAB(group);
                  
                  if(!gw->slot)
                        groupCreateSlot(group, w);
            
                  gw->destination.x = WIN_X(topTab) + (WIN_WIDTH(topTab) / 2) - (WIN_WIDTH(w) / 2);
                  gw->destination.y = WIN_Y(topTab) + (WIN_HEIGHT(topTab) / 2) - (WIN_HEIGHT(w) / 2);
                  gw->mainTabOffset.x = WIN_X(w) - gw->destination.x;
                  gw->mainTabOffset.y = WIN_Y(w) - gw->destination.y;
                  gw->orgPos.x = WIN_X(w);
                  gw->orgPos.y = WIN_Y(w);

                  gw->tx = gw->ty = gw->xVelocity = gw->yVelocity = 0.0f;
            
                  gw->animateState = IS_ANIMATED;

                  groupStartTabbingAnimation(group, TRUE);
                  
                  damageScreen(w->screen);
            }
      } else {
            GroupSelection *g = malloc(sizeof(GroupSelection));

            g->windows = (CompWindow **) calloc(1, sizeof(CompWindow *));
            g->windows[0] = w;
            g->screen = w->screen;
            g->nWins = 1;
            g->topTab = NULL;
            g->prevTopTab = NULL;
            g->nextTopTab = NULL;
            g->activateTab = NULL;
            g->doTabbing = FALSE;
            g->changeAnimationTime = 0;
            g->changeAnimationDirection = 0;
            g->changeState = PaintOff;
            g->tabbingState = PaintOff;
            g->changeTab = FALSE;
            g->ungroupState = UngroupNone;
            g->tabBar = NULL;

            g->grabWindow = None;
            g->grabMask = 0;
            
            g->inputPrevention = None;

            g->oldTopTabCenterX = 0;
            g->oldTopTabCenterY = 0;

            // glow color
            srand(time(NULL));
            g->color[0] = rand() % 0xFFFF;
            g->color[1] = rand() % 0xFFFF;
            g->color[2] = rand() % 0xFFFF;
            g->color[3] = 0xFFFF;

            // relink stack
            if (gs->groups) {
                  gs->groups->prev = g;
                  g->next = gs->groups;
                  g->prev = NULL;
                  gs->groups = g;
            } else {
                  g->prev = NULL;
                  g->next = NULL;
                  gs->groups = g;
            }

            gw->group = g;
      }
}

/*
 * groupGroupWindows
 *
 */
Bool
groupGroupWindows(CompDisplay * d, CompAction * action,
              CompActionState state, CompOption * option, int nOption)
{
      GROUP_DISPLAY(d);

      if (gd->tmpSel.nWins > 0) {
            int i;
            CompWindow *cw;
            GroupSelection *group = NULL;
            Bool tabbed = FALSE;

            for(i = 0; i < gd->tmpSel.nWins; i++)
            {
                  cw = gd->tmpSel.windows[i];
                  GROUP_WINDOW(cw);

                  if (gw->group)
                  {
                        if(!tabbed || group->tabBar)
                              group = gw->group;
                        
                        if(group->tabBar)
                              tabbed = TRUE;
                  }
            }

            // we need to do one first to get the pointer of a new group
            cw = gd->tmpSel.windows[0];
            groupAddWindowToGroup(cw, group);

            GROUP_WINDOW (cw);
            gw->inSelection = FALSE;
            damageScreen(cw->screen);
            group = gw->group;

            for (i = 1; i < gd->tmpSel.nWins; i++) {
                  cw = gd->tmpSel.windows[i];
                  GROUP_WINDOW(cw);

                  groupAddWindowToGroup(cw, group);

                  gw->inSelection = FALSE;
                  damageScreen(cw->screen);
            }

            // exit selection
            free(gd->tmpSel.windows);
            gd->tmpSel.windows = NULL;
            gd->tmpSel.nWins = 0;
      }

      return FALSE;
}

/*
 * groupUnGroupWindows
 *
 */
Bool
groupUnGroupWindows(CompDisplay * d, CompAction * action,
                CompActionState state, CompOption * option,
                int nOption)
{
      CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);

      if (!cw)
            return FALSE;

      GROUP_WINDOW(cw);

      if (gw->group) {
            groupDeleteGroup(gw->group);
      }

      return FALSE;
}

/*
 * groupRemoveWindow
 *
 */
Bool
groupRemoveWindow(CompDisplay * d, CompAction * action,
              CompActionState state, CompOption * option, int nOption)
{
      CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);
      if (!cw)
            return FALSE;
      GROUP_WINDOW(cw);

      if (gw->group)
            groupDeleteGroupWindow(cw, TRUE);

      return FALSE;
}

/*
 * groupCloseWindows
 *
 */
Bool
groupCloseWindows(CompDisplay * d, CompAction * action,
              CompActionState state, CompOption * option, int nOption)
{
      CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
      if (!w)
            return FALSE;
      GROUP_WINDOW(w);

      if (gw->group) {

            int nWins = gw->group->nWins;
            int i;
            for (i = 0; i < nWins; i++) {
                  CompWindow *cw = gw->group->windows[i];
                  closeWindow(cw, getCurrentTimeFromDisplay(d));
            }
      }

      return FALSE;
}

/*
 * groupChangeColor
 *
 */
Bool
groupChangeColor(CompDisplay * d, CompAction * action,
                 CompActionState state, CompOption * option,
                 int nOption)
{
      CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
      if (!w)
            return FALSE;
      GROUP_WINDOW(w);

      if (gw->group) {
            srand(time(NULL));
            gw->group->color[0] = rand() % 0xFFFF;
            gw->group->color[1] = rand() % 0xFFFF;
            gw->group->color[2] = rand() % 0xFFFF;

            groupRenderTopTabHighlight(gw->group);

            damageScreen(w->screen);
      }

      return FALSE;
}

/*
 * groupSetIgnore
 *
 */
Bool
groupSetIgnore(CompDisplay * d, CompAction * action, CompActionState state,
             CompOption * option, int nOption)
{
      GROUP_DISPLAY(d);

      gd->ignoreMode = TRUE;

      if (state & CompActionStateInitKey)
            action->state |= CompActionStateTermKey;

      return FALSE;
}

/*
 * groupUnsetIgnore
 *
 */
Bool
groupUnsetIgnore(CompDisplay * d, CompAction * action,
             CompActionState state, CompOption * option, int nOption)
{
      GROUP_DISPLAY(d);

      gd->ignoreMode = FALSE;

      action->state &= ~CompActionStateTermKey;

      return FALSE;
}

/*
 * groupHandleButtonPressEvent
 *
 */
static void
groupHandleButtonPressEvent(CompDisplay *d, XEvent *event)
{
      int xRoot = event->xbutton.x_root;
      int yRoot = event->xbutton.y_root;
      int button = event->xbutton.button;

      CompScreen *s = findScreenAtDisplay(d, event->xbutton.root);

      if (!s)
            return;

      GROUP_SCREEN(s);

      if (button == 1) {
            GroupSelection *group;
                  
            for (group = gs->groups; group; group = group->next) {
                  if ((group->inputPrevention == event->xbutton.window) && group->tabBar) {
                        GroupTabBarSlot *slot;
                              
                        for (slot = group->tabBar->slots; slot; slot = slot->next) {
                              if (XPointInRegion (slot->region, xRoot, yRoot)) {
                                    CompScreen *s = group->screen;
                                    GROUP_SCREEN(s);

                                    gs->draggedSlot = slot;
                                    gs->dragged = FALSE; // The slot isn't dragged yet...
                                          
                                    gs->prevX = xRoot;
                                    gs->prevY = yRoot;

                                    if (gs->grabState == ScreenGrabNone) {
                                          if (!otherScreenGrabExist(s, "group", "group-drag"))
                                                groupGrabScreen(s, ScreenGrabTabDrag);
                                    }
                              }
                        }
                  }
            }
      } else if ((button == 4) || (button == 5)) {
            CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
            CompWindow *topTab = w;
                  
            if(!w)
                  return;

            GROUP_WINDOW(w);
            GROUP_SCREEN(w->screen);
      
            if(!gw->slot || !gw->group || !gw->group->tabBar)
                  return;

            if(gw->group->tabBar->state != PaintOn && gw->group->tabBar->state != PaintPermanentOn)
                  return;

            if(!XPointInRegion(gw->group->tabBar->region, xRoot, yRoot))
                  return;
                  
            if(gw->group->nextTopTab)
                  topTab = NEXT_TOP_TAB(gw->group);
            else if(gw->group->topTab)
                  topTab = TOP_TAB(gw->group); // If there are no tabbing animations, topTab is never NULL.
                  
            gw = GET_GROUP_WINDOW(topTab, gs);

            if (button == 4) {
                  if(gw->slot->prev)
                        groupChangeTab(gw->slot->prev, RotateLeft);
                  else
                        groupChangeTab(gw->group->tabBar->revSlots, RotateLeft);
            } else {
                  if(gw->slot->next)
                        groupChangeTab(gw->slot->next, RotateRight);
                  else
                        groupChangeTab(gw->group->tabBar->slots, RotateRight);
            }
      }
}

/*
 * groupHandleButtonReleaseEvent
 *
 */
static void
groupHandleButtonReleaseEvent(CompDisplay *d, XEvent *event)
{
      GroupSelection *group;

      if (event->xbutton.button != 1)
            return;

      CompScreen *s = findScreenAtDisplay(d, event->xbutton.root);
      if (!s) 
            return;
      
      GROUP_SCREEN(s);

      if(!gs->draggedSlot)
            return;
                  
      if(!gs->dragged) {
            groupChangeTab(gs->draggedSlot, RotateUncertain);
            gs->draggedSlot = NULL;

            if (gs->grabState == ScreenGrabTabDrag)
                  groupGrabScreen(s, ScreenGrabNone);
                        
            return;
      }
                  
      GROUP_WINDOW(gs->draggedSlot->window);

      int vx, vy;
      Region newRegion = XCreateRegion();
      XUnionRegion(newRegion, gs->draggedSlot->region, newRegion);

      groupGetDrawOffsetForSlot(gs->draggedSlot, &vx, &vy);
      XOffsetRegion(newRegion, vx, vy);
      
      Bool inserted = FALSE;
      for(group = gs->groups; group; group = group->next) {
            Bool inTabBar;
            
            if (!group->tabBar)
                  continue;

            // create clipping region
            Region clip = groupGetClippingRegion(TOP_TAB(group));
            
            Region buf = XCreateRegion();
            XIntersectRegion(newRegion, group->tabBar->region, buf);
            XSubtractRegion(buf, clip, buf);
            XDestroyRegion(clip);
            
            inTabBar = !XEmptyRegion(buf);
            
            XDestroyRegion(buf);
            
            if(!inTabBar)
                  continue;

            GroupTabBarSlot *slot;
            
            for(slot = group->tabBar->slots; slot; slot = slot->next) {
                  if(slot == gs->draggedSlot)
                        continue;
                  
                  Region slotRegion = XCreateRegion();
                  XRectangle rect;
                  Bool inSlot;
                  
                  if(slot->prev && slot->prev != gs->draggedSlot)
                        rect.x = slot->prev->region->extents.x2;
                  else if(slot->prev && slot->prev == gs->draggedSlot && gs->draggedSlot->prev)
                        rect.x = gs->draggedSlot->prev->region->extents.x2;
                  else
                        rect.x = group->tabBar->region->extents.x1;
                  
                  rect.y = slot->region->extents.y1;
                  
                  if(slot->next && slot->next != gs->draggedSlot)
                        rect.width = slot->next->region->extents.x1 - rect.x;
                  else if(slot->next && slot->next == gs->draggedSlot && gs->draggedSlot->next)
                        rect.width = gs->draggedSlot->next->region->extents.x1 - rect.x;
                  else
                        rect.width = group->tabBar->region->extents.x2;
                  
                  rect.height = slot->region->extents.y2 - slot->region->extents.y1;
                  
                  XUnionRectWithRegion(&rect, slotRegion, slotRegion);
                  
                  Region buf = XCreateRegion();
                  XIntersectRegion(newRegion, slotRegion, buf);
                  
                  inSlot = !XEmptyRegion(buf);
                  
                  XDestroyRegion(buf);
                  XDestroyRegion(slotRegion);

                  if (!inSlot)
                        continue;
                  
                  GroupTabBarSlot *tmpDraggedSlot = gs->draggedSlot;
                              
                  if(group != gw->group) {
                        GroupSelection *tmpGroup = gw->group;
                        
                        // if the dragged window is not the top tab, move it onscreen
                        if (!IS_TOP_TAB(gs->draggedSlot->window, tmpGroup) && tmpGroup->topTab) {
                              CompWindow *tw = tmpGroup->topTab->window;

                              tmpGroup->oldTopTabCenterX = WIN_X(tw) + WIN_WIDTH(tw) / 2;
                              tmpGroup->oldTopTabCenterY = WIN_Y(tw) + WIN_HEIGHT(tw) / 2;

                              gs->queued = TRUE;
                              moveWindowOnscreen(gs->draggedSlot->window);
                              moveWindow(gs->draggedSlot->window, 
                                          gw->group->oldTopTabCenterX - WIN_X(gs->draggedSlot->window) - WIN_WIDTH(gs->draggedSlot->window) / 2, 
                                          gw->group->oldTopTabCenterY - WIN_Y(gs->draggedSlot->window) - WIN_HEIGHT(gs->draggedSlot->window) / 2, 
                                          TRUE, TRUE);
                              syncWindowPosition(gs->draggedSlot->window);
                              gs->queued = FALSE;
                        }

                        // Change the group.
                        groupAddWindowToGroup(gs->draggedSlot->window, group);
                  } else
                        groupUnhookTabBarSlot(group->tabBar, gs->draggedSlot, TRUE);

                  // for re-calculating the tab-bar including the dragged window
                  gs->draggedSlot = NULL;
                  gs->dragged = FALSE;
                  inserted = TRUE;
                        
                  if((tmpDraggedSlot->region->extents.x1 + tmpDraggedSlot->region->extents.x2 + (2 * vx)) / 2 > 
                            (slot->region->extents.x1 + slot->region->extents.x2) / 2)
                        groupInsertTabBarSlotAfter(group->tabBar, tmpDraggedSlot, slot);
                  else
                        groupInsertTabBarSlotBefore(group->tabBar, tmpDraggedSlot, slot);
                  
                  // Hide tab-bars.
                  GroupSelection *tmpGroup;
                  for(tmpGroup = gs->groups; tmpGroup; tmpGroup = tmpGroup->next)
                        groupTabSetVisibility(tmpGroup, FALSE, PERMANENT);
                  
                  break;
            }

            if (inserted)
                  break;
      }

      if (newRegion)
            XDestroyRegion(newRegion);

      if (!inserted) {
            CompWindow *draggedSlotWindow = gs->draggedSlot->window;
            GroupSelection *tmpGroup;
            
            for(tmpGroup = gs->groups; tmpGroup; tmpGroup = tmpGroup->next)
                  groupTabSetVisibility(tmpGroup, FALSE, PERMANENT);
                        
            gs->draggedSlot = NULL;
            gs->dragged = FALSE;

            if(gs->opt[GROUP_SCREEN_OPTION_DND_UNGROUP_WINDOW].value.b)
                  groupDeleteGroupWindow(draggedSlotWindow, TRUE);

            else if (gw->group && gw->group->topTab) {
                  groupRecalcTabBarPos(gw->group,
                        (gw->group->tabBar->region->extents.x1 + gw->group->tabBar->region->extents.x2) / 2,
                        gw->group->tabBar->region->extents.x1, gw->group->tabBar->region->extents.x2);
            }
                  
            // to remove the painted slot 
            damageScreen(s);
      }

      if (gs->grabState == ScreenGrabTabDrag)
            groupGrabScreen(s, ScreenGrabNone);

      if (gs->dragHoverTimeoutHandle) {
            compRemoveTimeout(gs->dragHoverTimeoutHandle);
            gs->dragHoverTimeoutHandle = 0;
      }
}

/*
 * groupHandleMotionEvent
 *
 */

/* the radius to determine if it was a click or a drag */
#define RADIUS 5

static void 
groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
      GROUP_SCREEN(s);

      if (gs->grabState == ScreenGrabTabDrag) {
            int dx, dy;
            REGION reg;
            Region draggedRegion = gs->draggedSlot->region;
                                                
            reg.rects = &reg.extents;
            reg.numRects = 1;

            dx = xRoot - gs->prevX;
            dy = yRoot - gs->prevY;
                        
            if(gs->dragged || abs(dx) > RADIUS || abs(dy) > RADIUS) {
                  gs->prevX = xRoot;
                  gs->prevY = yRoot;
                                    
                  if(!gs->dragged) {
                        GroupSelection *group;
                        GROUP_WINDOW(gs->draggedSlot->window);
                        
                        gs->dragged = TRUE;
                              
                        for(group = gs->groups; group; group = group->next)
                              groupTabSetVisibility(group, TRUE, PERMANENT);
                              
                        groupRecalcTabBarPos(gw->group, (gw->group->tabBar->region->extents.x1 + gw->group->tabBar->region->extents.x2) / 2,
                                                 gw->group->tabBar->region->extents.x1, gw->group->tabBar->region->extents.x2);
                  }
                  

                  int vx,vy;
                  groupGetDrawOffsetForSlot(gs->draggedSlot, &vx, &vy);

                  // (border = 5) + (buffer = 2) == (damage buffer = 7)
                  //TODO: respect border option.
                  reg.extents.x1 = draggedRegion->extents.x1 - 7 + vx;
                  reg.extents.y1 = draggedRegion->extents.y1 - 7 + vy;
                  reg.extents.x2 = draggedRegion->extents.x2 + 7 + vx;
                  reg.extents.y2 = draggedRegion->extents.y2 + 7 + vy;
                  damageScreenRegion(s, &reg);
                                                      
                  XOffsetRegion (gs->draggedSlot->region, dx, dy);
                  gs->draggedSlot->springX = (gs->draggedSlot->region->extents.x1 + gs->draggedSlot->region->extents.x2) / 2;

                  reg.extents.x1 = draggedRegion->extents.x1 - 7 + vx;
                  reg.extents.y1 = draggedRegion->extents.y1 - 7 + vy;
                  reg.extents.x2 = draggedRegion->extents.x2 + 7 + vx;
                  reg.extents.y2 = draggedRegion->extents.y2 + 7 + vy;
                  damageScreenRegion(s, &reg);
            }
      } else if (gs->grabState == ScreenGrabSelect) {
            groupDamageSelectionRect(s, xRoot, yRoot);
      }
}

/*
 * groupHandleEvent
 *
 */
void groupHandleEvent(CompDisplay * d, XEvent * event)
{
      GROUP_DISPLAY(d);

      switch (event->type) {
      case MotionNotify:
            {
                  CompScreen *s = findScreenAtDisplay(d, event->xmotion.root);
                  if (s)
                        groupHandleMotionEvent(s, d->pointerX, d->pointerY);
                  
                  break;
            }

      case ButtonPress:
            groupHandleButtonPressEvent(d, event);
            break;

      case ButtonRelease:
            groupHandleButtonReleaseEvent(d, event);
            break;

      case UnmapNotify:
            {
                  CompWindow *w = findWindowAtDisplay(d, event->xunmap.window);
                  if (!w)
                        break;
                  GROUP_WINDOW(w);
                  GROUP_SCREEN(w->screen);

                  if (w->pendingUnmaps) {
                        if (w->shaded) {
                              gw->windowState = WindowShaded;

                              if (gw->group && gs->opt[GROUP_SCREEN_OPTION_SHADE_ALL].value.b)
                                    groupShadeWindows(w, gw->group, TRUE);
                        } else if (w->minimized) {
                              gw->windowState = WindowMinimized;

                              if (gw->group && gs->opt[GROUP_SCREEN_OPTION_MINIMIZE_ALL].value.b)
                                    groupMinimizeWindows(w, gw->group, TRUE);
                        }
                  }
                  
                  if (gw->group) {
                        if (gw->group->tabBar && IS_TOP_TAB(w, gw->group)) {
                              /* on unmap of the top tab, hide the tab bar and the
                                 input prevention window */
                              groupTabSetVisibility(gw->group, FALSE, PERMANENT);
                        }
                        if (!w->pendingUnmaps) {
                              //close event
                              gw->ungroup = TRUE;     // This will prevent setting up animations on group.
                              groupDeleteGroupWindow(w, FALSE);
                              gw->ungroup = FALSE;
                              damageScreen(w->screen);
                        }
                  }
                  break;
            }

      case ClientMessage:
            if (event->xclient.message_type == d->winActiveAtom) {
                  CompWindow *w = findWindowAtDisplay(d, event->xclient.window);
                  if (!w)
                        return;

                  GROUP_WINDOW(w);

                  if (gw->group && gw->group->tabBar && HAS_TOP_WIN(gw->group)) {
                        CompWindow *tw = TOP_TAB(gw->group);

                        if (w->id != tw->id) {
                              /* if a non top-tab has been activated, switch to the
                                 top-tab instead - but only if is visible */
                              if (tw->shaded) {
                                    tw->state &= ~CompWindowStateShadedMask;
                                    updateWindowAttributes(tw, FALSE);
                              } else if (tw->minimized)
                                    unminimizeWindow(tw);

                              if (!(tw->state & CompWindowStateHiddenMask)) {
                                    if (!gw->group->changeTab)
                                          gw->group->activateTab = gw->slot;
                                    sendWindowActivationRequest(tw->screen, tw->id);
                              }
                        }
                  }
            }
            break;

      default:
            break;
      }

      UNWRAP(gd, d, handleEvent);
      (*d->handleEvent) (d, event);
      WRAP(gd, d, handleEvent, groupHandleEvent);

      switch (event->type) {
      case PropertyNotify:
            // focus event
            if (event->xproperty.atom == d->winActiveAtom) {
                  CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
                  if (!w)
                        break;

                  GROUP_WINDOW(w);
                  GROUP_SCREEN(w->screen);

                  if (gw->group) {
                        if (!gw->group->tabBar && !screenGrabExist(w->screen, "scale", 0) &&
                                    gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b) {
                              groupRaiseWindows(w, gw->group);
                        }

                        if (gw->group->activateTab) {
                              groupChangeTab(gw->group->activateTab, RotateUncertain);
                              gw->group->activateTab = NULL;
                        }
                  }
            }
            break;

      case EnterNotify:
            {
                  CompWindow *w = findWindowAtDisplay(d, event->xcrossing.window);
                  if (!w)
                        break;

                  GROUP_WINDOW(w);
                  if (gw->group) {
                        GROUP_SCREEN(w->screen);

                        if (gs->draggedSlot && gs->dragged && IS_TOP_TAB(w, gw->group)) {
                              int hoverTime = 
                                    gs->opt[GROUP_SCREEN_OPTION_TAB_DRAG_HOVER_TIME].value.f * 1000;
                              if (gs->dragHoverTimeoutHandle)
                                    compRemoveTimeout(gs->dragHoverTimeoutHandle);

                              if (hoverTime > 0)
                                    gs->dragHoverTimeoutHandle = 
                                          compAddTimeout(hoverTime, groupDragHoverTimeout, w);
                        }
                  }
            }

      case ConfigureNotify:
            {
                  CompWindow *w = findWindowAtDisplay(d, event->xconfigure.window);

                  if (!w)
                        break;

                  GROUP_WINDOW(w);

                  if (gw->group && gw->group->tabBar && IS_TOP_TAB(w, gw->group) && gw->group->inputPrevention)
                        groupUpdateInputPreventionWindow(gw->group);
            }
            break;


      default:
            break;
      }
}

/*
 * groupGetOutputExtentsForWindow
 *
 */
void
groupGetOutputExtentsForWindow (CompWindow * w, CompWindowExtents * output)
{
      GROUP_SCREEN (w->screen);
      GROUP_WINDOW (w);

      UNWRAP (gs, w->screen, getOutputExtentsForWindow);
      (*w->screen->getOutputExtentsForWindow) (w, output);
      WRAP (gs, w->screen, getOutputExtentsForWindow,
            groupGetOutputExtentsForWindow);

      if (gw->group && gw->group->nWins > 1)
      {
            int glowSize = gs->opt[GROUP_SCREEN_OPTION_GLOW_SIZE].value.i;

            if (glowSize > output->left)
                  output->left = glowSize;
            if (glowSize > output->right)
                  output->right = glowSize;
            if (glowSize > output->top)
                  output->top = glowSize;
            if (glowSize > output->bottom)
                  output->bottom = glowSize;
      }
}

/*
 * groupWindowResizeNotify
 *
 */
void groupWindowResizeNotify(CompWindow * w, int dx, int dy, int dwidth,
                                           int dheight, Bool preview)
{
      GROUP_SCREEN(w->screen);
      GROUP_DISPLAY(w->screen->display);
      GROUP_WINDOW(w);

      UNWRAP(gs, w->screen, windowResizeNotify);
      (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight, preview);
      WRAP(gs, w->screen, windowResizeNotify, groupWindowResizeNotify);

      if (gw->glowQuads)
            groupComputeGlowQuads (w, &gs->glowTexture.matrix);

      if (!dx && !dy && !dwidth && !dheight)
            return;

      if (preview)
            return;

      if (gw->group && gw->group->tabBar && 
          (gw->group->tabBar->state != PaintOff) && IS_TOP_TAB(w, gw->group)) {
            groupRecalcTabBarPos(gw->group, w->screen->display->pointerX,
                  WIN_X(w), WIN_X(w) + WIN_WIDTH(w));
      }

      if (gw->group && !gd->ignoreMode) {
            if (((gw->lastState & MAXIMIZE_STATE) != (w->state & MAXIMIZE_STATE))
                   && gs->opt[GROUP_SCREEN_OPTION_RESIZE_UNMAXIMIZE].value.b) 
            {
                  int i;
                  for (i = 0; i < gw->group->nWins; i++) {
                        CompWindow *cw = gw->group->windows[i];
                        if (!cw)
                              continue;

                        if (cw->id == w->id)
                              continue;

                        maximizeWindow(cw, w->state & MAXIMIZE_STATE);
                  }
            } else if ((gw->group->grabWindow == w->id) && gs->opt[GROUP_SCREEN_OPTION_RESIZE].value.b) {
                  int i;
                  for (i = 0; i < gw->group->nWins; i++) {
                        CompWindow *cw =  gw->group->windows[i];
                        if (!cw)
                              continue;
                  
                        if (cw->state & MAXIMIZE_STATE)
                              continue;

                        if (cw->id == w->id)
                              continue;

                        int nx = 0;
                        int ny = 0;
      
                        if (gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE].value.b) {
                              int distX = cw->serverX - (w->serverX - dx);
                              int distY = cw->serverY - (w->serverY - dy);
                              int ndistX = distX * ((float) w->serverWidth / (float) (w->serverWidth - dwidth));
                              int ndistY = distY * ((float) w->serverHeight / (float) (w->serverHeight - dheight));
                              nx = w->serverX + ndistX;
                              ny = w->serverY + ndistY;
                        } else {
                              nx = cw->serverX + dx;
                              ny = cw->serverY + dy;
                        }
      
                        int nwidth = cw->serverWidth + dwidth;
                        int nheight = cw->serverHeight + dheight;

                        constrainNewWindowSize(cw, nwidth, nheight, &nwidth, &nheight);

                        XWindowChanges xwc;
                        
                        xwc.x = nx;
                        xwc.y = ny;
                        xwc.width = nwidth;
                        xwc.height = nheight;

                        configureXWindow(cw, CWX | CWY | CWWidth | CWHeight, &xwc);
                  }
            }
      }
}

/*
 * groupWindowMoveNotify
 *
 */
void
groupWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate)
{
      GROUP_SCREEN(w->screen);
      GROUP_DISPLAY(w->screen->display);
      GROUP_WINDOW(w);

      UNWRAP(gs, w->screen, windowMoveNotify);
      (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
      WRAP(gs, w->screen, windowMoveNotify, groupWindowMoveNotify);

      if (gw->glowQuads)
            groupComputeGlowQuads (w, &gs->glowTexture.matrix);

      if(!gw->group || gs->queued)
            return;

      if (w->state & CompWindowStateOffscreenMask)
            return;
      
      Bool viewportChange = screenGrabExist (w->screen, "rotate", 0) &&
            ((dx && !(dx % w->screen->width)) || (dy && !(dy % w->screen->height)));

      if (viewportChange && (gw->animateState & IS_ANIMATED)) {
            gw->destination.x += dx;
            gw->destination.y += dy;
      }

      if (gw->group->tabBar && IS_TOP_TAB(w, gw->group)) {
            GroupTabBarSlot *slot;
            GroupTabBar *bar = gw->group->tabBar;

            if(gs->opt[GROUP_SCREEN_OPTION_SPRING_MODEL_ON_MOVE].value.b)
                  XOffsetRegion (bar->region, 0, dy);
            else
                  XOffsetRegion (bar->region, dx, dy);

            bar->rightSpringX += dx;
            bar->leftSpringX += dx;
                  
            for(slot = bar->slots; slot; slot = slot->next) {
                  if(gs->opt[GROUP_SCREEN_OPTION_SPRING_MODEL_ON_MOVE].value.b)
                        XOffsetRegion (slot->region, 0, dy);
                  else
                        XOffsetRegion (slot->region, dx, dy);
                  slot->springX += dx;
            }
                  
            groupUpdateInputPreventionWindow(gw->group);
            
            return;
      }

      if (gw->group->doTabbing || gd->ignoreMode || 
            (gw->group->grabWindow != w->id) ||
          !screenGrabExist (w->screen, "move", 0) ||
          !gs->opt[GROUP_SCREEN_OPTION_MOVE].value.b)
            return;

      int i;

      for (i = 0; i < gw->group->nWins; i++) {
            CompWindow *cw = gw->group->windows[i];
            if (!cw)
                  continue;

            if (cw->id == w->id)
                  continue;

            GROUP_WINDOW(cw);

            if (cw->state & MAXIMIZE_STATE) {
                  if (viewportChange) {
                        gw->needsPosSync = TRUE;
                        groupEnqueueMoveNotify (cw, -dx, -dy, TRUE);
                  }
            } else if (!viewportChange) {
                  gw->needsPosSync = TRUE;
                  groupEnqueueMoveNotify (cw, dx, dy, FALSE);
            }
      }
}

void
groupWindowGrabNotify(CompWindow * w,
                       int x, int y, unsigned int state, unsigned int mask)
{
      GROUP_SCREEN(w->screen);
      GROUP_DISPLAY(w->screen->display);
      GROUP_WINDOW(w);

      if (gw->group && !gd->ignoreMode && !gs->queued) {
            int i;
            for (i = 0; i < gw->group->nWins; i++) {
                  CompWindow *cw = gw->group->windows[i];
                  if (!cw)
                        continue;
                  
                  if (cw->id != w->id) 
                        groupEnqueueGrabNotify (cw, x, y, state, mask);
            }

            gw->group->grabWindow = w->id;
            gw->group->grabMask = mask;
      }

      UNWRAP(gs, w->screen, windowGrabNotify);
      (*w->screen->windowGrabNotify) (w, x, y, state, mask);
      WRAP(gs, w->screen, windowGrabNotify, groupWindowGrabNotify);
}

void groupWindowUngrabNotify(CompWindow * w)
{
      GROUP_SCREEN(w->screen);
      GROUP_DISPLAY(w->screen->display);
      GROUP_WINDOW(w);

      if (gw->group && !gd->ignoreMode && !gs->queued) {
            int i;

            groupDequeueMoveNotifies(w->screen);

            for (i = 0; i < gw->group->nWins; i++) {
                  CompWindow *cw = gw->group->windows[i];
                  if (!cw)
                        continue;

                  if (cw->id != w->id) {
                        GROUP_WINDOW(cw);

                        if (gw->needsPosSync) {
                              syncWindowPosition(cw);
                              gw->needsPosSync = FALSE;
                        }
                        groupEnqueueUngrabNotify (cw);
                  }
            }

            gw->group->grabWindow = None;
            gw->group->grabMask = 0;
      }

      UNWRAP(gs, w->screen, windowUngrabNotify);
      (*w->screen->windowUngrabNotify) (w);
      WRAP(gs, w->screen, windowUngrabNotify, groupWindowUngrabNotify);
}


Bool groupDamageWindowRect(CompWindow * w, Bool initial, BoxPtr rect)
{

      GROUP_SCREEN(w->screen);
      Bool status;

      UNWRAP(gs,w->screen,damageWindowRect);
      status = (*w->screen->damageWindowRect) (w,initial,rect);
      WRAP(gs,w->screen,damageWindowRect,groupDamageWindowRect);

      if (initial) {
            GROUP_WINDOW(w);
            
            if (gs->opt[GROUP_SCREEN_OPTION_AUTOTAB].value.b && (w->type & gs->wMask)) {
                  if (!gw->group && (gw->windowState == WindowNormal)) {
                        groupAddWindowToGroup(w, NULL);
                        groupTabGroup(w);
                  }
            }

            if ((gw->windowState == WindowMinimized) && gw->group) {
                  if (gs->opt[GROUP_SCREEN_OPTION_MINIMIZE_ALL].value.b)
                        groupMinimizeWindows(w, gw->group, FALSE);
            } else if ((gw->windowState == WindowShaded) && gw->group) {
                  if (gs->opt[GROUP_SCREEN_OPTION_SHADE_ALL].value.b)
                        groupShadeWindows(w, gw->group, FALSE);
            }
            
            gw->windowState = WindowNormal;
      }

      return status;

}

void groupWindowStateChangeNotify(CompWindow *w)
{
       GROUP_SCREEN(w->screen);
       GROUP_WINDOW(w);

       gw->lastState = w->lastState;

       UNWRAP(gs, w->screen, windowStateChangeNotify);
       (*w->screen->windowStateChangeNotify) (w);
       WRAP(gs, w->screen, windowStateChangeNotify, groupWindowStateChangeNotify);
}

Generated by  Doxygen 1.6.0   Back to index