/* * groupUpdateWindowProperty * */ void groupUpdateWindowProperty (CompWindow *w) { CompDisplay *d = &display; GROUP_WINDOW (w); GROUP_DISPLAY (d); // Do not change anything in this case if (gw->readOnlyProperty) return; if (gw->group) { long int buffer[5]; buffer[0] = gw->group->identifier; buffer[1] = (gw->slot) ? TRUE : FALSE; /* group color RGB */ buffer[2] = gw->group->color[0]; buffer[3] = gw->group->color[1]; buffer[4] = gw->group->color[2]; XChangeProperty (d->display, w->id, gd->groupWinPropertyAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) buffer, 5); } else { XDeleteProperty (d->display, w->id, gd->groupWinPropertyAtom); } }
/* * groupUnsetIgnore * */ Bool groupUnsetIgnore (void) { GROUP_DISPLAY (&display); gd->ignoreMode = FALSE; return FALSE; }
/* * groupFiniDisplay * */ static void groupFiniDisplay (CompPlugin *p, CompDisplay *d) { GROUP_DISPLAY (d); freeScreenPrivateIndex (gd->screenPrivateIndex); UNWRAP (gd, d, handleEvent); free (gd); }
/* * 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) { GROUP_DISPLAY (&display); const BananaValue * option_glow_size = bananaGetOption (bananaIndex, "glow_size", w->screen->screenNum); const BananaValue * option_glow_type = bananaGetOption (bananaIndex, "glow_type", w->screen->screenNum); int glowSize = option_glow_size->i; int glowType = option_glow_type->i; int glowTextureSize = gd->glowTextureProperties[glowType].textureSize; int glowOffset = gd->glowTextureProperties[glowType].glowOffset; glowSize = glowSize * (glowTextureSize - glowOffset) / glowTextureSize; /* glowSize is the size of the glow outside the window decoration * (w->input), while w->output includes the size of w->input * this is why we have to add w->input here */ output->left = MAX (output->left, glowSize + w->input.left); output->right = MAX (output->right, glowSize + w->input.right); output->top = MAX (output->top, glowSize + w->input.top); output->bottom = MAX (output->bottom, glowSize + w->input.bottom); } }
/* * groupCheckWindowProperty * */ Bool groupCheckWindowProperty (CompWindow *w, long int *id, Bool *tabbed, GLushort *color) { Atom type; int retval, fmt; unsigned long nitems, exbyte; long int *data; GROUP_DISPLAY (&display); retval = XGetWindowProperty (display.display, w->id, gd->groupWinPropertyAtom, 0, 5, False, XA_CARDINAL, &type, &fmt, &nitems, &exbyte, (unsigned char **)&data); if (retval == Success) { if (type == XA_CARDINAL && fmt == 32 && nitems == 5) { if (id) *id = data[0]; if (tabbed) *tabbed = (Bool) data[1]; if (color) { color[0] = (GLushort) data[2]; color[1] = (GLushort) data[3]; color[2] = (GLushort) data[4]; } XFree (data); return TRUE; } else if (fmt != 0) XFree (data); } return FALSE; }
void groupWindowStateChangeNotify (CompWindow *w, unsigned int lastState) { CompScreen *s = w->screen; GROUP_DISPLAY (&display); GROUP_SCREEN (s); GROUP_WINDOW (w); if (gw->group && !gd->ignoreMode) { const BananaValue * option_maximize_unmaximize_all = bananaGetOption (bananaIndex, "maximize_unmaximize_all", s->screenNum); if (((lastState & MAXIMIZE_STATE) != (w->state & MAXIMIZE_STATE)) && option_maximize_unmaximize_all->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); } } } UNWRAP (gs, s, windowStateChangeNotify); (*s->windowStateChangeNotify)(w, lastState); WRAP (gs, s, windowStateChangeNotify, groupWindowStateChangeNotify); }
/* * groupInitScreen * */ static Bool groupInitScreen (CompPlugin *p, CompScreen *s) { GroupScreen *gs; int glowType; GROUP_DISPLAY (&display); gs = malloc (sizeof (GroupScreen)); if (!gs) return FALSE; gs->windowPrivateIndex = allocateWindowPrivateIndex (s); if (gs->windowPrivateIndex < 0) { free (gs); return FALSE; } WRAP (gs, s, windowMoveNotify, groupWindowMoveNotify); WRAP (gs, s, windowResizeNotify, groupWindowResizeNotify); WRAP (gs, s, getOutputExtentsForWindow, groupGetOutputExtentsForWindow); WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen); WRAP (gs, s, paintOutput, groupPaintOutput); WRAP (gs, s, drawWindow, groupDrawWindow); WRAP (gs, s, paintWindow, groupPaintWindow); WRAP (gs, s, paintTransformedOutput, groupPaintTransformedOutput); WRAP (gs, s, donePaintScreen, groupDonePaintScreen); WRAP (gs, s, windowGrabNotify, groupWindowGrabNotify); WRAP (gs, s, windowUngrabNotify, groupWindowUngrabNotify); WRAP (gs, s, damageWindowRect, groupDamageWindowRect); WRAP (gs, s, windowStateChangeNotify, groupWindowStateChangeNotify); WRAP (gs, s, activateWindow, groupActivateWindow); s->privates[gd->screenPrivateIndex].ptr = gs; gs->groups = NULL; gs->tmpSel.windows = NULL; gs->tmpSel.nWins = 0; gs->grabIndex = 0; gs->grabState = ScreenGrabNone; gs->lastHoveredGroup = NULL; gs->queued = FALSE; gs->pendingMoves = NULL; gs->pendingGrabs = NULL; gs->pendingUngrabs = NULL; gs->dequeueTimeoutHandle = 0; gs->draggedSlot = NULL; gs->dragged = FALSE; gs->dragHoverTimeoutHandle = 0; gs->prevX = 0; gs->prevY = 0; gs->showDelayTimeoutHandle = 0; /* one-shot timeout for stuff that needs to be initialized after all screens and windows are initialized */ gs->initialActionsTimeoutHandle = compAddTimeout (0, 0, groupApplyInitialActions, (void *) s); initTexture (s, &gs->glowTexture); const BananaValue * option_glow_type = bananaGetOption (bananaIndex, "glow_type", s->screenNum); glowType = option_glow_type->i; imageDataToTexture (s, &gs->glowTexture, glowTextureProperties[glowType].textureData, glowTextureProperties[glowType].textureSize, glowTextureProperties[glowType].textureSize, GL_RGBA, GL_UNSIGNED_BYTE); const BananaValue * option_window_match = bananaGetOption (bananaIndex, "window_match", s->screenNum); matchInit (&gs->window_match); matchAddFromString (&gs->window_match, option_window_match->s); matchUpdate (&gs->window_match); const BananaValue * option_autotab_windows = bananaGetOption (bananaIndex, "autotab_windows", s->screenNum); gs->autotabCount = option_autotab_windows->list.nItem; gs->autotab = malloc (gs->autotabCount * sizeof (CompMatch)); int i; for (i = 0; i <= gs->autotabCount - 1; i++) { matchInit (&gs->autotab[i]); matchAddFromString (&gs->autotab[i], option_autotab_windows->list.item[i].s); matchUpdate (&gs->autotab[i]); } return TRUE; }
void groupComputeGlowQuads (CompWindow *w, CompMatrix *matrix) { BoxRec *box; CompMatrix *quadMatrix; int glowSize, glowOffset; int glowType; GROUP_WINDOW (w); const BananaValue * option_glow = bananaGetOption (bananaIndex, "glow", w->screen->screenNum); if (option_glow->b && matrix) { if (!gw->glowQuads) gw->glowQuads = malloc (NUM_GLOWQUADS * sizeof (GlowQuad)); if (!gw->glowQuads) return; } else { if (gw->glowQuads) { free (gw->glowQuads); gw->glowQuads = NULL; } return; } GROUP_DISPLAY (&display); const BananaValue * option_glow_size = bananaGetOption (bananaIndex, "glow_size", w->screen->screenNum); const BananaValue * option_glow_type = bananaGetOption (bananaIndex, "glow_type", w->screen->screenNum); glowSize = option_glow_size->i; glowType = option_glow_type->i; glowOffset = (glowSize * gd->glowTextureProperties[glowType].glowOffset / gd->glowTextureProperties[glowType].textureSize) + 1; /* Top left corner */ box = &gw->glowQuads[GLOWQUAD_TOPLEFT].box; gw->glowQuads[GLOWQUAD_TOPLEFT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_TOPLEFT].matrix; box->x1 = WIN_REAL_X (w) - glowSize + glowOffset; box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset; box->x2 = WIN_REAL_X (w) + glowOffset; box->y2 = WIN_REAL_Y (w) + glowOffset; quadMatrix->xx = 1.0f / glowSize; quadMatrix->yy = -1.0f / glowSize; quadMatrix->x0 = -(box->x1 * quadMatrix->xx); quadMatrix->y0 = 1.0 -(box->y1 * quadMatrix->yy); box->x2 = MIN (WIN_REAL_X (w) + glowOffset, WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2)); box->y2 = MIN (WIN_REAL_Y (w) + glowOffset, WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2)); /* Top right corner */ box = &gw->glowQuads[GLOWQUAD_TOPRIGHT].box; gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix; box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset; box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset; box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset; box->y2 = WIN_REAL_Y (w) + glowOffset; quadMatrix->xx = -1.0f / glowSize; quadMatrix->yy = -1.0f / glowSize; quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx); quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy); box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset, WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2)); box->y2 = MIN (WIN_REAL_Y (w) + glowOffset, WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2)); /* Bottom left corner */ box = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].box; gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix; box->x1 = WIN_REAL_X (w) - glowSize + glowOffset; box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset; box->x2 = WIN_REAL_X (w) + glowOffset; box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset; quadMatrix->xx = 1.0f / glowSize; quadMatrix->yy = 1.0f / glowSize; quadMatrix->x0 = -(box->x1 * quadMatrix->xx); quadMatrix->y0 = -(box->y1 * quadMatrix->yy); box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset, WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2)); box->x2 = MIN (WIN_REAL_X (w) + glowOffset, WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2)); /* Bottom right corner */ box = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].box; gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix; box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset; box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset; box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset; box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset; quadMatrix->xx = -1.0f / glowSize; quadMatrix->yy = 1.0f / glowSize; quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx); quadMatrix->y0 = -(box->y1 * quadMatrix->yy); box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset, WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2)); box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset, WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2)); /* Top edge */ box = &gw->glowQuads[GLOWQUAD_TOP].box; gw->glowQuads[GLOWQUAD_TOP].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_TOP].matrix; box->x1 = WIN_REAL_X (w) + glowOffset; box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset; box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset; box->y2 = WIN_REAL_Y (w) + glowOffset; quadMatrix->xx = 0.0f; quadMatrix->yy = -1.0f / glowSize; quadMatrix->x0 = 1.0; quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy); /* Bottom edge */ box = &gw->glowQuads[GLOWQUAD_BOTTOM].box; gw->glowQuads[GLOWQUAD_BOTTOM].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOM].matrix; box->x1 = WIN_REAL_X (w) + glowOffset; box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset; box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset; box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset; quadMatrix->xx = 0.0f; quadMatrix->yy = 1.0f / glowSize; quadMatrix->x0 = 1.0; quadMatrix->y0 = -(box->y1 * quadMatrix->yy); /* Left edge */ box = &gw->glowQuads[GLOWQUAD_LEFT].box; gw->glowQuads[GLOWQUAD_LEFT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_LEFT].matrix; box->x1 = WIN_REAL_X (w) - glowSize + glowOffset; box->y1 = WIN_REAL_Y (w) + glowOffset; box->x2 = WIN_REAL_X (w) + glowOffset; box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset; quadMatrix->xx = 1.0f / glowSize; quadMatrix->yy = 0.0f; quadMatrix->x0 = -(box->x1 * quadMatrix->xx); quadMatrix->y0 = 0.0; /* Right edge */ box = &gw->glowQuads[GLOWQUAD_RIGHT].box; gw->glowQuads[GLOWQUAD_RIGHT].matrix = *matrix; quadMatrix = &gw->glowQuads[GLOWQUAD_RIGHT].matrix; box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset; box->y1 = WIN_REAL_Y (w) + glowOffset; box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset; box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset; quadMatrix->xx = -1.0f / glowSize; quadMatrix->yy = 0.0f; quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx); quadMatrix->y0 = 0.0; }
/* * groupPaintOutput * */ Bool groupPaintOutput (CompScreen *s, const ScreenPaintAttrib *sAttrib, const CompTransform *transform, Region region, CompOutput *output, unsigned int mask) { GroupSelection *group; Bool status; GROUP_SCREEN (s); GROUP_DISPLAY (&display); gs->painted = FALSE; gs->vpX = s->x; gs->vpY = s->y; if (gd->resizeInfo) { mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; } else { for (group = gs->groups; group; group = group->next) { if (group->changeState != NoTabChange || group->tabbingState != NoTabbing) { mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; } else if (group->tabBar && (group->tabBar->state != PaintOff)) { mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; } } } UNWRAP (gs, s, paintOutput); status = (*s->paintOutput)(s, sAttrib, transform, region, output, mask); WRAP (gs, s, paintOutput, groupPaintOutput); if (status && !gs->painted) { if ((gs->grabState == ScreenGrabTabDrag) && gs->draggedSlot) { CompTransform wTransform = *transform; PaintState state; GROUP_WINDOW (gs->draggedSlot->window); transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &wTransform); glPushMatrix (); glLoadMatrixf (wTransform.m); /* prevent tab bar drawing.. */ state = gw->group->tabBar->state; gw->group->tabBar->state = PaintOff; groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE); gw->group->tabBar->state = state; glPopMatrix (); } else if (gs->grabState == ScreenGrabSelect) { groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE); } } return status; }
void groupWindowUngrabNotify (CompWindow *w) { CompScreen *s = w->screen; GROUP_SCREEN (s); GROUP_DISPLAY (&display); GROUP_WINDOW (w); if (gw->group && !gd->ignoreMode && !gs->queued) { int i; XRectangle rect; groupDequeueMoveNotifies (s); if (gd->resizeInfo) { rect.x = WIN_X (w); rect.y = WIN_Y (w); rect.width = WIN_WIDTH (w); rect.height = WIN_HEIGHT (w); } 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->resizeGeometry) { unsigned int mask; gw->resizeGeometry->x = WIN_X (cw); gw->resizeGeometry->y = WIN_Y (cw); gw->resizeGeometry->width = WIN_WIDTH (cw); gw->resizeGeometry->height = WIN_HEIGHT (cw); mask = groupUpdateResizeRectangle (cw, &rect, FALSE); if (mask) { XWindowChanges xwc; xwc.x = gw->resizeGeometry->x; xwc.y = gw->resizeGeometry->y; xwc.width = gw->resizeGeometry->width; xwc.height = gw->resizeGeometry->height; if (w->mapNum && (mask & (CWWidth | CWHeight))) sendSyncRequest (w); configureXWindow (cw, mask, &xwc); } else { free (gw->resizeGeometry); gw->resizeGeometry = NULL; } } if (gw->needsPosSync) { syncWindowPosition (cw); gw->needsPosSync = FALSE; } groupEnqueueUngrabNotify (cw); } } if (gd->resizeInfo) { free (gd->resizeInfo); gd->resizeInfo = NULL; } gw->group->grabWindow = None; gw->group->grabMask = 0; } UNWRAP (gs, s, windowUngrabNotify); (*s->windowUngrabNotify)(w); WRAP ( gs, s, windowUngrabNotify, groupWindowUngrabNotify); }
void groupWindowGrabNotify (CompWindow *w, int x, int y, unsigned int state, unsigned int mask) { CompScreen *s = w->screen; GROUP_SCREEN (s); GROUP_DISPLAY (&display); GROUP_WINDOW (w); if (gw->group && !gd->ignoreMode && !gs->queued) { Bool doResizeAll; int i; const BananaValue * option_resize_all = bananaGetOption (bananaIndex, "resize_all", s->screenNum); doResizeAll = option_resize_all->b && (mask & CompWindowGrabResizeMask); if (gw->group->tabBar) groupTabSetVisibility (gw->group, FALSE, 0); for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; if (!cw) continue; if (cw->id != w->id) { GroupWindow *gcw = GET_GROUP_WINDOW (cw, gs); groupEnqueueGrabNotify (cw, x, y, state, mask); if (doResizeAll && !(cw->state & MAXIMIZE_STATE)) { if (!gcw->resizeGeometry) gcw->resizeGeometry = malloc (sizeof (XRectangle)); if (gcw->resizeGeometry) { gcw->resizeGeometry->x = WIN_X (cw); gcw->resizeGeometry->y = WIN_Y (cw); gcw->resizeGeometry->width = WIN_WIDTH (cw); gcw->resizeGeometry->height = WIN_HEIGHT (cw); } } } } if (doResizeAll) { if (!gd->resizeInfo) gd->resizeInfo = malloc (sizeof (GroupResizeInfo)); if (gd->resizeInfo) { gd->resizeInfo->resizedWindow = w; gd->resizeInfo->origGeometry.x = WIN_X (w); gd->resizeInfo->origGeometry.y = WIN_Y (w); gd->resizeInfo->origGeometry.width = WIN_WIDTH (w); gd->resizeInfo->origGeometry.height = WIN_HEIGHT (w); } } gw->group->grabWindow = w->id; gw->group->grabMask = mask; } UNWRAP (gs, s, windowGrabNotify); (*s->windowGrabNotify)(w, x, y, state, mask); WRAP (gs, s, windowGrabNotify, groupWindowGrabNotify); }
/* * groupWindowMoveNotify * */ void groupWindowMoveNotify (CompWindow *w, int dx, int dy, Bool immediate) { CompScreen *s = w->screen; Bool viewportChange; int i; GROUP_SCREEN (s); GROUP_DISPLAY (&display); GROUP_WINDOW (w); UNWRAP (gs, s, windowMoveNotify); (*s->windowMoveNotify)(w, dx, dy, immediate); WRAP (gs, s, windowMoveNotify, groupWindowMoveNotify); if (gw->glowQuads) groupComputeGlowQuads (w, &gs->glowTexture.matrix); if (!gw->group || gs->queued) return; /* FIXME: we need a reliable, 100% safe way to detect window moves caused by viewport changes here */ viewportChange = ((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; bar->rightSpringX += dx; bar->leftSpringX += dx; groupMoveTabBarRegion (gw->group, dx, dy, TRUE); for (slot = bar->slots; slot; slot = slot->next) { XOffsetRegion (slot->region, dx, dy); slot->springX += dx; } } const BananaValue * option_move_all = bananaGetOption (bananaIndex, "move_all", s->screenNum); if (!option_move_all->b || gd->ignoreMode || (gw->group->tabbingState != NoTabbing) || (gw->group->grabWindow != w->id) || !(gw->group->grabMask & CompWindowGrabMoveMask)) { return; } 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) groupEnqueueMoveNotify (cw, -dx, -dy, immediate, TRUE); } else if (!viewportChange) { gw->needsPosSync = TRUE; groupEnqueueMoveNotify (cw, dx, dy, immediate, FALSE); } } }
static unsigned int groupUpdateResizeRectangle (CompWindow *w, XRectangle *masterGeometry, Bool damage) { XRectangle newGeometry; unsigned int mask = 0; int newWidth, newHeight; int widthDiff, heightDiff; GROUP_WINDOW (w); GROUP_DISPLAY (&display); if (!gw->resizeGeometry || !gd->resizeInfo) return 0; newGeometry.x = WIN_X (w) + (masterGeometry->x - gd->resizeInfo->origGeometry.x); newGeometry.y = WIN_Y (w) + (masterGeometry->y - gd->resizeInfo->origGeometry.y); widthDiff = masterGeometry->width - gd->resizeInfo->origGeometry.width; newGeometry.width = MAX (1, WIN_WIDTH (w) + widthDiff); heightDiff = masterGeometry->height - gd->resizeInfo->origGeometry.height; newGeometry.height = MAX (1, WIN_HEIGHT (w) + heightDiff); if (constrainNewWindowSize (w, newGeometry.width, newGeometry.height, &newWidth, &newHeight)) { newGeometry.width = newWidth; newGeometry.height = newHeight; } if (damage) { if (memcmp (&newGeometry, gw->resizeGeometry, sizeof (newGeometry)) != 0) { addWindowDamage (w); } } if (newGeometry.x != gw->resizeGeometry->x) { gw->resizeGeometry->x = newGeometry.x; mask |= CWX; } if (newGeometry.y != gw->resizeGeometry->y) { gw->resizeGeometry->y = newGeometry.y; mask |= CWY; } if (newGeometry.width != gw->resizeGeometry->width) { gw->resizeGeometry->width = newGeometry.width; mask |= CWWidth; } if (newGeometry.height != gw->resizeGeometry->height) { gw->resizeGeometry->height = newGeometry.height; mask |= CWHeight; } return mask; }
static void groupChangeNotify (const char *optionName, BananaType optionType, const BananaValue *optionValue, int screenNum) { GROUP_DISPLAY (&display); if (strcasecmp (optionName, "window_match") == 0) { CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); matchFini (&gs->window_match); matchInit (&gs->window_match); matchAddFromString (&gs->window_match, optionValue->s); matchUpdate (&gs->window_match); } else if (strcasecmp (optionName, "tab_base_color") == 0 || strcasecmp (optionName, "tab_highlight_color") == 0 || strcasecmp (optionName, "tab_border_color") == 0 || strcasecmp (optionName, "tab_style") == 0 || strcasecmp (optionName, "border_radius") == 0 || strcasecmp (optionName, "border_width") == 0) { GroupSelection *group; CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); for (group = gs->groups; group; group = group->next) if (group->tabBar) groupRenderTabBarBackground (group); } else if (strcasecmp (optionName, "tabbar_font_size") == 0 || strcasecmp (optionName, "tabbar_font_color") == 0) { GroupSelection *group; CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); for (group = gs->groups; group; group = group->next) groupRenderWindowTitle (group); } else if (strcasecmp (optionName, "thumb_size") == 0 || strcasecmp (optionName, "thumb_space") == 0) { GroupSelection *group; CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); for (group = gs->groups; group; group = group->next) if (group->tabBar) { BoxPtr box = &group->tabBar->region->extents; groupRecalcTabBarPos (group, (box->x1 + box->x2 ) / 2, box->x1, box->x2); } } else if (strcasecmp (optionName, "glow") == 0 || strcasecmp (optionName, "glow_size") == 0) { CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); CompWindow *w; for (w = s->windows; w; w = w->next) { GROUP_WINDOW (w); groupComputeGlowQuads (w, &gs->glowTexture.matrix); if (gw->glowQuads) { damageWindowOutputExtents (w); updateWindowOutputExtents (w); damageWindowOutputExtents (w); } } } else if (strcasecmp (optionName, "glow_type") == 0) { CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); int glowType; GlowTextureProperties *glowProperty; GROUP_DISPLAY (&display); const BananaValue * option_glow_type = bananaGetOption (bananaIndex, "glow_type", s->screenNum); glowType = option_glow_type->i; glowProperty = &gd->glowTextureProperties[glowType]; finiTexture (s, &gs->glowTexture); initTexture (s, &gs->glowTexture); imageDataToTexture (s, &gs->glowTexture, glowProperty->textureData, glowProperty->textureSize, glowProperty->textureSize, GL_RGBA, GL_UNSIGNED_BYTE); const BananaValue * option_glow = bananaGetOption (bananaIndex, "glow", s->screenNum); if (option_glow->b && gs->groups) { CompWindow *w; for (w = s->windows; w; w = w->next) groupComputeGlowQuads (w, &gs->glowTexture.matrix); damageScreen (s); } } else if (strcasecmp (optionName, "select_button") == 0) updateButton (optionValue->s, &gd->select_button); else if (strcasecmp (optionName, "select_single_key") == 0) updateKey (optionValue->s, &gd->select_single_key); else if (strcasecmp (optionName, "group_key") == 0) updateKey (optionValue->s, &gd->group_key); else if (strcasecmp (optionName, "ungroup_key") == 0) updateKey (optionValue->s, &gd->ungroup_key); else if (strcasecmp (optionName, "remove_key") == 0) updateKey (optionValue->s, &gd->remove_key); else if (strcasecmp (optionName, "close_key") == 0) updateKey (optionValue->s, &gd->close_key); else if (strcasecmp (optionName, "ignore_key") == 0) updateKey (optionValue->s, &gd->ignore_key); else if (strcasecmp (optionName, "tabmode_key") == 0) updateKey (optionValue->s, &gd->tabmode_key); else if (strcasecmp (optionName, "change_tab_left_key") == 0) updateKey (optionValue->s, &gd->change_tab_left_key); else if (strcasecmp (optionName, "change_tab_right_key") == 0) updateKey (optionValue->s, &gd->change_tab_right_key); else if (strcasecmp (optionName, "change_color_key") == 0) updateKey (optionValue->s, &gd->change_color_key); else if (strcasecmp (optionName, "autotab_windows") == 0) { CompScreen *s = getScreenFromScreenNum (screenNum); GROUP_SCREEN (s); int i; if (gs->autotab && gs->autotabCount != 0) { for (i = 0; i <= gs->autotabCount - 1; i++) matchFini (&gs->autotab[i]); free (gs->autotab); } gs->autotabCount = optionValue->list.nItem; gs->autotab = malloc (gs->autotabCount * sizeof (CompMatch)); for (i = 0; i <= gs->autotabCount - 1; i++) { matchInit (&gs->autotab[i]); matchAddFromString (&gs->autotab[i], optionValue->list.item[i].s); matchUpdate (&gs->autotab[i]); } } }
/* * groupDeleteGroup * */ void groupDeleteGroup (GroupSelection *group) { GroupSelection *next, *prev; CompScreen *s = group->screen; GROUP_SCREEN (s); GROUP_DISPLAY (&display); if (group->windows) { int i; if (group->tabBar) { /* set up untabbing animation and delete the group at the end of the animation */ groupUntabGroup (group); group->ungroupState = UngroupAll; return; } for (i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; GROUP_WINDOW (cw); damageWindowOutputExtents (cw); gw->group = NULL; updateWindowOutputExtents (cw); groupUpdateWindowProperty (cw); const BananaValue * option_autotab_create = bananaGetOption (bananaIndex, "autotab_create", s->screenNum); if (option_autotab_create->b && groupIsGroupWindow (cw)) { groupAddWindowToGroup (cw, NULL, 0); groupTabGroup (cw); } } free (group->windows); group->windows = NULL; } else if (group->tabBar) groupDeleteTabBar (group); prev = group->prev; 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; if (group == gs->lastHoveredGroup) gs->lastHoveredGroup = NULL; if (group == gd->lastRestackedGroup) gd->lastRestackedGroup = NULL; free (group); }
/* * groupRenderWindowTitle * */ void groupRenderWindowTitle (GroupSelection *group) { GroupCairoLayer *layer; int width, height; Pixmap pixmap = None; CompScreen *s = group->screen; CompDisplay *d = s->display; GroupTabBar *bar = group->tabBar; GROUP_DISPLAY (d); if (!bar || !HAS_TOP_WIN (group) || !bar->textLayer) return; width = bar->region->extents.x2 - bar->region->extents.x1; height = bar->region->extents.y2 - bar->region->extents.y1; bar->textLayer = groupRebuildCairoLayer (s, bar->textLayer, width, height); layer = bar->textLayer; if (!layer) return; if (bar->textSlot && bar->textSlot->window && gd->textFunc) { CompTextData *data; CompTextAttrib textAttrib; textAttrib.family = groupGetTabbarFontFamily(s); textAttrib.size = groupGetTabbarFontSize (s); textAttrib.flags = CompTextFlagStyleBold | CompTextFlagEllipsized | CompTextFlagNoAutoBinding; textAttrib.color[0] = groupGetTabbarFontColorRed (s); textAttrib.color[1] = groupGetTabbarFontColorGreen (s); textAttrib.color[2] = groupGetTabbarFontColorBlue (s); textAttrib.color[3] = groupGetTabbarFontColorAlpha (s); textAttrib.maxWidth = width; textAttrib.maxHeight = height; data = (gd->textFunc->renderWindowTitle) (s, bar->textSlot->window->id, FALSE, &textAttrib); if (data) { pixmap = data->pixmap; width = data->width; height = data->height; free (data); } } if (!pixmap) { /* getting the pixmap failed, so create an empty one */ pixmap = XCreatePixmap (d->display, s->root, width, height, 32); if (pixmap) { XGCValues gcv; GC gc; gcv.foreground = 0x00000000; gcv.plane_mask = 0xffffffff; gc = XCreateGC (d->display, pixmap, GCForeground, &gcv); XFillRectangle (d->display, pixmap, gc, 0, 0, width, height); XFreeGC (d->display, gc); } } layer->texWidth = width; layer->texHeight = height; if (pixmap) { layer->pixmap = pixmap; bindPixmapToTexture (s, &layer->texture, layer->pixmap, layer->texWidth, layer->texHeight, 32); } }
/* * groupHandleEvent * */ void groupHandleEvent (XEvent *event) { CompWindow *w; CompScreen *s; GROUP_DISPLAY (&display); switch (event->type) { case KeyPress: if (isKeyPressEvent (event, &gd->select_single_key)) groupSelectSingle (display.activeWindow); else if (isKeyPressEvent (event, &gd->group_key)) groupGroupWindows (event->xkey.root); else if (isKeyPressEvent (event, &gd->ungroup_key)) groupUnGroupWindows (event->xkey.root); else if (isKeyPressEvent (event, &gd->remove_key)) groupRemoveWindow (display.activeWindow); else if (isKeyPressEvent (event, &gd->close_key)) groupCloseWindows (display.activeWindow); else if (isKeyPressEvent (event, &gd->ignore_key)) groupSetIgnore (); else if (isKeyPressEvent (event, &gd->tabmode_key)) groupInitTab (display.activeWindow); else if (isKeyPressEvent (event, &gd->change_tab_left_key)) groupChangeTabLeft (display.activeWindow); else if (isKeyPressEvent (event, &gd->change_tab_right_key)) groupChangeTabRight (display.activeWindow); else if (isKeyPressEvent (event, &gd->change_color_key)) groupChangeColor (display.activeWindow); break; case KeyRelease: if (gd->ignore_key.keycode == event->xkey.keycode) groupUnsetIgnore (); break; case MotionNotify: s = findScreenAtDisplay (event->xmotion.root); if (s) groupHandleMotionEvent (s, pointerX, pointerY); break; case ButtonPress: if (isButtonPressEvent (event, &gd->select_button)) groupSelect (event->xbutton.window); s = findScreenAtDisplay (event->xbutton.root); if (s) groupHandleButtonPressEvent (s, event); break; case ButtonRelease: if (gd->select_button.button == event->xbutton.button) groupSelectTerminate (event->xbutton.root); s = findScreenAtDisplay (event->xbutton.root); if (s) groupHandleButtonReleaseEvent (s, event); break; case MapNotify: w = findWindowAtDisplay (event->xmap.window); if (w) { CompWindow *cw; for (cw = w->screen->windows; cw; cw = cw->next) { if (w->id == cw->frame) { GROUP_WINDOW (cw); if (gw->windowHideInfo) XUnmapWindow (display.display, cw->frame); } } } break; case UnmapNotify: w = findWindowAtDisplay (event->xunmap.window); if (w) { GROUP_WINDOW (w); if (w->pendingUnmaps) { if (w->shaded) { gw->windowState = WindowShaded; const BananaValue * option_shade_all = bananaGetOption (bananaIndex, "shade_all", w->screen->screenNum); if (gw->group && option_shade_all->b) groupShadeWindows (w, gw->group, TRUE); } else if (w->minimized) { gw->windowState = WindowMinimized; const BananaValue * option_minimize_all = bananaGetOption (bananaIndex, "minimize_all", w->screen->screenNum); if (gw->group && option_minimize_all->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 */ if (!(gw->animateState & IS_UNGROUPING)) { groupDeleteGroupWindow (w); damageScreen (w->screen); } } } } break; case ClientMessage: if (event->xclient.message_type == display.winActiveAtom) { w = findWindowAtDisplay (event->xclient.window); if (w) { GROUP_WINDOW (w); if (gw->group && gw->group->tabBar && !IS_TOP_TAB (w, gw->group)) { gw->group->checkFocusAfterTabChange = TRUE; groupChangeTab (gw->slot, RotateUncertain); } } } else if (event->xclient.message_type == gd->resizeNotifyAtom) { CompWindow *w; w = findWindowAtDisplay (event->xclient.window); if (w && gd->resizeInfo && (w == gd->resizeInfo->resizedWindow)) { GROUP_WINDOW (w); GROUP_SCREEN (w->screen); if (gw->group) { int i; XRectangle rect; rect.x = event->xclient.data.l[0]; rect.y = event->xclient.data.l[1]; rect.width = event->xclient.data.l[2]; rect.height = event->xclient.data.l[3]; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; GroupWindow *gcw; gcw = GET_GROUP_WINDOW (cw, gs); if (gcw->resizeGeometry) { if (groupUpdateResizeRectangle (cw, &rect, TRUE)) addWindowDamage (cw); } } } } } break; default: if (event->type == display.shapeEvent + ShapeNotify) { XShapeEvent *se = (XShapeEvent *) event; if (se->kind == ShapeInput) { CompWindow *w; w = findWindowAtDisplay (se->window); if (w) { GROUP_WINDOW (w); if (gw->windowHideInfo) groupClearWindowInputShape (w, gw->windowHideInfo); } } } break; } UNWRAP (gd, &display, handleEvent); (*display.handleEvent)(event); WRAP (gd, &display, handleEvent, groupHandleEvent); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == display.wmNameAtom) { CompWindow *w; w = findWindowAtDisplay (event->xproperty.window); if (w) { GROUP_WINDOW (w); if (gw->group && gw->group->tabBar && gw->group->tabBar->textSlot && gw->group->tabBar->textSlot->window == w) { /* make sure we are using the updated name */ groupRenderWindowTitle (gw->group); groupDamageTabBarRegion (gw->group); } } } break; case EnterNotify: { CompWindow *w; w = findWindowAtDisplay (event->xcrossing.window); if (w) { GROUP_WINDOW (w); GROUP_SCREEN (w->screen); if (gs->showDelayTimeoutHandle) compRemoveTimeout (gs->showDelayTimeoutHandle); if (w->id != w->screen->grabWindow) groupUpdateTabBars (w->screen, w->id); if (gw->group) { if (gs->draggedSlot && gs->dragged && IS_TOP_TAB (w, gw->group)) { int hoverTime; const BananaValue * option_drag_hover_time = bananaGetOption (bananaIndex, "drag_hover_time", w->screen->screenNum); hoverTime = option_drag_hover_time->f * 1000; if (gs->dragHoverTimeoutHandle) compRemoveTimeout (gs->dragHoverTimeoutHandle); if (hoverTime > 0) gs->dragHoverTimeoutHandle = compAddTimeout (hoverTime, (float) hoverTime * 1.2, groupDragHoverTimeout, w); } } } } break; case ConfigureNotify: { CompWindow *w; w = findWindowAtDisplay (event->xconfigure.window); if (w) { GROUP_WINDOW (w); if (gw->group && gw->group->tabBar && IS_TOP_TAB (w, gw->group) && gw->group->inputPrevention && gw->group->ipwMapped) { XWindowChanges xwc; xwc.stack_mode = Above; xwc.sibling = w->id; XConfigureWindow (display.display, gw->group->inputPrevention, CWSibling | CWStackMode, &xwc); } if (event->xconfigure.above != None) { if (gw->group && !gw->group->tabBar && (gw->group != gd->lastRestackedGroup)) { const BananaValue * option_raise_all = bananaGetOption (bananaIndex, "raise_all", w->screen->screenNum); if (option_raise_all->b) groupRaiseWindows (w, gw->group); } if (w->managed && !w->attrib.override_redirect) gd->lastRestackedGroup = gw->group; } } } break; default: break; } }